/* $Id: ModelAccessModelInterpreter.java 17837 2010-01-12 19:07:53Z linus $ ***************************************************************************** * Copyright (c) 2009 Contributors - see below * 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: * mvw ***************************************************************************** * * Some portions of this file was previously release using the BSD License: */ // Copyright (c) 2008-2009 The Regents of the University of California. All // Rights Reserved. Permission to use, copy, modify, and distribute this // software and its documentation without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph appear in all copies. This software program and // documentation are copyrighted by The Regents of the University of // California. The software program and documentation are supplied "AS // IS", without any accompanying services from The Regents. The Regents // does not warrant that the operation of the program will be // uninterrupted or error-free. The end-user understands that the program // was developed for research purposes and is advised not to rely // exclusively on the program for any reason. IN NO EVENT SHALL THE // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. package org.argouml.profile.internal.ocl.uml14; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Map; import org.apache.log4j.Logger; import org.argouml.model.Model; import org.argouml.profile.internal.ocl.DefaultOclEvaluator; import org.argouml.profile.internal.ocl.InvalidOclException; import org.argouml.profile.internal.ocl.ModelInterpreter; /** * Model Access * * @author maurelio1234 */ public class ModelAccessModelInterpreter implements ModelInterpreter { /** * Logger. */ private static final Logger LOG = Logger .getLogger(ModelAccessModelInterpreter.class); private static Uml14ModelInterpreter uml14mi = new Uml14ModelInterpreter(); /* * @see org.argouml.profile.internal.ocl.ModelInterpreter#invokeFeature(java.util.Map, * java.lang.Object, java.lang.String, java.lang.String, * java.lang.Object[]) */ @SuppressWarnings("unchecked") public Object invokeFeature(Map<String, Object> vt, Object subject, String feature, String type, Object[] parameters) { // TODO: This is an absurdly long method! Break it up. if (subject == null) { subject = vt.get("self"); } /* 4.5.2.1 Abstraction */ // TODO investigate: Abstraction.mapping is not in the Model Subsystem /* 4.5.2.3 Association */ if (Model.getFacade().isAAssociation(subject)) { if (type.equals(".")) { if (feature.equals("connection")) { return new ArrayList<Object>(Model.getFacade() .getConnections(subject)); } // Additional Operation 4.5.3.1 [1] if (feature.equals("allConnections")) { return new HashSet<Object>(Model.getFacade() .getConnections(subject)); } } } /* 4.5.2.5 AssociationEnd */ if (Model.getFacade().isAAssociationEnd(subject)) { if (type.equals(".")) { if (feature.equals("aggregation")) { return Model.getFacade().getAggregation(subject); } if (feature.equals("changeability")) { return Model.getFacade().getChangeability(subject); } if (feature.equals("ordering")) { return Model.getFacade().getOrdering(subject); } if (feature.equals("isNavigable")) { return Model.getFacade().isNavigable(subject); } if (feature.equals("multiplicity")) { return Model.getFacade().getMultiplicity(subject); } // TODO: isStatic in UML 2.x if (feature.equals("targetScope")) { return Model.getFacade().getTargetScope(subject); } if (feature.equals("visibility")) { return Model.getFacade().getVisibility(subject); } if (feature.equals("qualifier")) { return Model.getFacade().getQualifiers(subject); } if (feature.equals("specification")) { return Model.getFacade().getSpecification(subject); } if (feature.equals("participant")) { return Model.getFacade().getClassifier(subject); } // TODO investigate the "unnamed opposite end" // Additional Operation 4.5.3.3 [1] if (feature.equals("upperbound")) { return Model.getFacade().getUpper(subject); } } } /* 4.5.2.6 Attribute */ if (Model.getFacade().isAAttribute(subject)) { if (type.equals(".")) { if (feature.equals("initialValue")) { return Model.getFacade().getInitialValue(subject); } if (feature.equals("associationEnd")) { return new ArrayList<Object>(Model.getFacade() .getAssociationEnds(subject)); } } } /* 4.5.2.7 BehavioralFeature */ if (Model.getFacade().isABehavioralFeature(subject)) { if (type.equals(".")) { if (feature.equals("isQuery")) { return Model.getFacade().isQuery(subject); } if (feature.equals("parameter")) { return new ArrayList<Object>(Model.getFacade() .getParameters(subject)); } } // TODO implement additional operations in 4.5.3.5 } /* 4.5.2.8 Binding */ if (Model.getFacade().isABinding(subject)) { if (type.equals(".")) { if (feature.equals("argument")) { return Model.getFacade().getArguments(subject); } } } /* 4.5.2.9 Class */ if (Model.getFacade().isAClass(subject)) { if (type.equals(".")) { if (feature.equals("isActive")) { return Model.getFacade().isActive(subject); } } } /* 4.5.2.10 Classifier */ if (Model.getFacade().isAClassifier(subject)) { if (type.equals(".")) { if (feature.equals("feature")) { return new ArrayList<Object>(Model.getFacade() .getFeatures(subject)); } if (feature.equals("feature")) { return new ArrayList<Object>(Model.getFacade() .getFeatures(subject)); } if (feature.equals("association")) { return new ArrayList<Object>(Model.getFacade() .getAssociationEnds(subject)); } if (feature.equals("powertypeRange")) { return new HashSet<Object>(Model.getFacade() .getPowertypeRanges(subject)); } // TODO specifiedEnd?? if (feature.equals("feature")) { return new ArrayList<Object>(Model.getFacade() .getFeatures(subject)); } // Additional Operations in 4.5.3.8 if (feature.equals("allFeatures")) { return internalOcl(subject, vt, "self.feature->union(" + "self.parent.oclAsType(Classifier).allFeatures)"); } if (feature.equals("allOperations")) { return internalOcl(subject, vt, "self.allFeatures->" + "select(f | f.oclIsKindOf(Operation))"); } if (feature.equals("allMethods")) { return internalOcl(subject, vt, "self.allFeatures->" + "select(f | f.oclIsKindOf(Method))"); } if (feature.equals("allAttributes")) { return internalOcl(subject, vt, "self.allFeatures->" + "select(f | f.oclIsKindOf(Attribute))"); } if (feature.equals("associations")) { return internalOcl(subject, vt, "self.association.association->asSet()"); } if (feature.equals("allAssociations")) { return internalOcl( subject, vt, "self.associations->union(" + "self.parent.oclAsType(Classifier).allAssociations)"); } if (feature.equals("oppositeAssociationEnds")) { return internalOcl(subject, vt, "self.associations->select ( a | a.connection->select " + "( ae | ae.participant = self ).size = 1 )->" + "collect ( a | a.connection->" + "select ( ae | ae.participant <> self ) )->" + "union ( self.associations->" + "select ( a | a.connection->select ( ae |" + "ae.participant = self ).size > 1 )->" + "collect ( a | a.connection) )"); } if (feature.equals("allOppositeAssociationEnds")) { return internalOcl( subject, vt, "self.oppositeAssociationEnds->" + "union(self.parent.allOppositeAssociationEnds )"); } if (feature.equals("specification")) { return internalOcl( subject, vt, "self.clientDependency->" + "select(d |" + "d.oclIsKindOf(Abstraction)" + "and d.stereotype.name = \"realization\" " + "and d.supplier.oclIsKindOf(Classifier))" + ".supplier.oclAsType(Classifier)"); } if (feature.equals("allContents")) { return internalOcl(subject, vt, "self.contents->union(" + "self.parent.allContents->select(e |" + "e.elementOwnership.visibility = #public or true or " + " e.elementOwnership.visibility = #protected))"); } if (feature.equals("allDiscriminators")) { return internalOcl(subject, vt, "self.generalization.discriminator->" + "union(self.parent.oclAsType(Classifier)." + "allDiscriminators)"); } } } /* 4.5.2.11 Comment */ if (Model.getFacade().isAComment(subject)) { if (type.equals(".")) { if (feature.equals("body")) { return Model.getFacade().getBody(subject); } if (feature.equals("annotatedElement")) { return new HashSet<Object>(Model.getFacade() .getAnnotatedElements(subject)); } } } /* 4.5.2.12 Component */ if (Model.getFacade().isAComponent(subject)) { if (type.equals(".")) { if (feature.equals("deploymentLocation")) { return new HashSet<Object>(Model.getFacade() .getDeploymentLocations(subject)); } if (feature.equals("resident")) { // TODO check this return new HashSet<Object>(Model.getFacade() .getResidents(subject)); } // TODO implementation? // Additional Operation in 4.5.3.9 if (feature.equals("allResidentElements")) { return internalOcl(subject, vt, "self.resident->union(" + "self.parent.oclAsType(Component)." + "allResidentElements->select( re |" + "re.elementResidence.visibility = #public or " + "re.elementResidence.visibility = #protected))"); } } } /* 4.5.2.13 Constraint */ if (Model.getFacade().isAConstraint(subject)) { if (type.equals(".")) { if (feature.equals("body")) { return Model.getFacade().getBody(subject); } if (feature.equals("constrainedElement")) { // TODO check this return Model.getFacade().getConstrainedElements(subject); } } } /* 4.5.2.14 Dependency */ if (Model.getFacade().isADependency(subject)) { if (type.equals(".")) { if (feature.equals("client")) { return new HashSet<Object>(Model.getFacade() .getClients(subject)); } if (feature.equals("supplier")) { return new HashSet<Object>(Model.getFacade() .getSuppliers(subject)); } } } // TODO ElementOwnership is not in ModelSubsys!! /* 4.5.2.18 ElementOwnership */ if (Model.getFacade().isAElementResidence(subject)) { if (type.equals(".")) { if (feature.equals("visibility")) { return Model.getFacade().getVisibility(subject); } } } /* 4.5.2.19 Enumeration */ if (Model.getFacade().isAEnumeration(subject)) { if (type.equals(".")) { if (feature.equals("literal")) { return Model.getFacade().getEnumerationLiterals(subject); } } } /* 4.5.2.20 EnumerationLiteral */ if (Model.getFacade().isAEnumerationLiteral(subject)) { if (type.equals(".")) { if (feature.equals("enumeration")) { return Model.getFacade().getEnumeration(subject); } } } /* 4.5.2.21 Feature */ if (Model.getFacade().isAFeature(subject)) { if (type.equals(".")) { if (feature.equals("ownerScope")) { return Model.getFacade().isStatic(subject); } if (feature.equals("visibility")) { return Model.getFacade().getVisibility(subject); } if (feature.equals("owner")) { return Model.getFacade().getOwner(subject); } } } /* 4.5.2.23 Generalizable Element */ if (Model.getFacade().isAGeneralizableElement(subject)) { if (type.equals(".")) { if (feature.equals("isAbstract")) { return Model.getFacade().isAbstract(subject); } if (feature.equals("isLeaf")) { return Model.getFacade().isLeaf(subject); } if (feature.equals("isRoot")) { return Model.getFacade().isRoot(subject); } if (feature.equals("generalization")) { return new HashSet<Object>(Model.getFacade() .getGeneralizations(subject)); } if (feature.equals("specialization")) { return new HashSet<Object>(Model.getFacade() .getSpecializations(subject)); } // Additional Operation in 4.5.3.20 if (feature.equals("parent")) { return internalOcl(subject, vt, "self.generalization.parent"); } if (feature.equals("allParents")) { return internalOcl(subject, vt, "self.parent->union(self.parent.allParents)"); } } } /* 4.5.2.24 Generalization */ if (Model.getFacade().isAGeneralization(subject)) { if (type.equals(".")) { if (feature.equals("discriminator")) { return Model.getFacade().getDiscriminator(subject); } if (feature.equals("child")) { return Model.getFacade().getSpecific(subject); } if (feature.equals("parent")) { return Model.getFacade().getGeneral(subject); } if (feature.equals("powertype")) { return Model.getFacade().getPowertype(subject); } if (feature.equals("specialization")) { return new HashSet<Object>(Model.getFacade() .getSpecializations(subject)); } } } /* 4.5.2.26 Method */ if (Model.getFacade().isAMethod(subject)) { if (type.equals(".")) { if (feature.equals("body")) { return Model.getFacade().getBody(subject); } if (feature.equals("specification")) { return Model.getFacade().getSpecification(subject); } } } /* 4.5.2.27 ModelElement */ if (Model.getFacade().isAModelElement(subject)) { if (type.equals(".")) { if (feature.equals("name")) { String name = Model.getFacade().getName(subject); if (name == null) { // TODO check conformancy to specification // avoiding null names name = ""; } return name; } // TODO asArgument?? if (feature.equals("clientDependency")) { return new HashSet<Object>(Model.getFacade() .getClientDependencies(subject)); } if (feature.equals("constraint")) { return new HashSet<Object>(Model.getFacade() .getConstraints(subject)); } // TODO implementationLocation?? if (feature.equals("namespace")) { return Model.getFacade().getNamespace(subject); } // TODO presentation?? if (feature.equals("supplierDependency")) { return new HashSet<Object>(Model.getFacade() .getSupplierDependencies(subject)); } if (feature.equals("templateParameter")) { return Model.getFacade().getTemplateParameters(subject); } // As extended by 4.6.2.2 if (feature.equals("stereotype")) { return Model.getFacade().getStereotypes(subject); } if (feature.equals("taggedValue")) { return Model.getFacade().getTaggedValuesCollection(subject); } if (feature.equals("constraint")) { return Model.getFacade().getConstraints(subject); } // Additional Operations in 4.5.3.25 if (feature.equals("supplier")) { return internalOcl(subject, vt, "self.clientDependency.supplier"); } if (feature.equals("allSuppliers")) { return internalOcl(subject, vt, "self.supplier->union(self.supplier.allSuppliers)"); } if (feature.equals("model")) { return internalOcl(subject, vt, "self.namespace->" + "union(self.namespace.allSurroundingNamespaces)->" + "select( ns| ns.oclIsKindOf (Model))"); } if (feature.equals("isTemplate")) { return !Model.getFacade().getTemplateParameters(subject) .isEmpty(); } if (feature.equals("isInstantiated")) { return internalOcl(subject, vt, "self.clientDependency->" + "select(oclIsKindOf(Binding))->notEmpty"); } if (feature.equals("templateArgument")) { return internalOcl(subject, vt, "self.clientDependency->" + "select(oclIsKindOf(Binding))." + "oclAsType(Binding).argument"); } } } /* 4.5.2.28 Namespace */ if (Model.getFacade().isANamespace(subject)) { if (type.equals(".")) { if (feature.equals("ownedElement")) { return new HashSet<Object>(Model.getFacade() .getOwnedElements(subject)); } // Additional Operations in 4.5.3.26 if (feature.equals("contents")) { // TODO investigate typo in spec!! return internalOcl(subject, vt, "self.ownedElement->" + "union(self.ownedElement->" + "select(x|x.oclIsKindOf(Namespace)).contents)"); } if (feature.equals("allContents")) { return internalOcl(subject, vt, "self.contents"); } if (feature.equals("allVisibleElements")) { return internalOcl( subject, vt, "self.allContents ->" + "select(e |e.elementOwnership.visibility = #public)"); } if (feature.equals("allSurroundingNamespaces")) { return internalOcl(subject, vt, "self.namespace->" + "union(self.namespace.allSurroundingNamespaces)"); } } } /* 4.5.2.29 Node */ if (Model.getFacade().isANode(subject)) { if (type.equals(".")) { if (feature.equals("deployedComponent")) { return new HashSet<Object>(Model.getFacade() .getDeployedComponents(subject)); } } } /* 4.5.2.30 Operation */ if (Model.getFacade().isAOperation(subject)) { if (type.equals(".")) { if (feature.equals("concurrency")) { return Model.getFacade().getConcurrency(subject); } if (feature.equals("isAbstract")) { return Model.getFacade().isAbstract(subject); } if (feature.equals("isLeaf")) { return Model.getFacade().isLeaf(subject); } if (feature.equals("isRoot")) { return Model.getFacade().isRoot(subject); } } } /* 4.5.2.31 Parameter */ if (Model.getFacade().isAParameter(subject)) { if (type.equals(".")) { if (feature.equals("defaultValue")) { return Model.getFacade().getDefaultValue(subject); } if (feature.equals("kind")) { return Model.getFacade().getKind(subject); } } } /* 4.5.2.35 ProgrammingLanguageDataType */ // Gone from UML 2.x, so unsupported here // if (Model.getFacade().isAProgrammingLanguageDataType(subject)) { // if (type.equals(".")) { // if (feature.equals("expression")) { // return Model.getFacade().getExpression(subject); // } // } // } /* 4.5.2.37 StructuralFeature */ if (Model.getFacade().isAStructuralFeature(subject)) { if (type.equals(".")) { if (feature.equals("changeability")) { return Model.getFacade().getChangeability(subject); } if (feature.equals("multiplicity")) { return Model.getFacade().getMultiplicity(subject); } if (feature.equals("ordering")) { return Model.getFacade().getOrdering(subject); } // TODO: Removed from UML 2.x if (feature.equals("targetScope")) { return Model.getFacade().getTargetScope(subject); } if (feature.equals("type")) { return Model.getFacade().getType(subject); } } } /* 4.5.2.38 TemplateArgument */ if (Model.getFacade().isATemplateArgument(subject)) { if (type.equals(".")) { if (feature.equals("binding")) { return Model.getFacade().getBinding(subject); } if (feature.equals("modelElement")) { return Model.getFacade().getModelElement(subject); } } } /* 4.5.2.39 TemplateParameter */ if (Model.getFacade().isATemplateParameter(subject)) { if (type.equals(".")) { if (feature.equals("defaultElement")) { return Model.getFacade().getDefaultElement(subject); } } } /* 4.11.3.5 UseCase */ if (Model.getFacade().isAUseCase(subject)) { if (type.equals(".")) { if (feature.equals("specificationPath")) { /* The operation specificationPath results in a set containing * all surrounding Namespaces that are not instances of * Package. * specificationPath : Set(Namespace) * specificationPath = self.allSurroundingNamespaces->select(n | * n.oclIsKindOf(Subsystem) or n.oclIsKindOf(Class)) **/ return Model.getUseCasesHelper().getSpecificationPath(subject); } if (feature.equals("allExtensionPoints")) { Collection c = Model.getCoreHelper().getAllSupertypes(subject); Collection result = new ArrayList(Model.getFacade().getExtensionPoints(subject)); for (Object uc : c) { result.addAll(Model.getFacade().getExtensionPoints(uc)); } return result; } } } /* 4.5.3.2 AssociationClass */ if (Model.getFacade().isAAssociationClass(subject)) { if (type.equals(".")) { if (feature.equals("allConnections")) { /* The operation allConnections results in the set of all * AssociationEnds of the AssociationClass, including all * connections defined by its parent (transitive closure). */ return internalOcl( subject, vt, "self.connection->union(self.parent->select(" + "s | s.oclIsKindOf(Association))->collect(" + "a : Association | a.allConnections))->asSet()"); } } } /* 4.6.2.3 Stereotype */ if (Model.getFacade().isAStereotype(subject)) { if (type.equals(".")) { if (feature.equals("baseClass")) { return new HashSet<Object>(Model.getFacade() .getBaseClasses(subject)); } if (feature.equals("extendedElement")) { return new HashSet<Object>(Model.getFacade() .getExtendedElements(subject)); } if (feature.equals("definedTag")) { // TODO check this return new HashSet<Object>(Model.getFacade() .getTagDefinitions(subject)); } // stereotypeConstraint ? } } /* 4.6.2.4 TagDefinition */ if (Model.getFacade().isATagDefinition(subject)) { if (type.equals(".")) { if (feature.equals("multiplicity")) { return Model.getFacade().getMultiplicity(subject); } if (feature.equals("tagType")) { return Model.getFacade().getType(subject); } if (feature.equals("typedValue")) { return new HashSet<Object>(Model.getFacade() .getTypedValues(subject)); } if (feature.equals("owner")) { return Model.getFacade().getOwner(subject); } } } /* 4.6.2.5 TaggedValue */ if (Model.getFacade().isATaggedValue(subject)) { if (type.equals(".")) { if (feature.equals("dataValue")) { return Model.getFacade().getDataValue(subject); } if (feature.equals("type")) { return Model.getFacade().getType(subject); } if (feature.equals("referenceValue")) { return new HashSet<Object>(Model.getFacade() .getReferenceValue(subject)); } } } return null; } private Object internalOcl(Object subject, Map<String, Object> vt, String ocl) { try { Object oldSelf = vt.get("self"); vt.put("self", subject); Object ret = DefaultOclEvaluator.getInstance().evaluate(vt, uml14mi, ocl); vt.put("self", oldSelf); return ret; } catch (InvalidOclException e) { LOG.error("Exception", e); return null; } } /** * Add the metamodel-metaclasses as built-in symbols * * @param sym the symbol * @return the value of the symbol * @see org.argouml.profile.internal.ocl.ModelInterpreter#getBuiltInSymbol(java.lang.String) */ public Object getBuiltInSymbol(String sym) { for (String name : Model.getFacade().getMetatypeNames()) { if (name.equals(sym)) { return new OclType(sym); } } return null; } }