f8fb9f10ae1a6f0a8dbc11b487013f2d35e3c5b4
[vfc/nfvo/wfengine.git] / winery / org.eclipse.winery.repository / src / main / java / org / eclipse / winery / repository / resources / admin / NamespacesResource.java
1 /*******************************************************************************
2  * Copyright (c) 2012-2013 University of Stuttgart.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * and the Apache License 2.0 which both accompany this distribution,
6  * and are available at http://www.eclipse.org/legal/epl-v10.html
7  * and http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Contributors:
10  *     Oliver Kopp - initial API and implementation
11  *******************************************************************************/
12 package org.eclipse.winery.repository.resources.admin;
13
14 import java.util.Collection;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.TreeSet;
18
19 import javax.ws.rs.Consumes;
20 import javax.ws.rs.DELETE;
21 import javax.ws.rs.FormParam;
22 import javax.ws.rs.GET;
23 import javax.ws.rs.POST;
24 import javax.ws.rs.Path;
25 import javax.ws.rs.PathParam;
26 import javax.ws.rs.Produces;
27 import javax.ws.rs.core.MediaType;
28 import javax.ws.rs.core.Response;
29 import javax.ws.rs.core.Response.Status;
30
31 import org.apache.commons.lang3.StringUtils;
32 import org.eclipse.winery.common.Util;
33 import org.eclipse.winery.common.ids.Namespace;
34 import org.eclipse.winery.repository.Utils;
35 import org.eclipse.winery.repository.backend.Repository;
36 import org.eclipse.winery.repository.datatypes.ids.admin.NamespacesId;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 import com.fasterxml.jackson.core.JsonProcessingException;
41 import com.sun.jersey.api.view.Viewable;
42
43 /**
44  * Manages prefixes for the namespaces
45  */
46 public class NamespacesResource extends AbstractAdminResource {
47         
48         private static final Logger logger = LoggerFactory.getLogger(NamespacesResource.class);
49         
50         public final static NamespacesResource INSTANCE = new NamespacesResource();
51         
52         private Integer nsCount = 0;
53         
54         
55         private NamespacesResource() {
56                 super(new NamespacesId());
57                 
58                 // globally set prefixes
59                 // if that behavior is not desired, the code has to be moved to "generatePrefix" which checks for existence, ...
60                 this.configuration.setProperty("http://www.w3.org/2001/XMLSchema", "xsd");
61                 this.configuration.setProperty("http://www.w3.org/XML/1998/namespace", "xmlns");
62                 this.configuration.setProperty(org.eclipse.winery.common.constants.Namespaces.TOSCA_NAMESPACE, "tosca");
63                 this.configuration.setProperty(org.eclipse.winery.common.constants.Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "winery");
64         }
65         
66         private Collection<String> getAllPrefixes() {
67                 Iterator<String> keys = this.configuration.getKeys();
68                 HashSet<String> res = new HashSet<String>();
69                 while (keys.hasNext()) {
70                         String key = keys.next();
71                         String prefix = this.configuration.getString(key);
72                         res.add(prefix);
73                 }
74                 return res;
75         }
76         
77         @GET
78         @Produces(MediaType.TEXT_HTML)
79         public Response getHTML() {
80                 Viewable viewable = new Viewable("/jsp/admin/namespaces.jsp", this);
81                 return Response.ok().entity(viewable).build();
82         }
83         
84         /**
85          * Sets / overwrites prefix/namespace mapping
86          * 
87          * In case the prefix is already bound to another namespace, BAD_REQUEST is
88          * returned.
89          */
90         @POST
91         @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
92         public Response addNamespace(@FormParam("namespace") String namespace, @FormParam("nsPrefix") String prefix) {
93                 if (StringUtils.isEmpty(namespace)) {
94                         return Response.status(Status.BAD_REQUEST).entity("namespace must be given.").build();
95                 }
96                 if (StringUtils.isEmpty(prefix)) {
97                         return Response.status(Status.BAD_REQUEST).entity("prefix must be given.").build();
98                 }
99                 namespace = Util.URLdecode(namespace);
100                 prefix = Util.URLdecode(prefix);
101                 Collection<String> allPrefixes = this.getAllPrefixes();
102                 if (allPrefixes.contains(prefix)) {
103                         if (NamespacesResource.getPrefix(namespace).equals(prefix)) {
104                                 return Response.notModified().build();
105                         } else {
106                                 // the requested prefix is already bound to a different namespace
107                                 return Response.status(Status.BAD_REQUEST).entity("prefix already bound to a different namespace.").build();
108                         }
109                 }
110                 this.configuration.setProperty(namespace, prefix);
111                 return Response.noContent().build();
112         }
113         
114         /**
115          * Deletes given namespace from the repository
116          * 
117          * @param URI to delete. The namespace is URLencoded.
118          * @return
119          */
120         @DELETE
121         @Path("{namespace}")
122         public Response onDelete(@PathParam("namespace") String URI) {
123                 Response res;
124                 URI = Util.URLdecode(URI);
125                 if (this.configuration.containsKey(URI)) {
126                         this.configuration.clearProperty(URI);
127                         res = Response.noContent().build();
128                 } else {
129                         res = Response.status(Status.NOT_FOUND).build();
130                 }
131                 return res;
132         }
133         
134         /**
135          * SIDEFFECT: URI is added to list of known namespaces if it did not exist
136          * before
137          */
138         public static String getPrefix(Namespace namespace) {
139                 String ns = namespace.getDecoded();
140                 return NamespacesResource.getPrefix(ns);
141         }
142         
143         @Path("{namespace}")
144         @GET
145         @Produces(MediaType.TEXT_PLAIN)
146         public String getPrefixForEncodedNamespace(@PathParam("namespace") String URI) {
147                 URI = Util.URLdecode(URI);
148                 return NamespacesResource.getPrefix(URI);
149         }
150         
151         /**
152          * SIDEFFECT: URI is added to list of known namespaces if it did not exist
153          * before
154          */
155         public static String getPrefix(String namespace) {
156                 if (namespace == null) {
157                         throw new IllegalArgumentException("Namespace must not be null");
158                 }
159                 String prefix = NamespacesResource.INSTANCE.configuration.getString(namespace);
160                 if (prefix == null) {
161                         prefix = NamespacesResource.generatePrefix(namespace);
162                         NamespacesResource.INSTANCE.configuration.setProperty(namespace, prefix);
163                 }
164                 return prefix;
165         }
166         
167         private static String generatePrefix(String namespace) {
168                 String prefix = null;
169                 Collection<String> allPrefixes = NamespacesResource.INSTANCE.getAllPrefixes();
170                 
171                 // TODO: generate prefix using URI (and not "arbitrary" prefix)
172                 do {
173                         prefix = String.format("ns%d", NamespacesResource.INSTANCE.nsCount);
174                         NamespacesResource.INSTANCE.nsCount++;
175                 } while (allPrefixes.contains(prefix));
176                 return prefix;
177         }
178         
179         /**
180          * Returns the list of all namespaces registered with his manager. It could
181          * be incomplete, if entries have been added manually to the repository
182          * 
183          * @return all namespaces registered with this manager.
184          */
185         private HashSet<Namespace> getRegisteredNamespaces() {
186                 HashSet<Namespace> res = new HashSet<Namespace>();
187                 Iterator<String> keys = this.configuration.getKeys();
188                 while (keys.hasNext()) {
189                         String key = keys.next();
190                         Namespace ns = new Namespace(key, false);
191                         res.add(ns);
192                 }
193                 return res;
194         }
195         
196         /**
197          * Returns the list of all namespaces registered with his manager and used
198          * at component instances.
199          */
200         public static Collection<Namespace> getNamespaces() {
201                 HashSet<Namespace> res = NamespacesResource.INSTANCE.getRegisteredNamespaces();
202                 res.addAll(Repository.INSTANCE.getUsedNamespaces());
203                 return res;
204         }
205         
206         /**
207          * This method is required because static methods cannot be accessed by EL
208          * 
209          * @return see getNamespaces()
210          */
211         public Collection<Namespace> getNamespacesForJSP() {
212                 return NamespacesResource.getNamespaces();
213         }
214         
215         /**
216          * Returns the list of all namespaces registered with his manager and used
217          * at component instances.
218          * 
219          * @return a JSON list containing the non-encoded URIs of each known
220          *         namespace
221          */
222         @GET
223         @Produces(MediaType.APPLICATION_JSON)
224         public String getNamespacesAsJSONlist() {
225                 Collection<Namespace> namespaces = NamespacesResource.getNamespaces();
226                 
227                 // We now have all namespaces
228                 // We need to convert from Namespace to String
229                 
230                 TreeSet<String> stringNamespaces = new TreeSet<String>();
231                 for (Namespace ns : namespaces) {
232                         stringNamespaces.add(ns.getDecoded());
233                 }
234                 
235                 String res;
236                 try {
237                         res = Utils.mapper.writeValueAsString(stringNamespaces);
238                 } catch (JsonProcessingException e) {
239                         NamespacesResource.logger.error(e.getMessage(), e);
240                         res = "[]";
241                 }
242                 return res;
243         }
244         
245         /**
246          * Checks whether a prefix is registered for a namespace
247          * 
248          * Used at CSARImporter
249          */
250         public boolean getIsPrefixKnownForNamespace(String namespace) {
251                 return this.configuration.containsKey(namespace);
252         }
253 }