svn commit: r14390 - trunk/src/model-mdr/src/org/argouml/model/mdr/CoreHelperMDRImpl.java

[email protected]
Newsgroups gmane.comp.lang.uml.argouml.cvs
Message-ID <[email protected]>
Author: tfmorris
Date: 2008-04-18 21:59:15-0700
New Revision: 14390

Modified:
   trunk/src/model-mdr/src/org/argouml/model/mdr/CoreHelperMDRImpl.java

Log:
Issue 4808 - fix isValidNamespace to correctly process Associations.

Add support for profilePackages

Modified: trunk/src/model-mdr/src/org/argouml/model/mdr/CoreHelperMDRImpl.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/model-mdr/src/org/argouml/model/mdr/CoreHelperMDRImpl.java?view=diff&rev=14390&p1=trunk/src/model-mdr/src/org/argouml/model/mdr/CoreHelperMDRImpl.java&p2=trunk/src/model-mdr/src/org/argouml/model/mdr/CoreHelperMDRImpl.java&r1=14389&r2=14390
==============================================================================
--- trunk/src/model-mdr/src/org/argouml/model/mdr/CoreHelperMDRImpl.java	(original)
+++ trunk/src/model-mdr/src/org/argouml/model/mdr/CoreHelperMDRImpl.java	2008-04-18 21:59:15-0700
@@ -92,6 +92,7 @@
 import org.omg.uml.foundation.core.CorePackage;
 import org.omg.uml.foundation.core.DataType;
 import org.omg.uml.foundation.core.Dependency;
+import org.omg.uml.foundation.core.Element;
 import org.omg.uml.foundation.core.ElementResidence;
 import org.omg.uml.foundation.core.Enumeration;
 import org.omg.uml.foundation.core.EnumerationLiteral;
@@ -383,15 +384,45 @@
         if (!(generalizableElement instanceof GeneralizableElement)) {
             throw new IllegalArgumentException();
         }
