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
10 * Oliver Kopp - initial API and implementation
11 *******************************************************************************/
12 package org.eclipse.winery.repository.resources.servicetemplates;
14 import java.io.IOException;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.List;
19 import java.util.SortedSet;
21 import javax.ws.rs.DELETE;
22 import javax.ws.rs.GET;
23 import javax.ws.rs.Path;
24 import javax.ws.rs.Produces;
25 import javax.ws.rs.core.MediaType;
26 import javax.ws.rs.core.Response;
27 import javax.ws.rs.core.Response.Status;
28 import javax.xml.namespace.QName;
30 import org.eclipse.winery.common.RepositoryFileReference;
31 import org.eclipse.winery.common.ids.XMLId;
32 import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
33 import org.eclipse.winery.common.ids.elements.PlanId;
34 import org.eclipse.winery.common.ids.elements.PlansId;
35 import org.eclipse.winery.model.tosca.TBoundaryDefinitions;
36 import org.eclipse.winery.model.tosca.TExtensibleElements;
37 import org.eclipse.winery.model.tosca.TPlan;
38 import org.eclipse.winery.model.tosca.TPlan.PlanModelReference;
39 import org.eclipse.winery.model.tosca.TPlans;
40 import org.eclipse.winery.model.tosca.TServiceTemplate;
41 import org.eclipse.winery.model.tosca.TTopologyTemplate;
42 import org.eclipse.winery.repository.Utils;
43 import org.eclipse.winery.repository.backend.BackendUtils;
44 import org.eclipse.winery.repository.backend.Repository;
45 import org.eclipse.winery.repository.resources.AbstractComponentInstanceWithReferencesResource;
46 import org.eclipse.winery.repository.resources.IHasName;
47 import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.BoundaryDefinitionsResource;
48 import org.eclipse.winery.repository.resources.servicetemplates.plans.PlansResource;
49 import org.eclipse.winery.repository.resources.servicetemplates.selfserviceportal.SelfServicePortalResource;
50 import org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.TopologyTemplateResource;
51 import org.restdoc.annotations.RestDoc;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
55 public class ServiceTemplateResource extends AbstractComponentInstanceWithReferencesResource implements IHasName {
57 private static final Logger logger = LoggerFactory.getLogger(ServiceTemplateResource.class);
60 public ServiceTemplateResource(ServiceTemplateId id) {
66 @Path("topologytemplate/")
67 public TopologyTemplateResource getTopologyTemplateResource() {
68 if (this.getServiceTemplate().getTopologyTemplate() == null) {
69 // the main service template resource exists
70 // default topology template: empty template
71 // This eases the JSPs etc. and is valid as a non-existant topology template is equal to an empty one
72 this.getServiceTemplate().setTopologyTemplate(new TTopologyTemplate());
74 return new TopologyTemplateResource(this);
78 public PlansResource getPlansResource() {
79 TPlans plans = this.getServiceTemplate().getPlans();
82 this.getServiceTemplate().setPlans(plans);
84 return new PlansResource(plans.getPlan(), this);
87 @Path("selfserviceportal/")
88 public SelfServicePortalResource getSelfServicePortalResource() {
89 return new SelfServicePortalResource(this);
92 @Path("boundarydefinitions/")
93 public BoundaryDefinitionsResource getBoundaryDefinitionsResource() {
94 TBoundaryDefinitions boundaryDefinitions = this.getServiceTemplate().getBoundaryDefinitions();
95 if (boundaryDefinitions == null) {
96 boundaryDefinitions = new TBoundaryDefinitions();
97 this.getServiceTemplate().setBoundaryDefinitions(boundaryDefinitions);
99 return new BoundaryDefinitionsResource(this, boundaryDefinitions);
103 public String getName() {
104 String name = this.getServiceTemplate().getName();
107 name = this.getId().getXmlId().getDecoded();
113 public Response setName(String name) {
114 this.getServiceTemplate().setName(name);
115 return BackendUtils.persist(this);
120 @RestDoc(methodDescription="Returns the associated node type, which can be substituted by this service template.<br />" +
121 "@return a QName of the form {namespace}localName is returned.")
122 @Path("substitutableNodeType")
123 @Produces(MediaType.TEXT_PLAIN)
125 public Response getSubstitutableNodeTypeAsResponse() {
126 QName qname = this.getServiceTemplate().getSubstitutableNodeType();
128 return Response.status(Status.NOT_FOUND).build();
130 return Response.ok(qname.toString()).build();
136 * @return null if there is no substitutable node type
138 public QName getSubstitutableNodeType() {
139 return this.getServiceTemplate().getSubstitutableNodeType();
143 @RestDoc(methodDescription = "Removes the association to substitutable node type")
144 @Path("substitutableNodeType")
145 public Response deleteSubstitutableNodeType() {
146 this.getServiceTemplate().setSubstitutableNodeType(null);
147 BackendUtils.persist(this);
148 return Response.noContent().build();
151 public TServiceTemplate getServiceTemplate() {
152 return (TServiceTemplate) this.getElement();
156 protected TExtensibleElements createNewElement() {
157 return new TServiceTemplate();
161 protected void copyIdToFields() {
162 this.getServiceTemplate().setId(this.getId().getXmlId().getDecoded());
163 this.getServiceTemplate().setTargetNamespace(this.getId().getNamespace().getDecoded());
167 * Synchronizes the known plans with the data in the XML. When there is a
168 * stored file, but no known entry in the XML, we guess "BPEL" as language
169 * and "build plan" as type.
171 * @throws IOException
174 public void synchronizeReferences() {
175 // locally stored plans
176 TPlans plans = this.getServiceTemplate().getPlans();
178 // plans stored in the repository
179 PlansId plansContainerId = new PlansId((ServiceTemplateId) this.getId());
180 SortedSet<PlanId> nestedPlans = Repository.INSTANCE.getNestedIds(plansContainerId, PlanId.class);
182 Set<PlanId> plansToAdd = new HashSet<PlanId>();
183 plansToAdd.addAll(nestedPlans);
185 if (nestedPlans.isEmpty()) {
187 // data on the file system equals the data -> no plans
190 // we have to check for equality later
195 plans = new TPlans();
196 this.getServiceTemplate().setPlans(plans);
199 for (Iterator<TPlan> iterator = plans.getPlan().iterator(); iterator.hasNext();) {
200 TPlan plan = iterator.next();
201 if (plan.getPlanModel() != null) {
202 // in case, a plan is directly contained in a Model element, we do not need to do anything
205 PlanModelReference planModelReference = plan.getPlanModelReference();
206 if ((planModelReference = plan.getPlanModelReference()) != null) {
207 String ref = planModelReference.getReference();
208 if ((ref == null) || ref.startsWith("../")) {
209 // references to local plans start with "../"
210 // special case (due to errors in the importer): empty PlanModelReference field
211 if (plan.getId() == null) {
212 // invalid plan entry: no id.
213 // we remove the entry
217 PlanId planId = new PlanId(plansContainerId, new XMLId(plan.getId(), false));
218 if (nestedPlans.contains(planId)) {
219 // everything allright
220 // we do NOT need to add the plan on the HDD to the XML
221 plansToAdd.remove(planId);
223 // no local storage for the plan, we remove it from the XML
230 // add all plans locally stored, but not contained in the XML, as plan element to the plans of the service template.
231 List<TPlan> thePlans = plans.getPlan();
232 for (PlanId planId : plansToAdd) {
233 SortedSet<RepositoryFileReference> files = Repository.INSTANCE.getContainedFiles(planId);
234 if (files.size() != 1) {
235 throw new IllegalStateException("Currently, only one file per plan is supported.");
237 RepositoryFileReference ref = files.iterator().next();
239 TPlan plan = new TPlan();
240 plan.setId(planId.getXmlId().getDecoded());
241 plan.setName(planId.getXmlId().getDecoded());
242 plan.setPlanType(org.eclipse.winery.repository.Constants.TOSCA_PLANTYPE_BUILD_PLAN);
243 plan.setPlanLanguage(org.eclipse.winery.common.constants.Namespaces.URI_BPEL20_EXECUTABLE);
245 // create a PlanModelReferenceElement pointing to that file
246 String path = Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(ref));
247 // path is relative from the definitions element
249 PlanModelReference pref = new PlanModelReference();
250 pref.setReference(path);
252 plan.setPlanModelReference(pref);
258 } catch (IOException e) {
259 throw new IllegalStateException("Could not persist resource", e);