1 package net.sf.invicta.template; 2 3 import java.util.ArrayList ; 4 import java.util.HashMap ; 5 import java.util.Iterator ; 6 import java.util.List ; 7 import java.util.Map ; 8 import java.util.StringTokenizer ; 9 10 import net.sf.invicta.InvictaException; 11 import net.sf.invicta.handler.InvictaHandler; 12 13 import sun.misc.Service; 14 15 20 public class TemplateProcessor { 21 protected static final char HANDLER_SEPERATOR = ';'; 22 protected static final String EXTRA_SEPERATOR = ";"; 23 protected static final String EXTRA_MAP_SEPERATOR = "="; 24 protected static final char ESCAPE = '%'; 25 protected static final char PLACEHOLDER_START = '{'; 26 protected static final char PLACEHOLDER_END = '}'; 27 28 protected static Map handlers = new HashMap (); 29 30 static { 31 Iterator handlersIt = 32 Service.providers(InvictaHandler.class); 33 while (handlersIt.hasNext()) { 34 InvictaHandler handler = (InvictaHandler) handlersIt.next(); 35 handlers.put(handler.getName(), handler); 36 } 37 } 38 39 42 protected static InvictaHandler getHandler(String handler) { 43 return (InvictaHandler) handlers.get(handler); 44 } 45 46 53 protected static abstract class Instruction { 54 public abstract Object handle(Object [][] parameters, Object context) throws InvictaException, InvictaException ; 55 } 56 57 62 protected static class StaticInstruction extends Instruction { 63 private String text; 64 public StaticInstruction(String text) { 65 this.text = text; 66 } 67 public Object handle(Object [][] parameters, Object context) throws InvictaException { 68 return this.text; 69 } 70 } 71 72 82 protected static class DynamicInstruction extends Instruction { 83 protected String key = null; 84 protected int position = -1; 85 protected List extra = null; 86 87 88 public DynamicInstruction( 89 String key, 90 List extra) { 91 this.key = key; 92 try { 95 this.position = Integer.parseInt(key); 96 } catch (NumberFormatException e) { 97 } 99 this.extra = extra; 100 } 101 102 public Object handle(Object [][] parameters, Object context) throws InvictaException { 103 Object object = null; 104 105 boolean found = false; 106 if (!"".equals(key)) { 108 if (parameters == null) 109 throw new InvictaTemplateException( 110 "Parameter " 111 + key 112 + " is needed, but no parameters were given"); 113 if (position >= 0 && position < parameters.length) { 114 int index = position; 119 for (int i = 0; i < parameters.length; i++) { 120 Object [] pair = parameters[index]; 121 if (key.equals(pair[0])) { 122 object = pair[1]; 123 found = true; 124 break; 125 } 126 index = (index + 1) % parameters.length; 127 } 128 } else { 129 for (int i = 0; i < parameters.length; i++) { 132 Object [] pair = parameters[i]; 133 if (key.equals(pair[0])) { 134 object = pair[1]; 135 found = true; 136 break; 137 } 138 } 139 } 140 } 141 142 if (!found) { 143 144 InvictaHandler handler = (InvictaHandler)getHandler(key); 146 147 if (handler == null) 148 throw new InvictaTemplateException( 149 "Can't find parameter or handler named " + key); 150 151 Map extraMap = lookForExtraMap(extra); 152 153 if (extraMap == null) 154 object = handler.handle(context, extra); 155 else 156 object = handler.handle(context, extraMap); 157 158 } 159 160 if (object == null) 163 throw new InvictaTemplateException( 164 "Got null result for '" + key + "'"); 165 166 return object; 167 } 168 169 173 private Map lookForExtraMap(List extra) { 174 Map extraMap = new HashMap (); 175 for (Iterator iter = extra.iterator(); iter.hasNext();) { 176 String param = (String ) iter.next(); 177 int equal = param.indexOf(EXTRA_MAP_SEPERATOR); 178 if (equal == -1) 179 return null; 180 extraMap.put(param.substring(0, equal), param.substring(equal+1)); 181 } 182 183 return extraMap; 184 } 185 186 } 187 188 191 protected Instruction[] compiledFormat; 192 193 196 protected String template; 197 198 201 protected Object context; 202 203 209 public TemplateProcessor(String template) throws InvictaTemplateException { 210 this(template, null); 211 } 212 213 214 215 221 public TemplateProcessor(String template, Object context) throws InvictaTemplateException { 222 this.template = template; 223 this.context = context; 224 225 ArrayList compiledFormat = new ArrayList (); 226 227 int length = template.length(); 228 int position = 0; try { 230 while (position < length) { 231 int beginIndex = template.indexOf(ESCAPE, position); 233 if ((beginIndex == -1) || (beginIndex == length - 1)) { 236 compiledFormat.add( 237 new StaticInstruction(template.substring(position))); 238 break; 239 } 240 241 int nextIndex = beginIndex + 1; 245 char nextChar = template.charAt(nextIndex); 246 if (nextChar != PLACEHOLDER_START) { 247 if (nextChar == ESCAPE) { 248 251 } else { 253 nextIndex++; 255 } 256 257 compiledFormat.add( 258 new StaticInstruction( 259 template.substring(position, nextIndex))); 260 261 position = beginIndex + 2; 262 continue; 263 } 264 265 int endIndex = template.indexOf(PLACEHOLDER_END, beginIndex); 267 if (endIndex == -1) { 268 throw new InvictaTemplateException("Can't find end of placeholder"); 269 } 270 271 if (position != beginIndex) { 274 compiledFormat.add( 275 new StaticInstruction( 276 template.substring(position, beginIndex))); 277 } 278 279 String key = template.substring(beginIndex + 2, endIndex); 280 281 List extra = new ArrayList (); 282 283 int semicolon = key.indexOf(HANDLER_SEPERATOR); 285 if (semicolon != -1) { 286 String extraString = key.substring(semicolon + 1); 287 StringTokenizer st = new StringTokenizer (extraString, EXTRA_SEPERATOR); 288 while (st.hasMoreTokens()) { 289 String extraParam = st.nextToken().trim(); 290 extra.add(extraParam); 291 } 292 293 key = key.substring(0, semicolon); 294 } 295 296 297 DynamicInstruction instruction = 298 new DynamicInstruction(key, extra); 299 300 compiledFormat.add(instruction); 301 302 position = endIndex + 1; 304 } 305 306 this.compiledFormat = 308 (Instruction[]) compiledFormat.toArray( 309 new Instruction[compiledFormat.size()]); 310 } catch (Throwable problem) { 311 throw new InvictaTemplateException( 315 "Can't parse template: " + problem.getMessage(), problem, template); 316 317 } 318 } 319 320 329 public void format(Object [][] parameters, StringBuffer buffer) 330 throws InvictaTemplateException { 331 Throwable problem = null; 332 for (int i = 0; i < compiledFormat.length; i++) { 333 Instruction instruction = compiledFormat[i]; 334 try { 335 buffer.append(instruction.handle(parameters, context)); 336 } catch (Throwable t) { 337 problem = t; 338 } 339 } 340 if (problem != null) { 341 throw new InvictaTemplateException( 342 "Can't format template: " + problem.getMessage(), 343 problem, 344 buffer.toString()); 345 } 346 } 347 348 357 public String format(Object [][] parameters) throws InvictaTemplateException { 358 StringBuffer buffer = new StringBuffer (); 359 format(parameters, buffer); 360 return buffer.toString(); 361 } 362 363 static protected String [] conversion = 364 new String [] { 365 "0", 366 "1", 367 "2", 368 "3", 369 "4", 370 "5", 371 "6", 372 "7", 373 "8", 374 "9", 375 "10", 376 "11", 377 "12", 378 "13", 379 "14", 380 "15", 381 "16", 382 "17", 383 "18", 384 "19" }; 385 392 public static Object [][] positionToKey(Object [] array) { 393 if (array == null) 394 return null; 395 Object [][] parameters = new Object [array.length][2]; 396 for (int i = 0; i < array.length; i++) { 397 parameters[i][0] = conversion[i]; 398 parameters[i][1] = array[i]; 399 } 400 return parameters; 401 } 402 403 411 public static void format( 412 String template, 413 Object [][] parameters, 414 StringBuffer buffer) throws InvictaTemplateException { 415 new TemplateProcessor(template).format(parameters, buffer); 416 } 417 418 426 public static String format( 427 String template, 428 Object [][] parameters) throws InvictaTemplateException { 429 return new TemplateProcessor(template).format(parameters); 430 } 431 432 436 public Object getContext() { 437 return context; 438 } 439 440 444 public void setContext(Object context) { 445 this.context = context; 446 } 447 448 } 449 | Popular Tags |