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.scxml2.model;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.apache.commons.scxml2.ActionExecutionContext;
23 import org.apache.commons.scxml2.Context;
24 import org.apache.commons.scxml2.Evaluator;
25 import org.apache.commons.scxml2.SCXMLExpressionException;
26 import org.apache.commons.scxml2.TriggerEvent;
27 import org.apache.commons.scxml2.semantics.ErrorConstants;
28
29 /**
30 * The class in this SCXML object model that corresponds to the
31 * <if> SCXML element, which serves as a container for conditionally
32 * executed elements. <else> and <elseif> can optionally
33 * appear within an <if> as immediate children, and serve to partition
34 * the elements within an <if>.
35 *
36 */
37 public class If extends Action implements ActionsContainer {
38
39 /**
40 * Serial version UID.
41 */
42 private static final long serialVersionUID = 1L;
43
44 /**
45 * An conditional expression which can be evaluated to true or false.
46 */
47 private String cond;
48
49 /**
50 * The set of executable elements (those that inheriting from
51 * Action) that are contained in this <if> element.
52 */
53 private List<Action> actions;
54
55 /**
56 * The boolean value that dictates whether the particular child action
57 * should be executed.
58 */
59 private boolean execute;
60
61 /**
62 * Constructor.
63 */
64 public If() {
65 super();
66 this.actions = new ArrayList<Action>();
67 this.execute = false;
68 }
69
70 @Override
71 public final String getContainerElementName() {
72 return ELEM_IF;
73 }
74
75 /**
76 * Get the executable actions contained in this <if>.
77 *
78 * @return Returns the actions.
79 */
80 public final List<Action> getActions() {
81 return actions;
82 }
83
84 /**
85 * Add an Action to the list of executable actions contained in
86 * this <if>.
87 *
88 * @param action The action to add.
89 */
90 public final void addAction(final Action action) {
91 if (action != null) {
92 this.actions.add(action);
93 }
94 }
95
96 /**
97 * Get the conditional expression.
98 *
99 * @return Returns the cond.
100 */
101 public final String getCond() {
102 return cond;
103 }
104
105 /**
106 * Set the conditional expression.
107 *
108 * @param cond The cond to set.
109 */
110 public final void setCond(final String cond) {
111 this.cond = cond;
112 }
113
114 /**
115 * {@inheritDoc}
116 */
117 @Override
118 public void execute(ActionExecutionContext exctx) throws ModelException, SCXMLExpressionException {
119 EnterableState parentState = getParentEnterableState();
120 Context ctx = exctx.getContext(parentState);
121 Evaluator eval = exctx.getEvaluator();
122 ctx.setLocal(getNamespacesKey(), getNamespaces());
123 Boolean rslt;
124 try {
125 rslt = eval.evalCond(ctx, cond);
126 if (rslt == null) {
127 if (exctx.getAppLog().isDebugEnabled()) {
128 exctx.getAppLog().debug("Treating as false because the cond expression was evaluated as null: '"
129 + cond + "'");
130 }
131 rslt = Boolean.FALSE;
132 }
133 } catch (SCXMLExpressionException e) {
134 rslt = Boolean.FALSE;
135 exctx.getInternalIOProcessor().addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
136 exctx.getErrorReporter().onError(ErrorConstants.EXPRESSION_ERROR, "Treating as false due to error: "
137 + e.getMessage(), this);
138 }
139 execute = rslt;
140 ctx.setLocal(getNamespacesKey(), null);
141 // The "if" statement is a "container"
142 for (Action aa : actions) {
143 if (execute && !(aa instanceof ElseIf)) {
144 aa.execute(exctx);
145 } else if (execute && aa instanceof ElseIf) {
146 break;
147 } else if (aa instanceof Else) {
148 execute = true;
149 } else if (aa instanceof ElseIf) {
150 ctx.setLocal(getNamespacesKey(), getNamespaces());
151 execute = eval.evalCond(ctx, ((ElseIf) aa).getCond());
152 ctx.setLocal(getNamespacesKey(), null);
153 }
154 }
155 }
156
157 }
158