svn commit: r16658 - trunk/src/argouml-app/src/org/argouml/notation/providers/uml/AbstractMessageNotationUml.java

Michiel van der Wulp <[email protected]>
Newsgroups gmane.comp.lang.uml.argouml.cvs
Message-ID <[email protected]>
Author: mvw
Date: 2009-01-19 08:04:54-0800
New Revision: 16658

Modified:
   trunk/src/argouml-app/src/org/argouml/notation/providers/uml/AbstractMessageNotationUml.java

Log:
More commenting and refactoring as preparation for issue 5150.

Modified: trunk/src/argouml-app/src/org/argouml/notation/providers/uml/AbstractMessageNotationUml.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/src/org/argouml/notation/providers/uml/AbstractMessageNotationUml.java?view=diff&pathrev=16658&r1=16657&r2=16658
==============================================================================
--- trunk/src/argouml-app/src/org/argouml/notation/providers/uml/AbstractMessageNotationUml.java	(original)
+++ trunk/src/argouml-app/src/org/argouml/notation/providers/uml/AbstractMessageNotationUml.java	2009-01-19 08:04:54-0800
@@ -98,8 +98,16 @@
  * Parsing a text that is generated by one of the backup scenarios, 
  * causes it to be written back in the script of the Action.
  * Hence, editing the text on the diagram only once 
- * causes the Action Script to be used from then on.
- *
+ * causes the Action Script to be used from then on. <p>
+ * 
+ * Supported operations for the parser: <p>
+ * <ul>
+ * <li>Locating an Operation by name and the number of arguments - 
+ * the operation is hooked to the CallAction of the Message.
+ * <li>Create an Operation with given name (no arguments).
+ * <li>etc.
+ * </ul>
+ * 
  * @see MessageNotationUml
  * @see SDMessageNotationUml
  * @since 0.28.alpha1
@@ -428,14 +436,15 @@
     protected void parseMessage(Object umlMessage, String s)
         throws ParseException {
         String fname = null;
-        StringBuilder guard = null; // the condition or iteration expression (recurrence)
+     // the condition or iteration expression (recurrence):
+        StringBuilder guard = null;
         String paramExpr = null;
         String token;
         StringBuilder varname = null;
         List<List> predecessors = new ArrayList<List>();
         List<Integer> seqno = null;
         List<Integer> currentseq = new ArrayList<Integer>();
-        List<String> args = null;
+//        List<String> args = null;
         boolean mustBePre = false;
         boolean mustBeSeq = false;
         boolean parallell = false;
@@ -443,7 +452,6 @@
         boolean mayDeleteExpr = false;
         boolean refindOperation = false;
         boolean hasPredecessors = false;
-        int i;
 
         currentseq.add(null);
         currentseq.add(null);
@@ -713,43 +721,13 @@
             throw pre;
         }
 
