001    /*
002    @license.text@
003     */
004    package biz.hammurapi.eval;
005    
006    import java.io.FilterWriter;
007    import java.io.IOException;
008    import java.io.Writer;
009    import java.util.HashSet;
010    import java.util.Iterator;
011    import java.util.Set;
012    
013    import org.apache.log4j.Logger;
014    
015    import biz.hammurapi.config.Context;
016    import biz.hammurapi.convert.Converter;
017    
018    
019    /**
020     * @author Pavel Vlasov
021     * @version $Revision$
022     */
023    public class EvaluatingFilterWriter extends FilterWriter {
024        private int mode;
025    
026        private Context context;
027    
028        private Converter converter;
029    
030        private static final Logger logger = Logger.getLogger(EvaluatingFilterWriter.class);
031    
032            private Set keySet;
033    
034        public EvaluatingFilterWriter(
035                Writer out, 
036                int mode,
037                Context context, 
038                Converter converter) {
039                    this(out,mode,context, converter,new HashSet());
040        }
041        
042        private EvaluatingFilterWriter(
043                Writer out, 
044                int mode,
045                Context context, 
046                Converter converter,
047                            Set keySet) {
048            super(out);
049            this.mode = mode;
050            this.context = context;
051            this.converter = converter;
052            this.keySet=keySet;
053        }
054    
055        private int lastChar;
056    
057        private StringBuffer expressionBuffer;
058    
059        private static final int STATE_NORMAL = 0;
060    
061        private static final int STATE_DOLLAR = 1;
062    
063        private static final int STATE_EXPRESSION = 2;
064    
065        private static final int STATE_QUOTE = 3;
066    
067        public static final int MODE_LENIENT = 0;
068    
069        public static final int MODE_MESSAGE = 1;
070    
071        public static final int MODE_STRICT = 2;
072    
073        private int state = STATE_NORMAL;
074    
075        public void write(int c) throws IOException {
076            switch (c) {
077                    case '$':
078                        switch (state) {
079                                case STATE_NORMAL:
080                                    state = STATE_DOLLAR;
081                                    break;
082                                case STATE_DOLLAR:
083                                    state = STATE_NORMAL;
084                                    out.write(c);
085    //                              out.write(b);
086                                    break;
087                                case STATE_EXPRESSION:
088                                case STATE_QUOTE:
089                                    toBuffer(c);
090                                    break;
091                                default:
092                                    throw new IOException("Invalid lexer state: " + state);
093                        }
094                        break;
095                    case '{':
096                        switch (state) {
097                                case STATE_EXPRESSION:
098                                case STATE_QUOTE:
099                                    toBuffer(c);
100                                    break;
101                                case STATE_NORMAL:
102                                    out.write(c);
103                                    break;
104                                case STATE_DOLLAR:
105                                    state = STATE_EXPRESSION;
106                                    break;
107                                default:
108                                    throw new IOException("Invalid lexer state: " + state);
109                        }
110                        break;
111                    case '}':
112                        switch (state) {
113                                case STATE_NORMAL:
114                                    out.write(c);
115                                    break;
116                                case STATE_DOLLAR:
117                                    state = STATE_NORMAL;
118                                    out.write(c);
119                                case STATE_EXPRESSION:
120                                    state = STATE_NORMAL;
121                                    if (expressionBuffer == null) {
122                                        out.write('$');
123                                        out.write('{');
124                                        out.write('}');
125                                    } else {
126                                        String expression = expressionBuffer.toString();
127                                        expressionBuffer = null;
128                                        try {
129                                            Evaluator evaluator = new Evaluator(expression, null, converter);
130                                            Iterator it = evaluator.evaluate(context).iterator();
131                                            while (it.hasNext()) {
132                                                Object object = it.next();
133                                                if (object == null) {
134                                                    out.write("(null)");
135                                                } else {
136                                                    out.write(object.toString());
137                                                    if (it.hasNext()) {
138                                                        out.write(' ');
139                                                    }
140                                                }
141                                            }               
142                                        } catch (EvaluationException e) {
143                                            switch (mode) {
144                                                    case MODE_LENIENT:
145                                                        logger.warn("Evaluation failed for: " + expression,  e);
146                                                        out.write("${"+expression+"}");
147                                                        break;
148                                                    case MODE_MESSAGE:
149                                                        logger.warn("Evaluation failed for: " + expression,  e);
150                                                        out.write(" *** Evaluation failed for: " + expression+" *** ");
151                                                        break;                                  
152                                                    case MODE_STRICT:
153                                                        logger.error("Evaluation failed for: " + expression,  e);                               
154                                                        throw new IOException("Evaluation failed for: '" + expression+"' - " + e);
155                                                default:
156                                                    throw new IOException("Invalid mode: "+mode);
157                                            }
158                                        }
159                                    }
160                                    break;
161                                case STATE_QUOTE:
162                                    toBuffer(c);
163                                    break;
164                                default:
165                                    throw new IOException("Invalid lexer state: " + state);
166                            }
167                        break;
168                    case '"':
169                        switch (state) {
170                                case STATE_NORMAL:
171                                    out.write(c);
172                                    break;
173                                case STATE_DOLLAR:
174                                    state=STATE_NORMAL;
175                                    out.write(c);
176                                    break;
177                                case STATE_EXPRESSION:
178                                    state=STATE_QUOTE;
179                                    toBuffer(c);
180                                    break;
181                                case STATE_QUOTE:
182                                    if (lastChar!='\\') {
183                                        state=STATE_EXPRESSION;
184                                    }
185                                toBuffer(c);
186                                break;
187                                default:
188                                    throw new IOException("Invalid lexer state: " + state);
189                        }
190                        break;
191                    default:
192                        switch (state) {
193                                case STATE_NORMAL:
194                                    out.write(c);
195                                    break;
196                                case STATE_DOLLAR:
197                                    state=STATE_NORMAL;
198                                    out.write(c);
199                                    break;
200                                case STATE_EXPRESSION:
201                                case STATE_QUOTE:
202                                    toBuffer(c);
203                                    break;
204                                default:
205                                    throw new IOException("Invalid lexer state: " + state);
206                        }
207            }
208            lastChar = c;
209        }
210    
211        /**
212         * @param b
213         */
214        private void toBuffer(int b) {
215            if (expressionBuffer == null) {
216                expressionBuffer = new StringBuffer();
217            }
218            expressionBuffer.append((char) b);
219        }
220    
221        public void close() throws IOException {
222            if (state == STATE_DOLLAR) {
223                out.write('$');
224            } else if (state == STATE_EXPRESSION || state == STATE_QUOTE) {
225                out.write('$');
226                out.write('{');
227            }
228    
229            if (expressionBuffer != null) {
230                out.write(expressionBuffer.toString());
231                expressionBuffer = null;
232            }
233            out.close();
234            super.close();
235        }
236    
237        public void write(char[] cbuf, int off, int len) throws IOException {
238            for (int i=0; i<len; i++) {
239                write(cbuf[i+off]);
240            }
241        }
242        
243        public void write(String str, int off, int len) throws IOException {
244            for (int i=0; i<len; i++) {
245                write(str.charAt(i+off));
246            }
247        }
248    }