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 
+     * [EMAIL PROTECTED] 
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;
             }
         }

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to