blob: 5980211ce9df1c47786a11b8e0ad55438ef098ab [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.scxml2.env.groovy;
import groovy.lang.Binding;
import groovy.lang.MissingPropertyException;
import groovy.lang.Script;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;
import org.apache.commons.scxml2.Builtin;
/**
* Groovy {@link Script} base class for SCXML, providing the standard 'builtin' function {@link #In(String)},
* as well as JEXL like convenience functions {@link #empty(Object)} and {@link #var(String)}.
*/
public abstract class GroovySCXMLScript extends Script {
GroovyContext context;
GroovyContextBinding binding;
protected GroovySCXMLScript() {
super(null);
}
@Override
public void setBinding(final Binding binding) {
super.setBinding(binding);
this.binding = (GroovyContextBinding)binding;
this.context = this.binding.getContext();
}
/**
* Implements the In() predicate for SCXML documents ( see Builtin#isMember )
* @param state The State ID to compare with
* @return Whether this State belongs to this Set
*/
public boolean In(final String state) {
return Builtin.isMember(context, state);
}
/**
* The var function can be used to check if a variable is defined,
* <p>
* In the Groovy language (implementation) you cannot check for an undefined variable directly:
* Groovy will raise a MissingPropertyException before you get the chance.
* </p>
* <p>
* The var function works around this by indirectly looking up the variable, which you therefore have to specify as a String.
* </p>
* <p>
* So, use <code>var('name')</code>, not <code>var(name)</code>
* </p>
* <p>
* Note: this function doesn't support object navigation, like <code>var('name.property')</code>.<br>
* Instead, once you established a variable 'name' exists, you <em>thereafter</em> can use the standard Groovy
* Safe Navigation operator (?.), like so: <code>name?.property</code>.<br>
* See for more information: <a href="http://docs.codehaus.org/display/GROOVY/Operators#Operators-SafeNavigationOperator(?.)">Groovy SafeNavigationOperator</a>
* </p>
*
* @param property the name of variable to check if it exists
* @return true if the variable exists, false otherwise
*/
public boolean var(String property) {
if (!context.has(property)) {
try {
getMetaClass().getProperty(this, property);
} catch (MissingPropertyException e) {
return false;
}
}
return true;
}
/**
* The empty function mimics the behavior of the JEXL empty function, in that it returns true if the parameter is:
* <ul>
* <li>null, or</li>
* <li>an empty String, or</li>
* <li>an zero length Array, or</li>
* <li>an empty Collection, or</li>
* <li>an empty Map</li>
* </ul>
* <p>
* Note: one difference with the JEXL language is that Groovy doesn't allow checking for undefined variables.<br>
* Before being able to check, Groovy will already have raised an MissingPropertyException if the variable cannot be found.<br>
* To work around this, the custom {@link #var(String)} function is available.
* </p>
*
* @param obj the object to check if it is empty
* @return true if the object is empty, false otherwise
*/
public boolean empty(Object obj) {
return obj == null ||
(obj instanceof String && ((String)obj).isEmpty()) ||
((obj.getClass().isArray() && Array.getLength(obj)==0)) ||
(obj instanceof Collection && ((Collection)obj).size()==0) ||
(obj instanceof Map && ((Map)obj).isEmpty());
}
}