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