summaryrefslogtreecommitdiffstats
path: root/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java')
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java802
1 files changed, 802 insertions, 0 deletions
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java
new file mode 100644
index 0000000..765b07a
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java
@@ -0,0 +1,802 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Kálmán Képes - initial API and implementation and/or initial documentation
+ * Oliver Kopp - adapted to new storage model and to TOSCA v1.0
+ *******************************************************************************/
+package org.eclipse.winery.repository.export;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.constants.QNames;
+import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
+import org.eclipse.winery.common.ids.definitions.CapabilityTypeId;
+import org.eclipse.winery.common.ids.definitions.EntityTypeId;
+import org.eclipse.winery.common.ids.definitions.NodeTypeId;
+import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId;
+import org.eclipse.winery.common.ids.definitions.PolicyTemplateId;
+import org.eclipse.winery.common.ids.definitions.PolicyTypeId;
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeId;
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId;
+import org.eclipse.winery.common.ids.definitions.RequirementTypeId;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.common.ids.definitions.TopologyGraphElementEntityTypeId;
+import org.eclipse.winery.common.ids.definitions.imports.GenericImportId;
+import org.eclipse.winery.common.ids.elements.PlanId;
+import org.eclipse.winery.common.ids.elements.PlansId;
+import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition;
+import org.eclipse.winery.model.tosca.Definitions;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Policies;
+import org.eclipse.winery.model.tosca.TCapability;
+import org.eclipse.winery.model.tosca.TCapabilityDefinition;
+import org.eclipse.winery.model.tosca.TDeploymentArtifact;
+import org.eclipse.winery.model.tosca.TDeploymentArtifacts;
+import org.eclipse.winery.model.tosca.TEntityTemplate;
+import org.eclipse.winery.model.tosca.TEntityType;
+import org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition;
+import org.eclipse.winery.model.tosca.TImplementationArtifact;
+import org.eclipse.winery.model.tosca.TImplementationArtifacts;
+import org.eclipse.winery.model.tosca.TImport;
+import org.eclipse.winery.model.tosca.TNodeTemplate;
+import org.eclipse.winery.model.tosca.TNodeTemplate.Capabilities;
+import org.eclipse.winery.model.tosca.TNodeTemplate.Requirements;
+import org.eclipse.winery.model.tosca.TNodeType;
+import org.eclipse.winery.model.tosca.TNodeType.CapabilityDefinitions;
+import org.eclipse.winery.model.tosca.TNodeType.RequirementDefinitions;
+import org.eclipse.winery.model.tosca.TPolicy;
+import org.eclipse.winery.model.tosca.TRelationshipTemplate;
+import org.eclipse.winery.model.tosca.TRelationshipType;
+import org.eclipse.winery.model.tosca.TRelationshipType.ValidSource;
+import org.eclipse.winery.model.tosca.TRelationshipType.ValidTarget;
+import org.eclipse.winery.model.tosca.TRequirement;
+import org.eclipse.winery.model.tosca.TRequirementDefinition;
+import org.eclipse.winery.repository.JAXBSupport;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.backend.constants.Filename;
+import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId;
+import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal;
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+import org.eclipse.winery.repository.resources.EntityTypeResource;
+import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplateResource;
+import org.eclipse.winery.repository.resources.entitytemplates.policytemplates.PolicyTemplateResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypeResource;
+import org.eclipse.winery.repository.resources.entitytypes.requirementtypes.RequirementTypeResource;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+import org.w3c.dom.Document;
+
+public class TOSCAExportUtil {
+
+ private static final XLogger logger = XLoggerFactory.getXLogger(TOSCAExportUtil.class);
+
+ /*
+ * these two are GLOBAL VARIABLES leading to the fact that this class has to
+ * be constructed for each export
+ */
+
+ // collects the references to be put in the CSAR and the assigned path in
+ // the CSAR MANIFEST
+ // this allows to use other paths in the CSAR than on the local storage
+ private Map<RepositoryFileReference, String> referencesToPathInCSARMap = null;
+
+ /**
+ * Currently a very simple approach to configure the export
+ */
+ private Map<String, Object> exportConfiguration;
+
+
+ public enum ExportProperties {
+ INCLUDEXYCOORDINATES, REPOSITORY_URI
+ };
+
+
+ /**
+ * Writes the <em>complete</em> tosca xml into the given outputstream
+ *
+ * @param id the id of the TOSCA component instance to export
+ * @param out outputstream to write to
+ * @param addRelatedComponents true: all referenced components
+ * (artifactTemplates, artifactTypes, ...) are added, false: only
+ * the XML belonging to the id is exported. If XML types are
+ * generated by Winery (e.g., the properties XSD for node types),
+ * these XML types are also exported
+ * @param exportConfiguration the configuration map for the export. Uses
+ * @param exportedState exportedState object to modify. ExportProperties
+ * provides the possible keys
+ * @return a collection of TOSCAcomponentIds referenced by the given
+ * component
+ * @throws JAXBException
+ */
+ public Collection<TOSCAComponentId> exportTOSCA(TOSCAComponentId id, OutputStream out, Map<String, Object> exportConfiguration) throws IOException, JAXBException {
+ this.exportConfiguration = exportConfiguration;
+ this.initializeExport();
+ return this.writeDefinitionsElement(id, out);
+ }
+
+ private void initializeExport() {
+ this.setDefaultExportConfiguration();
+ // quick hack to avoid NPE
+ if (this.referencesToPathInCSARMap == null) {
+ this.referencesToPathInCSARMap = new HashMap<>();
+ }
+ }
+
+ /**
+ * Quick hack to set defaults. Typically, a configuration builder or similar
+ * is used
+ */
+ private void setDefaultExportConfiguration() {
+ this.checkConfig(ExportProperties.INCLUDEXYCOORDINATES, Boolean.FALSE);
+ }
+
+ private void checkConfig(ExportProperties propKey, Boolean bo) {
+ if (!this.exportConfiguration.containsKey(propKey.toString())) {
+ this.exportConfiguration.put(propKey.toString(), bo);
+ }
+ }
+
+ /**
+ * Writes the <em>complete</em> TOSCA XML into the given outputstream.
+ * Additionally, a the artifactMap is filled to enable the CSAR exporter to
+ * create necessary entries in TOSCA-Meta and to add them to the CSAR itself
+ *
+ * @param id the component instance to export
+ * @param out outputstream to write to
+ * @param exportConfiguration Configures the exporter
+ * @param referencesToPathInCSARMap collects the references to export. It is
+ * updated during the export
+ * @return a collection of TOSCAcomponentIds referenced by the given
+ * component
+ * @throws JAXBException
+ */
+ protected Collection<TOSCAComponentId> exportTOSCA(TOSCAComponentId id, OutputStream out, Map<RepositoryFileReference, String> referencesToPathInCSARMap, Map<String, Object> exportConfiguration) throws IOException, JAXBException {
+ this.referencesToPathInCSARMap = referencesToPathInCSARMap;
+ return this.exportTOSCA(id, out, exportConfiguration);
+ }
+
+ /**
+ * Called when the entry resource is definitions backed
+ *
+ * @throws JAXBException
+ */
+ private void writeDefinitionsElement(Definitions entryDefinitions, OutputStream out) throws JAXBException {
+ Marshaller m = JAXBSupport.createMarshaller(true);
+ m.marshal(entryDefinitions, out);
+ }
+
+ /**
+ * Writes the Definitions belonging to the given TOSCA component to the
+ * outputstream
+ *
+ * @return a collection of TOSCAcomponentIds referenced by the given
+ * component
+ *
+ * @throws IOException
+ * @throws JAXBException
+ * @throws IllegalStateException if tcId does not exist
+ */
+ private Collection<TOSCAComponentId> writeDefinitionsElement(TOSCAComponentId tcId, OutputStream out) throws IOException, JAXBException {
+ if (!Repository.INSTANCE.exists(tcId)) {
+ String error = "Component instance " + tcId.toString() + " does not exist.";
+ TOSCAExportUtil.logger.error(error);
+ throw new IllegalStateException(error);
+ }
+
+ AbstractComponentInstanceResource res = AbstractComponentsResource.getComponentInstaceResource(tcId);
+ Definitions entryDefinitions = res.getDefinitions();
+
+ // BEGIN: Definitions modification
+ // the "imports" collection contains the imports of Definitions, not of other definitions
+ // the other definitions are stored in entryDefinitions.getImport()
+ // we modify the internal definitions object directly. It is not written back to the storage. Therefore, we do not need to clone it
+
+ // the imports (pointing to not-definitions (xsd, wsdl, ...)) already have a correct relative URL. (quick hack)
+ URI uri = (URI) this.exportConfiguration.get(TOSCAExportUtil.ExportProperties.REPOSITORY_URI.toString());
+ if (uri != null) {
+ // we are in the plain-XML mode, the URLs of the imports have to be adjusted
+ for (TImport i : entryDefinitions.getImport()) {
+ String loc = i.getLocation();
+ assert (loc.startsWith("../"));
+ loc = loc.substring(3);
+ loc = uri + loc;
+ // now the location is an absolute URL
+ i.setLocation(loc);
+ }
+ }
+
+ // files of imports have to be added to the CSAR, too
+ for (TImport i : entryDefinitions.getImport()) {
+ String loc = i.getLocation();
+ if (Util.isRelativeURI(loc)) {
+ // locally stored, add to CSAR
+ GenericImportId iid = new GenericImportId(i);
+ String fileName = Util.getLastURIPart(loc);
+ fileName = Util.URLdecode(fileName);
+ RepositoryFileReference ref = new RepositoryFileReference(iid, fileName);
+ this.putRefAsReferencedItemInCSAR(ref);
+ }
+ }
+
+ // adjust imports: add imports of definitions to it
+ Collection<TOSCAComponentId> referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds(tcId);
+ Collection<TImport> imports = new ArrayList<>();
+ for (TOSCAComponentId id : referencedTOSCAComponentIds) {
+ this.addToImports(id, imports);
+ }
+ entryDefinitions.getImport().addAll(imports);
+
+ if (res.getElement() instanceof TEntityType) {
+ // we have an entity type with a possible properties definition
+ EntityTypeResource entityTypeRes = (EntityTypeResource) res;
+ WinerysPropertiesDefinition wpd = ModelUtilities.getWinerysPropertiesDefinition(entityTypeRes.getEntityType());
+ if (wpd != null) {
+ if (wpd.getIsDerivedFromXSD() == null) {
+ // Write WPD only to file if it exists and is NOT derived from an XSD (which may happen during import)
+
+ String wrapperElementNamespace = wpd.getNamespace();
+ String wrapperElementLocalName = wpd.getElementName();
+
+ // BEGIN: add import and put into CSAR
+
+ TImport imp = new TImport();
+ entryDefinitions.getImport().add(imp);
+
+ // fill known import values
+ imp.setImportType(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ imp.setNamespace(wrapperElementNamespace);
+ // add "winerysPropertiesDefinition" flag to import tag to support
+ Map<QName, String> otherAttributes = imp.getOtherAttributes();
+ otherAttributes.put(QNames.QNAME_WINERYS_PROPERTIES_DEFINITION_ATTRIBUTE, "true");
+
+ // Determine location
+ String loc = BackendUtils.getImportLocationForWinerysPropertiesDefinitionXSD((EntityTypeId) tcId, uri, wrapperElementLocalName);
+ if (uri == null) {
+ TOSCAExportUtil.logger.trace("CSAR Export mode. Putting XSD into CSAR");
+ // CSAR Export mode
+ // XSD has to be put into the CSAR
+ Document document = ModelUtilities.getWinerysPropertiesDefinitionXSDAsDocument(wpd);
+
+ // loc in import is URLencoded, loc on filesystem isn't
+ String locInCSAR = Util.URLdecode(loc);
+ // furthermore, the path has to start from the root of the CSAR; currently, it starts from Definitions/
+ locInCSAR = locInCSAR.substring(3);
+ TOSCAExportUtil.logger.trace("Location in CSAR: {}", locInCSAR);
+ this.referencesToPathInCSARMap.put(new DummyRepositoryFileReferenceForGeneratedXSD(document), locInCSAR);
+ }
+ imp.setLocation(loc);
+
+ // END: add import and put into CSAR
+
+ // BEGIN: generate TOSCA conforming PropertiesDefinition
+
+ TEntityType entityType = entityTypeRes.getEntityType();
+ PropertiesDefinition propertiesDefinition = new PropertiesDefinition();
+ propertiesDefinition.setType(new QName(wrapperElementNamespace, wrapperElementLocalName));
+ entityType.setPropertiesDefinition(propertiesDefinition);
+
+ // END: generate TOSCA conforming PropertiesDefinition
+ } else {
+ // otherwise WPD exists, but is derived from XSD
+ // we DO NOT have to remove the winery properties definition from the output to allow "debugging" of the CSAR
+ }
+ }
+ }
+
+ // END: Definitions modification
+
+ this.writeDefinitionsElement(entryDefinitions, out);
+
+ return referencedTOSCAComponentIds;
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(EntityTypeId id) {
+ return this.getReferencedTOSCAComponentIdOfParentForAnAbstractComponentsWithTypeReferenceResource(id);
+ }
+
+ /**
+ * There is now equivalent id class for
+ * AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal,
+ * therefore we take the super type and hope that the caller knows what he
+ * does.
+ */
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIdOfParentForAnAbstractComponentsWithTypeReferenceResource(TOSCAComponentId id) {
+ AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal res = (AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal) AbstractComponentsResource.getComponentInstaceResource(id);
+ String derivedFrom = res.getInheritanceManagement().getDerivedFrom();
+ if (StringUtils.isEmpty(derivedFrom)) {
+ return Collections.emptySet();
+ } else {
+ // Instantiate an id with the same class as the current id
+ TOSCAComponentId parentId;
+ QName qname = QName.valueOf(derivedFrom);
+
+ Constructor<? extends TOSCAComponentId> constructor;
+ try {
+ constructor = id.getClass().getConstructor(QName.class);
+ } catch (NoSuchMethodException | SecurityException e1) {
+ throw new IllegalStateException("Could get constructor to instantiate parent id", e1);
+ }
+ try {
+ parentId = constructor.newInstance(qname);
+ } catch (InstantiationException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException e) {
+ throw new IllegalStateException("Could not instantiate id for parent", e);
+ }
+
+ Collection<TOSCAComponentId> result = new ArrayList<>(1);
+ result.add(parentId);
+ return result;
+ }
+ }
+
+ /**
+ * This method is intended to be used by exportTOSCA. However,
+ * org.eclipse.winery.repository.client requires an XML representation of a
+ * component instances without a surrounding definitions element.
+ *
+ * We name this method differently to prevent wrong calling due to
+ * inheritance
+ *
+ * @param definitionsElement the parent XML element
+ */
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(TOSCAComponentId id) {
+ Collection<TOSCAComponentId> referencedTOSCAComponentIds;
+
+ // first of all, handle the concrete elements
+ if (id instanceof ServiceTemplateId) {
+ referencedTOSCAComponentIds = this.prepareForExport((ServiceTemplateId) id);
+ } else if (id instanceof NodeTypeId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((NodeTypeId) id);
+ } else if (id instanceof NodeTypeImplementationId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((NodeTypeImplementationId) id);
+ } else if (id instanceof RelationshipTypeId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((RelationshipTypeId) id);
+ } else if (id instanceof RelationshipTypeImplementationId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((RelationshipTypeImplementationId) id);
+ } else if (id instanceof RequirementTypeId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((RequirementTypeId) id);
+ } else if (id instanceof CapabilityTypeId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((CapabilityTypeId) id);
+ } else if (id instanceof ArtifactTypeId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((ArtifactTypeId) id);
+ } else if (id instanceof ArtifactTemplateId) {
+ referencedTOSCAComponentIds = this.prepareForExport((ArtifactTemplateId) id);
+ } else if (id instanceof PolicyTypeId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((PolicyTypeId) id);
+ } else if (id instanceof PolicyTemplateId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((PolicyTemplateId) id);
+ } else if (id instanceof GenericImportId) {
+ // in case of imports, there are no other ids referenced
+ referencedTOSCAComponentIds = Collections.emptyList();
+ } else {
+ throw new IllegalStateException("Unhandled id class " + id.getClass());
+ }
+
+ // Then, handle the super classes, which support inheritance
+ // Currently, it is EntityType and EntityTypeImplementation only
+ // Since the latter does not exist in the TOSCA MetaModel, we just handle EntityType here
+ if (id instanceof EntityTypeId) {
+ Collection<TOSCAComponentId> additionalRefs = this.getReferencedTOSCAComponentIds((EntityTypeId) id);
+ // the original referenceTOSCAComponentIds could be unmodifiable
+ // we just create a new one...
+ referencedTOSCAComponentIds = new ArrayList<>(referencedTOSCAComponentIds);
+ // ...and add the new reference
+ referencedTOSCAComponentIds.addAll(additionalRefs);
+ }
+
+ return referencedTOSCAComponentIds;
+ }
+
+ /**
+ * Adds the given id as import to the given imports collection
+ */
+ private void addToImports(TOSCAComponentId id, Collection<TImport> imports) {
+ TImport imp = new TImport();
+ imp.setImportType(org.eclipse.winery.common.constants.Namespaces.TOSCA_NAMESPACE);
+ imp.setNamespace(id.getNamespace().getDecoded());
+ URI uri = (URI) this.exportConfiguration.get(TOSCAExportUtil.ExportProperties.REPOSITORY_URI.toString());
+ if (uri == null) {
+ // self-contained mode
+ // all Definitions are contained in "Definitions" directory, therefore, we provide the filename only
+ // references are resolved relatively from a definitions element (COS01, line 425)
+ String fn = CSARExporter.getDefinitionsFileName(id);
+ fn = Util.URLencode(fn);
+ imp.setLocation(fn);
+ } else {
+ String path = Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(id));
+ path = path + "?definitions";
+ URI absoluteURI = uri.resolve(path);
+ imp.setLocation(absoluteURI.toString());
+ }
+ imports.add(imp);
+
+ // FIXME: Currently the depended elements (such as the artifact templates linked to a node type implementation) are gathered by the corresponding "addXY" method.
+ // Reason: the corresponding TDefinitions element is *not* updated if a related element is added/removed.
+ // That means: The imports are not changed.
+ // The current issue is that TOSCA allows imports of Definitions only and the repository has the concrete elements as main structure
+ // Although during save the import can be updated (by fetching the associated resource and get the definitions of it),
+ // The concrete definitions cannot be determined without
+ // a) having a complete index of all definitions in the repository
+ // b) crawling through the *complete* repository
+ // Possibly the current solution, just lazily adding all dependent elements is the better solution.
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(NodeTypeImplementationId id) {
+ // We have to use a HashSet to ensure that no duplicate ids are added
+ // There may be multiple DAs/IAs referencing the same type
+ Collection<TOSCAComponentId> ids = new HashSet<>();
+
+ NodeTypeImplementationResource res = new NodeTypeImplementationResource(id);
+
+ // DAs
+ TDeploymentArtifacts deploymentArtifacts = res.getNTI().getDeploymentArtifacts();
+ if (deploymentArtifacts != null) {
+ for (TDeploymentArtifact da : deploymentArtifacts.getDeploymentArtifact()) {
+ QName qname;
+ if ((qname = da.getArtifactRef()) != null) {
+ ids.add(new ArtifactTemplateId(qname));
+ }
+ ids.add(new ArtifactTypeId(da.getArtifactType()));
+ }
+ }
+
+ // IAs
+ TImplementationArtifacts implementationArtifacts = res.getNTI().getImplementationArtifacts();
+ if (implementationArtifacts != null) {
+ for (TImplementationArtifact ia : implementationArtifacts.getImplementationArtifact()) {
+ QName qname;
+ if ((qname = ia.getArtifactRef()) != null) {
+ ids.add(new ArtifactTemplateId(qname));
+ }
+ ids.add(new ArtifactTypeId(ia.getArtifactType()));
+ }
+ }
+
+ // inheritance
+ ids.addAll(this.getReferencedTOSCAComponentIdOfParentForAnAbstractComponentsWithTypeReferenceResource(id));
+
+ return ids;
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(RelationshipTypeImplementationId id) {
+ // We have to use a HashSet to ensure that no duplicate ids are added
+ // There may be multiple IAs referencing the same type
+ Collection<TOSCAComponentId> ids = new HashSet<>();
+
+ RelationshipTypeImplementationResource res = new RelationshipTypeImplementationResource(id);
+
+ // IAs
+ for (TImplementationArtifact ia : res.getRTI().getImplementationArtifacts().getImplementationArtifact()) {
+ QName qname;
+ if ((qname = ia.getArtifactRef()) != null) {
+ ids.add(new ArtifactTemplateId(qname));
+ }
+ ids.add(new ArtifactTypeId(ia.getArtifactType()));
+ }
+
+ // inheritance
+ ids.addAll(this.getReferencedTOSCAComponentIdOfParentForAnAbstractComponentsWithTypeReferenceResource(id));
+
+ return ids;
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(RequirementTypeId id) {
+ Collection<TOSCAComponentId> ids = new ArrayList<>(1);
+
+ RequirementTypeResource res = new RequirementTypeResource(id);
+ QName requiredCapabilityType = res.getRequirementType().getRequiredCapabilityType();
+ if (requiredCapabilityType != null) {
+ CapabilityTypeId capId = new CapabilityTypeId(requiredCapabilityType);
+ ids.add(capId);
+ }
+ return ids;
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(CapabilityTypeId id) {
+ return Collections.emptyList();
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(PolicyTypeId id) {
+ return Collections.emptyList();
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(PolicyTemplateId id) {
+ Collection<TOSCAComponentId> ids = new ArrayList<>();
+ PolicyTemplateResource res = new PolicyTemplateResource(id);
+ ids.add(new PolicyTypeId(res.getType()));
+ return ids;
+ }
+
+ /**
+ * Synchronizes the plan model references and returns the referenced TOSCA
+ * Component Ids.
+ */
+ private Collection<TOSCAComponentId> prepareForExport(ServiceTemplateId id) {
+ // We have to use a HashSet to ensure that no duplicate ids are added
+ // E.g., there may be multiple relationship templates having the same type
+ Collection<TOSCAComponentId> ids = new HashSet<>();
+ ServiceTemplateResource res = new ServiceTemplateResource(id);
+
+ // ensure that the plans stored locally are the same ones as stored in the definitions
+ res.synchronizeReferences();
+
+ // add all plans as reference in the CSAR
+ // the data model is consistent with the repository
+ // we crawl through the repository to as putRefAsReferencedItemInCSAR expects a repository file reference
+ PlansId plansContainerId = new PlansId(id);
+ SortedSet<PlanId> nestedPlans = Repository.INSTANCE.getNestedIds(plansContainerId, PlanId.class);
+ for (PlanId planId : nestedPlans) {
+ SortedSet<RepositoryFileReference> containedFiles = Repository.INSTANCE.getContainedFiles(planId);
+ // even if we currently support only one file in the directory, we just add everything
+ for (RepositoryFileReference ref : containedFiles) {
+ this.putRefAsReferencedItemInCSAR(ref);
+ }
+ }
+
+ // add included things to export queue
+
+ TBoundaryDefinitions boundaryDefs;
+ if ((boundaryDefs = res.getServiceTemplate().getBoundaryDefinitions()) != null) {
+ Policies policies = boundaryDefs.getPolicies();
+ if (policies != null) {
+ for (TPolicy policy : policies.getPolicy()) {
+ PolicyTypeId policyTypeId = new PolicyTypeId(policy.getPolicyType());
+ ids.add(policyTypeId);
+ }
+ }
+
+ // reqs and caps don't have to be exported here as they are references to existing reqs/caps (of nested node templates)
+ }
+
+ if (res.getServiceTemplate().getTopologyTemplate() != null) {
+ for (TEntityTemplate entityTemplate : res.getServiceTemplate().getTopologyTemplate().getNodeTemplateOrRelationshipTemplate()) {
+ QName qname = entityTemplate.getType();
+ if (entityTemplate instanceof TNodeTemplate) {
+ ids.add(new NodeTypeId(qname));
+ TNodeTemplate n = (TNodeTemplate) entityTemplate;
+
+ // crawl through deployment artifacts
+ TDeploymentArtifacts deploymentArtifacts = n.getDeploymentArtifacts();
+ if (deploymentArtifacts != null) {
+ List<TDeploymentArtifact> das = deploymentArtifacts.getDeploymentArtifact();
+ for (TDeploymentArtifact da : das) {
+ ids.add(new ArtifactTypeId(da.getArtifactType()));
+ if ((qname = da.getArtifactRef()) != null) {
+ ids.add(new ArtifactTemplateId(qname));
+ }
+ }
+ }
+
+ // crawl through reqs/caps
+ Requirements requirements = n.getRequirements();
+ if (requirements != null) {
+ for (TRequirement req : requirements.getRequirement()) {
+ QName type = req.getType();
+ RequirementTypeId rtId = new RequirementTypeId(type);
+ ids.add(rtId);
+ }
+ }
+ Capabilities capabilities = n.getCapabilities();
+ if (capabilities != null) {
+ for (TCapability cap : capabilities.getCapability()) {
+ QName type = cap.getType();
+ CapabilityTypeId ctId = new CapabilityTypeId(type);
+ ids.add(ctId);
+ }
+ }
+
+ // crawl through policies
+ org.eclipse.winery.model.tosca.TNodeTemplate.Policies policies = n.getPolicies();
+ if (policies != null) {
+ for (TPolicy pol : policies.getPolicy()) {
+ QName type = pol.getPolicyType();
+ PolicyTypeId ctId = new PolicyTypeId(type);
+ ids.add(ctId);
+ }
+ }
+ } else {
+ assert (entityTemplate instanceof TRelationshipTemplate);
+ ids.add(new RelationshipTypeId(qname));
+ }
+ }
+ }
+
+ return ids;
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(ArtifactTypeId id) {
+ // no recursive crawling needed
+ return Collections.emptyList();
+ }
+
+ /**
+ * Determines the referenced TOSCA Component Ids and also updates the
+ * references in the Artifact Template
+ *
+ * @return a collection of referenced TOCSA Component Ids
+ */
+ private Collection<TOSCAComponentId> prepareForExport(ArtifactTemplateId id) {
+ Collection<TOSCAComponentId> ids = new ArrayList<>();
+
+ ArtifactTemplateResource res = new ArtifactTemplateResource(id);
+
+ // "Export" type
+ QName type = res.getType();
+ if (type == null) {
+ throw new IllegalStateException("Type is null for " + id.toString());
+ }
+ ids.add(new ArtifactTypeId(type));
+
+ // Export files
+
+ // This method is called BEFORE the concrete definitions element is written.
+ // Therefore, we adapt the content of the attached files to the really existing files
+ res.synchronizeReferences();
+
+ ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId(id);
+ SortedSet<RepositoryFileReference> files = Repository.INSTANCE.getContainedFiles(fileDir);
+ for (RepositoryFileReference ref : files) {
+ // Even if writing a TOSCA only (!this.writingCSAR),
+ // we put the virtual path in the TOSCA
+ // Reason: Winery is mostly used as a service and local storage
+ // reference to not make sense
+ // The old implementation had absolutePath.toUri().toString();
+ // there, but this does not work when using a cloud blob store.
+
+ this.putRefAsReferencedItemInCSAR(ref);
+ }
+
+ return ids;
+ }
+
+ /**
+ * Puts the given reference as item in the CSAR
+ *
+ * Thereby, it uses the global variable referencesToPathInCSARMap
+ */
+ private void putRefAsReferencedItemInCSAR(RepositoryFileReference ref) {
+ // Determine path
+ String path = BackendUtils.getPathInsideRepo(ref);
+
+ // put mapping reference to path into global map
+ // the path is the same as put in "synchronizeReferences"
+ this.referencesToPathInCSARMap.put(ref, path);
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(RelationshipTypeId id) {
+ Collection<TOSCAComponentId> ids = new ArrayList<>();
+
+ // add all implementations
+ Collection<RelationshipTypeImplementationId> allTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(RelationshipTypeImplementationId.class, id.getQName());
+ for (RelationshipTypeImplementationId ntiId : allTypeImplementations) {
+ ids.add(ntiId);
+ }
+
+ RelationshipTypeResource res = new RelationshipTypeResource(id);
+ TRelationshipType relationshipType = (TRelationshipType) res.getElement();
+
+ ValidSource validSource = relationshipType.getValidSource();
+ if (validSource != null) {
+ QName typeRef = validSource.getTypeRef();
+ // can be a node type or a requirement type
+
+ // similar code as for valid target (difference: req/cap)
+ NodeTypeId ntId = new NodeTypeId(typeRef);
+ if (Repository.INSTANCE.exists(ntId)) {
+ ids.add(ntId);
+ } else {
+ RequirementTypeId rtId = new RequirementTypeId(typeRef);
+ ids.add(rtId);
+ }
+ }
+
+ ValidTarget validTarget = relationshipType.getValidTarget();
+ if (validTarget != null) {
+ QName typeRef = validTarget.getTypeRef();
+ // can be a node type or a capability type
+
+ // similar code as for valid target (difference: req/cap)
+ NodeTypeId ntId = new NodeTypeId(typeRef);
+ if (Repository.INSTANCE.exists(ntId)) {
+ ids.add(ntId);
+ } else {
+ CapabilityTypeId capId = new CapabilityTypeId(typeRef);
+ ids.add(capId);
+ }
+ }
+
+ this.addVisualAppearanceToCSAR(id);
+
+ return ids;
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(NodeTypeId id) {
+ Collection<TOSCAComponentId> ids = new ArrayList<>();
+ Collection<NodeTypeImplementationId> allNodeTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, id.getQName());
+ for (NodeTypeImplementationId ntiId : allNodeTypeImplementations) {
+ ids.add(ntiId);
+ }
+
+ NodeTypeResource res = new NodeTypeResource(id);
+ TNodeType nodeType = (TNodeType) res.getElement();
+
+ // add all referenced requirement types
+ RequirementDefinitions reqDefsContainer = nodeType.getRequirementDefinitions();
+ if (reqDefsContainer != null) {
+ List<TRequirementDefinition> reqDefs = reqDefsContainer.getRequirementDefinition();
+ for (TRequirementDefinition reqDef : reqDefs) {
+ RequirementTypeId reqTypeId = new RequirementTypeId(reqDef.getRequirementType());
+ ids.add(reqTypeId);
+ }
+ }
+
+ // add all referenced capability types
+ CapabilityDefinitions capDefsContainer = nodeType.getCapabilityDefinitions();
+ if (capDefsContainer != null) {
+ List<TCapabilityDefinition> capDefs = capDefsContainer.getCapabilityDefinition();
+ for (TCapabilityDefinition capDef : capDefs) {
+ CapabilityTypeId capTypeId = new CapabilityTypeId(capDef.getCapabilityType());
+ ids.add(capTypeId);
+ }
+ }
+
+ this.addVisualAppearanceToCSAR(id);
+
+ return ids;
+ }
+
+ private void addVisualAppearanceToCSAR(TopologyGraphElementEntityTypeId id) {
+ VisualAppearanceId visId = new VisualAppearanceId(id);
+ if (Repository.INSTANCE.exists(visId)) {
+ // we do NOT check for the id, but simply check for bigIcon.png (only exists in NodeType) and smallIcon.png (exists in NodeType and RelationshipType)
+
+ RepositoryFileReference ref = new RepositoryFileReference(visId, Filename.FILENAME_BIG_ICON);
+ if (Repository.INSTANCE.exists(ref)) {
+ this.referencesToPathInCSARMap.put(ref, BackendUtils.getPathInsideRepo(ref));
+ }
+
+ ref = new RepositoryFileReference(visId, Filename.FILENAME_SMALL_ICON);
+ if (Repository.INSTANCE.exists(ref)) {
+ this.referencesToPathInCSARMap.put(ref, BackendUtils.getPathInsideRepo(ref));
+ }
+ }
+ }
+
+}