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
10 * Oliver Kopp - initial API and implementation
11 *******************************************************************************/
12 package org.eclipse.winery.repository.resources.servicetemplates.plans;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.io.StringWriter;
17 import java.util.List;
19 import javax.ws.rs.Consumes;
20 import javax.ws.rs.POST;
21 import javax.ws.rs.Produces;
22 import javax.ws.rs.core.MediaType;
23 import javax.ws.rs.core.Response;
24 import javax.ws.rs.core.Response.Status;
26 import org.apache.commons.lang3.StringUtils;
27 import org.eclipse.winery.common.RepositoryFileReference;
28 import org.eclipse.winery.common.Util;
29 import org.eclipse.winery.common.ids.XMLId;
30 import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
31 import org.eclipse.winery.common.ids.elements.PlanId;
32 import org.eclipse.winery.common.ids.elements.PlansId;
33 import org.eclipse.winery.model.tosca.TPlan;
34 import org.eclipse.winery.model.tosca.TPlan.PlanModelReference;
35 import org.eclipse.winery.repository.Constants;
36 import org.eclipse.winery.repository.Utils;
37 import org.eclipse.winery.repository.backend.BackendUtils;
38 import org.eclipse.winery.repository.backend.Repository;
39 import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
40 import org.eclipse.winery.repository.resources.admin.types.PlanLanguagesManager;
41 import org.eclipse.winery.repository.resources.admin.types.PlanTypesManager;
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;
48 import com.fasterxml.jackson.core.JsonFactory;
49 import com.fasterxml.jackson.core.JsonGenerationException;
50 import com.fasterxml.jackson.core.JsonGenerator;
51 import com.sun.jersey.api.view.Viewable;
52 import com.sun.jersey.core.header.FormDataContentDisposition;
53 import com.sun.jersey.multipart.FormDataBodyPart;
54 import com.sun.jersey.multipart.FormDataParam;
57 * Presents the plans nested in one Service Template
59 public class PlansResource extends EntityWithIdCollectionResource<PlanResource, TPlan> {
61 private static final Logger logger = LoggerFactory.getLogger(PlansResource.class);
64 public PlansResource(List<TPlan> plans, ServiceTemplateResource res) {
65 super(PlanResource.class, TPlan.class, plans, res);
69 public Viewable getHTML() {
70 return new Viewable("/jsp/servicetemplates/plans/plans.jsp", new PlansResourceData(this.list));
74 @RestDoc(methodDescription = "<p>Linked plans are currently not supported. Existing plans with the same id are overwritten</p> <p>@return JSON with .tableData: Array with row data for dataTable</p>")
75 @Consumes({MediaType.MULTIPART_FORM_DATA})
76 @Produces(MediaType.APPLICATION_JSON)
77 // the supertype consumes JSON and XML at org.eclipse.winery.repository.resources._support.collections.EntityCollectionResource.addNewElement(EntityT)
79 public Response onPost(
80 @FormDataParam("planName") String name,
81 @FormDataParam("planType") String type,
82 @FormDataParam("planLanguage") @RestDocParam(description = "the plan language (e..g, BPMN or BPEL). Full URL.") String language,
83 @FormDataParam("file") @RestDocParam(description="(optional in the case of BPMN4TOSCA) file containing the plan.") InputStream uploadedInputStream,
84 @FormDataParam("file") FormDataContentDisposition fileDetail,
85 @FormDataParam("file") FormDataBodyPart body
88 if (StringUtils.isEmpty(name)) {
89 return Response.status(Status.BAD_REQUEST).entity("planName must be given").build();
91 if (StringUtils.isEmpty(type)) {
92 return Response.status(Status.BAD_REQUEST).entity("planType must be given").build();
94 if (StringUtils.isEmpty(language)) {
95 return Response.status(Status.BAD_REQUEST).entity("planLanguage must be given").build();
98 boolean bpmn4toscaMode = org.eclipse.winery.common.constants.Namespaces.URI_BPMN4TOSCA_20.equals(language);
99 if (!bpmn4toscaMode) {
100 if (uploadedInputStream == null) {
101 return Response.status(Status.BAD_REQUEST).entity("file must be given").build();
105 // A plan carries both a name and an ID
106 // To be user-friendly, we create the ID based on the name
107 // the drawback is, that we do not allow two plans with the same name
108 // during creation, but allow renaming plans to the same name (as we do
109 // not allow ID renaming)
110 String xmlId = Utils.createXMLidAsString(name);
112 // BEGIN: Store plan file
115 PlansId plansId = new PlansId((ServiceTemplateId) ((ServiceTemplateResource) this.res).getId());
116 PlanId planId = new PlanId(plansId, new XMLId(xmlId, false));
117 // Ensure overwriting
118 if (Repository.INSTANCE.exists(planId)) {
120 Repository.INSTANCE.forceDelete(planId);
121 // Quick hack to remove the deleted plan from the plans element
122 ((ServiceTemplateResource) this.res).synchronizeReferences();
123 } catch (IOException e) {
124 return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
129 if (bpmn4toscaMode) {
130 fileName = xmlId + Constants.SUFFIX_BPMN4TOSCA;
131 RepositoryFileReference ref = new RepositoryFileReference(planId, fileName);
133 Repository.INSTANCE.putContentToFile(ref, "{}", MediaType.APPLICATION_JSON_TYPE);
134 } catch (IOException e1) {
135 return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not create empty plan. " + e1.getMessage()).build();
138 // We use the filename also as local file name. Alternatively, we could use the xml id
139 // With URL encoding, this should not be an issue
140 fileName = Util.URLencode(fileDetail.getFileName());
143 RepositoryFileReference ref = new RepositoryFileReference(planId, fileName);
145 Repository.INSTANCE.putContentToFile(ref, uploadedInputStream, body.getMediaType());
146 } catch (IOException e1) {
147 return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not store plan. " + e1.getMessage()).build();
150 // END: Store plan file
152 TPlan plan = new TPlan();
155 plan.setPlanType(type);
156 plan.setPlanLanguage(language);
157 PlansResource.setPlanModelReference(plan, planId, fileName);
161 JsonFactory jsonFactory = new JsonFactory();
162 StringWriter sw = new StringWriter();
164 JsonGenerator jGenerator = jsonFactory.createGenerator(sw);
165 jGenerator.writeStartObject();
166 jGenerator.writeFieldName("tableData");
167 jGenerator.writeStartArray();
168 jGenerator.writeString(xmlId);
169 jGenerator.writeString(""); // precondition
170 jGenerator.writeString(name);
171 jGenerator.writeString(PlanTypesManager.INSTANCE.getShortName(type));
172 jGenerator.writeString(PlanLanguagesManager.INSTANCE.getShortName(language));
173 jGenerator.writeEndArray();
174 jGenerator.writeEndObject();
177 } catch (JsonGenerationException e) {
178 PlansResource.logger.error(e.getMessage(), e);
179 return Response.serverError().build();
180 } catch (IOException e) {
181 PlansResource.logger.error(e.getMessage(), e);
182 return Response.serverError().build();
185 Response res = BackendUtils.persist(this.res);
186 if (res.getStatus() == 204) {
187 // everything OK, return created
188 return Response.created(Utils.createURI(Util.URLencode(xmlId))).entity(sw.toString()).build();
194 static void setPlanModelReference(TPlan plan, PlanId planId, String fileName) {
195 PlanModelReference pref = new PlanModelReference();
196 // Set path relative to Definitions/ path inside CSAR.
197 pref.setReference("../" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(planId)) + fileName);
198 plan.setPlanModelReference(pref);
202 public String getId(TPlan plan) {