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.Reader;
028: import java.io.StringReader;
029: import java.io.StringWriter;
030: import java.io.Writer;
031: import java.util.Collection;
032: import java.util.HashSet;
033: import java.util.Iterator;
034: import java.util.Set;
035:
036: import biz.hammurapi.config.Context;
037:
038: /**
039: * @author Pavel Vlasov
040: * @version $Revision$
041: */
042: public class ExpandingFilterWriter extends FilterWriter {
043: private Context context;
044: private boolean stop;
045:
046: /**
047: * When pragma:stop token is encountered subsequent characters are not
048: * expanded until pragma:start token is encountered. pragma:start and pragma:stop are not output to
049: * filtered writer.
050: */
051: public static final String PRAGMA_STOP = "pragma:stop";
052: public static final String PRAGMA_START = "pragma:start";
053:
054: // private static final Logger logger = Logger.getLogger(ExpandingFilterWriter.class);
055:
056: private Set keySet;
057:
058: public ExpandingFilterWriter(Writer out, Context context) {
059: this (out, context, new HashSet());
060: }
061:
062: protected ExpandingFilterWriter(Writer out, Context context,
063: Set keySet) {
064: super (out);
065: this .context = context;
066: this .keySet = keySet;
067: }
068:
069: private int lastChar;
070:
071: private StringBuffer keyBuffer;
072:
073: private static final int STATE_NORMAL = 0;
074:
075: private static final int STATE_DOLLAR = 1;
076:
077: private static final int STATE_EXPRESSION = 2;
078:
079: private static final int STATE_QUOTE = 3;
080:
081: private int state = STATE_NORMAL;
082:
083: public void write(int c) throws IOException {
084: switch (c) {
085: case '$':
086: switch (state) {
087: case STATE_NORMAL:
088: state = STATE_DOLLAR;
089: break;
090: case STATE_DOLLAR:
091: state = STATE_NORMAL;
092: out.write(c);
093: if (stop) {
094: out.write(c);
095: }
096: // out.write(b);
097: break;
098: case STATE_EXPRESSION:
099: case STATE_QUOTE:
100: toBuffer(c);
101: break;
102: default:
103: throw new IOException("Invalid lexer state: " + state);
104: }
105: break;
106: case '{':
107: switch (state) {
108: case STATE_EXPRESSION:
109: case STATE_QUOTE:
110: toBuffer(c);
111: break;
112: case STATE_NORMAL:
113: out.write(c);
114: break;
115: case STATE_DOLLAR:
116: state = STATE_EXPRESSION;
117: break;
118: default:
119: throw new IOException("Invalid lexer state: " + state);
120: }
121: break;
122: case '}':
123: switch (state) {
124: case STATE_NORMAL:
125: out.write(c);
126: break;
127: case STATE_DOLLAR:
128: state = STATE_NORMAL;
129: out.write(c);
130: case STATE_EXPRESSION:
131: state = STATE_NORMAL;
132: if (keyBuffer == null || keyBuffer.length() == 0) {
133: out.write('$');
134: out.write('{');
135: out.write('}');
136: } else if (PRAGMA_START.equals(keyBuffer.toString())) {
137: stop = false;
138: keyBuffer = null;
139: } else if (PRAGMA_STOP.equals(keyBuffer.toString())) {
140: stop = true;
141: keyBuffer = null;
142: } else if (stop) {
143: out.write("${");
144: out.write(keyBuffer.toString());
145: out.write("}");
146: keyBuffer = null;
147: } else {
148: String key = keyBuffer.toString();
149: keyBuffer = null;
150:
151: if (keySet.contains(key)) {
152: throw new CircularReferenceException(
153: "Circular reference: " + key);
154: }
155:
156: Object o = context.get(key);
157: if (o == null) {
158: out.write("${");
159: out.write(key);
160: out.write("}");
161: } else {
162: if (o instanceof Collection) {
163: Iterator it = ((Collection) o).iterator();
164: while (it.hasNext()) {
165: Object object = it.next();
166: if (object == null) {
167: out.write("(null)");
168: } else {
169: try {
170: keySet.add(key);
171: out.write(toString(object,
172: context, keySet));
173: } finally {
174: keySet.remove(key);
175: }
176:
177: if (it.hasNext()) {
178: out.write(' ');
179: }
180: }
181: }
182: } else {
183: try {
184: keySet.add(key);
185: out.write(toString(o, context, keySet));
186: } finally {
187: keySet.remove(key);
188: }
189: }
190: }
191: }
192: break;
193: case STATE_QUOTE:
194: toBuffer(c);
195: break;
196: default:
197: throw new IOException("Invalid lexer state: " + state);
198: }
199: break;
200: case '"':
201: switch (state) {
202: case STATE_NORMAL:
203: out.write(c);
204: break;
205: case STATE_DOLLAR:
206: state = STATE_NORMAL;
207: out.write('$');
208: out.write(c);
209: break;
210: case STATE_EXPRESSION:
211: state = STATE_QUOTE;
212: toBuffer(c);
213: break;
214: case STATE_QUOTE:
215: if (lastChar != '\\') {
216: state = STATE_EXPRESSION;
217: }
218: toBuffer(c);
219: break;
220: default:
221: throw new IOException("Invalid lexer state: " + state);
222: }
223: break;
224: default:
225: switch (state) {
226: case STATE_NORMAL:
227: out.write(c);
228: break;
229: case STATE_DOLLAR:
230: state = STATE_NORMAL;
231: out.write('$');
232: out.write(c);
233: break;
234: case STATE_EXPRESSION:
235: case STATE_QUOTE:
236: toBuffer(c);
237: break;
238: default:
239: throw new IOException("Invalid lexer state: " + state);
240: }
241: }
242: lastChar = c;
243: }
244:
245: /**
246: * @param object
247: * @return
248: */
249: private static String toString(Object object, Context context,
250: Set keySet) {
251: try {
252: StringWriter sw = new StringWriter();
253: ExpandingFilterWriter efw = new ExpandingFilterWriter(sw,
254: context, keySet);
255: char[] buf = new char[1024];
256: StringReader reader = new StringReader(object.toString());
257: int l;
258: while ((l = reader.read(buf)) != -1) {
259: efw.write(buf, 0, l);
260: }
261: efw.close();
262: sw.close();
263: reader.close();
264: return sw.toString();
265: } catch (IOException e) {
266: throw new EvaluationException("Shall never happen", e);
267: }
268: }
269:
270: /**
271: * @param b
272: */
273: private void toBuffer(int b) {
274: if (keyBuffer == null) {
275: keyBuffer = new StringBuffer();
276: }
277: keyBuffer.append((char) b);
278: }
279:
280: public void close() throws IOException {
281: if (state == STATE_DOLLAR) {
282: out.write('$');
283: } else if (state == STATE_EXPRESSION /*|| state == STATE_QUOTE */) {
284: out.write('$');
285: out.write('{');
286: }
287:
288: if (keyBuffer != null) {
289: out.write(keyBuffer.toString());
290: keyBuffer = null;
291: }
292: out.close();
293: super .close();
294: }
295:
296: public void write(char[] cbuf, int off, int len) throws IOException {
297: for (int i = 0; i < len; i++) {
298: write(cbuf[i + off]);
299: }
300: }
301:
302: public void write(String str, int off, int len) throws IOException {
303: for (int i = 0; i < len; i++) {
304: write(str.charAt(i + off));
305: }
306: }
307:
308: public static Reader expand(Reader reader, Context context)
309: throws IOException {
310: return new StringReader(expandToString(reader, context));
311: }
312:
313: /**
314: * @param reader
315: * @param context
316: * @return
317: * @throws IOException
318: */
319: public static String expandToString(Reader reader, Context context)
320: throws IOException {
321: StringWriter sw = new StringWriter();
322: ExpandingFilterWriter efw = new ExpandingFilterWriter(sw,
323: context);
324: char[] buf = new char[1024];
325: int l;
326: while ((l = reader.read(buf)) != -1) {
327: efw.write(buf, 0, l);
328: }
329: efw.close();
330: sw.close();
331: reader.close();
332: return sw.toString();
333: }
334: }
|