001: /*
002: * hgcommons 7
003: * Hammurapi Group Common Library
004: * Copyright (C) 2003 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/hammurapi-group/products/products/hgcommons/index.html
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.eval;
024:
025: import java.io.FilterWriter;
026: import java.io.IOException;
027: import java.io.PrintWriter;
028: import java.io.Writer;
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.HashMap;
032: import java.util.HashSet;
033: import java.util.Iterator;
034: import java.util.Map;
035: import java.util.Set;
036:
037: import org.apache.log4j.Logger;
038:
039: import biz.hammurapi.config.Context;
040: import biz.hammurapi.config.MapContext;
041: import biz.hammurapi.convert.CompositeConverter;
042:
043: /**
044: * @author Pavel Vlasov
045: * @version $Revision$
046: */
047: public class EvaluatingFilterWriter extends FilterWriter {
048: private int mode;
049:
050: private Context context;
051:
052: private CompositeConverter converter;
053:
054: private static final Logger logger = Logger
055: .getLogger(EvaluatingFilterWriter.class);
056:
057: private Set keySet;
058:
059: public EvaluatingFilterWriter(Writer out, int mode,
060: Context context, CompositeConverter converter) {
061: this (out, mode, context, converter, new HashSet());
062: }
063:
064: private EvaluatingFilterWriter(Writer out, int mode,
065: Context context, CompositeConverter converter, Set keySet) {
066: super (out);
067: this .mode = mode;
068: this .context = context;
069: this .converter = converter;
070: this .keySet = keySet;
071: }
072:
073: private int lastChar;
074:
075: private StringBuffer expressionBuffer;
076:
077: private static final int STATE_NORMAL = 0;
078:
079: private static final int STATE_DOLLAR = 1;
080:
081: private static final int STATE_EXPRESSION = 2;
082:
083: private static final int STATE_QUOTE = 3;
084:
085: public static final int MODE_LENIENT = 0;
086:
087: public static final int MODE_MESSAGE = 1;
088:
089: public static final int MODE_STRICT = 2;
090:
091: private int state = STATE_NORMAL;
092:
093: public void write(int c) throws IOException {
094: switch (c) {
095: case '$':
096: switch (state) {
097: case STATE_NORMAL:
098: state = STATE_DOLLAR;
099: break;
100: case STATE_DOLLAR:
101: state = STATE_NORMAL;
102: out.write(c);
103: // out.write(b);
104: break;
105: case STATE_EXPRESSION:
106: case STATE_QUOTE:
107: toBuffer(c);
108: break;
109: default:
110: throw new IOException("Invalid lexer state: " + state);
111: }
112: break;
113: case '{':
114: switch (state) {
115: case STATE_EXPRESSION:
116: case STATE_QUOTE:
117: toBuffer(c);
118: break;
119: case STATE_NORMAL:
120: out.write(c);
121: break;
122: case STATE_DOLLAR:
123: state = STATE_EXPRESSION;
124: break;
125: default:
126: throw new IOException("Invalid lexer state: " + state);
127: }
128: break;
129: case '}':
130: switch (state) {
131: case STATE_NORMAL:
132: out.write(c);
133: break;
134: case STATE_DOLLAR:
135: state = STATE_NORMAL;
136: out.write(c);
137: case STATE_EXPRESSION:
138: state = STATE_NORMAL;
139: if (expressionBuffer == null) {
140: out.write('$');
141: out.write('{');
142: out.write('}');
143: } else {
144: String expression = expressionBuffer.toString();
145: expressionBuffer = null;
146: try {
147: Evaluator evaluator = new Evaluator(expression,
148: null, converter);
149: Iterator it = evaluator.evaluate(context)
150: .iterator();
151: while (it.hasNext()) {
152: Object object = it.next();
153: if (object == null) {
154: out.write("(null)");
155: } else {
156: out.write(object.toString());
157: if (it.hasNext()) {
158: out.write(' ');
159: }
160: }
161: }
162: } catch (EvaluationException e) {
163: switch (mode) {
164: case MODE_LENIENT:
165: logger.warn("Evaluation failed for: "
166: + expression, e);
167: out.write("${" + expression + "}");
168: break;
169: case MODE_MESSAGE:
170: logger.warn("Evaluation failed for: "
171: + expression, e);
172: out.write(" *** Evaluation failed for: "
173: + expression + " *** ");
174: break;
175: case MODE_STRICT:
176: logger.error("Evaluation failed for: "
177: + expression, e);
178: throw new IOException(
179: "Evaluation failed for: '"
180: + expression + "' - " + e);
181: default:
182: throw new IOException("Invalid mode: "
183: + mode);
184: }
185: }
186: }
187: break;
188: case STATE_QUOTE:
189: toBuffer(c);
190: break;
191: default:
192: throw new IOException("Invalid lexer state: " + state);
193: }
194: break;
195: case '"':
196: switch (state) {
197: case STATE_NORMAL:
198: out.write(c);
199: break;
200: case STATE_DOLLAR:
201: state = STATE_NORMAL;
202: out.write(c);
203: break;
204: case STATE_EXPRESSION:
205: state = STATE_QUOTE;
206: toBuffer(c);
207: break;
208: case STATE_QUOTE:
209: if (lastChar != '\\') {
210: state = STATE_EXPRESSION;
211: }
212: toBuffer(c);
213: break;
214: default:
215: throw new IOException("Invalid lexer state: " + state);
216: }
217: break;
218: default:
219: switch (state) {
220: case STATE_NORMAL:
221: out.write(c);
222: break;
223: case STATE_DOLLAR:
224: state = STATE_NORMAL;
225: out.write(c);
226: break;
227: case STATE_EXPRESSION:
228: case STATE_QUOTE:
229: toBuffer(c);
230: break;
231: default:
232: throw new IOException("Invalid lexer state: " + state);
233: }
234: }
235: lastChar = c;
236: }
237:
238: /**
239: * @param b
240: */
241: private void toBuffer(int b) {
242: if (expressionBuffer == null) {
243: expressionBuffer = new StringBuffer();
244: }
245: expressionBuffer.append((char) b);
246: }
247:
248: public void close() throws IOException {
249: if (state == STATE_DOLLAR) {
250: out.write('$');
251: } else if (state == STATE_EXPRESSION || state == STATE_QUOTE) {
252: out.write('$');
253: out.write('{');
254: }
255:
256: if (expressionBuffer != null) {
257: out.write(expressionBuffer.toString());
258: expressionBuffer = null;
259: }
260: out.close();
261: super .close();
262: }
263:
264: public static void main(String[] args) throws Exception {
265: Map ctx = new HashMap();
266: ctx.put("request", "Mama mila ramu");
267: ctx.put("a", new String[] { "a", "b", "c", "d" });
268: Collection values = new ArrayList();
269: values.add("Pasha");
270: values.add("Olga");
271: values.add("Daniel");
272:
273: EvaluatingFilterWriter efw = new EvaluatingFilterWriter(
274: new PrintWriter(System.out), MODE_STRICT,
275: new MapContext(ctx), CompositeConverter
276: .getDefaultConverter());
277:
278: efw.write("Simple ${a[1].length()} test ${zz}");
279: efw.close();
280: }
281:
282: public void write(char[] cbuf, int off, int len) throws IOException {
283: for (int i = 0; i < len; i++) {
284: write(cbuf[i + off]);
285: }
286: }
287:
288: public void write(String str, int off, int len) throws IOException {
289: for (int i = 0; i < len; i++) {
290: write(str.charAt(i + off));
291: }
292: }
293: }
|