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: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.script.el;
020:
021: import org.apache.beehive.netui.util.internal.InternalStringBuilder;
022: import org.apache.beehive.netui.util.logging.Logger;
023:
024: /**
025: * This class represents a complete and parsed expression string. An expression can be made up
026: * of any number of ExpressionTerm and LiteralTerm objects. If this parsed expression contains
027: * a single ExpressionTerm, it is considered "atomic" because it references a single property on
028: * a single object.
029: */
030: public class ParsedExpression {
031:
032: private static Logger LOGGER = Logger
033: .getInstance(ParsedExpression.class);
034: private static final boolean TRACE_ENABLED = LOGGER
035: .isTraceEnabled();
036: private static final String EMPTY_STRING = "";
037:
038: private String _expressionString;
039: private boolean _isExpression = false;
040: private boolean _containsExpression = false;
041:
042: /**
043: * An atomic expression is the common case, so keep a pointer to the first element in the array
044: * in order to avoid doing a cast from Term to ExpressionTerm when evaluating an expression. This
045: * trades off space for time, but it's a small amount of space relatively speaking.
046: */
047: private ExpressionTerm _atomicExpression = null;
048: private Term[] _termArray = new Term[0];
049:
050: public void seal() {
051: InternalStringBuilder buf = new InternalStringBuilder();
052: for (int i = 0; i < _termArray.length; i++) {
053: Term t = _termArray[i];
054: assert t != null;
055:
056: t.seal();
057:
058: if (t instanceof ExpressionTerm) {
059: if (_termArray.length == 1) {
060: _atomicExpression = (ExpressionTerm) t;
061: _isExpression = true;
062: }
063: _containsExpression = true;
064: } else if (t instanceof LiteralTerm) {
065: String lit = t.getExpressionString();
066: if (lit != null && lit.indexOf("{") > -1)
067: _containsExpression = true;
068: }
069:
070: buf.append(t.getExpressionString());
071: }
072: _expressionString = buf.toString();
073: }
074:
075: public boolean isExpression() {
076: return _isExpression;
077: }
078:
079: public boolean containsExpression() {
080: return _containsExpression;
081: }
082:
083: public void addTerm(Term term) {
084: assert _termArray != null;
085: Term[] newTerms = new Term[_termArray.length + 1];
086: System.arraycopy(_termArray, 0, newTerms, 0, _termArray.length);
087: newTerms[_termArray.length] = term;
088: _termArray = newTerms;
089: }
090:
091: public int getTokenCount() {
092: return _termArray.length;
093: }
094:
095: public Term getTerm(int i) {
096: assert _termArray != null;
097: assert i > 0 && i < _termArray.length;
098:
099: return _termArray[i];
100: }
101:
102: public ExpressionTerm getAtomicExpressionTerm() {
103: return _atomicExpression;
104: }
105:
106: public Object evaluate(NetUIVariableResolver vr) {
107: if (TRACE_ENABLED)
108: LOGGER.trace("evaluate expression: " + _expressionString);
109:
110: if (_isExpression) {
111: if (TRACE_ENABLED)
112: LOGGER.trace("atoimc expression");
113:
114: return _atomicExpression.read(vr);
115: } else {
116: InternalStringBuilder buf = new InternalStringBuilder();
117:
118: for (int i = 0; i < _termArray.length; i++) {
119: if (TRACE_ENABLED)
120: LOGGER.trace("term[" + i + "]: "
121: + _termArray[i].getClass().getName()
122: + " expression string: "
123: + _termArray[i].getExpressionString());
124:
125: Object result = _termArray[i].read(vr);
126:
127: buf.append(result != null ? result.toString()
128: : EMPTY_STRING);
129: }
130:
131: return buf.toString();
132: }
133: }
134:
135: public void update(Object value, NetUIVariableResolver vr) {
136: if (!_isExpression) {
137: String msg = "The expression can not be updated because it is not atomic.";
138: LOGGER.error(msg);
139: throw new RuntimeException(msg);
140: }
141:
142: _atomicExpression.update(value, vr);
143: }
144:
145: public String changeContext(String oldContext, String newContext,
146: Object index) {
147: if (!_isExpression) {
148: String msg = "The expression can not change context because it is not atomic.";
149: LOGGER.error(msg);
150: throw new RuntimeException(msg);
151: }
152:
153: return _atomicExpression.changeContext(oldContext, newContext,
154: index);
155: }
156:
157: public String qualify(String implicitObjectName) {
158: return "{" + implicitObjectName + "." + getExpressionString()
159: + "}";
160: }
161:
162: public String getExpressionString() {
163: return _expressionString;
164: }
165:
166: public String toString() {
167: return _expressionString;
168: }
169: }
|