Skip to content

Commit

Permalink
Feature Pattern Refinement (#367)
Browse files Browse the repository at this point in the history
* create Pattern Refinement Models (PRMs)
* refine Topologies using PRMs semi-automatically
  • Loading branch information
lharzenetter committed Sep 12, 2018
1 parent 5c9e5ff commit 7fb91d0
Show file tree
Hide file tree
Showing 154 changed files with 4,035 additions and 997 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import org.eclipse.winery.common.ids.definitions.EntityTemplateId;
import org.eclipse.winery.common.ids.definitions.EntityTypeId;
import org.eclipse.winery.common.ids.definitions.EntityTypeImplementationId;
import org.eclipse.winery.common.ids.definitions.PatternRefinementModelId;
import org.eclipse.winery.common.ids.definitions.PolicyTemplateId;
import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
import org.eclipse.winery.common.ids.definitions.imports.GenericImportId;
Expand Down Expand Up @@ -521,6 +522,8 @@ public static boolean instanceSupportsNameAttribute(Class<? extends DefinitionsC
return true;
} else if (ComplianceRuleId.class.isAssignableFrom(idClass)) {
return true;
} else if (PatternRefinementModelId.class.isAssignableFrom(idClass)) {
return true;
} else if ((EntityTypeId.class.isAssignableFrom(idClass)) || (EntityTypeImplementationId.class.isAssignableFrom(idClass))) {
// name is available, but no id attribute
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ public abstract class DefinitionsChildId extends GenericId {
RelationshipTypeImplementationId.class,
RequirementTypeId.class,
ServiceTemplateId.class,
ComplianceRuleId.class
ComplianceRuleId.class,
PatternRefinementModelId.class
);

private final Namespace namespace;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/********************************************************************************
* 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.common.ids.definitions;

import javax.xml.namespace.QName;

import org.eclipse.winery.common.ids.Namespace;
import org.eclipse.winery.common.ids.XmlId;

public class PatternRefinementModelId extends DefinitionsChildId {

public PatternRefinementModelId(Namespace namespace, XmlId xmlId) {
super(namespace, xmlId);
}

public PatternRefinementModelId(String ns, String id, boolean URLencoded) {
super(ns, id, URLencoded);
}

public PatternRefinementModelId(QName type) {
super(type);
}

@Override
public String getGroup() {
return "PatternRefinementModel";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.eclipse.winery.common.ids.definitions.DefinitionsChildId;
import org.eclipse.winery.common.ids.definitions.NodeTypeId;
import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId;
import org.eclipse.winery.common.ids.definitions.PatternRefinementModelId;
import org.eclipse.winery.common.ids.definitions.PolicyTemplateId;
import org.eclipse.winery.common.ids.definitions.PolicyTypeId;
import org.eclipse.winery.common.ids.definitions.RelationshipTypeId;
Expand All @@ -45,6 +46,7 @@
import org.eclipse.winery.model.tosca.TEntityType;
import org.eclipse.winery.model.tosca.TNodeType;
import org.eclipse.winery.model.tosca.TNodeTypeImplementation;
import org.eclipse.winery.model.tosca.TPatternRefinementModel;
import org.eclipse.winery.model.tosca.TPolicyTemplate;
import org.eclipse.winery.model.tosca.TPolicyType;
import org.eclipse.winery.model.tosca.TRelationshipType;
Expand Down Expand Up @@ -126,6 +128,10 @@ default TComplianceRule getElement(ComplianceRuleId id) {
return (TComplianceRule) this.getDefinitions(id).getElement();
}

default TPatternRefinementModel getElement(PatternRefinementModelId id) {
return (TPatternRefinementModel) this.getDefinitions(id).getElement();
}

/**
* Deletes the TOSCA element <b>and all sub elements</b> referenced by the given id from the repository
* <p>
Expand Down
35 changes: 35 additions & 0 deletions org.eclipse.winery.common/src/main/resources/TOSCA-v1.0.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
See https://github.com/eclipse/winery/issues/71 for a discussion.
- `processContents="lax"` was added to Properties at Boundary definitions.
- Make "Types" in "<Definitions>" valid as the only nested element in "<Definitions>"
- Add "PatternRefinementModels"
-->
<xs:schema targetNamespace="http://docs.oasis-open.org/tosca/ns/2011/12" elementFormDefault="qualified"
attributeFormDefault="unqualified" xmlns="http://docs.oasis-open.org/tosca/ns/2011/12"
Expand Down Expand Up @@ -80,6 +81,7 @@
<xs:element name="ArtifactTemplate" type="tArtifactTemplate"/>
<xs:element name="PolicyType" type="tPolicyType"/>
<xs:element name="PolicyTemplate" type="tPolicyTemplate"/>
<xs:element name="PatternRefinementModel" type="tPatternRefinementModel"/>
</xs:choice>
</xs:sequence>
<xs:attribute name="id" type="xs:ID" use="required"/>
Expand Down Expand Up @@ -791,6 +793,39 @@
<xs:complexType name="tRequiredContainerFeature">
<xs:attribute name="feature" type="xs:anyURI" use="required"/>
</xs:complexType>
<xs:complexType name="tPatternRefinementModel">
<xs:complexContent>
<xs:extension base="tExtensibleElements">
<xs:sequence>
<xs:element name="Detector" type="tTopologyTemplate"/>
<xs:element name="RefinementStructure" type="tTopologyTemplate"/>
<xs:element name="RelationMappings">
<xs:complexType>
<xs:sequence>
<xs:element name="RelationMapping" type="tRelationMapping" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="optional"/>
<xs:attribute name="targetNamespace" type="xs:anyURI"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="tRelationMapping">
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="detectorNode" type="xs:string" use="required"/>
<xs:attribute name="refinementNode" type="xs:string" use="required"/>
<xs:attribute name="relationType" type="xs:QName" use="required"/>
<xs:attribute name="direction" type="tDirection" use="required"/>
<xs:attribute name="validSourceOrTarget" type="xs:QName"/>
</xs:complexType>
<xs:simpleType name="tDirection">
<xs:restriction base="xs:string">
<xs:enumeration value="ingoing"/>
<xs:enumeration value="outgoing"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="tBoolean">
<xs:restriction base="xs:string">
<xs:enumeration value="yes"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.eclipse.winery.model.substitution;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.xml.namespace.QName;

import org.eclipse.winery.common.ids.definitions.NodeTypeId;
import org.eclipse.winery.common.ids.definitions.RelationshipTypeId;
import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
import org.eclipse.winery.common.version.VersionUtils;
import org.eclipse.winery.model.tosca.TNodeType;
import org.eclipse.winery.model.tosca.TRelationshipType;
import org.eclipse.winery.repository.backend.IRepository;
import org.eclipse.winery.repository.backend.RepositoryFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AbstractSubstitution {

private static final Logger LOGGER = LoggerFactory.getLogger(Substitution.class);

protected final IRepository repository;
protected final Map<QName, TNodeType> nodeTypes = new HashMap<>();
protected final Map<QName, TRelationshipType> relationshipTypes = new HashMap<>();

protected String versionAppendix = "substituted";

public AbstractSubstitution() {
this.repository = RepositoryFactory.getRepository();
this.loadDefinitions();
}

private void loadDefinitions() {
this.repository.getAllDefinitionsChildIds(NodeTypeId.class)
.forEach(id ->
this.nodeTypes.put(id.getQName(), this.repository.getElement(id))
);

this.repository.getAllDefinitionsChildIds(RelationshipTypeId.class)
.forEach(id ->
this.relationshipTypes.put(id.getQName(), this.repository.getElement(id))
);
}

/**
* Creates a new version of the given Service Template for the substitution.
* If no new version can be created, the given Service Template will be returned.
*
* @param serviceTemplateId the Service Template containing abstract types to be substituted
* @return the new Id of the Service Template
*/
protected ServiceTemplateId getSubstitutionServiceTemplateId(ServiceTemplateId serviceTemplateId) {
try {
ServiceTemplateId substitutedServiceTemplateId = new ServiceTemplateId(
serviceTemplateId.getNamespace().getDecoded(),
VersionUtils.getNewId(serviceTemplateId, versionAppendix),
false
);

repository.duplicate(serviceTemplateId, substitutedServiceTemplateId);
LOGGER.debug("Created new Service Template version {}", substitutedServiceTemplateId);

return substitutedServiceTemplateId;
} catch (IOException e) {
LOGGER.debug("Could not create new Service Template version during substitution", e);
LOGGER.debug("Reusing existing element");
}

return serviceTemplateId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,12 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.xml.namespace.QName;

import org.eclipse.winery.common.ids.definitions.CapabilityTypeId;
import org.eclipse.winery.common.ids.definitions.NodeTypeId;
import org.eclipse.winery.common.ids.definitions.RelationshipTypeId;
import org.eclipse.winery.common.ids.definitions.RequirementTypeId;
import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
import org.eclipse.winery.common.version.VersionUtils;
import org.eclipse.winery.model.tosca.TCapabilityRef;
import org.eclipse.winery.model.tosca.TCapabilityType;
import org.eclipse.winery.model.tosca.TNodeTemplate;
Expand All @@ -41,29 +37,18 @@
import org.eclipse.winery.model.tosca.TServiceTemplate;
import org.eclipse.winery.model.tosca.TTopologyTemplate;
import org.eclipse.winery.repository.backend.BackendUtils;
import org.eclipse.winery.repository.backend.IRepository;
import org.eclipse.winery.repository.backend.RepositoryFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Substitution {
public class Substitution extends AbstractSubstitution {

private static final Logger LOGGER = LoggerFactory.getLogger(Substitution.class);
private static final String versionAppendix = "substituted";

private final IRepository repository;

private final Map<QName, TServiceTemplate> nodeTypeSubstitutableWithServiceTemplate = new HashMap<>();
private final Map<QName, TRelationshipType> relationshipTypes = new HashMap<>();
private final Map<QName, TNodeType> nodeTypes = new HashMap<>();
private final Map<QName, TRequirementType> requirementTypes = new HashMap<>();
private final Map<QName, TCapabilityType> capabilityTypes = new HashMap<>();

public Substitution() {
repository = RepositoryFactory.getRepository();
}

public ServiceTemplateId substituteTopologyOfServiceTemplate(final ServiceTemplateId serviceTemplateId) {
// 0. Create a new version of the Service Template
ServiceTemplateId substitutedServiceTemplateId = getSubstitutionServiceTemplateId(serviceTemplateId);
Expand Down Expand Up @@ -213,54 +198,15 @@ private void replaceNodeTemplateWithServiceTemplate(TTopologyTemplate topologyTe
});
}

/**
* Creates a new version of the given Service Template for the substitution. If no new version can be created, the
* given Service Template will be returned.
*
* @param serviceTemplateId the Service Template containing abstract types to be substituted
* @return the new Id of the Service Template
*/
private ServiceTemplateId getSubstitutionServiceTemplateId(ServiceTemplateId serviceTemplateId) {
try {
ServiceTemplateId substitutedServiceTemplateId = new ServiceTemplateId(
serviceTemplateId.getNamespace().getDecoded(),
VersionUtils.getNewId(serviceTemplateId, versionAppendix),
false
);

repository.duplicate(serviceTemplateId, substitutedServiceTemplateId);
LOGGER.debug("Created new Service Template version {}", substitutedServiceTemplateId);

return substitutedServiceTemplateId;
} catch (IOException e) {
LOGGER.debug("Could not create new Service Template version during substitution", e);
LOGGER.debug("Reusing existing element");
}

return serviceTemplateId;
}

private void loadAllRequiredDefinitionsForTopologySubstitution() {
List<TServiceTemplate> serviceTemplates = this.repository.getAllDefinitionsChildIds(ServiceTemplateId.class)
this.repository.getAllDefinitionsChildIds(ServiceTemplateId.class)
.stream()
.map(repository::getElement).collect(Collectors.toList());

serviceTemplates.stream()
.map(repository::getElement)
.filter(element -> Objects.nonNull(element.getSubstitutableNodeType()))
.forEach(tServiceTemplate ->
this.nodeTypeSubstitutableWithServiceTemplate.put(tServiceTemplate.getSubstitutableNodeType(), tServiceTemplate)
);

this.repository.getAllDefinitionsChildIds(NodeTypeId.class)
.forEach(id ->
this.nodeTypes.put(id.getQName(), this.repository.getElement(id))
);

this.repository.getAllDefinitionsChildIds(RelationshipTypeId.class)
.forEach(id ->
this.relationshipTypes.put(id.getQName(), this.repository.getElement(id))
);

this.repository.getAllDefinitionsChildIds(RequirementTypeId.class)
.forEach(id ->
this.requirementTypes.put(id.getQName(), this.repository.getElement(id))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@
import org.eclipse.winery.model.tosca.HasInheritance;
import org.eclipse.winery.model.tosca.HasType;
import org.eclipse.winery.model.tosca.TBoolean;
import org.eclipse.winery.model.tosca.TNodeTemplate;
import org.eclipse.winery.model.tosca.TNodeType;
import org.eclipse.winery.repository.backend.NamespaceManager;
import org.eclipse.winery.repository.backend.RepositoryFactory;

public class SubstitutionUtils {

/**
* This method collects all templates of the given <code>templates</code> which must be substituted. Additionally, all children
* of the template's type are included as a list of trees.
* This method collects all templates of the given <code>templates</code> which are abstract and must be substituted.
* Additionally, all children of the template's type are included as a list of trees.
*
* @param templates the list of TOSCA templates which have to examied whether they must be substituted
* @param types the map of all types of the same kind (e.g. Node Templates and Node Types) identified by their corresponding <code>DefinitionsChildId</code>
Expand All @@ -54,11 +58,11 @@ public static <R extends HasType, T extends HasInheritance> Map<R, List<Subtypes
}

/**
* This method collects all elements of the given class <code>T</code> which are derived from the <code>nodeType</code>.
* This method collects all elements of the given class <code>T</code> which are derived from the <b>abstract</b> <code>parent</code>.
*
* @param <T> a TOSCA definitions type which has inheritance
* @param types all available types of the specified class <code>T</code>
* @param parent the parent
* @param parent abstract the parent
* @return an <code>Optional</code> containing a tree of subtypes
*/
public static <T extends HasInheritance> Optional<List<Subtypes<T>>> collectTypeHierarchy(Map<QName, T> types, QName parent) {
Expand All @@ -79,4 +83,14 @@ public static <T extends HasInheritance> Optional<List<Subtypes<T>>> collectType

return Optional.empty();
}

public static boolean containsPatterns(List<TNodeTemplate> topologyNodes, Map<QName, TNodeType> nodeTypes) {
NamespaceManager namespaceManager = RepositoryFactory.getRepository().getNamespaceManager();

return topologyNodes.stream()
.anyMatch(nodeTemplate -> {
TNodeType tNodeType = nodeTypes.get(nodeTemplate.getType());
return namespaceManager.isPatternNamespace(tNodeType.getTargetNamespace());
});
}
}

0 comments on commit 7fb91d0

Please sign in to comment.