diff options
author | huangjian <huang.jian12@zte.com.cn> | 2016-08-31 16:47:33 +0800 |
---|---|---|
committer | huangjian <huang.jian12@zte.com.cn> | 2016-08-31 16:47:33 +0800 |
commit | fa49e78cc199526a9e33b59c5194f8e3bf0f0952 (patch) | |
tree | 3478e867a8f304266dbceca6e992cceca410ede4 /winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources | |
parent | 159d40f0011559c8f82338b29dca1bffd700f2c8 (diff) |
Add winery source code
Change-Id: I1c5088121d79b71098c3cba1996c6f784737532e
Issue-id: TOSCA-49
Signed-off-by: huangjian <huang.jian12@zte.com.cn>
Diffstat (limited to 'winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources')
140 files changed, 12543 insertions, 0 deletions
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/APIResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/APIResource.java new file mode 100644 index 0000000..9393b7e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/APIResource.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 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.API; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.select2.Select2DataWithOptGroups; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; + +public class APIResource { + + @GET + @Path("getallartifacttemplatesofcontaineddeploymentartifacts") + @Produces(MediaType.APPLICATION_JSON) + public Response getAllArtifactTemplatesOfContainedDeploymentArtifacts(@QueryParam("servicetemplate") String serviceTemplateQNameString, @QueryParam("nodetemplateid") String nodeTemplateId) { + if (StringUtils.isEmpty(serviceTemplateQNameString)) { + return Response.status(Status.BAD_REQUEST).entity("servicetemplate has be given as query parameter").build(); + } + + QName serviceTemplateQName = QName.valueOf(serviceTemplateQNameString); + + ServiceTemplateId serviceTemplateId = new ServiceTemplateId(serviceTemplateQName); + if (!Repository.INSTANCE.exists(serviceTemplateId)) { + return Response.status(Status.BAD_REQUEST).entity("service template does not exist").build(); + } + ServiceTemplateResource serviceTemplateResource = new ServiceTemplateResource(serviceTemplateId); + + Collection<QName> artifactTemplates = new ArrayList<>(); + List<TNodeTemplate> allNestedNodeTemplates = BackendUtils.getAllNestedNodeTemplates(serviceTemplateResource.getServiceTemplate()); + for (TNodeTemplate nodeTemplate : allNestedNodeTemplates) { + if (StringUtils.isEmpty(nodeTemplateId) || nodeTemplate.getId().equals(nodeTemplateId)) { + Collection<QName> ats = BackendUtils.getArtifactTemplatesOfReferencedDeploymentArtifacts(nodeTemplate); + artifactTemplates.addAll(ats); + } + } + + // convert QName list to select2 data + Select2DataWithOptGroups res = new Select2DataWithOptGroups(); + for (QName qName : artifactTemplates) { + res.add(qName.getNamespaceURI(), qName.toString(), qName.getLocalPart()); + } + return Response.ok().entity(res.asSortedSet()).build(); + } + + /** + * Implementation similar to + * getAllArtifactTemplatesOfContainedDeploymentArtifacts. Only difference is + * "getArtifactTemplatesOfReferencedImplementationArtifacts" instead of + * "getArtifactTemplatesOfReferencedDeploymentArtifacts". + */ + @GET + @Path("getallartifacttemplatesofcontainedimplementationartifacts") + @Produces(MediaType.APPLICATION_JSON) + public Response getAllArtifactTemplatesOfContainedImplementationArtifacts(@QueryParam("servicetemplate") String serviceTemplateQNameString, @QueryParam("nodetemplateid") String nodeTemplateId) { + if (StringUtils.isEmpty(serviceTemplateQNameString)) { + return Response.status(Status.BAD_REQUEST).entity("servicetemplate has be given as query parameter").build(); + } + QName serviceTemplateQName = QName.valueOf(serviceTemplateQNameString); + + ServiceTemplateId serviceTemplateId = new ServiceTemplateId(serviceTemplateQName); + if (!Repository.INSTANCE.exists(serviceTemplateId)) { + return Response.status(Status.BAD_REQUEST).entity("service template does not exist").build(); + } + ServiceTemplateResource serviceTemplateResource = new ServiceTemplateResource(serviceTemplateId); + + Collection<QName> artifactTemplates = new ArrayList<>(); + List<TNodeTemplate> allNestedNodeTemplates = BackendUtils.getAllNestedNodeTemplates(serviceTemplateResource.getServiceTemplate()); + for (TNodeTemplate nodeTemplate : allNestedNodeTemplates) { + if (StringUtils.isEmpty(nodeTemplateId) || nodeTemplate.getId().equals(nodeTemplateId)) { + Collection<QName> ats = BackendUtils.getArtifactTemplatesOfReferencedImplementationArtifacts(nodeTemplate); + artifactTemplates.addAll(ats); + } + } + + // convert QName list to select2 data + Select2DataWithOptGroups res = new Select2DataWithOptGroups(); + for (QName qName : artifactTemplates) { + res.add(qName.getNamespaceURI(), qName.toString(), qName.getLocalPart()); + } + return Response.ok().entity(res.asSortedSet()).build(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/package-info.java new file mode 100644 index 0000000..6eda321 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/package-info.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 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 + *******************************************************************************/ + +/** + * This package contains all packages providing extended access to the stored models + * + * The idea is that the resources provide information stored in the respective definition file. + * With this API, the stored data is interpreted more abstractly. As a long-term goal, things + * such as inherticance should be supported here + */ +package org.eclipse.winery.repository.resources.API;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResource.java new file mode 100644 index 0000000..d4cc201 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResource.java @@ -0,0 +1,516 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,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; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.StreamingOutput; +import javax.ws.rs.core.UriInfo; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.TOSCADocumentBuilderFactory; +import org.eclipse.winery.common.constants.MimeTypes; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.model.tosca.Definitions; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImport; +import org.eclipse.winery.repository.JAXBSupport; +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.backend.constants.MediaTypes; +import org.eclipse.winery.repository.export.TOSCAExportUtil; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources.documentation.DocumentationsResource; +import org.eclipse.winery.repository.resources.imports.genericimports.GenericImportResource; +import org.eclipse.winery.repository.resources.tags.TagsResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import com.sun.jersey.api.view.Viewable; + +/** + * Resource for a component ( + * <ul> + * <li>ServiceTemplates,</li> + * <li>EntityTypes,</li> + * <li>EntityTypeImplementations,</li> + * <li>EntityTemplates</li> + * </ul> + * ). A component is directly nested in a TDefinitions element. See also + * {@link org.eclipse.winery.common.ids.definitions.TOSCAComponentId} + * + * Bundles all operations required for all components. e.g., namespace+XMLid, + * object comparison, import, export, tags + * + * Uses a TDefinitions document as storage. + * + * Additional setters and getters are added if it comes to Winery's extensions + * such as the color of a relationship type + */ +public abstract class AbstractComponentInstanceResource implements Comparable<AbstractComponentInstanceResource>, IPersistable { + + private static final Logger logger = LoggerFactory.getLogger(AbstractComponentInstanceResource.class); + + protected final TOSCAComponentId id; + + private final RepositoryFileReference ref; + + // the object representing the data of this resource + private Definitions definitions = null; + + // shortcut for this.definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + protected TExtensibleElements element = null; + + + /** + * Instantiates the resource. Assumes that the resource should exist + * (assured by the caller) + * + * The caller should <em>not</em> create the resource by other ways. E.g., + * by instantiating this resource and then adding data. + */ + public AbstractComponentInstanceResource(TOSCAComponentId id) { + this.id = id; + + // the resource itself exists + assert (Repository.INSTANCE.exists(id)); + + // the data file might not exist + this.ref = BackendUtils.getRefOfDefinitions(id); + if (Repository.INSTANCE.exists(this.ref)) { + this.load(); + } else { + this.createNew(); + } + } + + /** + * Convenience method for getId().getNamespace() + */ + public final Namespace getNamespace() { + return this.id.getNamespace(); + } + + /** + * Convenience method for getId().getXmlId() + */ + public final XMLId getXmlId() { + return this.id.getXmlId(); + } + + /** + * Convenience method for getId().getQName(); + * + * @return the QName associated with this resource + */ + public final QName getQName() { + return this.getId().getQName(); + } + + /** + * Returns the id associated with this resource + */ + public final TOSCAComponentId getId() { + return this.id; + } + + /** + * called from AbstractComponentResource + */ + @DELETE + public final Response onDelete() { + Response res = BackendUtils.delete(this.id); + return res; + } + + @Override + public final int compareTo(AbstractComponentInstanceResource o) { + return this.id.compareTo(o.id); + } + + @Override + public final boolean equals(Object o) { + if (o instanceof String) { + throw new IllegalStateException(); + } else if (o instanceof AbstractComponentInstanceResource) { + if (o.getClass().equals(this.getClass())) { + // only compare if the two objects are from the same class + return ((AbstractComponentInstanceResource) o).getId().equals(this.getId()); + } else { + throw new IllegalStateException(); + } + } else { + throw new IllegalStateException(); + } + } + + @Override + public final int hashCode() { + return this.getId().hashCode(); + } + + @GET + @Path("id") + public String getTOSCAId() { + return this.id.getXmlId().getDecoded(); + } + + @PUT + @Path("id") + public Response putId(@FormParam("id") String id) { + // this renames the entity type resource + // TODO: implement rename functionality + return Response.serverError().entity("not yet implemented").build(); + } + + /** + * Main page + */ + // @Produces(MediaType.TEXT_HTML) // not true because of ?csar leads to send + // a csar. We nevertheless have to annotate that to be able to get a JSON + // representation required for the file upload (in {@link + // ArtifactTemplateResource}) + // + // we cannot issue a request expecting content-type application/zip as it is + // not possible to offer the result in a "save-as"-dialog: + // http://stackoverflow.com/questions/7464665/ajax-response-content-disposition-attachment + @GET + @Produces(MediaType.TEXT_HTML) + public final Response getHTML(@QueryParam(value = "definitions") String definitions, @QueryParam(value = "csar") String csar, @Context UriInfo uriInfo) { + if (!Repository.INSTANCE.exists(this.id)) { + return Response.status(Status.NOT_FOUND).build(); + } + if (definitions != null) { + return Utils.getDefinitionsOfSelectedResource(this, uriInfo.getBaseUri()); + } else if (csar != null) { + return this.getCSAR(); + } else { + String type = Utils.getTypeForInstance(this.getClass()); + String viewableName = "/jsp/" + Utils.getIntermediateLocationStringForType(type, "/") + "/" + type.toLowerCase() + ".jsp"; + Viewable viewable = new Viewable(viewableName, this); + + return Response.ok().entity(viewable).build(); + + // we can't do the following as the GET request from the browser + // cannot set the accept header properly + // "vary: accept" header has to be set as we may also return a THOR + // on the same URL + // return Response.ok().header(HttpHeaders.VARY, + // HttpHeaders.ACCEPT).entity(viewable).build(); + } + } + + @GET + @Produces(MimeTypes.MIMETYPE_ZIP) + public final Response getCSAR() { + if (!Repository.INSTANCE.exists(this.id)) { + return Response.status(Status.NOT_FOUND).build(); + } + return Utils.getCSARofSelectedResource(this); + } + + /** + * Returns the definitions of this resource. Includes required imports of + * other definitions + * + * @param csar used because plan generator's GET request lands here + */ + @GET + @Produces({MimeTypes.MIMETYPE_TOSCA_DEFINITIONS, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + public Response getDefinitionsAsResponse(@QueryParam(value = "csar") String csar) { + if (!Repository.INSTANCE.exists(this.id)) { + return Response.status(Status.NOT_FOUND).build(); + } + + if (csar != null) { + return Utils.getCSARofSelectedResource(this); + } + + StreamingOutput so = new StreamingOutput() { + + @Override + public void write(OutputStream output) throws IOException, WebApplicationException { + TOSCAExportUtil exporter = new TOSCAExportUtil(); + // we include everything related + Map<String, Object> conf = new HashMap<>(); + try { + exporter.exportTOSCA(AbstractComponentInstanceResource.this.id, output, conf); + } catch (JAXBException e) { + throw new WebApplicationException(e); + } + } + }; + return Response.ok().type(MediaType.TEXT_XML).entity(so).build(); + } + + /** + * @throws IllegalStateException if an IOException occurred. We opted not to + * propagate the IOException directly as this exception occurs + * seldom and is a not an exception to be treated by all callers + * in the prototype. + */ + private void load() { + try { + InputStream is = Repository.INSTANCE.newInputStream(this.ref); + Unmarshaller u = JAXBSupport.createUnmarshaller(); + this.definitions = (Definitions) u.unmarshal(is); + } catch (Exception e) { + AbstractComponentInstanceResource.logger.error("Could not read content from file " + this.ref, e); + throw new IllegalStateException(e); + } + try { + this.element = this.definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + } catch (IndexOutOfBoundsException e) { + if (this instanceof GenericImportResource) { + // everything allright: + // ImportResource is a quick hack using 99% of the functionality offered here + // As only 1% has to be "quick hacked", we do that instead of a clean design + // Clean design: Introduce a class between this and AbstractComponentInstanceResource, where this class and ImportResource inhertis from + // A clean design introducing a super class AbstractDefinitionsBackedResource does not work, as we currently also support PropertiesBackedResources and such a super class would required multi-inheritance + } else { + throw new IllegalStateException("Wrong storage format: No ServiceTemplateOrNodeTypeOrNodeTypeImplementation found."); + } + } + } + + @Override + public void persist() throws IOException { + BackendUtils.persist(this.definitions, this.ref, MediaTypes.MEDIATYPE_TOSCA_DEFINITIONS); + } + + /** + * Creates a new instance of the object represented by this resource + */ + private void createNew() { + this.definitions = BackendUtils.createWrapperDefinitions(this.getId()); + + // create empty element + this.element = this.createNewElement(); + + // add the element to the definitions + this.definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().add(this.element); + + // copy ns + id + this.copyIdToFields(); + + // ensure that the definitions is persisted. Ensures that export works. + BackendUtils.persist(this); + } + + /** + * Creates an empty instance of an Element. + * + * The implementors do <em>not</em>have to copy the ns and the id to the + * appropriate fields. + * + * we have two implementation possibilities: + * <ul> + * <li>a) each subclass implements this method and returns the appropriate + * object</li> + * <li>b) we use java reflection to invoke the right constructor as done in + * the resources</li> + * </ul> + * We opted for a) to increase readability of the code + */ + protected abstract TExtensibleElements createNewElement(); + + /** + * Copies the current id of the resource to the appropriate fields in the + * element. + * + * For instance, the id is put in the "name" field for EntityTypes + * + * We opted for a separate method from createNewElement to enable renaming + * of the object + */ + protected abstract void copyIdToFields(); + + /** + * Returns the Element belonging to this resource. As Java does not allow + * overriding returned classes, we expect the caller to either cast right or + * to use "getXY" defined by each subclass, where XY is the concrete type + * + * Shortcut for + * getDefinitions().getServiceTemplateOrNodeTypeOrNodeTypeImplementation + * ().get(0); + * + * @return TCapabilityType|... + */ + public TExtensibleElements getElement() { + return this.element; + } + + /** + * @return the reference to the internal list of imports. Can be changed if + * some imports are required or should be removed + * @throws IllegalStateException if definitions was not loaded or not + * initialized + */ + protected List<TImport> getImport() { + if (this.definitions == null) { + throw new IllegalStateException("Trying to access uninitalized definitions object"); + } + return this.definitions.getImport(); + } + + /** + * Returns an XML representation of the definitions + * + * We return the complete definitions to allow the user changes to it, such + * as adding imports, etc. + */ + public String getDefinitionsAsXMLString() { + StringWriter w = new StringWriter(); + Marshaller m = JAXBSupport.createMarshaller(true); + try { + m.marshal(this.definitions, w); + } catch (JAXBException e) { + AbstractComponentInstanceResource.logger.error("Could not marshal definitions", e); + throw new IllegalStateException(e); + } + String res = w.toString(); + return res; + } + + /** + * @return the reference to the internal Definitions object + */ + public Definitions getDefinitions() { + return this.definitions; + } + + @PUT + @Consumes({MimeTypes.MIMETYPE_TOSCA_DEFINITIONS, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + public Response updateDefinitions(InputStream requestBodyStream) { + Unmarshaller u; + Definitions defs; + Document doc; + final StringBuilder sb = new StringBuilder(); + try { + DocumentBuilder db = TOSCADocumentBuilderFactory.INSTANCE.getTOSCADocumentBuilder(); + db.setErrorHandler(new ErrorHandler() { + + @Override + public void warning(SAXParseException exception) throws SAXException { + // we don't care + } + + @Override + public void fatalError(SAXParseException exception) throws SAXException { + sb.append("Fatal Error: "); + sb.append(exception.getMessage()); + sb.append("\n"); + } + + @Override + public void error(SAXParseException exception) throws SAXException { + sb.append("Fatal Error: "); + sb.append(exception.getMessage()); + sb.append("\n"); + } + }); + doc = db.parse(requestBodyStream); + if (sb.length() > 0) { + // some error happened + // doc is not null, because the parser parses even if it is not XSD conforming + return Response.status(Status.BAD_REQUEST).entity(sb.toString()).build(); + } + } catch (SAXException | IOException e) { + AbstractComponentInstanceResource.logger.debug("Could not parse XML", e); + return Utils.getResponseForException(e); + } + try { + u = JAXBSupport.createUnmarshaller(); + defs = (Definitions) u.unmarshal(doc); + } catch (JAXBException e) { + AbstractComponentInstanceResource.logger.debug("Could not unmarshal from request body stream", e); + return Utils.getResponseForException(e); + } + + // initial validity check + + // we allow changing the target namespace and the id + // This allows for inserting arbitrary definitions XML + // if (!this.definitions.getTargetNamespace().equals(this.id.getNamespace().getDecoded())) { + // return Response.status(Status.BAD_REQUEST).entity("Changing of the namespace is not supported").build(); + // } + // this.definitions.setTargetNamespace(this.id.getNamespace().getDecoded()); + + // TODO: check the provided definitions for validity + + TExtensibleElements tExtensibleElements = defs.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + if (!tExtensibleElements.getClass().equals(this.createNewElement().getClass())) { + return Response.status(Status.BAD_REQUEST).entity("First type in Definitions is not matching the type modeled by this resource").build(); + } + + this.definitions = defs; + + // replace existing element by retrieved data + this.element = this.definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + + // ensure that ids did not change + // TODO: future work: raise error if user changed id or namespace + this.copyIdToFields(); + + return BackendUtils.persist(this); + } + + @GET + @Path("xml/") + @Produces(MediaType.TEXT_HTML) + public Response getXML() { + Viewable viewable = new Viewable("/jsp/xmlSource.jsp", this); + return Response.ok().entity(viewable).build(); + } + + @Path("documentation/") + public DocumentationsResource getDocumentationsResource() { + return new DocumentationsResource(this, this.getElement().getDocumentation()); + } + + @Path("tags/") + public final TagsResource getTags() { + return new TagsResource(this.id); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.java new file mode 100644 index 0000000..7bc7c73 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import java.lang.reflect.Method; + +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.model.tosca.TBoolean; +import org.eclipse.winery.model.tosca.TEntityType.DerivedFrom; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Models a component instance with name, derived from, abstract, and final <br /> + * Tags are provided by AbstractComponentInstanceResource + * + * This class mirrors + * AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinalConfigurationBacked + * . We did not include interfaces as the getters are currently only called at + * the jsp + */ +public abstract class AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal extends AbstractComponentInstanceResource { + + private static final Logger logger = LoggerFactory.getLogger(AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.class); + + + protected AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal(TOSCAComponentId id) { + super(id); + } + + /** + * @return The associated name of this resource. CSDPR01 foresees a NCName + * name and no ID for an entity type. Therefore, we use the ID as + * unique identification and convert it to a name when a read + * request is put. + */ + @GET + @Path("name") + public String getName() { + return ModelUtilities.getName(this.getElement()); + } + + @PUT + @Path("name") + public Response putName(String name) { + ModelUtilities.setName(this.getElement(), name); + return BackendUtils.persist(this); + } + + @GET + @Path("derivedFrom") + public String getDerivedFrom() { + // TOSCA does not introduce a type like WithNameDerivedFromAbstractFinal + // We could enumerate all possible implementing classes + // Or use java reflection, what we're doing now. + Method method; + // We have three different "DerivedFrom", for NodeTypeImplementation and RelationshipTypeImplementation, we have to assign to a different "DerivedFrom" + // This has to be done in the derived resources + DerivedFrom derivedFrom; + try { + method = this.getElement().getClass().getMethod("getDerivedFrom"); + derivedFrom = (DerivedFrom) method.invoke(this.getElement()); + } catch (ClassCastException e) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Seems that *Implementation is now Definitions backed, but not yet fully implented", e); + throw new IllegalStateException(e); + } catch (Exception e) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Could not get derivedFrom", e); + throw new IllegalStateException(e); + } + if (derivedFrom == null) { + return null; + } + QName typeRef = derivedFrom.getTypeRef(); + if (typeRef == null) { + return null; + } else { + return typeRef.toString(); + } + } + + @PUT + @Path("derivedFrom") + public Response putDerivedFrom(String type) { + QName qname = QName.valueOf(type); + + // see getDerivedFrom for verbose comments + Method method; + DerivedFrom derivedFrom = new DerivedFrom(); + derivedFrom.setTypeRef(qname); + try { + method = this.getElement().getClass().getMethod("setDerivedFrom", DerivedFrom.class); + method.invoke(this.getElement(), derivedFrom); + } catch (ClassCastException e) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Seems that *Implementation is now Definitions backed, but not yet fully implemented", e); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build(); + } catch (Exception e) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Could not set derivedFrom", e); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build(); + } + + return BackendUtils.persist(this); + } + + /** + * @param methodName the method to call: getAbstract|getFinal + * @return {@inheritDoc} + */ + private String getTBoolean(String methodName) { + // see getDerivedFrom for verbose comments + Method method; + TBoolean tBoolean; + try { + method = this.getElement().getClass().getMethod(methodName); + tBoolean = (TBoolean) method.invoke(this.getElement()); + } catch (Exception e) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Could not get boolean " + methodName, e); + throw new IllegalStateException(e); + } + if (tBoolean == null) { + return null; + } else { + return tBoolean.value(); + } + } + + /** + * @param methodName the method to call: setAbstract|setFinal + * @return {@inheritDoc} + */ + private Response putTBoolean(String tBooleanStr, String methodName) { + // see getDerivedFrom for verbose comments + + Method method; + TBoolean tBoolean = TBoolean.fromValue(tBooleanStr); + try { + method = this.getElement().getClass().getMethod(methodName, TBoolean.class); + method.invoke(this.getElement(), tBoolean); + } catch (Exception e) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Could not set tBoolean " + methodName, e); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build(); + } + + return BackendUtils.persist(this); + } + + /** + * Method name is not "getAbstract" as ${it.abstract} does not work as + * "abstract" is not allowed at that place + */ + @GET + @Path("abstract") + public String getIsAbstract() { + return this.getTBoolean("getAbstract"); + } + + @PUT + @Path("abstract") + public Response putIsAbstract(String isAbstract) { + return this.putTBoolean(isAbstract, "setAbstract"); + } + + @GET + @Path("final") + public String getIsFinal() { + return this.getTBoolean("getFinal"); + } + + @PUT + @Path("final") + public Response putIsFinal(String isFinal) { + return this.putTBoolean(isFinal, "setFinal"); + } + + /** + * @return resource managing abstract, final, derivedFrom + */ + @Path("inheritance/") + public InheritanceResource getInheritanceManagement() { + return new InheritanceResource(this); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceWithReferencesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceWithReferencesResource.java new file mode 100644 index 0000000..3b63b0f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceWithReferencesResource.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.Definitions; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; + +public abstract class AbstractComponentInstanceWithReferencesResource extends AbstractComponentInstanceResource { + + public AbstractComponentInstanceWithReferencesResource(TOSCAComponentId id) { + super(id); + } + + /** + * Ensures that the presented XML is in line with the stored files + */ + @Override + public Response getXML() { + this.synchronizeReferences(); + return super.getXML(); + } + + @Override + public String getDefinitionsAsXMLString() { + this.synchronizeReferences(); + return super.getDefinitionsAsXMLString(); + } + + @Override + public Definitions getDefinitions() { + this.synchronizeReferences(); + return super.getDefinitions(); + } + + /** + * Synchronizes the artifact references with the files stored in the + * repository + */ + public abstract void synchronizeReferences(); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsResource.java new file mode 100644 index 0000000..5702376 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsResource.java @@ -0,0 +1,279 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import java.io.StringWriter; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.SortedSet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +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 javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.PolicyTemplateId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +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.backend.ResourceCreationResult; +import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplatesResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import com.sun.jersey.api.NotFoundException; +import com.sun.jersey.api.view.Viewable; + +/** + * Resource handling of a set of components. Each component has to provide a + * class to handle the set. This is required to provide the correct instances of + * TOSCAcomponentIds. + * + * TODO: Add generics here! + * {@link Utils.getComponentIdClassForComponentContainer} is then obsolete + */ +public abstract class AbstractComponentsResource<R extends AbstractComponentInstanceResource> { + + protected static final Logger logger = LoggerFactory.getLogger(AbstractComponentsResource.class); + + + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML() { + return Response.ok().entity(new Viewable("/jsp/genericcomponentpage.jsp", new GenericComponentPageData(this.getClass()))).build(); + } + + /** + * Creates a new component instance in the given namespace + * + * @param namespace plain namespace + * @param id plain id + */ + protected ResourceCreationResult onPost(String namespace, String name) { + ResourceCreationResult res; + if (StringUtils.isEmpty(namespace) || StringUtils.isEmpty(name)) { + res = new ResourceCreationResult(Status.BAD_REQUEST); + } else { + String id = Utils.createXMLidAsString(name); + TOSCAComponentId tcId; + try { + tcId = this.getTOSCAcomponentId(namespace, id, false); + res = this.createComponentInstance(tcId); + // in case the resource additionally supports a name attribute, we set the original name + if (res.getStatus().equals(Status.CREATED)) { + if ((tcId instanceof ServiceTemplateId) || (tcId instanceof ArtifactTemplateId) || (tcId instanceof PolicyTemplateId)) { + // these three types have an additional name (instead of a pure id) + // we store the name + IHasName resource = (IHasName) AbstractComponentsResource.getComponentInstaceResource(tcId); + resource.setName(name); + } + } + } catch (Exception e) { + AbstractComponentsResource.logger.debug("Could not create id instance", e); + res = new ResourceCreationResult(Status.INTERNAL_SERVER_ERROR); + } + } + return res; + } + + /** + * Creates a new component instance in the given namespace + * + * @param namespace plain namespace + * @param id plain id + * @param ignored this parameter is ignored, but necessary for + * {@link ArtifactTemplatesResource} to be able to accept the + * artifact type at a post + */ + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + public Response onPost(@FormParam("namespace") String namespace, @FormParam("name") String name, String ignored) { + ResourceCreationResult res = this.onPost(namespace, name); + return res.getResponse(); + } + + /** + * Creates a TOSCAcomponentId for the given namespace / id combination + * + * Uses reflection to create a new instance + */ + protected TOSCAComponentId getTOSCAcomponentId(String namespace, String id, boolean URLencoded) throws Exception { + Class<? extends TOSCAComponentId> idClass = Utils.getComponentIdClassForComponentContainer(this.getClass()); + return BackendUtils.getTOSCAcomponentId(idClass, namespace, id, URLencoded); + } + + /** + * Creates a new instance of the current component + * + * @return <ul> + * <li>Status.CREATED (201) if the resource has been created,</li> + * <li>Status.CONFLICT if the resource already exists,</li> + * <li>Status.INTERNAL_SERVER_ERROR (500) if something went wrong</li> + * </ul> + */ + protected ResourceCreationResult createComponentInstance(TOSCAComponentId tcId) { + return BackendUtils.create(tcId); + } + + @SuppressWarnings("unchecked") + private static Class<? extends AbstractComponentInstanceResource> getComponentInstanceResourceClassForType(String type) { + // Guess the package + String pkg = "org.eclipse.winery.repository.resources."; + + pkg += Utils.getIntermediateLocationStringForType(type, "."); + + // naming convention: Instance is named after container, but without the + // plural s + String className = pkg + "." + type + "Resource"; + try { + return (Class<? extends AbstractComponentInstanceResource>) Class.forName(className); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Could not find id class for component instance", e); + } + } + + /** + * + * @param namespace encoded namespace + * @param id encoded id + * @return an instance of the requested resource + */ + @Path("{namespace}/{id}/") + public R getComponentInstaceResource(@PathParam("namespace") String namespace, @PathParam("id") String id) { + return this.getComponentInstaceResource(namespace, id, true); + } + + /** + * @param encoded specifies whether namespace and id are encoded + * @return an instance of the requested resource + */ + @SuppressWarnings("unchecked") + public R getComponentInstaceResource(String namespace, String id, boolean encoded) { + TOSCAComponentId tcId; + try { + tcId = this.getTOSCAcomponentId(namespace, id, encoded); + } catch (Exception e) { + throw new IllegalStateException("Could not create id instance", e); + } + return (R) AbstractComponentsResource.getComponentInstaceResource(tcId); + } + + /** + * @return an instance of the requested resource + */ + public AbstractComponentInstanceResource getComponentInstaceResource(QName qname) { + return this.getComponentInstaceResource(qname.getNamespaceURI(), qname.getLocalPart(), false); + } + + /** + * @return an instance of the requested resource + * @throws NotFoundException if resource doesn't exist. + */ + public static AbstractComponentInstanceResource getComponentInstaceResource(TOSCAComponentId tcId) { + String type = Util.getTypeForComponentId(tcId.getClass()); + if (!Repository.INSTANCE.exists(tcId)) { + AbstractComponentsResource.logger.debug("TOSCA component id " + tcId.toString() + " not found"); + throw new NotFoundException("TOSCA component id " + tcId.toString() + " not found"); + } + Class<? extends AbstractComponentInstanceResource> newResource = AbstractComponentsResource.getComponentInstanceResourceClassForType(type); + Constructor<?>[] constructors = newResource.getConstructors(); + assert (constructors.length == 1); + AbstractComponentInstanceResource newInstance; + try { + newInstance = (AbstractComponentInstanceResource) constructors[0].newInstance(tcId); + } catch (InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException e) { + AbstractComponentsResource.logger.error("Could not instantiate sub resource " + tcId); + throw new IllegalStateException("Could not instantiate sub resource", e); + } + return newInstance; + } + + /** + * Returns resources for all known component instances + * + * Required by topologytemplateedit.jsp + */ + public Collection<AbstractComponentInstanceResource> getAll() { + Class<? extends TOSCAComponentId> idClass = Utils.getComponentIdClassForComponentContainer(this.getClass()); + SortedSet<? extends TOSCAComponentId> allTOSCAcomponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(idClass); + ArrayList<AbstractComponentInstanceResource> res = new ArrayList<AbstractComponentInstanceResource>(allTOSCAcomponentIds.size()); + for (TOSCAComponentId id : allTOSCAcomponentIds) { + AbstractComponentInstanceResource r = AbstractComponentsResource.getComponentInstaceResource(id); + res.add(r); + } + return res; + } + + /** + * Used by org.eclipse.winery.repository.repository.client and by the + * artifactcreationdialog.tag. Especially the "name" field is used there at + * the UI + * + * @return A list of all ids of all instances of this component type. If the + * "name" attribute is required, that name is used as id <br /> + * Format: + * <code>[({"namespace": "<namespace>", "id": "<id>"},)* ]</code>. A + * <code>name<code> field is added if the model allows an additional name attribute + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public String getListOfAllIds() { + Class<? extends TOSCAComponentId> idClass = Utils.getComponentIdClassForComponentContainer(this.getClass()); + boolean supportsNameAttribute = Util.instanceSupportsNameAttribute(idClass); + SortedSet<? extends TOSCAComponentId> allTOSCAcomponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(idClass); + JsonFactory jsonFactory = new JsonFactory(); + StringWriter sw = new StringWriter(); + + try { + JsonGenerator jg = jsonFactory.createGenerator(sw); + // We produce org.eclipse.winery.repository.client.WineryRepositoryClient.NamespaceAndId by hand here + // Refactoring could move this class to common and fill it here + jg.writeStartArray(); + for (TOSCAComponentId id : allTOSCAcomponentIds) { + jg.writeStartObject(); + jg.writeStringField("namespace", id.getNamespace().getDecoded()); + jg.writeStringField("id", id.getXmlId().getDecoded()); + if (supportsNameAttribute) { + AbstractComponentInstanceResource componentInstaceResource = AbstractComponentsResource.getComponentInstaceResource(id); + String name = ((IHasName) componentInstaceResource).getName(); + jg.writeStringField("name", name); + } + jg.writeEndObject(); + } + jg.writeEndArray(); + jg.close(); + } catch (Exception e) { + AbstractComponentsResource.logger.error(e.getMessage(), e); + return "[]"; + } + return sw.toString(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsWithTypeReferenceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsWithTypeReferenceResource.java new file mode 100644 index 0000000..33bc1d4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsWithTypeReferenceResource.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +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.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.repository.backend.ResourceCreationResult; +import org.restdoc.annotations.RestDocParam; + +/** + * This class does NOT inherit from TEntityTemplatesResource<ArtifactTemplate> + * as these templates are directly nested in a TDefinitionsElement + */ +public abstract class AbstractComponentsWithTypeReferenceResource<T extends AbstractComponentInstanceResource> extends AbstractComponentsResource<T> { + + /** + * Creates the resource and sets the specified type + * + * In contrast to the other component instances in this package, we + * additionally need the parameter "type" to set the type of the artifact + * template. + * + * @param namespace Namespace of the template + * @param name name attribute of the template + * @param type: QName of the type, format: {namespace}localname is retrieved + * from namespace manager + * + * @return URI of the created Resource, null if resource already exists, + * URI_internalServerError if an internal server error occurred + */ + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + @Override + public Response onPost(@RestDocParam(description = "Namespace of the component") @FormParam("namespace") String namespace, @RestDocParam(description = "name attribute of the component") @FormParam("name") String name, @RestDocParam(description = "QName of the type, format: {namespace}localname") @FormParam("type") String type) { + // only check for type parameter as namespace and name are checked in super.onPost + if (StringUtils.isEmpty(type)) { + return Response.status(Status.BAD_REQUEST).build(); + } + ResourceCreationResult creationResult = super.onPost(namespace, name); + if (!creationResult.isSuccess()) { + return creationResult.getResponse(); + } + if (creationResult.getStatus().equals(Status.CREATED)) { + IHasTypeReference resource = (IHasTypeReference) AbstractComponentsResource.getComponentInstaceResource((TOSCAComponentId) creationResult.getId()); + resource.setType(type); + // we assume that setType succeeded and just return the result of the + // creation of the artifact template resource + // Thus, we do NOT change res + } + return creationResult.getResponse(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintResource.java new file mode 100644 index 0000000..b9eb345 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintResource.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TConstraint; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; + +public class ConstraintResource extends EntityWithoutIdResource<TConstraint> { + + /** + * + * @param constraint the current constraint value + * @param list the list this constraint belongs to + * @param res the node type resource this constraint belongs to. Required + * for saving + */ + public ConstraintResource(TConstraint constraint, int idx, List<TConstraint> list, NodeTypeResource res) { + super(constraint, idx, list, res); + } + + /** + * Required for collectionResource + * + * @throws ClassCastException of !(res instanceof NodeTypeResource) + */ + public ConstraintResource(TConstraint constraint, int idx, List<TConstraint> list, AbstractComponentInstanceResource res) { + this(constraint, idx, list, (NodeTypeResource) res); + } + + private TConstraint getConstraint() { + return this.o; + } + + @GET + @Path("type") + @Produces(MediaType.TEXT_PLAIN) + public String getConstraintType() { + return this.getConstraint().getConstraintType(); + } + + @PUT + @Path("type") + @Consumes(MediaType.TEXT_PLAIN) + public Response putConstraintType(String constraintType) { + this.getConstraint().setConstraintType(constraintType); + return BackendUtils.persist(this.res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintsResource.java new file mode 100644 index 0000000..8aea92f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintsResource.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TConstraint; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class ConstraintsResource extends EntityWithoutIdCollectionResource<ConstraintResource, TConstraint> { + + private static final Logger logger = LoggerFactory.getLogger(ConstraintsResource.class); + + + public ConstraintsResource(List<TConstraint> constraints, NodeTypeResource res) { + super(ConstraintResource.class, TConstraint.class, constraints, res); + } + + @Override + public Viewable getHTML() { + // TODO Auto-generated method stub + throw new IllegalStateException("Not yet implemented."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/EntityTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/EntityTypeResource.java new file mode 100644 index 0000000..1b70d56 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/EntityTypeResource.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import java.util.Collection; +import java.util.SortedSet; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.datatypes.select2.Select2DataWithOptGroups; +import org.eclipse.winery.repository.datatypes.select2.Select2OptGroup; +import org.eclipse.winery.repository.resources.entitytypes.properties.PropertiesDefinitionResource; + +public abstract class EntityTypeResource extends AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal { + + protected EntityTypeResource(TOSCAComponentId id) { + super(id); + } + + @Override + protected void copyIdToFields() { + TEntityType entityType = this.getEntityType(); + entityType.setTargetNamespace(this.getId().getNamespace().getDecoded()); + entityType.setName(this.getId().getXmlId().getDecoded()); + } + + /** + * Convenience method to avoid casting. Required by + * PropertiesDefinitionResource's jsp + */ + public TEntityType getEntityType() { + return (TEntityType) this.element; + } + + /** + * Models PropertiesDefinition + */ + @Path("propertiesdefinition/") + public PropertiesDefinitionResource getPropertiesDefinitionResource() { + return new PropertiesDefinitionResource(this); + } + + /** + * Used by children to implement getListOfAllInstances() + */ + protected SortedSet<Select2OptGroup> getListOfAllInstances(Class<? extends TOSCAComponentId> clazz) { + Select2DataWithOptGroups data = new Select2DataWithOptGroups(); + + Collection<? extends TOSCAComponentId> instanceIds = BackendUtils.getAllElementsRelatedWithATypeAttribute(clazz, this.id.getQName()); + + for (TOSCAComponentId instanceId : instanceIds) { + String groupText = instanceId.getNamespace().getDecoded(); + String text = BackendUtils.getName(instanceId); + data.add(groupText, instanceId.getQName().toString(), text); + } + + return data.asSortedSet(); + } + + /** + * Returns an array suitable for processing in a {@code select2} field See + * {@link http://ivaynberg.github.io/select2} + * + * Each element: {id: "{ns}localname", text: "name/id"} + */ + @Path("instances/") + @GET + @Produces(MediaType.APPLICATION_JSON) + public SortedSet<Select2OptGroup> getListOfAllInstances() { + Response res = Response.status(Status.INTERNAL_SERVER_ERROR).entity("not yet implemented").build(); + throw new WebApplicationException(res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericComponentPageData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericComponentPageData.java new file mode 100644 index 0000000..a2a8533 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericComponentPageData.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import java.util.Collection; +import java.util.Collections; +import java.util.SortedSet; + +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.common.ids.definitions.PolicyTypeId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplatesResource; +import org.eclipse.winery.repository.resources.entitytemplates.policytemplates.PolicyTemplatesResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationsResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationsResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class GenericComponentPageData { + + private static final Logger logger = LoggerFactory.getLogger(GenericComponentPageData.class); + + private final SortedSet<? extends TOSCAComponentId> componentInstanceIds; + + private final Class<? extends AbstractComponentsResource> resourceClass; + + + public GenericComponentPageData(Class<? extends AbstractComponentsResource> resourceClass) { + this.resourceClass = resourceClass; + Class<? extends TOSCAComponentId> cIdClass = Utils.getComponentIdClassForComponentContainer(resourceClass); + this.componentInstanceIds = Repository.INSTANCE.getAllTOSCAComponentIds(cIdClass); + } + + /** + * Outputs the data for GenericComponentPage (Name / Id / Namespace) needed + * for the genericcomponentpage.jsp + */ + public SortedSet<? extends TOSCAComponentId> getComponentInstanceIds() { + return this.componentInstanceIds; + } + + public String getType() { + return Utils.getTypeForComponentContainer(this.resourceClass); + } + + public String getCSSclass() { + // The resources do NOT know their CSS class + // Layout is far away from a resource + // Instead of a huge if/else-cascade, we derive the CSS name from the + // class name + String type = this.getType(); + // convention: first letter in small letters + String res = type.substring(0, 1).toLowerCase() + type.substring(1); + // this generated "xSDImport" as CSS class for XSDImport + return res; + } + + public String getLabel() { + String type = this.getType(); + // E.g., convert ArtifactTemplate to Artifact Template + String res = type.replaceAll("(\\p{Lower})(\\p{Upper})", "$1 $2"); + return res; + } + + /** + * Required for genericcomponentpage.jsp -> addComponentInstance.jsp + * + * May only be used if the component supports the type (e.g., artifact + * templates) + * + * @return the list of all known <em>types</em> + */ + public Collection<? extends TOSCAComponentId> getTypeSelectorData() { + Class<? extends TOSCAComponentId> typeIdClass; + if (this.resourceClass.equals(ArtifactTemplatesResource.class)) { + typeIdClass = ArtifactTypeId.class; + } else if (this.resourceClass.equals(NodeTypeImplementationsResource.class)) { + typeIdClass = NodeTypeId.class; + } else if (this.resourceClass.equals(RelationshipTypeImplementationsResource.class)) { + typeIdClass = RelationshipTypeId.class; + } else if (this.resourceClass.equals(PolicyTemplatesResource.class)) { + typeIdClass = PolicyTypeId.class; + } else { + return Collections.emptyList(); + } + SortedSet<? extends TOSCAComponentId> allTOSCAcomponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(typeIdClass); + return allTOSCAcomponentIds; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericVisualAppearanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericVisualAppearanceResource.java new file mode 100644 index 0000000..51bbcf1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericVisualAppearanceResource.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import java.io.InputStream; +import java.net.URI; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.elements.TOSCAElementId; +import org.eclipse.winery.repository.Prefs; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.constants.Filename; +import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId; +import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource; + +//import com.fasterxml.jackson.annotation.JsonIgnore; // currently not required +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + +/** + * Contains methods for both visual appearance for + * <ul> + * <li>node types</li> + * <li>relationship types</li> + * </ul> + */ +public abstract class GenericVisualAppearanceResource { + + protected final Map<QName, String> otherAttributes; + protected final TopologyGraphElementEntityTypeResource res; + protected final TOSCAElementId id; + + + @DELETE + public Response onDelete() { + return BackendUtils.delete(this.id); + } + + /** + * Used for GUI when accessing the resource as data E.g., for topology + * template + */ + //@JsonIgnore + public URI getAbsoluteURL() { + String URI = Prefs.INSTANCE.getResourcePath(); + URI = URI + "/" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(this.id)); + return Utils.createURI(URI); + } + + //@JsonIgnore + public TOSCAElementId getId() { + return this.id; + } + + /** + * @param res + * @param otherAttributes the other attributes of the node/relationship type + * @param id the id of this subresource required for storing the images + */ + public GenericVisualAppearanceResource(TopologyGraphElementEntityTypeResource res, Map<QName, String> otherAttributes, VisualAppearanceId id) { + this.id = id; + this.res = res; + this.otherAttributes = otherAttributes; + } + + /** + * Determines repository reference to file in repo + */ + protected RepositoryFileReference getRepoFileRef(String name) { + return new RepositoryFileReference(this.id, name); + } + + protected Response getImage(String name, String modified) { + RepositoryFileReference target = this.getRepoFileRef(name); + return BackendUtils.returnRepoPath(target, modified); + } + + /** + * Arbitrary images are supported. There currently is no check for valid + * image media types + */ + protected Response putImage(String name, InputStream uploadedInputStream, MediaType mediaType) { + RepositoryFileReference target = this.getRepoFileRef(name); + return BackendUtils.putContentToFile(target, uploadedInputStream, mediaType); + } + + @GET + @Path("16x16") + public Response get16x16Image(@HeaderParam("If-Modified-Since") String modified) { + // Even if the extension is "png", it might contain a jpg, too + // We keep the file extension as the windows explorer can display previews even if the content is not a png + return this.getImage(Filename.FILENAME_SMALL_ICON, modified); + } + + @PUT + @Path("16x16") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response post16x16Image(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataBodyPart body) { + return this.putImage(Filename.FILENAME_SMALL_ICON, uploadedInputStream, body.getMediaType()); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasName.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasName.java new file mode 100644 index 0000000..08a3696 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasName.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.restdoc.annotations.RestDoc; + +/** + * Ensures that the AbstractComponentInstance has a getName method + */ +public interface IHasName { + + @GET + @Path("name") + // @formatter:off + @RestDoc(methodDescription = "Returns the name of the element. " + + "Defaults to the ID of the element. " + + "Some other ComponentInstances either carry a name or an ID. ") + // @formatter:on + @Produces(MediaType.TEXT_PLAIN) + public String getName(); + + @PUT + @Path("name") + public Response setName(@FormParam("value") String name); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasTypeReference.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasTypeReference.java new file mode 100644 index 0000000..cb42158 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasTypeReference.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +public interface IHasTypeReference { + + /** + * @return the QName of the type with full namespace, never null (according + * to spec) + */ + public QName getType(); + + /** + * Sets the type and directly persists the resource + */ + public Response setType(QName type); + + /** + * Calls setType(QName) with QName.valueOf(typeStr) + * + * Directly persists the resource + * + * @param typeStr a textual representation of a QName + */ + public Response setType(String typeStr); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResource.java new file mode 100644 index 0000000..c8438ef --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResource.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +/** + * Implementors can have DAs attached + */ +public interface INodeTemplateResourceOrNodeTypeImplementationResource extends INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java new file mode 100644 index 0000000..7bd178e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import org.eclipse.winery.common.ids.Namespace; + +/** + * Implementors can have IAs or DAs attached + */ +public interface INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource { + + Namespace getNamespace(); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java new file mode 100644 index 0000000..892a7cb --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +/** + * Implementors can have IAs attached + */ +public interface INodeTypeImplementationResourceOrRelationshipTypeImplementationResource extends INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/InheritanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/InheritanceResource.java new file mode 100644 index 0000000..7cc878a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/InheritanceResource.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.repository.backend.Repository; + +import com.sun.jersey.api.view.Viewable; + +/** + * Class for managing inheritance properties: abstract, final, derivedFromn + * + * The linking in the resources tree is different than the others. Here, there + * is no additional Id generated. + * + * We separated the code here to have the collection of valid super types in a + * separate class. We think, this is less confusing than including this + * functionality in + * AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinalDefinitionsBacked + */ +public class InheritanceResource { + + private AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal managedResource; + + + public InheritanceResource(AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal res) { + this.managedResource = res; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/inheritance.jsp", this); + } + + public String getIsAbstract() { + return this.managedResource.getIsAbstract(); + } + + public String getIsFinal() { + return this.managedResource.getIsAbstract(); + } + + public String getDerivedFrom() { + return this.managedResource.getDerivedFrom(); + } + + /** JSP Data **/ + + public SortedSet<? extends TOSCAComponentId> getPossibleSuperTypes() { + // sorted by Name, not by namespace + SortedSet<? extends TOSCAComponentId> allTOSCAcomponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(this.managedResource.getId().getClass()); + SortedSet<? extends TOSCAComponentId> res = new TreeSet<>(allTOSCAcomponentIds); + res.remove(this.managedResource.getId()); + // FEATURE: Possibly exclude all subtypes to avoid circles. However, this could be disappointing for users who know what they are doing + return res; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/MainResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/MainResource.java new file mode 100644 index 0000000..87b5275 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/MainResource.java @@ -0,0 +1,189 @@ +/******************************************************************************* + * 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; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +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.io.FileUtils; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.importing.CSARImporter; +import org.eclipse.winery.repository.resources.API.APIResource; +import org.eclipse.winery.repository.resources.admin.AdminTopResource; +import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplatesResource; +import org.eclipse.winery.repository.resources.entitytemplates.policytemplates.PolicyTemplatesResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationsResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationsResource; +import org.eclipse.winery.repository.resources.entitytypes.artifacttypes.ArtifactTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.capabilitytypes.CapabilityTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.policytypes.PolicyTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.requirementtypes.RequirementTypesResource; +import org.eclipse.winery.repository.resources.imports.ImportsResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplatesResource; +import org.restdoc.annotations.RestDoc; +import org.restdoc.annotations.RestDocParam; +import org.restdoc.annotations.RestDocReturnCode; + +import com.sun.jersey.api.view.Viewable; +import com.sun.jersey.core.header.FormDataContentDisposition; +import com.sun.jersey.multipart.FormDataParam; + +/** + * All paths listed here have to be listed in Jersey's filter configuration + */ +@Path("/") +public class MainResource { + + @Path("API/") + public APIResource api() { + return new APIResource(); + } + + @Path("artifacttemplates/") + public ArtifactTemplatesResource artifacttemplates() { + return new ArtifactTemplatesResource(); + } + + @Path("artifacttypes/") + public ArtifactTypesResource artifactypes() { + return new ArtifactTypesResource(); + } + + @Path("admin/") + public AdminTopResource admin() { + return new AdminTopResource(); + } + + @Path("capabilitytypes/") + public CapabilityTypesResource capabilitytypes() { + return new CapabilityTypesResource(); + } + + @Path("imports/") + public ImportsResource imports() { + return new ImportsResource(); + } + + @Path("nodetypes/") + public NodeTypesResource nodetypes() { + return new NodeTypesResource(); + } + + @Path("nodetypeimplementations/") + public NodeTypeImplementationsResource nodetypeimplementations() { + return new NodeTypeImplementationsResource(); + } + + @Path("other/") + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getOtherElements() { + return new Viewable("/jsp/otherElements.jsp"); + } + + @Path("policytemplates/") + public PolicyTemplatesResource policytemplates() { + return new PolicyTemplatesResource(); + } + + @Path("policytypes/") + public PolicyTypesResource policytypes() { + return new PolicyTypesResource(); + } + + @Path("relationshiptypes/") + public RelationshipTypesResource relationshiptypes() { + return new RelationshipTypesResource(); + } + + @Path("requirementtypes/") + public RequirementTypesResource requirementtypes() { + return new RequirementTypesResource(); + } + + @Path("relationshiptypeimplementations/") + public RelationshipTypeImplementationsResource relationshiptypeimplementations() { + return new RelationshipTypeImplementationsResource(); + } + + @Path("servicetemplates/") + public ServiceTemplatesResource servicetemplates() { + return new ServiceTemplatesResource(); + } + + /** + * Returns the main page of winery. + */ + @GET + @Produces(MediaType.TEXT_HTML) + public Response onGet() { + return Response.temporaryRedirect(Utils.createURI("servicetemplates/")).build(); + } + + @POST + @Consumes(MediaType.MULTIPART_FORM_DATA) + @RestDoc(methodDescription = "Imports the given CSAR (sent by simplesinglefileupload.jsp)") + @RestDocReturnCode(code = "200", description = "If the CSAR could be partially imported, the points where it failed are returned in the body") + // @formatter:off + public Response importCSAR( + @FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail, + @FormDataParam("overwrite") @RestDocParam(description = "true: content of CSAR overwrites existing content. false (default): existing content is kept") Boolean overwrite) { + // @formatter:on + CSARImporter importer = new CSARImporter(); + List<String> errors = new ArrayList<String>(); + boolean ow; + ow = (overwrite != null) && overwrite; + try { + importer.readCSAR(uploadedInputStream, errors, ow, true); + } catch (Exception e) { + return Response.serverError().entity("Could not import CSAR").entity(e.getMessage()).build(); + } + if (errors.isEmpty()) { + return Response.noContent().build(); + } else { + // In case there are errors, we send them as "bad request" + return Response.status(Status.BAD_REQUEST).entity(errors).build(); + } + } + + @POST + @Consumes(MediaType.APPLICATION_XML) + @Produces(MediaType.APPLICATION_JSON) + public Response importDefinitions(InputStream is) throws IOException { + File toscaFile; + toscaFile = File.createTempFile("TOSCA", ".tosca"); + FileUtils.copyInputStreamToFile(is, toscaFile); + CSARImporter importer = new CSARImporter(); + List<String> errors = new ArrayList<>(); + importer.importDefinitions(null, toscaFile.toPath(), errors, false, true); + if (errors.isEmpty()) { + return Response.noContent().build(); + } else { + return Response.status(Status.BAD_REQUEST).entity(errors).build(); + } + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/SubMenuData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/SubMenuData.java new file mode 100644 index 0000000..3f79c87 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/SubMenuData.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +/** + * Data used to render a submenu item + */ +public class SubMenuData { + + private final String href; + private final String text; + + public static final SubMenuData SUBMENU_DOCUMENTATION = new SubMenuData("#documentation", "Documentation"); + public static final SubMenuData SUBMENU_XML = new SubMenuData("#xml", "XML"); + + + public SubMenuData(String href, String text) { + this.href = href; + this.text = text; + } + + public String getHref() { + return this.href; + } + + public String getText() { + return this.text; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/IPersistable.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/IPersistable.java new file mode 100644 index 0000000..85f565c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/IPersistable.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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._support; + +import java.io.IOException; + +public interface IPersistable { + + /** + * @throws IOException if content could not be updated in the repository + * @throws IllegalStateException if an JAXBException occurred. This should + * never happen. + */ + public void persist() throws IOException; +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/CollectionsHelper.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/CollectionsHelper.java new file mode 100644 index 0000000..f150855 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/CollectionsHelper.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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._support.collections; + +import javax.ws.rs.core.Response; + +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; + +public class CollectionsHelper { + + private CollectionsHelper() { + } + + /** + * + * @param <X> + * @param resource the resource to be persisted + * @param idDetermination the object to use to determine the id of the + * entity + * @param entity the entity that was persisted. Used to determine the id + * @return the new id id of the resource + */ + public static <X> Response persist(IPersistable resource, IIdDetermination<X> idDetermination, X entity) { + Response res = BackendUtils.persist(resource); + if (res.getStatus() == 204) { + String id = idDetermination.getId(entity); + res = Response.ok(id).build(); + } + return res; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityCollectionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityCollectionResource.java new file mode 100644 index 0000000..64d0fbe --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityCollectionResource.java @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 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._support.collections; + +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.datatypes.select2.Select2DataItem; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.restdoc.annotations.RestDoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.NotFoundException; +import com.sun.jersey.api.view.Viewable; + +/** + * Class managing a list of entities. It is intended to manage subresources, + * which are stored in a list. Either all entities have a unique key given by + * the TOSCA specification (subclass EntityWithIdCollectionResource) or a unique + * key is generated (subclass EntityWithoutIdCollectionResource) + * + * @param <EntityResourceT> the resource modeling the entity + * @param <EntityT> the entity type of single items in the list + */ +public abstract class EntityCollectionResource<EntityResourceT extends EntityResource<EntityT>, EntityT> implements IIdDetermination<EntityT> { + + private static final Logger logger = LoggerFactory.getLogger(EntityCollectionResource.class); + + protected final List<EntityT> list; + + protected final IPersistable res; + + protected final Class<EntityT> entityTClazz; + + protected final Class<EntityResourceT> entityResourceTClazz; + + + /** + * @param clazz the class of EntityT. Required as it is not possible to call + * new EntityT (see http://stackoverflow.com/a/1090488/873282) + * @param list the list of entities contained in this resource. Has to be + * typed <Object> as not all TOSCA elements in the specification + * inherit from TExtensibleElements + * @param res the main resource the list is belonging to. Required for + * persistence. + */ + public EntityCollectionResource(Class<EntityResourceT> entityResourceTClazz, Class<EntityT> entityTClazz, List<EntityT> list, IPersistable res) { + this.entityResourceTClazz = entityResourceTClazz; + this.entityTClazz = entityTClazz; + this.list = list; + this.res = res; + } + + /** + * Returns a list of ids of all entities nested here + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public Object getListOfAllEntityIds(@QueryParam("select2") String select2) { + if (select2 == null) { + return this.getListOfAllEntityIdsAsList(); + } else { + // return data ready for consumption by select2 + List<Select2DataItem> res = new ArrayList<Select2DataItem>(this.list.size()); + for (EntityT o : this.list) { + String id = this.getId(o); + Select2DataItem di = new Select2DataItem(id, id); + res.add(di); + } + return res; + } + } + + public List<String> getListOfAllEntityIdsAsList() { + List<String> res = new ArrayList<String>(this.list.size()); + for (EntityT o : this.list) { + // We assume that different Object serializations *always* have different hashCodes + res.add(this.getId(o)); + } + return res; + } + + /** + * Required by reqandcapdefs.jsp + */ + public List<EntityResourceT> getAllEntityResources() { + List<String> listOfAllSubResources = this.getListOfAllEntityIdsAsList(); + List<EntityResourceT> res = new ArrayList<EntityResourceT>(listOfAllSubResources.size()); + for (String id : listOfAllSubResources) { + res.add(this.getEntityResourceFromDecodedId(id)); + } + return res; + } + + public EntityResourceT getEntityResourceFromDecodedId(String id) { + EntityT entity = null; + int idx = -1; + for (EntityT c : this.list) { + idx++; + String cId = this.getId(c); + if (cId.equals(id)) { + entity = c; + break; + } + } + if (entity == null) { + throw new NotFoundException(); + } else { + return this.getEntityResourceInstance(entity, idx); + } + } + + @Path("{id}/") + public EntityResourceT getEntityResource(@PathParam("id") String id) { + if (id == null) { + throw new IllegalArgumentException("id has to be given"); + } + id = Util.URLdecode(id); + return this.getEntityResourceFromDecodedId(id); + } + + /** + * @param entity the entity to create a resource for + * @param idx the index in the list + * @return the resource managing the given entity + */ + protected abstract EntityResourceT getEntityResourceInstance(EntityT entity, int idx); + + @GET + @Produces(MediaType.TEXT_HTML) + @RestDoc(methodDescription = "@return the HTML fragment (DIV-container) to be embedded in the 'Interface' part of nodetype.js ") + public Response getHTMLAsResponse() { + Viewable viewable = this.getHTML(); + return Response.ok().header(HttpHeaders.VARY, HttpHeaders.ACCEPT).entity(viewable).build(); + } + + /** + * called by getHTMLAsResponse + */ + public abstract Viewable getHTML(); + + /** + * Adds a new entity + * + * In case the element already exists, we return "CONFLICT" + */ + @POST + @Consumes({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + public Response addNewElement(EntityT entity) { + if (entity == null) { + return Response.status(Status.BAD_REQUEST).entity("a valid XML/JSON element has to be posted").build(); + } + if (this.alreadyContains(entity)) { + // we do not replace the element, but replace it + return Response.status(Status.CONFLICT).build(); + } + this.list.add(entity); + return CollectionsHelper.persist(this.res, this, entity); + } + + @Override + public abstract String getId(EntityT entity); + + /** + * Checks for containment of e in the list. <code>equals</code> is not used + * as most EntityT do not offer a valid implementation + * + * @return true if list already contains e. + */ + public boolean alreadyContains(EntityT e) { + String id = this.getId(e); + for (EntityT el : this.list) { + if (this.getId(el).equals(id)) { + // break loop + // we found an equal list item + return true; + } + } + // all items checked: nothing equal contained + return false; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityResource.java new file mode 100644 index 0000000..361fcfb --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityResource.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,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._support.collections; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +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.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; + +/** + * Class to hold a single entity residing in a list of entities + * + * @param <EntityT> the entity type contained in the list + */ +public abstract class EntityResource<EntityT> { + + // This is non-final as a "PUT" may update the object + // it might be unnecessary to update this object as the resource is created at each request + // We update the reference nevertheless to be safe if the resource is used in another context + protected EntityT o; + + protected final int idx; + + protected final List<EntityT> list; + + protected final IPersistable res; + + protected IIdDetermination<EntityT> idDetermination; + + + /** + * + * @param idDetermination the object offering determination of an id of + * EntityT. May be null. If null, then setIdDetermination(obj) + * has to be called to enable this class functioning properly + * @param o the object this resource is representing + * @param idx the index of the object in the list + * @param list the list, where the object is stored in + * @param res the resource the object/list belongs to + */ + public EntityResource(IIdDetermination<EntityT> idDetermination, EntityT o, int idx, List<EntityT> list, IPersistable res) { + this.idDetermination = idDetermination; + this.o = o; + this.idx = idx; + this.list = list; + this.res = res; + } + + /** + * Quick hack for AbstractReqOrCapDefResource which is itself an + * IIdDetermination + */ + protected final void setIdDetermination(IIdDetermination<EntityT> idDetermination) { + this.idDetermination = idDetermination; + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getJSON() { + assert (this.o != null); + return Response.ok().entity(this.o).build(); + } + + @GET + @Produces(MediaType.TEXT_XML) + @SuppressWarnings("unchecked") + public Response getXML() { + assert (this.o != null); + // Utils.getXML has to be used as Jersey can only serialize XMLRootElements + return Utils.getXML((Class<EntityT>) this.o.getClass(), this.o); + } + + /** + * Replaces the whole entity by the given entity + * + * As we use the hash code as index, the index changes when the resource is + * updated. This is not in line with REST. The alternative implementation is + * to use the index in the list as resource identification. That changes at + * each modification of the list itself (if elements are deleted / inserted + * before the current entry). When using the hash value, users may + * concurrently edit items and the list may also be updated + * + * @return the new id. + */ + @PUT + @Consumes(MediaType.TEXT_XML) + @Produces(MediaType.TEXT_PLAIN) + public Response setValue(EntityT o) { + this.list.set(this.idx, o); + this.o = o; + return CollectionsHelper.persist(this.res, this.idDetermination, o); + } + + @DELETE + public Response onDelete() { + try { + this.list.remove(this.idx); + } catch (IndexOutOfBoundsException e) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not delete entity, even if it should exist").build(); + } + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/IIdDetermination.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/IIdDetermination.java new file mode 100644 index 0000000..e479e70 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/IIdDetermination.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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._support.collections; + +public interface IIdDetermination<EntityT> { + + /** + * @return the id of the given entity + */ + public String getId(EntityT e); +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdCollectionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdCollectionResource.java new file mode 100644 index 0000000..f428752 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdCollectionResource.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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._support.collections.withid; + +import java.lang.reflect.Constructor; +import java.util.List; + +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.EntityCollectionResource; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class EntityWithIdCollectionResource<EntityResourceT extends EntityWithIdResource<EntityT>, EntityT> extends EntityCollectionResource<EntityResourceT, EntityT> { + + private static final Logger logger = LoggerFactory.getLogger(EntityWithIdCollectionResource.class); + + + /** + * {@inheritDoc} + */ + public EntityWithIdCollectionResource(Class<EntityResourceT> entityResourceTClazz, Class<EntityT> entityTClazz, List<EntityT> list, IPersistable res) { + super(entityResourceTClazz, entityTClazz, list, res); + } + + /** + * Each CollectionResource has to implement the id getting by itself as + * TOSCA XSD does not provide a general purpose id fetching mechanism + */ + @Override + public abstract String getId(EntityT entity); + + @Override + protected EntityResourceT getEntityResourceInstance(EntityT entity, int idx) { + Constructor<EntityResourceT> constructor; + try { + constructor = this.entityResourceTClazz.getConstructor(IIdDetermination.class, this.entityTClazz, int.class, List.class, this.res.getClass()); + } catch (Exception e) { + try { + constructor = this.entityResourceTClazz.getConstructor(IIdDetermination.class, this.entityTClazz, int.class, List.class, IPersistable.class); + } catch (Exception e2) { + EntityWithIdCollectionResource.logger.debug("Could not get constructor", e); + EntityWithIdCollectionResource.logger.debug("res.getClass() was {}", this.res.getClass()); + throw new IllegalStateException(e2); + } + } + EntityResourceT newInstance; + try { + newInstance = constructor.newInstance(this, entity, idx, this.list, this.res); + } catch (Exception e) { + EntityWithIdCollectionResource.logger.debug("Could not instantiate class", e); + throw new IllegalStateException(e); + } + return newInstance; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdResource.java new file mode 100644 index 0000000..1ac6775 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdResource.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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._support.collections.withid; + +import java.util.List; + +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.EntityResource; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; + +public class EntityWithIdResource<EntityT> extends EntityResource<EntityT> { + + /** + * {@inheritDoc} + */ + public EntityWithIdResource(IIdDetermination<EntityT> idDetermination, EntityT o, int idx, List<EntityT> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdCollectionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdCollectionResource.java new file mode 100644 index 0000000..8255f5d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdCollectionResource.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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._support.collections.withoutid; + +import java.lang.reflect.Constructor; +import java.util.List; + +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.EntityCollectionResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.NotFoundException; + +/** + * Class managing a list of entities. It is intended to manage subresources, + * where the TOSCA specification did not specify a unique key. Currently, the + * hashCode of the XML String representation is used. If other representation + * should be used, the method {@code getEntityResource} has to be overriden. + * + * @param <EntityResourceT> the resource modeling the entity + * @param <EntityT> the entity type of single items in the list + */ +public abstract class EntityWithoutIdCollectionResource<EntityResourceT extends EntityWithoutIdResource<EntityT>, EntityT> extends EntityCollectionResource<EntityResourceT, EntityT> { + + private static final Logger logger = LoggerFactory.getLogger(EntityWithoutIdCollectionResource.class); + + + /** + * {@inheritDoc} + */ + public EntityWithoutIdCollectionResource(Class<EntityResourceT> entityResourceTClazz, Class<EntityT> entityTClazz, List<EntityT> list, IPersistable res) { + super(entityResourceTClazz, entityTClazz, list, res); + } + + /** + * Method searching the list for an id with the hashcode instead of + * getId(EntityT) + */ + @Override + @Path("{id}/") + public EntityResourceT getEntityResource(@PathParam("id") String id) { + id = Util.URLdecode(id); + int idInt; + try { + idInt = Integer.parseInt(id); + } catch (java.lang.NumberFormatException e) { + throw new NotFoundException(id + " is not a valid id"); + } + EntityT entity = null; + int idx = -1; + for (EntityT c : this.list) { + idx++; + // speed optimization - instead of using getId() we directly use the hash code + int hash = Utils.getXMLAsString(c).hashCode(); + if (hash == idInt) { + entity = c; + break; + } + } + if (entity == null) { + throw new NotFoundException(); + } else { + return this.getEntityResourceInstance(entity, idx); + } + } + + @Override + public String getId(EntityT entity) { + return IdDeterminationWithHashCode.INSTANCE.getId(entity); + } + + /** + * {@inheritDoc} + */ + @Override + protected EntityResourceT getEntityResourceInstance(EntityT entity, int idx) { + Constructor<EntityResourceT> constructor; + try { + constructor = this.entityResourceTClazz.getConstructor(this.entityTClazz, int.class, List.class, AbstractComponentInstanceResource.class); + } catch (Exception e) { + try { + constructor = this.entityResourceTClazz.getConstructor(this.entityTClazz, int.class, List.class, IPersistable.class); + } catch (NoSuchMethodException | SecurityException e1) { + EntityWithoutIdCollectionResource.logger.debug("Could not get constructor", e); + throw new IllegalStateException(e); + } + } + EntityResourceT newInstance; + try { + newInstance = constructor.newInstance(entity, idx, this.list, this.res); + } catch (Exception e) { + EntityWithoutIdCollectionResource.logger.debug("Could not instantiate class", e); + throw new IllegalStateException(e); + } + return newInstance; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdResource.java new file mode 100644 index 0000000..0cf2766 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdResource.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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._support.collections.withoutid; + +import java.util.List; + +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.EntityResource; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; + +/** + * {@inheritDoc} + */ +public abstract class EntityWithoutIdResource<EntityT> extends EntityResource<EntityT> { + + /** + * {@inheritDoc} + */ + @SuppressWarnings("unchecked") + public EntityWithoutIdResource(EntityT o, int idx, List<EntityT> list, IPersistable res) { + super((IIdDetermination<EntityT>) IdDeterminationWithHashCode.INSTANCE, o, idx, list, res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/IdDeterminationWithHashCode.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/IdDeterminationWithHashCode.java new file mode 100644 index 0000000..6b4e247 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/IdDeterminationWithHashCode.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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._support.collections.withoutid; + +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; + +public class IdDeterminationWithHashCode implements IIdDetermination<Object> { + + public static final IdDeterminationWithHashCode INSTANCE = new IdDeterminationWithHashCode(); + + + @Override + public String getId(Object entity) { + // We assume that different Object serializations *always* have different hashCodes + int hash = Utils.getXMLAsString(entity).hashCode(); + return Integer.toString(hash); + } + + /** + * Static wrapper method for functions.tld + */ + public static String getIdStatically(Object entity) { + return IdDeterminationWithHashCode.INSTANCE.getId(entity); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/package-info.java new file mode 100644 index 0000000..c62b344 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/package-info.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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 + *******************************************************************************/ +/** + * This package contains abstract resources implementing common functionality to + * support collections of entities, where the data model does not provide a + * unique id + */ +package org.eclipse.winery.repository.resources._support.collections.withoutid;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AbstractAdminResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AbstractAdminResource.java new file mode 100644 index 0000000..cd4e20e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AbstractAdminResource.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.admin; + +import javax.ws.rs.DELETE; +import javax.ws.rs.core.Response; + +import org.apache.commons.configuration.Configuration; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.ids.admin.AdminId; + +/** + * Instance of one admin resource + * + * Offers a configuration object to store data + */ +public abstract class AbstractAdminResource { + + protected final AdminId id; + protected Configuration configuration; + + + /** + * @param id the id of the element rendered by this resource + */ + public AbstractAdminResource(AdminId id) { + this.id = id; + this.configuration = Repository.INSTANCE.getConfiguration(id); + } + + @DELETE + public Response onDelete() { + return BackendUtils.delete(this.id); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AdminTopResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AdminTopResource.java new file mode 100644 index 0000000..7e4a662 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AdminTopResource.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.admin; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.eclipse.winery.repository.resources.admin.types.ConstraintTypesManager; +import org.eclipse.winery.repository.resources.admin.types.PlanLanguagesManager; +import org.eclipse.winery.repository.resources.admin.types.PlanTypesManager; + +import com.sun.jersey.api.view.Viewable; + +public class AdminTopResource { + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/admin/adminindex.jsp", this); + } + + @Path("namespaces/") + public NamespacesResource getNamespacesResource() { + return NamespacesResource.INSTANCE; + } + + @Path("repository/") + public RepositoryAdminResource getRepositoryAdminResource() { + return new RepositoryAdminResource(); + } + + @Path("planlanguages/") + public PlanLanguagesManager getPlanLanguagesResource() { + return PlanLanguagesManager.INSTANCE; + } + + @Path("plantypes/") + public PlanTypesManager getPlanTypesResource() { + return PlanTypesManager.INSTANCE; + } + + @Path("constrainttypes/") + public ConstraintTypesManager getConstraintTypesManager() { + return ConstraintTypesManager.INSTANCE; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/NamespacesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/NamespacesResource.java new file mode 100644 index 0000000..f8fb9f1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/NamespacesResource.java @@ -0,0 +1,253 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.admin; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.TreeSet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +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.Util; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.ids.admin.NamespacesId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.sun.jersey.api.view.Viewable; + +/** + * Manages prefixes for the namespaces + */ +public class NamespacesResource extends AbstractAdminResource { + + private static final Logger logger = LoggerFactory.getLogger(NamespacesResource.class); + + public final static NamespacesResource INSTANCE = new NamespacesResource(); + + private Integer nsCount = 0; + + + private NamespacesResource() { + super(new NamespacesId()); + + // globally set prefixes + // if that behavior is not desired, the code has to be moved to "generatePrefix" which checks for existence, ... + this.configuration.setProperty("http://www.w3.org/2001/XMLSchema", "xsd"); + this.configuration.setProperty("http://www.w3.org/XML/1998/namespace", "xmlns"); + this.configuration.setProperty(org.eclipse.winery.common.constants.Namespaces.TOSCA_NAMESPACE, "tosca"); + this.configuration.setProperty(org.eclipse.winery.common.constants.Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "winery"); + } + + private Collection<String> getAllPrefixes() { + Iterator<String> keys = this.configuration.getKeys(); + HashSet<String> res = new HashSet<String>(); + while (keys.hasNext()) { + String key = keys.next(); + String prefix = this.configuration.getString(key); + res.add(prefix); + } + return res; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML() { + Viewable viewable = new Viewable("/jsp/admin/namespaces.jsp", this); + return Response.ok().entity(viewable).build(); + } + + /** + * Sets / overwrites prefix/namespace mapping + * + * In case the prefix is already bound to another namespace, BAD_REQUEST is + * returned. + */ + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response addNamespace(@FormParam("namespace") String namespace, @FormParam("nsPrefix") String prefix) { + if (StringUtils.isEmpty(namespace)) { + return Response.status(Status.BAD_REQUEST).entity("namespace must be given.").build(); + } + if (StringUtils.isEmpty(prefix)) { + return Response.status(Status.BAD_REQUEST).entity("prefix must be given.").build(); + } + namespace = Util.URLdecode(namespace); + prefix = Util.URLdecode(prefix); + Collection<String> allPrefixes = this.getAllPrefixes(); + if (allPrefixes.contains(prefix)) { + if (NamespacesResource.getPrefix(namespace).equals(prefix)) { + return Response.notModified().build(); + } else { + // the requested prefix is already bound to a different namespace + return Response.status(Status.BAD_REQUEST).entity("prefix already bound to a different namespace.").build(); + } + } + this.configuration.setProperty(namespace, prefix); + return Response.noContent().build(); + } + + /** + * Deletes given namespace from the repository + * + * @param URI to delete. The namespace is URLencoded. + * @return + */ + @DELETE + @Path("{namespace}") + public Response onDelete(@PathParam("namespace") String URI) { + Response res; + URI = Util.URLdecode(URI); + if (this.configuration.containsKey(URI)) { + this.configuration.clearProperty(URI); + res = Response.noContent().build(); + } else { + res = Response.status(Status.NOT_FOUND).build(); + } + return res; + } + + /** + * SIDEFFECT: URI is added to list of known namespaces if it did not exist + * before + */ + public static String getPrefix(Namespace namespace) { + String ns = namespace.getDecoded(); + return NamespacesResource.getPrefix(ns); + } + + @Path("{namespace}") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getPrefixForEncodedNamespace(@PathParam("namespace") String URI) { + URI = Util.URLdecode(URI); + return NamespacesResource.getPrefix(URI); + } + + /** + * SIDEFFECT: URI is added to list of known namespaces if it did not exist + * before + */ + public static String getPrefix(String namespace) { + if (namespace == null) { + throw new IllegalArgumentException("Namespace must not be null"); + } + String prefix = NamespacesResource.INSTANCE.configuration.getString(namespace); + if (prefix == null) { + prefix = NamespacesResource.generatePrefix(namespace); + NamespacesResource.INSTANCE.configuration.setProperty(namespace, prefix); + } + return prefix; + } + + private static String generatePrefix(String namespace) { + String prefix = null; + Collection<String> allPrefixes = NamespacesResource.INSTANCE.getAllPrefixes(); + + // TODO: generate prefix using URI (and not "arbitrary" prefix) + do { + prefix = String.format("ns%d", NamespacesResource.INSTANCE.nsCount); + NamespacesResource.INSTANCE.nsCount++; + } while (allPrefixes.contains(prefix)); + return prefix; + } + + /** + * Returns the list of all namespaces registered with his manager. It could + * be incomplete, if entries have been added manually to the repository + * + * @return all namespaces registered with this manager. + */ + private HashSet<Namespace> getRegisteredNamespaces() { + HashSet<Namespace> res = new HashSet<Namespace>(); + Iterator<String> keys = this.configuration.getKeys(); + while (keys.hasNext()) { + String key = keys.next(); + Namespace ns = new Namespace(key, false); + res.add(ns); + } + return res; + } + + /** + * Returns the list of all namespaces registered with his manager and used + * at component instances. + */ + public static Collection<Namespace> getNamespaces() { + HashSet<Namespace> res = NamespacesResource.INSTANCE.getRegisteredNamespaces(); + res.addAll(Repository.INSTANCE.getUsedNamespaces()); + return res; + } + + /** + * This method is required because static methods cannot be accessed by EL + * + * @return see getNamespaces() + */ + public Collection<Namespace> getNamespacesForJSP() { + return NamespacesResource.getNamespaces(); + } + + /** + * Returns the list of all namespaces registered with his manager and used + * at component instances. + * + * @return a JSON list containing the non-encoded URIs of each known + * namespace + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public String getNamespacesAsJSONlist() { + Collection<Namespace> namespaces = NamespacesResource.getNamespaces(); + + // We now have all namespaces + // We need to convert from Namespace to String + + TreeSet<String> stringNamespaces = new TreeSet<String>(); + for (Namespace ns : namespaces) { + stringNamespaces.add(ns.getDecoded()); + } + + String res; + try { + res = Utils.mapper.writeValueAsString(stringNamespaces); + } catch (JsonProcessingException e) { + NamespacesResource.logger.error(e.getMessage(), e); + res = "[]"; + } + return res; + } + + /** + * Checks whether a prefix is registered for a namespace + * + * Used at CSARImporter + */ + public boolean getIsPrefixKnownForNamespace(String namespace) { + return this.configuration.containsKey(namespace); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/RepositoryAdminResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/RepositoryAdminResource.java new file mode 100644 index 0000000..408704d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/RepositoryAdminResource.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.admin; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; + +import org.eclipse.winery.repository.Prefs; +import org.eclipse.winery.repository.backend.IRepositoryAdministration; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.backend.filebased.GitBasedRepository; +import org.restdoc.annotations.RestDoc; +import org.restdoc.annotations.RestDocParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; +import com.sun.jersey.core.header.FormDataContentDisposition; +import com.sun.jersey.multipart.FormDataParam; + +public class RepositoryAdminResource { + + private static final Logger logger = LoggerFactory.getLogger(RepositoryAdminResource.class); + + + // @formatter:off + @GET + @Produces(MediaType.TEXT_HTML) // we cannot add MimeTypes.MIMETYPE_ZIP as dumpRepository also produces that mimetype + @RestDoc(methodDescription = "Returns the repository admin page and implements administration utility") + public Response onGet( + @QueryParam(value = "dump") @RestDocParam(description = "If given, a dump of the repository is sent") String dump, + @QueryParam(value = "reset") @RestDocParam(description = "Resets the repository to the last “official” known state") String reset, + @QueryParam(value = "commit") @RestDocParam(description = "Commits the current state to the repository and pushes it upstream") String commit + ) { + // @formatter:on + if (dump != null) { + return this.dumpRepository(); + } else if (reset != null) { + try { + ((GitBasedRepository) Prefs.INSTANCE.getRepository()).cleanAndResetHard(); + } catch (Exception e) { + Response res; + res = Response.serverError().entity(e.getMessage()).build(); + return res; + } + return Response.noContent().build(); + } else if (commit != null) { + try { + ((GitBasedRepository) Prefs.INSTANCE.getRepository()).addCommitPush(); + } catch (Exception e) { + Response res; + res = Response.serverError().entity(e.getMessage()).build(); + return res; + } + return Response.noContent().build(); + } else { + Viewable viewable = new Viewable("/jsp/admin/repository.jsp", this); + return Response.ok().entity(viewable).build(); + } + } + + /** + * Imports the given ZIP + */ + @POST + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response importRepositoryDump(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail) { + ((IRepositoryAdministration) Repository.INSTANCE).doImport(uploadedInputStream); + return Response.noContent().build(); + } + + @DELETE + public void deleteRepositoryData() { + ((IRepositoryAdministration) Repository.INSTANCE).doClear(); + } + + @GET + @Produces(org.eclipse.winery.common.constants.MimeTypes.MIMETYPE_ZIP) + public Response dumpRepository() { + StreamingOutput so = new StreamingOutput() { + + @Override + public void write(OutputStream output) throws IOException, WebApplicationException { + ((IRepositoryAdministration) Repository.INSTANCE).doDump(output); + } + }; + StringBuilder sb = new StringBuilder(); + sb.append("attachment;filename=\"repository.zip\""); + return Response.ok().header("Content-Disposition", sb.toString()).type(org.eclipse.winery.common.constants.MimeTypes.MIMETYPE_ZIP).entity(so).build(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/AbstractTypesManager.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/AbstractTypesManager.java new file mode 100644 index 0000000..bf3c024 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/AbstractTypesManager.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.admin.types; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.datatypes.TypeWithShortName; +import org.eclipse.winery.repository.datatypes.ids.admin.TypesId; +import org.eclipse.winery.repository.datatypes.select2.Select2DataItem; +import org.eclipse.winery.repository.resources.admin.AbstractAdminResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +/** + * Handles longname/shortname by using properties + * + * FIXME: This class does NOT support dynamic reloading of the underlying + * Configuration instance + * + */ +public abstract class AbstractTypesManager extends AbstractAdminResource { + + @Context + private UriInfo uriInfo; + + protected static final Logger logger = LoggerFactory.getLogger(AbstractTypesManager.class); + + // hashes from a long type string to the type object holding complete type data + private final HashMap<String, TypeWithShortName> hashTypeStringToType; + + + public AbstractTypesManager(TypesId id) { + super(id); + // now, this.configuration is filled with stored data + + // copy over information from configuration to internal data structure + this.hashTypeStringToType = new HashMap<String, TypeWithShortName>(); + Iterator<String> keys = this.configuration.getKeys(); + while (keys.hasNext()) { + String key = keys.next(); + String value = this.configuration.getString(key); + TypeWithShortName typeInfo = new TypeWithShortName(key, value); + this.hashTypeStringToType.put(key, typeInfo); + } + } + + protected void addData(String longName, String shortName) { + TypeWithShortName t = new TypeWithShortName(longName, shortName); + this.addData(t); + } + + /** + * Adds data to the internal data structure WITHOUT persisting it + * + * More or less a quick hack to enable adding default types without + * persisting them in the storage + * + * @param t the type to add + */ + private void addData(TypeWithShortName t) { + this.hashTypeStringToType.put(t.getType(), t); + } + + public synchronized void addTypeWithShortName(TypeWithShortName type) { + this.addData(type); + this.configuration.setProperty(type.getType(), type.getShortName()); + } + + /** + * Removes a type. Will not remove a type added by "addData" + */ + @DELETE + @Path("{type}") + public Response removeTypeWithResponse(@PathParam("type") String type) { + type = Util.URLdecode(type); + if (this.configuration.containsKey(type)) { + this.hashTypeStringToType.remove(type); + this.configuration.clearProperty(type); + return Response.noContent().build(); + } else if (this.hashTypeStringToType.containsKey(type)) { + // predefined types may not be deleted + // this branch is hit at types added via addData (e.g., predefined plantypes) + return Response.status(Status.FORBIDDEN).build(); + } else { + return Response.status(Status.NOT_FOUND).build(); + } + } + + /** + * Returns a sorted list of all available types + */ + public Collection<TypeWithShortName> getTypes() { + Collection<TypeWithShortName> res = new TreeSet<TypeWithShortName>(this.hashTypeStringToType.values()); + return res; + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Object getTypesAsJSONArrayList(@QueryParam("select2") String select2) { + if (select2 == null) { + return this.getTypes(); + } else { + // select2 mode + SortedSet<Select2DataItem> res = new TreeSet<>(); + for (TypeWithShortName t : this.getTypes()) { + Select2DataItem item = new Select2DataItem(t.getType(), t.getShortName()); + res.add(item); + } + return res; + } + } + + /** + * <b>SIDEEFFECT:</b> If there currently isn't any short type name, it is + * created + */ + public TypeWithShortName getTypeWithShortName(String typeString) { + TypeWithShortName t = this.hashTypeStringToType.get(typeString); + if (t == null) { + String shortName = this.getShortName(typeString); + t = new TypeWithShortName(typeString, shortName); + this.addTypeWithShortName(t); + } + return t; + } + + /** + * <b>SIDEEFFECT:</b> If there currently isn't any short type name, it is + * created + */ + public String getShortName(String typeString) { + TypeWithShortName type = this.hashTypeStringToType.get(typeString); + String res; + if (type == null) { + // happens if artifact type is not registered in artifacttypes.list + // (DATAFILENAME) + res = typeString; + } else { + res = type.getShortName(); + } + return res; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML(@Context UriInfo uriInfo) { + this.uriInfo = uriInfo; + return new Viewable("/jsp/admin/types/types.jsp", this); + } + + @POST + public Response updateTypeMapping(@FormParam("shortname") String shortName, @FormParam("type") String type) { + if (StringUtils.isEmpty(shortName)) { + return Response.status(Status.BAD_REQUEST).entity("shortName has to be given").build(); + } + if (StringUtils.isEmpty(type)) { + return Response.status(Status.BAD_REQUEST).entity("type has to be given").build(); + } + shortName = Util.URLdecode(shortName); + type = Util.URLdecode(type); + TypeWithShortName tws = new TypeWithShortName(type, shortName); + this.addTypeWithShortName(tws); + return Response.noContent().build(); + } + + /** + * Required by types.jsp + */ + public String getURL() { + return this.uriInfo.getAbsolutePath().toString(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/ConstraintTypesManager.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/ConstraintTypesManager.java new file mode 100644 index 0000000..d8a9c0e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/ConstraintTypesManager.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.admin.types; + +import org.eclipse.winery.repository.datatypes.ids.admin.ConstraintTypesId; + +public class ConstraintTypesManager extends AbstractTypesManager { + + public final static ConstraintTypesManager INSTANCE = new ConstraintTypesManager(); + + + private ConstraintTypesManager() { + super(new ConstraintTypesId()); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanLanguagesManager.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanLanguagesManager.java new file mode 100644 index 0000000..e5b35b9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanLanguagesManager.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.admin.types; + +import org.eclipse.winery.repository.datatypes.ids.admin.PlanLanguagesId; + +public class PlanLanguagesManager extends AbstractTypesManager { + + public final static PlanLanguagesManager INSTANCE = new PlanLanguagesManager(); + + + private PlanLanguagesManager() { + super(new PlanLanguagesId()); + // add data without rendering in the plan languages file + this.addData(org.eclipse.winery.common.constants.Namespaces.URI_BPEL20_EXECUTABLE, "BPEL 2.0 (executable)"); + this.addData(org.eclipse.winery.common.constants.Namespaces.URI_BPMN20_MODEL, "BPMN 2.0"); + this.addData(org.eclipse.winery.common.constants.Namespaces.URI_BPMN4TOSCA_20, "BPMN4TOSCA 2.0"); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanTypesManager.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanTypesManager.java new file mode 100644 index 0000000..de6e7ba --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanTypesManager.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.admin.types; + +import org.eclipse.winery.repository.datatypes.ids.admin.PlanTypesId; + +public class PlanTypesManager extends AbstractTypesManager { + + public final static PlanTypesManager INSTANCE = new PlanTypesManager(); + + + private PlanTypesManager() { + super(new PlanTypesId()); + // add data without rendering in the plan types file + this.addData(org.eclipse.winery.repository.Constants.TOSCA_PLANTYPE_BUILD_PLAN, "Build Plan"); + this.addData(org.eclipse.winery.repository.Constants.TOSCA_PLANTYPE_TERMINATION_PLAN, "Termination Plan"); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactResource.java new file mode 100644 index 0000000..ec7a86b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactResource.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,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.artifacts; + +import java.util.List; + +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.model.tosca.TDeploymentArtifact; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; + +public class DeploymentArtifactResource extends GenericArtifactResource<TDeploymentArtifact> { + + private final TDeploymentArtifact a; + + + /** + * Converts the given artifactId to an DeploymentArtifact. + * + * <em>SIDE EFFECT</em> Adds it to the DeploymentArtifacts list if it does + * not yet exist. + */ + private static TDeploymentArtifact getDeploymentArtifact(String artifactId, List<TDeploymentArtifact> deploymentArtifacts) { + for (TDeploymentArtifact ia : deploymentArtifacts) { + if (ia.getName().equals(artifactId)) { + return ia; + } + } + // DA does not exist in list + TDeploymentArtifact ia = new TDeploymentArtifact(); + ia.setName(artifactId); + deploymentArtifacts.add(ia); + return ia; + } + + public DeploymentArtifactResource(String artifactId, List<TDeploymentArtifact> deploymentArtifacts, IPersistable res) { + this(DeploymentArtifactResource.getDeploymentArtifact(artifactId, deploymentArtifacts), deploymentArtifacts, res); + } + + public DeploymentArtifactResource(IIdDetermination<TDeploymentArtifact> idDetermination, TDeploymentArtifact o, int idx, List<TDeploymentArtifact> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + this.a = o; + } + + public DeploymentArtifactResource(TDeploymentArtifact deploymentArtifact, List<TDeploymentArtifact> deploymentArtifacts, IPersistable res) { + this(new IIdDetermination<TDeploymentArtifact>() { + + @Override + public String getId(TDeploymentArtifact e) { + return e.getName(); + } + }, deploymentArtifact, deploymentArtifacts.indexOf(deploymentArtifact), deploymentArtifacts, res); + } + + public TDeploymentArtifact getDeploymentArtifact() { + return this.a; + } + + @Override + public void setArtifactType(ArtifactTypeId artifactTypeId) { + this.getDeploymentArtifact().setArtifactType(artifactTypeId.getQName()); + BackendUtils.persist(this.res); + } + + @Override + public void setArtifactTemplate(ArtifactTemplateId artifactTemplateId) { + this.getDeploymentArtifact().setArtifactRef(artifactTemplateId.getQName()); + BackendUtils.persist(this.res); + } + + @Override + public TDeploymentArtifact getA() { + return this.a; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactsResource.java new file mode 100644 index 0000000..dcb5ca7 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactsResource.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,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.artifacts; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.winery.model.tosca.TDeploymentArtifact; +import org.eclipse.winery.model.tosca.TDeploymentArtifacts; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DeploymentArtifactsResource extends GenericArtifactsResource<DeploymentArtifactResource, TDeploymentArtifact> { + + private static final Logger logger = LoggerFactory.getLogger(DeploymentArtifactsResource.class); + + private List<TDeploymentArtifact> deploymentArtifacts; + + + public DeploymentArtifactsResource(List<TDeploymentArtifact> deploymentArtifact, INodeTemplateResourceOrNodeTypeImplementationResource res) { + super(DeploymentArtifactResource.class, TDeploymentArtifact.class, deploymentArtifact, res); + this.deploymentArtifacts = deploymentArtifact; + } + + /** + * Determines the list of DAs belonging to the given node template. + * + * If no DAs are existing, an empty list is created in the model for the + * node template + */ + private static List<TDeploymentArtifact> getDeploymentArtifacts(TNodeTemplate nodeTemplate) { + TDeploymentArtifacts deploymentArtifacts = nodeTemplate.getDeploymentArtifacts(); + final List<TDeploymentArtifact> res; + if (deploymentArtifacts == null) { + deploymentArtifacts = new TDeploymentArtifacts(); + nodeTemplate.setDeploymentArtifacts(deploymentArtifacts); + } + res = deploymentArtifacts.getDeploymentArtifact(); + return res; + } + + public DeploymentArtifactsResource(TNodeTemplate nodeTemplate, INodeTemplateResourceOrNodeTypeImplementationResource res) { + this(DeploymentArtifactsResource.getDeploymentArtifacts(nodeTemplate), res); + } + + @Override + public Collection<DeploymentArtifactResource> getAllArtifactResources() { + Collection<DeploymentArtifactResource> res = new ArrayList<DeploymentArtifactResource>(this.deploymentArtifacts.size()); + for (TDeploymentArtifact da : this.deploymentArtifacts) { + DeploymentArtifactResource r = new DeploymentArtifactResource(da, this.deploymentArtifacts, this.res); + res.add(r); + } + return res; + } + + @Override + public String getId(TDeploymentArtifact entity) { + return entity.getName(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactResource.java new file mode 100644 index 0000000..9295082 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactResource.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,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.artifacts; + +import java.util.List; + +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; + +/** + * Currently no common things for deployment artifacts and implementation + * artifacts as the data model also has no common ancestor (besides + * TExensibleElement) + */ +public abstract class GenericArtifactResource<ArtifactT> extends EntityWithIdResource<ArtifactT> { + + public GenericArtifactResource(IIdDetermination<ArtifactT> idDetermination, ArtifactT o, int idx, List<ArtifactT> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + public abstract void setArtifactType(ArtifactTypeId artifactTypeId); + + public abstract void setArtifactTemplate(ArtifactTemplateId artifactTemplateId); + + /** + * required by artifacts.jsp + */ + public abstract ArtifactT getA(); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactsResource.java new file mode 100644 index 0000000..0cef56e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactsResource.java @@ -0,0 +1,572 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.artifacts; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.generators.ia.Generator; +import org.eclipse.winery.model.tosca.TDeploymentArtifact; +import org.eclipse.winery.model.tosca.TEntityTemplate.Properties; +import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact; +import org.eclipse.winery.model.tosca.TInterface; +import org.eclipse.winery.model.tosca.TNodeType; +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.backend.ResourceCreationResult; +import org.eclipse.winery.repository.backend.filebased.FileUtils; +import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; +import org.eclipse.winery.repository.resources.IHasTypeReference; +import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.eclipse.winery.repository.resources.entitytemplates.PropertiesResource; +import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplateResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.EntityTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; +import org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.NodeTemplateResource; +import org.restdoc.annotations.RestDoc; +import org.restdoc.annotations.RestDocParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Text; +import org.xml.sax.InputSource; + +import com.sun.jersey.api.view.Viewable; + +/** + * Resource handling both deployment and implementation artifacts + * + */ +public abstract class GenericArtifactsResource<ArtifactResource extends GenericArtifactResource<ArtifactT>, ArtifactT> extends EntityWithIdCollectionResource<ArtifactResource, ArtifactT> { + + private static final Logger logger = LoggerFactory.getLogger(GenericArtifactsResource.class); + + protected final INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource resWithNamespace; + + + public GenericArtifactsResource(Class<ArtifactResource> entityResourceTClazz, Class<ArtifactT> entityTClazz, List<ArtifactT> list, INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) { + super(entityResourceTClazz, entityTClazz, list, GenericArtifactsResource.getAbstractComponentInstanceResource(res)); + this.resWithNamespace = res; + } + + // @formatter:off + + /** + * @return TImplementationArtifact | TDeploymentArtifact (XML) | URL of generated IA zip (in case of autoGenerateIA) + */ + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_XML) + @RestDoc(methodDescription = "Creates a new implementation/deployment artifact. " + + "If an implementation artifact with the same name already exists, it is <em>overridden</em>.") + @SuppressWarnings("unchecked") + public Response onPost( + @FormParam("artifactName") + @RestDocParam(description = "This is the name of the implementation/deployment artifact. " + + "Is <em>also</em>used as prefix of the name of the corresponding artifact template if no specific template is provided. " + + "In contrast to CS01, we require a artifactName also for the implementationArtifact to be able to properly referencing it.") + String artifactNameStr, + + @FormParam("artifactTemplate") + @RestDocParam(description = "QName of the artifact Template - used by Winery Backend instead of artifactTemplateName + artifactTemplateNS") + String artifactTemplate, + + @FormParam("artifactTemplateName") + @RestDocParam(description = "if provided and autoCreateArtifactTemplate, a template of this id localname and artifactTemplateNS generated. " + + "Winery always sends this string if auto creation is desired.") + String artifactTemplateName, + + @FormParam("artifactTemplateNS") + String artifactTemplateNS, + + @FormParam("autoCreateArtifactTemplate") + @RestDocParam(description = "if empty, no, or false, no artifact template is created. " + + "An artifact type has to be given in that case. " + + "Furthermore, an artifact template name + artifact template namespace has to be provided. " + + "Otherwise, the artifactNameStr is used as name for the artifact and a <em>new</em> artifact template is created having {@code <artifactNameString>Template} as name") + String autoCreateArtifactTemplate, + + @FormParam("artifactType") + @RestDocParam(description = "QName of the type, format: {namespace}localname. " + + "Optional if artifactTemplateName + artifactTempalteNS is provided") + String artifactTypeStr, + + @FormParam("artifactSpecificContent") + @RestDocParam(description = "<em>XML</em> snippet that should be put inside the artifact XML in the TOSCA serialization. " + + "This feature will be removed soon. " + + "TODO: This only works if there is a single child element expected and not several elements. " + + "Future versions of the Winery will support arbitrary content there.") + String artifactSpecificContent, + + @FormParam("interfaceName") + String interfaceNameStr, + + @FormParam("operationName") + String operationNameStr, + + @FormParam("autoGenerateIA") + @RestDocParam(description = "If not empty, the IA generator will be called") + String autoGenerateIA, + + @FormParam("javapackage") + @RestDocParam(description = "The Java package to use for IA generation") + String javapackage, + + @Context UriInfo uriInfo + ){ + // we assume that the parent ComponentInstance container exists + + // @formatter:on + + if (StringUtils.isEmpty(artifactNameStr)) { + return Response.status(Status.BAD_REQUEST).entity("Empty artifactName").build(); + } + if (StringUtils.isEmpty(artifactTypeStr)) { + if (StringUtils.isEmpty(artifactTemplateName) || StringUtils.isEmpty(artifactTemplateNS)) { + if (StringUtils.isEmpty(artifactTemplate)) { + return Response.status(Status.BAD_REQUEST).entity("No artifact type given and no template given. Cannot guess artifact type").build(); + } + } + } + + if (!StringUtils.isEmpty(autoGenerateIA)) { + if (StringUtils.isEmpty(javapackage)) { + return Response.status(Status.BAD_REQUEST).entity("no java package name supplied for IA auto generation.").build(); + } + if (StringUtils.isEmpty(interfaceNameStr)) { + return Response.status(Status.BAD_REQUEST).entity("no interface name supplied for IA auto generation.").build(); + } + } + + // convert second calling form to first calling form + if (!StringUtils.isEmpty(artifactTemplate)) { + QName qname = QName.valueOf(artifactTemplate); + artifactTemplateName = qname.getLocalPart(); + artifactTemplateNS = qname.getNamespaceURI(); + } + + Document doc = null; + + // check artifact specific content for validity + // if invalid, abort and do not create anything + if (!StringUtils.isEmpty(artifactSpecificContent)) { + try { + DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + InputSource is = new InputSource(); + StringReader sr = new StringReader(artifactSpecificContent); + is.setCharacterStream(sr); + doc = db.parse(is); + } catch (Exception e) { + // FIXME: currently we allow a single element only. However, the content should be internally wrapped by an (arbitrary) XML element as the content will be nested in the artifact element, too + GenericArtifactsResource.logger.debug("Invalid content", e); + return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } + } + + // determine artifactTemplate and artifactType + + ArtifactTypeId artifactTypeId; + ArtifactTemplateId artifactTemplateId = null; + ArtifactTemplateResource artifactTemplateResource = null; + + boolean doAutoCreateArtifactTemplate = !(StringUtils.isEmpty(autoCreateArtifactTemplate) || autoCreateArtifactTemplate.equalsIgnoreCase("no") || autoCreateArtifactTemplate.equalsIgnoreCase("false")); + if (!doAutoCreateArtifactTemplate) { + // no auto creation + if (!StringUtils.isEmpty(artifactTemplateName) && !StringUtils.isEmpty(artifactTemplateNS)) { + QName artifactTemplateQName = new QName(artifactTemplateNS, artifactTemplateName); + artifactTemplateId = BackendUtils.getTOSCAcomponentId(ArtifactTemplateId.class, artifactTemplateQName); + } + if (StringUtils.isEmpty(artifactTypeStr)) { + // derive the type from the artifact template + if (artifactTemplateId == null) { + return Response.status(Status.NOT_ACCEPTABLE).entity("No artifactTemplate and no artifactType provided. Deriving the artifactType is not possible.").build(); + } + artifactTemplateResource = new ArtifactTemplateResource(artifactTemplateId); + artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTemplateResource.getType()); + } else { + // artifactTypeStr is directly given, use that + artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTypeStr); + } + } else { + // do the artifact template auto creation magic + + if (StringUtils.isEmpty(artifactTypeStr)) { + return Response.status(Status.BAD_REQUEST).entity("Artifact template auto creation requested, but no artifact type supplied.").build(); + } + + // we assume that the type points to a valid artifact type + artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTypeStr); + + if (StringUtils.isEmpty(artifactTemplateName) || StringUtils.isEmpty(artifactTemplateNS)) { + // no explicit name provided + // we use the artifactNameStr as prefix for the + // artifact template name + + // we create a new artifact template in the namespace of the parent + // element + Namespace namespace = this.resWithNamespace.getNamespace(); + + artifactTemplateId = new ArtifactTemplateId(namespace, new XMLId(artifactNameStr + "artifactTemplate", false)); + } else { + QName artifactTemplateQName = new QName(artifactTemplateNS, artifactTemplateName); + artifactTemplateId = new ArtifactTemplateId(artifactTemplateQName); + } + ResourceCreationResult creationResult = BackendUtils.create(artifactTemplateId); + if (!creationResult.isSuccess()) { + // something went wrong. skip + return creationResult.getResponse(); + } + + // associate the type to the created artifact template + artifactTemplateResource = new ArtifactTemplateResource(artifactTemplateId); + // set the type. The resource is automatically persisted inside + artifactTemplateResource.setType(artifactTypeStr); + } + + // variable artifactTypeId is set + // variable artifactTemplateId is not null if artifactTemplate has been generated + + // we have to generate the DA/IA resource now + // Doing it here instead of doing it at the subclasses is dirty on the + // one hand, but quicker to implement on the other hand + + // Create the artifact itself + + ArtifactT resultingArtifact; + + if (this instanceof ImplementationArtifactsResource) { + ImplementationArtifact a = new ImplementationArtifact(); + // Winery internal id is the name of the artifact: + // store the name + a.setName(artifactNameStr); + a.setInterfaceName(interfaceNameStr); + a.setOperationName(operationNameStr); + assert (artifactTypeId != null); + a.setArtifactType(artifactTypeId.getQName()); + if (artifactTemplateId != null) { + a.setArtifactRef(artifactTemplateId.getQName()); + } + if (doc != null) { + // the content has been checked for validity at the beginning of the method. + // If this point in the code is reached, the XML has been parsed into doc + // just copy over the dom node. Hopefully, that works... + a.getAny().add(doc.getDocumentElement()); + } + + this.list.add((ArtifactT) a); + resultingArtifact = (ArtifactT) a; + } else { + // for comments see other branch + + TDeploymentArtifact a = new TDeploymentArtifact(); + a.setName(artifactNameStr); + assert (artifactTypeId != null); + a.setArtifactType(artifactTypeId.getQName()); + if (artifactTemplateId != null) { + a.setArtifactRef(artifactTemplateId.getQName()); + } + if (doc != null) { + a.getAny().add(doc.getDocumentElement()); + } + + this.list.add((ArtifactT) a); + resultingArtifact = (ArtifactT) a; + } + + Response persistResponse = BackendUtils.persist(super.res); + // TODO: check for error and in case one found return that + + if (StringUtils.isEmpty(autoGenerateIA)) { + // no IA generation + // we include an XML for the data table + + String implOrDeplArtifactXML = Utils.getXMLAsString(resultingArtifact); + + return Response.created(Utils.createURI(Util.URLencode(artifactNameStr))).entity(implOrDeplArtifactXML).build(); + } else { + // after everything was created, we fire up the artifact generation + return this.generateImplementationArtifact(interfaceNameStr, javapackage, uriInfo, artifactTemplateId, artifactTemplateResource); + } + } + + /** + * Generates a unique and valid name to be used for the generated maven + * project name, java project name, class name, port type name. + */ + private String generateName(NodeTypeId nodeTypeId, String interfaceName) { + String name = Util.namespaceToJavaPackage(nodeTypeId.getNamespace().getDecoded()); + name += Util.FORBIDDEN_CHARACTER_REPLACEMENT; + + // Winery already ensures that this is a valid NCName + // getName() returns the id of the nodeType: A nodeType carries the "id" attribute only (and no name attribute) + name += nodeTypeId.getXmlId().getDecoded(); + + // Two separators to distinguish node type and interface part + name += Util.FORBIDDEN_CHARACTER_REPLACEMENT; + name += Util.FORBIDDEN_CHARACTER_REPLACEMENT; + name += Util.namespaceToJavaPackage(interfaceName); + + // In addition we must replace '.', because Java class names must not + // contain dots, but for Winery they are fine. + return name.replace(".", Util.FORBIDDEN_CHARACTER_REPLACEMENT); + } + + /** + * Generates the implementation artifact using the implementation artifact + * generator. Also sets the proeprties according to the requirements of + * OpenTOSCA. + * + * @param interfaceNameStr + * @param javapackage + * @param uriInfo + * @param artifactTemplateId + * @param artifactTemplateResource the resource associated with the + * artifactTempalteId. If null, the object is created in this + * method + * + * @return {@inheritDoc} + */ + private Response generateImplementationArtifact(String interfaceNameStr, String javapackage, UriInfo uriInfo, ArtifactTemplateId artifactTemplateId, ArtifactTemplateResource artifactTemplateResource) { + TInterface iface; + + assert (this instanceof ImplementationArtifactsResource); + IHasTypeReference typeRes = (EntityTypeImplementationResource) this.res; + QName type = typeRes.getType(); + TOSCAComponentId typeId; + TNodeType nodeType = null; + if (typeRes instanceof NodeTypeImplementationResource) { + // TODO: refactor: This is more a model/repo utilities thing than something which should happen here... + + typeId = new NodeTypeId(type); + NodeTypeResource ntRes = (NodeTypeResource) AbstractComponentsResource.getComponentInstaceResource(typeId); + + // required for IA Generation + nodeType = ntRes.getNodeType(); + + List<TInterface> interfaces = nodeType.getInterfaces().getInterface(); + Iterator<TInterface> it = interfaces.iterator(); + do { + iface = it.next(); + if (iface.getName().equals(interfaceNameStr)) { + break; + } + } while (it.hasNext()); + // iface now contains the right interface + } else { + assert (typeRes instanceof RelationshipTypeImplementationResource); + return Response.serverError().entity("IA creation for relation ship type implementations not yet possible").build(); + } + + Path workingDir; + try { + workingDir = Files.createTempDirectory("winery"); + } catch (IOException e2) { + GenericArtifactsResource.logger.debug("Could not create temporary directory", e2); + return Response.serverError().entity("Could not create temporary directory").build(); + } + + URI artifactTemplateFilesUri = uriInfo.getBaseUri().resolve(Utils.getAbsoluteURL(artifactTemplateId)).resolve("files/"); + URL artifactTemplateFilesUrl; + try { + artifactTemplateFilesUrl = artifactTemplateFilesUri.toURL(); + } catch (MalformedURLException e2) { + GenericArtifactsResource.logger.debug("Could not convert URI to URL", e2); + return Response.serverError().entity("Could not convert URI to URL").build(); + } + + String name = this.generateName((NodeTypeId) typeId, interfaceNameStr); + Generator gen = new Generator(iface, javapackage, artifactTemplateFilesUrl, name, workingDir.toFile()); + File zipFile = gen.generateProject(); + if (zipFile == null) { + return Response.serverError().entity("IA generator failed").build(); + } + + // store it + // TODO: refactor: this is more a RepositoryUtils thing than a special thing here; see also importFile at CSARImporter + + ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId(artifactTemplateId); + RepositoryFileReference fref = new RepositoryFileReference(fileDir, zipFile.getName().toString()); + try (InputStream is = Files.newInputStream(zipFile.toPath()); + BufferedInputStream bis = new BufferedInputStream(is)) { + String mediaType = Utils.getMimeType(bis, zipFile.getName()); + // TODO: do the catch thing as in CSARImporter + + Repository.INSTANCE.putContentToFile(fref, bis, MediaType.valueOf(mediaType)); + } catch (IOException e1) { + throw new IllegalStateException("Could not import generated files", e1); + } + + // cleanup dir + try { + FileUtils.forceDelete(workingDir); + } catch (IOException e) { + GenericArtifactsResource.logger.debug("Could not delete working directory", e); + } + + // store the properties in the artifact template + if (artifactTemplateResource == null) { + artifactTemplateResource = (ArtifactTemplateResource) AbstractComponentsResource.getComponentInstaceResource(artifactTemplateId); + } + this.storeProperties(artifactTemplateResource, typeId, name); + + URI url = uriInfo.getBaseUri().resolve(Utils.getAbsoluteURL(fref)); + return Response.created(url).build(); + } + + + private final String NS_OPENTOSCA_WAR_TYPE = "http://www.uni-stuttgart.de/opentosca"; + + + private void storeProperties(ArtifactTemplateResource artifactTemplateResource, TOSCAComponentId typeId, String name) { + // We generate the properties by hand instead of using JAX-B as using JAX-B causes issues at org.eclipse.winery.common.ModelUtilities.getPropertiesKV(TEntityTemplate): + // getAny() does not always return "w3c.dom.element" anymore + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder; + try { + builder = dbf.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + GenericArtifactsResource.logger.error(e.getMessage(), e); + return; + } + Document doc = builder.newDocument(); + Element root = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "WSProperties"); + doc.appendChild(root); + + Element element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "ServiceEndpoint"); + Text text = doc.createTextNode("/services/" + name + "Port"); + element.appendChild(text); + root.appendChild(element); + + element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "PortType"); + text = doc.createTextNode("{" + typeId.getNamespace().getDecoded() + "}" + name); + element.appendChild(text); + root.appendChild(element); + + element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "InvocationType"); + text = doc.createTextNode("SOAP/HTTP"); + element.appendChild(text); + root.appendChild(element); + + Properties properties = new Properties(); + properties.setAny(root); + PropertiesResource propertiesResource = artifactTemplateResource.getPropertiesResource(); + propertiesResource.setProperties(properties); + } + + @Override + public Viewable getHTML() { + return new Viewable("/jsp/artifacts/artifacts.jsp", this); + } + + /** + * Required for artifacts.jsp + * + * @return list of known artifact types. + */ + public List<QName> getAllArtifactTypes() { + SortedSet<ArtifactTypeId> allArtifactTypes = Repository.INSTANCE.getAllTOSCAComponentIds(ArtifactTypeId.class); + List<QName> res = new ArrayList<QName>(allArtifactTypes.size()); + for (ArtifactTypeId id : allArtifactTypes) { + res.add(id.getQName()); + } + return res; + } + + /** + * Required for artifacts.jsp + * + * @return list of all contained artifacts. + */ + public abstract Collection<ArtifactResource> getAllArtifactResources(); + + /** + * Required by artifact.jsp to decide whether to display + * "Deployment Artifact" or "Implementation Artifact" + */ + public boolean getIsDeploymentArtifacts() { + boolean res = (this instanceof DeploymentArtifactsResource); + return res; + } + + /** + * required by artifacts.jsp + */ + public String getNamespace() { + return this.resWithNamespace.getNamespace().getDecoded(); + } + + /** + * For saving resources, an AbstractComponentInstanceResource is required. + * DAs may be attached to a node template, which is not an + * AbstractComponentInstanceResource, but its grandparent resource + * ServiceTemplate is + * + * @param res the resource to determine the the + * AbstractComponentInstanceResource for + * @return the AbstractComponentInstanceResource where the given res is + * contained in + */ + public static AbstractComponentInstanceResource getAbstractComponentInstanceResource(INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) { + final AbstractComponentInstanceResource r; + if (res instanceof NodeTemplateResource) { + r = ((NodeTemplateResource) res).getServiceTemplateResource(); + } else { + // quick hack: the resource has to be an abstract component instance + r = (AbstractComponentInstanceResource) res; + } + return r; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactResource.java new file mode 100644 index 0000000..bc5580c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactResource.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.artifacts; + +import java.util.List; + +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; + +public class ImplementationArtifactResource extends GenericArtifactResource<ImplementationArtifact> { + + private ImplementationArtifact a; + + + /** + * Converts the given artifactId to an ImplementArtifact. + * + * <em>SIDE EFFECT</em> Adds it to the implementationArtifacts list if it + * does not yet exist. + */ + private static ImplementationArtifact getImplementationArtifact(String artifactId, List<ImplementationArtifact> implementationArtifacts) { + if (artifactId == null) { + throw new IllegalArgumentException("artifactId must not be null"); + } + if (implementationArtifacts == null) { + throw new IllegalArgumentException("implementationArtifacts must not be null"); + } + for (ImplementationArtifact ia : implementationArtifacts) { + // ia.getName() might be null as TOSCA COS01 does not forsee a name on the implementation artifact + // Therefore, we begin the test with "artifactId" + if (artifactId.equals(ia.getName())) { + return ia; + } + } + // IA does not exist in list + ImplementationArtifact ia = new ImplementationArtifact(); + ia.setName(artifactId); + implementationArtifacts.add(ia); + return ia; + } + + public ImplementationArtifactResource(String artifactId, List<ImplementationArtifact> implementationArtifacts, IPersistable res) { + this(ImplementationArtifactResource.getImplementationArtifact(artifactId, implementationArtifacts), implementationArtifacts, res); + } + + public ImplementationArtifactResource(IIdDetermination<ImplementationArtifact> idDetermination, ImplementationArtifact o, int idx, List<ImplementationArtifact> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + this.a = o; + } + + public ImplementationArtifactResource(ImplementationArtifact a, List<ImplementationArtifact> implementationArtifacts, IPersistable res) { + this(new IIdDetermination<ImplementationArtifact>() { + + @Override + public String getId(ImplementationArtifact e) { + return e.getName(); + } + }, a, implementationArtifacts.indexOf(a), implementationArtifacts, res); + } + + public ImplementationArtifact getImplementationArtifact() { + return this.a; + } + + @Override + public void setArtifactType(ArtifactTypeId artifactTypeId) { + this.getImplementationArtifact().setArtifactType(artifactTypeId.getQName()); + BackendUtils.persist(this.res); + } + + @Override + public void setArtifactTemplate(ArtifactTemplateId artifactTemplateId) { + this.getImplementationArtifact().setArtifactRef(artifactTemplateId.getQName()); + BackendUtils.persist(this.res); + } + + @Override + public ImplementationArtifact getA() { + return this.a; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactsResource.java new file mode 100644 index 0000000..e1d7aa6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactsResource.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,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.artifacts; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact; +import org.eclipse.winery.repository.resources.INodeTypeImplementationResourceOrRelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypesResource; +import org.eclipse.winery.repository.resources.interfaces.InterfaceResource; + +/** + * ImplementationArtifact instead of TImplementationArtifact has to be used + * because of difference in the XSD at tImplementationArtifacts vs. + * tDeploymentArtifacts + */ +public class ImplementationArtifactsResource extends GenericArtifactsResource<ImplementationArtifactResource, ImplementationArtifact> { + + private List<ImplementationArtifact> implementationArtifacts; + + + public ImplementationArtifactsResource(List<ImplementationArtifact> implementationArtifact, INodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) { + super(ImplementationArtifactResource.class, ImplementationArtifact.class, implementationArtifact, res); + this.implementationArtifacts = implementationArtifact; + } + + /** + * @return a cast to TNodeTypeImplementationResource of the parent of this + * resource. + */ + protected NodeTypeImplementationResource getNTI() { + return (NodeTypeImplementationResource) this.res; + } + + /** + * @return a cast to TNodeTypeImplementationResource of the parent of this + * resource. + */ + protected RelationshipTypeImplementationResource getRTI() { + return (RelationshipTypeImplementationResource) this.res; + } + + @Override + public Collection<ImplementationArtifactResource> getAllArtifactResources() { + Collection<ImplementationArtifactResource> res = new ArrayList<ImplementationArtifactResource>(this.implementationArtifacts.size()); + for (ImplementationArtifact da : this.implementationArtifacts) { + ImplementationArtifactResource r = new ImplementationArtifactResource(da, this.implementationArtifacts, this.res); + res.add(r); + } + return res; + } + + /** required by artifacts.jsp **/ + public List<InterfaceResource> getInterfacesOfAssociatedType() { + boolean isNodeTypeImplementation = this.res instanceof NodeTypeImplementationResource; + QName type; + List<InterfaceResource> interfaces = new ArrayList<InterfaceResource>(); + if (isNodeTypeImplementation) { + type = this.getNTI().getType(); + NodeTypeResource typeResource = (NodeTypeResource) new NodeTypesResource().getComponentInstaceResource(type); + interfaces.addAll(typeResource.getInterfaces().getAllEntityResources()); + } else { + type = this.getRTI().getType(); + RelationshipTypeResource typeResource = (RelationshipTypeResource) new RelationshipTypesResource().getComponentInstaceResource(type); + interfaces.addAll(typeResource.getSourceInterfaces().getAllEntityResources()); + interfaces.addAll(typeResource.getTargetInterfaces().getAllEntityResources()); + } + return interfaces; + } + + @Override + public String getId(ImplementationArtifact entity) { + return entity.getName(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationResource.java new file mode 100644 index 0000000..6783948 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationResource.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.documentation; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.PUT; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TDocumentation; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.CollectionsHelper; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource; + +public class DocumentationResource extends EntityWithoutIdResource<TDocumentation> { + + public DocumentationResource(TDocumentation o, int idx, List<TDocumentation> list, IPersistable res) { + super(o, idx, list, res); + } + + @PUT + @Consumes(MediaType.TEXT_HTML) + @Produces(MediaType.TEXT_PLAIN) + public Response setValue(String documentation) { + this.o.getContent().clear(); + this.o.getContent().add(documentation); + this.list.set(this.idx, this.o); + return CollectionsHelper.persist(this.res, this.idDetermination, this.o); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationsResource.java new file mode 100644 index 0000000..1466a57 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationsResource.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.documentation; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.model.tosca.TDocumentation; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.CollectionsHelper; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class DocumentationsResource extends EntityWithoutIdCollectionResource<DocumentationResource, TDocumentation> { + + private static final Logger logger = LoggerFactory.getLogger(DocumentationResource.class); + + + public DocumentationsResource(IPersistable res, List<TDocumentation> documentations) { + super(DocumentationResource.class, TDocumentation.class, documentations, res); + } + + @Override + public Viewable getHTML() { + return new Viewable("/jsp/documentation.jsp", this.list); + } + + /** + * Adds a new documentation + */ + @POST + @Consumes(MediaType.TEXT_HTML) + public Response addNewElement(String documentation) { + if (documentation == null) { + return Response.status(Status.BAD_REQUEST).entity("No content provided").build(); + } + TDocumentation doc = new TDocumentation(); + doc.getContent().add(documentation); + // TODO: check for duplicates as in instance states + this.list.add(doc); + return CollectionsHelper.persist(this.res, this, doc); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/IEntityTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/IEntityTemplateResource.java new file mode 100644 index 0000000..e5025b1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/IEntityTemplateResource.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytemplates; + +import javax.ws.rs.DELETE; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources.IHasTypeReference; + +/** + * Interface ensuring that no methods are forgotten when implementing an + * {@link AbstractComponentInstanceResource}, which is also a template + */ +public interface IEntityTemplateResource<E extends TEntityTemplate> extends IHasTypeReference { + + @Path("properties/") + public PropertiesResource getPropertiesResource(); + + @DELETE + public Response onDelete(); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/PropertiesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/PropertiesResource.java new file mode 100644 index 0000000..4341095 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/PropertiesResource.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytemplates; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; + +import com.sun.jersey.api.view.Viewable; + +public class PropertiesResource { + + private AbstractComponentInstanceResource res; + private TEntityTemplate template; + + + /** + * @param template the template to store the definitions at + * @param res the resource to save after modifications + */ + public PropertiesResource(TEntityTemplate template, AbstractComponentInstanceResource res) { + this.template = template; + this.res = res; + } + + /** + * Currently, properties can only be updated as a whole XML fragment + * + * Getting/setting a fragment of properties is not possible yet + */ + @PUT + @Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML, MediaType.APPLICATION_JSON}) + public Response setProperties(TEntityTemplate.Properties properties) { + this.getTemplate().setProperties(properties); + return BackendUtils.persist(this.res); + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytemplates/properties.jsp", this); + } + + /** data for the JSP **/ + + public TEntityTemplate getTemplate() { + return this.template; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplateResource.java new file mode 100644 index 0000000..ee9064b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplateResource.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 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.entitytemplates; + +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources.IHasTypeReference; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; + +public class TEntityTemplateResource<E extends TEntityTemplate> extends EntityWithIdResource<E> implements IEntityTemplateResource<E>, IHasTypeReference { + + /** + * This constructor is used for both entity templates nested in an component + * instance as well as for entity templates being component instances + * itself. + * + * As Java does not support multi-inheritance, we implemented a quick hack + * to re-use this class as inner implementation at templates extending + * AbstractComponentInstanceResourceDefinitionsBacked + */ + public TEntityTemplateResource(IIdDetermination<E> idDetermination, E o, int idx, List<E> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + // public String getId() { + // return this.template.getId(); + // } + // + // public void setId(String id) { + // // TODO: There is no check for uniqueness of the given id + // this.template.setId(id); + // } + + /** + * {@inheritDoc} + */ + @Override + public QName getType() { + return this.o.getType(); + } + + @Path("type") + @GET + public String getTypeAsQNameString() { + return this.getType().toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public Response setType(QName type) { + this.o.setType(type); + return BackendUtils.persist(this.res); + } + + /** + * {@inheritDoc} + */ + @Override + public Response setType(String typeStr) { + return this.setType(QName.valueOf(typeStr)); + } + + /** + * {@inheritDoc} + */ + @Override + public PropertiesResource getPropertiesResource() { + return new PropertiesResource(this.o, (AbstractComponentInstanceResource) this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplatesResource.java new file mode 100644 index 0000000..256e376 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplatesResource.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 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.entitytemplates; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; + +/** + * This resource models the list of TEntityTemplates + */ +public abstract class TEntityTemplatesResource<R extends EntityWithIdResource<T>, T extends TEntityTemplate> extends EntityWithIdCollectionResource<R, T> { + + public TEntityTemplatesResource(Class<R> entityResourceTClazz, Class<T> entityTClazz, List<T> list, IPersistable res) { + super(entityResourceTClazz, entityTClazz, list, res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplateResource.java new file mode 100644 index 0000000..f3ed0e9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplateResource.java @@ -0,0 +1,308 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 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.entitytemplates.artifacttemplates; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.SortedSet; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.model.tosca.TArtifactReference; +import org.eclipse.winery.model.tosca.TArtifactTemplate; +import org.eclipse.winery.model.tosca.TArtifactTemplate.ArtifactReferences; +import org.eclipse.winery.model.tosca.TDeploymentArtifact; +import org.eclipse.winery.model.tosca.TDeploymentArtifacts; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImplementationArtifact; +import org.eclipse.winery.model.tosca.TImplementationArtifacts; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +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.datatypes.ids.elements.ArtifactTemplateDirectoryId; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceWithReferencesResource; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; +import org.eclipse.winery.repository.resources.IHasName; +import org.eclipse.winery.repository.resources.entitytemplates.IEntityTemplateResource; +import org.eclipse.winery.repository.resources.entitytemplates.PropertiesResource; +import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplateResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypes.artifacttypes.ArtifactTypeResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; + +/** + * Models an Artifact Template with its artifact references + * + * The associated files (through tArtifactReference) are stored directly within + * this resource. The element <ArtifactReference> is generated during export + * only + * + * This class inherits from AbstractComponentInstanceResourceDefinitionsBacked + * and not from TEntityTemplateResource<TArtifactTemplate>, because + * ArtifactTemplates are directly available under TDefinitions and we need the + * generic resource handling + */ + +public class ArtifactTemplateResource extends AbstractComponentInstanceWithReferencesResource implements IEntityTemplateResource<TArtifactTemplate>, IHasName { + + private final TEntityTemplateResource<TArtifactTemplate> entityTemplateResource; + + + public ArtifactTemplateResource(ArtifactTemplateId id) { + super(id); + // we provide the minimum requirements for the resource + this.entityTemplateResource = new TEntityTemplateResource<TArtifactTemplate>(null, this.getTArtifactTemplate(), 0, null, this); + } + + /** + * @return null if no artifact type resource is defined + */ + public ArtifactTypeResource getAritfactTypeResource() { + ArtifactTypeId atId = new ArtifactTypeId(this.getTArtifactTemplate().getType()); + return new ArtifactTypeResource(atId); + } + + private TArtifactTemplate getTArtifactTemplate() { + return (TArtifactTemplate) this.element; + } + + @Override + public String getName() { + String name = this.getTArtifactTemplate().getName(); + if (name == null) { + return this.getTArtifactTemplate().getId(); + } else { + return name; + } + } + + @Override + public Response setName(String name) { + this.getTArtifactTemplate().setName(name); + return BackendUtils.persist(this); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TArtifactTemplate(); + } + + @Override + protected void copyIdToFields() { + this.getTArtifactTemplate().setId(this.getId().getXmlId().getDecoded()); + // Namespace cannot be set as the namespace is contained in TDefinitions only + } + + /** + * {@inheritDoc} + */ + @Override + public void synchronizeReferences() { + TArtifactTemplate template = this.getTArtifactTemplate(); + + ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId((ArtifactTemplateId) this.id); + SortedSet<RepositoryFileReference> files = Repository.INSTANCE.getContainedFiles(fileDir); + if (files.isEmpty()) { + // clear artifact references + template.setArtifactReferences(null); + } else { + ArtifactReferences artifactReferences = new ArtifactReferences(); + template.setArtifactReferences(artifactReferences); + List<TArtifactReference> artRefList = artifactReferences.getArtifactReference(); + for (RepositoryFileReference ref : files) { + // determine path + // path relative from the root of the CSAR is ok (COS01, line 2663) + String path = Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(ref)); + + // put path into data structure + // we do not use Inlude/Exclude as we directly reference a concrete file + TArtifactReference artRef = new TArtifactReference(); + artRef.setReference(path); + artRefList.add(artRef); + } + } + } + + @Path("files/") + public FilesResource getFilesResource() { + ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId((ArtifactTemplateId) this.id); + return new FilesResource(fileDir); + } + + /*********************************************************************** + * "inheritance" from TEntityTemplateResource<TArtifactTemplate> * + * + * Offering all methods of TEntityTemplateResource<TArtifactTemplate> and + * forwarding it to our private instance of it + */ + + @Override + public QName getType() { + return this.entityTemplateResource.getType(); + } + + @Override + public Response setType(QName type) { + this.entityTemplateResource.setType(type); + return BackendUtils.persist(this); + } + + @Override + public Response setType(String typeStr) { + this.entityTemplateResource.setType(typeStr); + return BackendUtils.persist(this); + } + + @Override + public PropertiesResource getPropertiesResource() { + return new PropertiesResource(this.getTArtifactTemplate(), this); + } + + int getReferenceCount() { + // We do not use a database, therefore, we have to go through all possibilities pointing to the artifact template + // DAs and IAs point to an artifact template + // DAs are contained in Node Type Implementations and Node Templates + // IAs are contained in Node Type Implementations and Relationship Type Implementations + + int count = 0; + + Collection<TDeploymentArtifact> allDAs = new HashSet<>(); + Collection<TImplementationArtifact> allIAs = new HashSet<>(); + + // handle Node Type Implementation, which contains DAs and IAs + SortedSet<NodeTypeImplementationId> nodeTypeImplementations = Repository.INSTANCE.getAllTOSCAComponentIds(NodeTypeImplementationId.class); + for (NodeTypeImplementationId ntiId : nodeTypeImplementations) { + NodeTypeImplementationResource ntiRes = (NodeTypeImplementationResource) AbstractComponentsResource.getComponentInstaceResource(ntiId); + TDeploymentArtifacts deploymentArtifacts = ntiRes.getNTI().getDeploymentArtifacts(); + if (deploymentArtifacts != null) { + allDAs.addAll(deploymentArtifacts.getDeploymentArtifact()); + } + TImplementationArtifacts implementationArtifacts = ntiRes.getNTI().getImplementationArtifacts(); + if (implementationArtifacts != null) { + allIAs.addAll(implementationArtifacts.getImplementationArtifact()); + } + } + + // check all Relationshiptype Implementations for IAs + SortedSet<RelationshipTypeImplementationId> relationshipTypeImplementations = Repository.INSTANCE.getAllTOSCAComponentIds(RelationshipTypeImplementationId.class); + for (RelationshipTypeImplementationId rtiId : relationshipTypeImplementations) { + RelationshipTypeImplementationResource rtiRes = (RelationshipTypeImplementationResource) AbstractComponentsResource.getComponentInstaceResource(rtiId); + TImplementationArtifacts implementationArtifacts = rtiRes.getRTI().getImplementationArtifacts(); + if (implementationArtifacts != null) { + allIAs.addAll(implementationArtifacts.getImplementationArtifact()); + } + } + + // check all node templates for DAs + SortedSet<ServiceTemplateId> serviceTemplates = Repository.INSTANCE.getAllTOSCAComponentIds(ServiceTemplateId.class); + for (ServiceTemplateId sid : serviceTemplates) { + ServiceTemplateResource serviceTemplateRes = (ServiceTemplateResource) AbstractComponentsResource.getComponentInstaceResource(sid); + TTopologyTemplate topologyTemplate = serviceTemplateRes.getServiceTemplate().getTopologyTemplate(); + if (topologyTemplate != null) { + List<TEntityTemplate> nodeTemplateOrRelationshipTemplate = topologyTemplate.getNodeTemplateOrRelationshipTemplate(); + for (TEntityTemplate template : nodeTemplateOrRelationshipTemplate) { + if (template instanceof TNodeTemplate) { + TNodeTemplate nodeTemplate = (TNodeTemplate) template; + TDeploymentArtifacts deploymentArtifacts = nodeTemplate.getDeploymentArtifacts(); + if (deploymentArtifacts != null) { + allDAs.addAll(deploymentArtifacts.getDeploymentArtifact()); + } + } + } + } + } + + // now we have all DAs and IAs + + QName ourQName = this.getQName(); + + // check DAs for artifact templates + for (TDeploymentArtifact da : allDAs) { + QName artifactRef = da.getArtifactRef(); + if (ourQName.equals(artifactRef)) { + count++; + } + } + + // check IAs for artifact templates + for (TImplementationArtifact ia : allIAs) { + QName artifactRef = ia.getArtifactRef(); + if (ourQName.equals(artifactRef)) { + count++; + } + } + + return count; + } + + /** + * Query parameter {@code type}:<br /> + * Returns the type of the artifact template + * + * Query parameter {@code referenceCount}:<br /> + * Determines the number of elements known by the repository which point to + * this resource. This method probably can be moved up the type hierarchy. + * Currently, it is only required here by the topology modeler. + * + * @return the type of the artifact template OR the number of references + * pointing to this resource + */ + @GET + @Produces(MediaType.TEXT_PLAIN) + public Response getRefereneCount(@QueryParam("referenceCount") String referenceCount, @QueryParam("type") String type) { + if (referenceCount != null) { + String res = Integer.toString(this.getReferenceCount()); + return Response.ok().entity(res).build(); + } else if (type != null) { + String res = this.getType().toString(); + return Response.ok().entity(res).build(); + } else { + // we enforce the query parameter to be extensible to other queries + return Response.status(Status.BAD_REQUEST).entity("You have to pass the query parameter referenceCount or type").build(); + } + + } + + /* not yet implemented */ + /* + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getReferenes(@QueryParam("references") String references) { + if (references== null) { + // we enforce the query parameter to be extensible to other queries + return Response.status(Status.BAD_REQUEST).entity("You have to pass the query parameter references").build(); + } + + String res = Integer.toString(this.getReferenceCount()); + return Response.ok().entity(res).build(); + } + */ + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplatesResource.java new file mode 100644 index 0000000..e02a668 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplatesResource.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytemplates.artifacttemplates; + +import org.eclipse.winery.repository.resources.AbstractComponentsWithTypeReferenceResource; + +/** + * This class does NOT inherit from TEntityTemplatesResource<ArtifactTemplate> + * as these templates are directly nested in a TDefinitionsElement + */ +public class ArtifactTemplatesResource extends AbstractComponentsWithTypeReferenceResource<ArtifactTemplateResource> { +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/FilesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/FilesResource.java new file mode 100644 index 0000000..0a910fe --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/FilesResource.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,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.entitytemplates.artifacttemplates; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.SortedSet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +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.datatypes.FileMeta; +import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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; + +public class FilesResource { + + private static final Logger logger = LoggerFactory.getLogger(FilesResource.class); + private final ArtifactTemplateDirectoryId fileDir; + + + public FilesResource(ArtifactTemplateDirectoryId fileDir) { + this.fileDir = fileDir; + } + + private String getData4jqueryFileUpload(List<FileMeta> metas) { + String data4jqueryFileUpload = Utils.Object2JSON(metas); + data4jqueryFileUpload = "{\"files\":" + data4jqueryFileUpload + "}"; + return data4jqueryFileUpload; + } + + /** + * Handles the upload of a <em>single</em> file. Adds the given file to the + * current artifact template. + * + * If the file already exists, is it <em>overridden</em> + * + * @return JSON with data required by JQuery-File-Upload (see + * https://github.com/blueimp/jQuery-File-Upload/wiki/Setup) + */ + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response onPost(@FormDataParam("files[]") InputStream uploadedInputStream, @FormDataParam("files[]") FormDataContentDisposition fileDetail, @FormDataParam("files[]") FormDataBodyPart body, @Context UriInfo uriInfo) { + // existence check not required as instantiation of the resource ensures that the object only exists if the resource exists + FilesResource.logger.debug("Beginning with file upload"); + + String fileName = fileDetail.getFileName(); + if (StringUtils.isEmpty(fileName)) { + return Response.status(Status.BAD_REQUEST).build(); + } + RepositoryFileReference ref = this.fileName2fileRef(fileName, false); + + // TODO: instead of fixing the media type, we could overwrite the browser's mediatype by using some user configuration + BufferedInputStream bis = new BufferedInputStream(uploadedInputStream); + MediaType mediaType = Utils.getFixedMimeType(bis, fileName, body.getMediaType()); + + Response response = BackendUtils.putContentToFile(ref, bis, mediaType); + if (response.getStatus() == Status.INTERNAL_SERVER_ERROR.getStatusCode()) { + return response; + } + + // create FileMeta object + String URL = Utils.getAbsoluteURL(this.fileDir) + Util.URLencode(fileName); + String thumbnailURL = uriInfo.getBaseUriBuilder().path(Constants.PATH_MIMETYPEIMAGES).path(FilenameUtils.getExtension(fileName) + Constants.SUFFIX_MIMETYPEIMAGES).build().toString(); + long size; + try { + size = Repository.INSTANCE.getSize(ref); + } catch (IOException e) { + FilesResource.logger.error(e.getMessage(), e); + return Response.serverError().entity(e.getMessage()).build(); + } + FileMeta fileMeta = new FileMeta(fileName, size, URL, thumbnailURL); + + List<FileMeta> metas = new ArrayList<FileMeta>(); + metas.add(fileMeta); + return Response.created(Utils.createURI(URL)).entity(this.getData4jqueryFileUpload(metas)).build(); + } + + /** + * Returns a list of file meta object + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public String getJSON() { + return this.getData4jqueryFileUpload(this.getAllFileMetas()); + } + + private List<FileMeta> getAllFileMetas() { + List<FileMeta> res = new ArrayList<FileMeta>(); + SortedSet<RepositoryFileReference> fileRefs = Repository.INSTANCE.getContainedFiles(this.fileDir); + for (RepositoryFileReference ref : fileRefs) { + res.add(new FileMeta(ref)); + } + return res; + } + + private RepositoryFileReference fileName2fileRef(String fileName, boolean encoded) { + if (encoded) { + fileName = Util.URLdecode(fileName); + } + RepositoryFileReference ref = new RepositoryFileReference(this.fileDir, fileName); + return ref; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytemplates/artifacttemplates/files.jsp"); + } + + @GET + @Path("/{fileName}") + public Response getFile(@PathParam("fileName") String fileName, @HeaderParam("If-Modified-Since") String modified) { + RepositoryFileReference ref = this.fileName2fileRef(fileName, true); + return BackendUtils.returnRepoPath(ref, modified); + } + + @DELETE + @Path("/{fileName}") + public Response deleteFile(@PathParam("fileName") String fileName) { + RepositoryFileReference ref = this.fileName2fileRef(fileName, true); + return BackendUtils.delete(ref); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/package-info.java new file mode 100644 index 0000000..4375378 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/package-info.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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 + *******************************************************************************/ +/** + * The sub packages of this package contains all resources, which are derived + * from tEntityTemplate + * + * EntityTemplates get their namespaces from the surrounding + * Definitions-element. <br /> + * Nevertheless, they are stored using the same filesystem structure as + * EntityTypes + * + * {@link org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.RelationshipTemplateResource} + * and + * {@link org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.NodeTemplateResource} + * are stored in the topology package + */ +package org.eclipse.winery.repository.resources.entitytemplates; + diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplateResource.java new file mode 100644 index 0000000..e69a282 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplateResource.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytemplates.policytemplates; + +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.PolicyTemplateId; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TPolicyTemplate; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources.IHasName; +import org.eclipse.winery.repository.resources.entitytemplates.IEntityTemplateResource; +import org.eclipse.winery.repository.resources.entitytemplates.PropertiesResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class PolicyTemplateResource extends AbstractComponentInstanceResource implements IEntityTemplateResource<TPolicyTemplate>, IHasName { + + private static final Logger logger = LoggerFactory.getLogger(PolicyTemplateResource.class); + + + /** + * Constructor has to be public because of test cases + */ + public PolicyTemplateResource(PolicyTemplateId id) { + super(id); + } + + /** + * Convenience method to avoid casting at the caller's side. + */ + public TPolicyTemplate getPolicyTemplate() { + return (TPolicyTemplate) this.getElement(); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TPolicyTemplate(); + } + + @Override + public QName getType() { + return this.getPolicyTemplate().getType(); + } + + @Override + public Response setType(QName type) { + this.getPolicyTemplate().setType(type); + return BackendUtils.persist(this); + } + + @Override + public Response setType(String typeStr) { + this.getPolicyTemplate().setType(QName.valueOf(typeStr)); + return BackendUtils.persist(this); + } + + @Override + public PropertiesResource getPropertiesResource() { + return new PropertiesResource(this.getPolicyTemplate(), this); + } + + @Override + protected void copyIdToFields() { + this.getPolicyTemplate().setId(this.getId().getXmlId().getDecoded()); + } + + @Override + public String getName() { + String name = this.getPolicyTemplate().getName(); + if (name == null) { + return this.getPolicyTemplate().getId(); + } else { + return name; + } + } + + @Override + public Response setName(String name) { + this.getPolicyTemplate().setName(name); + return BackendUtils.persist(this); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplatesResource.java new file mode 100644 index 0000000..685ab66 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplatesResource.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytemplates.policytemplates; + +import org.eclipse.winery.repository.resources.AbstractComponentsWithTypeReferenceResource; + +/** + * Manages all policy types in all available namespaces <br /> + * The actual implementation is done in the + * AbstractComponentsWithTypeReferenceResource + */ +public class PolicyTemplatesResource extends AbstractComponentsWithTypeReferenceResource<PolicyTemplateResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/EntityTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/EntityTypeImplementationResource.java new file mode 100644 index 0000000..8b48e74 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/EntityTypeImplementationResource.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypeimplementations; + +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal; +import org.eclipse.winery.repository.resources.IHasTypeReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class EntityTypeImplementationResource extends AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal implements IHasTypeReference { + + private static final Logger logger = LoggerFactory.getLogger(EntityTypeImplementationResource.class); + + + protected EntityTypeImplementationResource(TOSCAComponentId id) { + super(id); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationResource.java new file mode 100644 index 0000000..95b95d2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationResource.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypeimplementations.nodetypeimplementations; + +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId; +import org.eclipse.winery.model.tosca.TDeploymentArtifacts; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImplementationArtifacts; +import org.eclipse.winery.model.tosca.TNodeTypeImplementation; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResource; +import org.eclipse.winery.repository.resources.INodeTypeImplementationResourceOrRelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.artifacts.DeploymentArtifactsResource; +import org.eclipse.winery.repository.resources.artifacts.ImplementationArtifactsResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.EntityTypeImplementationResource; + +public class NodeTypeImplementationResource extends EntityTypeImplementationResource implements INodeTemplateResourceOrNodeTypeImplementationResource, INodeTypeImplementationResourceOrRelationshipTypeImplementationResource { + + public NodeTypeImplementationResource(NodeTypeImplementationId id) { + super(id); + } + + /** + * public because of exporter + */ + public TNodeTypeImplementation getNTI() { + return (TNodeTypeImplementation) this.getElement(); + } + + /** + * Even if both node type implementations and relationship type + * implementations have implementation artifacts, there is no common + * supertype. To avoid endless casts, we just implement the method here + * + * @return + */ + @Path("implementationartifacts/") + public ImplementationArtifactsResource getImplementationArtifacts() { + TImplementationArtifacts implementationArtifacts; + implementationArtifacts = this.getNTI().getImplementationArtifacts(); + if (implementationArtifacts == null) { + implementationArtifacts = new TImplementationArtifacts(); + this.getNTI().setImplementationArtifacts(implementationArtifacts); + } + return new ImplementationArtifactsResource(implementationArtifacts.getImplementationArtifact(), this); + } + + /** + * Only NodeTypes have deployment artifacts, not RelationshipType. + * Therefore, this method is declared in + * {@link NodeTypeImplementationResource} and not in + * {@link EntityTypeImplementationResource} + */ + @Path("deploymentartifacts/") + public DeploymentArtifactsResource getDeploymentArtifacts() { + TDeploymentArtifacts deploymentArtifacts; + deploymentArtifacts = this.getNTI().getDeploymentArtifacts(); + if (deploymentArtifacts == null) { + deploymentArtifacts = new TDeploymentArtifacts(); + this.getNTI().setDeploymentArtifacts(deploymentArtifacts); + } + return new DeploymentArtifactsResource(deploymentArtifacts.getDeploymentArtifact(), this); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TNodeTypeImplementation(); + } + + @Override + protected void copyIdToFields() { + this.getNTI().setTargetNamespace(this.getId().getNamespace().getDecoded()); + this.getNTI().setName(this.getId().getXmlId().getDecoded()); + } + + @Override + public QName getType() { + return this.getNTI().getNodeType(); + } + + @Override + public Response setType(QName type) { + this.getNTI().setNodeType(type); + return BackendUtils.persist(this); + } + + @Override + public Response setType(String typeStr) { + QName type = QName.valueOf(typeStr); + return this.setType(type); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationsResource.java new file mode 100644 index 0000000..b9c0836 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationsResource.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypeimplementations.nodetypeimplementations; + +import org.eclipse.winery.repository.resources.AbstractComponentsWithTypeReferenceResource; + +public class NodeTypeImplementationsResource extends AbstractComponentsWithTypeReferenceResource<NodeTypeImplementationResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/package-info.java new file mode 100644 index 0000000..af1c346 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/package-info.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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 + *******************************************************************************/ +/** + * The sub packages of this package contains all resources, which are + * implementations of a type. <br /> + * The specification does NOT introduce tEntityTypeImplementation, but we + * implement as if that had been happened. + */ +package org.eclipse.winery.repository.resources.entitytypeimplementations; + diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationResource.java new file mode 100644 index 0000000..521758a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationResource.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypeimplementations.relationshiptypeimplementations; + +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImplementationArtifacts; +import org.eclipse.winery.model.tosca.TRelationshipTypeImplementation; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.INodeTypeImplementationResourceOrRelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.artifacts.ImplementationArtifactsResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.EntityTypeImplementationResource; + +public class RelationshipTypeImplementationResource extends EntityTypeImplementationResource implements INodeTypeImplementationResourceOrRelationshipTypeImplementationResource { + + public RelationshipTypeImplementationResource(RelationshipTypeImplementationId id) { + super(id); + } + + public TRelationshipTypeImplementation getRTI() { + return (TRelationshipTypeImplementation) this.getElement(); + } + + /** + * Even if both node type implementations and relationship type + * implementations have implementation artifacts, there is no common + * supertype. To avoid endless casts, we just implement the method here + */ + @Path("implementationartifacts/") + public ImplementationArtifactsResource getImplementationArtifacts() { + TImplementationArtifacts implementationArtifacts; + implementationArtifacts = this.getRTI().getImplementationArtifacts(); + if (implementationArtifacts == null) { + implementationArtifacts = new TImplementationArtifacts(); + this.getRTI().setImplementationArtifacts(implementationArtifacts); + } + return new ImplementationArtifactsResource(implementationArtifacts.getImplementationArtifact(), this); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TRelationshipTypeImplementation(); + } + + @Override + protected void copyIdToFields() { + this.getRTI().setTargetNamespace(this.getId().getNamespace().getDecoded()); + this.getRTI().setName(this.getId().getXmlId().getDecoded()); + } + + @Override + public QName getType() { + return this.getRTI().getRelationshipType(); + } + + @Override + public Response setType(QName type) { + this.getRTI().setRelationshipType(type); + return BackendUtils.persist(this); + } + + @Override + public Response setType(String typeStr) { + QName qname = QName.valueOf(typeStr); + return this.setType(qname); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationsResource.java new file mode 100644 index 0000000..f503a6f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationsResource.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypeimplementations.relationshiptypeimplementations; + +import org.eclipse.winery.repository.resources.AbstractComponentsWithTypeReferenceResource; + +public class RelationshipTypeImplementationsResource extends AbstractComponentsWithTypeReferenceResource<RelationshipTypeImplementationResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/ImplementationsOfOneType.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/ImplementationsOfOneType.java new file mode 100644 index 0000000..5f4d06e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/ImplementationsOfOneType.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,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.entitytypes; + +import java.util.Collection; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.definitions.TopologyGraphElementEntityTypeId; +import org.eclipse.winery.repository.resources.admin.NamespacesResource; + +import com.sun.jersey.api.view.Viewable; + +/** + * specifies the methods required by implementations.jsp + */ +public abstract class ImplementationsOfOneType { + + private final TopologyGraphElementEntityTypeId typeId; + + + public ImplementationsOfOneType(TopologyGraphElementEntityTypeId typeId) { + this.typeId = typeId; + } + + public TopologyGraphElementEntityTypeId getTypeId() { + return this.typeId; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML() { + Viewable viewable = new Viewable("/jsp/entitytypes/implementations.jsp", this); + return Response.ok().entity(viewable).build(); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public abstract Response getJSON(); + + public Collection<Namespace> getNamespaceAutocompletionList() { + return NamespacesResource.getNamespaces(); + } + + /** + * @return a list of type implementations implementing the associated node + * type + */ + public abstract String getImplementationsTableData(); + + /** + * The string used as URL part + */ + public abstract String getType(); + + /** + * The string displayed to the user + */ + public abstract String getTypeStr(); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/InstanceStatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/InstanceStatesResource.java new file mode 100644 index 0000000..4eaea1c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/InstanceStatesResource.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +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.model.tosca.TTopologyElementInstanceStates; +import org.eclipse.winery.model.tosca.TTopologyElementInstanceStates.InstanceState; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.backend.BackendUtils; + +import com.sun.jersey.api.view.Viewable; + +/** + * Resource for instance states <br /> + * Used by relationship types and node types + */ +public class InstanceStatesResource { + + private TopologyGraphElementEntityTypeResource typeResource; + private TTopologyElementInstanceStates instanceStates; + + + /** + * + * @param instanceStates the instanceStates to manage + * @param typeResource the type resource, where the instance states are + * managed. This reference is required to fire "persist()" in + * case of updates + */ + public InstanceStatesResource(TTopologyElementInstanceStates instanceStates, TopologyGraphElementEntityTypeResource typeResource) { + this.instanceStates = instanceStates; + this.typeResource = typeResource; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/instancestates.jsp", this); + } + + public List<String> getInstanceStates() { + List<InstanceState> instanceStates = this.instanceStates.getInstanceState(); + ArrayList<String> states = new ArrayList<String>(instanceStates.size()); + for (InstanceState instanceState : instanceStates) { + states.add(instanceState.getState()); + } + return states; + } + + @DELETE + @Path("{instanceState}") + public Response deleteInstanceState(@PathParam("instanceState") String instanceStateToRemove) { + if (StringUtils.isEmpty(instanceStateToRemove)) { + return Response.status(Status.BAD_REQUEST).entity("null instance to remove").build(); + } + instanceStateToRemove = Util.URLdecode(instanceStateToRemove); + + // InstanceState does not override "equals()", therefore we have to manually remove it + + List<InstanceState> instanceStates = this.instanceStates.getInstanceState(); + Iterator<InstanceState> iterator = instanceStates.iterator(); + boolean found = false; + while (iterator.hasNext() && !found) { + if (iterator.next().getState().equals(instanceStateToRemove)) { + found = true; + } + } + + if (!found) { + return Response.status(Status.NOT_FOUND).build(); + } + + iterator.remove(); + + return BackendUtils.persist(this.typeResource); + } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response addInstanceState(@FormParam("state") String state) { + if (StringUtils.isEmpty(state)) { + return Response.notAcceptable(null).build(); + } + + // InstanceState does not override "equals()", therefore we have to manually check for existance + + List<InstanceState> instanceStates = this.instanceStates.getInstanceState(); + Iterator<InstanceState> iterator = instanceStates.iterator(); + boolean found = false; + while (iterator.hasNext() && !found) { + if (iterator.next().getState().equals(state)) { + found = true; + } + } + + if (found) { + // no error, just return + return Response.noContent().build(); + } + + InstanceState instanceState = new InstanceState(); + instanceState.setState(state); + instanceStates.add(instanceState); + + return BackendUtils.persist(this.typeResource); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/TopologyGraphElementEntityTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/TopologyGraphElementEntityTypeResource.java new file mode 100644 index 0000000..6cebfe8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/TopologyGraphElementEntityTypeResource.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes; + +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.repository.resources.EntityTypeResource; + +public abstract class TopologyGraphElementEntityTypeResource extends EntityTypeResource { + + protected TopologyGraphElementEntityTypeResource(TOSCAComponentId id) { + super(id); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypeResource.java new file mode 100644 index 0000000..232d4f9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypeResource.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.artifacttypes; + +import java.util.SortedSet; + +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.constants.Namespaces; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.model.tosca.TArtifactType; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.datatypes.select2.Select2OptGroup; +import org.eclipse.winery.repository.resources.EntityTypeResource; + +public class ArtifactTypeResource extends EntityTypeResource { + + public ArtifactTypeResource(ArtifactTypeId id) { + super(id); + } + + + private final QName qnameFileExtension = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "fileExtension"); + + + /** + * @return the file extension associated with this artifact type. May be + * null + */ + @GET + @Path("/fileextension") + public String getAssociatedFileExtension() { + return this.getDefinitions().getOtherAttributes().get(this.qnameFileExtension); + } + + @PUT + @Path("/fileextension") + public Response setAssociatedFileExtension(String fileExtension) { + this.getDefinitions().getOtherAttributes().put(this.qnameFileExtension, fileExtension); + return BackendUtils.persist(this); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TArtifactType(); + } + + @Override + public SortedSet<Select2OptGroup> getListOfAllInstances() { + return this.getListOfAllInstances(ArtifactTemplateId.class); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypesResource.java new file mode 100644 index 0000000..b52aa31 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypesResource.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.artifacttypes; + +import java.util.SortedSet; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +public class ArtifactTypesResource extends AbstractComponentsResource<ArtifactTypeResource> { + + // This cannot be used as the INSTANCE is per startup of the whole + // application + // We could do some checking for the number of ArtifactTypeResources or + // timestamp, + // + // private final HashMap<String, ArtifactTypeResource> fileExtensionMapping + // = new ArtifactTypesResource().getFileExtensionMapping(); + + /** + * @return a mapping from file extension to artifact type resources + */ + // public HashMap<String, ArtifactTypeResource> getFileExtensionMapping() { + // HashMap<String, ArtifactTypeResource> res = new HashMap<String, + // ArtifactTypeResource>(); + // for (ArtifactTypeResource at : this.getArtifactTypeResources()) { + // if (at.getAssociatedFileExtension() != null) { + // res.put(at.getAssociatedFileExtension(), at); + // } + // } + // return res; + // } + + @GET + // should be "QName", but that MIME type is not available. XLink is too + // complicated for our setup + @Produces(MediaType.TEXT_PLAIN) + public Response getArtifactTypeQNameForExtension(@QueryParam("extension") String extension) { + if (extension == null) { + return Response.status(Status.NOT_ACCEPTABLE).build(); + } + ArtifactTypeResource artifactType = this.getArtifactTypeForExtension(extension); + Response res; + if (artifactType == null) { + res = Response.status(Status.NOT_FOUND).build(); + } else { + res = Response.ok().entity(artifactType.getId().getQName().toString()).build(); + } + return res; + } + + /** + * Returns the first matching ArtifactTypeResource for the given file + * extension. Returns null if no such ArtifactType can be found + * + * The case of the extension is ignored. + * + * This is more a DAO method + */ + public ArtifactTypeResource getArtifactTypeForExtension(String extension) { + SortedSet<ArtifactTypeId> allArtifactTypeIds = Repository.INSTANCE.getAllTOSCAComponentIds(ArtifactTypeId.class); + ArtifactTypeResource res = null; + for (ArtifactTypeId id : allArtifactTypeIds) { + ArtifactTypeResource r = new ArtifactTypeResource(id); + if (extension.equalsIgnoreCase(r.getAssociatedFileExtension())) { + res = r; + break; + } + } + return res; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypeResource.java new file mode 100644 index 0000000..924efd4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypeResource.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.capabilitytypes; + +import org.eclipse.winery.model.tosca.TCapabilityType; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.common.ids.definitions.CapabilityTypeId; +import org.eclipse.winery.repository.resources.EntityTypeResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class CapabilityTypeResource extends EntityTypeResource { + + private static final Logger logger = LoggerFactory.getLogger(CapabilityTypeResource.class); + + + /** + * Constructor has to be public because of test cases + */ + public CapabilityTypeResource(CapabilityTypeId id) { + super(id); + } + + /** + * Convenience method to avoid casting at the caller's side. + * + * @return the CapabilityType object this resource is representing + */ + public TCapabilityType getCapabilityType() { + return (TCapabilityType) this.getElement(); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TCapabilityType(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypesResource.java new file mode 100644 index 0000000..a34aac2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypesResource.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.capabilitytypes; + +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +/** + * Manages all capability types in all available namespaces <br /> + * The actual implementation is done in the AbstractComponentsResource + */ +public class CapabilityTypesResource extends AbstractComponentsResource<CapabilityTypeResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/ImplementationsOfOneNodeTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/ImplementationsOfOneNodeTypeResource.java new file mode 100644 index 0000000..63d483d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/ImplementationsOfOneNodeTypeResource.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,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.entitytypes.nodetypes; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; + +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.entitytypes.ImplementationsOfOneType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; + +public class ImplementationsOfOneNodeTypeResource extends ImplementationsOfOneType { + + private static final Logger logger = LoggerFactory.getLogger(ImplementationsOfOneNodeTypeResource.class); + + + /** + * The constructor is different from the usual constructors as this resource + * does NOT store own data, but retrieves its data solely from the + * associated node type + * + * @param nodeTypeId the node type id, where this list of implementations + * belongs to + */ + public ImplementationsOfOneNodeTypeResource(NodeTypeId nodeTypeId) { + super(nodeTypeId); + } + + /** + * required by implementations.jsp + * + * @return for each node type implementation implementing the associated + * node type + */ + @Override + public String getImplementationsTableData() { + String res; + JsonFactory jsonFactory = new JsonFactory(); + StringWriter tableDataSW = new StringWriter(); + try { + JsonGenerator jGenerator = jsonFactory.createGenerator(tableDataSW); + jGenerator.writeStartArray(); + + Collection<NodeTypeImplementationId> allNodeTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, this.getTypeId().getQName()); + for (NodeTypeImplementationId ntiID : allNodeTypeImplementations) { + jGenerator.writeStartArray(); + jGenerator.writeString(ntiID.getNamespace().getDecoded()); + jGenerator.writeString(ntiID.getXmlId().getDecoded()); + jGenerator.writeEndArray(); + } + jGenerator.writeEndArray(); + jGenerator.close(); + tableDataSW.close(); + res = tableDataSW.toString(); + } catch (Exception e) { + ImplementationsOfOneNodeTypeResource.logger.error(e.getMessage(), e); + res = "[]"; + } + return res; + } + + @Override + public String getType() { + return "nodetype"; + } + + @Override + public String getTypeStr() { + return "Node Type"; + } + + @Override + public Response getJSON() { + Collection<NodeTypeImplementationId> allImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, this.getTypeId().getQName()); + ArrayList<QName> res = new ArrayList<QName>(allImplementations.size()); + for (NodeTypeImplementationId id : allImplementations) { + res.add(id.getQName()); + } + return Response.ok().entity(res).build(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypeResource.java new file mode 100644 index 0000000..6c573a5 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypeResource.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.nodetypes; + +import javax.ws.rs.Path; + +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TNodeType.CapabilityDefinitions; +import org.eclipse.winery.model.tosca.TNodeType.Interfaces; +import org.eclipse.winery.model.tosca.TNodeType.RequirementDefinitions; +import org.eclipse.winery.model.tosca.TTopologyElementInstanceStates; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.repository.resources.entitytypes.InstanceStatesResource; +import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs.CapabilityDefinitionsResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs.RequirementDefinitionsResource; +import org.eclipse.winery.repository.resources.interfaces.InterfacesResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NodeTypeResource extends TopologyGraphElementEntityTypeResource { + + private static final Logger logger = LoggerFactory.getLogger(NodeTypeResource.class); + + + public NodeTypeResource(NodeTypeId id) { + super(id); + } + + /** + * Convenience method to avoid casting at the caller's side. + */ + public TNodeType getNodeType() { + return (TNodeType) this.getElement(); + } + + /** sub-resources **/ + + @Path("implementations/") + public ImplementationsOfOneNodeTypeResource getImplementations() { + return new ImplementationsOfOneNodeTypeResource((NodeTypeId) this.id); + } + + @Path("instancestates/") + public InstanceStatesResource getInstanceStatesResource() { + TTopologyElementInstanceStates instanceStates = this.getNodeType().getInstanceStates(); + if (instanceStates == null) { + // if an explicit (empty) list does not exist, create it + instanceStates = new TTopologyElementInstanceStates(); + this.getNodeType().setInstanceStates(instanceStates); + } + return new InstanceStatesResource(instanceStates, this); + } + + @Path("interfaces/") + public InterfacesResource getInterfaces() { + Interfaces interfaces = this.getNodeType().getInterfaces(); + if (interfaces == null) { + interfaces = new Interfaces(); + this.getNodeType().setInterfaces(interfaces); + } + return new InterfacesResource(null, interfaces.getInterface(), this); + } + + @Path("requirementdefinitions/") + public RequirementDefinitionsResource getRequirementDefinitions() { + RequirementDefinitions definitions = this.getNodeType().getRequirementDefinitions(); + if (definitions == null) { + definitions = new RequirementDefinitions(); + this.getNodeType().setRequirementDefinitions(definitions); + } + return new RequirementDefinitionsResource(this, definitions.getRequirementDefinition()); + } + + @Path("capabilitydefinitions/") + public CapabilityDefinitionsResource getCapabilityDefinitions() { + CapabilityDefinitions definitions = this.getNodeType().getCapabilityDefinitions(); + if (definitions == null) { + definitions = new CapabilityDefinitions(); + this.getNodeType().setCapabilityDefinitions(definitions); + } + return new CapabilityDefinitionsResource(this, definitions.getCapabilityDefinition()); + } + + @Path("visualappearance/") + public VisualAppearanceResource getVisualAppearanceResource() { + return new VisualAppearanceResource(this, this.getElement().getOtherAttributes(), (NodeTypeId) this.id); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TNodeType(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypesResource.java new file mode 100644 index 0000000..798e5a5 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypesResource.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.nodetypes; + +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +/** + * Manages all nodetypes in all available namespaces <br /> + * The actual implementation is done in the AbstractComponentsResource + */ +public class NodeTypesResource extends AbstractComponentsResource<NodeTypeResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/VisualAppearanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/VisualAppearanceResource.java new file mode 100644 index 0000000..d897efe --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/VisualAppearanceResource.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.nodetypes; + +import java.io.InputStream; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.constants.QNames; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.constants.Filename; +import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId; +import org.eclipse.winery.repository.resources.GenericVisualAppearanceResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + +public class VisualAppearanceResource extends GenericVisualAppearanceResource { + + private static final Logger logger = LoggerFactory.getLogger(VisualAppearanceResource.class); + + + public VisualAppearanceResource(NodeTypeResource res, Map<QName, String> map, NodeTypeId parentId) { + super(res, map, new VisualAppearanceId(parentId)); + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML() { + Viewable viewable = new Viewable("/jsp/entitytypes/nodetypes/visualappearance.jsp", this); + return Response.ok().entity(viewable).build(); + } + + @GET + @Path("50x50") + public Response get50x50Image(@HeaderParam("If-Modified-Since") String modified) { + return this.getImage(Filename.FILENAME_BIG_ICON, modified); + } + + @PUT + @Path("50x50") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response post50x50Image(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataBodyPart body) { + return this.putImage(Filename.FILENAME_BIG_ICON, uploadedInputStream, body.getMediaType()); + } + + @GET + @Path("bordercolor") + public String getBorderColor() { + return BackendUtils.getColorAndSetDefaultIfNotExisting(this.getId().getParent().getXmlId().getDecoded(), QNames.QNAME_BORDER_COLOR, this.otherAttributes, this.res); + } + + @PUT + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Path("bordercolor") + public Response putBorderColor(@FormParam("color") String color) { + this.otherAttributes.put(QNames.QNAME_BORDER_COLOR, color); + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/AbstractReqOrCapDefResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/AbstractReqOrCapDefResource.java new file mode 100644 index 0000000..b7eea92 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/AbstractReqOrCapDefResource.java @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.nodetypes.reqandcapdefs; + +import java.lang.reflect.Method; +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TCapabilityDefinition; +import org.eclipse.winery.model.tosca.TConstraint; +import org.eclipse.winery.model.tosca.TRequirementDefinition; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.ConstraintsResource; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Bundles common properties of TRequirementDefinition and TCapabilityDefinition + * + * We agreed in the project not to modify org.eclipse.winery.model.tosca. + * Therefore, this resource models the common properties of a + * TRequirementDefinition and a TCapabilityDefinition + */ +public abstract class AbstractReqOrCapDefResource<ReqOrCapDef> extends EntityWithIdResource<ReqOrCapDef> implements IIdDetermination<ReqOrCapDef> { + + private static final Logger logger = LoggerFactory.getLogger(AbstractReqOrCapDefResource.class); + + protected NodeTypeResource parent; + + // the capability or the requirement + private Object reqOrCapDef; + + private List<TConstraint> constraints; + + + /** + * @param constraints additional parameter (in comparison to the constructor + * of EntityWithIdResource) as we require that sublist for the + * constrinats sub resource + */ + public AbstractReqOrCapDefResource(IIdDetermination<ReqOrCapDef> idDetermination, ReqOrCapDef reqOrCapDef, int idx, List<ReqOrCapDef> list, NodeTypeResource res, List<TConstraint> constraints) { + super(idDetermination, reqOrCapDef, idx, list, res); + assert ((reqOrCapDef instanceof TRequirementDefinition) || (reqOrCapDef instanceof TCapabilityDefinition)); + this.parent = res; + this.reqOrCapDef = reqOrCapDef; + this.constraints = constraints; + } + + @GET + @Path("name") + public String getName() { + return (String) this.invokeGetter("getName"); + } + + static String getName(Object reqOrCapDef) { + return (String) AbstractReqOrCapDefResource.invokeGetter(reqOrCapDef, "getName"); + } + + @GET + @Path("lowerbound") + public int getLowerBound() { + return (int) this.invokeGetter("getLowerBound"); + } + + @GET + @Path("upperbound") + public String getUpperBound() { + return (String) this.invokeGetter("getUpperBound"); + } + + @PUT + @Path("name") + public Response setName(@FormParam(value = "name") String name) { + // TODO: type check - see also min/max Instance of a node template + this.invokeSetter("setName", name); + return BackendUtils.persist(this.parent); + } + + @PUT + @Path("lowerbound") + public Response setLowerBound(@FormParam(value = "lowerbound") String value) { + // TODO: type check + this.invokeSetter("setLowerBound", value); + return BackendUtils.persist(this.parent); + } + + @PUT + @Path("upperbound") + public Response setUpperBound(@FormParam(value = "upperbound") String value) { + // TODO: type check + this.invokeSetter("setUpperBound", value); + return BackendUtils.persist(this.parent); + } + + @Path("constraints/") + public ConstraintsResource getConstraintsResource() { + return new ConstraintsResource(this.constraints, this.parent); + } + + private static Object invokeGetter(Object reqOrCapDef, String getterName) { + Method method; + Object res; + try { + method = reqOrCapDef.getClass().getMethod(getterName); + res = method.invoke(reqOrCapDef); + } catch (Exception e) { + AbstractReqOrCapDefResource.logger.error("Could not invoke getter {}", getterName, e); + throw new IllegalStateException(e); + } + return res; + } + + private Object invokeGetter(String getterName) { + return AbstractReqOrCapDefResource.invokeGetter(this.reqOrCapDef, getterName); + } + + /** + * Quick hack method for RequirementOrCapabilityDefinitionsResource + */ + static void invokeSetter(Object reqOrCapDef, String setterName, Object value) { + Method method; + try { + method = reqOrCapDef.getClass().getMethod(setterName, value.getClass()); + method.invoke(reqOrCapDef, value); + } catch (Exception e) { + AbstractReqOrCapDefResource.logger.error("Could not invoke setter {}", setterName, e); + throw new IllegalStateException(e); + } + } + + private void invokeSetter(String setterName, Object value) { + AbstractReqOrCapDefResource.invokeSetter(this.reqOrCapDef, setterName, value); + } + + @GET + @Path("type") + @Produces(MediaType.TEXT_PLAIN) + public String getTypeAsString() { + return this.getType().toString(); + } + + /** + * required by the JSP. + * + * Therefore, we have two getters for the type: QName for the JSP and String + * for REST clients + */ + public abstract QName getType(); + + /** + * Required by reqandcapdefs.jsp + */ + public Object getDef() { + return this.reqOrCapDef; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionResource.java new file mode 100644 index 0000000..0fd3bd3 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionResource.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.nodetypes.reqandcapdefs; + +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TCapabilityDefinition; +import org.eclipse.winery.model.tosca.TCapabilityDefinition.Constraints; +import org.eclipse.winery.model.tosca.TConstraint; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; + +/** + * Implementation similar to RequirementDefinitionResource, but with + * TCapabilityDefinition instead of TRequirementDefinition + */ +public final class CapabilityDefinitionResource extends AbstractReqOrCapDefResource<TCapabilityDefinition> { + + private TCapabilityDefinition capDef; + + + /** + * Constructor has to follow the pattern of EnetityTResource as the + * constructor is invoked by reflection in EntityWithIdcollectionResource + * + * @param res the resource this req def is nested in. Has to be of Type + * "NodeTypeResource". Due to the implementation of + * org.eclipse.winery .repository.resources._support.collections. + * withid.EntityWithIdCollectionResource + * .getEntityResourceInstance(EntityT, int), we have to use + * "AbstractComponentInstanceResource" as type + */ + public CapabilityDefinitionResource(IIdDetermination<TCapabilityDefinition> idDetermination, TCapabilityDefinition capDef, int idx, List<TCapabilityDefinition> list, AbstractComponentInstanceResource res) { + super(idDetermination, capDef, idx, list, (NodeTypeResource) res, CapabilityDefinitionResource.getConstraints(capDef)); + this.capDef = capDef; + } + + /** + * Quick hack to avoid internal server error + */ + public CapabilityDefinitionResource(IIdDetermination<TCapabilityDefinition> idDetermination, TCapabilityDefinition capDef, int idx, List<TCapabilityDefinition> list, IPersistable res) { + this(idDetermination, capDef, idx, list, (AbstractComponentInstanceResource) res); + } + + /** + * Fetch the list of constraints from the given definition. If the list does + * not exist, the list is created an stored in the given capDef + */ + public static List<TConstraint> getConstraints(TCapabilityDefinition capDef) { + Constraints constraints = capDef.getConstraints(); + if (constraints == null) { + constraints = new Constraints(); + capDef.setConstraints(constraints); + } + return constraints.getConstraint(); + } + + public QName getType() { + return this.capDef.getCapabilityType(); + } + + @PUT + @Path("type") + public Response setType(@FormParam(value = "type") String value) { + QName qname = QName.valueOf(value); + this.capDef.setCapabilityType(qname); + return BackendUtils.persist(this.parent); + } + + @Override + public String getId(TCapabilityDefinition e) { + return e.getName(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionsResource.java new file mode 100644 index 0000000..d93edb4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionsResource.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.nodetypes.reqandcapdefs; + +import java.util.Collection; +import java.util.List; +import java.util.SortedSet; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.CapabilityTypeId; +import org.eclipse.winery.model.tosca.TCapabilityDefinition; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class CapabilityDefinitionsResource extends RequirementOrCapabilityDefinitionsResource<CapabilityDefinitionResource, TCapabilityDefinition> { + + private static final Logger logger = LoggerFactory.getLogger(CapabilityDefinitionsResource.class); + + + public CapabilityDefinitionsResource(NodeTypeResource res, List<TCapabilityDefinition> defs) { + super(CapabilityDefinitionResource.class, TCapabilityDefinition.class, defs, res); + } + + @Override + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/nodetypes/reqandcapdefs/capdefs.jsp", this); + } + + @Override + public Collection<QName> getAllTypes() { + SortedSet<CapabilityTypeId> allTOSCAComponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(CapabilityTypeId.class); + return BackendUtils.convertTOSCAComponentIdCollectionToQNameCollection(allTOSCAComponentIds); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionResource.java new file mode 100644 index 0000000..aeee000 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionResource.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.nodetypes.reqandcapdefs; + +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TConstraint; +import org.eclipse.winery.model.tosca.TRequirementDefinition; +import org.eclipse.winery.model.tosca.TRequirementDefinition.Constraints; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; + +public final class RequirementDefinitionResource extends AbstractReqOrCapDefResource<TRequirementDefinition> { + + private TRequirementDefinition reqDef; + + + /** + * Constructor has to follow the pattern of EnetityTResource as the + * constructor is invoked by reflection in EntityWithIdcollectionResource + * + * @param res the resource this req def is nested in. Has to be of Type + * "NodeTypeResource". Due to the implementation of + * org.eclipse.winery .repository.resources._support.collections. + * withid.EntityWithIdCollectionResource + * .getEntityResourceInstance(EntityT, int), we have to use + * "AbstractComponentInstanceResource" as type + */ + public RequirementDefinitionResource(IIdDetermination<TRequirementDefinition> idDetermination, TRequirementDefinition reqDef, int idx, List<TRequirementDefinition> list, AbstractComponentInstanceResource res) { + super(idDetermination, reqDef, idx, list, (NodeTypeResource) res, RequirementDefinitionResource.getConstraints(reqDef)); + this.reqDef = reqDef; + } + + /** + * Quick fix to avoid internal server error when opening + * RequirementDefinitions Tab + */ + public RequirementDefinitionResource(IIdDetermination<TRequirementDefinition> idDetermination, TRequirementDefinition reqDef, int idx, List<TRequirementDefinition> list, IPersistable res) { + this(idDetermination, reqDef, idx, list, (AbstractComponentInstanceResource) res); + } + + /** + * Fetch the list of constraints from the given definition. If the list does + * not exist, the list is created an stored in the given def + */ + public static List<TConstraint> getConstraints(TRequirementDefinition def) { + Constraints constraints = def.getConstraints(); + if (constraints == null) { + constraints = new Constraints(); + def.setConstraints(constraints); + } + return constraints.getConstraint(); + } + + public QName getType() { + return this.reqDef.getRequirementType(); + } + + @PUT + @Path("type") + public Response setType(@FormParam(value = "type") String value) { + QName qname = QName.valueOf(value); + this.reqDef.setRequirementType(qname); + return BackendUtils.persist(this.parent); + } + + @Override + public String getId(TRequirementDefinition e) { + return e.getName(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionsResource.java new file mode 100644 index 0000000..62db596 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionsResource.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.nodetypes.reqandcapdefs; + +import java.util.Collection; +import java.util.List; +import java.util.SortedSet; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.RequirementTypeId; +import org.eclipse.winery.model.tosca.TRequirementDefinition; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; + +import com.sun.jersey.api.view.Viewable; + +public class RequirementDefinitionsResource extends RequirementOrCapabilityDefinitionsResource<RequirementDefinitionResource, TRequirementDefinition> { + + public RequirementDefinitionsResource(NodeTypeResource res, List<TRequirementDefinition> defs) { + super(RequirementDefinitionResource.class, TRequirementDefinition.class, defs, res); + } + + @Override + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/nodetypes/reqandcapdefs/reqdefs.jsp", this); + } + + @Override + public Collection<QName> getAllTypes() { + SortedSet<RequirementTypeId> allTOSCAComponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(RequirementTypeId.class); + return BackendUtils.convertTOSCAComponentIdCollectionToQNameCollection(allTOSCAComponentIds); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementOrCapabilityDefinitionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementOrCapabilityDefinitionsResource.java new file mode 100644 index 0000000..0c6936e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementOrCapabilityDefinitionsResource.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.nodetypes.reqandcapdefs; + +import java.util.Collection; +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.model.tosca.TCapabilityDefinition; +import org.eclipse.winery.model.tosca.TRequirementDefinition; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; + +import com.sun.jersey.api.view.Viewable; + +/** + * This superclass has only a few methods as we cannot easily abstract from the + * subclasses: We would need Java reflection to invoke "getName" (to get the + * subresource). The hope is that this copy'n'paste programming will not + * introduce bugs when changing childs + * + * We try to abstract from the problems by using generics and reflections + * + * @param <ReqDefOrCapDef> TRequirementDefinition or TCapabilityDefinition + * @param <ReqDefOrCapDefResource> the resource managing ReqDefOrCapDef + */ +public abstract class RequirementOrCapabilityDefinitionsResource<ReqDefOrCapDefResource extends AbstractReqOrCapDefResource<ReqDefOrCapDef>, ReqDefOrCapDef> extends EntityWithIdCollectionResource<ReqDefOrCapDefResource, ReqDefOrCapDef> { + + protected final NodeTypeResource res; + + + public RequirementOrCapabilityDefinitionsResource(Class<ReqDefOrCapDefResource> entityResourceTClazz, Class<ReqDefOrCapDef> entityTClazz, List<ReqDefOrCapDef> list, NodeTypeResource res) { + super(entityResourceTClazz, entityTClazz, list, res); + this.res = res; + } + + @Override + public abstract Viewable getHTML(); + + /** + * @return collection of all available types + */ + public abstract Collection<QName> getAllTypes(); + + @POST + // As there is no supertype of TCapabilityType and TRequirementType containing the common attributes, we have to rely on unchecked casts + @SuppressWarnings("unchecked") + public Response onPost(@FormParam("name") String name, @FormParam("type") String type, @FormParam("lowerbound") String lowerBound, @FormParam("upperbound") String upperbound) { + if (StringUtils.isEmpty(name)) { + return Response.status(Status.BAD_REQUEST).entity("Name has to be provided").build(); + } + if (StringUtils.isEmpty(type)) { + return Response.status(Status.BAD_REQUEST).entity("Type has to be provided").build(); + } + + int lbound = 1; + if (!StringUtils.isEmpty(lowerBound)) { + try { + lbound = Integer.parseInt(lowerBound); + } catch (NumberFormatException e) { + return Response.status(Status.BAD_REQUEST).entity("Bad format of lowerbound: " + e.getMessage()).build(); + } + } + + String ubound = "1"; + if (!StringUtils.isEmpty(upperbound)) { + ubound = upperbound; + } + + // we also support replacement of existing requirements + // therefore, we loop through the existing requirements + int idx = -1; + boolean found = false; + for (ReqDefOrCapDef d : this.list) { + idx++; + if (this.getId(d).equals(name)) { + found = true; + break; + } + } + + QName typeQName = QName.valueOf(type); + // Create object and put type in it + ReqDefOrCapDef def; + if (this instanceof CapabilityDefinitionsResource) { + def = (ReqDefOrCapDef) new TCapabilityDefinition(); + ((TCapabilityDefinition) def).setCapabilityType(typeQName); + } else { + assert (this instanceof RequirementDefinitionsResource); + def = (ReqDefOrCapDef) new TRequirementDefinition(); + ((TRequirementDefinition) def).setRequirementType(typeQName); + } + + // copy all other data into object + AbstractReqOrCapDefResource.invokeSetter(def, "setName", name); + AbstractReqOrCapDefResource.invokeSetter(def, "setLowerBound", lbound); + AbstractReqOrCapDefResource.invokeSetter(def, "setUpperBound", ubound); + + if (found) { + // replace element + this.list.set(idx, def); + } else { + // add new element + this.list.add(def); + } + + Response r = BackendUtils.persist(this.res); + return r; + } + + @Override + public String getId(ReqDefOrCapDef reqDefOrCapDef) { + return AbstractReqOrCapDefResource.getName(reqDefOrCapDef); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/package-info.java new file mode 100644 index 0000000..6fbbc5a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/package-info.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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 + *******************************************************************************/ +/** + * The sub packages of this package contains all resources, which are derived + * from tEntityType + */ +package org.eclipse.winery.repository.resources.entitytypes; + diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/AppliesToResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/AppliesToResource.java new file mode 100644 index 0000000..0e4b560 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/AppliesToResource.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.policytypes; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.eclipse.winery.model.tosca.TPolicyType; + +import com.sun.jersey.api.view.Viewable; + +public class AppliesToResource { + + private PolicyTypeResource policyTypeResource; + + + public AppliesToResource(PolicyTypeResource policyTypeResource) { + this.policyTypeResource = policyTypeResource; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/policytypes/appliesto.jsp", this); + } + + public TPolicyType getPolicyType() { + return this.policyTypeResource.getPolicyType(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/LanguageResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/LanguageResource.java new file mode 100644 index 0000000..036cc73 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/LanguageResource.java @@ -0,0 +1,28 @@ +package org.eclipse.winery.repository.resources.entitytypes.policytypes; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import com.sun.jersey.api.view.Viewable; + +public class LanguageResource { + + private PolicyTypeResource policyTypeResource; + + + public LanguageResource(PolicyTypeResource policyTypeResource) { + this.policyTypeResource = policyTypeResource; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/policytypes/language.jsp", this); + } + + public String getLanguage() { + return this.policyTypeResource.getPolicyType().getPolicyLanguage(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypeResource.java new file mode 100644 index 0000000..62c728a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypeResource.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.policytypes; + +import java.util.SortedSet; + +import javax.ws.rs.Path; + +import org.eclipse.winery.common.ids.definitions.PolicyTemplateId; +import org.eclipse.winery.common.ids.definitions.PolicyTypeId; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TPolicyType; +import org.eclipse.winery.repository.datatypes.select2.Select2OptGroup; +import org.eclipse.winery.repository.resources.EntityTypeResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class PolicyTypeResource extends EntityTypeResource { + + private static final Logger logger = LoggerFactory.getLogger(PolicyTypeResource.class); + + + /** + * Constructor has to be public because of test cases + */ + public PolicyTypeResource(PolicyTypeId id) { + super(id); + } + + /** + * Convenience method to avoid casting at the caller's side. + */ + public TPolicyType getPolicyType() { + return (TPolicyType) this.getElement(); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TPolicyType(); + } + + @Path("appliesto/") + public AppliesToResource getAppliesTo() { + return new AppliesToResource(this); + } + + @Path("language/") + public LanguageResource getLanguage() { + return new LanguageResource(this); + } + + @Override + public SortedSet<Select2OptGroup> getListOfAllInstances() { + return this.getListOfAllInstances(PolicyTemplateId.class); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypesResource.java new file mode 100644 index 0000000..17d4db0 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypesResource.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.policytypes; + +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +/** + * Manages all policy types in all available namespaces <br /> + * The actual implementation is done in the AbstractComponentsResource + */ +public class PolicyTypesResource extends AbstractComponentsResource<PolicyTypeResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/JSPData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/JSPData.java new file mode 100644 index 0000000..a5338ed --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/JSPData.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.properties; + +import java.util.List; + +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV; +import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; +import org.eclipse.winery.model.tosca.TEntityType; + +/** + * Collects data used by the JSP + */ +public class JSPData { + + // FIXME: this is a quick hack and provides a fixed list of available + // property types only. This list has to be made dynamically updatable (and offer plugins to edit) + // currently only http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#built-in-datatypes are supported + private static final String[] availablePropertyTypes = {"xsd:string", "xsd:boolean", "xsd:decimal", "xsd:float", "xsd:anyURI", "xsd:QName"}; + + private final PropertiesDefinitionResource propertiesDefinitionResource; + private final WinerysPropertiesDefinition wpd; + + + public JSPData(PropertiesDefinitionResource propertiesDefinitionResource, WinerysPropertiesDefinition wpd) { + this.propertiesDefinitionResource = propertiesDefinitionResource; + this.wpd = wpd; + } + + public List<PropertyDefinitionKV> getPropertyDefinitionKVList() { + // as this method is used by the JSP, we have to initialize the list and not provide a fake list + // in other words: we are in the mode, where the user has chosen the winery property handling + assert (this.getIsWineryKeyValueProperties()); + if (this.wpd.getPropertyDefinitionKVList() == null) { + return java.util.Collections.emptyList(); + } else { + return this.wpd.getPropertyDefinitionKVList(); + } + } + + public Boolean getIsWineryKeyValueProperties() { + return (this.wpd != null); + // the jsp renders list data only if the list is existing + // we could (somehow) also always keep the old list, but we opted for keeping the choice between the four options also in the XML (and not storing stale data) + // in the case, the WPD is derived from XSD, the list is rendered nevertheless + } + + public boolean getIsWineryKeyValuePropertiesDerivedFromXSD() { + return ((this.wpd != null) && (this.wpd.getIsDerivedFromXSD() != null)); + } + + public String[] getAvailablePropertyTypes() { + return JSPData.availablePropertyTypes; + } + + public TEntityType getEntityType() { + return this.propertiesDefinitionResource.getEntityType(); + } + + public String getElementName() { + if (this.wpd == null) { + return null; + } else { + return this.wpd.getElementName(); + } + } + + public String getNamespace() { + if (this.wpd == null) { + return null; + } else { + return this.wpd.getNamespace(); + } + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/PropertiesDefinitionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/PropertiesDefinitionResource.java new file mode 100644 index 0000000..6a63791 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/PropertiesDefinitionResource.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.properties; + +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +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 javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.constants.MimeTypes; +import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.EntityTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.properties.winery.WinerysPropertiesDefinitionResource; +import org.restdoc.annotations.RestDoc; +import org.restdoc.annotations.RestDocParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +/** + * Models + * <ol> + * <li>TOSCA conforming properties definition (XML element / XML schema / none)</li> + * <li>Winery's KV properties (in the subresource "winery")</li> + * </ol> + * + * This class does not have "KV" in its name, because it models + * {@link TEntityType.PropertiesDefinition} + */ +public class PropertiesDefinitionResource { + + private static final Logger logger = LoggerFactory.getLogger(PropertiesDefinitionResource.class); + + // We hold a copy of super.res as we work on the type EntityTypeResource instead of AbstractComponentInstanceResource + private final EntityTypeResource parentRes; + + // we assume that this class is created at each request + // therefore, we can have "wpd" final + private final WinerysPropertiesDefinition wpd; + + + public PropertiesDefinitionResource(EntityTypeResource res) { + this.parentRes = res; + this.wpd = ModelUtilities.getWinerysPropertiesDefinition(res.getEntityType()); + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/properties/propertiesDefinition.jsp", new JSPData(this, this.wpd)); + } + + public TEntityType getEntityType() { + return this.parentRes.getEntityType(); + } + + @Path("winery/") + public WinerysPropertiesDefinitionResource getWinerysPropertiesDefinitionResource() { + // this.wpd is null if there is no winery definition exisitin. The subresource handles that case, too + return new WinerysPropertiesDefinitionResource(this.parentRes, this.wpd); + } + + @DELETE + public Response clearPropertiesDefinition() { + this.getEntityType().setPropertiesDefinition(null); + ModelUtilities.removeWinerysPropertiesDefinition(this.getEntityType()); + return BackendUtils.persist(this.parentRes); + } + + public boolean getIsWineryKeyValueProperties() { + return (this.wpd != null); + } + + @GET + @Produces(MimeTypes.MIMETYPE_XSD) + public Response getXSD() { + if (this.getIsWineryKeyValueProperties()) { + return Response.ok().entity(ModelUtilities.getWinerysPropertiesDefinitionXSDAsDocument(this.wpd)).build(); + } else { + // not yet implemented + // We would have to check the imports in the repo for the defined property + // This also has to be similarly done at the export to determine the right imports + return Response.status(Status.NOT_FOUND).build(); + } + } + + @GET + @RestDoc(methodDescription = "We provide the XSD at . and at ./xsd/ to enable simple quering in the browser without the hazzle of setting the correct mime type.") + @Path("xsd/") + @Produces(MimeTypes.MIMETYPE_XSD) + public Response getXSDAtSubResource() { + return this.getXSD(); + } + + // @formatter:off + @POST + @RestDoc(methodDescription="Updates/creates a property based on XSD element or XML schema.") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + public Response onPost( + @FormParam("name") @RestDocParam(description="Either xsdelement or xsdtype. 'name' comes from x-editable, which uses that as field name") String name, + @FormParam("value") @RestDocParam(description="The qname") String value) { + // @formatter:on + if (StringUtils.isEmpty(name)) { + return Response.status(Status.BAD_REQUEST).entity("You have to provide a key/type or a name/value pair").build(); + } + if (StringUtils.isEmpty(value)) { + return Response.status(Status.BAD_REQUEST).entity("If a name is provided, a value has also to be provided").build(); + } + + // first of all, remove Winery's Properties definition (if it exists) + ModelUtilities.removeWinerysPropertiesDefinition(this.getEntityType()); + + QName qname = QName.valueOf(value); + + // replace old properties definition by new one + PropertiesDefinition def = new PropertiesDefinition(); + if (name.equals("xsdtype")) { + def.setType(qname); + } else if (name.equals("xsdelement")) { + def.setElement(qname); + } else { + return Response.status(Status.BAD_REQUEST).entity("Invalid name. Choose xsdelement or xsdtype").build(); + } + this.getEntityType().setPropertiesDefinition(def); + List<String> errors = new ArrayList<>(); + BackendUtils.deriveWPD(this.getEntityType(), errors); + // currently the errors are just logged + for (String error : errors) { + PropertiesDefinitionResource.logger.debug(error); + } + return BackendUtils.persist(this.parentRes); + + } + +}
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVListResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVListResource.java new file mode 100644 index 0000000..f967042 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVListResource.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.properties.winery; + +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV; +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKVList; +import org.eclipse.winery.repository.resources.EntityTypeResource; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; + +import com.sun.jersey.api.view.Viewable; + +/** + * Supports Winery's k/v properties introducing sub resources + * "PropertyDefinition", which defines <em>one</em> property + */ +public class PropertyDefinitionKVListResource extends EntityWithIdCollectionResource<PropertyDefinitionKVResource, PropertyDefinitionKV> { + + public PropertyDefinitionKVListResource(EntityTypeResource res, PropertyDefinitionKVList list) { + super(PropertyDefinitionKVResource.class, PropertyDefinitionKV.class, list, res); + } + + @Override + public String getId(PropertyDefinitionKV entity) { + return entity.getKey(); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not yet implemented."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVResource.java new file mode 100644 index 0000000..00a8d24 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVResource.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.properties.winery; + +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; +import org.restdoc.annotations.RestDoc; + +/** + * Models a definition of one property + * + * This is NOT in line with CSPRD01, which forces one element of one type + */ +public class PropertyDefinitionKVResource extends EntityWithIdResource<PropertyDefinitionKV> { + + public PropertyDefinitionKVResource(IIdDetermination<PropertyDefinitionKV> idDetermination, PropertyDefinitionKV o, int idx, List<PropertyDefinitionKV> list, AbstractComponentInstanceResource res) { + super(idDetermination, o, idx, list, res); + } + + public PropertyDefinitionKVResource(IIdDetermination<PropertyDefinitionKV> idDetermination, PropertyDefinitionKV o, int idx, List<PropertyDefinitionKV> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + @GET + @RestDoc(methodDescription = "@return type is the 'id' of the type ('shortType'), not the full type name") + @Path("type") + public String getType() { + return this.o.getType(); + } + + @PUT + @RestDoc(methodDescription = "@return type is the 'id' of the type ('shortType'), not the full type name") + @Path("type") + public Response setType(@FormParam("type") String type) { + this.o.setType(type); + return BackendUtils.persist(this.res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/WinerysPropertiesDefinitionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/WinerysPropertiesDefinitionResource.java new file mode 100644 index 0000000..0d219e3 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/WinerysPropertiesDefinitionResource.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.properties.winery; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKVList; +import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.EntityTypeResource; +import org.restdoc.annotations.RestDoc; + +import com.sun.jersey.api.NotFoundException; + +public class WinerysPropertiesDefinitionResource { + + private final EntityTypeResource res; + private final WinerysPropertiesDefinition wpd; + + + /** + * @param res the resource where winery's k/v properties are defined + * @param wpd winery's properties definition object, MAY be null + */ + public WinerysPropertiesDefinitionResource(EntityTypeResource res, WinerysPropertiesDefinition wpd) { + this.res = res; + this.wpd = wpd; + } + + @POST + @RestDoc(methodDescription = "switches the mode to winery properties instead of element/type properties") + public Response onPost() { + TEntityType et = this.res.getEntityType(); + + // clear current properties definition + et.setPropertiesDefinition(null); + + // create empty winery properties definition and persist it + WinerysPropertiesDefinition wpd = new WinerysPropertiesDefinition(); + ModelUtilities.replaceWinerysPropertiesDefinition(et, wpd); + return BackendUtils.persist(this.res); + } + + @Path("namespace") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getNamespace() { + if (this.wpd == null) { + throw new NotFoundException(); + } + return this.wpd.getNamespace(); + } + + @Path("namespace") + @PUT + @Consumes(MediaType.TEXT_PLAIN) + public Response setNamespace(String namespace) { + if (this.wpd == null) { + throw new NotFoundException(); + } + this.wpd.setNamespace(namespace); + return BackendUtils.persist(this.res); + } + + @Path("elementname") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getElementName() { + if (this.wpd == null) { + throw new NotFoundException(); + } + return this.wpd.getElementName(); + } + + @Path("elementname") + @PUT + @Consumes(MediaType.TEXT_PLAIN) + public Response setLocalname(String elementName) { + if (this.wpd == null) { + throw new NotFoundException(); + } + this.wpd.setElementName(elementName); + return BackendUtils.persist(this.res); + } + + @Path("elementname") + @PUT + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response setLocalnameViaWebUI(@FormParam(value = "name") String elementName) { + if (this.wpd == null) { + throw new NotFoundException(); + } + this.wpd.setElementName(elementName); + return BackendUtils.persist(this.res); + } + + /** + * Here, also the addition of k/v properties is handled. + */ + @Path("list/") + public PropertyDefinitionKVListResource getListResource() { + if (this.wpd == null) { + throw new NotFoundException(); + } + PropertyDefinitionKVList list = this.wpd.getPropertyDefinitionKVList(); + if (list == null) { + list = new PropertyDefinitionKVList(); + this.wpd.setPropertyDefinitionKVList(list); + } + return new PropertyDefinitionKVListResource(this.res, list); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/ImplementationsOfOneRelationshipTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/ImplementationsOfOneRelationshipTypeResource.java new file mode 100644 index 0000000..c7cf2d6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/ImplementationsOfOneRelationshipTypeResource.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,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.entitytypes.relationshiptypes; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; + +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.RelationshipTypeId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.entitytypes.ImplementationsOfOneType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; + +public class ImplementationsOfOneRelationshipTypeResource extends ImplementationsOfOneType { + + public ImplementationsOfOneRelationshipTypeResource(RelationshipTypeId typeId) { + super(typeId); + } + + + private static final Logger logger = LoggerFactory.getLogger(ImplementationsOfOneRelationshipTypeResource.class); + + + /** + * required by implementations.jsp + * + * Method similar top the one of ImplementationsOfOneNodeTypeResource + * + * @return for each node type implementation implementing the associated + * node type + */ + @Override + public String getImplementationsTableData() { + String res; + JsonFactory jsonFactory = new JsonFactory(); + StringWriter tableDataSW = new StringWriter(); + try { + JsonGenerator jGenerator = jsonFactory.createGenerator(tableDataSW); + jGenerator.writeStartArray(); + + Collection<RelationshipTypeImplementationId> allNTIids = BackendUtils.getAllElementsRelatedWithATypeAttribute(RelationshipTypeImplementationId.class, this.getTypeId().getQName()); + for (RelationshipTypeImplementationId ntiID : allNTIids) { + jGenerator.writeStartArray(); + jGenerator.writeString(ntiID.getNamespace().getDecoded()); + jGenerator.writeString(ntiID.getXmlId().getDecoded()); + jGenerator.writeEndArray(); + } + jGenerator.writeEndArray(); + jGenerator.close(); + tableDataSW.close(); + res = tableDataSW.toString(); + } catch (Exception e) { + ImplementationsOfOneRelationshipTypeResource.logger.error(e.getMessage(), e); + res = "[]"; + } + return res; + } + + @Override + public String getType() { + return "relationshiptype"; + } + + @Override + public String getTypeStr() { + return "Relationship Type"; + } + + @Override + public Response getJSON() { + Collection<RelationshipTypeImplementationId> allImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(RelationshipTypeImplementationId.class, this.getTypeId().getQName()); + ArrayList<QName> res = new ArrayList<QName>(allImplementations.size()); + for (RelationshipTypeImplementationId id : allImplementations) { + res.add(id.getQName()); + } + return Response.ok().entity(res).build(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypeResource.java new file mode 100644 index 0000000..c874bd5 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypeResource.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.relationshiptypes; + +import java.util.Collection; +import java.util.SortedSet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TRelationshipType.SourceInterfaces; +import org.eclipse.winery.model.tosca.TRelationshipType.TargetInterfaces; +import org.eclipse.winery.model.tosca.TRelationshipType.ValidSource; +import org.eclipse.winery.model.tosca.TRelationshipType.ValidTarget; +import org.eclipse.winery.model.tosca.TTopologyElementInstanceStates; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeId; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.entitytypes.InstanceStatesResource; +import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource; +import org.eclipse.winery.repository.resources.interfaces.InterfacesResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class RelationshipTypeResource extends TopologyGraphElementEntityTypeResource { + + private static final Logger logger = LoggerFactory.getLogger(RelationshipTypeResource.class); + + + public RelationshipTypeResource(RelationshipTypeId id) { + super(id); + } + + @Path("implementations/") + public ImplementationsOfOneRelationshipTypeResource getImplementations() { + return new ImplementationsOfOneRelationshipTypeResource((RelationshipTypeId) this.id); + } + + @Path("visualappearance/") + public VisualAppearanceResource getVisualAppearanceResource() { + return new VisualAppearanceResource(this, this.getElement().getOtherAttributes(), (RelationshipTypeId) this.id); + } + + @Path("instancestates/") + public InstanceStatesResource getInstanceStatesResource() { + TTopologyElementInstanceStates instanceStates = this.getRelationshipType().getInstanceStates(); + if (instanceStates == null) { + // if an explicit (empty) list does not exist, create it + instanceStates = new TTopologyElementInstanceStates(); + this.getRelationshipType().setInstanceStates(instanceStates); + } + return new InstanceStatesResource(this.getRelationshipType().getInstanceStates(), this); + } + + @Path("sourceinterfaces/") + public InterfacesResource getSourceInterfaces() { + SourceInterfaces interfaces = this.getRelationshipType().getSourceInterfaces(); + if (interfaces == null) { + interfaces = new SourceInterfaces(); + this.getRelationshipType().setSourceInterfaces(interfaces); + } + return new InterfacesResource("source", interfaces.getInterface(), this); + } + + @Path("targetinterfaces/") + public InterfacesResource getTargetInterfaces() { + TargetInterfaces interfaces = this.getRelationshipType().getTargetInterfaces(); + if (interfaces == null) { + interfaces = new TargetInterfaces(); + this.getRelationshipType().setTargetInterfaces(interfaces); + } + return new InterfacesResource("target", interfaces.getInterface(), this); + } + + @Path("validendings/") + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML() { + Viewable viewable = new Viewable("/jsp/entitytypes/relationshiptypes/validendings.jsp", this); + return Response.ok().entity(viewable).build(); + } + + @Path("validsource") + @GET + public String getValidSource() { + ValidSource validSource; + if (((validSource = this.getRelationshipType().getValidSource()) == null) || (validSource.getTypeRef() == null)) { + return null; + } + return this.getRelationshipType().getValidSource().getTypeRef().toString(); + } + + @Path("validsource") + @PUT + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response setValidSource(String typeRef) { + ValidSource vs = new ValidSource(); + QName qname = QName.valueOf(typeRef); + vs.setTypeRef(qname); + this.getRelationshipType().setValidSource(vs); + return BackendUtils.persist(this); + } + + @Path("validtarget") + @GET + public String getValidTarget() { + ValidTarget validTarget; + if (((validTarget = this.getRelationshipType().getValidTarget()) == null) || (validTarget.getTypeRef() == null)) { + return null; + } + return this.getRelationshipType().getValidTarget().getTypeRef().toString(); + } + + @Path("validtarget") + @PUT + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response setValidTarget(String typeRef) { + ValidTarget vt = new ValidTarget(); + QName qname = QName.valueOf(typeRef); + vt.setTypeRef(qname); + this.getRelationshipType().setValidTarget(vt); + return BackendUtils.persist(this); + } + + /** + * Required for validendings.jsp + */ + public Collection<NodeTypeId> getPossibleValidEndings() { + SortedSet<NodeTypeId> allNodeTypeIds = Repository.INSTANCE.getAllTOSCAComponentIds(NodeTypeId.class); + return allNodeTypeIds; + } + + /** + * Convenience method to avoid casting at the caller's side. + */ + public TRelationshipType getRelationshipType() { + return (TRelationshipType) this.getElement(); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TRelationshipType(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypesResource.java new file mode 100644 index 0000000..1c73ab0 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypesResource.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.relationshiptypes; + +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +public class RelationshipTypesResource extends AbstractComponentsResource<RelationshipTypeResource> { +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/VisualAppearanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/VisualAppearanceResource.java new file mode 100644 index 0000000..c17c19b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/VisualAppearanceResource.java @@ -0,0 +1,291 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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 + * Jerome Tagliaferri - support for setting the color + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.relationshiptypes; + +import java.io.StringWriter; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +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 javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.constants.Defaults; +import org.eclipse.winery.common.constants.Namespaces; +import org.eclipse.winery.common.constants.QNames; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeId; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId; +import org.eclipse.winery.repository.resources.GenericVisualAppearanceResource; +import org.restdoc.annotations.RestDoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import com.sun.jersey.api.view.Viewable; + +public class VisualAppearanceResource extends GenericVisualAppearanceResource { + + private static final Logger logger = LoggerFactory.getLogger(VisualAppearanceResource.class); + + private static final QName QNAME_ARROWHEAD_SOURCE = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "sourceArrowHead"); + private static final QName QNAME_ARROWHEAD_TARGET = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "targetArrowHead"); + private static final QName QNAME_DASH = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "dash"); + private static final QName QNAME_LINEWIDTH = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "linewidth"); + private static final QName QNAME_HOVER_COLOR = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "hovercolor"); + + + public VisualAppearanceResource(RelationshipTypeResource res, Map<QName, String> map, RelationshipTypeId parentId) { + super(res, map, new VisualAppearanceId(parentId)); + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML() { + Viewable viewable = new Viewable("/jsp/entitytypes/relationshiptypes/visualappearance.jsp", this); + return Response.ok().entity(viewable).build(); + } + + @GET + @RestDoc(methodDescription = "@return JSON object to be used at jsPlumb.registerConnectionType('NAME', <data>)") + @Produces(MediaType.APPLICATION_JSON) + public Response getConnectionTypeForJsPlumbData() { + JsonFactory jsonFactory = new JsonFactory(); + StringWriter sw = new StringWriter(); + try { + JsonGenerator jg = jsonFactory.createGenerator(sw); + jg.writeStartObject(); + + jg.writeFieldName("connector"); + jg.writeString("Flowchart"); + + jg.writeFieldName("paintStyle"); + jg.writeStartObject(); + jg.writeFieldName("lineWidth"); + jg.writeNumber(this.getLineWidth()); + jg.writeFieldName("strokeStyle"); + jg.writeObject(this.getColor()); + String dash = this.getDash(); + if (!StringUtils.isEmpty(dash)) { + String dashStyle = null; + switch (dash) { + case "dotted": + dashStyle = "1 5"; + break; + case "dotted2": + dashStyle = "3 4"; + break; + case "plain": + // default works + // otherwise, "1 0" can be used + break; + } + if (dashStyle != null) { + jg.writeStringField("dashstyle", dashStyle); + } + } + jg.writeEndObject(); + + jg.writeFieldName("hoverPaintStyle"); + jg.writeStartObject(); + jg.writeFieldName("strokeStyle"); + jg.writeObject(this.getHoverColor()); + jg.writeEndObject(); + + // BEGIN: Overlays + + jg.writeFieldName("overlays"); + jg.writeStartArray(); + + // source arrow head + String head = this.getSourceArrowHead(); + if (!head.equals("none")) { + jg.writeStartArray(); + jg.writeString(head); + + jg.writeStartObject(); + + jg.writeFieldName("location"); + jg.writeNumber(0); + + // arrow should point towards the node and not away from it + jg.writeFieldName("direction"); + jg.writeNumber(-1); + + jg.writeFieldName("width"); + jg.writeNumber(20); + + jg.writeFieldName("length"); + jg.writeNumber(12); + + jg.writeEndObject(); + jg.writeEndArray(); + } + + // target arrow head + head = this.getTargetArrowHead(); + if (!head.equals("none")) { + jg.writeStartArray(); + jg.writeString(head); + jg.writeStartObject(); + jg.writeFieldName("location"); + jg.writeNumber(1); + jg.writeFieldName("width"); + jg.writeNumber(20); + jg.writeFieldName("length"); + jg.writeNumber(12); + jg.writeEndObject(); + jg.writeEndArray(); + } + + // Type in brackets on the arrow + jg.writeStartArray(); + jg.writeString("Label"); + jg.writeStartObject(); + jg.writeStringField("id", "label"); + jg.writeStringField("label", "(" + ((RelationshipTypeResource) this.res).getName() + ")"); + jg.writeStringField("cssClass", "relationshipTypeLabel"); + jg.writeFieldName("location"); + jg.writeNumber(0.5); + jg.writeEndObject(); + jg.writeEndArray(); + + jg.writeEndArray(); + + // END: Overlays + + jg.writeEndObject(); + + jg.close(); + } catch (Exception e) { + VisualAppearanceResource.logger.error(e.getMessage(), e); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build(); + } + String res = sw.toString(); + return Response.ok(res).build(); + } + + private String getOtherAttributeWithDefault(QName qname, String def) { + String res = this.otherAttributes.get(qname); + if (StringUtils.isEmpty(res)) { + return def; + } else { + return res; + } + } + + /* * * source arrow head * * */ + + public String getSourceArrowHead() { + return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_ARROWHEAD_SOURCE, Defaults.DEFAULT_RT_ARROWHEAD_SOURCE); + } + + @PUT + @Consumes(MediaType.TEXT_PLAIN) + @Path("sourcearrowhead") + public Response onPutSourceHead(String config) { + if (StringUtils.isEmpty(config)) { + return Response.status(Status.BAD_REQUEST).entity("config must not be empty").build(); + } + this.otherAttributes.put(VisualAppearanceResource.QNAME_ARROWHEAD_SOURCE, config); + return BackendUtils.persist(this.res); + } + + /* * * target arrow head * * */ + + public String getTargetArrowHead() { + return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_ARROWHEAD_TARGET, Defaults.DEFAULT_RT_ARROWHEAD_TARGET); + } + + @PUT + @Consumes(MediaType.TEXT_PLAIN) + @Path("targetarrowhead") + public Response onPutTargetHead(String config) { + if (StringUtils.isEmpty(config)) { + return Response.status(Status.BAD_REQUEST).entity("config must not be empty").build(); + } + this.otherAttributes.put(VisualAppearanceResource.QNAME_ARROWHEAD_TARGET, config); + return BackendUtils.persist(this.res); + } + + /* * * + * + * stroke dash array / represents the line + * + * Attention: if a linewidth != 1 is chosen, the dash has to be multiplied somehow by the line width + * See: http://jsplumbtoolkit.com/doc/paint-styles: + * "The dashstyle attribute is specified as an array of strokes and spaces, where each value is some multiple of the width of the Connector" + * + * * * */ + + public String getDash() { + return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_DASH, Defaults.DEFAULT_RT_DASH); + } + + @PUT + @Consumes(MediaType.TEXT_PLAIN) + @Path("dash") + public Response onPutDash(String config) { + if (StringUtils.isEmpty(config)) { + return Response.status(Status.BAD_REQUEST).entity("config must not be empty").build(); + } + this.otherAttributes.put(VisualAppearanceResource.QNAME_DASH, config); + return BackendUtils.persist(this.res); + } + + /* * * stroke/line width * * */ + + public String getLineWidth() { + return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_LINEWIDTH, Defaults.DEFAULT_RT_LINEWIDTH); + } + + /* * * color * * */ + + /** + * read by topologytemplateeditor.jsp via ${it.color} + */ + public String getColor() { + return BackendUtils.getColorAndSetDefaultIfNotExisting(this.getId().getParent().getXmlId().getDecoded(), QNames.QNAME_COLOR, this.otherAttributes, this.res); + } + + @PUT + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Path("color") + public Response onPutColor(@FormParam("color") String color) { + this.otherAttributes.put(QNames.QNAME_COLOR, color); + return BackendUtils.persist(this.res); + } + + /** + * read by topologytemplateeditor.jsp via ${it.hoverColor} + */ + public String getHoverColor() { + return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_HOVER_COLOR, Defaults.DEFAULT_RT_HOVER_COLOR); + } + + @PUT + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Path("hovercolor") + public Response onPutHoverColor(@FormParam("color") String color) { + this.otherAttributes.put(VisualAppearanceResource.QNAME_HOVER_COLOR, color); + return BackendUtils.persist(this.res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequiredCapabilityTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequiredCapabilityTypeResource.java new file mode 100644 index 0000000..c076835 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequiredCapabilityTypeResource.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.requirementtypes; + +import java.util.Collection; +import java.util.SortedSet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +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 javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.ids.definitions.CapabilityTypeId; +import org.eclipse.winery.model.tosca.TRequirementType; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; + +import com.sun.jersey.api.NotFoundException; +import com.sun.jersey.api.view.Viewable; + +public class RequiredCapabilityTypeResource { + + private RequirementTypeResource requirementTypeResource; + + + public RequiredCapabilityTypeResource(RequirementTypeResource requirementTypeResource) { + this.requirementTypeResource = requirementTypeResource; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/requirementtypes/requiredcapabilitytype.jsp", this); + } + + public TRequirementType getRequirementType() { + return this.requirementTypeResource.getRequirementType(); + } + + @PUT + @Consumes(MediaType.TEXT_PLAIN) + public Response putRequiredCapabilityType(String type) { + if (StringUtils.isEmpty(type)) { + return Response.status(Status.BAD_REQUEST).entity("type must not be empty").build(); + } + QName qname = QName.valueOf(type); + CapabilityTypeId id = new CapabilityTypeId(qname); + if (Repository.INSTANCE.exists(id)) { + // everything allright. Store new reference + this.getRequirementType().setRequiredCapabilityType(qname); + return BackendUtils.persist(this.requirementTypeResource); + } else { + throw new NotFoundException("Given QName could not be resolved to an existing capability type"); + } + } + + @DELETE + public Response deleteRequiredCapabilityType() { + this.getRequirementType().setRequiredCapabilityType(null); + return BackendUtils.persist(this.requirementTypeResource); + } + + /** required for jsp **/ + public Collection<QName> getAllCapabilityTypes() { + SortedSet<CapabilityTypeId> allTOSCAComponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(CapabilityTypeId.class); + return BackendUtils.convertTOSCAComponentIdCollectionToQNameCollection(allTOSCAComponentIds); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypeResource.java new file mode 100644 index 0000000..0f143fb --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypeResource.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.requirementtypes; + +import javax.ws.rs.Path; + +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TRequirementType; +import org.eclipse.winery.common.ids.definitions.RequirementTypeId; +import org.eclipse.winery.repository.resources.EntityTypeResource; + +public class RequirementTypeResource extends EntityTypeResource { + + public RequirementTypeResource(RequirementTypeId id) { + super(id); + } + + /** + * Convenience method to avoid casting at the caller's side. + */ + public TRequirementType getRequirementType() { + return (TRequirementType) this.getElement(); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TRequirementType(); + } + + @Path("requiredcapabilitytype/") + public RequiredCapabilityTypeResource getRequiredCapabilityTypeResource() { + return new RequiredCapabilityTypeResource(this); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypesResource.java new file mode 100644 index 0000000..955e4fb --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypesResource.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.entitytypes.requirementtypes; + +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +/** + * Manages all capability types in all available namespaces <br /> + * The actual implementation is done in the AbstractComponentsResource + */ +public class RequirementTypesResource extends AbstractComponentsResource<RequirementTypeResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/ImportsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/ImportsResource.java new file mode 100644 index 0000000..82ff02e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/ImportsResource.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.imports; + +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; +import org.eclipse.winery.repository.resources.imports.genericimports.GenericImportsResource; +import org.eclipse.winery.repository.resources.imports.xsdimports.XSDImportsResource; + +/** + * The specification does not nest the sequence of import elements in an imports + * container. We introduce such a container to be consistent with the other + * resource naming + */ +public class ImportsResource { + + @Path("{id}/") + public AbstractComponentsResource getXSDsResource(@PathParam("id") String id) { + // once: decoding for browser locations + id = Util.URLdecode(id); + // once again: real URI + id = Util.URLdecode(id); + if (id.equals("http://www.w3.org/2001/XMLSchema")) { + // Models http://www.w3.org/2001/XMLSchema. We do not use xsd instead of the + // encoded namespace, because this induces special cases at many places + return new XSDImportsResource(); + } else { + return new GenericImportsResource(id); + } + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportResource.java new file mode 100644 index 0000000..ddcb462 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportResource.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.imports.genericimports; + +import java.util.SortedSet; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.definitions.imports.GenericImportId; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImport; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; + +public class GenericImportResource extends AbstractComponentInstanceResource { + + // The import belonging to this resource + protected final TImport theImport; + + + public GenericImportResource(GenericImportId id) { + super(id); + + boolean needsPersistence = false; + + if (this.getDefinitions().getServiceTemplateOrNodeTypeOrNodeTypeImplementation().isEmpty()) { + // super class loaded an existing definitions + + // we have to manually assign our import right + this.theImport = this.getDefinitions().getImport().get(0); + + // element is not assigned as there are no service templates/... + // we assign the value to be sure that no NPEs occur + this.element = this.theImport; + } else { + // super class created a new import + + // store it locally + this.theImport = (TImport) this.element; + + // undo the side effect of adding it at the wrong place at TDefinitions + this.getDefinitions().getServiceTemplateOrNodeTypeOrNodeTypeImplementation().clear(); + + // add import at the right place + this.getDefinitions().getImport().add(this.theImport); + + // Super class has persisted the definitions + // We have to persist the new variant + needsPersistence = true; + } + + if (this.theImport.getLocation() == null) { + // invalid import -- try to synchronize with storage + + SortedSet<RepositoryFileReference> containedFiles = Repository.INSTANCE.getContainedFiles(id); + // there is also a .definitions contained + // we are only interested in the non-.definitions + for (RepositoryFileReference ref : containedFiles) { + if (!ref.getFileName().endsWith(".definitions")) { + // associated file found + // set the filename of the import to the found xsd + // TODO: no more validity checks are done currently. In the case of XSD: targetNamespace matches, not more than one xsd + this.theImport.setLocation(ref.getFileName()); + needsPersistence = true; + break; + } + } + } + + if (needsPersistence) { + BackendUtils.persist(this); + } + } + + @Override + protected TExtensibleElements createNewElement() { + throw new IllegalStateException("This should not never happen."); + } + + @Override + protected void copyIdToFields() { + // this.theImport cannot be used as this method is called by the super constructor + ((TImport) this.element).setNamespace(this.id.getNamespace().getDecoded()); + } + + @GET + @Path("{filename}") + public Response getFile(@PathParam("filename") String fileName) { + fileName = Util.URLdecode(fileName); + String location; + if ((location = this.getLocation()) == null) { + return Response.status(Status.NOT_FOUND).build(); + } + if (!location.equals(fileName)) { + return Response.status(Status.NOT_FOUND).build(); + } + RepositoryFileReference ref = new RepositoryFileReference(this.id, location); + return BackendUtils.returnRepoPath(ref, null); + + } + + public String getLocation() { + return this.theImport.getLocation(); + } + + /** + * @return a name suitable for componentnaming.jspf + */ + public String getName() { + if (this.getLocation() == null) { + return this.id.getXmlId().getDecoded(); + } else { + return this.getLocation(); + } + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportsResource.java new file mode 100644 index 0000000..9117175 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportsResource.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.imports.genericimports; + +import org.eclipse.winery.common.ids.definitions.imports.GenericImportId; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +/** + * Manages a certain kind of imports without special treatments + */ +public class GenericImportsResource extends AbstractComponentsResource<GenericImportResource> { + + private String type; + + + /** + * @param id the (decoded) id, e.g., http://schemas.xmlsoap.org/wsdl/ + */ + public GenericImportsResource(String id) { + this.type = id; + } + + @Override + public GenericImportResource getComponentInstaceResource(String namespace, String id, boolean encoded) { + GenericImportId iId = new GenericImportId(namespace, id, encoded, this.type); + return new GenericImportResource(iId); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportResource.java new file mode 100644 index 0000000..49ea468 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportResource.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.imports.xsdimports; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import javax.ws.rs.GET; +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 javax.xml.XMLConstants; + +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSModel; +import org.apache.xerces.xs.XSNamedMap; +import org.apache.xerces.xs.XSObject; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.definitions.imports.XSDImportId; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImport; +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.imports.genericimports.GenericImportResource; +import org.restdoc.annotations.RestDoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonProcessingException; + +/** + * Even if we are not a component instance, we use that infrastructure to manage + * imports. Some hacks will be necessary. However, these are less effort than + * doing a clean design + */ +public class XSDImportResource extends GenericImportResource { + + private static final Logger logger = LoggerFactory.getLogger(XSDImportResource.class); + + + public XSDImportResource(XSDImportId id) { + super(id); + } + + @Override + protected TExtensibleElements createNewElement() { + TImport imp = new TImport(); + imp.setImportType(XMLConstants.W3C_XML_SCHEMA_NS_URI); + return imp; + } + + /** + * public required by XSDImportsResource + * + * @return null if XSD file does not exist + */ + public RepositoryFileReference getXSDFileReference() { + String loc = this.getLocation(); + if (loc == null) { + return null; + } + final RepositoryFileReference ref = new RepositoryFileReference(this.id, loc); + return ref; + } + + /** + * @return null if no file is associated + */ + private XSModel getXSModel() { + final RepositoryFileReference ref = this.getXSDFileReference(); + return BackendUtils.getXSModel(ref); + } + + // we need "unchecked", because of the parsing of the cache + @SuppressWarnings("unchecked") + public Collection<String> getAllDefinedLocalNames(short type) { + RepositoryFileReference ref = this.getXSDFileReference(); + if (ref == null) { + return Collections.emptySet(); + } + Date lastUpdate = Repository.INSTANCE.getLastUpdate(ref); + + String cacheFileName = "definedLocalNames " + Integer.toString(type) + ".cache"; + RepositoryFileReference cacheRef = new RepositoryFileReference(this.id, cacheFileName); + boolean cacheNeedsUpdate = true; + if (Repository.INSTANCE.exists(cacheRef)) { + Date lastUpdateCache = Repository.INSTANCE.getLastUpdate(cacheRef); + if (lastUpdate.compareTo(lastUpdateCache) <= 0) { + cacheNeedsUpdate = false; + } + } + + List<String> result; + if (cacheNeedsUpdate) { + + XSModel model = this.getXSModel(); + if (model == null) { + return Collections.emptySet(); + } + XSNamedMap components = model.getComponents(type); + //@SuppressWarnings("unchecked") + int len = components.getLength(); + result = new ArrayList<String>(len); + for (int i = 0; i < len; i++) { + XSObject item = components.item(i); + // if queried for TYPE_DEFINITION, then XSD base types (such as IDREF) are also returned + // We want to return only types defined in the namespace of this resource + if (item.getNamespace().equals(this.id.getNamespace().getDecoded())) { + result.add(item.getName()); + } + } + + String cacheContent = null; + try { + cacheContent = Utils.mapper.writeValueAsString(result); + } catch (JsonProcessingException e) { + XSDImportResource.logger.error("Could not generate cache content", e); + } + try { + Repository.INSTANCE.putContentToFile(cacheRef, cacheContent, MediaType.APPLICATION_JSON_TYPE); + } catch (IOException e) { + XSDImportResource.logger.error("Could not update cache", e); + } + } else { + // read content from cache + // cache should contain most recent information + try (InputStream is = Repository.INSTANCE.newInputStream(cacheRef)) { + result = Utils.mapper.readValue(is, java.util.List.class); + } catch (IOException e) { + XSDImportResource.logger.error("Could not read from cache", e); + result = Collections.emptyList(); + } + } + return result; + } + + public Collection<String> getAllDefinedElementsLocalNames() { + return this.getAllDefinedLocalNames(XSConstants.ELEMENT_DECLARATION); + } + + public Collection<String> getAllDefinedTypesLocalNames() { + return this.getAllDefinedLocalNames(XSConstants.TYPE_DEFINITION); + } + + @GET + @RestDoc(methodDescription = "May be used by the modeler to generate an XML editor based on the XML schema") + // we cannot use "MimeTypes.MIMETYPE_XSD" here as the latter is "text/xml" and org.eclipse.winery.repository.resources.AbstractComponentInstanceResource.getDefinitionsAsResponse() also produces text/xml + @Produces("text/xsd") + public Response getXSD() { + String location; + if ((location = this.getLocation()) == null) { + return Response.status(Status.NOT_FOUND).build(); + } + RepositoryFileReference ref = new RepositoryFileReference(this.id, location); + return BackendUtils.returnRepoPath(ref, null); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportsResource.java new file mode 100644 index 0000000..61af3bd --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportsResource.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.imports.xsdimports; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.definitions.imports.XSDImportId; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; +import org.restdoc.annotations.RestDoc; + +import com.fasterxml.jackson.core.JsonProcessingException; + +/** + * Manages all imports of type XML Schema Definition <br /> + * The actual implementation is done in the AbstractComponentsResource + * + * FIXME: This class should be generalized to handle ImportId + */ +public class XSDImportsResource extends AbstractComponentsResource<XSDImportResource> { + + @Path("{namespace}/") + @GET + @RestDoc(methodDescription = "Returns all available local names of defined elements in this namespace") + @Produces(MediaType.APPLICATION_JSON) + public String getAllElementLocalNames(@PathParam("namespace") String nsString, @QueryParam(value = "elements") String returnElements, @QueryParam(value = "types") String returnTypes) { + // returnElements is not read as either types or elements may be read + Set<String> allNCNames = this.getAllElementLocalNamesAsSet(nsString, returnTypes != null); + try { + return Utils.mapper.writeValueAsString(allNCNames); + } catch (JsonProcessingException e) { + throw new IllegalStateException(e); + } + } + + /** + * @param nsString the namesapce as String + * @param returnTypes true: return ElementTypes, false: return Elements + */ + private Set<String> getAllElementLocalNamesAsSet(final String nsString, final boolean getTypes) { + Set<XSDImportId> importsOfNS = this.getImportsOfNS(nsString); + + // TreeSet enables ordering + Set<String> allNCNames = new TreeSet<String>(); + + for (XSDImportId imp : importsOfNS) { + XSDImportResource res = new XSDImportResource(imp); + Collection<String> col; + if (getTypes) { + col = res.getAllDefinedTypesLocalNames(); + } else { + col = res.getAllDefinedElementsLocalNames(); + } + allNCNames.addAll(col); + } + return allNCNames; + } + + /** + * Finds out all imports belonging to the given namespace + * + * @param nsString the namespace to query + */ + private Set<XSDImportId> getImportsOfNS(final String nsString) { + // FIXME: Currently not supported by the repository, therefore, we filter by hand + Set<XSDImportId> allImports = Repository.INSTANCE.getAllTOSCAComponentIds(XSDImportId.class); + Namespace ns = new Namespace(nsString, true); + Set<XSDImportId> importsOfNs = new HashSet<XSDImportId>(); + for (XSDImportId imp : allImports) { + if (imp.getNamespace().equals(ns)) { + importsOfNs.add(imp); + } + } + return importsOfNs; + } + + /** + * Returns a mapping from localnames to XSD files, containing the defined + * local names for the given namespace + */ + public Map<String, RepositoryFileReference> getMapFromLocalNameToXSD(final String nsString, final boolean getTypes) { + Set<XSDImportId> importsOfNS = this.getImportsOfNS(nsString); + Map<String, RepositoryFileReference> result = new HashMap<>(); + for (XSDImportId imp : importsOfNS) { + XSDImportResource res = new XSDImportResource(imp); + Collection<String> col; + if (getTypes) { + col = res.getAllDefinedTypesLocalNames(); + } else { + col = res.getAllDefinedElementsLocalNames(); + } + RepositoryFileReference ref = res.getXSDFileReference(); + for (String localName : col) { + result.put(localName, ref); + } + } + return result; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfaceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfaceResource.java new file mode 100644 index 0000000..b7b7c15 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfaceResource.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.interfaces; + +import java.util.List; + +import javax.ws.rs.Path; + +import org.eclipse.winery.model.tosca.TInterface; +import org.eclipse.winery.model.tosca.TOperation; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; + +public class InterfaceResource extends EntityWithIdResource<TInterface> { + + private final TInterface iface; + + + public InterfaceResource(IIdDetermination<TInterface> idDetermination, TInterface o, int idx, List<TInterface> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + this.iface = o; + } + + /** + * required by artifacts.jsp + */ + public String getName() { + return this.iface.getName(); + } + + @Path("operations/") + public OperationsResource getOperationsResouce() { + List<TOperation> list = this.o.getOperation(); + return new OperationsResource(list, this.res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfacesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfacesResource.java new file mode 100644 index 0000000..4acfbd9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfacesResource.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.interfaces; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +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.model.tosca.TInterface; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypeResource; +import org.restdoc.annotations.RestDoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class InterfacesResource extends EntityWithIdCollectionResource<InterfaceResource, TInterface> { + + private static final Logger logger = LoggerFactory.getLogger(InterfacesResource.class); + + private TopologyGraphElementEntityTypeResource typeResource; + + private String urlPrefix; + + + public InterfacesResource(IPersistable res, List<TInterface> list) { + super(InterfaceResource.class, TInterface.class, list, res); + } + + /** + * @param urlPrefix prefix to be prepended to the URL. + * "source"|"target"|null. E.g., "source" for "sourceinterfaces" + */ + public InterfacesResource(String urlPrefix, List<TInterface> list, IPersistable typeResource) { + super(InterfaceResource.class, TInterface.class, list, typeResource); + this.urlPrefix = urlPrefix; + this.typeResource = (TopologyGraphElementEntityTypeResource) typeResource; + } + + @Override + public Viewable getHTML() { + return new Viewable("/jsp/interfaces/interfaces.jsp", this); + } + + /** + * Implementation base: <br /> + * {@link org.eclipse.winery.repository.resources.AbstractComponentResource. + * onPost(String)} + * + * @return entity: id of the stored interface + */ + @POST + @RestDoc(methodDescription = "Creates a new interface. Returns conflict if interface already exists") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + public Response onPost(@FormParam("interfaceName") String interfaceName) { + if (StringUtils.isEmpty(interfaceName)) { + return Response.status(Status.BAD_REQUEST).entity("null interfaceName").build(); + } + + TInterface iface = new TInterface(); + iface.setName(interfaceName); + + // check for duplicates + // return "conflict" if interface already exists + if (this.alreadyContains(iface)) { + return Response.status(Status.CONFLICT).build(); + } + + this.list.add(iface); + return BackendUtils.persist(this.res); + } + + /** + * Required by interfaces.jsp + */ + public String getUrlPrefix() { + return this.urlPrefix; + } + + @Override + public String getId(TInterface entity) { + return entity.getName(); + } + + /** + * @return the namespace of the node/relationship type + */ + public String getNamespace() { + return this.typeResource.getId().getNamespace().getDecoded(); + } + + /** + * @return the name of the node/relationship type + */ + public String getName() { + return this.typeResource.getName(); + } + + public String getRelationshipTypeOrNodeTypeURLFragment() { + if (this.typeResource instanceof RelationshipTypeResource) { + return "relationshiptype"; + } else { + return "nodetype"; + } + } + + public String getRelationshipTypeOrNodeType() { + if (this.typeResource instanceof RelationshipTypeResource) { + return "Relationship Type"; + } else { + return "Node Type"; + } + } + + public String getTypeQName() { + String res = this.typeResource.getId().getQName().toString(); + return res; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationResource.java new file mode 100644 index 0000000..7657e99 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationResource.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.interfaces; + +import java.util.List; + +import javax.ws.rs.Path; + +import org.eclipse.winery.model.tosca.TInterface; +import org.eclipse.winery.model.tosca.TOperation; +import org.eclipse.winery.model.tosca.TOperation.InputParameters; +import org.eclipse.winery.model.tosca.TOperation.OutputParameters; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OperationResource extends EntityWithIdResource<TOperation> { + + private static final Logger logger = LoggerFactory.getLogger(OperationResource.class); + + + public OperationResource(IIdDetermination<TOperation> idDetermination, TOperation o, int idx, List<TOperation> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + /** + * @return TOperation object for the corresponding object of operationName + * in the operation list contained in the given interface. null if + * interface could not be found in list + */ + public static TOperation getTOperation(String operationName, TInterface iface) { + List<TOperation> operationList = iface.getOperation(); + for (TOperation op : operationList) { + if (op.getName().equals(operationName)) { + return op; + } + } + return null; + } + + @Path("inputparameters/") + public ParametersResource getInputparameters() { + InputParameters inputParameters = this.o.getInputParameters(); + if (inputParameters == null) { + inputParameters = new InputParameters(); + this.o.setInputParameters(inputParameters); + } + return new ParametersResource(inputParameters.getInputParameter(), this.res); + } + + @Path("outputparameters/") + public ParametersResource getOutputparameters() { + OutputParameters outputParameters = this.o.getOutputParameters(); + if (outputParameters == null) { + outputParameters = new OutputParameters(); + this.o.setOutputParameters(outputParameters); + } + return new ParametersResource(outputParameters.getOutputParameter(), this.res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationsResource.java new file mode 100644 index 0000000..3e214e4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationsResource.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.interfaces; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +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.model.tosca.TOperation; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.restdoc.annotations.RestDocParam; + +import com.sun.jersey.api.view.Viewable; + +public class OperationsResource extends EntityWithIdCollectionResource<OperationResource, TOperation> { + + public OperationsResource(List<TOperation> list, IPersistable res) { + super(OperationResource.class, TOperation.class, list, res); + } + + @Override + public String getId(TOperation entity) { + return entity.getName(); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not yet implemented."); + } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + public Response createOperation(@FormParam("name") @RestDocParam(description = "used as name and id") String operationName) { + if (StringUtils.isEmpty(operationName)) { + return Response.status(Status.BAD_REQUEST).entity("operationName not provided").build(); + } + + operationName = Util.URLdecode(operationName); + + // TODO: check for duplicates as in instance states + + TOperation operation = new TOperation(); + operation.setName(operationName); + this.list.add(operation); + + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParameterResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParameterResource.java new file mode 100644 index 0000000..46662fd --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParameterResource.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,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.interfaces; + +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TBoolean; +import org.eclipse.winery.model.tosca.TParameter; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; + +public class ParameterResource extends EntityWithIdResource<TParameter> { + + public ParameterResource(IIdDetermination<TParameter> idDetermination, TParameter o, int idx, List<TParameter> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + @GET + @Path("type") + public String getType() { + return this.o.getType(); + } + + @PUT + @Path("type") + public Response putType(@FormParam(value = "type") String type) { + this.o.setType(type); + return BackendUtils.persist(this.res); + } + + @GET + @Path("required") + public String getRequired() { + return this.o.getRequired().toString(); + } + + @PUT + @Path("required") + public Response putRequired(@FormParam(value = "required") String required) { + TBoolean tb = TBoolean.valueOf(required); + this.o.setRequired(tb); + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParametersResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParametersResource.java new file mode 100644 index 0000000..c3afcbc --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParametersResource.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.interfaces; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +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.model.tosca.TBoolean; +import org.eclipse.winery.model.tosca.TParameter; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.restdoc.annotations.RestDocParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class ParametersResource extends EntityWithIdCollectionResource<ParameterResource, TParameter> { + + private static final Logger logger = LoggerFactory.getLogger(ParametersResource.class); + + + public ParametersResource(List<TParameter> parameters, IPersistable typeResource) { + super(ParameterResource.class, TParameter.class, parameters, typeResource); + } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + // @formatter:off + public Response createParamter( + @FormParam("name") String name, + @FormParam("type") String type, + @FormParam("required") @RestDocParam(description="type tYesNo, not Boolean. For convenience, on/off is also supported. In case this parameter is not provided, 'off' is assumed. This is in contrast to the specification, but it eases implementing the UI") String required) { + // @formatter:on + if (StringUtils.isEmpty(name)) { + return Response.status(Status.BAD_REQUEST).entity("name must not be null").build(); + } + if (StringUtils.isEmpty(type)) { + return Response.status(Status.BAD_REQUEST).entity("type must not be null").build(); + } + + TParameter param = new TParameter(); + param.setName(name); + param.setType(type); + TBoolean tb; + if (required == null) { + // The specification states that the default value is "yes" + // We assume "no", because Chrome does not send the checkbox data if a checkbox is not checked + tb = TBoolean.NO; + } else { + if (required.equalsIgnoreCase("on")) { + tb = TBoolean.YES; + } else if (required.equalsIgnoreCase("off")) { + tb = TBoolean.NO; + } else { + try { + tb = TBoolean.valueOf(required); + } catch (java.lang.IllegalArgumentException e) { + return Response.status(Status.BAD_REQUEST).entity("Wrong format of required").build(); + } + } + } + param.setRequired(tb); + + this.list.add(param); + + return BackendUtils.persist(this.res); + } + + @Override + public String getId(TParameter entity) { + return entity.getName(); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not yet implemented."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/package-info.java new file mode 100644 index 0000000..ea94a21 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/package-info.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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 + *******************************************************************************/ +/** + * This package contains the REST resources + * + * Mostly, they produces Viewables, where a JSP and the current resource is + * passed As the JSP itself handles plain Java objects and not Responses, the + * resources have also methods returning POJOs. This might be ugly design, but + * was quick to implement. + * + * The package structure is mirrored in src/main/webapp/jsp to ease finding the + * JSPs belonging to a resource. + * + * The resources are <em>not</em> in line with the resource model of the TOSCA + * container. Especially, we do not employ HATEOAS here. + */ +package org.eclipse.winery.repository.resources; + diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplateResource.java new file mode 100644 index 0000000..6a249df --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplateResource.java @@ -0,0 +1,263 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +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 javax.xml.namespace.QName; + +import org.eclipse.winery.common.RepositoryFileReference; +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.TBoundaryDefinitions; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.model.tosca.TPlan.PlanModelReference; +import org.eclipse.winery.model.tosca.TPlans; +import org.eclipse.winery.model.tosca.TServiceTemplate; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +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.AbstractComponentInstanceWithReferencesResource; +import org.eclipse.winery.repository.resources.IHasName; +import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.BoundaryDefinitionsResource; +import org.eclipse.winery.repository.resources.servicetemplates.plans.PlansResource; +import org.eclipse.winery.repository.resources.servicetemplates.selfserviceportal.SelfServicePortalResource; +import org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.TopologyTemplateResource; +import org.restdoc.annotations.RestDoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ServiceTemplateResource extends AbstractComponentInstanceWithReferencesResource implements IHasName { + + private static final Logger logger = LoggerFactory.getLogger(ServiceTemplateResource.class); + + + public ServiceTemplateResource(ServiceTemplateId id) { + super(id); + } + + /** sub-resources **/ + + @Path("topologytemplate/") + public TopologyTemplateResource getTopologyTemplateResource() { + if (this.getServiceTemplate().getTopologyTemplate() == null) { + // the main service template resource exists + // default topology template: empty template + // This eases the JSPs etc. and is valid as a non-existant topology template is equal to an empty one + this.getServiceTemplate().setTopologyTemplate(new TTopologyTemplate()); + } + return new TopologyTemplateResource(this); + } + + @Path("plans/") + public PlansResource getPlansResource() { + TPlans plans = this.getServiceTemplate().getPlans(); + if (plans == null) { + plans = new TPlans(); + this.getServiceTemplate().setPlans(plans); + } + return new PlansResource(plans.getPlan(), this); + } + + @Path("selfserviceportal/") + public SelfServicePortalResource getSelfServicePortalResource() { + return new SelfServicePortalResource(this); + } + + @Path("boundarydefinitions/") + public BoundaryDefinitionsResource getBoundaryDefinitionsResource() { + TBoundaryDefinitions boundaryDefinitions = this.getServiceTemplate().getBoundaryDefinitions(); + if (boundaryDefinitions == null) { + boundaryDefinitions = new TBoundaryDefinitions(); + this.getServiceTemplate().setBoundaryDefinitions(boundaryDefinitions); + } + return new BoundaryDefinitionsResource(this, boundaryDefinitions); + } + + @Override + public String getName() { + String name = this.getServiceTemplate().getName(); + if (name == null) { + // place default + name = this.getId().getXmlId().getDecoded(); + } + return name; + } + + @Override + public Response setName(String name) { + this.getServiceTemplate().setName(name); + return BackendUtils.persist(this); + } + + // @formatter:off + @GET + @RestDoc(methodDescription="Returns the associated node type, which can be substituted by this service template.<br />" + + "@return a QName of the form {namespace}localName is returned.") + @Path("substitutableNodeType") + @Produces(MediaType.TEXT_PLAIN) + // @formatter:on + public Response getSubstitutableNodeTypeAsResponse() { + QName qname = this.getServiceTemplate().getSubstitutableNodeType(); + if (qname == null) { + return Response.status(Status.NOT_FOUND).build(); + } else { + return Response.ok(qname.toString()).build(); + } + } + + /** + * + * @return null if there is no substitutable node type + */ + public QName getSubstitutableNodeType() { + return this.getServiceTemplate().getSubstitutableNodeType(); + } + + @DELETE + @RestDoc(methodDescription = "Removes the association to substitutable node type") + @Path("substitutableNodeType") + public Response deleteSubstitutableNodeType() { + this.getServiceTemplate().setSubstitutableNodeType(null); + BackendUtils.persist(this); + return Response.noContent().build(); + } + + public TServiceTemplate getServiceTemplate() { + return (TServiceTemplate) this.getElement(); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TServiceTemplate(); + } + + @Override + protected void copyIdToFields() { + this.getServiceTemplate().setId(this.getId().getXmlId().getDecoded()); + this.getServiceTemplate().setTargetNamespace(this.getId().getNamespace().getDecoded()); + } + + /** + * Synchronizes the known plans with the data in the XML. When there is a + * stored file, but no known entry in the XML, we guess "BPEL" as language + * and "build plan" as type. + * + * @throws IOException + */ + @Override + public void synchronizeReferences() { + // locally stored plans + TPlans plans = this.getServiceTemplate().getPlans(); + + // plans stored in the repository + PlansId plansContainerId = new PlansId((ServiceTemplateId) this.getId()); + SortedSet<PlanId> nestedPlans = Repository.INSTANCE.getNestedIds(plansContainerId, PlanId.class); + + Set<PlanId> plansToAdd = new HashSet<PlanId>(); + plansToAdd.addAll(nestedPlans); + + if (nestedPlans.isEmpty()) { + if (plans == null) { + // data on the file system equals the data -> no plans + return; + } else { + // we have to check for equality later + } + } + + if (plans == null) { + plans = new TPlans(); + this.getServiceTemplate().setPlans(plans); + } + + for (Iterator<TPlan> iterator = plans.getPlan().iterator(); iterator.hasNext();) { + TPlan plan = iterator.next(); + if (plan.getPlanModel() != null) { + // in case, a plan is directly contained in a Model element, we do not need to do anything + continue; + } + PlanModelReference planModelReference = plan.getPlanModelReference(); + if ((planModelReference = plan.getPlanModelReference()) != null) { + String ref = planModelReference.getReference(); + if ((ref == null) || ref.startsWith("../")) { + // references to local plans start with "../" + // special case (due to errors in the importer): empty PlanModelReference field + if (plan.getId() == null) { + // invalid plan entry: no id. + // we remove the entry + iterator.remove(); + continue; + } + PlanId planId = new PlanId(plansContainerId, new XMLId(plan.getId(), false)); + if (nestedPlans.contains(planId)) { + // everything allright + // we do NOT need to add the plan on the HDD to the XML + plansToAdd.remove(planId); + } else { + // no local storage for the plan, we remove it from the XML + iterator.remove(); + } + } + } + } + + // add all plans locally stored, but not contained in the XML, as plan element to the plans of the service template. + List<TPlan> thePlans = plans.getPlan(); + for (PlanId planId : plansToAdd) { + SortedSet<RepositoryFileReference> files = Repository.INSTANCE.getContainedFiles(planId); + if (files.size() != 1) { + throw new IllegalStateException("Currently, only one file per plan is supported."); + } + RepositoryFileReference ref = files.iterator().next(); + + TPlan plan = new TPlan(); + plan.setId(planId.getXmlId().getDecoded()); + plan.setName(planId.getXmlId().getDecoded()); + plan.setPlanType(org.eclipse.winery.repository.Constants.TOSCA_PLANTYPE_BUILD_PLAN); + plan.setPlanLanguage(org.eclipse.winery.common.constants.Namespaces.URI_BPEL20_EXECUTABLE); + + // create a PlanModelReferenceElement pointing to that file + String path = Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(ref)); + // path is relative from the definitions element + path = "../" + path; + PlanModelReference pref = new PlanModelReference(); + pref.setReference(path); + + plan.setPlanModelReference(pref); + thePlans.add(plan); + } + + try { + this.persist(); + } catch (IOException e) { + throw new IllegalStateException("Could not persist resource", e); + } + return; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplatesResource.java new file mode 100644 index 0000000..fd8b82c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplatesResource.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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; + +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +public class ServiceTemplatesResource extends AbstractComponentsResource<ServiceTemplateResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java new file mode 100644 index 0000000..0d4b141 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java @@ -0,0 +1,113 @@ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.SortedSet; + +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.taglibs.standard.functions.Functions; +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.ids.definitions.PolicyTypeId; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties; +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.model.tosca.TPlans; +import org.eclipse.winery.model.tosca.TServiceTemplate; +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.datatypes.TypeWithShortName; +import org.eclipse.winery.repository.datatypes.select2.Select2DataItem; +import org.eclipse.winery.repository.resources.admin.types.ConstraintTypesManager; + +public class BoundaryDefinitionsJSPData { + + private final TServiceTemplate ste; + private final TBoundaryDefinitions defs; + private URI baseURI; + + + /** + * + * @param ste the service template of the boundary definitions. Required to + * get a list of all plans + * @param baseURI the base URI of the service. Requried for rendering the + * topology template for the selections + */ + public BoundaryDefinitionsJSPData(TServiceTemplate ste, URI baseURI) { + this.ste = ste; + this.defs = ste.getBoundaryDefinitions(); + this.baseURI = baseURI; + } + + private String getDefinedProperties() { + Properties p = ModelUtilities.getProperties(this.defs); + Object o = p.getAny(); + if (o == null) { + // nothing stored -> return empty string + return ""; + } else { + // something stored --> return that + return Utils.getXMLAsString(p.getAny()); + } + } + + /** + * Helper method to return an initialized properties object only containing + * the user-defined properties. The TOSCA properties-element is not returned + * as the TOSCA XSD allows a single element only + */ + public String getDefinedPropertiesAsEscapedHTML() { + String s = this.getDefinedProperties(); + s = StringEscapeUtils.escapeHtml4(s); + return s; + } + + public String getDefinedPropertiesAsJSONString() { + String s = this.getDefinedProperties(); + s = StringEscapeUtils.escapeEcmaScript(s); + return s; + } + + public TBoundaryDefinitions getDefs() { + return this.defs; + } + + public String getBoundaryDefinitionsAsXMLStringEncoded() { + String res = Utils.getXMLAsString(this.defs); + return Functions.escapeXml(res); + } + + public Collection<TypeWithShortName> getConstraintTypes() { + return ConstraintTypesManager.INSTANCE.getTypes(); + } + + public Collection<QName> getAllPolicyTypes() { + SortedSet<PolicyTypeId> allTOSCAComponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(PolicyTypeId.class); + return BackendUtils.convertTOSCAComponentIdCollectionToQNameCollection(allTOSCAComponentIds); + } + + public String getRepositoryURL() { + return this.baseURI.toString(); + } + + public List<Select2DataItem> getlistOfAllPlans() { + TPlans plans = this.ste.getPlans(); + if (plans == null) { + return null; + } else { + List<Select2DataItem> res = new ArrayList<>(plans.getPlan().size()); + for (TPlan plan : plans.getPlan()) { + String id = plan.getId(); + String name = ModelUtilities.getNameWithIdFallBack(plan); + Select2DataItem di = new Select2DataItem(id, name); + res.add(di); + } + return res; + } + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java new file mode 100644 index 0000000..58dfbe9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 2013-2014 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.boundarydefinitions; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Capabilities; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Interfaces; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Policies; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties.PropertyMappings; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Requirements; +import org.eclipse.winery.model.tosca.TCapabilityRef; +import org.eclipse.winery.model.tosca.TRequirementRef; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces.InterfacesResource; +import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.policies.PoliciesResource; +import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps.CapabilitiesResource; +import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps.RequirementsResource; +import org.restdoc.annotations.RestDoc; +import org.restdoc.annotations.RestDocParam; +import org.w3c.dom.Document; + +import com.sun.jersey.api.view.Viewable; + +public class BoundaryDefinitionsResource { + + private final ServiceTemplateResource serviceTemplateResource; + private final TBoundaryDefinitions boundaryDefinitions; + + + public BoundaryDefinitionsResource(ServiceTemplateResource serviceTemplateResource, TBoundaryDefinitions boundaryDefinitions) { + this.serviceTemplateResource = serviceTemplateResource; + this.boundaryDefinitions = boundaryDefinitions; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML(@Context UriInfo uriInfo) { + return new Viewable("/jsp/servicetemplates/boundarydefinitions/boundarydefinitions.jsp", new BoundaryDefinitionsJSPData(this.serviceTemplateResource.getServiceTemplate(), uriInfo.getBaseUri())); + } + + @PUT + @RestDoc(methodDescription = "Replaces the boundary definitions by the information given in the XML") + @Consumes(MediaType.TEXT_XML) + public Response setModel(TBoundaryDefinitions boundaryDefinitions) { + this.serviceTemplateResource.getServiceTemplate().setBoundaryDefinitions(boundaryDefinitions); + return BackendUtils.persist(this.serviceTemplateResource); + } + + @Path("properties/") + @PUT + @Consumes(MediaType.TEXT_XML) + @RestDoc(resourceDescription = "Models the user-defined properties. The property mappings go into a separate resource propertymappings.") + public Response putProperties(@RestDocParam(description = "Stored properties. The XSD allows a single element only. Therefore, we go for the contained element") Document doc) { + org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties properties = ModelUtilities.getProperties(this.boundaryDefinitions); + properties.setAny(doc.getDocumentElement()); + return BackendUtils.persist(this.serviceTemplateResource); + } + + @Path("requirements/") + public RequirementsResource getRequiremensResource() { + Requirements requirements = this.boundaryDefinitions.getRequirements(); + if (requirements == null) { + requirements = new Requirements(); + this.boundaryDefinitions.setRequirements(requirements); + } + List<TRequirementRef> refs = requirements.getRequirement(); + return new RequirementsResource(this.serviceTemplateResource, refs); + } + + @Path("capabilities/") + public CapabilitiesResource getCapabilitiesResource() { + Capabilities caps = this.boundaryDefinitions.getCapabilities(); + if (caps == null) { + caps = new Capabilities(); + this.boundaryDefinitions.setCapabilities(caps); + } + List<TCapabilityRef> refs = caps.getCapability(); + return new CapabilitiesResource(this.serviceTemplateResource, refs); + } + + @Path("policies/") + public PoliciesResource getPoliciesResource() { + Policies policies = this.boundaryDefinitions.getPolicies(); + if (policies == null) { + policies = new Policies(); + this.boundaryDefinitions.setPolicies(policies); + } + return new PoliciesResource(policies.getPolicy(), this.serviceTemplateResource); + } + + /** + * This path is below "boundary definitions" to ease implementation If it + * was modeled following the XSD, it would have been nested below + * "properties". We did not do that + */ + @Path("propertymappings/") + public PropertyMappingsResource getPropertyMappings() { + Properties properties = this.boundaryDefinitions.getProperties(); + if (properties == null) { + properties = new Properties(); + this.boundaryDefinitions.setProperties(properties); + } + PropertyMappings propertyMappings = properties.getPropertyMappings(); + if (propertyMappings == null) { + propertyMappings = new PropertyMappings(); + properties.setPropertyMappings(propertyMappings); + } + return new PropertyMappingsResource(propertyMappings, this.serviceTemplateResource); + } + + @Path("interfaces/") + public InterfacesResource getInterfacesResource() { + Interfaces interfaces = this.boundaryDefinitions.getInterfaces(); + if (interfaces == null) { + interfaces = new Interfaces(); + this.boundaryDefinitions.setInterfaces(interfaces); + } + return new InterfacesResource(interfaces.getInterface(), this.serviceTemplateResource); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/PropertyMappingsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/PropertyMappingsResource.java new file mode 100644 index 0000000..a6872e0 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/PropertyMappingsResource.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2013-2014 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.boundarydefinitions; + +import java.util.Iterator; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +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.ModelUtilities; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties.PropertyMappings; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TPropertyMapping; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.restdoc.annotations.RestDoc; + +public class PropertyMappingsResource { + + private final PropertyMappings propertyMappings; + private final ServiceTemplateResource res; + + + public PropertyMappingsResource(PropertyMappings propertyMappings, ServiceTemplateResource res) { + this.propertyMappings = propertyMappings; + this.res = res; + } + + @Path("{serviceTemplatePropertyRef}") + @DELETE + public Response onDelete(@PathParam("serviceTemplatePropertyRef") String serviceTemplatePropertyRef) { + serviceTemplatePropertyRef = Util.URLdecode(serviceTemplatePropertyRef); + Iterator<TPropertyMapping> iterator = this.propertyMappings.getPropertyMapping().iterator(); + while (iterator.hasNext()) { + TPropertyMapping propertyMapping = iterator.next(); + if (propertyMapping.getServiceTemplatePropertyRef().equals(serviceTemplatePropertyRef)) { + iterator.remove(); + return BackendUtils.persist(this.res); + } + } + // if the property mapping was not found, we reach this point + // otherwise "iterator.remove()" has called and the resource persisted + return Response.status(Status.NOT_FOUND).build(); + } + + private void updatePropertyMapping(TPropertyMapping propertyMapping, String serviceTemplatePropertyRef, TEntityTemplate template, String targetPropertyRef) { + propertyMapping.setServiceTemplatePropertyRef(serviceTemplatePropertyRef); + propertyMapping.setTargetObjectRef(template); + propertyMapping.setTargetPropertyRef(targetPropertyRef); + } + + @RestDoc(methodDescription = "Creates or updates a property mapping with the given fields") + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + // @formatter:off + public Response onPost( + @FormParam("serviceTemplatePropertyRef") String serviceTemplatePropertyRef, + @FormParam("targetObjectRef") String targetObjectRef, + @FormParam("targetPropertyRef") String targetPropertyRef + ) { + // @formatter:on + if (StringUtils.isEmpty(serviceTemplatePropertyRef)) { + return Response.status(Status.BAD_REQUEST).entity("serviceTemplatePropertyRef must not be empty").build(); + } + if (StringUtils.isEmpty(targetObjectRef)) { + return Response.status(Status.BAD_REQUEST).entity("targetObjectRef must not be empty").build(); + } + if (StringUtils.isEmpty(targetPropertyRef)) { + return Response.status(Status.BAD_REQUEST).entity("targetPropertyRef must not be empty").build(); + } + + TEntityTemplate template = ModelUtilities.findNodeTemplateOrRequirementOfNodeTemplateOrCapabilityOfNodeTemplateOrRelationshipTemplate(this.res.getServiceTemplate().getTopologyTemplate(), targetObjectRef); + if (template == null) { + return Response.status(Status.BAD_REQUEST).entity("targetObjectRef " + targetObjectRef + " could not be resolved.").build(); + } + + // replace propertyMapping if it exists + Iterator<TPropertyMapping> iterator = this.propertyMappings.getPropertyMapping().iterator(); + while (iterator.hasNext()) { + TPropertyMapping propertyMapping = iterator.next(); + if (propertyMapping.getServiceTemplatePropertyRef().equals(serviceTemplatePropertyRef)) { + // we found a property with the same mapping + // just update it ... + this.updatePropertyMapping(propertyMapping, serviceTemplatePropertyRef, template, targetPropertyRef); + // ... and finish processing + return BackendUtils.persist(this.res); + } + } + + // the property mapping didn't exist, + // we create a new one + TPropertyMapping newPropertyMapping = new TPropertyMapping(); + this.updatePropertyMapping(newPropertyMapping, serviceTemplatePropertyRef, template, targetPropertyRef); + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedInterfaceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedInterfaceResource.java new file mode 100644 index 0000000..b69e802 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedInterfaceResource.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2014 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.boundarydefinitions.interfaces; + +import java.util.List; + +import javax.ws.rs.Path; + +import org.eclipse.winery.model.tosca.TExportedInterface; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; + +public class ExportedInterfaceResource extends EntityWithIdResource<TExportedInterface> { + + public ExportedInterfaceResource(IIdDetermination<TExportedInterface> idDetermination, TExportedInterface o, int idx, List<TExportedInterface> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + @Path("exportedoperations/") + public ExportedOperationsResource getExportedOperationsResource() { + return new ExportedOperationsResource(this.o.getOperation(), this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationResource.java new file mode 100644 index 0000000..dd10751 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationResource.java @@ -0,0 +1,249 @@ +/******************************************************************************* + * Copyright (c) 2014 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.boundarydefinitions.interfaces; + +import java.io.StringWriter; +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.model.tosca.TExportedOperation; +import org.eclipse.winery.model.tosca.TExportedOperation.NodeOperation; +import org.eclipse.winery.model.tosca.TExportedOperation.Plan; +import org.eclipse.winery.model.tosca.TExportedOperation.RelationshipOperation; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TServiceTemplate; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; + +public class ExportedOperationResource extends EntityWithIdResource<TExportedOperation> { + + private static final Logger logger = LoggerFactory.getLogger(ExportedOperationResource.class); + + + public ExportedOperationResource(IIdDetermination<TExportedOperation> idDetermination, TExportedOperation o, int idx, List<TExportedOperation> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public String getJSONRepresentation() { + JsonFactory jsonFactory = new JsonFactory(); + StringWriter sw = new StringWriter(); + try { + JsonGenerator jg = jsonFactory.createGenerator(sw); + jg.writeStartObject(); + String type = this.getType(); + jg.writeStringField("type", type); + jg.writeStringField("ref", this.getReference()); + if ((type != null) && (!type.equals("Plan"))) { + jg.writeStringField("interfacename", this.getInterfaceName()); + jg.writeStringField("operationname", this.getOperationName()); + } + jg.writeEndObject(); + jg.close(); + } catch (Exception e) { + ExportedOperationResource.logger.error(e.getMessage(), e); + throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build()); + } + String res = sw.toString(); + return res; + } + + /** + * + * @return "NodeOperation" | "RelationshipOperation" | "Plan" | null. null + * is returned if no type is set + */ + @Path("type") + @GET + public String getType() { + if (this.o.getNodeOperation() != null) { + return "NodeOperation"; + } else if (this.o.getRelationshipOperation() != null) { + return "RelationshipOperation"; + } else if (this.o.getPlan() != null) { + return "Plan"; + } else { + return null; + } + } + + @Path("type") + @PUT + public Response setType(String type) { + switch (type) { + case "NodeOperation": + if (this.o.getNodeOperation() == null) { + // only do something, if the type is really changed + this.o.setRelationshipOperation(null); + this.o.setPlan(null); + NodeOperation no = new NodeOperation(); + this.o.setNodeOperation(no); + } + break; + case "RelationshipOperation": + if (this.o.getRelationshipOperation() == null) { + // only do something, if the type is really changed + this.o.setNodeOperation(null); + this.o.setPlan(null); + RelationshipOperation ro = new RelationshipOperation(); + this.o.setRelationshipOperation(ro); + } + break; + case "Plan": + if (this.o.getPlan() == null) { + // only do something, if the type is really changed + this.o.setNodeOperation(null); + this.o.setRelationshipOperation(null); + Plan plan = new Plan(); + this.o.setPlan(plan); + } + break; + default: + return Response.status(Status.BAD_REQUEST).entity("Unknown type " + type).build(); + } + return BackendUtils.persist(this.res); + } + + /** + * @return null if no reference is set + */ + @Path("ref") + @GET + public String getReference() { + if (this.o.getNodeOperation() != null) { + TNodeTemplate nt = (TNodeTemplate) this.o.getNodeOperation().getNodeRef(); + if (nt == null) { + return null; + } + return nt.getId(); + } else if (this.o.getRelationshipOperation() != null) { + TRelationshipTemplate rt = (TRelationshipTemplate) this.o.getRelationshipOperation().getRelationshipRef(); + if (rt == null) { + return null; + } + return rt.getId(); + } else if (this.o.getPlan() != null) { + TPlan plan = (TPlan) this.o.getPlan().getPlanRef(); + if (plan == null) { + return null; + } + return plan.getId(); + } else { + // no type set -> no reference can be returned + return null; + } + } + + @Path("ref") + @PUT + public Response setReference(String ref) { + TServiceTemplate ste = ((ServiceTemplateResource) this.res).getServiceTemplate(); + + // we assume that a correctly set type also means that getX (getNodeOperation, ...) returns non null + switch (this.getType()) { + case "NodeOperation": + TNodeTemplate nodeTemplate = ModelUtilities.resolveNodeTemplate(ste, ref); + this.o.getNodeOperation().setNodeRef(nodeTemplate); + break; + case "RelationshipOperation": + TRelationshipTemplate relationshipTemplate = ModelUtilities.resolveRelationshipTemplate(ste, ref); + this.o.getRelationshipOperation().setRelationshipRef(relationshipTemplate); + break; + case "Plan": + TPlan plan = ModelUtilities.resolvePlan(ste, ref); + this.o.getPlan().setPlanRef(plan); + break; + default: + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Unknown type " + this.getType()).build(); + } + return BackendUtils.persist(this.res); + } + + @Path("interfacename") + @GET + public String getInterfaceName() { + if (this.o.getNodeOperation() != null) { + return this.o.getNodeOperation().getInterfaceName(); + } else if (this.o.getRelationshipOperation() != null) { + return this.o.getRelationshipOperation().getInterfaceName(); + } else if (this.o.getPlan() != null) { + throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("A plan does not carry an interface").build()); + } else { + throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity("Unsupported state of ExportedOperation").build()); + } + } + + @Path("interfacename") + @PUT + public Response setInterfaceName(String interfacename) { + if (this.o.getNodeOperation() != null) { + this.o.getNodeOperation().setInterfaceName(interfacename); + } else if (this.o.getRelationshipOperation() != null) { + this.o.getRelationshipOperation().setInterfaceName(interfacename); + } else if (this.o.getPlan() != null) { + throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("A plan does not carry an interface").build()); + } else { + throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("No type set").build()); + } + return BackendUtils.persist(this.res); + } + + @Path("operationname") + @GET + public String getOperationName() { + if (this.o.getNodeOperation() != null) { + return this.o.getNodeOperation().getOperationName(); + } else if (this.o.getRelationshipOperation() != null) { + return this.o.getRelationshipOperation().getOperationName(); + } else if (this.o.getPlan() != null) { + throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("A plan does not carry an operation").build()); + } else { + throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity("Unsupported state of ExportedOperation").build()); + } + } + + @Path("operationname") + @PUT + public Response setOperationName(String name) { + if (this.o.getNodeOperation() != null) { + this.o.getNodeOperation().setOperationName(name); + } else if (this.o.getRelationshipOperation() != null) { + this.o.getRelationshipOperation().setOperationName(name); + } else if (this.o.getPlan() != null) { + throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("A plan does not carry an operation").build()); + } else { + throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("No type set").build()); + } + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationsResource.java new file mode 100644 index 0000000..d8788fd --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationsResource.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2014 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.boundarydefinitions.interfaces; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TExportedOperation; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; + +import com.sun.jersey.api.view.Viewable; + +public class ExportedOperationsResource extends EntityWithIdCollectionResource<ExportedOperationResource, TExportedOperation> { + + public ExportedOperationsResource(List<TExportedOperation> list, IPersistable res) { + super(ExportedOperationResource.class, TExportedOperation.class, list, res); + } + + @Override + public String getId(TExportedOperation entity) { + return entity.getName(); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("No implementation required: boundarydefinitions.jsp contains all required html."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/InterfacesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/InterfacesResource.java new file mode 100644 index 0000000..301f457 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/InterfacesResource.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2014 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.boundarydefinitions.interfaces; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TExportedInterface; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; + +import com.sun.jersey.api.view.Viewable; + +public class InterfacesResource extends EntityWithIdCollectionResource<ExportedInterfaceResource, TExportedInterface> { + + public InterfacesResource(List<TExportedInterface> list, IPersistable res) { + super(ExportedInterfaceResource.class, TExportedInterface.class, list, res); + } + + @Override + public String getId(TExportedInterface entity) { + return entity.getName(); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("No implementation required: boundarydefinitions.jsp contains all required html."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/package-info.java new file mode 100644 index 0000000..6a342ea --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/package-info.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + *******************************************************************************/ + +/** + * This package models exported interfaces nested in a boundary definitions. + */ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PoliciesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PoliciesResource.java new file mode 100644 index 0000000..b18341f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PoliciesResource.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2014 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.boundarydefinitions.policies; + +import java.util.List; + +import javax.ws.rs.PUT; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TPolicy; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource; + +import com.sun.jersey.api.view.Viewable; + +public class PoliciesResource extends EntityWithoutIdCollectionResource<PolicyResource, TPolicy> { + + public PoliciesResource(List<TPolicy> list, IPersistable res) { + super(PolicyResource.class, TPolicy.class, list, res); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not required: boundarydefinitions.jsp also includes the content of the Policy tab."); + } + + @PUT + public Response replaceAll(List<TPolicy> newList) { + this.list.clear(); + for (TPolicy policy : newList) { + this.list.add(policy); + } + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PolicyResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PolicyResource.java new file mode 100644 index 0000000..08fbd8d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PolicyResource.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2014 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.boundarydefinitions.policies; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TPolicy; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource; + +public class PolicyResource extends EntityWithoutIdResource<TPolicy> { + + public PolicyResource(TPolicy o, int idx, List<TPolicy> list, IPersistable res) { + super(o, idx, list, res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/package-info.java new file mode 100644 index 0000000..45bc0c7 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/package-info.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + *******************************************************************************/ + +/** + * This package models policies nested in a boundary definitions. It could be resued for the topology modeler, but currently, this is not necessary. + */ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.policies;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilitiesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilitiesResource.java new file mode 100644 index 0000000..80f2640 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilitiesResource.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2014 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.boundarydefinitions.reqscaps; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.model.tosca.TCapability; +import org.eclipse.winery.model.tosca.TCapabilityRef; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.CollectionsHelper; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; + +import com.sun.jersey.api.view.Viewable; + +/** + * This class is an adaption from + * {@link org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps.RequirementsResource} + */ +public class CapabilitiesResource extends EntityWithoutIdCollectionResource<CapabilityResource, TCapabilityRef> { + + public CapabilitiesResource(IPersistable res, List<TCapabilityRef> refs) { + super(CapabilityResource.class, TCapabilityRef.class, refs, res); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not yet required: boundarydefinitions.jsp renders all tab content."); + } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response addNewElement(@FormParam("name") String name, @FormParam("ref") String reference) { + // Implementation adapted from super addNewElement + + if (reference == null) { + return Response.status(Status.BAD_REQUEST).entity("A reference has to be provided").build(); + } + + TCapabilityRef ref = new TCapabilityRef(); + ref.setName(name); // may also be null + + // The XML model fordces us to put a reference to the object and not just the string + ServiceTemplateResource rs = (ServiceTemplateResource) this.res; + TCapability resolved = ModelUtilities.resolveCapability(rs.getServiceTemplate(), reference); + // In case nothing was found: report back to the user + if (resolved == null) { + return Response.status(Status.BAD_REQUEST).entity("Reference could not be resolved").build(); + } + + ref.setRef(resolved); + + // "this.alreadyContains(ref)" cannot be called as this leads to a mappable exception: The data does not contain an id where the given ref attribute may point to + + this.list.add(ref); + return CollectionsHelper.persist(this.res, this, ref); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilityResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilityResource.java new file mode 100644 index 0000000..7cb7b49 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilityResource.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2014 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.boundarydefinitions.reqscaps; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TCapabilityRef; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource; + +public class CapabilityResource extends EntityWithoutIdResource<TCapabilityRef> { + + public CapabilityResource(TCapabilityRef o, int idx, List<TCapabilityRef> list, IPersistable res) { + super(o, idx, list, res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementResource.java new file mode 100644 index 0000000..72a7476 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementResource.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2014 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.boundarydefinitions.reqscaps; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TRequirementRef; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource; + +public class RequirementResource extends EntityWithoutIdResource<TRequirementRef> { + + public RequirementResource(TRequirementRef o, int idx, List<TRequirementRef> list, IPersistable res) { + super(o, idx, list, res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementsResource.java new file mode 100644 index 0000000..dc6ad94 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementsResource.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2014 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.boundarydefinitions.reqscaps; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.model.tosca.TRequirement; +import org.eclipse.winery.model.tosca.TRequirementRef; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.CollectionsHelper; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; + +import com.sun.jersey.api.view.Viewable; + +/** + * This class is mirrored at + * {@link org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps.CapabilitiesResource} + */ +public class RequirementsResource extends EntityWithoutIdCollectionResource<RequirementResource, TRequirementRef> { + + public RequirementsResource(IPersistable res, List<TRequirementRef> refs) { + super(RequirementResource.class, TRequirementRef.class, refs, res); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not yet required: boundarydefinitions.jsp renders all tab content."); + } + + /** + * Adds an element using form-encoding + * + * This is necessary as TRequirementRef contains an IDREF and the XML + * snippet itself does not contain the target id + * + * @param name the optional name of the requirement + * @param reference the reference to a requirement in the topology + */ + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response addNewElement(@FormParam("name") String name, @FormParam("ref") String reference) { + // Implementation adapted from super addNewElement + + if (reference == null) { + return Response.status(Status.BAD_REQUEST).entity("A reference has to be provided").build(); + } + + TRequirementRef ref = new TRequirementRef(); + ref.setName(name); // may also be null + + // The XML model forces us to put a reference to the object and not just the string + ServiceTemplateResource rs = (ServiceTemplateResource) this.res; + TRequirement resolved = ModelUtilities.resolveRequirement(rs.getServiceTemplate(), reference); + // In case nothing was found: report back to the user + if (resolved == null) { + return Response.status(Status.BAD_REQUEST).entity("Reference could not be resolved").build(); + } + + ref.setRef(resolved); + + // "this.alreadyContains(ref)" cannot be called as this leads to a mappable exception: The data does not contain an id where the given ref attribute may point to + + this.list.add(ref); + return CollectionsHelper.persist(this.res, this, ref); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/package-info.java new file mode 100644 index 0000000..f6a3c5d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/package-info.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + *******************************************************************************/ + +/** + * This package contains all classes for requirement refs and capability refs + * + * They are nested as "Requirements" / "Capabilities" in the boundary definitions, but the things itself are called "...Ref" + */ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanFileResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanFileResource.java new file mode 100644 index 0000000..5a4b56f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanFileResource.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2014-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.File; +import java.io.IOException; +import java.io.InputStream; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.elements.PlanId; +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.restdoc.annotations.RestDoc; + +import com.sun.jersey.core.header.FormDataContentDisposition; +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + +public class PlanFileResource { + + private final PlanId planId; + private TPlan plan; + private ServiceTemplateResource res; + + + public PlanFileResource(ServiceTemplateResource res, PlanId planId, TPlan plan) { + this.res = res; + this.planId = planId; + this.plan = plan; + } + + /** + * Extracts the file reference from plan's planModelReference + */ + private RepositoryFileReference getFileRef() { + String reference = this.plan.getPlanModelReference().getReference(); + File f = new File(reference); + return new RepositoryFileReference(this.planId, f.getName()); + } + + @PUT + @Consumes({MediaType.MULTIPART_FORM_DATA}) + @RestDoc(methodDescription = "Resource currently works for BPMN4TOSCA plans only") + // @formatter:off + public Response onPutFile( + @FormDataParam("file") InputStream uploadedInputStream, + @FormDataParam("file") FormDataContentDisposition fileDetail, + @FormDataParam("file") FormDataBodyPart body + ) { + // @formatter:on + + String fileName = fileDetail.getFileName(); + RepositoryFileReference ref = new RepositoryFileReference(this.planId, fileName); + RepositoryFileReference oldRef = this.getFileRef(); + boolean persistanceNecessary; + if (ref.equals(oldRef)) { + // nothing todo, file will be replaced + persistanceNecessary = false; + } else { + // new filename sent + BackendUtils.delete(oldRef); + PlansResource.setPlanModelReference(this.plan, this.planId, fileName); + persistanceNecessary = true; + } + + // Really store it + 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(); + } + + if (persistanceNecessary) { + return BackendUtils.persist(this.res); + } else { + return Response.noContent().build(); + } + } + + @PUT + @Consumes({MediaType.APPLICATION_JSON}) + // @formatter:off + public Response onPutJSON(InputStream is) { + RepositoryFileReference ref = this.getFileRef(); + return BackendUtils.putContentToFile(ref, is, MediaType.APPLICATION_JSON_TYPE); + } + + /** + * Returns the stored file. + */ + @GET + public Response getFile(@HeaderParam("If-Modified-Since") String modified) { + RepositoryFileReference ref = this.getFileRef(); + return BackendUtils.returnRepoPath(ref, modified); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanResource.java new file mode 100644 index 0000000..704c831 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanResource.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * 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.net.URI; +import java.util.List; + +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.lang3.StringUtils; +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.definitions.TOSCAComponentId; +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.InputParameters; +import org.eclipse.winery.model.tosca.TPlan.OutputParameters; +import org.eclipse.winery.repository.Prefs; +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.IHasName; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; +import org.eclipse.winery.repository.resources.interfaces.ParametersResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Does <em>not</em> implement + * {@link org.eclipse.winery.repository.resources.IHasTypeReference}, because + * the type of a plan is outside the system of TOSCA. + */ +public class PlanResource extends EntityWithIdResource<TPlan> implements IHasName { + + private static final Logger logger = LoggerFactory.getLogger(PlanResource.class); + + + public PlanResource(IIdDetermination<TPlan> idDetermination, TPlan o, int idx, List<TPlan> list, ServiceTemplateResource res) { + super(idDetermination, o, idx, list, res); + } + + /** + * Ugly hack to get the parent service template resource + * + */ + public ServiceTemplateResource getServiceTemplateResource() { + // Solution proposal 1: Each sub-resource should know its parent service + // template + // + // Solution proposal 2 (Generic solution): Each resource should know its + // parent resource + // + // Does not work when plan is used at as component instance (then, + // serviceTemplateResource is null). In this case, a plan is not associated + // with a service template. + + // we cannot use "((PlanId) id).getParent()" as this "only" returns an + // ID + // we could create a newly resource based on that ID + // However, the parent resource has already been created when the + // PlanResource has been generated: + // Jersey crawls down from the main resource through the service + // template resource to the plan resource + return (ServiceTemplateResource) this.res; + } + + /** + * Determines the id of the current resource + */ + private PlanId getId() { + ServiceTemplateId sId = (ServiceTemplateId) this.getServiceTemplateResource().getId(); + PlansId psId = new PlansId(sId); + PlanId pId = new PlanId(psId, new XMLId(this.o.getId(), false)); + return pId; + } + + @Override + @DELETE + public Response onDelete() { + Response res = super.onDelete(); + if (Utils.isSuccessFulResponse(res)) { + try { + Repository.INSTANCE.forceDelete(this.getId()); + } catch (IOException e) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not remove plan file").build(); + } + return BackendUtils.persist(this.res); + } else { + return res; + } + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML(@Context UriInfo uriInfo) { + boolean isBPMN4TOSCA = this.o.getPlanLanguage().equals(org.eclipse.winery.common.constants.Namespaces.URI_BPMN4TOSCA_20); + String bpmn4toscaBaseURL = Prefs.INSTANCE.getBPMN4TOSCABaseURL(); + if (isBPMN4TOSCA && (!StringUtils.isEmpty(bpmn4toscaBaseURL))) { + String uri = bpmn4toscaBaseURL; + URI repositoryURI = uriInfo.getBaseUri(); + uri += "?repositoryURL=" + Util.URLencode(repositoryURI.toString()); + TOSCAComponentId serviceTemplateId = this.getServiceTemplateResource().getId(); + uri += "&namespace=" + serviceTemplateId.getNamespace().getEncoded(); + uri += "&id=" + serviceTemplateId.getXmlId().getEncoded(); + uri += "&plan=" + this.getName(); + return Response.temporaryRedirect(Utils.createURI(uri)).build(); + } else { + // return Response.ok().entity("No editor plugin found for plan language " + this.o.getPlanLanguage()).build(); + URI fileURI = uriInfo.getAbsolutePath().resolve("file"); + return Response.seeOther(fileURI).build(); + } + } + + @Override + public String getName() { + String name = this.o.getName(); + if (name == null) { + name = this.o.getId(); + } + return name; + } + + @Override + public Response setName(@FormParam("value") String name) { + this.o.setName(name); + return BackendUtils.persist(this.res); + } + + @Path("file") + public PlanFileResource getPlanFileResource() { + return new PlanFileResource((ServiceTemplateResource) this.res, this.getId(), this.o); + } + + @GET + @Path("type") + public String getType() { + return this.o.getPlanType(); + } + + @PUT + @Path("type") + public Response setType(@FormParam("type") String type) { + this.o.setPlanType(type); + return BackendUtils.persist(this.res); + } + + @GET + @Path("language") + public String getLanguage() { + return this.o.getPlanLanguage(); + } + + @PUT + @Path("language") + public Response setLanguage(@FormParam("language") String language) { + this.o.setPlanType(language); + return BackendUtils.persist(this.res); + } + + @Path("inputparameters/") + public ParametersResource getInputParametersResource() { + InputParameters inputParameters = this.o.getInputParameters(); + if (inputParameters == null) { + inputParameters = new InputParameters(); + this.o.setInputParameters(inputParameters); + } + return new ParametersResource(inputParameters.getInputParameter(), this.getServiceTemplateResource()); + } + + @Path("outputparameters/") + public ParametersResource getOutputParametersResource() { + OutputParameters outputParameters = this.o.getOutputParameters(); + if (outputParameters == null) { + outputParameters = new OutputParameters(); + this.o.setOutputParameters(outputParameters); + } + return new ParametersResource(outputParameters.getOutputParameter(), this.getServiceTemplateResource()); + } +} 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(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResourceData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResourceData.java new file mode 100644 index 0000000..8527eb4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResourceData.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.StringWriter; +import java.util.Collection; +import java.util.List; + +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.model.tosca.TPlan.PlanModelReference; +import org.eclipse.winery.repository.datatypes.TypeWithShortName; +import org.eclipse.winery.repository.resources.admin.types.PlanLanguagesManager; +import org.eclipse.winery.repository.resources.admin.types.PlanTypesManager; +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; + +public class PlansResourceData { + + private static final Logger logger = LoggerFactory.getLogger(PlansResourceData.class); + + // data: [ [id, pre, name, type, lang]* ] + private String embeddedPlansTableData; + + // data: [ [id, pre, name, type, lang, reference]* ] + private String linkedPlansTableData; + + + /** + * Data object for the JSP + * + * @param serviceTemplateResource the service template the plans belong to + */ + public PlansResourceData(List<TPlan> plans) { + if (plans.isEmpty()) { + this.embeddedPlansTableData = "[]"; + this.linkedPlansTableData = "[]"; + return; + } + JsonFactory jsonFactory = new JsonFactory(); + StringWriter embeddedPlansTableDataSW = new StringWriter(); + StringWriter linkedPlansTableDataSW = new StringWriter(); + try { + JsonGenerator jGeneratorEmbedded = jsonFactory.createGenerator(embeddedPlansTableDataSW); + JsonGenerator jGeneratorLinked = jsonFactory.createGenerator(linkedPlansTableDataSW); + + jGeneratorEmbedded.writeStartArray(); + jGeneratorLinked.writeStartArray(); + + for (TPlan plan : plans) { + String name = plan.getName(); + if (name == null) { + // name defaults to id + name = plan.getId(); + } + String type = PlanTypesManager.INSTANCE.getShortName(plan.getPlanType()); + String language = PlanLanguagesManager.INSTANCE.getShortName(plan.getPlanLanguage()); + PlanModelReference planModelReference = plan.getPlanModelReference(); + String reference = planModelReference != null ? planModelReference.getReference() : null; + JsonGenerator gen; + boolean writeReference; + if (reference == null) { + gen = jGeneratorEmbedded; + writeReference = false; + } else if (reference.startsWith("../")) { + gen = jGeneratorEmbedded; + writeReference = false; + } else { + gen = jGeneratorLinked; + writeReference = true; + } + + gen.writeStartArray(); + gen.writeString(plan.getId()); + gen.writeString(""); // precondition + gen.writeString(name); + gen.writeString(type); + gen.writeString(language); + if (writeReference) { + gen.writeString(reference); + } + gen.writeEndArray(); + } + + jGeneratorEmbedded.writeEndArray(); + jGeneratorLinked.writeEndArray(); + + jGeneratorEmbedded.close(); + embeddedPlansTableDataSW.close(); + jGeneratorLinked.close(); + linkedPlansTableDataSW.close(); + } catch (JsonGenerationException e) { + PlansResourceData.logger.error(e.getMessage(), e); + this.embeddedPlansTableData = "[]"; + this.linkedPlansTableData = "[]"; + return; + } catch (IOException e) { + PlansResourceData.logger.error("", e); + this.embeddedPlansTableData = "[]"; + this.linkedPlansTableData = "[]"; + return; + } + this.embeddedPlansTableData = embeddedPlansTableDataSW.toString(); + this.linkedPlansTableData = linkedPlansTableDataSW.toString(); + } + + public String getEmbeddedPlansTableData() { + return this.embeddedPlansTableData; + } + + public String getLinkedPlansTableData() { + return this.linkedPlansTableData; + } + + public Collection<TypeWithShortName> getPlanTypes() { + return PlanTypesManager.INSTANCE.getTypes(); + } + + public Collection<TypeWithShortName> getPlanLanguages() { + return PlanLanguagesManager.INSTANCE.getTypes(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionResource.java new file mode 100644 index 0000000..9ce11f9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionResource.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.selfserviceportal; + +import java.io.IOException; +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.model.selfservice.ApplicationOption; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.ids.elements.SelfServiceMetaDataId; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OptionResource extends EntityWithIdResource<ApplicationOption> { + + private static final Logger logger = LoggerFactory.getLogger(OptionResource.class); + + static final String ICON_JPG = "icon.jpg"; + static final String PLAN_INPUT_XML = "plan.input.xml"; + private SelfServiceMetaDataId ssmdId; + + + public OptionResource(IIdDetermination<ApplicationOption> idDetermination, ApplicationOption o, int idx, List<ApplicationOption> list, SelfServicePortalResource res) { + super(idDetermination, o, idx, list, res); + this.ssmdId = ((SelfServicePortalResource) this.res).getId(); + } + + private String getFileNamePrefix() { + return OptionResource.getFileNamePrefix(this.o.getId()); + } + + public static String getFileNamePrefix(String id) { + return "option_" + id + "_"; + } + + @Path(OptionResource.ICON_JPG) + @GET + public Response getIcon(@HeaderParam("If-Modified-Since") String modified) { + RepositoryFileReference ref = new RepositoryFileReference(this.ssmdId, this.getFileNamePrefix() + OptionResource.ICON_JPG); + return BackendUtils.returnRepoPath(ref, modified); + } + + @Path("planinputmessage") + @GET + public Response getPlanInputMessage(@HeaderParam("If-Modified-Since") String modified) { + RepositoryFileReference ref = new RepositoryFileReference(this.ssmdId, this.getFileNamePrefix() + OptionResource.PLAN_INPUT_XML); + return BackendUtils.returnRepoPath(ref, modified); + } + + @Override + public Response onDelete() { + // delete icon and plan model reference ... + + // delete icon + // we use the URL stored in the data instead of the generated URL to be compatible with manually edits + RepositoryFileReference ref = new RepositoryFileReference(this.ssmdId, this.o.getIconUrl()); + try { + Repository.INSTANCE.forceDelete(ref); + } catch (IOException e) { + OptionResource.logger.error("Could not remove file", e); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + + // delete plan input + // we use the URL stored in the data instead of the generated URL to be compatible with manually edits + ref = new RepositoryFileReference(this.ssmdId, this.o.getPlanInputMessageUrl()); + try { + Repository.INSTANCE.forceDelete(ref); + } catch (IOException e) { + OptionResource.logger.error("Could not remove file", e); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + + // after deleting files, continue with list deletion + return super.onDelete(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionsResource.java new file mode 100644 index 0000000..86fa102 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionsResource.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.selfserviceportal; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +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.model.selfservice.ApplicationOption; +import org.eclipse.winery.common.RepositoryFileReference; +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.datatypes.ids.elements.SelfServiceMetaDataId; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.restdoc.annotations.RestDoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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; + +public class OptionsResource extends EntityWithIdCollectionResource<OptionResource, ApplicationOption> { + + private static final Logger logger = LoggerFactory.getLogger(OptionsResource.class); + + + public OptionsResource(List<ApplicationOption> list, SelfServicePortalResource res) { + super(OptionResource.class, ApplicationOption.class, list, res); + } + + @Override + public String getId(ApplicationOption entity) { + return entity.getId(); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not yet implemented."); + } + + @POST + @RestDoc(methodDescription = "Adds a new option<p>TODO: @return JSON with .tableData: Array with row data for dataTable</p>") + @Consumes(MediaType.MULTIPART_FORM_DATA) + // @formatter:off + public Response onPost( + @FormDataParam("name") String name, + @FormDataParam("description") String description, + @FormDataParam("planServiceName") String planServiceName, + @FormDataParam("planInputMessage") String planInputMessage, + @FormDataParam("file") 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(description)) { + return Response.status(Status.BAD_REQUEST).entity("description must be given").build(); + } + if (StringUtils.isEmpty(planServiceName)) { + return Response.status(Status.BAD_REQUEST).entity("planServiceName must be given").build(); + } + if (StringUtils.isEmpty(planInputMessage)) { + return Response.status(Status.BAD_REQUEST).entity("planInputMessage must be given").build(); + } + if (uploadedInputStream == null) { + return Response.status(Status.BAD_REQUEST).entity("file has to be provided").build(); + } + ApplicationOption option = new ApplicationOption(); + + String id = Utils.createXMLidAsString(name); + + String fileNamePrefix = OptionResource.getFileNamePrefix(id); + String iconFileName = fileNamePrefix + OptionResource.ICON_JPG; + String planInputMessageFileName = fileNamePrefix + OptionResource.PLAN_INPUT_XML; + + // create option data + option.setId(id); + option.setName(name); + option.setDescription(description); + option.setIconUrl(iconFileName); + option.setPlanInputMessageUrl(planInputMessageFileName); + option.setPlanServiceName(planServiceName); + + // BEGIN: store icon and planInputMessage + + SelfServiceMetaDataId ssmdId = ((SelfServicePortalResource) this.res).getId(); + + RepositoryFileReference iconRef = new RepositoryFileReference(ssmdId, iconFileName); + try { + Repository.INSTANCE.putContentToFile(iconRef, uploadedInputStream, body.getMediaType()); + } catch (IOException e) { + OptionsResource.logger.error(e.getMessage(), e); + return Response.serverError().entity(e.getMessage()).build(); + } + + RepositoryFileReference planInputMessageRef = new RepositoryFileReference(ssmdId, planInputMessageFileName); + try { + Repository.INSTANCE.putContentToFile(planInputMessageRef, planInputMessage, MediaType.TEXT_XML_TYPE); + } catch (IOException e) { + OptionsResource.logger.error(e.getMessage(), e); + return Response.serverError().entity(e.getMessage()).build(); + } + + // END: store icon and planInputMessage + + this.list.add(option); + Response response = BackendUtils.persist(this.res); + return response; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/SelfServicePortalResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/SelfServicePortalResource.java new file mode 100644 index 0000000..98e1dcf --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/SelfServicePortalResource.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.selfserviceportal; + +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.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import org.apache.commons.io.IOUtils; +import org.apache.taglibs.standard.functions.Functions; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.model.selfservice.Application; +import org.eclipse.winery.model.selfservice.Application.Options; +import org.eclipse.winery.model.tosca.TDocumentation; +import org.eclipse.winery.repository.JAXBSupport; +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.datatypes.ids.elements.SelfServiceMetaDataId; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + +public class SelfServicePortalResource implements IPersistable { + + private static final Logger logger = LoggerFactory.getLogger(SelfServicePortalResource.class); + + private final ServiceTemplateResource serviceTemplateResource; + + public final RepositoryFileReference data_xml_ref; + public final RepositoryFileReference icon_jpg_ref; + public final RepositoryFileReference image_jpg_ref; + + private final Application application; + + private final SelfServiceMetaDataId id; + + + public SelfServicePortalResource(ServiceTemplateId serviceTemplateId) { + this(null, serviceTemplateId); + } + + public SelfServicePortalResource(ServiceTemplateResource serviceTemplateResource) { + this(serviceTemplateResource, (ServiceTemplateId) serviceTemplateResource.getId()); + } + + SelfServiceMetaDataId getId() { + return this.id; + } + + /** + * @param serviceTemplateResource may be null + * @param serviceTemplateId the id, must not be null + */ + private SelfServicePortalResource(ServiceTemplateResource serviceTemplateResource, ServiceTemplateId serviceTemplateId) { + this.serviceTemplateResource = serviceTemplateResource; + this.id = new SelfServiceMetaDataId(serviceTemplateId); + this.data_xml_ref = new RepositoryFileReference(this.id, "data.xml"); + this.icon_jpg_ref = new RepositoryFileReference(this.id, "icon.jpg"); + this.image_jpg_ref = new RepositoryFileReference(this.id, "image.jpg"); + this.application = this.getData(); + } + + private Application getData() { + if (Repository.INSTANCE.exists(this.data_xml_ref)) { + Unmarshaller u = JAXBSupport.createUnmarshaller(); + try (InputStream is = Repository.INSTANCE.newInputStream(this.data_xml_ref);) { + return (Application) u.unmarshal(is); + } catch (IOException | JAXBException e) { + SelfServicePortalResource.logger.error("Could not read from " + this.data_xml_ref, e); + return new Application(); + } + } else { + return this.getDefaultApplicationData(); + } + } + + private Application getDefaultApplicationData() { + Application app = new Application(); + app.setIconUrl("icon.jpg"); + app.setImageUrl("image.jpg"); + if (this.serviceTemplateResource != null) { + app.setDisplayName(this.serviceTemplateResource.getName()); + List<TDocumentation> documentation = this.serviceTemplateResource.getServiceTemplate().getDocumentation(); + if ((documentation != null) && (!documentation.isEmpty())) { + TDocumentation doc = documentation.get(0); + List<Object> content = doc.getContent(); + if ((content != null) && (!content.isEmpty())) { + app.setDescription(content.get(0).toString()); + } + } + } + return app; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/servicetemplates/selfservicemetadata/selfservicemetadata.jsp", this); + } + + @Override + public void persist() throws IOException { + BackendUtils.persist(this.application, this.data_xml_ref, MediaType.TEXT_XML_TYPE); + } + + @PUT + @Consumes(MediaType.TEXT_XML) + public Response onPutXML(Application data) { + String content = Utils.getXMLAsString(data); + return BackendUtils.putContentToFile(this.data_xml_ref, content, MediaType.TEXT_XML_TYPE); + } + + @Path("icon.jpg") + @GET + public Response getIcon(@HeaderParam("If-Modified-Since") String modified) { + RepositoryFileReference ref = new RepositoryFileReference(this.id, "icon.jpg"); + return BackendUtils.returnRepoPath(ref, modified); + } + + @Path("icon.jpg") + @PUT + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response putIcon(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataBodyPart body) { + RepositoryFileReference ref = new RepositoryFileReference(this.id, "icon.jpg"); + return BackendUtils.putContentToFile(ref, uploadedInputStream, body.getMediaType()); + } + + @Path("image.jpg") + @GET + public Response getImage(@HeaderParam("If-Modified-Since") String modified) { + RepositoryFileReference ref = new RepositoryFileReference(this.id, "image.jpg"); + return BackendUtils.returnRepoPath(ref, modified); + } + + @Path("image.jpg") + @PUT + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response putImage(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataBodyPart body) { + RepositoryFileReference ref = new RepositoryFileReference(this.id, "image.jpg"); + return BackendUtils.putContentToFile(ref, uploadedInputStream, body.getMediaType()); + } + + @Path("displayname") + @PUT + public Response onPutOnDisplayName(@FormParam("value") String value) { + this.application.setDisplayName(value); + return BackendUtils.persist(this); + } + + @Path("description") + @PUT + public Response onPutOnDescription(@FormParam("value") String value) { + this.application.setDescription(value); + return BackendUtils.persist(this); + } + + @Path("options/") + public OptionsResource getOptionsResource() { + Options options = this.application.getOptions(); + if (options == null) { + options = new Options(); + this.application.setOptions(options); + } + return new OptionsResource(options.getOption(), this); + } + + /** + * @return the internal application object. Used for the export. + */ + public Application getApplication() { + return this.application; + } + + /** + * Used in JSP only + */ + public String getApplicationAsXMLStringEncoded() { + String res; + if (Repository.INSTANCE.exists(this.data_xml_ref)) { + StringWriter sw = new StringWriter(); + try (InputStream is = Repository.INSTANCE.newInputStream(this.data_xml_ref);) { + IOUtils.copy(is, sw); + } catch (IOException e) { + SelfServicePortalResource.logger.error("Could not read from file", e); + } + res = sw.toString(); + } else { + // return skeleton for application + // application object is already filled with default values if no file exists in repo + res = Utils.getXMLAsString(this.getApplication()); + } + return Functions.escapeXml(res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplateResource.java new file mode 100644 index 0000000..2a59aa5 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplateResource.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 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.topologytemplates; + +import java.util.List; +import java.util.Map; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HEAD; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.constants.Namespaces; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResource; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources.artifacts.DeploymentArtifactsResource; +import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplateResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.restdoc.annotations.RestDoc; + +public class NodeTemplateResource extends TEntityTemplateResource<TNodeTemplate> implements INodeTemplateResourceOrNodeTypeImplementationResource { + + public NodeTemplateResource(IIdDetermination<TNodeTemplate> idDetermination, TNodeTemplate o, int idx, List<TNodeTemplate> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + @Path("deploymentartifacts/") + public DeploymentArtifactsResource getDeploymentArtifacts() { + return new DeploymentArtifactsResource(this.o, this); + } + + @GET + @RestDoc(methodDescription = "* The following methods are currently *not* used by the topology modeler.<br />" + "The modeler is using the repository client to interact with the repository") + @Path("minInstances") + public String getMinInstances() { + return Integer.toString(this.o.getMinInstances()); + } + + @PUT + @Path("minInstances") + public Response setMinInstances(@FormParam(value = "minInstances") String minInstances) { + int min = Integer.parseInt(minInstances); + this.o.setMinInstances(min); + return BackendUtils.persist(this.res); + } + + @GET + @Path("maxInstances") + public String getMaxInstances() { + return this.o.getMaxInstances(); + } + + @PUT + @Path("maxInstances") + public Response setMaxInstances(@FormParam(value = "maxInstances") String maxInstances) { + // TODO: check for valid integer | "unbound" + this.o.setMaxInstances(maxInstances); + return BackendUtils.persist(this.res); + } + + + /* * * + * The visual appearance + * + * We do not use a subresource "visualappearance" here to avoid generation of more objects + * * */ + + private final QName qnameX = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "x"); + private final QName qnameY = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "y"); + + + @Path("x") + @GET + @RestDoc(methodDescription = "@return the x coordinate of the node template") + public String getX() { + Map<QName, String> otherAttributes = this.o.getOtherAttributes(); + return otherAttributes.get(this.qnameX); + } + + @Path("x") + @PUT + public Response setX(String x) { + this.o.getOtherAttributes().put(this.qnameX, x); + return BackendUtils.persist(this.res); + } + + @Path("y") + @GET + @RestDoc(methodDescription = "@return the y coordinate of the node template") + public String getY() { + Map<QName, String> otherAttributes = this.o.getOtherAttributes(); + return otherAttributes.get(this.qnameY); + } + + @Path("y") + @PUT + public Response setY(String y) { + this.o.getOtherAttributes().put(this.qnameY, y); + return BackendUtils.persist(this.res); + } + + @Override + public Namespace getNamespace() { + // TODO Auto-generated method stub + throw new IllegalStateException("Not yet implemented."); + } + + /** + * Required for persistence after a change of the deployment artifact. + * Required by DeploymentArtifactResource to be able to persist + * + * @return the service template this node template belongs to + */ + public ServiceTemplateResource getServiceTemplateResource() { + return (ServiceTemplateResource) this.res; + } + + /** + * required for topology modeler to check for existence of a node template + * at the server + * + * @return empty response + */ + @HEAD + public Response getHEAD() { + return Response.noContent().build(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplatesResource.java new file mode 100644 index 0000000..64c5de8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplatesResource.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 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.topologytemplates; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplatesResource; + +import com.sun.jersey.api.view.Viewable; + +public class NodeTemplatesResource extends TEntityTemplatesResource<NodeTemplateResource, TNodeTemplate> { + + public NodeTemplatesResource(List<TNodeTemplate> list, IPersistable res) { + super(NodeTemplateResource.class, TNodeTemplate.class, list, res); + } + + @Override + public String getId(TNodeTemplate entity) { + return entity.getId(); + } + + @Override + public Viewable getHTML() { + // TODO Auto-generated method stub + throw new IllegalStateException("Not yet implemented."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplateResource.java new file mode 100644 index 0000000..a3eaed5 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplateResource.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 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.topologytemplates; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplateResource; + +public class RelationshipTemplateResource extends TEntityTemplateResource<TRelationshipTemplate> { + + public RelationshipTemplateResource(IIdDetermination<TRelationshipTemplate> idDetermination, TRelationshipTemplate o, int idx, List<TRelationshipTemplate> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplatesResource.java new file mode 100644 index 0000000..8073e83 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplatesResource.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 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.topologytemplates; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplatesResource; + +import com.sun.jersey.api.view.Viewable; + +public class RelationshipTemplatesResource extends TEntityTemplatesResource<RelationshipTemplateResource, TRelationshipTemplate> { + + public RelationshipTemplatesResource(List<TRelationshipTemplate> list, IPersistable res) { + super(RelationshipTemplateResource.class, TRelationshipTemplate.class, list, res); + } + + @Override + public String getId(TRelationshipTemplate entity) { + return entity.getId(); + } + + @Override + public Viewable getHTML() { + // TODO Auto-generated method stub + throw new IllegalStateException("Not yet implemented."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/TopologyTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/TopologyTemplateResource.java new file mode 100644 index 0000000..b4b3646 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/TopologyTemplateResource.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * 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.topologytemplates; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.repository.Prefs; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.client.IWineryRepositoryClient; +import org.eclipse.winery.repository.client.WineryRepositoryClientFactory; +import org.eclipse.winery.repository.json.TopologyTemplateModule; +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.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.WebResource.Builder; +import com.sun.jersey.api.view.Viewable; + +public class TopologyTemplateResource { + + private static final Logger logger = LoggerFactory.getLogger(TopologyTemplateResource.class); + + private final TTopologyTemplate topologyTemplate; + + private final ServiceTemplateResource serviceTemplateRes; + + + /** + * A topology template is always nested in a service template + */ + public TopologyTemplateResource(ServiceTemplateResource parent) { + this.topologyTemplate = parent.getServiceTemplate().getTopologyTemplate(); + this.serviceTemplateRes = parent; + } + + + public static class DataForJSP { + + private String location; + private TTopologyTemplate topologyTemplate; + private URI repositoryURI; + private String additonalCSS; + private Boolean autoLayoutOnLoad; + private String additionalScript; + + + public DataForJSP(String location, URI repositoryURI, TTopologyTemplate topologyTemplate, String additonalCSS, String additionalScript, Boolean autoLayoutOnLoad) { + this.location = location; + this.repositoryURI = repositoryURI; + this.topologyTemplate = topologyTemplate; + this.additonalCSS = additonalCSS; + this.additionalScript = additionalScript; + this.autoLayoutOnLoad = autoLayoutOnLoad; + } + + public String getLocation() { + return this.location; + } + + public TTopologyTemplate getTopologyTemplate() { + return this.topologyTemplate; + } + + public String getAdditonalCSS() { + return this.additonalCSS; + } + + public String getAdditionalScript() { + return this.additionalScript; + } + + public Boolean getAutoLayoutOnLoad() { + return this.autoLayoutOnLoad; + } + + public IWineryRepositoryClient getClient() { + // Quick hack + // IWineryRepository is not implemented by Prefs.INSTANCE.getRepository() + // Therefore, we have to generate a real WineryRepositoryClient even if that causes more http load + IWineryRepositoryClient client = WineryRepositoryClientFactory.getWineryRepositoryClient(); + client.addRepository(this.repositoryURI.toString()); + return client; + } + + } + + + @GET + @RestDoc(methodDescription = "?edit is used in the URL to get the jsPlumb-based editor") + @Produces(MediaType.TEXT_HTML) + // @formatter:off + public Response getHTML( + @QueryParam(value = "edit") String edit, + @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, + @QueryParam(value = "view") String view, + @QueryParam(value = "autoLayoutOnLoad") String autoLayoutOnLoad, + @Context UriInfo uriInfo) { + // @formatter:on + Response res; + String JSPName; + String location = Prefs.INSTANCE.getWineryTopologyModelerPath(); + location = uriInfo.getBaseUri().resolve(location).toString(); + // at the topology modeler, jersey needs to have an absolute path + URI repositoryURI = uriInfo.getBaseUri(); + location = location + "/?repositoryURL="; + location = location + Util.URLencode(repositoryURI.toString()); + ServiceTemplateId serviceTemplate = (ServiceTemplateId) this.serviceTemplateRes.getId(); + location = location + "&ns="; + location = location + serviceTemplate.getNamespace().getEncoded(); + location = location + "&id="; + location = location + serviceTemplate.getXmlId().getEncoded(); + if (edit == null) { + String additionalCSS = null; + Boolean autoLayoutOnLoadBoolean = false; + if (view == null) { + // integration in Winery + // currently not maintained: Winery includes ?view as iframe + JSPName = "/jsp/servicetemplates/topologytemplates/topologytemplate.jsp"; + } else { + // view only mode + // fullscreen: additionalCSS and script possible + if (!"".equals(view)) { + // view with additional CSS + URI cssURI = URI.create(view); + if (cssURI.isAbsolute()) { + additionalCSS = view; + } else { + // relative URLs starts at "/css/topologyrendering/" + additionalCSS = uriInfo.getBaseUri().resolve("css/topologytemplaterendering/").resolve(view).toString(); + if (!additionalCSS.endsWith(".css")) { + additionalCSS += ".css"; + } + } + } + if (autoLayoutOnLoad != null) { + autoLayoutOnLoadBoolean = true; + } + JSPName = "/jsp/servicetemplates/topologytemplates/topologytemplateview.jsp"; + } + Viewable viewable = new Viewable(JSPName, new DataForJSP(location, repositoryURI, this.topologyTemplate, additionalCSS, script, autoLayoutOnLoadBoolean)); + res = Response.ok().header(HttpHeaders.VARY, HttpHeaders.ACCEPT).entity(viewable).build(); + } else { + // edit mode + URI uri = Utils.createURI(location); + res = Response.seeOther(uri).build(); + } + return res; + } + + /** + * + * @param uriInfo the URI ending with "topologytemplate/" of a service + * template + */ + @GET + @Produces(MediaType.TEXT_PLAIN) + public Response triggerGenerateBuildPlan(@Context UriInfo uriInfo) { + String plansURI = uriInfo.getAbsolutePath().resolve("../plans/").toString(); + String csarURI = uriInfo.getAbsolutePath().resolve("../?csar").toString(); + + String request = "<generatePlanForTopology><CSARURL>"; + request += csarURI; + request += "</CSARURL><PLANPOSTURL>"; + request += plansURI; + request += "</PLANPOSTURL></generatePlanForTopology>"; + + Client client = Client.create(); + Builder wr = client.resource("http://localhost:1339/planbuilder/sync").type(MediaType.APPLICATION_XML); + + try { + wr.post(String.class, request); + } catch (com.sun.jersey.api.client.UniformInterfaceException e) { + return Response.serverError().entity(e.getMessage()).build(); + } + + return Response.ok().build(); + } + + // @formatter:off + @GET + @RestDoc(methodDescription="Returns a JSON representation of the topology template. <br />" + + "X and Y coordinates are embedded as attributes. QName string with Namespace: <br />" + + "{@link org.eclipse.winery.repository.common.constants.Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE} <br />" + + "@return The JSON representation of the topology template <em>without</em> associated artifacts and without the parent service template") + @Produces(MediaType.APPLICATION_JSON) + // @formatter:on + public Response getComponentInstanceJSON() { + Response res; + ObjectMapper mapper = new ObjectMapper(); + mapper.enable(SerializationFeature.INDENT_OUTPUT); + mapper.registerModule(new TopologyTemplateModule()); + try { + // convert it to json + String json = mapper.writeValueAsString(this.topologyTemplate); + res = Response.ok(json).build(); + } catch (Exception e) { + TopologyTemplateResource.logger.error(e.getMessage(), e); + res = Response.serverError().entity(e.getMessage()).build(); + } + return res; + } + + @Path("nodetemplates/") + public NodeTemplatesResource getNodeTemplatesResource() { + // 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 + List<TNodeTemplate> l = BackendUtils.getAllNestedNodeTemplates(this.serviceTemplateRes.getServiceTemplate()); + return new NodeTemplatesResource(l, this.serviceTemplateRes); + } + + @Path("relationshiptemplates/") + public RelationshipTemplatesResource getRelationshipTemplatesResource() { + // FIXME: onDelete will not work. See getNodeTemplatesResource + List<TRelationshipTemplate> l = new ArrayList<TRelationshipTemplate>(); + for (TEntityTemplate t : this.topologyTemplate.getNodeTemplateOrRelationshipTemplate()) { + if (t instanceof TRelationshipTemplate) { + l.add((TRelationshipTemplate) t); + } + } + return new RelationshipTemplatesResource(l, this.serviceTemplateRes); + } + + @PUT + @RestDoc(methodDescription = "Replaces the topology by the information given in the XML") + @Consumes(MediaType.TEXT_XML) + public Response setModel(TTopologyTemplate topologyTemplate) { + this.serviceTemplateRes.getServiceTemplate().setTopologyTemplate(topologyTemplate); + return BackendUtils.persist(this.serviceTemplateRes); + } + + // @formatter:off + @GET + @RestDoc(methodDescription="<p>Returns an XML representation of the topology template." + + " X and Y coordinates are embedded as attributes. Namespace:" + + "{@link org.eclipse.winery.repository.common.constants.Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE} </p>" + + "<p>{@link org.eclipse.winery.repository.client.WineryRepositoryClient." + + "getTopologyTemplate(QName)} consumes this template</p>" + + "<p>@return The XML representation of the topology template <em>without</em>" + + "associated artifacts and without the parent service template </p>") + @Produces(MediaType.TEXT_XML) + // @formatter:on + public Response getComponentInstanceXML() { + return Utils.getXML(TTopologyTemplate.class, this.topologyTemplate); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/tags/TagsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/tags/TagsResource.java new file mode 100644 index 0000000..21596e6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/tags/TagsResource.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 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.tags; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class TagsResource { + + private static final Logger logger = LoggerFactory.getLogger(TagsResource.class); + + + public TagsResource(TOSCAComponentId parentId) { + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/tags/tags.jsp", this); + } + +} |