001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.scxml2.model; 018 019import java.io.IOException; 020 021import javax.xml.parsers.DocumentBuilderFactory; 022import javax.xml.parsers.FactoryConfigurationError; 023import javax.xml.parsers.ParserConfigurationException; 024 025import org.apache.commons.logging.LogFactory; 026import org.apache.commons.scxml2.ActionExecutionContext; 027import org.apache.commons.scxml2.Context; 028import org.apache.commons.scxml2.Evaluator; 029import org.apache.commons.scxml2.PathResolver; 030import org.apache.commons.scxml2.SCXMLExpressionException; 031import org.w3c.dom.*; 032import org.xml.sax.SAXException; 033 034/** 035 * The class in this SCXML object model that corresponds to the 036 * <assign> SCXML element. 037 * 038 */ 039public class Assign extends Action implements PathResolverHolder { 040 041 /** 042 * Serial version UID. 043 */ 044 private static final long serialVersionUID = 1L; 045 046 /** 047 * Left hand side expression evaluating to a location within 048 * a previously defined XML data tree. 049 */ 050 private String location; 051 052 /** 053 * The source where the new XML instance for this location exists. 054 */ 055 private String src; 056 057 /** 058 * Expression evaluating to the new value of the variable. 059 */ 060 private String expr; 061 062 /** 063 * Defines the nature of the insertion to be performed, default {@link Evaluator.AssignType#REPLACE_CHILDREN} 064 */ 065 private Evaluator.AssignType type; 066 067 /** 068 * The attribute name to add at the specified location when using {@link Evaluator.AssignType#ADD_ATTRIBUTE} 069 */ 070 private String attr; 071 072 /** 073 * {@link PathResolver} for resolving the "src" result. 074 */ 075 private PathResolver pathResolver; 076 077 /** 078 * Constructor. 079 */ 080 public Assign() { 081 super(); 082 } 083 084 /** 085 * Get the expr that will evaluate to the new value. 086 * 087 * @return Returns the expr. 088 */ 089 public String getExpr() { 090 return expr; 091 } 092 093 /** 094 * Set the expr that will evaluate to the new value. 095 * 096 * @param expr The expr to set. 097 */ 098 public void setExpr(final String expr) { 099 this.expr = expr; 100 } 101 102 /** 103 * Get the location for a previously defined XML data tree. 104 * 105 * @return Returns the location. 106 */ 107 public String getLocation() { 108 return location; 109 } 110 111 /** 112 * Set the location for a previously defined XML data tree. 113 * 114 * @param location The location. 115 */ 116 public void setLocation(final String location) { 117 this.location = location; 118 } 119 120 /** 121 * Get the source where the new XML instance for this location exists. 122 * 123 * @return Returns the source. 124 */ 125 public String getSrc() { 126 return src; 127 } 128 129 /** 130 * Set the source where the new XML instance for this location exists. 131 * 132 * @param src The source. 133 */ 134 public void setSrc(final String src) { 135 this.src = src; 136 } 137 138 /** 139 * Get the {@link PathResolver}. 140 * 141 * @return Returns the pathResolver. 142 */ 143 public PathResolver getPathResolver() { 144 return pathResolver; 145 } 146 147 /** 148 * Set the {@link PathResolver}. 149 * 150 * @param pathResolver The pathResolver to set. 151 */ 152 public void setPathResolver(final PathResolver pathResolver) { 153 this.pathResolver = pathResolver; 154 } 155 156 public Evaluator.AssignType getType() { 157 return type; 158 } 159 160 public void setType(final Evaluator.AssignType type) { 161 this.type = type; 162 } 163 164 public String getAttr() { 165 return attr; 166 } 167 168 public void setAttr(final String attr) { 169 this.attr = attr; 170 } 171 172 /** 173 * {@inheritDoc} 174 */ 175 @Override 176 public void execute(ActionExecutionContext exctx) throws ModelException, SCXMLExpressionException { 177 EnterableState parentState = getParentEnterableState(); 178 Context ctx = exctx.getContext(parentState); 179 Evaluator evaluator = exctx.getEvaluator(); 180 ctx.setLocal(getNamespacesKey(), getNamespaces()); 181 Object data; 182 if (src != null && src.trim().length() > 0) { 183 data = getSrcNode(); 184 } else { 185 data = evaluator.eval(ctx, expr); 186 } 187 188 evaluator.evalAssign(ctx, location, data, type, attr); 189 if (exctx.getAppLog().isDebugEnabled()) { 190 exctx.getAppLog().debug("<assign>: '" + location + "' updated"); 191 } 192 // TODO: introduce a optional 'trace.change' setting or something alike to enable .change events, 193 // but don't do this by default as it can interfere with transitions not expecting such events 194 /* 195 if ((Evaluator.XPATH_DATA_MODEL.equals(evaluator.getSupportedDatamodel()) && location.startsWith("$") && ctx.has(location.substring(1)) 196 || ctx.has(location))) { 197 TriggerEvent ev = new TriggerEvent(location + ".change", TriggerEvent.CHANGE_EVENT); 198 exctx.getInternalIOProcessor().addEvent(ev); 199 } 200 */ 201 ctx.setLocal(getNamespacesKey(), null); 202 } 203 204 /** 205 * Get the {@link Node} the "src" attribute points to. 206 * 207 * @return The node the "src" attribute points to. 208 */ 209 private Node getSrcNode() { 210 String resolvedSrc = src; 211 if (pathResolver != null) { 212 resolvedSrc = pathResolver.resolvePath(src); 213 } 214 Document doc = null; 215 try { 216 doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(resolvedSrc); 217 } catch (FactoryConfigurationError t) { 218 logError(t); 219 } catch (SAXException e) { 220 logError(e); 221 } catch (IOException e) { 222 logError(e); 223 } catch (ParserConfigurationException e) { 224 logError(e); 225 } 226 if (doc == null) { 227 return null; 228 } 229 return doc.getDocumentElement(); 230 } 231 232 /** 233 * @param throwable The throwable to log about 234 */ 235 private void logError(Throwable throwable) { 236 org.apache.commons.logging.Log log = LogFactory. 237 getLog(Assign.class); 238 log.error(throwable.getMessage(), throwable); 239 } 240}