View Javadoc

    1   /*
    2    *
    3    *   Copyright 2005 The Apache Software Foundation.
    4    *
    5    *  Licensed under the Apache License, Version 2.0 (the "License");
    6    *  you may not use this file except in compliance with the License.
    7    *  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   *  Unless required by applicable law or agreed to in writing, software
    12   *  distributed under the License is distributed on an "AS IS" BASIS,
    13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   *  See the License for the specific language governing permissions and
    15   *  limitations under the License.
    16   *
    17   */
    18  package org.apache.commons.scxml.model;
    19
    20  import java.util.Collection;
    21
    22  import javax.xml.parsers.DocumentBuilderFactory;
    23
    24  import org.apache.commons.logging.Log;
    25  import org.apache.commons.logging.LogFactory;
    26  import org.apache.commons.scxml.Context;
    27  import org.apache.commons.scxml.ErrorReporter;
    28  import org.apache.commons.scxml.Evaluator;
    29  import org.apache.commons.scxml.EventDispatcher;
    30  import org.apache.commons.scxml.PathResolver;
    31  import org.apache.commons.scxml.SCInstance;
    32  import org.apache.commons.scxml.SCXMLExpressionException;
    33  import org.apache.commons.scxml.SCXMLHelper;
    34  import org.apache.commons.scxml.TriggerEvent;
    35  import org.w3c.dom.Document;
    36  import org.w3c.dom.Node;
    37
    38  /***
    39   * The class in this SCXML object model that corresponds to the
    40   * &lt;assign&gt; SCXML element.
    41   *
    42   */
    43  public final class Assign extends Action implements PathResolverHolder {
    44
    45      /***
    46       * Left hand side expression evaluating to a previously
    47       * defined variable.
    48       */
    49      private String name;
    50
    51      /***
    52       * Left hand side expression evaluating to a location within
    53       * a previously defined XML data tree.
    54       */
    55      private String location;
    56
    57      /***
    58       * The source where the new XML instance for this location exists.
    59       */
    60      private String src;
    61
    62      /***
    63       * Expression evaluating to the new value of the variable.
    64       */
    65      private String expr;
    66
    67      /***
    68       * {@link PathResolver} for resolving the "src" result.
    69       */
    70      private PathResolver pathResolver;
    71
    72      /***
    73       * Constructor.
    74       */
    75      public Assign() {
    76          super();
    77      }
    78
    79      /***
    80       * Get the variable to be assigned a new value.
    81       *
    82       * @return Returns the name.
    83       */
    84      public String getName() {
    85          return name;
    86      }
    87
    88      /***
    89       * Get the variable to be assigned a new value.
    90       *
    91       * @param name The name to set.
    92       */
    93      public void setName(final String name) {
    94          this.name = name;
    95      }
    96
    97      /***
    98       * Get the expr that will evaluate to the new value.
    99       *
    100      * @return Returns the expr.
    101      */
    102     public String getExpr() {
    103         return expr;
    104     }
    105
    106     /***
    107      * Set the expr that will evaluate to the new value.
    108      *
    109      * @param expr The expr to set.
    110      */
    111     public void setExpr(final String expr) {
    112         this.expr = expr;
    113     }
    114
    115     /***
    116      * Get the location for a previously defined XML data tree.
    117      *
    118      * @return Returns the location.
    119      */
    120     public String getLocation() {
    121         return location;
    122     }
    123
    124     /***
    125      * Set the location for a previously defined XML data tree.
    126      *
    127      * @param location The location.
    128      */
    129     public void setLocation(final String location) {
    130         this.location = location;
    131     }
    132
    133     /***
    134      * Get the source where the new XML instance for this location exists.
    135      *
    136      * @return Returns the source.
    137      */
    138     public String getSrc() {
    139         return src;
    140     }
    141
    142     /***
    143      * Set the source where the new XML instance for this location exists.
    144      *
    145      * @param src The source.
    146      */
    147     public void setSrc(final String src) {
    148         this.src = src;
    149     }
    150
    151     /***
    152      * Get the {@link PathResolver}.
    153      *
    154      * @return Returns the pathResolver.
    155      */
    156     public PathResolver getPathResolver() {
    157         return pathResolver;
    158     }
    159
    160     /***
    161      * Set the {@link PathResolver}.
    162      *
    163      * @param pathResolver The pathResolver to set.
    164      */
    165     public void setPathResolver(final PathResolver pathResolver) {
    166         this.pathResolver = pathResolver;
    167     }
    168
    169     /***
    170      * {@inheritDoc}
    171      */
    172     public void execute(final EventDispatcher evtDispatcher,
    173             final ErrorReporter errRep, final SCInstance scInstance,
    174             final Log appLog, final Collection derivedEvents)
    175     throws ModelException, SCXMLExpressionException {
    176         State parentState = getParentState();
    177         Context ctx = scInstance.getContext(parentState);
    178         Evaluator eval = scInstance.getEvaluator();
    179         // "location" gets preference over "name"
    180         if (!SCXMLHelper.isStringEmpty(location)) {
    181             Node oldNode = eval.evalLocation(ctx, location);
    182             if (oldNode != null) {
    183                 //// rvalue may be ...
    184                 // a Node, if so, import it at location
    185                 Node newNode = null;
    186                 try {
    187                     if (src != null && src.trim().length() > 0) {
    188                         newNode = getSrcNode();
    189                     } else {
    190                         newNode = eval.evalLocation(ctx, expr);
    191                     }
    192                     if (newNode != null) {
    193                         // adopt children, possible spec clarification needed
    194                         for (Node child = newNode.getFirstChild();
    195                                 child != null;
    196                                 child = child.getNextSibling()) {
    197                             Node importedNode = oldNode.getOwnerDocument().
    198                                 importNode(child, true);
    199                             oldNode.appendChild(importedNode);
    200                         }
    201                     }
    202                 } catch (SCXMLExpressionException see) {
    203                     // or something else, stuff toString() into lvalue
    204                     Object valueObject = eval.eval(ctx, expr);
    205                     SCXMLHelper.setNodeValue(oldNode, valueObject.toString());
    206                 }
    207                 TriggerEvent ev = new TriggerEvent(name + ".change",
    208                     TriggerEvent.CHANGE_EVENT);
    209                 derivedEvents.add(ev);
    210             } else {
    211                 appLog.error("<assign>: location does not point to"
    212                     + " a <data> node");
    213             }
    214         } else {
    215             // lets try "name" (usage as in Sep '05 WD, useful with <var>)
    216             if (!ctx.has(name)) {
    217                 errRep.onError(ErrorReporter.UNDEFINED_VARIABLE, name
    218                     + " = null", parentState);
    219             } else {
    220                 Object varObj = null;
    221                 if (src != null && src.trim().length() > 0) {
    222                     varObj = getSrcNode();
    223                 } else {
    224                     varObj = eval.eval(ctx, expr);
    225                 }
    226                 ctx.set(name, varObj);
    227                 TriggerEvent ev = new TriggerEvent(name + ".change",
    228                     TriggerEvent.CHANGE_EVENT);
    229                 derivedEvents.add(ev);
    230             }
    231         }
    232     }
    233
    234     /***
    235      * Get the {@link Node} the "src" attribute points to.
    236      *
    237      * @return The node the "src" attribute points to.
    238      */
    239     private Node getSrcNode() {
    240         String resolvedSrc = src;
    241         if (pathResolver != null) {
    242             resolvedSrc = pathResolver.resolvePath(src);
    243         }
    244         Document doc = null;
    245         try {
    246             doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().
    247                 parse(resolvedSrc);
    248         } catch (Throwable t) {
    249             org.apache.commons.logging.Log log = LogFactory.
    250                 getLog(Assign.class);
    251             log.error(t.getMessage(), t);
    252         }
    253         if (doc == null) {
    254             return null;
    255         }
    256         return doc.getDocumentElement();
    257     }
    258
    259 }