blob: 9065246f374237e20a6068c0bcb0c412b141a15f [file] [log] [blame]
/*
* Copyright (c) 2011, 2014 CEA and others.
* 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:
* Kenn Hussey (CEA) - initial API and implementation
* Kenn Hussey (CEA) - 351774, 405374, 418466
*
*/
package org.eclipse.uml2.uml.resource;
import java.io.InputStream;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.eclipse.uml2.common.util.UML2Util;
import org.eclipse.uml2.uml.Activity;
import org.eclipse.uml2.uml.ActivityGroup;
import org.eclipse.uml2.uml.ActivityNode;
import org.eclipse.uml2.uml.Behavior;
import org.eclipse.uml2.uml.BehavioredClassifier;
import org.eclipse.uml2.uml.CallEvent;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.ComponentRealization;
import org.eclipse.uml2.uml.Connector;
import org.eclipse.uml2.uml.Dependency;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.EnumerationLiteral;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.InteractionUse;
import org.eclipse.uml2.uml.Message;
import org.eclipse.uml2.uml.MessageOccurrenceSpecification;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.OccurrenceSpecification;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.ProfileApplication;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.SignalEvent;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.uml2.uml.StructuredActivityNode;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.UMLPlugin;
import org.eclipse.uml2.uml.util.UMLSwitch;
import org.eclipse.uml2.uml.util.UMLUtil;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.InternalEList;
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.BasicResourceHandler;
import org.eclipse.emf.ecore.xml.type.AnyType;
/**
* Resource handler that converts .uml models.
* OMG: UML 2.2 and UML 2.4
* API: UML2 3.x and UML2 4.0
*
* @since 4.0
*/
public class UML302UMLResourceHandler
extends BasicResourceHandler {
protected static final boolean DEBUG = true;
protected static final String STEREOTYPE__BEHAVIORED_CLASSIFIER = "BehavioredClassifier"; //$NON-NLS-1$
protected static final String STEREOTYPE__INTERACTION_USE = "InteractionUse"; //$NON-NLS-1$
protected static final String TAG_DEFINITION__ARGUMENT = "argument"; //$NON-NLS-1$
protected static final String TAG_DEFINITION__OWNED_TRIGGER = "ownedTrigger"; //$NON-NLS-1$
protected boolean resolveProxies = true;
protected String xmiVersion = null;
protected AnyType getExtension(XMLResource resource, EObject eObject) {
return resource.getEObjectToExtensionMap().get(eObject);
}
protected AnyType putExtension(XMLResource resource, EObject eObject,
AnyType extension) {
return resource.getEObjectToExtensionMap().put(eObject, extension);
}
protected AnyType removeExtension(XMLResource resource, EObject eObject) {
return resource.getEObjectToExtensionMap().remove(eObject);
}
protected Object getValue(FeatureMap featureMap, String name) {
return getValue(featureMap, name, false);
}
protected Object getValue(FeatureMap featureMap, String name, boolean remove) {
for (Iterator<FeatureMap.Entry> entries = featureMap.iterator(); entries
.hasNext();) {
FeatureMap.Entry entry = entries.next();
if (name.equals(entry.getEStructuralFeature().getName())) {
if (remove) {
entries.remove();
}
return entry.getValue();
}
}
return null;
}
private EObject getEObject(AnyType extension, Resource resource,
String name, boolean remove) {
if (extension != null) {
Object value = getValue(extension.getAnyAttribute(), name, remove);
if (value == null) {
value = getValue(extension.getMixed(), name, remove);
if (value instanceof EObject) {
return (EObject) value;
}
} else if (value instanceof String && resource != null) {
return resource.getEObject((String) value);
}
}
return null;
}
protected Collection<Object> getValues(FeatureMap featureMap, String name) {
return getValues(featureMap, name, false);
}
protected Collection<Object> getValues(FeatureMap featureMap, String name,
boolean remove) {
Collection<Object> values = new UniqueEList.FastCompare<Object>();
for (Iterator<FeatureMap.Entry> entries = featureMap.iterator(); entries
.hasNext();) {
FeatureMap.Entry entry = entries.next();
if (name.equals(entry.getEStructuralFeature().getName())) {
if (remove) {
entries.remove();
}
values.add(entry.getValue());
}
}
return values;
}
private Collection<EObject> getEObjects(AnyType extension,
Resource resource, String name, boolean remove) {
Collection<EObject> eObjects = new UniqueEList.FastCompare<EObject>();
if (extension != null) {
Collection<Object> values = getValues(extension.getAnyAttribute(),
name, remove);
if (values.isEmpty()) {
values = getValues(extension.getMixed(), name, remove);
for (Object value : values) {
if (value instanceof EObject) {
eObjects.add((EObject) value);
}
}
} else if (resource != null) {
for (Object value : values) {
if (value instanceof String) {
EObject eObject = resource.getEObject((String) value);
if (eObject != null) {
eObjects.add(eObject);
}
}
}
}
}
return eObjects;
}
protected InternalEObject handleProxy(InternalEObject internalEObject) {
if (internalEObject != null && internalEObject.eIsProxy()) {
URI eProxyURI = internalEObject.eProxyURI();
Map<URI, URI> uriMap = UML302UMLExtendedMetaData.getURIMap();
URI uri = uriMap.get(eProxyURI);
if (uri != null) {
internalEObject.eSetProxyURI(uri);
} else {
uri = uriMap.get(eProxyURI.trimFragment());
if (uri != null) {
String eProxyURIFragment = eProxyURI.fragment();
String fragment = UML302UMLExtendedMetaData
.getFragmentMap().get(eProxyURIFragment);
if (fragment != null) {
internalEObject.eSetProxyURI(uri
.appendFragment(fragment));
} else {
internalEObject.eSetProxyURI(uri
.appendFragment(eProxyURIFragment));
}
}
}
}
return internalEObject;
}
protected EObject reincarnate(EObject eObject, EClass eClass,
XMLResource resource) {
if (eObject.eClass() == eClass) {
return eObject;
} else {
EObject newEObject = EcoreUtil.create(eClass);
if (resource != null) {
resource.setID(newEObject, resource.getID(eObject));
}
for (EStructuralFeature eStructuralFeature : eObject.eClass()
.getEAllStructuralFeatures()) {
if (eStructuralFeature.isChangeable()
&& ((EStructuralFeature.Internal) eStructuralFeature)
.getEOpposite() == null
&& eObject.eIsSet(eStructuralFeature)) {
try {
newEObject.eSet(
eClass.getEStructuralFeature(eStructuralFeature
.getName()), eStructuralFeature.isMany()
? ((InternalEList<?>) eObject
.eGet(eStructuralFeature)).basicList()
: eObject.eGet(eStructuralFeature));
} catch (Exception e) {
UMLPlugin.INSTANCE.log(e);
}
}
}
for (EStructuralFeature.Setting inverseReference : UML2Util
.getInverseReferences(eObject)) {
EStructuralFeature eStructuralFeature = inverseReference
.getEStructuralFeature();
if (eStructuralFeature.isChangeable()) {
try {
if (eStructuralFeature.isMany()) {
@SuppressWarnings("unchecked")
List<EObject> values = (List<EObject>) inverseReference
.get(false);
values.set(values.indexOf(eObject), newEObject);
} else {
inverseReference.set(newEObject);
}
} catch (Exception e) {
UMLPlugin.INSTANCE.log(e);
}
}
}
return newEObject;
}
}
protected Profile getProfile(Element element, String uri) {
Resource eResource = element.eResource();
if (eResource != null) {
ResourceSet resourceSet = eResource.getResourceSet();
if (resourceSet != null) {
return UML2Util.load(resourceSet,
URI.createURI(uri),
UMLPackage.Literals.PROFILE);
}
}
return null;
}
protected Profile getUML2Profile(Element element) {
return getProfile(element, UML302UMLResource.UML2_PROFILE_URI);
}
protected Stereotype getUML2Stereotype(Element element, String name) {
Profile ecoreProfile = getUML2Profile(element);
return ecoreProfile != null
? ecoreProfile.getOwnedStereotype(name)
: null;
}
@Override
public void preLoad(XMLResource resource, InputStream inputStream,
Map<?, ?> options) {
xmiVersion = ((XMIResource)resource).getXMIVersion();
}
@Override
public void postLoad(final XMLResource resource, InputStream inputStream,
Map<?, ?> options) {
final EList<EObject> resourceContents = resource.getContents();
UMLSwitch<Object> umlSwitch = new UMLSwitch<Object>() {
@Override
public Object caseActivity(Activity activity) {
EList<StructuredActivityNode> structuredNodes = activity
.getStructuredNodes();
EList<ActivityGroup> groups = activity.getGroups();
for (ListIterator<ActivityGroup> ownedGroups = activity
.getOwnedGroups().listIterator(); ownedGroups.hasNext();) {
ActivityGroup group = (ActivityGroup) ownedGroups.next();
if (group instanceof StructuredActivityNode) {
ownedGroups.remove();
structuredNodes.add((StructuredActivityNode) group);
}
groups.add(group);
}
EList<ActivityNode> nodes = activity.getNodes();
for (ListIterator<ActivityNode> ownedNodes = activity
.getOwnedNodes().listIterator(); ownedNodes.hasNext();) {
ActivityNode node = (ActivityNode) ownedNodes.next();
if (node instanceof StructuredActivityNode) {
ownedNodes.remove();
structuredNodes.add((StructuredActivityNode) node);
}
nodes.add(node);
}
for (StructuredActivityNode structuredNode : structuredNodes) {
if (!groups.contains(structuredNode)) {
groups.add(structuredNode);
}
if (!nodes.contains(structuredNode)) {
nodes.add(structuredNode);
}
}
return super.caseActivity(activity);
}
@Override
public Object caseBehavior(Behavior behavior) {
if (!behavior.isSetIsReentrant()) {
behavior.setIsReentrant(false);
}
return super.caseBehavior(behavior);
}
@Override
public Object caseBehavioredClassifier(
BehavioredClassifier behavioredClassifier) {
AnyType extension = getExtension(resource, behavioredClassifier);
if (extension != null) {
Collection<EObject> ownedTriggers = getEObjects(extension,
resource, TAG_DEFINITION__OWNED_TRIGGER, true);
if (!ownedTriggers.isEmpty()) {
UMLUtil.setTaggedValue(
behavioredClassifier,
getUML2Stereotype(behavioredClassifier,
STEREOTYPE__BEHAVIORED_CLASSIFIER),
TAG_DEFINITION__OWNED_TRIGGER, ownedTriggers);
}
}
return super.caseBehavioredClassifier(behavioredClassifier);
}
@Override
public Object caseComment(Comment comment) {
AnyType extension = getExtension(resource, comment);
if (extension != null) {
Object value = getValue(extension.getAnyAttribute(),
"body", true); //$NON-NLS-1$
if (value instanceof String) {
comment.setBody((String) value);
}
}
return super.caseComment(comment);
}
@Override
public Object caseConnector(Connector connector) {
AnyType extension = getExtension(resource, connector);
if (extension != null) {
getValue(extension.getAnyAttribute(), "kind", true); //$NON-NLS-1$
}
return super.caseConnector(connector);
}
@Override
public Object caseDependency(Dependency dependency) {
AnyType extension = getExtension(resource, dependency);
if (extension != null) {
Collection<EObject> clients = getEObjects(extension,
resource, "client", true); //$NON-NLS-1$
InternalEList<NamedElement> dependencyClients = (InternalEList<NamedElement>) (dependency instanceof ComponentRealization
? dependency.getSuppliers()
: dependency.getClients());
for (EObject client : clients) {
if (client instanceof NamedElement
&& !dependencyClients.contains(client)) {
dependencyClients.addUnique((NamedElement) client);
}
}
Collection<EObject> suppliers = getEObjects(extension,
resource, "supplier", true); //$NON-NLS-1$
InternalEList<NamedElement> dependencySuppliers = (InternalEList<NamedElement>) (dependency instanceof ComponentRealization
? dependency.getClients()
: dependency.getSuppliers());
for (EObject supplier : suppliers) {
if (supplier instanceof NamedElement
&& !dependencySuppliers.contains(supplier)) {
dependencySuppliers
.addUnique((NamedElement) supplier);
}
}
}
return super.caseDependency(dependency);
}
@Override
public Object caseInstanceSpecification(
InstanceSpecification instanceSpecification) {
AnyType extension = getExtension(resource,
instanceSpecification);
if (extension != null) {
Collection<EObject> classifiers = getEObjects(extension,
resource, "classifier", true); //$NON-NLS-1$
if (!classifiers.isEmpty()
&& !(instanceSpecification instanceof EnumerationLiteral)) {
InternalEList<Classifier> instanceSpecificationClassifiers = (InternalEList<Classifier>) instanceSpecification
.getClassifiers();
for (EObject classifier : classifiers) {
if (classifier instanceof Classifier) {
instanceSpecificationClassifiers
.addUnique((Classifier) classifier);
}
}
}
}
return super.caseInstanceSpecification(instanceSpecification);
}
@Override
public Object caseInteractionUse(InteractionUse interactionUse) {
AnyType extension = getExtension(resource, interactionUse);
if (extension != null) {
Collection<EObject> arguments = getEObjects(extension,
resource, TAG_DEFINITION__ARGUMENT, true);
if (!arguments.isEmpty()) {
UMLUtil.setTaggedValue(
interactionUse,
getUML2Stereotype(interactionUse,
STEREOTYPE__INTERACTION_USE),
TAG_DEFINITION__ARGUMENT, arguments);
}
}
return super.caseInteractionUse(interactionUse);
}
@Override
public Object caseNamedElement(NamedElement namedElement) {
AnyType extension = getExtension(resource, namedElement);
if (extension != null) {
getValue(extension.getAnyAttribute(), "clientDependency", true); //$NON-NLS-1$
}
return super.caseNamedElement(namedElement);
}
@Override
public Object caseOccurrenceSpecification(OccurrenceSpecification occurrenceSpecification) {
EObject event = getEObject(getExtension(resource, occurrenceSpecification),
resource, "event", true); //$NON-NLS-1$
if (event != null) {
EClass eClass = event.eClass();
String name = eClass.getName();
if ("DestructionEvent".equals(name)) { //$NON-NLS-1$
return reincarnate(
occurrenceSpecification,
UMLPackage.Literals.DESTRUCTION_OCCURRENCE_SPECIFICATION,
resource);
} else if (occurrenceSpecification instanceof MessageOccurrenceSpecification) {
Message message = ((MessageOccurrenceSpecification) occurrenceSpecification)
.getMessage();
if (message == null) {
for (EStructuralFeature.Setting inverseReference : UML2Util
.getInverseReferences(occurrenceSpecification)) {
EObject eObject = inverseReference.getEObject();
if (eObject instanceof Message) {
message = (Message) eObject;
break;
}
}
}
if (message != null) {
if ("CallEvent".equals(name)) { //$NON-NLS-1$
message.setSignature(((CallEvent) event)
.getOperation());
} else if ("ReceiveOperationEvent".equals(name) //$NON-NLS-1$
|| "SendOperationEvent".equals(name)) { //$NON-NLS-1$
message.setSignature((NamedElement) getEObject(
(AnyType) event, resource, "operation", //$NON-NLS-1$
false));
} else if ("ReceiveSignalEvent".equals(name) //$NON-NLS-1$
|| "SendSignalEvent".equals(name)) { //$NON-NLS-1$
message
.setSignature((NamedElement) getEObject(
(AnyType) event, resource, "signal", //$NON-NLS-1$
false));
} else if ("SignalEvent".equals(name)) { //$NON-NLS-1$
message.setSignature(((SignalEvent) event)
.getSignal());
}
}
}
}
return super.caseOccurrenceSpecification(occurrenceSpecification);
}
@Override
public Object casePackage(org.eclipse.uml2.uml.Package package_) {
AnyType extension = getExtension(resource, package_);
if (extension != null) {
getEObjects(extension, resource, "packagedElement", true); //$NON-NLS-1$
}
for (ProfileApplication profileApplication : package_
.getProfileApplications()) {
defaultCase(profileApplication);
}
Object nsURI = UMLUtil.getTaggedValue(package_,
UMLUtil.PROFILE__ECORE + NamedElement.SEPARATOR
+ UMLUtil.STEREOTYPE__E_PACKAGE,
UMLUtil.TAG_DEFINITION__NS_URI);
if (nsURI instanceof String) {
package_.setURI((String) nsURI);
}
return super.casePackage(package_);
}
@Override
public Object caseProperty(Property property) {
Object isID = UMLUtil.getTaggedValue(property,
UMLUtil.PROFILE__ECORE + NamedElement.SEPARATOR
+ UMLUtil.STEREOTYPE__E_ATTRIBUTE,
UMLUtil.TAG_DEFINITION__IS_ID);
if (isID instanceof Boolean) {
property.setIsID((Boolean) isID);
}
return super.caseProperty(property);
}
@Override
public Object defaultCase(EObject eObject) {
AnyType extension = getExtension(resource, eObject);
if (extension != null) {
if (extension.getAnyAttribute().isEmpty()
&& extension.getMixed().isEmpty()) {
removeExtension(resource, eObject);
} else if (DEBUG) {
System.out.println(eObject);
System.out.println("->"); //$NON-NLS-1$
System.out.println(extension);
EAnnotation eAnnotation = UML2Util.createEAnnotation(
null, ExtendedMetaData.ANNOTATION_URI);
eAnnotation.getContents().add(extension);
eAnnotation.getReferences().add(eObject);
resourceContents.add(eAnnotation);
}
}
for (EReference eReference : eObject.eClass()
.getEAllReferences()) {
if (!eReference.isDerived() && !eReference.isContainer()
&& !eReference.isContainment()
&& eObject.eIsSet(eReference)) {
if (eReference.isMany()) {
@SuppressWarnings("unchecked")
InternalEList<InternalEObject> values = (InternalEList<InternalEObject>) eObject
.eGet(eReference);
for (InternalEObject value : values) {
handleProxy(value);
}
} else {
handleProxy((InternalEObject) eObject.eGet(
eReference, false));
}
}
}
Iterator<?> contents = resolveProxies
? eObject.eContents().iterator()
: ((InternalEList<?>) eObject.eContents()).basicIterator();
if (contents != null) {
while (contents.hasNext()) {
doSwitch((EObject) contents.next());
}
}
return eObject;
}
};
for (int i = 0; i < resourceContents.size(); i++) {
umlSwitch.doSwitch(resourceContents.get(i));
}
((XMIResource)resource).setXMIVersion(xmiVersion);
}
}