View Javadoc

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