blob: 308315eb8c57d45c25b4cae88f0546c274fc16dd [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2017 CEA LIST.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* CEA LIST - Initial API and implementation
*****************************************************************************/
package org.eclipse.papyrus.moka.modeling.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.uml2.uml.Class ;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.InstanceValue;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PrimitiveType;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Slot;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.ValueSpecification;
/**
* A utility class for the generation of an instance specification tree
*
*/
public class InstanceSpecificationGeneratorUtil {
/**
* The container for the generated instance specifications
*/
protected Package rootContainer ;
/**
* An index map used for the generation of unique instance names
*/
protected Map<Classifier, Integer> indexes = new HashMap<Classifier, Integer>() ;
/**
* Constructor
*
* @param rootContainer The root container for the generated instances
*/
public InstanceSpecificationGeneratorUtil(Package rootContainer) {
super();
this.rootContainer = rootContainer;
}
/**
* Generates a tree of instance specification, where the root of the tree is typed by the given classifier.
* Instances can be generated recursively if the given classifier owns composite parts which are typed by a Class.
* All instance specifications are generated inside the package given as an argument of the constructor.
* For a given property of the classifier, a slot is generated only if canGenerateSlot returns true.
* For a given slot, a value is generated only if canGenerateNewValue returns true.
*
* @param classifier The type of the root instance specification to be generated
* @return The root instance specification generated
*/
public InstanceSpecification generateInstanceSpecification(Classifier classifier) {
return generateInstanceSpecification(classifier, new ArrayList<Classifier>()) ;
}
/**
* See generateInstanceSpecification(Classifier classifier).
*
* @param classifier The type of the root instance specification to be generated
* @param visited A list of "visited" classifiers, completed at each recursive call, to avoid infinite recursions
* @return The root instance specification generated
*/
protected InstanceSpecification generateInstanceSpecification(Classifier classifier, List<Classifier> visited) {
visited.add(classifier) ;
String instanceSpecName = this.generateInstanceName(classifier) ;
InstanceSpecification instanceSpec = (InstanceSpecification)this.rootContainer.createPackagedElement(instanceSpecName, UMLPackage.eINSTANCE.getInstanceSpecification()) ;
instanceSpec.getClassifiers().add(classifier) ;
for (Property p : classifier.getAllAttributes()) {
if (this.canGenerateSlot(classifier, p)) {
Slot slot = instanceSpec.createSlot() ;
slot.setDefiningFeature(p);
if (p.getDefaultValue() != null) {
ValueSpecification v = p.getDefaultValue() ;
ValueSpecification copy = EcoreUtil.copy(v) ;
slot.getValues().add(copy) ;
copy.setName("valueFor " + p.getName());
}
else {
if (this.canGenerateNewValue(classifier, p)) {
Type type = p.getType() ;
if (type instanceof Enumeration || type instanceof PrimitiveType) {
generateValueSpecification(slot) ;
}
else {
if (! visited.contains(type)) {
List<Classifier> newVisited = new ArrayList<Classifier>() ;
newVisited.addAll(visited) ;
InstanceValue instanceValue = (InstanceValue)slot.createValue("valueFor " + p.getName(), type, UMLPackage.eINSTANCE.getInstanceValue());
InstanceSpecification generatedInstanceSpec = this.generateInstanceSpecification((Classifier)p.getType(), newVisited) ;
instanceValue.setInstance(generatedInstanceSpec);
}
}
}
}
}
}
return instanceSpec ;
}
/**
* Generate and assign a value specification to a slot, in the case where the defining feature of the slot
* is typed by an Enumeration or a PrimitiveType
*
* @param slot
* @return The generated value specification, which has been assigned to the given slot
*/
protected ValueSpecification generateValueSpecification(Slot slot) {
Property p = (Property)slot.getDefiningFeature() ;
Type type = p.getType() ;
ValueSpecification v = null ;
if (type instanceof Enumeration) {
v = slot.createValue("valueFor " + p.getName(), type, UMLPackage.eINSTANCE.getInstanceValue());
}
else if (type instanceof PrimitiveType) {
String name = "" + type.getName() ;
if (name.equals("Integer")) {
v = slot.createValue("valueFor " + p.getName(), type, UMLPackage.eINSTANCE.getLiteralInteger());
} else if (name.equals("Boolean")) { //$NON-NLS-1$
v = slot.createValue("valueFor " + p.getName(), type, UMLPackage.eINSTANCE.getLiteralBoolean());
} else if (name.equals("Real")) { //$NON-NLS-1$
v = slot.createValue("valueFor " + p.getName(), type, UMLPackage.eINSTANCE.getLiteralReal());
} else if (name.equals("String")){
v = slot.createValue("valueFor " + p.getName(), type, UMLPackage.eINSTANCE.getLiteralString());
}
}
return v ;
}
/**
* Generate an instance name, based on a given classifier
*
* @param classifier
* @return The generated instance name
*/
protected String generateInstanceName(Classifier classifier) {
int index = 0;
if (this.indexes.get(classifier) == null) {
index = 1 ;
}
this.indexes.put(classifier, index + 1) ;
return "" + classifier.getName().toLowerCase() + " " + index;
}
/**
* Determines if it is allowed to generate a slot for the given property.
* It always returns true, but it can be overridden by clients.
*
* @param contextClassifier
* @param property
* @return always true (but can be overridden by clients)
*/
protected boolean canGenerateSlot(Classifier contextClassifier, Property property) {
return true ;
}
/**
* Determines if it is allowed to generate a value for the given property.
* If the property is typed by a class, it returns true if the property is composite.
* If the property is not typed by a class, it returns true.
* It returns false only if the property is not typed.
*
* @param contextClassifier
* @param property
* @return true if it is allowed to generate a value for the given property, false otherwise
*/
protected boolean canGenerateNewValue(Classifier contextClassifier, Property property) {
if (property.getType() != null) {
if (property.getType() instanceof Class) {
return property.isComposite() ;
}
return true ;
}
return false ;
}
}