Java tutorial
/******************************************************************************* * 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: * Klmn Kpes - initial API and implementation and/or initial documentation * Oliver Kopp - adapted to new storage model and to TOSCA v1.0 *******************************************************************************/ /* * Modifications Copyright 2016 ZTE Corporation. */ 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.GroupTypeId; 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.TGroupTemplate; import org.eclipse.winery.model.tosca.TGroupTemplates; 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.model.tosca.TTarget; 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.ext.export.custom.DefinitionResultInfo; import org.eclipse.winery.repository.ext.export.custom.ExportFileGenerator; import org.eclipse.winery.repository.ext.export.yaml.YamlExportFileGenerator; 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.grouptypes.GroupTypeResource; 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; private ArrayList<DefinitionResultInfo> yamlExportDefResultList = new ArrayList<DefinitionResultInfo>(); private String yamlEntryDefinitionsReference = null; 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, ExportFileGenerator extendPoint) throws IOException, JAXBException { this.exportConfiguration = exportConfiguration; this.initializeExport(); return this.writeDefinitionsElement(id, out, extendPoint); } 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, ExportFileGenerator extendPoint) throws IOException, JAXBException { this.referencesToPathInCSARMap = referencesToPathInCSARMap; return this.exportTOSCA(id, out, exportConfiguration, extendPoint); } /** * 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, ExportFileGenerator extendPoint) 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); if (!isValueExist(this.referencesToPathInCSARMap, 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 if (extendPoint != null) { extendPoint.setArchiveFiles(this.yamlExportDefResultList); DefinitionResultInfo[] fileResultInfos = extendPoint.makeFile(entryDefinitions, out); if (extendPoint instanceof YamlExportFileGenerator) { if (Utils.isServiceTemplateDefinition(entryDefinitions)) { this.yamlEntryDefinitionsReference = fileResultInfos[0].getFileFullName(); } for (DefinitionResultInfo fileResult : fileResultInfos) { yamlExportDefResultList.add(fileResult); } } } else this.writeDefinitionsElement(entryDefinitions, out); return referencedTOSCAComponentIds; } public String getYamlEntryDefinitionsReference() { return yamlEntryDefinitionsReference; } public ArrayList<DefinitionResultInfo> getYamlExportDefResultList() { return yamlExportDefResultList; } private boolean isValueExist(Map<RepositoryFileReference, String> refMap, String value) { for (RepositoryFileReference ref : refMap.keySet()) { if (refMap.get(ref).equals(value)) return true; } return false; } 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 if (id instanceof GroupTypeId) { referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((GroupTypeId) id); } 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(); QName substitutableNodeType = res.getServiceTemplate().getSubstitutableNodeType(); if (null != substitutableNodeType) { ids.add(new NodeTypeId(substitutableNodeType)); } ids.addAll(getGroupTypeIds(res)); // 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); QName policyTemplateRef = policy.getPolicyRef(); if (null != policyTemplateRef) { PolicyTemplateId policyTemplateId = new PolicyTemplateId(policyTemplateRef); ids.add(policyTemplateId); } } } // 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<GroupTypeId> getGroupTypeIds(ServiceTemplateResource res) { Map<String, GroupTypeId> map = new HashMap<String, GroupTypeId>(); TGroupTemplates groupTemplates = res.getServiceTemplate().getGroupTemplates(); if (null != groupTemplates) { List<TGroupTemplate> groups = groupTemplates.getGroupTemplates(); if (null != groups && !groups.isEmpty()) { for (TGroupTemplate group : groups) { QName type = group.getType(); map.put(type.toString(), new GroupTypeId(type)); } } } return map.values(); } 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 Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(GroupTypeId id) { GroupTypeResource groupRes = new GroupTypeResource(id); TTarget targets = groupRes.getGroupType().getTargets(); if (null == targets || null == targets.getTarget()) { return Collections.emptyList(); } Collection<TOSCAComponentId> ids = new ArrayList<TOSCAComponentId>(); Map<String, TOSCAComponentId> nodeTypeMap = new HashMap<String, TOSCAComponentId>(); SortedSet<NodeTypeId> allNodeTypes = Repository.INSTANCE.getAllTOSCAComponentIds(NodeTypeId.class); for (NodeTypeId nodeId : allNodeTypes) { NodeTypeResource res = new NodeTypeResource(nodeId); nodeTypeMap.put(res.getNodeType().getName(), nodeId); } for (String target : targets.getTarget()) { if (nodeTypeMap.containsKey(target)) { ids.add(nodeTypeMap.get(target)); } } 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)); } } } }