-        if (paramExpr != null) {
-            MyTokenizer st = new MyTokenizer(paramExpr, "\\,",
-                    parameterCustomSep);
-            args = new ArrayList<String>();
-            while (st.hasMoreTokens()) {
-                token = st.nextToken();
-
-                if (",".equals(token)) {
-                    if (args.size() == 0) {
-                        args.add(null);
-                    }
-                    args.add(null);
-                } else {
-                    if (args.size() == 0) {
-                        if (token.trim().length() == 0) {
-                            continue;
-                        }
-                        args.add(null);
-                    }
-                    String arg = args.get(args.size() - 1);
-                    if (arg != null) {
-                        arg = arg + token;
-                    } else {
-                        arg = token;
-                    }
-                    args.set(args.size() - 1, arg);
-                }
-            }
-        } else if (mayDeleteExpr) {
-            args = new ArrayList<String>();
-        }
+        List<String> args = parseArguments(paramExpr, mayDeleteExpr);
 
         if (LOG.isDebugEnabled()) {
             StringBuffer buf = new StringBuffer();
             buf.append("ParseMessage: " + s + "\n");
             buf.append("Message: ");
-            for (i = 0; seqno != null && i + 1 < seqno.size(); i += 2) {
+            for (int i = 0; seqno != null && i + 1 < seqno.size(); i += 2) {
                 if (i > 0) {
                     buf.append(", ");
                 }
@@ -757,7 +735,7 @@
             }
             buf.append("\n");
             buf.append("predecessors: " + predecessors.size() + "\n");
-            for (i = 0; i < predecessors.size(); i++) {
+            for (int i = 0; i < predecessors.size(); i++) {
                 int j;
                 List v = predecessors.get(i);
                 buf.append("    Predecessor: ");
@@ -799,22 +777,66 @@
     }
 
     /**
-     * @param umlMessage
-     * @param predecessors
-     * @param hasPredecessors
-     * @throws ParseException
+     * @param paramExpr
+     * @param mayDeleteExpr
+     * @return
+     */
+    protected List<String> parseArguments(String paramExpr,
+            boolean mayDeleteExpr) {
+        String token;
+        List<String> args = null;
+        if (paramExpr != null) {
+            MyTokenizer st = new MyTokenizer(paramExpr, "\\,",
+                    parameterCustomSep);
+            args = new ArrayList<String>();
+            while (st.hasMoreTokens()) {
+                token = st.nextToken();
+
+                if (",".equals(token)) {
+                    if (args.size() == 0) {
+                        args.add(null);
+                    }
+                    args.add(null);
+                } else {
+                    if (args.size() == 0) {
+                        if (token.trim().length() == 0) {
+                            continue;
+                        }
+                        args.add(null);
+                    }
+                    String arg = args.get(args.size() - 1);
+                    if (arg != null) {
+                        arg = arg + token;
+                    } else {
+                        arg = token;
+                    }
+                    args.set(args.size() - 1, arg);
+                }
+            }
+        } else if (mayDeleteExpr) {
+            args = new ArrayList<String>();
+        }
+        return args;
+    }
+
+    /**
+     * Set the predecessors of the given Message.
+     * 
+     * @param umlMessage the given UML Message object to be adapted
+     * @param predecessors the given predecessors as parsed
+     * @param hasPredecessors true if there are some, if false we do nothing
+     * @throws ParseException if something is wrong with the predecessor text
      */
     protected void handlePredecessors(Object umlMessage,
             List<List> predecessors, boolean hasPredecessors)
         throws ParseException {
-        int i;
-        // TODO: Predecessors is not implemented, because it
-        // causes some problems that I've not found an easy way to handle yet,
+
+        // Predecessors used to be not implemented, because it
+        // caused some problems that I've not found an easy way to handle yet,
         // d00mst. The specific problem is that the notation currently is
         // ambiguous on second message after a thread split.
-
         // Why not implement it anyway? d00mst
-
+        // TODO: Document this ambiguity and the choice made.
         if (hasPredecessors) {
             Collection roots =
                 findCandidateRoots(
@@ -823,13 +845,12 @@
                                 null,
                                 null);
             List<Object> pre = new ArrayList<Object>();
-            Iterator it;
+
         predfor:
-            for (i = 0; i < predecessors.size(); i++) {
-                it = roots.iterator();
-                while (it.hasNext()) {
+            for (int i = 0; i < predecessors.size(); i++) {
+                for (Object root : roots) {
                     Object msg =
-                        walkTree(it.next(), predecessors.get(i));
+                        walkTree(root, predecessors.get(i));
                     if (msg != null && msg != umlMessage) {
                         if (isBadPreMsg(umlMessage, msg)) {
                             String parseMsg = "parsing.error.message.one-pred";
@@ -853,31 +874,40 @@
     }
 
     /**
-     * @param umlMessage
-     * @param fname
-     * @param refindOperation
+     * Update the model with the operation name. <p>
+     * 
+     * The given operation name is located on the receiver of the given message.
+     * If an operation with the given name 
+     * and a matching number of arguments is located,
+     * then the CallAction of the message is adapted accordingly.
+     *   
+     * @param umlMessage the message of which the CallAction is to be adapted
+     * @param fname the name of the operation to be used
+     * @param refindOperation true if we have to set the operation 
+     * of the CallAction
+     * @throws ParseException if the operation syntax can not be parsed
      */
     protected void handleOperation(Object umlMessage, String fname,
-            boolean refindOperation) {
+            boolean refindOperation) throws ParseException {
         if (fname != null && refindOperation) {
             Object role = Model.getFacade().getReceiver(umlMessage);
             List ops =
                 getOperation(
-                        Model.getFacade().getBases(role),
-                        fname.trim(),
-                        Model.getFacade().getActualArguments(
-                                Model.getFacade().getAction(umlMessage)).size());
-
-            // TODO: Should someone choose one, if there are more
-            // than one?
-            if (Model.getFacade().isACallAction(
-                    Model.getFacade().getAction(umlMessage))) {
-                Object a = /* (MCallAction) */Model.getFacade().getAction(umlMessage);
+                    Model.getFacade().getBases(role),
+                    fname.trim(),
+                    Model.getFacade().getActualArguments(
+                            Model.getFacade().getAction(umlMessage)).size());
+
+            Object callAction = Model.getFacade().getAction(umlMessage);
+            if (Model.getFacade().isACallAction(callAction)) {
                 if (ops.size() > 0) {
-                    Model.getCommonBehaviorHelper().setOperation(a,
-                            /* (MOperation) */ops.get(0));
+                    // If there are more than one suitable operation,
+                    // then we pick the first one.
+                    Model.getCommonBehaviorHelper().setOperation(callAction,
+                            ops.get(0));
                 } else {
-                    Model.getCommonBehaviorHelper().setOperation(a, null);
+                    Model.getCommonBehaviorHelper().setOperation(
+                            callAction, null);
                 }
             }
         }
@@ -1099,11 +1129,18 @@
     }
 
     /**
-     * @param umlMessage
-     * @param fname
-     * @param varname
-     * @param refindOperation
-     * @return
+     * Store the given function name and return variable name 
+     * in the script of the action of the given message. <p>
+     * 
+     * Constraint: the given Message shall have an Action.
+     * 
+     * @param umlMessage the given UML Message object to adapt
+     * @param fname the name of the function
+     * @param varname the return variable name
+     * @param refindOperation if false, then we may return true or false. 
+     * If true, we return true.
+     * @return true if we stored the fname and varname 
+     * in the Action of the Message
      */
     protected boolean handleFunctionName(Object umlMessage, String fname,
             StringBuilder varname, boolean refindOperation) {
@@ -1113,18 +1150,18 @@
                 expr = varname.toString().trim() + " := " + expr;
             }
 
-            if (Model.getFacade().getScript(
-                    Model.getFacade().getAction(umlMessage)) == null
-                    || !expr.equals(Model.getFacade().getBody(
-                            Model.getFacade().getScript(
-                                    Model.getFacade().getAction(umlMessage))))) {
-                Object e =
+            Object action = Model.getFacade().getAction(umlMessage);
+            assert action != null;
+            Object script = Model.getFacade().getScript(action);
+            if (script == null
+                    || !expr.equals(Model.getFacade().getBody(script))) {
+                Object newActionExpression =
                     Model.getDataTypesFactory()
                         .createActionExpression(
                             getExpressionLanguage(),
                             expr.trim());
                 Model.getCommonBehaviorHelper().setScript(
-                        Model.getFacade().getAction(umlMessage), e);
+                        action, newActionExpression);
                 refindOperation = true;
             }
         }
@@ -1132,23 +1169,25 @@
     }
 
     /**
-     * @param umlMessage
-     * @param varname
-     * @param mayDeleteExpr
-     * @return
+     * Fill in the variable name if it is blank.  <p>
+     * The variable name is the part in front of the assignment operator.
+     * 
+     * @param umlMessage the given message to fill the variable name for
+     * @param varname if null, then we get the variable name from the model. 
+     * @param mayDeleteExpr if true, then we may delete the variable, 
+     * and hence we return an empty string
+     * @return the original variable name, or if it was null, 
+     * a variable name generated from the model
      */
     protected StringBuilder fillBlankVariableName(Object umlMessage,
             StringBuilder varname, boolean mayDeleteExpr) {
         /* If no variable name was given, then retain the one in the model. */
         if (varname == null) {
-            if (!mayDeleteExpr
-                    && Model.getFacade().getScript(
-                            Model.getFacade().getAction(umlMessage))
-                            != null) {
+            Object script = Model.getFacade().getScript(
+                    Model.getFacade().getAction(umlMessage));
+            if (!mayDeleteExpr && script != null) {
                 String body =
-                    (String) Model.getFacade().getBody(
-                            Model.getFacade().getScript(
-                                    Model.getFacade().getAction(umlMessage)));
+                    (String) Model.getFacade().getBody(script);
                 int idx = body.indexOf(":=");
                 if (idx < 0) {
                     idx = body.indexOf("=");
@@ -1167,23 +1206,26 @@
     }
 
     /**
-     * @param umlMessage
-     * @param fname
-     * @param mayDeleteExpr
-     * @return
+     * Fill in the function name if it is blank. <p>
+     * 
+     * The fname is the part of the script after the assignment operator.
+     * 
+     * @param umlMessage the given message to fill the fname for
+     * @param fname if null, then we get the fname from the model. 
+     * @param mayDeleteExpr if true, then we may delete the function, 
+     * and hence we return an empty string
+     * @return the original fname, or if it was null, 
+     * a fname generated from the model
      */
     protected String fillBlankFunctionName(Object umlMessage, String fname,
             boolean mayDeleteExpr) {
         /* If no function-name was given, then retain the one in the model. */
         if (fname == null) {
-            if (!mayDeleteExpr
-                    && Model.getFacade().getScript(
-                            Model.getFacade().getAction(umlMessage))
-                            != null) {
+            Object script = Model.getFacade().getScript(
+                    Model.getFacade().getAction(umlMessage));
+            if (!mayDeleteExpr && script != null) {
                 String body =
-                    (String) Model.getFacade().getBody(
-                            Model.getFacade().getScript(
-                                    Model.getFacade().getAction(umlMessage)));
+                    (String) Model.getFacade().getBody(script);
 
                 int idx = body.indexOf(":=");
                 if (idx >= 0) {
@@ -1210,7 +1252,8 @@
      * @param umlMessage the UML Message object
      * @param guard the guard expression string
      * @param parallell true if parallel execution was indicated
-     * @param iterative true if this is an iterative expression, as opposed to a condition
+     * @param iterative true if this is an iterative expression, 
+     * as opposed to a condition
      */
     protected void handleGuard(Object umlMessage, StringBuilder guard,
             boolean parallell, boolean iterative) {
@@ -1234,9 +1277,10 @@
     }
 
     /**
-     * Build an Action for the given UML Message if it did not have one yet.
+     * Build a CallAction for the given UML Message
+     * if it did not have an Action yet.
      * 
-     * @param umlMessage
+     * @param umlMessage the UML Message object to create an Action for
      */
     protected void buildAction(Object umlMessage) {
         if (Model.getFacade().getAction(umlMessage) == null) {
@@ -1250,7 +1294,14 @@
     }
 
     /**
-     * TODO: This name of the expression language should be configurable by the user.
+     * TODO: This name of the expression language should be 
+     * configurable by the user. <p>
+     * 
+     * According to the UML standard, 
+     * the expression language should be the same 
+     * for all elements in one diagram. <p>
+     * 
+     * UML is not a sensible default - usually this is some pseudo-language.
      * 
      * @return the name of the expression language
      */
@@ -1259,7 +1310,8 @@
     }
 
     /**
-     * Walks a call tree from a root node following the directions given in path
+     * Walks a call tree from a <code>root</code> node 
+     * following the directions given in <code>path</code>
      * to a destination node. If the destination node cannot be reached, then
      * null is returned.
      *
@@ -1597,50 +1649,47 @@
     }
 
     /**
-     * Finds the operations in Collection c with the given name 
+     * Finds all operations in a given collection of classifiers 
+     * with the given name 
      * and the given number of parameters. 
-     * If no operation is found, one is created. The applicable
-     * operations are returned.
+     * If no operation is found, one is created in the first given Classifier. 
+     * The applicable operations are returned.
      *
-     * @param c the collection of operations to be searched
+     * @param classifiers the collection of classifiers to search for operations
      * @param name the name of the operation to be found
      * @param params the number of parameters of the operation to be found
      * @return a list of the sought operations
+     * @throws ParseException if the operation syntax can not be parsed
      */
-    private List getOperation(Collection c, String name, int params) {
-        List<Object> ops = new ArrayList<Object>();
-        Iterator it;
+    private List getOperation(Collection classifiers, String name, int params) 
+        throws ParseException {
+        List<Object> operations = new ArrayList<Object>();
     
         if (name == null || name.length() == 0) {
-            return ops;
+            return operations;
         }
     
-        it = c.iterator();
-        while (it.hasNext()) {
-            Object clf = /* (MClassifier) */it.next();
+        for (Object clf : classifiers) {
             Collection oe = Model.getFacade().getFeatures(clf);
-            Iterator it2 = oe.iterator();
-            while (it2.hasNext()) {
-                Object me = /* (MModelElement) */it2.next();
-                if (!(Model.getFacade().isAOperation(me))) {
+            for (Object operation : oe) {
+                if (!(Model.getFacade().isAOperation(operation))) {
                     continue;
                 }
-    
-                Object op = /* (MOperation) */me;
-                if (!name.equals(Model.getFacade().getName(op))) {
+
+                if (!name.equals(Model.getFacade().getName(operation))) {
                     continue;
                 }
-                if (params != countParameters(op)) {
+                if (params != countParameters(operation)) {
                     continue;
                 }
-                ops.add(op);
+                operations.add(operation);
             }
         }
-        if (ops.size() > 0) {
-            return ops;
+        if (operations.size() > 0) {
+            return operations;
         }
     
-        it = c.iterator();
+        Iterator it = classifiers.iterator();
         if (it.hasNext()) {
             StringBuilder expr = new StringBuilder(name + "(");
             int i;
@@ -1660,17 +1709,11 @@
                         .getCurrentProject().getDefaultReturnType();
             Object op = Model.getCoreFactory().buildOperation(cls, returnType);
     
-            try {
-                (new OperationNotationUml(op)).parseOperation(
+            new OperationNotationUml(op).parseOperation(
                         expr.toString(), op);
-            } catch (ParseException pe) {
-                LOG.error("Unexpected ParseException in getOperation: " + pe,
-                        pe);
-    
-            }
-            ops.add(op);
+            operations.add(op);
         }
-        return ops;
+        return operations;
     }
 
     /**
@@ -1706,7 +1749,8 @@
         }
 
         activator = Model.getFacade().getActivator(umlMessage);
-        for (Object predecessor : Model.getFacade().getPredecessors(umlMessage)) {
+        for (Object predecessor 
+                : Model.getFacade().getPredecessors(umlMessage)) {
             if (Model.getFacade().getActivator(predecessor) 
                     != activator) {
                 continue;

------------------------------------------------------
http://argouml.tigris.org/ds/viewMessage.do?dsForumId=5905&dsMessageId=1034925

To unsubscribe from this discussion, e-mail: [[email protected]].
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.