Add winery source code
[vfc/nfvo/wfengine.git] / winery / org.eclipse.winery.repository / src / main / java / org / eclipse / winery / repository / resources / servicetemplates / topologytemplates / TopologyTemplateResource.java
1 /*******************************************************************************
2  * Copyright (c) 2012-2015 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.servicetemplates.topologytemplates;
13
14 import java.net.URI;
15 import java.util.ArrayList;
16 import java.util.List;
17
18 import javax.ws.rs.Consumes;
19 import javax.ws.rs.GET;
20 import javax.ws.rs.PUT;
21 import javax.ws.rs.Path;
22 import javax.ws.rs.Produces;
23 import javax.ws.rs.QueryParam;
24 import javax.ws.rs.core.Context;
25 import javax.ws.rs.core.HttpHeaders;
26 import javax.ws.rs.core.MediaType;
27 import javax.ws.rs.core.Response;
28 import javax.ws.rs.core.UriInfo;
29
30 import org.eclipse.winery.common.Util;
31 import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
32 import org.eclipse.winery.model.tosca.TEntityTemplate;
33 import org.eclipse.winery.model.tosca.TNodeTemplate;
34 import org.eclipse.winery.model.tosca.TRelationshipTemplate;
35 import org.eclipse.winery.model.tosca.TTopologyTemplate;
36 import org.eclipse.winery.repository.Prefs;
37 import org.eclipse.winery.repository.Utils;
38 import org.eclipse.winery.repository.backend.BackendUtils;
39 import org.eclipse.winery.repository.client.IWineryRepositoryClient;
40 import org.eclipse.winery.repository.client.WineryRepositoryClientFactory;
41 import org.eclipse.winery.repository.json.TopologyTemplateModule;
42 import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
43 import org.restdoc.annotations.RestDoc;
44 import org.restdoc.annotations.RestDocParam;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 import com.fasterxml.jackson.databind.ObjectMapper;
49 import com.fasterxml.jackson.databind.SerializationFeature;
50 import com.sun.jersey.api.client.Client;
51 import com.sun.jersey.api.client.WebResource.Builder;
52 import com.sun.jersey.api.view.Viewable;
53
54 public class TopologyTemplateResource {
55         
56         private static final Logger logger = LoggerFactory.getLogger(TopologyTemplateResource.class);
57         
58         private final TTopologyTemplate topologyTemplate;
59         
60         private final ServiceTemplateResource serviceTemplateRes;
61         
62         
63         /**
64          * A topology template is always nested in a service template
65          */
66         public TopologyTemplateResource(ServiceTemplateResource parent) {
67                 this.topologyTemplate = parent.getServiceTemplate().getTopologyTemplate();
68                 this.serviceTemplateRes = parent;
69         }
70         
71         
72         public static class DataForJSP {
73                 
74                 private String location;
75                 private TTopologyTemplate topologyTemplate;
76                 private URI repositoryURI;
77                 private String additonalCSS;
78                 private Boolean autoLayoutOnLoad;
79                 private String additionalScript;
80                 
81                 
82                 public DataForJSP(String location, URI repositoryURI, TTopologyTemplate topologyTemplate, String additonalCSS, String additionalScript, Boolean autoLayoutOnLoad) {
83                         this.location = location;
84                         this.repositoryURI = repositoryURI;
85                         this.topologyTemplate = topologyTemplate;
86                         this.additonalCSS = additonalCSS;
87                         this.additionalScript = additionalScript;
88                         this.autoLayoutOnLoad = autoLayoutOnLoad;
89                 }
90                 
91                 public String getLocation() {
92                         return this.location;
93                 }
94                 
95                 public TTopologyTemplate getTopologyTemplate() {
96                         return this.topologyTemplate;
97                 }
98                 
99                 public String getAdditonalCSS() {
100                         return this.additonalCSS;
101                 }
102                 
103                 public String getAdditionalScript() {
104                         return this.additionalScript;
105                 }
106                 
107                 public Boolean getAutoLayoutOnLoad() {
108                         return this.autoLayoutOnLoad;
109                 }
110                 
111                 public IWineryRepositoryClient getClient() {
112                         // Quick hack
113                         // IWineryRepository is not implemented by Prefs.INSTANCE.getRepository()
114                         // Therefore, we have to generate a real WineryRepositoryClient even if that causes more http load
115                         IWineryRepositoryClient client = WineryRepositoryClientFactory.getWineryRepositoryClient();
116                         client.addRepository(this.repositoryURI.toString());
117                         return client;
118                 }
119                 
120         }
121         
122         
123         @GET
124         @RestDoc(methodDescription = "?edit is used in the URL to get the jsPlumb-based editor")
125         @Produces(MediaType.TEXT_HTML)
126         // @formatter:off
127         public Response getHTML(
128                         @QueryParam(value = "edit") String edit,
129                         @QueryParam(value = "script") @RestDocParam(description = "the script to include in a <script> tag. The function wineryViewExternalScriptOnLoad if it is defined. Only available if 'view' is also set") String script,
130                         @QueryParam(value = "view") String view,
131                         @QueryParam(value = "autoLayoutOnLoad") String autoLayoutOnLoad,
132                         @Context UriInfo uriInfo) {
133                 // @formatter:on
134                 Response res;
135                 String JSPName;
136                 String location = Prefs.INSTANCE.getWineryTopologyModelerPath();
137                 location = uriInfo.getBaseUri().resolve(location).toString();
138                 // at the topology modeler, jersey needs to have an absolute path
139                 URI repositoryURI = uriInfo.getBaseUri();
140                 location = location + "/?repositoryURL=";
141                 location = location + Util.URLencode(repositoryURI.toString());
142                 ServiceTemplateId serviceTemplate = (ServiceTemplateId) this.serviceTemplateRes.getId();
143                 location = location + "&ns=";
144                 location = location + serviceTemplate.getNamespace().getEncoded();
145                 location = location + "&id=";
146                 location = location + serviceTemplate.getXmlId().getEncoded();
147                 if (edit == null) {
148                         String additionalCSS = null;
149                         Boolean autoLayoutOnLoadBoolean = false;
150                         if (view == null) {
151                                 // integration in Winery
152                                 // currently not maintained: Winery includes ?view as iframe
153                                 JSPName = "/jsp/servicetemplates/topologytemplates/topologytemplate.jsp";
154                         } else {
155                                 // view only mode
156                                 // fullscreen: additionalCSS and script possible
157                                 if (!"".equals(view)) {
158                                         // view with additional CSS
159                                         URI cssURI = URI.create(view);
160                                         if (cssURI.isAbsolute()) {
161                                                 additionalCSS = view;
162                                         } else {
163                                                 // relative URLs starts at "/css/topologyrendering/"
164                                                 additionalCSS = uriInfo.getBaseUri().resolve("css/topologytemplaterendering/").resolve(view).toString();
165                                                 if (!additionalCSS.endsWith(".css")) {
166                                                         additionalCSS += ".css";
167                                                 }
168                                         }
169                                 }
170                                 if (autoLayoutOnLoad != null) {
171                                         autoLayoutOnLoadBoolean = true;
172                                 }
173                                 JSPName = "/jsp/servicetemplates/topologytemplates/topologytemplateview.jsp";
174                         }
175                         Viewable viewable = new Viewable(JSPName, new DataForJSP(location, repositoryURI, this.topologyTemplate, additionalCSS, script, autoLayoutOnLoadBoolean));
176                         res = Response.ok().header(HttpHeaders.VARY, HttpHeaders.ACCEPT).entity(viewable).build();
177                 } else {
178                         // edit mode
179                         URI uri = Utils.createURI(location);
180                         res = Response.seeOther(uri).build();
181                 }
182                 return res;
183         }
184         
185         /**
186          * 
187          * @param uriInfo the URI ending with "topologytemplate/" of a service
188          *            template
189          */
190         @GET
191         @Produces(MediaType.TEXT_PLAIN)
192         public Response triggerGenerateBuildPlan(@Context UriInfo uriInfo) {
193                 String plansURI = uriInfo.getAbsolutePath().resolve("../plans/").toString();
194                 String csarURI = uriInfo.getAbsolutePath().resolve("../?csar").toString();
195                 
196                 String request = "<generatePlanForTopology><CSARURL>";
197                 request += csarURI;
198                 request += "</CSARURL><PLANPOSTURL>";
199                 request += plansURI;
200                 request += "</PLANPOSTURL></generatePlanForTopology>";
201                 
202                 Client client = Client.create();
203                 Builder wr = client.resource("http://localhost:1339/planbuilder/sync").type(MediaType.APPLICATION_XML);
204                 
205                 try {
206                         wr.post(String.class, request);
207                 } catch (com.sun.jersey.api.client.UniformInterfaceException e) {
208                         return Response.serverError().entity(e.getMessage()).build();
209                 }
210                 
211                 return Response.ok().build();
212         }
213         
214         // @formatter:off
215         @GET
216         @RestDoc(methodDescription="Returns a JSON representation of the topology template. <br />" +
217         "X and Y coordinates are embedded as attributes. QName string with Namespace: <br />" +
218         "{@link org.eclipse.winery.repository.common.constants.Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE} <br />" +
219         "@return The JSON representation of the topology template <em>without</em> associated artifacts and without the parent service template")
220         @Produces(MediaType.APPLICATION_JSON)
221         // @formatter:on
222         public Response getComponentInstanceJSON() {
223                 Response res;
224                 ObjectMapper mapper = new ObjectMapper();
225                 mapper.enable(SerializationFeature.INDENT_OUTPUT);
226                 mapper.registerModule(new TopologyTemplateModule());
227                 try {
228                         // convert it to json
229                         String json = mapper.writeValueAsString(this.topologyTemplate);
230                         res = Response.ok(json).build();
231                 } catch (Exception e) {
232                         TopologyTemplateResource.logger.error(e.getMessage(), e);
233                         res = Response.serverError().entity(e.getMessage()).build();
234                 }
235                 return res;
236         }
237         
238         @Path("nodetemplates/")
239         public NodeTemplatesResource getNodeTemplatesResource() {
240                 // FIXME: onDelete will not work as we have a copy of the original list. We have to add a "listener" to remove at the list and route that remove to the original list
241                 List<TNodeTemplate> l = BackendUtils.getAllNestedNodeTemplates(this.serviceTemplateRes.getServiceTemplate());
242                 return new NodeTemplatesResource(l, this.serviceTemplateRes);
243         }
244         
245         @Path("relationshiptemplates/")
246         public RelationshipTemplatesResource getRelationshipTemplatesResource() {
247                 // FIXME: onDelete will not work. See getNodeTemplatesResource
248                 List<TRelationshipTemplate> l = new ArrayList<TRelationshipTemplate>();
249                 for (TEntityTemplate t : this.topologyTemplate.getNodeTemplateOrRelationshipTemplate()) {
250                         if (t instanceof TRelationshipTemplate) {
251                                 l.add((TRelationshipTemplate) t);
252                         }
253                 }
254                 return new RelationshipTemplatesResource(l, this.serviceTemplateRes);
255         }
256         
257         @PUT
258         @RestDoc(methodDescription = "Replaces the topology by the information given in the XML")
259         @Consumes(MediaType.TEXT_XML)
260         public Response setModel(TTopologyTemplate topologyTemplate) {
261                 this.serviceTemplateRes.getServiceTemplate().setTopologyTemplate(topologyTemplate);
262                 return BackendUtils.persist(this.serviceTemplateRes);
263         }
264         
265         // @formatter:off
266         @GET
267         @RestDoc(methodDescription="<p>Returns an XML representation of the topology template." +
268         " X and Y coordinates are embedded as attributes. Namespace:" +
269         "{@link org.eclipse.winery.repository.common.constants.Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE} </p>" +
270         "<p>{@link org.eclipse.winery.repository.client.WineryRepositoryClient." +
271         "getTopologyTemplate(QName)} consumes this template</p>" +
272         "<p>@return The XML representation of the topology template <em>without</em>" +
273         "associated artifacts and without the parent service template </p>")
274         @Produces(MediaType.TEXT_XML)
275         // @formatter:on
276         public Response getComponentInstanceXML() {
277                 return Utils.getXML(TTopologyTemplate.class, this.topologyTemplate);
278         }
279         
280 }