From f2fbee343a11ce913a002bed057e9453a2da9885 Mon Sep 17 00:00:00 2001 From: Vladimir Yussupov Date: Thu, 19 Jul 2018 14:59:01 +0200 Subject: [PATCH 1/5] Add initial implementation Signed-off-by: Vladimir Yussupov --- .../model/tosca/TBoundaryDefinitions.java | 154 +++++++++++++++++- .../winery/model/tosca/TServiceTemplate.java | 82 ++++++++++ .../PropertiesDefinitionResourceApiData.java | 19 +++ .../ServiceTemplateResource.java | 7 + .../BoundaryDefinitionsJSPData.java | 64 ++++++-- .../BoundaryDefinitionsResource.java | 20 ++- ...ndaryDefsPropertiesDefinitionResource.java | 137 ++++++++++++++++ .../src/app/instance/instance.service.ts | 2 +- .../boundaryDefinitions.module.ts | 3 +- .../properties/properties.service.ts | 4 + .../serviceTemplate.module.ts | 4 +- .../serviceTemplateRouter.module.ts | 2 + 12 files changed, 475 insertions(+), 23 deletions(-) create mode 100644 org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/propertiesdefinition/BoundaryDefsPropertiesDefinitionResource.java diff --git a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TBoundaryDefinitions.java b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TBoundaryDefinitions.java index 1335542f3f..5a4eaeee0d 100644 --- a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TBoundaryDefinitions.java +++ b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TBoundaryDefinitions.java @@ -15,7 +15,9 @@ package org.eclipse.winery.model.tosca; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import javax.xml.bind.annotation.XmlAccessType; @@ -23,9 +25,21 @@ import javax.xml.bind.annotation.XmlAnyElement; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlType; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.eclipse.winery.model.tosca.constants.Namespaces; + +import io.github.adr.embedded.ADR; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "tBoundaryDefinitions", propOrder = { @@ -197,13 +211,151 @@ public static class Properties { @Nullable public Object getAny() { - return any; + if (this.getKVProperties() == null) { + return any; + } else { + return null; + } } public void setAny(@Nullable Object value) { this.any = value; } + /** + * This is a special method for Winery. Winery allows to define a property by specifying name/value values. + * Instead of parsing the XML contained in TNodeType, this method is a convenience method to access this + * information assumes the properties are key/value pairs (see WinerysPropertiesDefinition), all other cases are + * return null. + *

+ * Returns a map of key/values of this template based on the information of WinerysPropertiesDefinition. In case + * no value is set, the empty string is used. The map is implemented as {@link LinkedHashMap} to ensure that the + * order of the elements is the same as in the XML. We return the type {@link LinkedHashMap}, because there is + * no appropriate Java interface for "sorted" Maps + *

+ * In case the element is not of the form k/v, null is returned + *

+ * This method assumes that the any field is always populated. + * + * @return null if not k/v, a map of k/v properties otherwise + */ + @ADR(12) + public LinkedHashMap getKVProperties() { + // we use the internal variable "any", because getAny() returns null, if we have KVProperties + if (any == null || !(any instanceof Element)) { + return null; + } + + Element el = (Element) any; + if (el == null) { + return null; + } + + // we have no type information in this place + // we could inject a repository, but if Winery is used with multiple repositories, this could cause race conditions + // therefore, we guess at the instance of the properties definition (i.e., here) if it is key/value or not. + + boolean isKv = true; + + LinkedHashMap properties = new LinkedHashMap<>(); + + NodeList childNodes = el.getChildNodes(); + + if (childNodes.getLength() == 0) { + // somehow invalid XML - do not treat it as k/v + return null; + } + + for (int i = 0; i < childNodes.getLength(); i++) { + Node item = childNodes.item(i); + if (item instanceof Element) { + String key = item.getLocalName(); + String value; + + Element kvElement = (Element) item; + NodeList kvElementChildNodes = kvElement.getChildNodes(); + if (kvElementChildNodes.getLength() == 0) { + value = ""; + } else if (kvElementChildNodes.getLength() > 1) { + // This is a wrong guess if comments are used, but this is prototype + isKv = false; + break; + } else { + // one child - just get the text. + value = item.getTextContent(); + } + properties.put(key, value); + } else if (item instanceof Text || item instanceof Comment) { + // these kinds of nodes are OK + } + } + + if (isKv) { + return properties; + } else { + return null; + } + } + + @ADR(12) + public void setKVProperties(Map properties) { + Objects.requireNonNull(properties); + Element el = (Element) any; + + if (el == null) { + // special case if JSON is parsed without updating an existing element + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db; + try { + db = dbf.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + throw new IllegalStateException("Could not instantiate document builder", e); + } + Document doc = db.newDocument(); + + // We cannot access the wrapper definitions, because we don't have access to the type + // Element root = doc.createElementNS(wpd.getNamespace(), wpd.getElementName()); + // Therefore, we create a dummy wrapper element: + + Element root = doc.createElementNS(Namespaces.EXAMPLE_NAMESPACE_URI, "Properties"); + doc.appendChild(root); + + // No wpd - so this is not possible: + // we produce the serialization in the same order the XSD would be generated (because of the usage of xsd:sequence) + // for (PropertyDefinitionKV prop : wpd.getPropertyDefinitionKVList()) { + + for (String key : properties.keySet()) { + // wpd.getNamespace() + Element element = doc.createElementNS(Namespaces.EXAMPLE_NAMESPACE_URI, key); + root.appendChild(element); + String value = properties.get(key); + if (value != null) { + Text text = doc.createTextNode(value); + element.appendChild(text); + } + } + + this.setAny(doc.getDocumentElement()); + } else { + // straight-forward copy over to existing property structure + NodeList childNodes = el.getChildNodes(); + + for (int i = 0; i < childNodes.getLength(); i++) { + Node item = childNodes.item(i); + if (item instanceof Element) { + final Element element = (Element) item; + final String key = element.getLocalName(); + final String value = properties.get(key); + if (value != null) { + element.setTextContent(value); + } + } else if (item instanceof Text || item instanceof Comment) { + // these kinds of nodes are OK + } + } + } + } + public TBoundaryDefinitions.Properties.@Nullable PropertyMappings getPropertyMappings() { return propertyMappings; } diff --git a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TServiceTemplate.java b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TServiceTemplate.java index 4b6942ead0..8d68dd0f36 100644 --- a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TServiceTemplate.java +++ b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TServiceTemplate.java @@ -21,20 +21,34 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElements; import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.XmlType; import javax.xml.namespace.QName; +import org.eclipse.winery.model.tosca.constants.Namespaces; +import org.eclipse.winery.model.tosca.kvproperties.WinerysPropertiesDefinition; + +import com.fasterxml.jackson.annotation.JsonIgnore; import org.eclipse.jdt.annotation.Nullable; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "tServiceTemplate", propOrder = { + "propertiesDefinition", "tags", "boundaryDefinitions", "topologyTemplate", "plans" }) public class TServiceTemplate extends HasId implements HasName, HasTargetNamespace { + public static final String NS_SUFFIX_PROPERTIESDEFINITION_WINERY = "propertiesdefinition/winery"; + + @XmlElements( { + @XmlElement(name = "PropertiesDefinition", namespace = Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, type = TServiceTemplate.PropertiesDefinition.class), + @XmlElement(name = "PropertiesDefinition", namespace = Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, type = WinerysPropertiesDefinition.class) + }) + protected Object propertiesDefinition; @XmlElement(name = "Tags") protected TTags tags; @@ -158,6 +172,74 @@ public void setSubstitutableNodeType(QName value) { this.substitutableNodeType = value; } + public Object getPropertiesDefinition() { + return propertiesDefinition; + } + + public void setPropertiesDefinition(Object value) { + this.propertiesDefinition = value; + } + + /** + *

Java class for anonymous complex type. + *

+ *

The following schema fragment specifies the expected content contained within this class. + *

+ *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <attribute name="element" type="{http://www.w3.org/2001/XMLSchema}QName" />
+     *       <attribute name="type" type="{http://www.w3.org/2001/XMLSchema}QName" />
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "") + public static class PropertiesDefinition extends TEntityType.PropertiesDefinition { + } + + /** + * This is a special method for Winery. Winery allows to define a property definition by specifying name/type + * values. Instead of parsing the extensible elements returned TDefinitions, this method is a convenience method to + * access this information + * + * @return a WinerysPropertiesDefinition object, which includes a map of name/type-pairs denoting the associated + * property definitions. A default element name and namespace is added if it is not defined in the underlying XML. + * null if no Winery specific KV properties are defined for the given entity type + */ + @XmlTransient + @JsonIgnore + public WinerysPropertiesDefinition getWinerysPropertiesDefinition() { + // similar implementation as org.eclipse.winery.repository.resources.entitytypes.properties.PropertiesDefinitionResource.getListFromEntityType(TEntityType) + WinerysPropertiesDefinition res = null; + if (this.getPropertiesDefinition() instanceof WinerysPropertiesDefinition) { + res = (WinerysPropertiesDefinition) this.getPropertiesDefinition(); + } + + if (res != null) { + // we put defaults if elementname and namespace have not been set + + if (res.getElementName() == null) { + res.setElementName("Properties"); + } + + if (res.getNamespace() == null) { + // we use the targetnamespace of the original element + String ns = this.getTargetNamespace(); + if (!ns.endsWith("/")) { + ns += "/"; + } + ns += NS_SUFFIX_PROPERTIESDEFINITION_WINERY; + res.setNamespace(ns); + } + } + + return res; + } + public static class Builder extends HasId.Builder { private final TTopologyTemplate topologyTemplate; diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/apiData/PropertiesDefinitionResourceApiData.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/apiData/PropertiesDefinitionResourceApiData.java index 1243fc4810..3da8d9e675 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/apiData/PropertiesDefinitionResourceApiData.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/apiData/PropertiesDefinitionResourceApiData.java @@ -43,4 +43,23 @@ public PropertiesDefinitionResourceApiData( this.selectedValue = PropertiesDefinitionEnum.None; } } + + public PropertiesDefinitionResourceApiData(Object propertiesDefinition) { + if (propertiesDefinition instanceof TEntityType.PropertiesDefinition) { + this.propertiesDefinition = (TEntityType.PropertiesDefinition) propertiesDefinition; + } + if (propertiesDefinition instanceof WinerysPropertiesDefinition) { + this.winerysPropertiesDefinition = (WinerysPropertiesDefinition) propertiesDefinition; + } + + if ((winerysPropertiesDefinition != null) && (winerysPropertiesDefinition.getIsDerivedFromXSD() == null)) { + this.selectedValue = PropertiesDefinitionEnum.Custom; + } else if ((this.propertiesDefinition != null) && (this.propertiesDefinition.getElement() != null)) { + this.selectedValue = PropertiesDefinitionEnum.Element; + } else if ((this.propertiesDefinition != null) && (this.propertiesDefinition.getType() != null)) { + this.selectedValue = PropertiesDefinitionEnum.Type; + } else { + this.selectedValue = PropertiesDefinitionEnum.None; + } + } } diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/ServiceTemplateResource.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/ServiceTemplateResource.java index b86f675e1f..b92f6d63cd 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/ServiceTemplateResource.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/ServiceTemplateResource.java @@ -52,8 +52,10 @@ import org.eclipse.winery.repository.rest.resources._support.IHasName; import org.eclipse.winery.repository.rest.resources._support.dataadapter.injectionadapter.InjectorReplaceData; import org.eclipse.winery.repository.rest.resources._support.dataadapter.injectionadapter.InjectorReplaceOptions; +import org.eclipse.winery.repository.rest.resources.apiData.PropertiesDefinitionResourceApiData; import org.eclipse.winery.repository.rest.resources.servicetemplates.boundarydefinitions.BoundaryDefinitionsResource; import org.eclipse.winery.repository.rest.resources.servicetemplates.plans.PlansResource; +import org.eclipse.winery.repository.rest.resources.servicetemplates.propertiesdefinition.BoundaryDefsPropertiesDefinitionResource; import org.eclipse.winery.repository.rest.resources.servicetemplates.selfserviceportal.SelfServicePortalResource; import org.eclipse.winery.repository.rest.resources.servicetemplates.topologytemplates.TopologyTemplateResource; import org.eclipse.winery.repository.splitting.Splitting; @@ -119,6 +121,11 @@ public BoundaryDefinitionsResource getBoundaryDefinitionsResource() { return new BoundaryDefinitionsResource(this, boundaryDefinitions); } + @Path("propertiesdefinition/") + public BoundaryDefsPropertiesDefinitionResource getJson() { + return new BoundaryDefsPropertiesDefinitionResource(this); + } + @Override public String getName() { String name = this.getServiceTemplate().getName(); diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java index 0f1f864b8b..bb5b137c96 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java @@ -13,14 +13,22 @@ *******************************************************************************/ package org.eclipse.winery.repository.rest.resources.servicetemplates.boundarydefinitions; -import org.apache.commons.lang3.StringEscapeUtils; -import org.apache.taglibs.standard.functions.Functions; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.SortedSet; + +import javax.xml.namespace.QName; + 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.model.tosca.kvproperties.WinerysPropertiesDefinition; import org.eclipse.winery.model.tosca.utils.ModelUtilities; import org.eclipse.winery.repository.backend.BackendUtils; import org.eclipse.winery.repository.backend.RepositoryFactory; @@ -28,12 +36,7 @@ import org.eclipse.winery.repository.rest.datatypes.select2.Select2DataItem; import org.eclipse.winery.repository.rest.resources.admin.types.ConstraintTypesManager; -import javax.xml.namespace.QName; -import java.net.URI; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.SortedSet; +import org.apache.taglibs.standard.functions.Functions; public class BoundaryDefinitionsJSPData { @@ -51,8 +54,8 @@ public BoundaryDefinitionsJSPData(TServiceTemplate ste, URI baseURI) { this.baseURI = baseURI; } - private String getDefinedProperties() { - Properties p = ModelUtilities.getProperties(this.defs); + private Map getDefinedProperties() { + /*TBoundaryDefinitions.Properties p = ModelUtilities.getProperties(this.defs); Object o = p.getAny(); if (o == null) { // nothing stored -> return empty string @@ -60,10 +63,42 @@ private String getDefinedProperties() { } else { // something stored --> return that return BackendUtils.getXMLAsString(p.getAny()); + }*/ + + WinerysPropertiesDefinition wpd = ste.getWinerysPropertiesDefinition(); + + if (Objects.isNull(wpd)) { + // no Winery special treatment, just return the XML properties + // These can be null resulting in 200 No Content at the caller + /*if (props == null) { + return Response.ok().entity("{}").type(MediaType.APPLICATION_JSON).build(); + } else { + @Nullable final Object any = props.getAny(); + if (any == null) { + LOGGER.debug("XML properties expected, but none found. Returning empty JSON."); + return Response.ok().entity("{}").type(MediaType.APPLICATION_JSON).build(); + } + try { + @ADR(6) + String xmlAsString = BackendUtils.getXMLAsString(TEntityTemplate.Properties.class, props, true); + return Response + .ok() + .entity(xmlAsString) + .type(MediaType.TEXT_XML) + .build(); + } catch (Exception e) { + throw new WebApplicationException(e); + } + }*/ + return null; + } else { + return ste.getBoundaryDefinitions().getProperties().getKVProperties(); + //return Response.ok().entity(kvProperties).type(MediaType.APPLICATION_JSON).build(); } + } - public String getPropertiesAsXMLString() { + public Map getPropertiesAsXMLString() { return this.getDefinedProperties(); } @@ -71,7 +106,7 @@ public String getPropertiesAsXMLString() { * 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() { + /*public String getDefinedPropertiesAsEscapedHTML() { String s = this.getDefinedProperties(); s = StringEscapeUtils.escapeHtml4(s); return s; @@ -81,8 +116,7 @@ public String getDefinedPropertiesAsJSONString() { String s = this.getDefinedProperties(); s = StringEscapeUtils.escapeEcmaScript(s); return s; - } - + }*/ public TBoundaryDefinitions getDefs() { return this.defs; } diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java index 483ebeb7da..7a24a86098 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java @@ -15,6 +15,7 @@ package org.eclipse.winery.repository.rest.resources.servicetemplates.boundarydefinitions; import java.util.List; +import java.util.Map; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -52,7 +53,6 @@ public class BoundaryDefinitionsResource { private final ServiceTemplateResource serviceTemplateResource; private final TBoundaryDefinitions boundaryDefinitions; - public BoundaryDefinitionsResource(ServiceTemplateResource serviceTemplateResource, TBoundaryDefinitions boundaryDefinitions) { this.serviceTemplateResource = serviceTemplateResource; this.boundaryDefinitions = boundaryDefinitions; @@ -81,9 +81,12 @@ public Response setModel(TBoundaryDefinitions boundaryDefinitions) { @Path("properties/") @GET - @Produces(MediaType.APPLICATION_XML) - public String getProperties(@Context UriInfo uriInfo) { - return new BoundaryDefinitionsJSPData(this.serviceTemplateResource.getServiceTemplate(), uriInfo.getBaseUri()).getPropertiesAsXMLString(); + @Produces(MediaType.APPLICATION_JSON) + public Response getProperties(@Context UriInfo uriInfo) { + return Response.ok() + .entity(new BoundaryDefinitionsJSPData(this.serviceTemplateResource.getServiceTemplate(), uriInfo.getBaseUri()).getPropertiesAsXMLString()) + .type(MediaType.APPLICATION_JSON) + .build(); } /** @@ -100,6 +103,15 @@ public Response putProperties(@ApiParam(value = "Stored properties. The XSD allo return RestUtils.persist(this.serviceTemplateResource); } + @Path("properties/") + @PUT + @Consumes( {MediaType.APPLICATION_JSON}) + @ApiOperation(value = "saves properties of boundary definitions", notes = "Models the user-defined properties. The property mappings go into a separate resource propertymappings.") + public Response putCustomProperties(@ApiParam(value = "Stored properties. The XSD allows a single element only. Therefore, we go for the contained element") Map props) { + this.boundaryDefinitions.getProperties().setKVProperties(props); + return RestUtils.persist(this.serviceTemplateResource); + } + @Path("requirements/") public RequirementsResource getRequiremensResource() { Requirements requirements = this.boundaryDefinitions.getRequirements(); diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/propertiesdefinition/BoundaryDefsPropertiesDefinitionResource.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/propertiesdefinition/BoundaryDefsPropertiesDefinitionResource.java new file mode 100644 index 0000000000..30167acddc --- /dev/null +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/propertiesdefinition/BoundaryDefsPropertiesDefinitionResource.java @@ -0,0 +1,137 @@ +/******************************************************************************** + * Copyright (c) 2018 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + *******************************************************************************/ + +package org.eclipse.winery.repository.rest.resources.servicetemplates.propertiesdefinition; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +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.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.eclipse.winery.model.tosca.TBoundaryDefinitions; +import org.eclipse.winery.model.tosca.kvproperties.PropertyDefinitionKV; +import org.eclipse.winery.repository.backend.NamespaceManager; +import org.eclipse.winery.repository.backend.RepositoryFactory; +import org.eclipse.winery.repository.backend.xsd.NamespaceAndDefinedLocalNames; +import org.eclipse.winery.repository.rest.RestUtils; +import org.eclipse.winery.repository.rest.datatypes.NamespaceAndDefinedLocalNamesForAngular; +import org.eclipse.winery.repository.rest.resources.apiData.PropertiesDefinitionEnum; +import org.eclipse.winery.repository.rest.resources.apiData.PropertiesDefinitionResourceApiData; +import org.eclipse.winery.repository.rest.resources.servicetemplates.ServiceTemplateResource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class BoundaryDefsPropertiesDefinitionResource { + private static final Logger LOGGER = LoggerFactory.getLogger(BoundaryDefsPropertiesDefinitionResource.class); + + private final ServiceTemplateResource parentRes; + + public BoundaryDefsPropertiesDefinitionResource(ServiceTemplateResource res) { + this.parentRes = res; + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public PropertiesDefinitionResourceApiData getJson() { + Object definition = parentRes.getServiceTemplate().getPropertiesDefinition(); + return new PropertiesDefinitionResourceApiData(definition); + } + + @GET + @Path("{type}") + @Produces(MediaType.APPLICATION_JSON) + public List getXsdDefinitionJson(@PathParam("type") String type) { + List allDeclaredElementsLocalNames = null; + switch (type) { + case "type": + allDeclaredElementsLocalNames = RepositoryFactory.getRepository().getXsdImportManager().getAllDefinedTypesLocalNames(); + break; + case "element": + allDeclaredElementsLocalNames = RepositoryFactory.getRepository().getXsdImportManager().getAllDeclaredElementsLocalNames(); + break; + } + + if (allDeclaredElementsLocalNames == null) { + LOGGER.error("No such parameter available in this call", type); + throw new WebApplicationException(Response.Status.BAD_REQUEST); + } + + return RestUtils.convert(allDeclaredElementsLocalNames); + } + + @DELETE + public Response clearPropertiesDefinition() { + parentRes.getServiceTemplate().setPropertiesDefinition(null); + return RestUtils.persist(this.parentRes); + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + public Response onJsonPost(PropertiesDefinitionResourceApiData data) { + if (data.selectedValue == PropertiesDefinitionEnum.Element || data.selectedValue == PropertiesDefinitionEnum.Type) { + // TODO + // return RestUtils.persist(this.parentRes); + } else if (data.selectedValue == PropertiesDefinitionEnum.Custom) { + parentRes.getServiceTemplate().setPropertiesDefinition(data.winerysPropertiesDefinition); + String namespace = data.winerysPropertiesDefinition.getNamespace(); + NamespaceManager namespaceManager = RepositoryFactory.getRepository().getNamespaceManager(); + if (!namespaceManager.hasPermanentPrefix(namespace)) { + namespaceManager.addPermanentNamespace(namespace); + } + + // BackendUtils.initializeProperties(repository, (TEntityTemplate) element); + Document document; + try { + document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + } catch (ParserConfigurationException e) { + LOGGER.error("Could not create document", e); + return Response.serverError().build(); + } + + final String ns = data.winerysPropertiesDefinition.getNamespace(); + final Element wrapperElement = document.createElementNS(ns, data.winerysPropertiesDefinition.getElementName()); + document.appendChild(wrapperElement); + + // we produce the serialization in the same order the XSD would be generated (because of the usage of xsd:sequence) + for (PropertyDefinitionKV propertyDefinitionKV : data.winerysPropertiesDefinition.getPropertyDefinitionKVList()) { + // we always write the element tag as the XSD forces that + final Element valueElement = document.createElementNS(ns, propertyDefinitionKV.getKey()); + wrapperElement.appendChild(valueElement); + } + + TBoundaryDefinitions.Properties properties = new TBoundaryDefinitions.Properties(); + properties.setAny(document.getDocumentElement()); + parentRes.getServiceTemplate().setBoundaryDefinitions(new TBoundaryDefinitions()); + parentRes.getServiceTemplate().getBoundaryDefinitions().setProperties(properties); + + return RestUtils.persist(this.parentRes); + } + + return Response.status(Status.BAD_REQUEST).entity("Wrong data submitted!").build(); + } +} diff --git a/org.eclipse.winery.repository.ui/src/app/instance/instance.service.ts b/org.eclipse.winery.repository.ui/src/app/instance/instance.service.ts index b16a2b5a56..47088f4389 100644 --- a/org.eclipse.winery.repository.ui/src/app/instance/instance.service.ts +++ b/org.eclipse.winery.repository.ui/src/app/instance/instance.service.ts @@ -50,7 +50,7 @@ export class InstanceService { break; case ToscaTypes.ServiceTemplate: subMenu = ['README', 'LICENSE', 'Topology Template', 'Plans', 'Selfservice Portal', - 'Boundary Definitions', 'Tags', 'Constraint Checking', 'Documentation', 'XML']; + 'Boundary Definitions', 'Tags', 'Properties Definition', 'Constraint Checking', 'Documentation', 'XML']; break; case ToscaTypes.RelationshipType: subMenu = ['README', 'LICENSE', 'Visual Appearance', 'Instance States', 'Source Interfaces', 'Target Interfaces', diff --git a/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/boundaryDefinitions.module.ts b/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/boundaryDefinitions.module.ts index 34b4afd683..685a446f68 100644 --- a/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/boundaryDefinitions.module.ts +++ b/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/boundaryDefinitions.module.ts @@ -35,9 +35,10 @@ import { InterfacesComponent } from '../../sharedComponents/interfaces/interface import { InterfacesModule } from '../../sharedComponents/interfaces/interfaces.module'; import { WineryQNameSelectorModule } from '../../../wineryQNameSelector/wineryQNameSelector.module'; import { WineryEditorModule } from '../../../wineryEditorModule/wineryEditor.module'; +import { PropertiesComponent } from '../../sharedComponents/properties/properties.component'; export const boundaryDefinitionsRoutes: Routes = [ - { path: 'properties', component: EditXMLComponent }, + { path: 'properties', component: PropertiesComponent}, { path: 'propertymappings', component: PropertyMappingsComponent }, { path: 'propertyconstraints', component: PropertyConstraintsComponent }, { path: 'requirements', component: RequirementsComponent }, diff --git a/org.eclipse.winery.repository.ui/src/app/instance/sharedComponents/properties/properties.service.ts b/org.eclipse.winery.repository.ui/src/app/instance/sharedComponents/properties/properties.service.ts index 7b95914ed8..1f0f13cd72 100644 --- a/org.eclipse.winery.repository.ui/src/app/instance/sharedComponents/properties/properties.service.ts +++ b/org.eclipse.winery.repository.ui/src/app/instance/sharedComponents/properties/properties.service.ts @@ -17,6 +17,7 @@ import { Observable } from 'rxjs'; import { backendBaseURL } from '../../../configuration'; import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; import { map } from 'rxjs/operators'; +import { ToscaTypes } from '../../../model/enums'; @Injectable() export class PropertiesService { @@ -26,6 +27,9 @@ export class PropertiesService { constructor(private http: HttpClient, private sharedData: InstanceService) { this.path = backendBaseURL + this.sharedData.path + '/properties/'; + if (this.sharedData.toscaComponent.toscaType == ToscaTypes.ServiceTemplate ) { + this.path = this.path.replace('/properties/', '/boundarydefinitions/properties/') + } } /** diff --git a/org.eclipse.winery.repository.ui/src/app/wineryMainModules/serviceTemplates/serviceTemplate.module.ts b/org.eclipse.winery.repository.ui/src/app/wineryMainModules/serviceTemplates/serviceTemplate.module.ts index cd845928ca..fd05f4963d 100644 --- a/org.eclipse.winery.repository.ui/src/app/wineryMainModules/serviceTemplates/serviceTemplate.module.ts +++ b/org.eclipse.winery.repository.ui/src/app/wineryMainModules/serviceTemplates/serviceTemplate.module.ts @@ -35,6 +35,7 @@ import { WinerySourceModule } from '../../instance/sharedComponents/artifactSour import { ConstraintCheckingComponent } from '../../instance/serviceTemplates/constraintChecking/constraintChecking.component'; import { WineryEditorModule } from '../../wineryEditorModule/wineryEditor.module'; import { TopologyTemplateModule } from '../../instance/serviceTemplates/topologyTemplate/topologyTemplate.module'; +import { PropertiesDefinitionModule } from '../../instance/sharedComponents/propertiesDefinition/propertiesDefinition.module'; @NgModule({ imports: [ @@ -56,7 +57,8 @@ import { TopologyTemplateModule } from '../../instance/serviceTemplates/topology WineryTableModule, ServiceTemplateRouterModule, WineryReadmeModule, - WineryLicenseModule + WineryLicenseModule, + PropertiesDefinitionModule ], declarations: [ PlansComponent, diff --git a/org.eclipse.winery.repository.ui/src/app/wineryMainModules/serviceTemplates/serviceTemplateRouter.module.ts b/org.eclipse.winery.repository.ui/src/app/wineryMainModules/serviceTemplates/serviceTemplateRouter.module.ts index 5ea37ebdbc..f1ac7df612 100644 --- a/org.eclipse.winery.repository.ui/src/app/wineryMainModules/serviceTemplates/serviceTemplateRouter.module.ts +++ b/org.eclipse.winery.repository.ui/src/app/wineryMainModules/serviceTemplates/serviceTemplateRouter.module.ts @@ -30,6 +30,7 @@ import { ToscaTypes } from '../../model/enums'; import { WineryReadmeComponent } from '../../wineryReadmeModule/wineryReadme.component'; import { WineryLicenseComponent } from '../../wineryLicenseModule/wineryLicense.component'; import { ConstraintCheckingComponent } from '../../instance/serviceTemplates/constraintChecking/constraintChecking.component'; +import { PropertiesDefinitionComponent } from '../../instance/sharedComponents/propertiesDefinition/propertiesDefinition.component'; const toscaType = ToscaTypes.ServiceTemplate; @@ -59,6 +60,7 @@ const serviceTemplateRoutes: Routes = [ // 'app/instance/serviceTemplates/boundaryDefinitions/boundaryDefinitions.module#BoundaryDefinitionsModule' children: boundaryDefinitionsRoutes }, + {path: 'propertiesdefinition', component: PropertiesDefinitionComponent}, {path: 'constraintchecking', component: ConstraintCheckingComponent}, {path: 'tags', component: TagComponent}, {path: 'documentation', component: DocumentationComponent}, From 9d68b3d250e303d29de3ddd6667dc4656576496a Mon Sep 17 00:00:00 2001 From: Vladimir Yussupov Date: Fri, 3 Aug 2018 14:14:04 +0200 Subject: [PATCH 2/5] Improve initial implementation Signed-off-by: Vladimir Yussupov --- .../model/tosca/TBoundaryDefinitions.java | 169 +----------- .../winery/model/tosca/TEntityType.java | 53 +--- .../model/tosca/TExtensibleElements.java | 49 +++- .../winery/model/tosca/TServiceTemplate.java | 75 ++---- .../model/tosca/utils/ModelUtilities.java | 4 +- .../PropertiesDefinitionResourceApiData.java | 19 -- .../entitytemplates/PropertiesResource.java | 26 +- .../PropertiesDefinitionResource.java | 38 ++- .../BoundaryDefinitionsJSPData.java | 47 +--- ...BoundaryDefinitionsPropertiesResource.java | 107 ++++++++ .../BoundaryDefinitionsResource.java | 33 +-- ...ndaryDefsPropertiesDefinitionResource.java | 141 +++++----- .../src/app/instance/instance.service.ts | 4 +- .../propertyMappings.component.html | 29 ++- .../propertyMappings.component.ts | 49 ++-- .../propertyMappings.service.ts | 19 +- .../properties/properties.service.ts | 3 +- .../repository/backend/BackendUtils.java | 243 +++++++++++------- 18 files changed, 536 insertions(+), 572 deletions(-) create mode 100644 org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsPropertiesResource.java diff --git a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TBoundaryDefinitions.java b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TBoundaryDefinitions.java index 17cd0be164..2ea08da06b 100644 --- a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TBoundaryDefinitions.java +++ b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TBoundaryDefinitions.java @@ -15,32 +15,18 @@ package org.eclipse.winery.model.tosca; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlAnyElement; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlType; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import org.eclipse.winery.model.tosca.constants.Namespaces; import org.eclipse.winery.model.tosca.visitor.Visitor; -import io.github.adr.embedded.ADR; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; -import org.w3c.dom.Comment; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.Text; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "tBoundaryDefinitions", propOrder = { @@ -203,164 +189,11 @@ public List getPolicy() { } @XmlAccessorType(XmlAccessType.FIELD) - @XmlType(name = "", propOrder = { - "any", - "propertyMappings" - }) - public static class Properties { + public static class Properties extends TEntityTemplate.Properties { - @XmlAnyElement(lax = true) - protected Object any; @XmlElement(name = "PropertyMappings") protected TBoundaryDefinitions.Properties.PropertyMappings propertyMappings; - @Nullable - public Object getAny() { - if (this.getKVProperties() == null) { - return any; - } else { - return null; - } - } - - public void setAny(@Nullable Object value) { - this.any = value; - } - - /** - * This is a special method for Winery. Winery allows to define a property by specifying name/value values. - * Instead of parsing the XML contained in TNodeType, this method is a convenience method to access this - * information assumes the properties are key/value pairs (see WinerysPropertiesDefinition), all other cases are - * return null. - *

- * Returns a map of key/values of this template based on the information of WinerysPropertiesDefinition. In case - * no value is set, the empty string is used. The map is implemented as {@link LinkedHashMap} to ensure that the - * order of the elements is the same as in the XML. We return the type {@link LinkedHashMap}, because there is - * no appropriate Java interface for "sorted" Maps - *

- * In case the element is not of the form k/v, null is returned - *

- * This method assumes that the any field is always populated. - * - * @return null if not k/v, a map of k/v properties otherwise - */ - @ADR(12) - public LinkedHashMap getKVProperties() { - // we use the internal variable "any", because getAny() returns null, if we have KVProperties - if (any == null || !(any instanceof Element)) { - return null; - } - - Element el = (Element) any; - if (el == null) { - return null; - } - - // we have no type information in this place - // we could inject a repository, but if Winery is used with multiple repositories, this could cause race conditions - // therefore, we guess at the instance of the properties definition (i.e., here) if it is key/value or not. - - boolean isKv = true; - - LinkedHashMap properties = new LinkedHashMap<>(); - - NodeList childNodes = el.getChildNodes(); - - if (childNodes.getLength() == 0) { - // somehow invalid XML - do not treat it as k/v - return null; - } - - for (int i = 0; i < childNodes.getLength(); i++) { - Node item = childNodes.item(i); - if (item instanceof Element) { - String key = item.getLocalName(); - String value; - - Element kvElement = (Element) item; - NodeList kvElementChildNodes = kvElement.getChildNodes(); - if (kvElementChildNodes.getLength() == 0) { - value = ""; - } else if (kvElementChildNodes.getLength() > 1) { - // This is a wrong guess if comments are used, but this is prototype - isKv = false; - break; - } else { - // one child - just get the text. - value = item.getTextContent(); - } - properties.put(key, value); - } else if (item instanceof Text || item instanceof Comment) { - // these kinds of nodes are OK - } - } - - if (isKv) { - return properties; - } else { - return null; - } - } - - @ADR(12) - public void setKVProperties(Map properties) { - Objects.requireNonNull(properties); - Element el = (Element) any; - - if (el == null) { - // special case if JSON is parsed without updating an existing element - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db; - try { - db = dbf.newDocumentBuilder(); - } catch (ParserConfigurationException e) { - throw new IllegalStateException("Could not instantiate document builder", e); - } - Document doc = db.newDocument(); - - // We cannot access the wrapper definitions, because we don't have access to the type - // Element root = doc.createElementNS(wpd.getNamespace(), wpd.getElementName()); - // Therefore, we create a dummy wrapper element: - - Element root = doc.createElementNS(Namespaces.EXAMPLE_NAMESPACE_URI, "Properties"); - doc.appendChild(root); - - // No wpd - so this is not possible: - // we produce the serialization in the same order the XSD would be generated (because of the usage of xsd:sequence) - // for (PropertyDefinitionKV prop : wpd.getPropertyDefinitionKVList()) { - - for (String key : properties.keySet()) { - // wpd.getNamespace() - Element element = doc.createElementNS(Namespaces.EXAMPLE_NAMESPACE_URI, key); - root.appendChild(element); - String value = properties.get(key); - if (value != null) { - Text text = doc.createTextNode(value); - element.appendChild(text); - } - } - - this.setAny(doc.getDocumentElement()); - } else { - // straight-forward copy over to existing property structure - NodeList childNodes = el.getChildNodes(); - - for (int i = 0; i < childNodes.getLength(); i++) { - Node item = childNodes.item(i); - if (item instanceof Element) { - final Element element = (Element) item; - final String key = element.getLocalName(); - final String value = properties.get(key); - if (value != null) { - element.setTextContent(value); - } - } else if (item instanceof Text || item instanceof Comment) { - // these kinds of nodes are OK - } - } - } - } - public TBoundaryDefinitions.Properties.@Nullable PropertyMappings getPropertyMappings() { return propertyMappings; } diff --git a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TEntityType.java b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TEntityType.java index 2e6bf3c367..e9c8877333 100644 --- a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TEntityType.java +++ b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TEntityType.java @@ -23,7 +23,6 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlSchemaType; import javax.xml.bind.annotation.XmlSeeAlso; -import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.adapters.CollapsedStringAdapter; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @@ -32,7 +31,6 @@ import org.eclipse.winery.model.tosca.kvproperties.WinerysPropertiesDefinition; import org.eclipse.winery.model.tosca.visitor.Visitor; -import com.fasterxml.jackson.annotation.JsonIgnore; import io.github.adr.embedded.ADR; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; @@ -52,8 +50,7 @@ TPolicyType.class }) public abstract class TEntityType extends TExtensibleElements implements HasName, HasInheritance, HasTargetNamespace { - public static final String NS_SUFFIX_PROPERTIESDEFINITION_WINERY = "propertiesdefinition/winery"; - + @XmlElement(name = "Tags") protected TTags tags; @XmlElement(name = "DerivedFrom") @@ -178,47 +175,19 @@ public void setTargetNamespace(@Nullable String value) { this.targetNamespace = value; } - /** - * This is a special method for Winery. Winery allows to define a property definition by specifying name/type - * values. Instead of parsing the extensible elements returned TDefinitions, this method is a convenience method to - * access this information - * - * @return a WinerysPropertiesDefinition object, which includes a map of name/type-pairs denoting the associated - * property definitions. A default element name and namespace is added if it is not defined in the underlying XML. - * null if no Winery specific KV properties are defined for the given entity type - */ - @XmlTransient - @JsonIgnore - public WinerysPropertiesDefinition getWinerysPropertiesDefinition() { - // similar implementation as org.eclipse.winery.repository.resources.entitytypes.properties.PropertiesDefinitionResource.getListFromEntityType(TEntityType) - WinerysPropertiesDefinition res = null; - for (Object o : this.getAny()) { - if (o instanceof WinerysPropertiesDefinition) { - res = (WinerysPropertiesDefinition) o; - } - } - - if (res != null) { - // we put defaults if elementname and namespace have not been set - - if (res.getElementName() == null) { - res.setElementName("Properties"); - } - - if (res.getNamespace() == null) { - // we use the targetnamespace of the original element - String ns = this.getTargetNamespace(); - if (!ns.endsWith("/")) { - ns += "/"; - } - ns += NS_SUFFIX_PROPERTIESDEFINITION_WINERY; - res.setNamespace(ns); + @Override + protected void setWPDNamespace(WinerysPropertiesDefinition res) { + if (res.getNamespace() == null) { + // we use the targetnamespace of the original element + String ns = this.getTargetNamespace(); + if (!ns.endsWith("/")) { + ns += "/"; } + ns += NS_SUFFIX_PROPERTIESDEFINITION_WINERY; + res.setNamespace(ns); } - - return res; } - + @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "") public static class DerivedFrom implements HasType { diff --git a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TExtensibleElements.java b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TExtensibleElements.java index 6fa8f324fc..fefb267c22 100644 --- a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TExtensibleElements.java +++ b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TExtensibleElements.java @@ -26,11 +26,14 @@ import javax.xml.bind.annotation.XmlAnyAttribute; import javax.xml.bind.annotation.XmlAnyElement; import javax.xml.bind.annotation.XmlSeeAlso; +import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.XmlType; import javax.xml.namespace.QName; +import org.eclipse.winery.model.tosca.kvproperties.WinerysPropertiesDefinition; import org.eclipse.winery.model.tosca.visitor.Visitor; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import io.github.adr.embedded.ADR; import org.eclipse.jdt.annotation.NonNull; @@ -60,6 +63,7 @@ }) @JsonInclude(JsonInclude.Include.NON_NULL) public abstract class TExtensibleElements { + public static final String NS_SUFFIX_PROPERTIESDEFINITION_WINERY = "propertiesdefinition/winery"; protected List documentation; @@ -68,7 +72,7 @@ public abstract class TExtensibleElements { @XmlAnyAttribute @NonNull - private Map otherAttributes = new HashMap(); + private Map otherAttributes = new HashMap<>(); public TExtensibleElements() { } @@ -101,7 +105,7 @@ public int hashCode() { @NonNull public List getDocumentation() { if (documentation == null) { - documentation = new ArrayList(); + documentation = new ArrayList<>(); } return this.documentation; } @@ -109,11 +113,49 @@ public List getDocumentation() { @NonNull public List getAny() { if (any == null) { - any = new ArrayList(); + any = new ArrayList<>(); } return this.any; } + /** + * This is a special method for Winery. Winery allows to define a property definition by specifying name/type + * values. Instead of parsing the extensible elements returned TDefinitions, this method is a convenience method to + * access this information + * + * @return a WinerysPropertiesDefinition object, which includes a map of name/type-pairs denoting the associated + * property definitions. A default element name and namespace is added if it is not defined in the underlying XML. + * null if no Winery specific KV properties are defined for the given entity type + */ + @XmlTransient + @JsonIgnore + public WinerysPropertiesDefinition getWinerysPropertiesDefinition() { + // similar implementation as org.eclipse.winery.repository.resources.entitytypes.properties.PropertiesDefinitionResource.getListFromEntityType(TEntityType) + WinerysPropertiesDefinition res = null; + for (Object o : this.getAny()) { + if (o instanceof WinerysPropertiesDefinition) { + res = (WinerysPropertiesDefinition) o; + } + } + + if (res != null) { + // we put defaults if elementname and namespace have not been set + setWPDElement(res); + setWPDNamespace(res); + } + + return res; + } + + protected void setWPDElement(WinerysPropertiesDefinition res) { + if (res.getElementName() == null) { + res.setElementName("Properties"); + } + } + + protected void setWPDNamespace(WinerysPropertiesDefinition res) { + } + @NonNull public Map getOtherAttributes() { return otherAttributes; @@ -254,6 +296,5 @@ public T addOtherAttributes(QName key, String value) { @ADR(11) public abstract T self(); - } } diff --git a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TServiceTemplate.java b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TServiceTemplate.java index 5cbd860e68..b829e78e88 100644 --- a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TServiceTemplate.java +++ b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TServiceTemplate.java @@ -21,9 +21,7 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElements; import javax.xml.bind.annotation.XmlSchemaType; -import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.XmlType; import javax.xml.namespace.QName; @@ -32,7 +30,6 @@ import org.eclipse.winery.model.tosca.utils.RemoveEmptyLists; import org.eclipse.winery.model.tosca.visitor.Visitor; -import com.fasterxml.jackson.annotation.JsonIgnore; import org.eclipse.jdt.annotation.Nullable; @XmlAccessorType(XmlAccessType.FIELD) @@ -44,13 +41,9 @@ "plans" }) public class TServiceTemplate extends HasId implements HasName, HasTargetNamespace { - public static final String NS_SUFFIX_PROPERTIESDEFINITION_WINERY = "propertiesdefinition/winery"; - - @XmlElements( { - @XmlElement(name = "PropertiesDefinition", namespace = Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, type = TServiceTemplate.PropertiesDefinition.class), - @XmlElement(name = "PropertiesDefinition", namespace = Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, type = WinerysPropertiesDefinition.class) - }) - protected Object propertiesDefinition; + + @XmlElement(name = "BoundaryDefPropertiesDefinition", namespace = Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE) + protected TServiceTemplate.PropertiesDefinition propertiesDefinition; @XmlElement(name = "Tags") protected TTags tags; @@ -79,6 +72,7 @@ public TServiceTemplate() { public TServiceTemplate(Builder builder) { super(builder); + this.propertiesDefinition = builder.propertiesDefinition; this.tags = builder.tags; this.boundaryDefinitions = builder.boundaryDefinitions; this.topologyTemplate = builder.topologyTemplate; @@ -94,7 +88,8 @@ public boolean equals(Object o) { if (!(o instanceof TServiceTemplate)) return false; if (!super.equals(o)) return false; TServiceTemplate that = (TServiceTemplate) o; - return Objects.equals(tags, that.tags) && + return Objects.equals(propertiesDefinition, that.propertiesDefinition) && + Objects.equals(tags, that.tags) && Objects.equals(boundaryDefinitions, that.boundaryDefinitions) && Objects.equals(topologyTemplate, that.topologyTemplate) && Objects.equals(plans, that.plans) && @@ -105,7 +100,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(super.hashCode(), tags, boundaryDefinitions, topologyTemplate, plans, name, targetNamespace, substitutableNodeType); + return Objects.hash(super.hashCode(), propertiesDefinition, tags, boundaryDefinitions, topologyTemplate, plans, name, targetNamespace, substitutableNodeType); } @Nullable @@ -182,11 +177,11 @@ public void accept(Visitor visitor) { visitor.visit(this); } - public Object getPropertiesDefinition() { + public TServiceTemplate.@Nullable PropertiesDefinition getPropertiesDefinition() { return propertiesDefinition; } - public void setPropertiesDefinition(Object value) { + public void setPropertiesDefinition(TServiceTemplate.@Nullable PropertiesDefinition value) { this.propertiesDefinition = value; } @@ -211,50 +206,25 @@ public void setPropertiesDefinition(Object value) { public static class PropertiesDefinition extends TEntityType.PropertiesDefinition { } - /** - * This is a special method for Winery. Winery allows to define a property definition by specifying name/type - * values. Instead of parsing the extensible elements returned TDefinitions, this method is a convenience method to - * access this information - * - * @return a WinerysPropertiesDefinition object, which includes a map of name/type-pairs denoting the associated - * property definitions. A default element name and namespace is added if it is not defined in the underlying XML. - * null if no Winery specific KV properties are defined for the given entity type - */ - @XmlTransient - @JsonIgnore - public WinerysPropertiesDefinition getWinerysPropertiesDefinition() { - // similar implementation as org.eclipse.winery.repository.resources.entitytypes.properties.PropertiesDefinitionResource.getListFromEntityType(TEntityType) - WinerysPropertiesDefinition res = null; - if (this.getPropertiesDefinition() instanceof WinerysPropertiesDefinition) { - res = (WinerysPropertiesDefinition) this.getPropertiesDefinition(); - } - - if (res != null) { - // we put defaults if elementname and namespace have not been set - - if (res.getElementName() == null) { - res.setElementName("Properties"); - } - - if (res.getNamespace() == null) { - // we use the targetnamespace of the original element - String ns = this.getTargetNamespace(); - if (!ns.endsWith("/")) { - ns += "/"; - } - ns += NS_SUFFIX_PROPERTIESDEFINITION_WINERY; - res.setNamespace(ns); + @Override + protected void setWPDNamespace(WinerysPropertiesDefinition res) { + if (Objects.isNull(res.getNamespace())) { + // we use the targetnamespace of the original element + String ns = this.getTargetNamespace(); + if (!ns.endsWith("/")) { + ns += "/"; } + ns += NS_SUFFIX_PROPERTIESDEFINITION_WINERY; + res.setNamespace(ns); } - - return res; } - + public static class Builder extends HasId.Builder { private final TTopologyTemplate topologyTemplate; private TTags tags; private TBoundaryDefinitions boundaryDefinitions; + private TServiceTemplate.PropertiesDefinition propertiesDefinition; private TPlans plans; private String name; private String targetNamespace; @@ -336,5 +306,10 @@ public Builder self() { public TServiceTemplate build() { return new TServiceTemplate(this); } + + public Builder setPropertiesDefinition(PropertiesDefinition propertiesDefinition) { + this.propertiesDefinition = propertiesDefinition; + return this; + } } } diff --git a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/utils/ModelUtilities.java b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/utils/ModelUtilities.java index 9bd4746ad2..4882cbf7fb 100644 --- a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/utils/ModelUtilities.java +++ b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/utils/ModelUtilities.java @@ -146,7 +146,7 @@ public static Document getWinerysPropertiesDefinitionXsdAsDocument(WinerysProper * Removes an existing Winery's Properties definition. If no such definition exists, the TEntityType is not * modified */ - public static void removeWinerysPropertiesDefinition(TEntityType et) { + public static void removeWinerysPropertiesDefinition(TExtensibleElements et) { for (Iterator iterator = et.getAny().iterator(); iterator.hasNext(); ) { Object o = iterator.next(); if (o instanceof WinerysPropertiesDefinition) { @@ -156,7 +156,7 @@ public static void removeWinerysPropertiesDefinition(TEntityType et) { } } - public static void replaceWinerysPropertiesDefinition(TEntityType et, WinerysPropertiesDefinition wpd) { + public static void replaceWinerysPropertiesDefinition(TExtensibleElements et, WinerysPropertiesDefinition wpd) { ModelUtilities.removeWinerysPropertiesDefinition(et); et.getAny().add(wpd); } diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/apiData/PropertiesDefinitionResourceApiData.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/apiData/PropertiesDefinitionResourceApiData.java index 3da8d9e675..1243fc4810 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/apiData/PropertiesDefinitionResourceApiData.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/apiData/PropertiesDefinitionResourceApiData.java @@ -43,23 +43,4 @@ public PropertiesDefinitionResourceApiData( this.selectedValue = PropertiesDefinitionEnum.None; } } - - public PropertiesDefinitionResourceApiData(Object propertiesDefinition) { - if (propertiesDefinition instanceof TEntityType.PropertiesDefinition) { - this.propertiesDefinition = (TEntityType.PropertiesDefinition) propertiesDefinition; - } - if (propertiesDefinition instanceof WinerysPropertiesDefinition) { - this.winerysPropertiesDefinition = (WinerysPropertiesDefinition) propertiesDefinition; - } - - if ((winerysPropertiesDefinition != null) && (winerysPropertiesDefinition.getIsDerivedFromXSD() == null)) { - this.selectedValue = PropertiesDefinitionEnum.Custom; - } else if ((this.propertiesDefinition != null) && (this.propertiesDefinition.getElement() != null)) { - this.selectedValue = PropertiesDefinitionEnum.Element; - } else if ((this.propertiesDefinition != null) && (this.propertiesDefinition.getType() != null)) { - this.selectedValue = PropertiesDefinitionEnum.Type; - } else { - this.selectedValue = PropertiesDefinitionEnum.None; - } - } } diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/entitytemplates/PropertiesResource.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/entitytemplates/PropertiesResource.java index e9cda41249..6591222acd 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/entitytemplates/PropertiesResource.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/entitytemplates/PropertiesResource.java @@ -13,9 +13,16 @@ *******************************************************************************/ package org.eclipse.winery.repository.rest.resources.entitytemplates; -import io.github.adr.embedded.ADR; -import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.jdt.annotation.Nullable; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + import org.eclipse.winery.model.tosca.TEntityTemplate; import org.eclipse.winery.model.tosca.TEntityType; import org.eclipse.winery.model.tosca.kvproperties.WinerysPropertiesDefinition; @@ -23,14 +30,13 @@ import org.eclipse.winery.repository.backend.RepositoryFactory; import org.eclipse.winery.repository.rest.RestUtils; import org.eclipse.winery.repository.rest.resources._support.AbstractComponentInstanceResource; + +import io.github.adr.embedded.ADR; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.util.Map; - public class PropertiesResource { private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesResource.class); @@ -38,6 +44,10 @@ public class PropertiesResource { private AbstractComponentInstanceResource res; private TEntityTemplate template; + public PropertiesResource() { + + } + /** * @param template the template to store the definitions at * @param res the resource to save after modifications diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/entitytypes/properties/PropertiesDefinitionResource.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/entitytypes/properties/PropertiesDefinitionResource.java index 76b5205fff..2370d94a97 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/entitytypes/properties/PropertiesDefinitionResource.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/entitytypes/properties/PropertiesDefinitionResource.java @@ -13,6 +13,21 @@ *******************************************************************************/ package org.eclipse.winery.repository.rest.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.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.WebApplicationException; +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.TEntityType; import org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition; import org.eclipse.winery.model.tosca.kvproperties.WinerysPropertiesDefinition; @@ -26,16 +41,10 @@ import org.eclipse.winery.repository.rest.resources.apiData.PropertiesDefinitionEnum; import org.eclipse.winery.repository.rest.resources.apiData.PropertiesDefinitionResourceApiData; import org.eclipse.winery.repository.rest.resources.entitytypes.EntityTypeResource; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import java.util.ArrayList; -import java.util.List; - /** * Models *
    @@ -47,20 +56,23 @@ * {@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; + protected final WinerysPropertiesDefinition wpd; + // We hold a copy of super.res as we work on the type EntityTypeResource instead of AbstractComponentInstanceResource + private final EntityTypeResource parentRes; public PropertiesDefinitionResource(EntityTypeResource res) { this.parentRes = res; - this.wpd = ModelUtilities.getWinerysPropertiesDefinition(res.getEntityType()); + this.wpd = res.getEntityType().getWinerysPropertiesDefinition(); + } + + protected PropertiesDefinitionResource() { + wpd = null; + parentRes = null; } @GET diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java index bb5b137c96..6e665da587 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java @@ -17,8 +17,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.Objects; import java.util.SortedSet; import javax.xml.namespace.QName; @@ -28,7 +26,6 @@ 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.model.tosca.kvproperties.WinerysPropertiesDefinition; import org.eclipse.winery.model.tosca.utils.ModelUtilities; import org.eclipse.winery.repository.backend.BackendUtils; import org.eclipse.winery.repository.backend.RepositoryFactory; @@ -36,6 +33,7 @@ import org.eclipse.winery.repository.rest.datatypes.select2.Select2DataItem; import org.eclipse.winery.repository.rest.resources.admin.types.ConstraintTypesManager; +import org.apache.commons.lang3.StringEscapeUtils; import org.apache.taglibs.standard.functions.Functions; public class BoundaryDefinitionsJSPData { @@ -54,8 +52,8 @@ public BoundaryDefinitionsJSPData(TServiceTemplate ste, URI baseURI) { this.baseURI = baseURI; } - private Map getDefinedProperties() { - /*TBoundaryDefinitions.Properties p = ModelUtilities.getProperties(this.defs); + private String getDefinedProperties() { + TBoundaryDefinitions.Properties p = ModelUtilities.getProperties(this.defs); Object o = p.getAny(); if (o == null) { // nothing stored -> return empty string @@ -63,42 +61,10 @@ private Map getDefinedProperties() { } else { // something stored --> return that return BackendUtils.getXMLAsString(p.getAny()); - }*/ - - WinerysPropertiesDefinition wpd = ste.getWinerysPropertiesDefinition(); - - if (Objects.isNull(wpd)) { - // no Winery special treatment, just return the XML properties - // These can be null resulting in 200 No Content at the caller - /*if (props == null) { - return Response.ok().entity("{}").type(MediaType.APPLICATION_JSON).build(); - } else { - @Nullable final Object any = props.getAny(); - if (any == null) { - LOGGER.debug("XML properties expected, but none found. Returning empty JSON."); - return Response.ok().entity("{}").type(MediaType.APPLICATION_JSON).build(); - } - try { - @ADR(6) - String xmlAsString = BackendUtils.getXMLAsString(TEntityTemplate.Properties.class, props, true); - return Response - .ok() - .entity(xmlAsString) - .type(MediaType.TEXT_XML) - .build(); - } catch (Exception e) { - throw new WebApplicationException(e); - } - }*/ - return null; - } else { - return ste.getBoundaryDefinitions().getProperties().getKVProperties(); - //return Response.ok().entity(kvProperties).type(MediaType.APPLICATION_JSON).build(); } - } - public Map getPropertiesAsXMLString() { + public String getPropertiesAsXMLString() { return this.getDefinedProperties(); } @@ -106,7 +72,7 @@ public Map getPropertiesAsXMLString() { * 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() { + public String getDefinedPropertiesAsEscapedHTML() { String s = this.getDefinedProperties(); s = StringEscapeUtils.escapeHtml4(s); return s; @@ -116,7 +82,8 @@ public String getDefinedPropertiesAsJSONString() { String s = this.getDefinedProperties(); s = StringEscapeUtils.escapeEcmaScript(s); return s; - }*/ + } + public TBoundaryDefinitions getDefs() { return this.defs; } diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsPropertiesResource.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsPropertiesResource.java new file mode 100644 index 0000000000..2de29ffe29 --- /dev/null +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsPropertiesResource.java @@ -0,0 +1,107 @@ +/******************************************************************************** + * Copyright (c) 2018 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + *******************************************************************************/ + +package org.eclipse.winery.repository.rest.resources.servicetemplates.boundarydefinitions; + +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TBoundaryDefinitions; +import org.eclipse.winery.model.tosca.TServiceTemplate; +import org.eclipse.winery.model.tosca.kvproperties.WinerysPropertiesDefinition; +import org.eclipse.winery.model.tosca.utils.ModelUtilities; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.rest.RestUtils; +import org.eclipse.winery.repository.rest.resources._support.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.rest.resources.servicetemplates.ServiceTemplateResource; + +import io.github.adr.embedded.ADR; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; + +public class BoundaryDefinitionsPropertiesResource { + private static final Logger LOGGER = LoggerFactory.getLogger(BoundaryDefinitionsPropertiesResource.class); + + private AbstractComponentInstanceResource res; + private TServiceTemplate template; + + public BoundaryDefinitionsPropertiesResource(AbstractComponentInstanceResource res) { + this.template = ((ServiceTemplateResource) res).getServiceTemplate(); + this.res = res; + } + + @GET + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + public Response getProperties() { + WinerysPropertiesDefinition wpd = template.getWinerysPropertiesDefinition(); + TBoundaryDefinitions.Properties props = this.template.getBoundaryDefinitions().getProperties(); + if (wpd == null) { + // no Winery special treatment, just return the XML properties + // These can be null resulting in 200 No Content at the caller + if (props == null) { + return Response.ok().type(MediaType.APPLICATION_XML).build(); + } else { + /*if (props.getAny() == null) { + LOGGER.debug("XML properties expected, but none found. Returning empty JSON."); + return Response.noContent().type(MediaType.APPLICATION_XML).build(); + }*/ + try { + @ADR(6) + String xmlAsString = BackendUtils.getXMLAsString(TBoundaryDefinitions.Properties.class, props, true); + return Response + .ok() + .entity(xmlAsString) + .type(MediaType.APPLICATION_XML) + .build(); + } catch (Exception e) { + throw new WebApplicationException(e); + } + } + } else { + Map kvProperties = this.template.getBoundaryDefinitions().getProperties().getKVProperties(); + return Response.ok().entity(kvProperties).type(MediaType.APPLICATION_JSON).build(); + } + } + + /* + * The well-formedness of the XML element is done using the framework. If you see [Fatal Error] :1:19: The + * prefix "tosca" for element "tosca:properties" is not bound. in the console, it is an indicator that the XML element is not well-formed. + */ + @PUT + @Consumes( {MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + @ApiOperation(value = "saves properties of boundary definitions", notes = "Models the user-defined properties. The property mappings go into a separate resource propertymappings.") + public Response putProperties(@ApiParam(value = "Stored properties. The XSD allows a single element only. Therefore, we go for the contained element") Document doc) { + TBoundaryDefinitions.Properties properties = ModelUtilities.getProperties(this.template.getBoundaryDefinitions()); + properties.setAny(doc.getDocumentElement()); + return RestUtils.persist(res); + } + + @PUT + @Consumes( {MediaType.APPLICATION_JSON}) + @ApiOperation(value = "saves properties of boundary definitions", notes = "Models the user-defined properties. The property mappings go into a separate resource propertymappings.") + public Response putCustomProperties(@ApiParam(value = "Stored properties. The XSD allows a single element only. Therefore, we go for the contained element") Map props) { + this.template.getBoundaryDefinitions().getProperties().setKVProperties(props); + return RestUtils.persist(res); + } +} diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java index 7a24a86098..f9e0f2156a 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java @@ -80,36 +80,9 @@ public Response setModel(TBoundaryDefinitions boundaryDefinitions) { } @Path("properties/") - @GET - @Produces(MediaType.APPLICATION_JSON) - public Response getProperties(@Context UriInfo uriInfo) { - return Response.ok() - .entity(new BoundaryDefinitionsJSPData(this.serviceTemplateResource.getServiceTemplate(), uriInfo.getBaseUri()).getPropertiesAsXMLString()) - .type(MediaType.APPLICATION_JSON) - .build(); - } - - /** - * The well-formedness of the XML element is done using the framework. If you see [Fatal Error] :1:19: The - * prefix "tosca" for element "tosca:properties" is not bound. in the console, it is an indicator that the XML element is not well-formed. - */ - @Path("properties/") - @PUT - @Consumes( {MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - @ApiOperation(value = "saves properties of boundary definitions", notes = "Models the user-defined properties. The property mappings go into a separate resource propertymappings.") - public Response putProperties(@ApiParam(value = "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 RestUtils.persist(this.serviceTemplateResource); - } - - @Path("properties/") - @PUT - @Consumes( {MediaType.APPLICATION_JSON}) - @ApiOperation(value = "saves properties of boundary definitions", notes = "Models the user-defined properties. The property mappings go into a separate resource propertymappings.") - public Response putCustomProperties(@ApiParam(value = "Stored properties. The XSD allows a single element only. Therefore, we go for the contained element") Map props) { - this.boundaryDefinitions.getProperties().setKVProperties(props); - return RestUtils.persist(this.serviceTemplateResource); + public BoundaryDefinitionsPropertiesResource getProperties(@Context UriInfo uriInfo) { + return new BoundaryDefinitionsPropertiesResource(this.serviceTemplateResource); + //return new BoundaryDefinitionsJSPData(this.serviceTemplateResource.getServiceTemplate(), uriInfo.getBaseUri()).getPropertiesAsXMLString(); } @Path("requirements/") diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/propertiesdefinition/BoundaryDefsPropertiesDefinitionResource.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/propertiesdefinition/BoundaryDefsPropertiesDefinitionResource.java index 30167acddc..05a5de526c 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/propertiesdefinition/BoundaryDefsPropertiesDefinitionResource.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/propertiesdefinition/BoundaryDefsPropertiesDefinitionResource.java @@ -14,124 +14,129 @@ package org.eclipse.winery.repository.rest.resources.servicetemplates.propertiesdefinition; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; 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.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import org.eclipse.winery.model.tosca.TBoundaryDefinitions; -import org.eclipse.winery.model.tosca.kvproperties.PropertyDefinitionKV; +import org.eclipse.winery.model.tosca.TServiceTemplate; +import org.eclipse.winery.model.tosca.kvproperties.WinerysPropertiesDefinition; +import org.eclipse.winery.model.tosca.utils.ModelUtilities; +import org.eclipse.winery.repository.backend.BackendUtils; import org.eclipse.winery.repository.backend.NamespaceManager; import org.eclipse.winery.repository.backend.RepositoryFactory; -import org.eclipse.winery.repository.backend.xsd.NamespaceAndDefinedLocalNames; import org.eclipse.winery.repository.rest.RestUtils; -import org.eclipse.winery.repository.rest.datatypes.NamespaceAndDefinedLocalNamesForAngular; import org.eclipse.winery.repository.rest.resources.apiData.PropertiesDefinitionEnum; import org.eclipse.winery.repository.rest.resources.apiData.PropertiesDefinitionResourceApiData; +import org.eclipse.winery.repository.rest.resources.entitytypes.properties.PropertiesDefinitionResource; import org.eclipse.winery.repository.rest.resources.servicetemplates.ServiceTemplateResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -public class BoundaryDefsPropertiesDefinitionResource { +public class BoundaryDefsPropertiesDefinitionResource extends PropertiesDefinitionResource { private static final Logger LOGGER = LoggerFactory.getLogger(BoundaryDefsPropertiesDefinitionResource.class); private final ServiceTemplateResource parentRes; + private final WinerysPropertiesDefinition wpd; public BoundaryDefsPropertiesDefinitionResource(ServiceTemplateResource res) { this.parentRes = res; + this.wpd = res.getElement().getWinerysPropertiesDefinition(); } @GET @Produces(MediaType.APPLICATION_JSON) public PropertiesDefinitionResourceApiData getJson() { - Object definition = parentRes.getServiceTemplate().getPropertiesDefinition(); - return new PropertiesDefinitionResourceApiData(definition); - } - - @GET - @Path("{type}") - @Produces(MediaType.APPLICATION_JSON) - public List getXsdDefinitionJson(@PathParam("type") String type) { - List allDeclaredElementsLocalNames = null; - switch (type) { - case "type": - allDeclaredElementsLocalNames = RepositoryFactory.getRepository().getXsdImportManager().getAllDefinedTypesLocalNames(); - break; - case "element": - allDeclaredElementsLocalNames = RepositoryFactory.getRepository().getXsdImportManager().getAllDeclaredElementsLocalNames(); - break; - } - - if (allDeclaredElementsLocalNames == null) { - LOGGER.error("No such parameter available in this call", type); - throw new WebApplicationException(Response.Status.BAD_REQUEST); - } - - return RestUtils.convert(allDeclaredElementsLocalNames); + TServiceTemplate.PropertiesDefinition definition = this.parentRes.getServiceTemplate().getPropertiesDefinition(); + return new PropertiesDefinitionResourceApiData(definition, this.wpd); } @DELETE public Response clearPropertiesDefinition() { - parentRes.getServiceTemplate().setPropertiesDefinition(null); + TServiceTemplate st = this.parentRes.getServiceTemplate(); + st.setPropertiesDefinition(null); + if (Objects.nonNull(st.getBoundaryDefinitions())) { + if (Stream.of( + st.getBoundaryDefinitions().getPolicies(), + st.getBoundaryDefinitions().getCapabilities(), + st.getBoundaryDefinitions().getPropertyConstraints(), + st.getBoundaryDefinitions().getRequirements(), + st.getBoundaryDefinitions().getInterfaces()) + .allMatch(Objects::isNull)) { + st.setBoundaryDefinitions(null); + } else { + st.getBoundaryDefinitions().setProperties(null); + } + } + ModelUtilities.removeWinerysPropertiesDefinition(this.parentRes.getServiceTemplate()); return RestUtils.persist(this.parentRes); } @POST @Consumes(MediaType.APPLICATION_JSON) public Response onJsonPost(PropertiesDefinitionResourceApiData data) { + TServiceTemplate st = this.parentRes.getServiceTemplate(); + if (data.selectedValue == PropertiesDefinitionEnum.Element || data.selectedValue == PropertiesDefinitionEnum.Type) { - // TODO - // return RestUtils.persist(this.parentRes); - } else if (data.selectedValue == PropertiesDefinitionEnum.Custom) { - parentRes.getServiceTemplate().setPropertiesDefinition(data.winerysPropertiesDefinition); - String namespace = data.winerysPropertiesDefinition.getNamespace(); - NamespaceManager namespaceManager = RepositoryFactory.getRepository().getNamespaceManager(); - if (!namespaceManager.hasPermanentPrefix(namespace)) { - namespaceManager.addPermanentNamespace(namespace); + if (Objects.nonNull(st.getBoundaryDefinitions())) { + st.getBoundaryDefinitions().setProperties(null); } - - // BackendUtils.initializeProperties(repository, (TEntityTemplate) element); - Document document; - try { - document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); - } catch (ParserConfigurationException e) { - LOGGER.error("Could not create document", e); - return Response.serverError().build(); + // first of all, remove Winery's Properties definition (if it exists) + ModelUtilities.removeWinerysPropertiesDefinition(st); + // replace old properties definition by new one + TServiceTemplate.PropertiesDefinition def = new TServiceTemplate.PropertiesDefinition(); + + if (data.propertiesDefinition.getElement() != null) { + def.setElement(data.propertiesDefinition.getElement()); + } else if (data.propertiesDefinition.getType() != null) { + def.setType(data.propertiesDefinition.getType()); + } else { + return Response.status(Response.Status.BAD_REQUEST).entity("Wrong data submitted!").build(); } - final String ns = data.winerysPropertiesDefinition.getNamespace(); - final Element wrapperElement = document.createElementNS(ns, data.winerysPropertiesDefinition.getElementName()); - document.appendChild(wrapperElement); - - // we produce the serialization in the same order the XSD would be generated (because of the usage of xsd:sequence) - for (PropertyDefinitionKV propertyDefinitionKV : data.winerysPropertiesDefinition.getPropertyDefinitionKVList()) { - // we always write the element tag as the XSD forces that - final Element valueElement = document.createElementNS(ns, propertyDefinitionKV.getKey()); - wrapperElement.appendChild(valueElement); + st.setPropertiesDefinition(def); + List errors = new ArrayList<>(); + BackendUtils.deriveWPD(st, errors); + // currently the errors are just logged + for (String error : errors) { + LOGGER.debug(error); } + BackendUtils.initializeProperties(RepositoryFactory.getRepository(), st); - TBoundaryDefinitions.Properties properties = new TBoundaryDefinitions.Properties(); - properties.setAny(document.getDocumentElement()); - parentRes.getServiceTemplate().setBoundaryDefinitions(new TBoundaryDefinitions()); - parentRes.getServiceTemplate().getBoundaryDefinitions().setProperties(properties); + return RestUtils.persist(this.parentRes); + } else if (data.selectedValue == PropertiesDefinitionEnum.Custom) { + // clear current properties definition + st.setPropertiesDefinition(null); + + if (!data.winerysPropertiesDefinition.getPropertyDefinitionKVList().getPropertyDefinitionKVs().isEmpty()) { + // create winery properties definition and persist it + ModelUtilities.replaceWinerysPropertiesDefinition(st, data.winerysPropertiesDefinition); + String namespace = data.winerysPropertiesDefinition.getNamespace(); + NamespaceManager namespaceManager = RepositoryFactory.getRepository().getNamespaceManager(); + if (!namespaceManager.hasPermanentProperties(namespace)) { + namespaceManager.addPermanentNamespace(namespace); + } + + BackendUtils.initializeProperties(RepositoryFactory.getRepository(), st); + } + else { + return Response.status(Response.Status.BAD_REQUEST) + .entity("Empty KV Properties Definition is not allowed!") + .build(); + } return RestUtils.persist(this.parentRes); } - return Response.status(Status.BAD_REQUEST).entity("Wrong data submitted!").build(); + return Response.status(Response.Status.BAD_REQUEST).entity("Wrong data submitted!").build(); } } diff --git a/org.eclipse.winery.repository.ui/src/app/instance/instance.service.ts b/org.eclipse.winery.repository.ui/src/app/instance/instance.service.ts index 9c4d5dd1fe..6662679a22 100644 --- a/org.eclipse.winery.repository.ui/src/app/instance/instance.service.ts +++ b/org.eclipse.winery.repository.ui/src/app/instance/instance.service.ts @@ -48,8 +48,8 @@ export class InstanceService { 'Inheritance', 'Documentation', 'XML']; break; case ToscaTypes.ServiceTemplate: - subMenu = ['README', 'LICENSE', 'Topology Template', 'Plans', 'Selfservice Portal', - 'Boundary Definitions', 'Tags', 'Properties Definition', 'Constraint Checking', 'Documentation', 'XML']; + subMenu = ['README', 'LICENSE', 'Topology Template', 'Plans', 'Selfservice Portal', 'Constraint Checking', + 'Tags', 'Properties Definition', 'Boundary Definitions', 'Documentation', 'XML']; break; case ToscaTypes.RelationshipType: subMenu = ['README', 'LICENSE', 'Visual Appearance', 'Instance States', 'Source Interfaces', 'Target Interfaces', diff --git a/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.component.html b/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.component.html index 7c73f423d2..a1b194b671 100644 --- a/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.component.html +++ b/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.component.html @@ -32,7 +32,15 @@
    Service Template Property
    -
    + + + +
    -
    -
    -
    - Property name is required! +
    +
    + Property name is required! +
    @@ -145,8 +153,9 @@ + [disableOkButton]="!(propertyMappingForm?.form.valid && currentSelectedItem.serviceTemplatePropertyRef && currentSelectedItem.serviceTemplatePropertyRef.length > 0 + && currentSelectedItem.targetObjectRef && currentSelectedItem.targetObjectRef.length > 0 + && currentSelectedItem.targetPropertyRef && currentSelectedItem.targetPropertyRef.length > 0)"> @@ -164,7 +173,7 @@ + [okButtonLabel]="'Delete'"> diff --git a/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.component.ts b/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.component.ts index 8b77858892..3f6acaf5bd 100644 --- a/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.component.ts +++ b/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.component.ts @@ -38,7 +38,7 @@ export class PropertyMappingsComponent implements OnInit { loading = true; targetTypeSelected = false; - apiData: PropertyMappingsApiData; + apiData: PropertyMappingsApiData = { propertyMappings: { propertyMapping: [] } }; columns: Array = [ { title: 'Service Template Property', name: 'serviceTemplatePropertyRef', sort: true }, { title: 'Target', name: 'targetObjectRef', sort: true }, @@ -53,6 +53,8 @@ export class PropertyMappingsComponent implements OnInit { currentSelectedItem: Property = new Property(); addOrUpdate = 'Add'; properties: { name: string, property: string } = { name: '', property: '' }; + propertiesList: Array = []; + propertiesAreKeyValuePairs: boolean = false; xmlData: any; selectedProperty = ''; templateList: Array = []; @@ -71,13 +73,14 @@ export class PropertyMappingsComponent implements OnInit { ngOnInit() { this.getMappings(); - this.getProperties(); - this.getTopologyTemplate(); } getMappings() { this.service.getPropertyMappings().subscribe( - data => this.handleData(data), + data => { + this.handleData(data); + this.getProperties(); + }, error => this.notify.error(error.toString()) ); } @@ -91,26 +94,39 @@ export class PropertyMappingsComponent implements OnInit { getProperties() { this.service.getPropertiesOfServiceTemplate().subscribe( - data => this.handleProperties(data), + data => { + this.handleProperties(data); + this.getTopologyTemplate(); + }, error => this.handleError(error) ); } handleTopologyTemplateData(data: WineryTopologyTemplate) { this.topologyTemplate = data; - if (!isNullOrUndefined(this.xmlData) && !isNullOrUndefined(this.apiData)) { - this.loading = false; - } + this.loading = false; } - handleProperties(props: string) { - const parser = new DOMParser(); - this.xmlData = parser.parseFromString(props, 'application/xml'); - this.properties.name = this.xmlData.firstChild.localName; - this.properties.property = '/*[local-name()=\'' + this.properties.name + '\']'; + handleProperties(props: any) { + if (props.isXML) { + if (props.properties) { + const parser = new DOMParser(); + this.xmlData = parser.parseFromString(props.properties, 'application/xml'); + this.properties.name = this.xmlData.firstChild.localName; + this.properties.property = '/*[local-name()=\'' + this.properties.name + '\']'; + } + } + else { + this.propertiesAreKeyValuePairs = true; + for (let p in props.properties) { + this.propertiesList.push({ 'id': p, 'text': p }); + } + } + } - if (!isNullOrUndefined(this.topologyTemplate) && !isNullOrUndefined(this.apiData)) { - this.loading = false; + onPropertySelected(property: any) { + if (property.text && property.text.length > 0) { + this.currentSelectedItem.serviceTemplatePropertyRef = property.text; } } @@ -200,9 +216,6 @@ export class PropertyMappingsComponent implements OnInit { handleData(data: PropertyMappingsApiData) { this.apiData = data; - if (!isNullOrUndefined(this.xmlData) && !isNullOrUndefined(this.topologyTemplate)) { - this.loading = false; - } } onCellSelected(selectedItem: WineryRowData) { diff --git a/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.service.ts b/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.service.ts index e2ed5f835d..9b5575fc1c 100644 --- a/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.service.ts +++ b/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.service.ts @@ -18,6 +18,7 @@ import { backendBaseURL } from '../../../../configuration'; import { ModalDirective } from 'ngx-bootstrap'; import { PropertiesDefinitionsResourceApiData } from '../../../sharedComponents/propertiesDefinition/propertiesDefinitionsResourceApiData'; import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; +import { map } from 'rxjs/operators'; export class Property { serviceTemplatePropertyRef: string; @@ -66,14 +67,24 @@ export class PropertyMappingService { ); } - getPropertiesOfServiceTemplate(): Observable { - const headers = new HttpHeaders({ 'Accept': 'application/xml' }); + getPropertiesOfServiceTemplate(): Observable { + //const headers = new HttpHeaders({ 'Accept': 'application/xml' }); const newPath: string = this.path.replace('propertymappings', 'properties'); + return this.http.get(newPath, { observe: 'response', responseType: 'text' }) + .pipe(map(res => { + if (res.headers.get('Content-Type') === 'application/json') { + return { + isXML: false, properties: JSON.parse(res.body) + }; + } else { + return { isXML: true, properties: res.body }; + } + })); - return this.http + /*return this.http .get(newPath + '/', { headers: headers, responseType: 'text' } - ); + );*/ } getTargetObjKVProperties(targetPath: string): Observable { diff --git a/org.eclipse.winery.repository.ui/src/app/instance/sharedComponents/properties/properties.service.ts b/org.eclipse.winery.repository.ui/src/app/instance/sharedComponents/properties/properties.service.ts index 1f0f13cd72..f0126dcc01 100644 --- a/org.eclipse.winery.repository.ui/src/app/instance/sharedComponents/properties/properties.service.ts +++ b/org.eclipse.winery.repository.ui/src/app/instance/sharedComponents/properties/properties.service.ts @@ -50,8 +50,7 @@ export class PropertiesService { } public saveProperties(properties: any, isXML: boolean): Observable> { - const headers = new HttpHeaders(); - headers.set('Content-Type', isXML ? 'application/xml' : 'application/json'); + const headers = new HttpHeaders({ 'Content-Type' : isXML ? 'application/xml' : 'application/json'}); return this.http .put( this.path, diff --git a/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/BackendUtils.java b/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/BackendUtils.java index f89132c96a..eef86c1233 100644 --- a/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/BackendUtils.java +++ b/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/BackendUtils.java @@ -95,6 +95,7 @@ import org.eclipse.winery.model.tosca.TArtifactReference; import org.eclipse.winery.model.tosca.TArtifactTemplate; import org.eclipse.winery.model.tosca.TArtifactType; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions; import org.eclipse.winery.model.tosca.TCapability; import org.eclipse.winery.model.tosca.TCapabilityType; import org.eclipse.winery.model.tosca.TDefinitions; @@ -114,6 +115,7 @@ import org.eclipse.winery.model.tosca.TPlans; import org.eclipse.winery.model.tosca.TPolicyTemplate; import org.eclipse.winery.model.tosca.TPolicyType; +import org.eclipse.winery.model.tosca.TPropertyMapping; import org.eclipse.winery.model.tosca.TRelationshipTemplate; import org.eclipse.winery.model.tosca.TRelationshipType; import org.eclipse.winery.model.tosca.TRelationshipTypeImplementation; @@ -295,7 +297,7 @@ public static String getName(DefinitionsChildId instanceId) throws RepositoryCor } /** - * Do not use this for creating URLs. Use {@link Utils#getURLforPathInsideRepo(java.lang.String)} or + * Do not use this for creating URLs. Use {@link Utils.getURLforPathInsideRepo(java.lang.String)} or * {@link Utils#getAbsoluteURL(org.eclipse.winery.common.ids.GenericId) instead. * * @return the path starting from the root element to the current element. Separated by "/", URLencoded, but @@ -626,17 +628,32 @@ public static Definitions createWrapperDefinitionsAndInitialEmptyElement(IReposi /** * Properties need to be initialized in the case of K/V Properties * - * @param repository The repository to work on - * @param entityTemplate the entity template to update + * @param repository The repository to work on + * @param extEl The entity template or service template to update */ - public static void initializeProperties(IRepository repository, TEntityTemplate entityTemplate) { + public static void initializeProperties(IRepository repository, TExtensibleElements extEl) { Objects.requireNonNull(repository); - Objects.requireNonNull(entityTemplate); + Objects.requireNonNull(extEl); - Objects.requireNonNull(entityTemplate.getType()); + if (extEl instanceof TEntityTemplate) { + Objects.requireNonNull(((TEntityTemplate) extEl).getType()); + } + + WinerysPropertiesDefinition winerysPropertiesDefinition; + Map existingKVProperties = null; + List addedPropertyNames = new ArrayList<>(); + if (extEl instanceof TEntityTemplate) { + final TEntityType entityType = repository.getTypeForTemplate(((TEntityTemplate) extEl)); + winerysPropertiesDefinition = entityType.getWinerysPropertiesDefinition(); + } else { + // serviceTemplate allows direct access to WinerysPropertiesDefinition + winerysPropertiesDefinition = extEl.getWinerysPropertiesDefinition(); + TServiceTemplate st = ((TServiceTemplate) extEl); + if (Objects.nonNull(st.getBoundaryDefinitions()) && Objects.nonNull(st.getBoundaryDefinitions().getProperties())) { + existingKVProperties = st.getBoundaryDefinitions().getProperties().getKVProperties(); + } + } - final TEntityType entityType = repository.getTypeForTemplate(entityTemplate); - final WinerysPropertiesDefinition winerysPropertiesDefinition = entityType.getWinerysPropertiesDefinition(); if (winerysPropertiesDefinition == null) { return; } @@ -656,12 +673,46 @@ public static void initializeProperties(IRepository repository, TEntityTemplate for (PropertyDefinitionKV propertyDefinitionKV : winerysPropertiesDefinition.getPropertyDefinitionKVList()) { // we always write the element tag as the XSD forces that final Element valueElement = document.createElementNS(namespace, propertyDefinitionKV.getKey()); + + if (Objects.nonNull(existingKVProperties)) { + if (existingKVProperties.containsKey(propertyDefinitionKV.getKey())) { + valueElement.setTextContent(existingKVProperties.get(propertyDefinitionKV.getKey())); + } + } wrapperElement.appendChild(valueElement); + addedPropertyNames.add(propertyDefinitionKV.getKey()); } - TEntityTemplate.Properties properties = new TEntityTemplate.Properties(); - properties.setAny(document.getDocumentElement()); - entityTemplate.setProperties(properties); + if (extEl instanceof TEntityTemplate) { + TEntityTemplate.Properties properties = new TEntityTemplate.Properties(); + properties.setAny(document.getDocumentElement()); + ((TEntityTemplate) extEl).setProperties(properties); + } else { + TServiceTemplate st = ((TServiceTemplate) extEl); + TBoundaryDefinitions bd = st.getBoundaryDefinitions(); + + TBoundaryDefinitions.Properties properties = new TBoundaryDefinitions.Properties(); + properties.setAny(document.getDocumentElement()); + + if (Objects.nonNull(bd) && Objects.nonNull(bd.getProperties()) + && Objects.nonNull(bd.getProperties().getPropertyMappings())) { + + TBoundaryDefinitions.Properties.PropertyMappings propertyMappings = new TBoundaryDefinitions.Properties.PropertyMappings(); + for (TPropertyMapping mapping : bd.getProperties().getPropertyMappings().getPropertyMapping()) { + if (addedPropertyNames.contains(mapping.getServiceTemplatePropertyRef())) { + propertyMappings.getPropertyMapping().add(mapping); + } + } + properties.setPropertyMappings(propertyMappings); + } + + if (Objects.nonNull(bd)) { + st.getBoundaryDefinitions().setProperties(properties); + } else { + st.setBoundaryDefinitions(new TBoundaryDefinitions()); + st.getBoundaryDefinitions().setProperties(properties); + } + } } /** @@ -816,72 +867,83 @@ public String getBaseURI() { * @param ci the entity type to try to modify the WPDs * @param errors the list to add errors to */ - public static void deriveWPD(TEntityType ci, List errors) { + public static void deriveWPD(TExtensibleElements ci, List errors) { BackendUtils.LOGGER.trace("deriveWPD"); - PropertiesDefinition propertiesDefinition = ci.getPropertiesDefinition(); - QName element = propertiesDefinition.getElement(); - if (element == null) { - BackendUtils.LOGGER.debug("only works for an element definition, not for types"); - } else { - BackendUtils.LOGGER.debug("Looking for the definition of {" + element.getNamespaceURI() + "}" + element.getLocalPart()); - // fetch the XSD defining the element - final XsdImportManager xsdImportManager = RepositoryFactory.getRepository().getXsdImportManager(); - Map mapFromLocalNameToXSD = xsdImportManager.getMapFromLocalNameToXSD(new Namespace(element.getNamespaceURI(), false), false); - RepositoryFileReference ref = mapFromLocalNameToXSD.get(element.getLocalPart()); - if (ref == null) { - String msg = "XSD not found for " + element.getNamespaceURI() + " / " + element.getLocalPart(); - BackendUtils.LOGGER.debug(msg); - errors.add(msg); - return; + if (ci instanceof TEntityType || ci instanceof TServiceTemplate) { + PropertiesDefinition propertiesDefinition; + if (ci instanceof TEntityType) { + propertiesDefinition = ((TEntityType) ci).getPropertiesDefinition(); + } else { + propertiesDefinition = ((TServiceTemplate) ci).getPropertiesDefinition(); } - final Optional xsModelOptional = BackendUtils.getXSModel(ref); - if (!xsModelOptional.isPresent()) { - LOGGER.error("no XSModel found"); - } - XSModel xsModel = xsModelOptional.get(); - XSElementDeclaration elementDeclaration = xsModel.getElementDeclaration(element.getLocalPart(), element.getNamespaceURI()); - if (elementDeclaration == null) { - String msg = "XSD model claimed to contain declaration for {" + element.getNamespaceURI() + "}" + element.getLocalPart() + ", but it did not."; - BackendUtils.LOGGER.debug(msg); - errors.add(msg); - return; - } + QName element = propertiesDefinition.getElement(); + if (element == null) { + BackendUtils.LOGGER.debug("only works for an element definition, not for types"); + } else { + BackendUtils.LOGGER.debug("Looking for the definition of {" + element.getNamespaceURI() + "}" + element.getLocalPart()); + // fetch the XSD defining the element + final XsdImportManager xsdImportManager = RepositoryFactory.getRepository().getXsdImportManager(); + Map mapFromLocalNameToXSD = xsdImportManager.getMapFromLocalNameToXSD(new Namespace(element.getNamespaceURI(), false), false); + RepositoryFileReference ref = mapFromLocalNameToXSD.get(element.getLocalPart()); + if (ref == null) { + String msg = "XSD not found for " + element.getNamespaceURI() + " / " + element.getLocalPart(); + BackendUtils.LOGGER.debug(msg); + errors.add(msg); + return; + } - // go through the XSD definition and - XSTypeDefinition typeDefinition = elementDeclaration.getTypeDefinition(); - if (typeDefinition instanceof XSComplexTypeDefinition) { - XSComplexTypeDefinition cTypeDefinition = (XSComplexTypeDefinition) typeDefinition; - XSParticle particle = cTypeDefinition.getParticle(); - if (particle == null) { - BackendUtils.LOGGER.debug("XSD does not follow the requirements put by winery: Complex type does not contain particles"); - } else { - XSTerm term = particle.getTerm(); - if (term instanceof XSModelGroup) { - XSModelGroup modelGroup = (XSModelGroup) term; - if (modelGroup.getCompositor() == XSModelGroup.COMPOSITOR_SEQUENCE) { - XSObjectList particles = modelGroup.getParticles(); - int len = particles.getLength(); - boolean everyThingIsASimpleType = true; - PropertyDefinitionKVList list = new PropertyDefinitionKVList(); - if (len != 0) { - for (int i = 0; i < len; i++) { - XSParticle innerParticle = (XSParticle) particles.item(i); - XSTerm innerTerm = innerParticle.getTerm(); - if (innerTerm instanceof XSElementDeclaration) { - XSElementDeclaration innerElementDeclaration = (XSElementDeclaration) innerTerm; - String name = innerElementDeclaration.getName(); - XSTypeDefinition innerTypeDefinition = innerElementDeclaration.getTypeDefinition(); - if (innerTypeDefinition instanceof XSSimpleType) { - XSSimpleType xsSimpleType = (XSSimpleType) innerTypeDefinition; - String typeNS = xsSimpleType.getNamespace(); - String typeName = xsSimpleType.getName(); - if (typeNS.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) { - PropertyDefinitionKV def = new PropertyDefinitionKV(); - def.setKey(name); - // convention at WPD: use "xsd" as prefix for XML Schema Definition - def.setType("xsd:" + typeName); - list.add(def); + final Optional xsModelOptional = BackendUtils.getXSModel(ref); + if (!xsModelOptional.isPresent()) { + LOGGER.error("no XSModel found"); + } + XSModel xsModel = xsModelOptional.get(); + XSElementDeclaration elementDeclaration = xsModel.getElementDeclaration(element.getLocalPart(), element.getNamespaceURI()); + if (elementDeclaration == null) { + String msg = "XSD model claimed to contain declaration for {" + element.getNamespaceURI() + "}" + element.getLocalPart() + ", but it did not."; + BackendUtils.LOGGER.debug(msg); + errors.add(msg); + return; + } + + // go through the XSD definition and + XSTypeDefinition typeDefinition = elementDeclaration.getTypeDefinition(); + if (typeDefinition instanceof XSComplexTypeDefinition) { + XSComplexTypeDefinition cTypeDefinition = (XSComplexTypeDefinition) typeDefinition; + XSParticle particle = cTypeDefinition.getParticle(); + if (particle == null) { + BackendUtils.LOGGER.debug("XSD does not follow the requirements put by winery: Complex type does not contain particles"); + } else { + XSTerm term = particle.getTerm(); + if (term instanceof XSModelGroup) { + XSModelGroup modelGroup = (XSModelGroup) term; + if (modelGroup.getCompositor() == XSModelGroup.COMPOSITOR_SEQUENCE) { + XSObjectList particles = modelGroup.getParticles(); + int len = particles.getLength(); + boolean everyThingIsASimpleType = true; + PropertyDefinitionKVList list = new PropertyDefinitionKVList(); + if (len != 0) { + for (int i = 0; i < len; i++) { + XSParticle innerParticle = (XSParticle) particles.item(i); + XSTerm innerTerm = innerParticle.getTerm(); + if (innerTerm instanceof XSElementDeclaration) { + XSElementDeclaration innerElementDeclaration = (XSElementDeclaration) innerTerm; + String name = innerElementDeclaration.getName(); + XSTypeDefinition innerTypeDefinition = innerElementDeclaration.getTypeDefinition(); + if (innerTypeDefinition instanceof XSSimpleType) { + XSSimpleType xsSimpleType = (XSSimpleType) innerTypeDefinition; + String typeNS = xsSimpleType.getNamespace(); + String typeName = xsSimpleType.getName(); + if (typeNS.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) { + PropertyDefinitionKV def = new PropertyDefinitionKV(); + def.setKey(name); + // convention at WPD: use "xsd" as prefix for XML Schema Definition + def.setType("xsd:" + typeName); + list.add(def); + } else { + everyThingIsASimpleType = false; + break; + } } else { everyThingIsASimpleType = false; break; @@ -890,33 +952,30 @@ public static void deriveWPD(TEntityType ci, List errors) { everyThingIsASimpleType = false; break; } - } else { - everyThingIsASimpleType = false; - break; } } - } - if (everyThingIsASimpleType) { - // everything went allright, we can add a WPD - WinerysPropertiesDefinition wpd = new WinerysPropertiesDefinition(); - wpd.setIsDerivedFromXSD(Boolean.TRUE); - wpd.setElementName(element.getLocalPart()); - wpd.setNamespace(element.getNamespaceURI()); - wpd.setPropertyDefinitionKVList(list); - ModelUtilities.replaceWinerysPropertiesDefinition(ci, wpd); - BackendUtils.LOGGER.debug("Successfully generated WPD"); + if (everyThingIsASimpleType) { + // everything went allright, we can add a WPD + WinerysPropertiesDefinition wpd = new WinerysPropertiesDefinition(); + wpd.setIsDerivedFromXSD(Boolean.TRUE); + wpd.setElementName(element.getLocalPart()); + wpd.setNamespace(element.getNamespaceURI()); + wpd.setPropertyDefinitionKVList(list); + ModelUtilities.replaceWinerysPropertiesDefinition(ci, wpd); + BackendUtils.LOGGER.debug("Successfully generated WPD"); + } else { + BackendUtils.LOGGER.debug("XSD does not follow the requirements put by winery: Not all types in the sequence are simple types"); + } } else { - BackendUtils.LOGGER.debug("XSD does not follow the requirements put by winery: Not all types in the sequence are simple types"); + BackendUtils.LOGGER.debug("XSD does not follow the requirements put by winery: Model group is not a sequence"); } } else { - BackendUtils.LOGGER.debug("XSD does not follow the requirements put by winery: Model group is not a sequence"); + BackendUtils.LOGGER.debug("XSD does not follow the requirements put by winery: Not a model group"); } - } else { - BackendUtils.LOGGER.debug("XSD does not follow the requirements put by winery: Not a model group"); } + } else { + BackendUtils.LOGGER.debug("XSD does not follow the requirements put by winery: No Complex Type Definition"); } - } else { - BackendUtils.LOGGER.debug("XSD does not follow the requirements put by winery: No Complex Type Definition"); } } } From 5aad601f2bdc52e0930fd24d5d54c8a22fe892a6 Mon Sep 17 00:00:00 2001 From: Vladimir Yussupov Date: Fri, 3 Aug 2018 16:48:39 +0200 Subject: [PATCH 3/5] Remove unused imports Signed-off-by: Vladimir Yussupov --- .../winery/model/tosca/TExtensibleElements.java | 2 ++ .../servicetemplates/ServiceTemplateResource.java | 1 - .../BoundaryDefinitionsPropertiesResource.java | 10 +--------- .../BoundaryDefinitionsResource.java | 4 ---- 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TExtensibleElements.java b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TExtensibleElements.java index fefb267c22..cca70abc5d 100644 --- a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TExtensibleElements.java +++ b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TExtensibleElements.java @@ -154,6 +154,8 @@ protected void setWPDElement(WinerysPropertiesDefinition res) { } protected void setWPDNamespace(WinerysPropertiesDefinition res) { + // bo be overridden by subclasses willing to use getWinerysPropertiesDefinition() + // Template method pattern } @NonNull diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/ServiceTemplateResource.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/ServiceTemplateResource.java index cda8dee942..21a5ae3434 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/ServiceTemplateResource.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/ServiceTemplateResource.java @@ -53,7 +53,6 @@ import org.eclipse.winery.repository.rest.resources._support.IHasName; import org.eclipse.winery.repository.rest.resources._support.dataadapter.injectionadapter.InjectorReplaceData; import org.eclipse.winery.repository.rest.resources._support.dataadapter.injectionadapter.InjectorReplaceOptions; -import org.eclipse.winery.repository.rest.resources.apiData.PropertiesDefinitionResourceApiData; import org.eclipse.winery.repository.rest.resources.servicetemplates.boundarydefinitions.BoundaryDefinitionsResource; import org.eclipse.winery.repository.rest.resources.servicetemplates.plans.PlansResource; import org.eclipse.winery.repository.rest.resources.servicetemplates.propertiesdefinition.BoundaryDefsPropertiesDefinitionResource; diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsPropertiesResource.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsPropertiesResource.java index 2de29ffe29..2fb67ef7ab 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsPropertiesResource.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsPropertiesResource.java @@ -36,13 +36,10 @@ import io.github.adr.embedded.ADR; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.w3c.dom.Document; public class BoundaryDefinitionsPropertiesResource { - private static final Logger LOGGER = LoggerFactory.getLogger(BoundaryDefinitionsPropertiesResource.class); - + private AbstractComponentInstanceResource res; private TServiceTemplate template; @@ -58,14 +55,9 @@ public Response getProperties() { TBoundaryDefinitions.Properties props = this.template.getBoundaryDefinitions().getProperties(); if (wpd == null) { // no Winery special treatment, just return the XML properties - // These can be null resulting in 200 No Content at the caller if (props == null) { return Response.ok().type(MediaType.APPLICATION_XML).build(); } else { - /*if (props.getAny() == null) { - LOGGER.debug("XML properties expected, but none found. Returning empty JSON."); - return Response.noContent().type(MediaType.APPLICATION_XML).build(); - }*/ try { @ADR(6) String xmlAsString = BackendUtils.getXMLAsString(TBoundaryDefinitions.Properties.class, props, true); diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java index f9e0f2156a..e89da4c3f5 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java @@ -15,7 +15,6 @@ package org.eclipse.winery.repository.rest.resources.servicetemplates.boundarydefinitions; import java.util.List; -import java.util.Map; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -36,7 +35,6 @@ 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.model.tosca.utils.ModelUtilities; import org.eclipse.winery.repository.rest.RestUtils; import org.eclipse.winery.repository.rest.resources.servicetemplates.ServiceTemplateResource; import org.eclipse.winery.repository.rest.resources.servicetemplates.boundarydefinitions.interfaces.InterfacesResource; @@ -45,8 +43,6 @@ import org.eclipse.winery.repository.rest.resources.servicetemplates.boundarydefinitions.reqscaps.RequirementsResource; import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import org.w3c.dom.Document; public class BoundaryDefinitionsResource { From c2f8beb814d2cddf095760e35fab29fa19c37f1b Mon Sep 17 00:00:00 2001 From: Vladimir Yussupov Date: Thu, 9 Aug 2018 09:59:28 +0200 Subject: [PATCH 4/5] Add requested changes Signed-off-by: Vladimir Yussupov --- .../eclipse/winery/model/tosca/TEntityType.java | 13 ------------- .../winery/model/tosca/TExtensibleElements.java | 17 +++++++++++++---- .../winery/model/tosca/TServiceTemplate.java | 13 ------------- .../entitytemplates/PropertiesResource.java | 4 ---- .../propertyMappings.component.ts | 13 ++++++++----- .../propertyMappings.service.ts | 6 ------ .../properties/properties.service.ts | 4 ++-- 7 files changed, 23 insertions(+), 47 deletions(-) diff --git a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TEntityType.java b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TEntityType.java index e9c8877333..acff93368e 100644 --- a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TEntityType.java +++ b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TEntityType.java @@ -175,19 +175,6 @@ public void setTargetNamespace(@Nullable String value) { this.targetNamespace = value; } - @Override - protected void setWPDNamespace(WinerysPropertiesDefinition res) { - if (res.getNamespace() == null) { - // we use the targetnamespace of the original element - String ns = this.getTargetNamespace(); - if (!ns.endsWith("/")) { - ns += "/"; - } - ns += NS_SUFFIX_PROPERTIESDEFINITION_WINERY; - res.setNamespace(ns); - } - } - @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "") public static class DerivedFrom implements HasType { diff --git a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TExtensibleElements.java b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TExtensibleElements.java index cca70abc5d..8df881ee49 100644 --- a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TExtensibleElements.java +++ b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TExtensibleElements.java @@ -147,15 +147,24 @@ public WinerysPropertiesDefinition getWinerysPropertiesDefinition() { return res; } - protected void setWPDElement(WinerysPropertiesDefinition res) { + private void setWPDElement(WinerysPropertiesDefinition res) { if (res.getElementName() == null) { res.setElementName("Properties"); } } - protected void setWPDNamespace(WinerysPropertiesDefinition res) { - // bo be overridden by subclasses willing to use getWinerysPropertiesDefinition() - // Template method pattern + private void setWPDNamespace(WinerysPropertiesDefinition res) { + if (Objects.isNull(res.getNamespace())) { + if (this instanceof HasTargetNamespace) { + // we use the targetnamespace of the original element + String ns = ((HasTargetNamespace) this).getTargetNamespace(); + if (!ns.endsWith("/")) { + ns += "/"; + } + ns += NS_SUFFIX_PROPERTIESDEFINITION_WINERY; + res.setNamespace(ns); + } + } } @NonNull diff --git a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TServiceTemplate.java b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TServiceTemplate.java index b829e78e88..a0043e576c 100644 --- a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TServiceTemplate.java +++ b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TServiceTemplate.java @@ -206,19 +206,6 @@ public void setPropertiesDefinition(TServiceTemplate.@Nullable PropertiesDefinit public static class PropertiesDefinition extends TEntityType.PropertiesDefinition { } - @Override - protected void setWPDNamespace(WinerysPropertiesDefinition res) { - if (Objects.isNull(res.getNamespace())) { - // we use the targetnamespace of the original element - String ns = this.getTargetNamespace(); - if (!ns.endsWith("/")) { - ns += "/"; - } - ns += NS_SUFFIX_PROPERTIESDEFINITION_WINERY; - res.setNamespace(ns); - } - } - public static class Builder extends HasId.Builder { private final TTopologyTemplate topologyTemplate; diff --git a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/entitytemplates/PropertiesResource.java b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/entitytemplates/PropertiesResource.java index 6591222acd..4a2322cdeb 100644 --- a/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/entitytemplates/PropertiesResource.java +++ b/org.eclipse.winery.repository.rest/src/main/java/org/eclipse/winery/repository/rest/resources/entitytemplates/PropertiesResource.java @@ -44,10 +44,6 @@ public class PropertiesResource { private AbstractComponentInstanceResource res; private TEntityTemplate template; - public PropertiesResource() { - - } - /** * @param template the template to store the definitions at * @param res the resource to save after modifications diff --git a/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.component.ts b/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.component.ts index 3f6acaf5bd..c1c2bc40bb 100644 --- a/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.component.ts +++ b/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.component.ts @@ -54,7 +54,7 @@ export class PropertyMappingsComponent implements OnInit { addOrUpdate = 'Add'; properties: { name: string, property: string } = { name: '', property: '' }; propertiesList: Array = []; - propertiesAreKeyValuePairs: boolean = false; + propertiesAreKeyValuePairs = false; xmlData: any; selectedProperty = ''; templateList: Array = []; @@ -115,11 +115,14 @@ export class PropertyMappingsComponent implements OnInit { this.properties.name = this.xmlData.firstChild.localName; this.properties.property = '/*[local-name()=\'' + this.properties.name + '\']'; } - } - else { + } else { this.propertiesAreKeyValuePairs = true; - for (let p in props.properties) { - this.propertiesList.push({ 'id': p, 'text': p }); + if (props.properties) { + for (const p in props.properties) { + if (props.properties.hasOwnProperty(p)) { + this.propertiesList.push({ 'id': p, 'text': p }); + } + } } } } diff --git a/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.service.ts b/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.service.ts index 9b5575fc1c..3f25d5ceda 100644 --- a/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.service.ts +++ b/org.eclipse.winery.repository.ui/src/app/instance/serviceTemplates/boundaryDefinitions/propertyMappings/propertyMappings.service.ts @@ -68,7 +68,6 @@ export class PropertyMappingService { } getPropertiesOfServiceTemplate(): Observable { - //const headers = new HttpHeaders({ 'Accept': 'application/xml' }); const newPath: string = this.path.replace('propertymappings', 'properties'); return this.http.get(newPath, { observe: 'response', responseType: 'text' }) .pipe(map(res => { @@ -80,11 +79,6 @@ export class PropertyMappingService { return { isXML: true, properties: res.body }; } })); - - /*return this.http - .get(newPath + '/', - { headers: headers, responseType: 'text' } - );*/ } getTargetObjKVProperties(targetPath: string): Observable { diff --git a/org.eclipse.winery.repository.ui/src/app/instance/sharedComponents/properties/properties.service.ts b/org.eclipse.winery.repository.ui/src/app/instance/sharedComponents/properties/properties.service.ts index f0126dcc01..2e76df1a85 100644 --- a/org.eclipse.winery.repository.ui/src/app/instance/sharedComponents/properties/properties.service.ts +++ b/org.eclipse.winery.repository.ui/src/app/instance/sharedComponents/properties/properties.service.ts @@ -27,8 +27,8 @@ export class PropertiesService { constructor(private http: HttpClient, private sharedData: InstanceService) { this.path = backendBaseURL + this.sharedData.path + '/properties/'; - if (this.sharedData.toscaComponent.toscaType == ToscaTypes.ServiceTemplate ) { - this.path = this.path.replace('/properties/', '/boundarydefinitions/properties/') + if (this.sharedData.toscaComponent.toscaType === ToscaTypes.ServiceTemplate ) { + this.path = this.path.replace('/properties/', '/boundarydefinitions/properties/'); } } From 5f2e7399c1f738c41d4a56b0e68650721a033db7 Mon Sep 17 00:00:00 2001 From: Lukas Harzenetter Date: Fri, 14 Feb 2020 14:59:00 +0100 Subject: [PATCH 5/5] fix missing import --- .../main/java/org/eclipse/winery/model/tosca/TEntityType.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TEntityType.java b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TEntityType.java index aa32bee198..3a37b345d7 100644 --- a/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TEntityType.java +++ b/org.eclipse.winery.model.tosca/src/main/java/org/eclipse/winery/model/tosca/TEntityType.java @@ -28,9 +28,9 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import javax.xml.namespace.QName; -import org.eclipse.winery.model.tosca.kvproperties.WinerysPropertiesDefinition; import org.eclipse.winery.model.tosca.visitor.Visitor; +import com.fasterxml.jackson.annotation.JsonIgnore; import io.github.adr.embedded.ADR; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; @@ -50,7 +50,7 @@ TPolicyType.class }) public abstract class TEntityType extends TExtensibleElements implements HasName, HasInheritance, HasTargetNamespace { - + @XmlElement(name = "Tags") protected TTags tags; @XmlElement(name = "DerivedFrom")