-        Collection<Generalization> gc = 
-            ((GeneralizableElement) generalizableElement).getGeneralization();
+        try {
+            return getParents((GeneralizableElement) generalizableElement);
+        } catch (InvalidObjectException e) {
+            throw new InvalidElementException(e);
+        }
+    }
+    
+    /**
+     * Return the parents of a GeneralizableElement
+     * @param ge generalizable element
+     * @return parents of all generalizations
+     */
+    static Collection<GeneralizableElement> getParents(
+            GeneralizableElement ge) {
         Set<GeneralizableElement> result = new HashSet<GeneralizableElement>();
-        for (Generalization g : gc) {
+        for (Generalization g : ge.getGeneralization()) {
             result.add(g.getParent());
         }
         return result;
     }
 
+    /**
+     * Return the parents of a GeneralizableElement and parents of those parents
+     * all the way up the hierarchy.
+     * 
+     * @param ge generalizable element
+     * @return parents of all generalizations
+     */
+    static Collection<GeneralizableElement> getAllParents(
+            GeneralizableElement ge) {
+        Collection<GeneralizableElement> result = 
+            new HashSet<GeneralizableElement>();
+        for (GeneralizableElement parent : getParents(ge)) {
+            result.add(parent);
+            result.addAll(getAllParents(parent));
+        }
+        return result;
+    }
+    
     public List<Parameter> getReturnParameters(Object operation) {
         List<Parameter> returnParams = new ArrayList<Parameter>();
         try {
@@ -885,6 +916,7 @@
 
 
     @SuppressWarnings("deprecation")
+    @Deprecated
     public Collection getAllContents(Object clazz) {
         if (clazz == null) {
             return Collections.EMPTY_SET;
@@ -898,7 +930,7 @@
 
     public Collection<Attribute> getAllAttributes(Object clazz) {
         if (clazz == null) {
-            return Collections.EMPTY_SET;
+            return Collections.emptySet();
         }
         if (!(clazz instanceof Classifier)) {
             throw new IllegalArgumentException();
@@ -925,19 +957,26 @@
         if (!(ns instanceof Namespace)) {
             throw new IllegalArgumentException();
         }
-
-        List<ModelElement> list = new ArrayList<ModelElement>();
         try {
-            for (ModelElement element : ((Namespace) ns).getOwnedElement()) {
-                if (element.getVisibility()
-                        .equals(VisibilityKindEnum.VK_PUBLIC)) {
-                    list.add(element);
-                }
-            }
+            return getAllVisibleElements((Namespace) ns);
         } catch (InvalidObjectException e) {
             throw new InvalidElementException(e);
         }
-        return list;
+    }
+    
+    /**
+     * Get all publicly visible elements in a namespace.
+     * @param ns the namespace
+     * @return all owned elements with a visibility of VK_PUBLIC
+     */
+    static Collection<ModelElement> getAllVisibleElements(Namespace ns) {
+        Collection<ModelElement> result = new ArrayList<ModelElement>();
+        for (ModelElement element : ns.getOwnedElement()) {
+            if (VisibilityKindEnum.VK_PUBLIC.equals(element.getVisibility())) {
+                result.add(element);
+            }
+        }
+        return result;
     }
 
 
@@ -1125,9 +1164,7 @@
             for (Dependency dependency : ((ModelElement) client)
                     .getClientDependency()) {
                 if (dependency instanceof Permission
-                        && Model.getExtensionMechanismsHelper().hasStereotype(
-                                dependency,
-                                ModelManagementHelper.IMPORT_STEREOTYPE)) {
+                        && hasImportStereotype((Permission) dependency)) {
                     result.add((Permission) dependency);
                 }
             }
@@ -1137,6 +1174,26 @@
         return result;
     }
     
+    /**
+     * Return true if the given Permission has any of our acceptable
+     * import stereotypes <code>import</code> or <code>access</code>.
+     * <p>
+     * NOTE: We don't currently consider the <code>friend</code> stereotype.
+     * 
+     * @param permission Permission to test
+     * @return true if this is an import permission
+     */
+    private boolean hasImportStereotype(Permission permission) {
+        return (Model.getExtensionMechanismsHelper().hasStereotype(permission,
+                ModelManagementHelper.IMPORT_STEREOTYPE)
+                || Model.getExtensionMechanismsHelper().hasStereotype(
+                        permission, ModelManagementHelper.ACCESS_STEREOTYPE)
+                        // TODO: Do we want to <<friend>> stereotypes too?
+//                        || Model.getExtensionMechanismsHelper().hasStereotype(
+//                        permission, ModelManagementHelper.FRIEND_STEREOTYPE)
+                        );
+    }
+    
     public Permission getPackageImport(Object supplier, Object client) {
         for (Dependency dependency : getDependencies(supplier, client)) {
             if (dependency instanceof Permission
@@ -1200,11 +1257,13 @@
             if (modelElement == ns) {
                 return false;
             }
-            if (modelElement instanceof Namespace
-                    && modelElement
-                            == getFirstSharedNamespace(modelElement, ns)) {
-                return false;
-            }
+            // TODO: Is this checking for circular containment?  If so, it's
+            // done implicitly by MDR - tfm 20080514
+//            if (modelElement instanceof Namespace
+//                    && modelElement
+//                            == getFirstSharedNamespace(modelElement, ns)) {
+//                return false;
+//            }
             if (ns instanceof Interface
                     || ns instanceof Actor
                     || ns instanceof DataType
@@ -1296,10 +1355,9 @@
                     return false;
                 }
             } else if (ns instanceof UmlPackage) {
-                boolean profilePackage = false; // not yet implemented
                 // A Profile is a special package having the <<profile>>
                 // stereotype which can only contain the following types
-                if (profilePackage) {
+                if (isProfilePackage(ns)) {
                     if (!(modelElement instanceof Stereotype
                             || modelElement instanceof Constraint
                             || modelElement instanceof TagDefinition
@@ -1373,6 +1431,11 @@
         }
     }
 
+    private boolean isProfilePackage(Namespace ns) {
+        // A Profile is a special package having the <<profile>> stereotype
+        return Model.getFacade().isStereotype(ns, "profile");
+    }
+
     /**
      * The base of a AssociationRole or ClassifierRole should be contained in
      * the given Namespace. If no base is set (yet), then allow any namespace.
@@ -1402,15 +1465,26 @@
     }
 
     private boolean isValidNamespace(Generalization gen, Namespace ns) {
-        if (gen.getParent() == null || gen.getChild() == null) {
-            return true;
-        }
-        Namespace ns1 = gen.getParent().getNamespace();
-        Namespace ns2 = gen.getChild().getNamespace();
-        if (ns == getFirstSharedNamespace(ns1, ns2)) {
-            return true;
-        }
-        return false;
+        // TODO: Implement following WFR for GeneralizableElements
+        // [4] The parent must be included in the Namespace of the 
+        //     GeneralizableElement.
+        //       self.generalization->forAll(g |
+        //           self.namespace.allContents->includes(g.parent) )
+        return ModelManagementHelperMDRImpl.getContents(ns).contains(
+                gen.getParent());
+        
+        
+        // These old checks don't appear to be supported by the
+        // UML 1.4 spec. - tfm 20080514
+//      if (gen.getParent() == null || gen.getChild() == null) {
+//      return true;
+//  }
+//        Namespace ns1 = gen.getParent().getNamespace();
+//        Namespace ns2 = gen.getChild().getNamespace();
+//        if (ns == getFirstSharedNamespace(ns1, ns2)) {
+//            return true;
+//        }
+//        return false;
     }
 
     private boolean isValidNamespace(StructuralFeature struc, Namespace ns) {
@@ -1431,63 +1505,145 @@
     }
 
     private boolean isValidNamespace(UmlAssociation assoc, Namespace ns) {
-        List<Namespace> namespaces = new ArrayList<Namespace>();
         for (AssociationEnd end : assoc.getConnection()) {
-            Classifier participant = end.getParticipant();
-            if (participant != null) {
-                Namespace namespace = participant.getNamespace();
-                if (namespace != null) {
-                    namespaces.add(namespace);
-                }
+            if (!isVisible(end.getParticipant(), ns)) {
+                return false;
             }
         }
-        if (namespaces.size() < 2) {
+        return true;
+    }
+    
+    /**
+     * Return true if the given element is visible from this namespace.
+     * <blockquote>The OCL that this is intended to check is this:
+     * self.allConnections->forAll(r | self.namespace.allContents->includes
+        (r.participant) ) or
+        self.allConnections->forAll(r | self.namespace.allContents->excludes
+        (r.participant) implies
+        self.namespace.clientDependency->exists (d |
+        d.oclIsTypeOf(Permission) and
+        d.stereotype.name = 'access' and
+        d.supplier.oclAsType(Namespace).ownedElement->select (e |
+        e.elementOwnership.visibility =
+        #public)->includes (r.participant) or
+        d.supplier.oclAsType(GeneralizableElement).
+        allParents.oclAsType(Namespace).ownedElement->select (e |
+        e. elementOwnership.visibility =
+        #public)->includes (r.participant) or
+        d.supplier.oclAsType(Package).allImportedElements->select (e |
+        e. elementImport.visibility =
+        #public) ->includes (r.participant) ) )
+        </blockquote>
+     * <p>
+     * NOTE: This is very similar to the logic in 
+     * {@link ModelManagementHelperMDRImpl#getAllImportedElements(Object)}
+     * which returns a collection of imported elements.  Here we quit as soon
+     * as we find the element that we're testing for (and we don't deal with 
+     * the <code>friend</code> or <code>access</code> stereotypes.
+     * 
+     * @param ns
+     *                The namespace to check visibility from
+     * @param element
+     *                the element to check for visibility
+     * @return Return true if the given element is visible from this namespace.
+     */
+    private boolean isVisible(ModelElement element, Namespace ns) {
+        if (ns == null || element == null) {
             return false;
         }
-        Namespace ns1 = namespaces.get(0);
-        Namespace ns2 = namespaces.get(1);
-        // TODO: This is incorrect.  AssociationEnds must be
-        // visible from Association's namespace, not vice versa. - tfm
-        // This is also assuming a binary association
-        if (ns == getFirstSharedNamespace(ns1, ns2)) {
+
+        //  self.allConnections->forAll(r 
+        // | self.namespace.allContents->includes(r.participant) )
+        Collection nsAllContents = 
+            modelImpl.getModelManagementHelper().getAllContents(ns);
+        if (nsAllContents.contains(element)) {
             return true;
         }
+        // or
+        //      self.allConnections->forAll(
+        //              r | self.namespace.allContents->excludes
+        //      (r.participant) implies
+        //      self.namespace.clientDependency->exists (d |
+        //      d.oclIsTypeOf(Permission) and
+        //      d.stereotype.name = 'access' and
+        
+        // TODO: this actually returns permissions with stereotypes
+        // of both <<access>> and <<import>> when the spec calls for
+        // only the former, but that seems to give different semantics
+        // to the way package imports work.  Review to see which is wrong.
+        Collection<Permission> permissions = getPackageImports(ns);
+        for (Permission imp : permissions) {
+            Collection<ModelElement> suppliers = imp.getSupplier();
+            for (ModelElement me : suppliers) {
+                //  d.supplier.oclAsType(Namespace).ownedElement->select (e |
+                //  e.elementOwnership.visibility =
+                //  #public)->includes (r.participant) or
+                if (me instanceof Namespace
+                        && isVisiblyOwned(element, (Namespace) me)) {
+                    return true;
+                }
+                //  d.supplier.oclAsType(GeneralizableElement).
+                //  allParents.oclAsType(Namespace).ownedElement->select (e |
+                //              e. elementOwnership.visibility =
+                //                      #public)->includes (r.participant) or
+                if (me instanceof GeneralizableElement) {
+                    Collection<GeneralizableElement> allParents = 
+                        getAllParents((GeneralizableElement) me);
+                    for (GeneralizableElement parent : allParents) {
+                        if (parent instanceof Namespace
+                                && isVisiblyOwned(element, 
+                                        (Namespace) parent)) {
+                            return true;
+                        }
+                    }
+                }
+                //  d.supplier.oclAsType(Package).allImportedElements->select (
+                //                  e | e. elementImport.visibility =
+                //                      #public) ->includes (r.participant) ) )
+                if (me instanceof UmlPackage) {
+                    Collection<ElementImport> imports =
+                            ((UmlPackage) me).getElementImport();
+                    for (ElementImport ei : imports) {
+                        if (element.equals(ei.getImportedElement())
+                                && VisibilityKindEnum.VK_PUBLIC.equals(ei
+                                        .getVisibility())) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }       
         return false;
     }
-
+    
+    /**
+     * Returns true if ModelElement is owned by the given Namespace and it is
+     * publicly visible.
+     * 
+     * @param me ModelElement
+     * @param ns Namespace
+     * @return true if ModelElement is owned by the given Namespace and it is
+     *         publicly visible.
+     */
+    private boolean isVisiblyOwned(ModelElement me, Namespace ns) {
+        return ((Namespace) ns).getOwnedElement().contains(me)
+                && VisibilityKindEnum.VK_PUBLIC.equals(((ModelElement) me)
+                        .getVisibility());
+    }
+    
     private boolean isValidNamespace(
             GeneralizableElement generalizableElement,
             Namespace namespace) {
         
         CorePackage corePackage = modelImpl.getUmlPackage().getCore();
-        Collection<Generalization> generalizations =
-            corePackage.getAChildGeneralization().
-                getGeneralization(generalizableElement); 
+        Collection<Generalization> generalizations = 
+            generalizableElement.getGeneralization();
         
         for (Generalization generalization : generalizations) {
-            /* TODO: Fix the following problem, as described in issue 3772:
-             * Both implementations for valid namespace check whether
-             * the parents are owned by the namespace. This is invalid.
-             * The constraint
-             * [4] The parent must be included in the Namespace
-             * of the GeneralizableElement.self.generalization->forAll(g |
-             * self.namespace.allContents->includes(g.parent) )
-             * only asks that they are included,
-             * that is there can also be an elementimport
-             * at work somewhere. (same as in java - you can also use
-             * an import and then generalize, without the classes being
-             * required to be located in the same package).
-             * Symptom of this problem:
-             * Load the project attached to issue 3772. Select the "class1".
-             * The UMLModelElementNamespaceComboBoxModel gives
-             * a warning. Then add an import permission.
-             * The warning should not be given anymore. - mvw 20060408
-             */
-            // The following will do it when called method is implemented:
-//            if(!modelImpl.getModelManagementHelper().getAllContents(ns)
-//                    .contains(gen2.getParent())) {
+            // TODO: Fix the following problem, as described in issue 3772:
             GeneralizableElement parent = generalization.getParent();
-            if (!namespace.getOwnedElement().contains(parent)) {
+            if (!modelImpl.getModelManagementHelper().getAllContents(namespace)
+                    .contains(parent)) {
                 LOG.debug(parent.getName() + " is the ancestor of "
                         + generalizableElement.getName()
                         + ". It is not in the same namespace "
@@ -2174,8 +2330,7 @@
                 return;
             }
             if (handle instanceof Classifier) {
-                modelImpl.getUmlPackage().getCore().getATypedParameterType().
-                        add((Parameter) parameter, (Classifier) handle);
+                ((Parameter) parameter).setType((Classifier) handle);
                 return;
             }
         }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.