001: /**
002: * Licensed under the Common Development and Distribution License,
003: * you may not use this file except in compliance with the License.
004: * You may obtain a copy of the License at
005: *
006: * http://www.sun.com/cddl/
007: *
008: * Unless required by applicable law or agreed to in writing, software
009: * distributed under the License is distributed on an "AS IS" BASIS,
010: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * permissions and limitations under the License.
013: */package com.sun.facelets.el;
014:
015: import java.io.IOException;
016: import java.io.StringWriter;
017: import java.io.Writer;
018: import java.util.ArrayList;
019: import java.util.List;
020:
021: import javax.el.ELContext;
022: import javax.el.ELException;
023: import javax.el.ExpressionFactory;
024: import javax.el.ValueExpression;
025: import javax.faces.context.ResponseWriter;
026:
027: import com.sun.facelets.util.FastWriter;
028:
029: /**
030: * Handles parsing EL Strings in accordance with the EL-API Specification. The
031: * parser accepts either <code>${..}</code> or <code>#{..}</code>.
032: *
033: * @author Jacob Hookom
034: * @version $Id: ELText.java,v 1.7 2008/02/20 06:56:22 rlubke Exp $
035: */
036: public class ELText {
037:
038: private static final class LiteralValueExpression extends
039: ValueExpression {
040:
041: /**
042: *
043: */
044: private static final long serialVersionUID = 1L;
045:
046: private final String text;
047:
048: public LiteralValueExpression(String text) {
049: this .text = text;
050: }
051:
052: public boolean isLiteralText() {
053: return false;
054: }
055:
056: public int hashCode() {
057: return 0;
058: }
059:
060: public String getExpressionString() {
061: return this .text;
062: }
063:
064: public boolean equals(Object obj) {
065: return false;
066: }
067:
068: public void setValue(ELContext context, Object value) {
069: }
070:
071: public boolean isReadOnly(ELContext context) {
072: return false;
073: }
074:
075: public Object getValue(ELContext context) {
076: return null;
077: }
078:
079: public Class getType(ELContext context) {
080: return null;
081: }
082:
083: public Class getExpectedType() {
084: return null;
085: }
086:
087: }
088:
089: private static final class ELTextComposite extends ELText {
090: private final ELText[] txt;
091:
092: public ELTextComposite(ELText[] txt) {
093: super (null);
094: this .txt = txt;
095: }
096:
097: public void write(Writer out, ELContext ctx)
098: throws ELException, IOException {
099: for (int i = 0; i < this .txt.length; i++) {
100: this .txt[i].write(out, ctx);
101: }
102: }
103:
104: public void writeText(ResponseWriter out, ELContext ctx)
105: throws ELException, IOException {
106: for (int i = 0; i < this .txt.length; i++) {
107: this .txt[i].writeText(out, ctx);
108: }
109: }
110:
111: public String toString(ELContext ctx) {
112: StringBuffer sb = new StringBuffer();
113: for (int i = 0; i < this .txt.length; i++) {
114: sb.append(this .txt[i].toString(ctx));
115: }
116: return sb.toString();
117: }
118:
119: /*
120: * public String toString(ELContext ctx) { StringBuffer sb = new
121: * StringBuffer(); for (int i = 0; i < this.txt.length; i++) {
122: * sb.append(this.txt[i].toString(ctx)); } return sb.toString(); }
123: */
124:
125: public String toString() {
126: StringBuffer sb = new StringBuffer();
127: for (int i = 0; i < this .txt.length; i++) {
128: sb.append(this .txt[i].toString());
129: }
130: return sb.toString();
131: }
132:
133: public boolean isLiteral() {
134: return false;
135: }
136:
137: public ELText apply(ExpressionFactory factory, ELContext ctx) {
138: int len = this .txt.length;
139: ELText[] nt = new ELText[len];
140: for (int i = 0; i < len; i++) {
141: nt[i] = this .txt[i].apply(factory, ctx);
142: }
143: return new ELTextComposite(nt);
144: }
145: }
146:
147: private static final class ELTextVariable extends ELText {
148: private final ValueExpression ve;
149:
150: public ELTextVariable(ValueExpression ve) {
151: super (ve.getExpressionString());
152: this .ve = ve;
153: }
154:
155: public boolean isLiteral() {
156: return false;
157: }
158:
159: public ELText apply(ExpressionFactory factory, ELContext ctx) {
160: return new ELTextVariable(factory.createValueExpression(
161: ctx, this .ve.getExpressionString(), String.class));
162: }
163:
164: public void write(Writer out, ELContext ctx)
165: throws ELException, IOException {
166: Object v = this .ve.getValue(ctx);
167: if (v != null) {
168: out.write((String) v);
169: }
170: }
171:
172: public String toString(ELContext ctx) throws ELException {
173: Object v = this .ve.getValue(ctx);
174: if (v != null) {
175: return v.toString();
176: }
177:
178: return null;
179: }
180:
181: public void writeText(ResponseWriter out, ELContext ctx)
182: throws ELException, IOException {
183: Object v = this .ve.getValue(ctx);
184: if (v != null) {
185: out.writeText((String) v, null);
186: }
187: }
188: }
189:
190: protected final String literal;
191:
192: public ELText(String literal) {
193: this .literal = literal;
194: }
195:
196: /**
197: * If it's literal text
198: *
199: * @return true if the String is literal (doesn't contain <code>#{..}</code>
200: * or <code>${..}</code>)
201: */
202: public boolean isLiteral() {
203: return true;
204: }
205:
206: /**
207: * Return an instance of <code>this</code> that is applicable given the
208: * ELContext and ExpressionFactory state.
209: *
210: * @param factory
211: * the ExpressionFactory to use
212: * @param ctx
213: * the ELContext to use
214: * @return an ELText instance
215: */
216: public ELText apply(ExpressionFactory factory, ELContext ctx) {
217: return this ;
218: }
219:
220: /**
221: * Allow this instance to write to the passed Writer, given the ELContext
222: * state
223: *
224: * @param out
225: * Writer to write to
226: * @param ctx
227: * current ELContext state
228: * @throws ELException
229: * @throws IOException
230: */
231: public void write(Writer out, ELContext ctx) throws ELException,
232: IOException {
233: out.write(this .literal);
234: }
235:
236: public void writeText(ResponseWriter out, ELContext ctx)
237: throws ELException, IOException {
238: out.writeText(this .literal, null);
239: }
240:
241: /**
242: * Evaluates the ELText to a String
243: *
244: * @param ctx
245: * current ELContext state
246: * @throws ELException
247: * @return the evaluated String
248: */
249: public String toString(ELContext ctx) throws ELException {
250: return this .literal;
251: }
252:
253: public String toString() {
254: return this .literal;
255: }
256:
257: /**
258: * Parses the passed string to determine if it's literal or not
259: *
260: * @param in
261: * input String
262: * @return true if the String is literal (doesn't contain <code>#{..}</code>
263: * or <code>${..}</code>)
264: */
265: public static boolean isLiteral(String in) {
266: ELText txt = parse(in);
267: return txt == null || txt.isLiteral();
268: }
269:
270: /**
271: * Factory method for creating an unvalidated ELText instance. NOTE: All
272: * expressions in the passed String are treated as
273: * {@link com.sun.facelets.el.LiteralValueExpression LiteralValueExpressions}.
274: *
275: * @param in
276: * String to parse
277: * @return ELText instance that knows if the String was literal or not
278: * @throws javax.el.ELException
279: */
280: public static ELText parse(String in) throws ELException {
281: return parse(null, null, in);
282: }
283:
284: /**
285: * Factory method for creating a validated ELText instance. When an
286: * Expression is hit, it will use the ExpressionFactory to create a
287: * ValueExpression instance, resolving any functions at that time. <p/>
288: * Variables and properties will not be evaluated.
289: *
290: * @param fact
291: * ExpressionFactory to use
292: * @param ctx
293: * ELContext to validate against
294: * @param in
295: * String to parse
296: * @return ELText that can be re-applied later
297: * @throws javax.el.ELException
298: */
299: public static ELText parse(ExpressionFactory fact, ELContext ctx,
300: String in) throws ELException {
301: char[] ca = in.toCharArray();
302: int i = 0;
303: char c = 0;
304: int len = ca.length;
305: int end = len - 1;
306: boolean esc = false;
307: int vlen = 0;
308:
309: StringBuffer buff = new StringBuffer(128);
310: List text = new ArrayList();
311: ELText t = null;
312: ValueExpression ve = null;
313:
314: while (i < len) {
315: c = ca[i];
316: if ('\\' == c) {
317: esc = !esc;
318: if (esc && i < end
319: && (ca[i + 1] == '$' || ca[i + 1] == '#')) {
320: i++;
321: continue;
322: }
323: } else if (!esc && ('$' == c || '#' == c)) {
324: if (i < end) {
325: if ('{' == ca[i + 1]) {
326: if (buff.length() > 0) {
327: text.add(new ELText(buff.toString()));
328: buff.setLength(0);
329: }
330: vlen = findVarLength(ca, i);
331: if (ctx != null && fact != null) {
332: ve = fact.createValueExpression(ctx,
333: new String(ca, i, vlen),
334: String.class);
335: t = new ELTextVariable(ve);
336: } else {
337: t = new ELTextVariable(
338: new LiteralValueExpression(
339: new String(ca, i, vlen)));
340: }
341: text.add(t);
342: i += vlen;
343: continue;
344: }
345: }
346: }
347: esc = false;
348: buff.append(c);
349: i++;
350: }
351:
352: if (buff.length() > 0) {
353: text.add(new ELText(new String(buff.toString())));
354: buff.setLength(0);
355: }
356:
357: if (text.size() == 0) {
358: return null;
359: } else if (text.size() == 1) {
360: return (ELText) text.get(0);
361: } else {
362: ELText[] ta = (ELText[]) text.toArray(new ELText[text
363: .size()]);
364: return new ELTextComposite(ta);
365: }
366: }
367:
368: private static int findVarLength(char[] ca, int s)
369: throws ELException {
370: int i = s;
371: int len = ca.length;
372: char c = 0;
373: int str = 0;
374: while (i < len) {
375: c = ca[i];
376: if ('\\' == c && i < len - 1) {
377: i++;
378: } else if ('\'' == c || '"' == c) {
379: if (str == c) {
380: str = 0;
381: } else {
382: str = c;
383: }
384: } else if (str == 0 && ('}' == c)) {
385: return i - s + 1;
386: }
387: i++;
388: }
389: throw new ELException("EL Expression Unbalanced: ... "
390: + new String(ca, s, i - s));
391: }
392:
393: }
|