aboutsummaryrefslogtreecommitdiffstats
path: root/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java
diff options
context:
space:
mode:
Diffstat (limited to 'winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java')
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java205
1 files changed, 205 insertions, 0 deletions
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java
new file mode 100644
index 0000000..13a8420
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.plans;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.common.ids.elements.PlanId;
+import org.eclipse.winery.common.ids.elements.PlansId;
+import org.eclipse.winery.model.tosca.TPlan;
+import org.eclipse.winery.model.tosca.TPlan.PlanModelReference;
+import org.eclipse.winery.repository.Constants;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
+import org.eclipse.winery.repository.resources.admin.types.PlanLanguagesManager;
+import org.eclipse.winery.repository.resources.admin.types.PlanTypesManager;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+import org.restdoc.annotations.RestDoc;
+import org.restdoc.annotations.RestDocParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.sun.jersey.api.view.Viewable;
+import com.sun.jersey.core.header.FormDataContentDisposition;
+import com.sun.jersey.multipart.FormDataBodyPart;
+import com.sun.jersey.multipart.FormDataParam;
+
+/**
+ * Presents the plans nested in one Service Template
+ */
+public class PlansResource extends EntityWithIdCollectionResource<PlanResource, TPlan> {
+
+ private static final Logger logger = LoggerFactory.getLogger(PlansResource.class);
+
+
+ public PlansResource(List<TPlan> plans, ServiceTemplateResource res) {
+ super(PlanResource.class, TPlan.class, plans, res);
+ }
+
+ @Override
+ public Viewable getHTML() {
+ return new Viewable("/jsp/servicetemplates/plans/plans.jsp", new PlansResourceData(this.list));
+ }
+
+ @POST
+ @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>")
+ @Consumes({MediaType.MULTIPART_FORM_DATA})
+ @Produces(MediaType.APPLICATION_JSON)
+ // the supertype consumes JSON and XML at org.eclipse.winery.repository.resources._support.collections.EntityCollectionResource.addNewElement(EntityT)
+ // @formatter:off
+ public Response onPost(
+ @FormDataParam("planName") String name,
+ @FormDataParam("planType") String type,
+ @FormDataParam("planLanguage") @RestDocParam(description = "the plan language (e..g, BPMN or BPEL). Full URL.") String language,
+ @FormDataParam("file") @RestDocParam(description="(optional in the case of BPMN4TOSCA) file containing the plan.") InputStream uploadedInputStream,
+ @FormDataParam("file") FormDataContentDisposition fileDetail,
+ @FormDataParam("file") FormDataBodyPart body
+ ) {
+ // @formatter:on
+ if (StringUtils.isEmpty(name)) {
+ return Response.status(Status.BAD_REQUEST).entity("planName must be given").build();
+ }
+ if (StringUtils.isEmpty(type)) {
+ return Response.status(Status.BAD_REQUEST).entity("planType must be given").build();
+ }
+ if (StringUtils.isEmpty(language)) {
+ return Response.status(Status.BAD_REQUEST).entity("planLanguage must be given").build();
+ }
+
+ boolean bpmn4toscaMode = org.eclipse.winery.common.constants.Namespaces.URI_BPMN4TOSCA_20.equals(language);
+ if (!bpmn4toscaMode) {
+ if (uploadedInputStream == null) {
+ return Response.status(Status.BAD_REQUEST).entity("file must be given").build();
+ }
+ }
+
+ // A plan carries both a name and an ID
+ // To be user-friendly, we create the ID based on the name
+ // the drawback is, that we do not allow two plans with the same name
+ // during creation, but allow renaming plans to the same name (as we do
+ // not allow ID renaming)
+ String xmlId = Utils.createXMLidAsString(name);
+
+ // BEGIN: Store plan file
+
+ // Determine Id
+ PlansId plansId = new PlansId((ServiceTemplateId) ((ServiceTemplateResource) this.res).getId());
+ PlanId planId = new PlanId(plansId, new XMLId(xmlId, false));
+ // Ensure overwriting
+ if (Repository.INSTANCE.exists(planId)) {
+ try {
+ Repository.INSTANCE.forceDelete(planId);
+ // Quick hack to remove the deleted plan from the plans element
+ ((ServiceTemplateResource) this.res).synchronizeReferences();
+ } catch (IOException e) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ }
+
+ String fileName;
+ if (bpmn4toscaMode) {
+ fileName = xmlId + Constants.SUFFIX_BPMN4TOSCA;
+ RepositoryFileReference ref = new RepositoryFileReference(planId, fileName);
+ try {
+ Repository.INSTANCE.putContentToFile(ref, "{}", MediaType.APPLICATION_JSON_TYPE);
+ } catch (IOException e1) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not create empty plan. " + e1.getMessage()).build();
+ }
+ } else {
+ // We use the filename also as local file name. Alternatively, we could use the xml id
+ // With URL encoding, this should not be an issue
+ fileName = Util.URLencode(fileDetail.getFileName());
+
+ // Really store it
+ RepositoryFileReference ref = new RepositoryFileReference(planId, fileName);
+ try {
+ Repository.INSTANCE.putContentToFile(ref, uploadedInputStream, body.getMediaType());
+ } catch (IOException e1) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not store plan. " + e1.getMessage()).build();
+ }
+ }
+ // END: Store plan file
+
+ TPlan plan = new TPlan();
+ plan.setId(xmlId);
+ plan.setName(name);
+ plan.setPlanType(type);
+ plan.setPlanLanguage(language);
+ PlansResource.setPlanModelReference(plan, planId, fileName);
+ this.list.add(plan);
+
+ // prepare result
+ JsonFactory jsonFactory = new JsonFactory();
+ StringWriter sw = new StringWriter();
+ try {
+ JsonGenerator jGenerator = jsonFactory.createGenerator(sw);
+ jGenerator.writeStartObject();
+ jGenerator.writeFieldName("tableData");
+ jGenerator.writeStartArray();
+ jGenerator.writeString(xmlId);
+ jGenerator.writeString(""); // precondition
+ jGenerator.writeString(name);
+ jGenerator.writeString(PlanTypesManager.INSTANCE.getShortName(type));
+ jGenerator.writeString(PlanLanguagesManager.INSTANCE.getShortName(language));
+ jGenerator.writeEndArray();
+ jGenerator.writeEndObject();
+ jGenerator.close();
+ sw.close();
+ } catch (JsonGenerationException e) {
+ PlansResource.logger.error(e.getMessage(), e);
+ return Response.serverError().build();
+ } catch (IOException e) {
+ PlansResource.logger.error(e.getMessage(), e);
+ return Response.serverError().build();
+ }
+
+ Response res = BackendUtils.persist(this.res);
+ if (res.getStatus() == 204) {
+ // everything OK, return created
+ return Response.created(Utils.createURI(Util.URLencode(xmlId))).entity(sw.toString()).build();
+ } else {
+ return res;
+ }
+ }
+
+ static void setPlanModelReference(TPlan plan, PlanId planId, String fileName) {
+ PlanModelReference pref = new PlanModelReference();
+ // Set path relative to Definitions/ path inside CSAR.
+ pref.setReference("../" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(planId)) + fileName);
+ plan.setPlanModelReference(pref);
+ }
+
+ @Override
+ public String getId(TPlan plan) {
+ return plan.getId();
+ }
+}