001 package com.hammurapi.eventbus;
002
003 import java.io.File;
004 import java.io.FileOutputStream;
005 import java.io.FileWriter;
006 import java.io.IOException;
007 import java.io.ObjectOutputStream;
008 import java.io.StringWriter;
009 import java.io.Writer;
010 import java.lang.reflect.Method;
011 import java.lang.reflect.ParameterizedType;
012 import java.lang.reflect.Type;
013 import java.lang.reflect.TypeVariable;
014 import java.util.ArrayList;
015 import java.util.Arrays;
016 import java.util.Collection;
017 import java.util.Collections;
018 import java.util.Comparator;
019 import java.util.HashMap;
020 import java.util.HashSet;
021 import java.util.Iterator;
022 import java.util.List;
023 import java.util.Locale;
024 import java.util.Map;
025 import java.util.Set;
026
027 import org.apache.commons.lang.StringEscapeUtils;
028 import org.onemind.jxp.JxpContext;
029 import org.onemind.jxp.JxpPageSource;
030 import org.onemind.jxp.JxpProcessor;
031 import org.onemind.jxp.ResourceStreamPageSource;
032
033 import com.hammurapi.common.Context;
034 import com.hammurapi.common.TokenExpander;
035 import com.hammurapi.common.TokenExpander.TokenSource;
036 import com.hammurapi.convert.AbstractReflectiveAtomicConvertersBundle;
037 import com.hammurapi.convert.ConverterMethod;
038 import com.hammurapi.convert.ConvertingService;
039 import com.hammurapi.eventbus.IntrospectorBase.IntrospectionResult;
040 import com.hammurapi.extract.BinaryExtractor;
041 import com.hammurapi.extract.ComparisonResult;
042 import com.hammurapi.extract.CompositePredicate;
043 import com.hammurapi.extract.Constant;
044 import com.hammurapi.extract.Equal;
045 import com.hammurapi.extract.Extractor;
046 import com.hammurapi.extract.False;
047 import com.hammurapi.extract.IndexedExtractor;
048 import com.hammurapi.extract.InstanceOfPredicate;
049 import com.hammurapi.extract.MappedExtractor;
050 import com.hammurapi.extract.Not;
051 import com.hammurapi.extract.NotEqual;
052 import com.hammurapi.extract.Predicate;
053 import com.hammurapi.extract.True;
054 import com.hammurapi.extract.java.JavaExtractor;
055 import com.hammurapi.render.RenderingException;
056 import com.hammurapi.render.WriterRenderer;
057
058 /**
059 * This class generates source code for Java binding class.
060 * By default binder classes are put to the same package as handler classes and have postfix ''JavaBinder''.
061 * This behavior can be changed by subclassing the compiler. The class keeps track of generated predicate
062 * classes and attempts to reuse them.
063 *
064 * @author Pavel Vlasov
065 *
066 */
067 public class JavaBinderCompiler {
068
069 protected static final String BINDER_CLASS_PACKAGE = "binderClassPackage";
070 private static final String JAVA_INLINE = "java_inline";
071 private static final String JAVA = "java";
072 private static final String BIND_HELPER = "bindHelper";
073
074 private class EventDispatchContextDescriptor {
075
076 private Class<EventDispatchContext> contextClass;
077 private _Type[] contextTypeParameters;
078
079 public EventDispatchContextDescriptor(Class<EventDispatchContext> contextClass, _Type[] eventBusTypeParameters) {
080 this.contextClass = contextClass;
081
082 TypeVariable<Class<EventDispatchContext>>[] cctp = EventDispatchContext.class.getTypeParameters();
083 contextTypeParameters = new _Type[cctp.length];
084 for (int i=0; i< cctp.length; ++i) {
085 contextTypeParameters[i] = _Type.createType(cctp[i]);
086 }
087
088 List<List<PathEntry>> iPaths = inheritancePaths(contextClass, EventDispatchContext.class);
089 Collections.sort(iPaths, new Comparator<List<PathEntry>>() {
090
091 @Override
092 public int compare(List<PathEntry> o1, List<PathEntry> o2) {
093 int sizeDelta = o1.size() - o2.size();
094 if (sizeDelta!=0) {
095 return sizeDelta;
096 }
097 return o1.hashCode() - o2.hashCode();
098 }
099 });
100 for (List<PathEntry> path: iPaths) {
101 for (PathEntry pe: path) {
102 pe.bind(contextTypeParameters);
103 }
104 break;
105 }
106
107 for (int i=0; i<contextTypeParameters.length; ++i) {
108 bind(contextTypeParameters, i, new _TypeVariable("E"), eventBusTypeParameters[0]);
109 bind(contextTypeParameters, i, new _TypeVariable("P"), eventBusTypeParameters[1]);
110 bind(contextTypeParameters, i, new _TypeVariable("C"), eventBusTypeParameters[2]);
111 bind(contextTypeParameters, i, new _TypeVariable("K"), eventBusTypeParameters[3]);
112 bind(contextTypeParameters, i, new _TypeVariable("H"), eventBusTypeParameters[4]);
113 bind(contextTypeParameters, i, new _TypeVariable("S"), eventBusTypeParameters[5]);
114 }
115
116 }
117
118 private void bind(_Type[] contextTypeParameters, int i, _TypeVariable from, _Type to) {
119 if (from.equals(contextTypeParameters[i])) {
120 contextTypeParameters[i] = to;
121 } else {
122 contextTypeParameters[i].bind(from, to);
123 }
124 }
125
126 public String getType() {
127 _Class cls = new _Class(contextClass);
128 cls.bind(new _TypeVariable("E"), contextTypeParameters[0]);
129 cls.bind(new _TypeVariable("P"), contextTypeParameters[1]);
130 cls.bind(new _TypeVariable("C"), contextTypeParameters[2]);
131 cls.bind(new _TypeVariable("H"), contextTypeParameters[3]);
132 cls.bind(new _TypeVariable("S"), contextTypeParameters[4]);
133
134 return cls.toJavaDeclaration();
135 }
136
137 public String getEventType() {
138 return contextTypeParameters[0].toJavaDeclaration();
139 }
140
141 public String getStoreType() {
142 return contextTypeParameters[4].toJavaDeclaration();
143 }
144
145 public boolean isJoin() {
146 return EventDispatchJoinContext.class.isAssignableFrom(contextClass);
147 }
148 }
149
150 private class BindMethod<E, HC> {
151
152 private IntrospectionResult<E, HC> ir;
153 private String name;
154 private EventDispatchContextDescriptor eventDispatchContextDescriptor;
155 private Class<E> busEventType;
156 private Map<String, Object> renderingEnvironment;
157
158 @SuppressWarnings({ "unchecked", "rawtypes" })
159 BindMethod(String name, IntrospectionResult<E, HC> ir, Class<E> busEventType, _Type[] typeParameters, Map<String, Object> renderingEnvironment) {
160 this.ir = ir;
161 this.name = name;
162 Class<?> firstParameterType = ir.getMethod().getParameterTypes()[0];
163 if (ir.getOffset()==1
164 && EventDispatchContext.class.isAssignableFrom(firstParameterType)
165 && !(EventDispatchContext.class.equals(firstParameterType)) || EventDispatchJoinContext.class.equals(firstParameterType)) {
166
167 eventDispatchContextDescriptor = new EventDispatchContextDescriptor((Class<EventDispatchContext>) firstParameterType, typeParameters);
168 }
169 this.busEventType = busEventType;
170 this.renderingEnvironment = renderingEnvironment;
171 }
172
173 public String getName() {
174 return name;
175 }
176
177 public String getParameterTypeCast(int pIdx) {
178 Class<E> parameterType = ir.getParameterTypes()[pIdx];
179 if (parameterType.isAssignableFrom(busEventType)) {
180 return "";
181 }
182
183 if (parameterType.isPrimitive()) {
184 if (boolean.class.equals(parameterType)) {
185 return "("+Boolean.class.getName()+")";
186 } else if (char.class.equals(parameterType)) {
187 return "("+Character.class.getName()+")";
188 } else if (byte.class.equals(parameterType)) {
189 return "("+Byte.class.getName()+")";
190 } else if (short.class.equals(parameterType)) {
191 return "("+Short.class.getName()+")";
192 } else if (int.class.equals(parameterType)) {
193 return "("+Integer.class.getName()+")";
194 } else if (long.class.equals(parameterType)) {
195 return "("+Long.class.getName()+")";
196 } else if (float.class.equals(parameterType)) {
197 return "("+Float.class.getName()+")";
198 } else if (double.class.equals(parameterType)) {
199 return "("+Double.class.getName()+")";
200 } else if (void.class.equals(parameterType)) {
201 throw new IllegalArgumentException("Parameter type cannot be void");
202 }
203 }
204 return "("+parameterType.getName()+")";
205 }
206
207 public Method getMethod() {
208 return ir.getMethod();
209 }
210
211 public boolean isVoid() {
212 return void.class.equals(getMethod().getReturnType());
213 }
214
215 public Predicate<E, HC>[] getPredicates() {
216 return ir.getPredicates();
217 }
218
219 public String inlinePredicate(int pIdx) throws Exception {
220 WriterRenderer renderer = ConvertingService.convert(ir.getPredicates()[pIdx], WriterRenderer.class);
221 if (renderer==null) {
222 throw new EventBusException("Cannot compile predicate "+ir.getPredicates()[pIdx].getClass().getName());
223 }
224
225 StringWriter sw = new StringWriter();
226 if (renderer.render(sw, renderingEnvironment, Context.INSTANCE, JAVA_INLINE, null, outputDir)) {
227 sw.close();
228 return sw.toString();
229 }
230 throw new EventBusException("Cannot compile predicate "+ir.getPredicates()[pIdx].getClass().getName());
231 }
232
233 public int getOffset() {
234 return ir.getOffset();
235 }
236
237 public Class<E>[] getParameterTypes() {
238 return ir.getParameterTypes();
239 }
240
241 public Handler getHandlerAnnotation() {
242 return ir.getHandlerAnnotation();
243 }
244
245 public EventDispatchContextDescriptor getEventDispatchContext() {
246 return eventDispatchContextDescriptor;
247 }
248
249 }
250
251 public static class JavaExtractorEntry {
252
253 private JavaExtractor javaExtractor;
254 private String packageName;
255 private String className;
256
257 JavaExtractorEntry(JavaExtractor javaExtractor, String packageName, String className) {
258 super();
259 this.javaExtractor = javaExtractor;
260 this.packageName = packageName;
261 this.className = className;
262 }
263
264 JavaExtractor getJavaExtractor() {
265 return javaExtractor;
266 }
267
268 String getPackageName() {
269 return packageName;
270 }
271
272 String getClassName() {
273 return className;
274 }
275
276 }
277
278 private class BindHelper<E, HC> {
279
280 private Collection<BindMethod<E,HC>> bindMethods = new ArrayList<JavaBinderCompiler.BindMethod<E,HC>>();
281 private Collection<JavaExtractorEntry> javaExtractorEntries;
282 private Class<?> contextType;
283
284 BindHelper(
285 Collection<IntrospectionResult<E, HC>> irc,
286 Class<E> busEventType,
287 _Type[] typeParameters,
288 Collection<JavaExtractorEntry> javaExtractorEntries,
289 String binderClassPackage) {
290
291 Set<String> usedNames = new HashSet<String>();
292 for (IntrospectionResult<E, HC> ir: irc) {
293 String name = ir.getMethod().getName();
294 for (int i=0; usedNames.contains(name); ++i) {
295 name = ir.getMethod().getName()+i;
296 }
297 usedNames.add(name);
298 Map<String, Object> renderingEnvironment = new HashMap<String, Object>();
299 renderingEnvironment.put(BIND_HELPER, this);
300 renderingEnvironment.put(BINDER_CLASS_PACKAGE, binderClassPackage);
301 bindMethods.add(new BindMethod<E, HC>(name, ir, busEventType, typeParameters, renderingEnvironment));
302 }
303 this.javaExtractorEntries = javaExtractorEntries;
304 this.contextType = ((_Class) typeParameters[2]).clazz;
305 }
306
307 public Collection<BindMethod<E,HC>> getBindMethods() {
308 return bindMethods;
309 }
310
311 public Collection<JavaExtractorEntry> getJavaExtractorEntries() {
312 return javaExtractorEntries;
313 }
314
315 public Class<?> getContextType() {
316 return contextType;
317 }
318
319 }
320
321 private File outputDir;
322 private ArrayList<JavaExtractorEntry> javaExtractorEntries = new ArrayList<JavaExtractorEntry>();
323
324 public JavaBinderCompiler(File outputDir) {
325 this.outputDir = outputDir;
326 }
327
328 public <E, C, HC extends C, BC extends EventBus<E, ?, C, ?, ?, ?>> void compileJavaBinder(Class<HC> handlerClass, Class<BC> busClass, ClassLoader classLoader, TokenExpander tokenExpander) {
329
330 try {
331 Map<String, Object> environment = new HashMap<String, Object>();
332 environment.put(BINDER_CLASS_PACKAGE, getBinderClassPackage(handlerClass));
333 environment.put("binderClassName", getBinderClassName(handlerClass));
334 environment.put("binderClassComment", "Binds handler class "+handlerClass.getName()+" to event bus "+busClass.getName());
335
336 TypeVariable<Class<EventBus>>[] ebtp = EventBus.class.getTypeParameters();
337 _Type[] eventBusTypeParameters = new _Type[ebtp.length];
338 for (int i=0; i< ebtp.length; ++i) {
339 eventBusTypeParameters[i] = _Type.createType(ebtp[i]);
340 }
341
342 List<List<PathEntry>> iPaths = inheritancePaths(busClass, EventBus.class);
343 Collections.sort(iPaths, new Comparator<List<PathEntry>>() {
344
345 @Override
346 public int compare(List<PathEntry> o1, List<PathEntry> o2) {
347 int sizeDelta = o1.size() - o2.size();
348 if (sizeDelta!=0) {
349 return sizeDelta;
350 }
351 return o1.hashCode() - o2.hashCode();
352 }
353 });
354 for (List<PathEntry> path: iPaths) {
355 for (PathEntry pe: path) {
356 pe.bind(eventBusTypeParameters);
357 }
358 break;
359 }
360
361 _Type pType = eventBusTypeParameters[1];
362 if (pType instanceof _TypeVariable) {
363 _Class to = new _Class(Integer.class);
364 for (int i=0; i<eventBusTypeParameters.length; ++i) {
365 if (pType.equals(eventBusTypeParameters[i])) {
366 eventBusTypeParameters[i] = to;
367 } else {
368 eventBusTypeParameters[i].bind((_TypeVariable) pType, to);
369 }
370 }
371 }
372
373 Class<E> busEventType;
374 if (eventBusTypeParameters[0] instanceof _TypeVariable) {
375 busEventType = (Class<E>) Object.class;
376 _Type eType = eventBusTypeParameters[0];
377 _Class to = new _Class(busEventType);
378 for (int i=0; i<eventBusTypeParameters.length; ++i) {
379 if (eType.equals(eventBusTypeParameters[i])) {
380 eventBusTypeParameters[i] = to;
381 } else {
382 eventBusTypeParameters[i].bind((_TypeVariable) eType, to);
383 }
384 }
385 } else if (eventBusTypeParameters[0] instanceof _Class) {
386 busEventType = (Class<E>) ((_Class) eventBusTypeParameters[0]).clazz;
387 } else if (eventBusTypeParameters[0] instanceof _ParameterizedType) {
388 busEventType = (Class<E>) ((_ParameterizedType) eventBusTypeParameters[0]).rawType;
389 } else {
390 throw new EventBusException("Unexpected type: "+eventBusTypeParameters[0]);
391 }
392
393 if (eventBusTypeParameters[2] instanceof _TypeVariable) {
394 _Type eType = eventBusTypeParameters[2];
395 _Class to = new _Class(Object.class);
396 for (int i=0; i<eventBusTypeParameters.length; ++i) {
397 if (eType.equals(eventBusTypeParameters[i])) {
398 eventBusTypeParameters[i] = to;
399 } else {
400 eventBusTypeParameters[i].bind((_TypeVariable) eType, to);
401 }
402 }
403 }
404
405 environment.put("E", eventBusTypeParameters[0].toJavaDeclaration());
406 environment.put("P", eventBusTypeParameters[1].toJavaDeclaration());
407 environment.put("C", eventBusTypeParameters[2].toJavaDeclaration());
408 environment.put("K", eventBusTypeParameters[3].toJavaDeclaration());
409 environment.put("H", eventBusTypeParameters[4].toJavaDeclaration());
410 environment.put("S", eventBusTypeParameters[5].toJavaDeclaration());
411
412 List<String> genericParameters = new ArrayList<String>();
413 for (int i=0; i<eventBusTypeParameters.length; ++i) {
414 if (eventBusTypeParameters[i] instanceof _TypeVariable) {
415 genericParameters.add(eventBusTypeParameters[i].toJavaDeclaration());
416 }
417 }
418
419 if (genericParameters.isEmpty()) {
420 environment.put("genericParameters", "");
421 } else {
422 StringBuilder sb = new StringBuilder("<");
423 Iterator<String> gpit = genericParameters.iterator();
424 while (gpit.hasNext()) {
425 sb.append(gpit.next());
426 if (gpit.hasNext()) {
427 sb.append(", ");
428 }
429 }
430 sb.append(">");
431 environment.put("genericParameters", sb.toString());
432 }
433
434 environment.put("B", toJavaDeclaration(busClass, eventBusTypeParameters));
435 environment.put("I", toJavaDeclaration(handlerClass, eventBusTypeParameters));
436
437 IntrospectorBase<E,HC> introspector = new IntrospectorBase<E, HC>(classLoader, tokenExpander);
438
439 environment.put("bindHelper", new BindHelper<E, HC>(introspector.introspect(handlerClass, busEventType), busEventType, eventBusTypeParameters, javaExtractorEntries, getBinderClassPackage(handlerClass)));
440
441 String prefix = getClass().getPackage().getName().replace('.', '/');
442 JxpPageSource pageSource = new ResourceStreamPageSource("/"+prefix);
443 JxpContext context = new JxpContext(pageSource);
444 JxpProcessor processor = new JxpProcessor(context);
445
446 File packageDir = new File(outputDir, getBinderClassPackage(handlerClass).replace('.', File.separatorChar));
447 packageDir.mkdirs();
448 File outputFile = new File(packageDir, getBinderClassName(handlerClass)+".java");
449 Writer writer = new FileWriter(outputFile);
450 try {
451 processor.process("JavaBinder.jxp", writer, environment);
452 } finally {
453 writer.close();
454 }
455 } catch (Exception e) {
456 throw new EventBusException(e);
457 }
458 }
459
460 private String toJavaDeclaration(Class<?> clazz, _Type[] typeParameters) {
461 _Class cls = new _Class(clazz);
462 cls.bind(new _TypeVariable("E"), typeParameters[0]);
463 cls.bind(new _TypeVariable("P"), typeParameters[1]);
464 cls.bind(new _TypeVariable("C"), typeParameters[2]);
465 cls.bind(new _TypeVariable("K"), typeParameters[3]);
466 cls.bind(new _TypeVariable("H"), typeParameters[4]);
467 cls.bind(new _TypeVariable("S"), typeParameters[5]);
468
469 return cls.toJavaDeclaration();
470 }
471
472 protected String getBinderClassPackage(Class<?> handlerClass) {
473 return handlerClass.getPackage().getName();
474 }
475
476 protected String getBinderClassName(Class<?> handlerClass) {
477 int idx = handlerClass.getName().lastIndexOf('.');
478 return (idx==-1 ? handlerClass.getName() : handlerClass.getName().substring(idx+1))+"JavaBinder";
479 }
480
481 private static abstract class _Type {
482
483 abstract void bind(_TypeVariable from, _Type to);
484
485 abstract String toJavaDeclaration();
486
487 static _Type createType(Type rType) {
488 if (rType instanceof TypeVariable<?>) {
489 return new _TypeVariable((TypeVariable<?>) rType);
490 }
491
492 if (rType instanceof ParameterizedType) {
493 return new _ParameterizedType((ParameterizedType) rType);
494 }
495
496 if (rType instanceof Class) {
497 return new _Class((Class) rType);
498 }
499 throw new UnsupportedOperationException();
500 }
501 }
502
503 private static class _Class extends _Type {
504
505 private Class<?> clazz;
506
507 public _Class(Class<?> clazz) {
508 this.clazz = clazz;
509 TypeVariable<?>[] ctp = clazz.getTypeParameters();
510 this.typeParameters = new _Type[ctp.length];
511 for (int i=0; i<ctp.length; ++i) {
512 typeParameters[i] = _Type.createType(ctp[i]);
513 }
514 }
515
516 @Override
517 public String toString() {
518 return "_Class [clazz=" + clazz + "]";
519 }
520
521 _Type[] typeParameters;
522
523 @Override
524 void bind(_TypeVariable from, _Type to) {
525 for (int i=0; i<typeParameters.length; ++i) {
526 if (from.equals(typeParameters[i])) {
527 typeParameters[i] = to;
528 } else {
529 typeParameters[i].bind(from, to);
530 }
531 }
532 }
533
534 @Override
535 String toJavaDeclaration() {
536 StringBuilder sb = new StringBuilder(((Class) clazz).getCanonicalName());
537 if (typeParameters.length>0) {
538 sb.append("<");
539 for (int i=0; i<typeParameters.length; ++i) {
540 if (i>0) {
541 sb.append(", ");
542 }
543 sb.append(typeParameters[i].toJavaDeclaration());
544 }
545 sb.append(">");
546 }
547 return sb.toString();
548 }
549 }
550
551 private static class _TypeVariable extends _Type {
552 private String name;
553
554 public _TypeVariable(TypeVariable<?> rTypeVariable) {
555 super();
556 this.name = rTypeVariable.getName();
557 }
558
559 public _TypeVariable(String name) {
560 super();
561 this.name = name;
562 }
563
564 @Override
565 public int hashCode() {
566 final int prime = 31;
567 int result = 1;
568 result = prime * result + ((name == null) ? 0 : name.hashCode());
569 return result;
570 }
571
572 @Override
573 public String toString() {
574 return "_TypeVariable [name=" + name + "]";
575 }
576
577 @Override
578 public boolean equals(Object obj) {
579 if (this == obj)
580 return true;
581 if (obj == null)
582 return false;
583 if (getClass() != obj.getClass())
584 return false;
585 _TypeVariable other = (_TypeVariable) obj;
586 if (name == null) {
587 if (other.name != null)
588 return false;
589 } else if (!name.equals(other.name))
590 return false;
591 return true;
592 }
593
594 public String getName() {
595 return name;
596 }
597
598 public void setName(String name) {
599 this.name = name;
600 }
601
602 @Override
603 void bind(_TypeVariable from, _Type to) {
604 if (from.getName().equals(name)) {
605 if (to instanceof _TypeVariable) {
606 name = ((_TypeVariable) to).name;
607 } else {
608 throw new UnsupportedOperationException();
609 }
610 }
611 }
612
613 @Override
614 String toJavaDeclaration() {
615 return name;
616 }
617 }
618
619 private static class _ParameterizedType extends _Type {
620 Type rawType;
621 _Type[] actualTypeArguments;
622
623 public _ParameterizedType(ParameterizedType pt) {
624 rawType = pt.getRawType();
625 Type[] atp = pt.getActualTypeArguments();
626 actualTypeArguments = new _Type[atp.length];
627 for (int i=0; i<atp.length; ++i) {
628 actualTypeArguments[i]=_Type.createType(atp[i]);
629 }
630 }
631
632 @Override
633 void bind(_TypeVariable from, _Type to) {
634 for (int i=0; i<actualTypeArguments.length; ++i) {
635 if (from.equals(actualTypeArguments[i])) {
636 actualTypeArguments[i] = to;
637 } else {
638 actualTypeArguments[i].bind(from, to);
639 }
640 }
641 }
642
643 @Override
644 public String toString() {
645 return "_ParameterizedType [rawType=" + rawType
646 + ", actualTypeArguments="
647 + Arrays.toString(actualTypeArguments) + "]";
648 }
649
650 @Override
651 String toJavaDeclaration() {
652 StringBuilder sb = new StringBuilder(((Class) rawType).getCanonicalName());
653 sb.append("<");
654 for (int i=0; i<actualTypeArguments.length; ++i) {
655 if (i>0) {
656 sb.append(", ");
657 }
658 sb.append(actualTypeArguments[i].toJavaDeclaration());
659 }
660 sb.append(">");
661 return sb.toString();
662 }
663
664 }
665
666 private static class PathEntry {
667 Type sType;
668 Class<?> clazz;
669 public PathEntry(Type type, Class<?> clazz) {
670 super();
671 if (clazz==null) {
672 throw new IllegalArgumentException();
673 }
674 sType = type;
675 this.clazz = clazz;
676 }
677
678 void bind(_Type[] typeParameters) {
679 TypeVariable<?>[] ctp = clazz.getTypeParameters();
680 Type[] atp = ((ParameterizedType) sType).getActualTypeArguments();
681 for (int i=0; i<ctp.length; ++i) {
682 _TypeVariable from = (_TypeVariable) _Type.createType(ctp[i]);
683 _Type to = _Type.createType(atp[i]);
684 for (int j=0; j<typeParameters.length; ++j) {
685 if (from.equals(typeParameters[j])) {
686 typeParameters[j] = to;
687 } else {
688 typeParameters[j].bind(from, to);
689 }
690 }
691 }
692 }
693
694 @Override
695 public String toString() {
696 TypeVariable<?>[] typeParameters = clazz.getTypeParameters();
697 return "PathEntry[type = "+sType+", class = "+clazz+", type parameters = "+(typeParameters==null ? "(no type parameters)" : Arrays.toString(typeParameters))+"]";
698 }
699 }
700
701 private static <S> List<List<PathEntry>> inheritancePaths(Class<? extends S> from, Class<S> to) {
702 List<List<PathEntry>> ret = new ArrayList<List<PathEntry>>();
703 if (from.equals(to)) {
704 ret.add(new ArrayList<PathEntry>());
705 } else if (to.isAssignableFrom(from)) {
706 Class<?> fromSuperClass = from.getSuperclass();
707 if (fromSuperClass!=null) {
708 for (List<PathEntry> path: inheritancePaths((Class<? extends S>) fromSuperClass, to)) {
709 Type gsc = from.getGenericSuperclass();
710 Class<? extends S> sc = (Class<? extends S>) from.getSuperclass();
711 if (sc!=null) {
712 path.add(new PathEntry(gsc, sc));
713 ret.add(path);
714 }
715 }
716 }
717
718 Type[] gi = from.getGenericInterfaces();
719 Class[] si = from.getInterfaces();
720 for (int i=0; i<gi.length; ++i) {
721 for (List<PathEntry> path: inheritancePaths((Class<? extends S>) si[i], to)) {
722 path.add(new PathEntry(gi[i], si[i]));
723 ret.add(path);
724 }
725 }
726 }
727
728 return ret;
729 }
730
731 public static class ConvertersBundle extends AbstractReflectiveAtomicConvertersBundle {
732
733 @ConverterMethod
734 public WriterRenderer toWriterRenderer(final CompositePredicate predicate) {
735 return new WriterRenderer() {
736
737 @Override
738 public boolean render(
739 Writer out,
740 Map<String, Object> environment,
741 Context context,
742 String profile,
743 Locale locale,
744 File outputDir) throws RenderingException {
745
746 if (!JAVA_INLINE.equals(profile)) {
747 return false;
748 }
749
750 try {
751 out.write("new "+predicate.getClass().getCanonicalName()+"(0, null, ");
752 Iterator<Predicate> pit = predicate.getParts().iterator();
753 while (pit.hasNext()) {
754 Predicate part = pit.next();
755 WriterRenderer pwr = ConvertingService.convert(part, WriterRenderer.class);
756 if (pwr==null) {
757 throw new RenderingException("Cannot render "+part.getClass().getName());
758 }
759 if (!pwr.render(out, environment, context, profile, locale, outputDir)) {
760 throw new RenderingException("Cannot render "+part.getClass().getName());
761 }
762 if (pit.hasNext()) {
763 out.write(", ");
764 }
765 }
766 out.write(")");
767 } catch (IOException e) {
768 throw new RenderingException(e);
769 }
770
771 return true;
772 }
773 };
774 }
775
776 @ConverterMethod
777 public WriterRenderer toWriterRenderer(final BinaryExtractor extractor) {
778 return new WriterRenderer() {
779
780 @Override
781 public boolean render(
782 Writer out,
783 Map<String, Object> environment,
784 Context context,
785 String profile,
786 Locale locale,
787 File outputDir) throws RenderingException {
788
789 if (!JAVA_INLINE.equals(profile)) {
790 return false;
791 }
792
793 try {
794 out.write("new "+extractor.getClass().getCanonicalName()+"(0, null, ");
795 Extractor leftExtractor = extractor.getLeftExtractor();
796 WriterRenderer lwr = ConvertingService.convert(leftExtractor, WriterRenderer.class);
797 if (lwr==null) {
798 throw new RenderingException("Cannot render "+leftExtractor.getClass().getName());
799 }
800 if (!lwr.render(out, environment, context, profile, locale, outputDir)) {
801 throw new RenderingException("Cannot render "+leftExtractor.getClass().getName());
802 }
803 out.write(", ");
804 Extractor rightExtractor = extractor.getRightExtractor();
805 WriterRenderer rwr = ConvertingService.convert(rightExtractor, WriterRenderer.class);
806 if (rwr==null) {
807 throw new RenderingException("Cannot render "+rightExtractor.getClass().getName());
808 }
809 if (!rwr.render(out, environment, context, profile, locale, outputDir)) {
810 throw new RenderingException("Cannot render "+rightExtractor.getClass().getName());
811 }
812
813 if (extractor instanceof Equal) {
814 out.write(", " + ((Equal) extractor).isIdentity());
815 } else if (extractor instanceof NotEqual) {
816 out.write(", " + ((NotEqual) extractor).isIdentity());
817 }
818
819 out.write(")");
820 } catch (IOException e) {
821 throw new RenderingException(e);
822 }
823
824 return true;
825 }
826 };
827 }
828
829 @ConverterMethod
830 public WriterRenderer toWriterRenderer(final Constant extractor) {
831 return new WriterRenderer() {
832
833 @Override
834 public boolean render(
835 Writer out,
836 Map<String, Object> environment,
837 Context context,
838 String profile,
839 Locale locale,
840 File outputDir) throws RenderingException {
841
842 if (!JAVA_INLINE.equals(profile)) {
843 return false;
844 }
845
846 try {
847 out.write("new "+extractor.getClass().getCanonicalName()+"(");
848 if (extractor.getValue() == null) {
849 out.write("null");
850 } else if (extractor.getValue() instanceof String) {
851 out.write("\"");
852 out.write(StringEscapeUtils.escapeJava(extractor.getValue().toString()));
853 out.write("\"");
854 } else if (extractor.getValue() instanceof Character) {
855 out.write("\'");
856 out.write(StringEscapeUtils.escapeJava(extractor.getValue().toString()));
857 out.write("\'");
858 } else {
859 out.write("("+extractor.getValue().getClass().getCanonicalName()+") ");
860 out.write(String.valueOf(extractor.getValue()));
861 }
862 out.write(")");
863 } catch (IOException e) {
864 throw new RenderingException(e);
865 }
866
867 return true;
868 }
869 };
870 }
871
872 @ConverterMethod
873 public WriterRenderer toWriterRenderer(final False extractor) {
874 return new WriterRenderer() {
875
876 @Override
877 public boolean render(
878 Writer out,
879 Map<String, Object> environment,
880 Context context,
881 String profile,
882 Locale locale,
883 File outputDir) throws RenderingException {
884
885 if (!JAVA_INLINE.equals(profile)) {
886 return false;
887 }
888
889 try {
890 out.write(False.class.getCanonicalName()+".getInstance()");
891 } catch (IOException e) {
892 throw new RenderingException(e);
893 }
894
895 return true;
896 }
897 };
898 }
899
900 @ConverterMethod
901 public WriterRenderer toWriterRenderer(final IndexedExtractor extractor) {
902 return new WriterRenderer() {
903
904 @Override
905 public boolean render(
906 Writer out,
907 Map<String, Object> environment,
908 Context context,
909 String profile,
910 Locale locale,
911 File outputDir) throws RenderingException {
912
913 if (!JAVA_INLINE.equals(profile)) {
914 return false;
915 }
916
917 try {
918 out.write("new "+extractor.getClass().getCanonicalName()+"(");
919 out.write(String.valueOf(extractor.getIndex()));
920 out.write(")");
921 } catch (IOException e) {
922 throw new RenderingException(e);
923 }
924
925 return true;
926 }
927 };
928 }
929
930 @ConverterMethod
931 public WriterRenderer toWriterRenderer(final InstanceOfPredicate extractor) {
932 return new WriterRenderer() {
933
934 @Override
935 public boolean render(
936 Writer out,
937 Map<String, Object> environment,
938 Context context,
939 String profile,
940 Locale locale,
941 File outputDir) throws RenderingException {
942
943 if (!JAVA_INLINE.equals(profile)) {
944 return false;
945 }
946
947 try {
948 out.write("new "+extractor.getClass().getCanonicalName()+"(");
949 WriterRenderer er = ConvertingService.convert(extractor.getExtractor(), WriterRenderer.class);
950 if (er==null) {
951 throw new RenderingException("Cannot render "+extractor.getExtractor().getClass().getName());
952 }
953 if (!er.render(out, environment, context, profile, locale, outputDir)) {
954 throw new RenderingException("Cannot render "+extractor.getExtractor().getClass().getName());
955 }
956 out.write(", ");
957 out.write(extractor.getInstanceType().getName()+".class");
958 out.write(")");
959 } catch (IOException e) {
960 throw new RenderingException(e);
961 }
962
963 return true;
964 }
965 };
966 }
967
968 @ConverterMethod
969 public WriterRenderer toWriterRenderer(final MappedExtractor extractor) {
970 return new WriterRenderer() {
971
972 @Override
973 public boolean render(
974 Writer out,
975 Map<String, Object> environment,
976 Context context,
977 String profile,
978 Locale locale,
979 File outputDir) throws RenderingException {
980
981 if (!JAVA_INLINE.equals(profile)) {
982 return false;
983 }
984
985 try {
986 out.write("new "+extractor.getClass().getCanonicalName()+"(");
987 WriterRenderer ewr = ConvertingService.convert(extractor.getTarget(), WriterRenderer.class);
988 if (ewr==null) {
989 throw new RenderingException("Cannot render "+extractor.getTarget().getClass().getName());
990 }
991 if (!ewr.render(out, environment, context, profile, locale, outputDir)) {
992 throw new RenderingException("Cannot render "+extractor.getTarget().getClass().getName());
993 }
994
995 out.write(", new int[] {");
996 int[] map = extractor.getMap();
997 for (int i=0; i<map.length; ++i) {
998 if (i>0) {
999 out.write(", ");
1000 }
1001 out.write(String.valueOf(map[i]));
1002 }
1003
1004 out.write("})");
1005 } catch (IOException e) {
1006 throw new RenderingException(e);
1007 }
1008
1009 return true;
1010 }
1011 };
1012 }
1013
1014 // @ConverterMethod
1015 // public WriterRenderer toWriterRenderer(final MethodExtractor extractor) {
1016 // return new WriterRenderer() {
1017 //
1018 // @Override
1019 // public boolean render(
1020 // Writer out,
1021 // Map<String, Object> environment,
1022 // Context context,
1023 // String profile,
1024 // Locale locale,
1025 // File outputDir) throws RenderingException {
1026 //
1027 // if (!JAVA_INLINE.equals(profile)) {
1028 // return false;
1029 // }
1030 //
1031 // try {
1032 // out.write("new "+extractor.getClass().getCanonicalName()+"(");
1033 //
1034 // out.write("777~~~Not implemented~~~777");
1035 //
1036 // out.write(")");
1037 // } catch (IOException e) {
1038 // throw new RenderingException(e);
1039 // }
1040 //
1041 // return true;
1042 // }
1043 // };
1044 // }
1045
1046 @ConverterMethod
1047 public WriterRenderer toWriterRenderer(final Not extractor) {
1048 return new WriterRenderer() {
1049
1050 @Override
1051 public boolean render(
1052 Writer out,
1053 Map<String, Object> environment,
1054 Context context,
1055 String profile,
1056 Locale locale,
1057 File outputDir) throws RenderingException {
1058
1059 if (!JAVA_INLINE.equals(profile)) {
1060 return false;
1061 }
1062
1063 try {
1064 out.write("new "+extractor.getClass().getCanonicalName()+"(");
1065
1066 WriterRenderer ewr = ConvertingService.convert(extractor.getPredicate(), WriterRenderer.class);
1067 if (ewr==null) {
1068 throw new RenderingException("Cannot render "+extractor.getPredicate().getClass().getName());
1069 }
1070 if (!ewr.render(out, environment, context, profile, locale, outputDir)) {
1071 throw new RenderingException("Cannot render "+extractor.getPredicate().getClass().getName());
1072 }
1073
1074 out.write(")");
1075 } catch (IOException e) {
1076 throw new RenderingException(e);
1077 }
1078
1079 return true;
1080 }
1081 };
1082 }
1083
1084 // @ConverterMethod
1085 // public WriterRenderer toWriterRenderer(final TimeIntervalPredicate extractor) {
1086 // return new WriterRenderer() {
1087 //
1088 // @Override
1089 // public boolean render(
1090 // Writer out,
1091 // Map<String, Object> environment,
1092 // Context context,
1093 // String profile,
1094 // Locale locale,
1095 // File outputDir) throws RenderingException {
1096 //
1097 // if (!JAVA_INLINE.equals(profile)) {
1098 // return false;
1099 // }
1100 //
1101 // try {
1102 // out.write("new "+extractor.getClass().getCanonicalName()+"(");
1103 //
1104 // out.write("777~~~Not implemented~~~777");
1105 //
1106 // out.write(")");
1107 // } catch (IOException e) {
1108 // throw new RenderingException(e);
1109 // }
1110 //
1111 // return true;
1112 // }
1113 // };
1114 // }
1115
1116 @ConverterMethod
1117 public WriterRenderer toWriterRenderer(final True extractor) {
1118 return new WriterRenderer() {
1119
1120 @Override
1121 public boolean render(
1122 Writer out,
1123 Map<String, Object> environment,
1124 Context context,
1125 String profile,
1126 Locale locale,
1127 File outputDir) throws RenderingException {
1128
1129 if (!JAVA_INLINE.equals(profile)) {
1130 return false;
1131 }
1132
1133 try {
1134 out.write(True.class.getCanonicalName()+".getInstance()");
1135 } catch (IOException e) {
1136 throw new RenderingException(e);
1137 }
1138
1139 return true;
1140 }
1141 };
1142 }
1143
1144 @ConverterMethod
1145 public WriterRenderer toWriterRenderer(final JavaExtractor extractor) {
1146 return new WriterRenderer() {
1147
1148 @Override
1149 public boolean render(
1150 Writer out,
1151 Map<String, Object> environment,
1152 Context context,
1153 String profile,
1154 Locale locale,
1155 File outputDir) throws RenderingException {
1156
1157 if (!JAVA_INLINE.equals(profile)) {
1158 return false;
1159 }
1160
1161 try {
1162 // Try to find existing compiled predicate/extractor
1163 BindHelper bindHelper = (BindHelper) environment.get(BIND_HELPER);
1164 String packageName = (String) environment.get(BINDER_CLASS_PACKAGE);
1165 for (JavaExtractorEntry jee: (Collection<JavaExtractorEntry>) bindHelper.getJavaExtractorEntries()) {
1166 if (packageName.equals(jee.getPackageName())) {
1167 ComparisonResult cr = jee.getJavaExtractor().compareTo(extractor); // TODO - verify right order.
1168 if (cr!=null) {
1169 switch (cr.getType()) {
1170 case OPPOSITE:
1171 out.write("new "+Not.class.getCanonicalName()+"(");
1172 case EQUAL:
1173 out.write("new "+jee.getClassName()+"(");
1174 if (cr.getIndexMap()==null) {
1175 out.write("null");
1176 } else {
1177 out.write("new int[] {");
1178 for (int i=0; i<cr.getIndexMap().length; ++i) {
1179 if (i>0) {
1180 out.write(", ");
1181 }
1182 out.write(String.valueOf(i));
1183 }
1184 out.write("}");
1185 }
1186 out.write(")");
1187
1188 if (ComparisonResult.Type.OPPOSITE.equals(cr.getType())) {
1189 out.write(")");
1190 }
1191
1192 return true;
1193 }
1194 }
1195 }
1196 }
1197
1198 File outputFile;
1199 int i = 0;
1200 do {
1201 outputFile = new File(outputDir, packageName.replace('.', File.separatorChar)+File.separator+prefix(extractor)+(++i)+".java");
1202 } while (outputFile.exists());
1203
1204 outputFile.getParentFile().mkdirs();
1205
1206 JavaExtractorEntry newJee = new JavaExtractorEntry(extractor, packageName, prefix(extractor)+i);
1207 bindHelper.getJavaExtractorEntries().add(newJee);
1208
1209 File identityFile = new File(outputFile.getParentFile(), prefix(extractor)+i+".identity");
1210 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(identityFile));
1211 try {
1212 oos.writeObject(extractor.getIdentity());
1213 } finally {
1214 oos.close();
1215 }
1216
1217 String prefix = getClass().getPackage().getName().replace('.', '/');
1218 JxpPageSource pageSource = new ResourceStreamPageSource("/"+prefix);
1219 JxpContext jxpContext = new JxpContext(pageSource);
1220 JxpProcessor processor = new JxpProcessor(jxpContext);
1221 Writer writer = new FileWriter(outputFile);
1222 CompileHelper compileHelper = new CompileHelper(packageName, prefix(extractor)+i, bindHelper.getContextType(), extractor);
1223 environment.put("compileHelper", compileHelper);
1224 processor.process("JavaExtractor.jxp", writer, environment);
1225 writer.close();
1226
1227 out.write("new "+prefix(extractor)+i+"(null)");
1228 } catch (Exception e) {
1229 throw new RenderingException(e);
1230 }
1231
1232 return true;
1233 }
1234 };
1235 }
1236
1237 private static String prefix(Extractor extractor) {
1238 return extractor instanceof Predicate ? "Predicate" : "Extractor";
1239 }
1240
1241 // /**
1242 // * For testing.
1243 // * @param extractor
1244 // * @return
1245 // */
1246 // @ConverterMethod
1247 // public WriterRenderer toWriterRenderer(final Extractor extractor) {
1248 // return new WriterRenderer() {
1249 //
1250 // @Override
1251 // public boolean render(
1252 // Writer out,
1253 // Map<String, Object> environment,
1254 // Context context,
1255 // String profile,
1256 // Locale locale,
1257 // File outputDir) throws RenderingException {
1258 //
1259 // if (!JAVA_INLINE.equals(profile)) {
1260 // return false;
1261 // }
1262 //
1263 // try {
1264 // out.write(extractor.toString());
1265 // } catch (IOException e) {
1266 // throw new RenderingException(e);
1267 // }
1268 //
1269 // return true;
1270 // }
1271 // };
1272 // }
1273
1274 }
1275
1276 private static class CompileHelper {
1277
1278 private String packageName;
1279 private String className;
1280 private _Type[] extractorTypeParameters;
1281 private JavaExtractor javaExtractor;
1282
1283 public CompileHelper(String packageName, String className, Class<?> contextType, JavaExtractor javaExtractor) {
1284 this.packageName = packageName;
1285 this.className = className;
1286 this.javaExtractor = javaExtractor;
1287
1288 TypeVariable<Class<Extractor>>[] etp = Extractor.class.getTypeParameters();
1289 extractorTypeParameters = new _Type[etp.length];
1290 for (int i=0; i< etp.length; ++i) {
1291 extractorTypeParameters[i] = _Type.createType(etp[i]);
1292 }
1293
1294 List<List<PathEntry>> iPaths = inheritancePaths(javaExtractor.getClass(), Extractor.class);
1295 Collections.sort(iPaths, new Comparator<List<PathEntry>>() {
1296
1297 @Override
1298 public int compare(List<PathEntry> o1, List<PathEntry> o2) {
1299 int sizeDelta = o1.size() - o2.size();
1300 if (sizeDelta!=0) {
1301 return sizeDelta;
1302 }
1303 return o1.hashCode() - o2.hashCode();
1304 }
1305 });
1306
1307 for (List<PathEntry> path: iPaths) {
1308 for (PathEntry pe: path) {
1309 pe.bind(extractorTypeParameters);
1310 }
1311 break;
1312 }
1313
1314 _Type tType = extractorTypeParameters[0]; // T
1315 if (tType instanceof _TypeVariable) {
1316 _Class to = new _Class(Object.class);
1317 for (int i=0; i<extractorTypeParameters.length; ++i) {
1318 if (tType.equals(extractorTypeParameters[i])) {
1319 extractorTypeParameters[i] = to;
1320 } else {
1321 extractorTypeParameters[i].bind((_TypeVariable) tType, to);
1322 }
1323 }
1324 }
1325
1326 _Type vType = extractorTypeParameters[1]; // V
1327 if (vType instanceof _TypeVariable) { // redundant
1328 _Class to = new _Class(javaExtractor instanceof Predicate ? Boolean.class : Object.class);
1329 for (int i=0; i<extractorTypeParameters.length; ++i) {
1330 if (vType.equals(extractorTypeParameters[i])) {
1331 extractorTypeParameters[i] = to;
1332 } else {
1333 extractorTypeParameters[i].bind((_TypeVariable) vType, to);
1334 }
1335 }
1336 }
1337
1338 _Type cType = extractorTypeParameters[2]; // C
1339 if (cType instanceof _TypeVariable) {
1340 _Class to = new _Class(contextType);
1341 for (int i=0; i<extractorTypeParameters.length; ++i) {
1342 if (cType.equals(extractorTypeParameters[i])) {
1343 extractorTypeParameters[i] = to;
1344 } else {
1345 extractorTypeParameters[i].bind((_TypeVariable) cType, to);
1346 }
1347 }
1348 }
1349 }
1350
1351 public String getPackageName() {
1352 return packageName;
1353 }
1354
1355 public String getClassName() {
1356 return className;
1357 }
1358
1359 public String getT() {
1360 return extractorTypeParameters[0].toJavaDeclaration();
1361 }
1362
1363 public String getV() {
1364 return extractorTypeParameters[1].toJavaDeclaration();
1365 }
1366
1367 public String getC() {
1368 return extractorTypeParameters[2].toJavaDeclaration();
1369 }
1370
1371 public boolean isPredicate() {
1372 return javaExtractor instanceof Predicate;
1373 }
1374
1375 public boolean isContextDependent() {
1376 return javaExtractor.isContextDependent();
1377 }
1378
1379 public String getParameterIndicesCSV() {
1380 StringBuilder ret = new StringBuilder();
1381 for (Object pi: javaExtractor.parameterIndices()) {
1382 if (ret.length()>0) {
1383 ret.append(", ");
1384 }
1385 ret.append(pi);
1386 }
1387 return ret.toString();
1388 }
1389
1390 public Iterable<JavaExtractor.Parameter> getParameters() {
1391 return javaExtractor.getParameters();
1392 }
1393
1394 public String maybeCastParameter(JavaExtractor.Parameter parameter) {
1395 Class<?> pType = parameter.getType();
1396 Class<?> tType = ((_Class) extractorTypeParameters[0]).clazz;
1397 if (pType.isAssignableFrom(tType)) {
1398 return "";
1399 }
1400
1401 if (pType.isPrimitive()) {
1402 if (boolean.class.equals(pType)) {
1403 return "("+Boolean.class.getName()+")";
1404 } else if (char.class.equals(pType)) {
1405 return "("+Character.class.getName()+")";
1406 } else if (byte.class.equals(pType)) {
1407 return "("+Byte.class.getName()+")";
1408 } else if (short.class.equals(pType)) {
1409 return "("+Short.class.getName()+")";
1410 } else if (int.class.equals(pType)) {
1411 return "("+Integer.class.getName()+")";
1412 } else if (long.class.equals(pType)) {
1413 return "("+Long.class.getName()+")";
1414 } else if (float.class.equals(pType)) {
1415 return "("+Float.class.getName()+")";
1416 } else if (double.class.equals(pType)) {
1417 return "("+Double.class.getName()+")";
1418 } else if (void.class.equals(pType)) {
1419 throw new IllegalArgumentException("Parameter type cannot be void");
1420 }
1421 }
1422
1423 return "("+pType.getCanonicalName()+")";
1424 }
1425
1426 public String getExpression() {
1427 return javaExtractor.getExpression();
1428 }
1429
1430 public String getEscapedExpression() {
1431 return StringEscapeUtils.escapeJava(javaExtractor.getExpression());
1432 }
1433 }
1434
1435 /**
1436 * Compiles bindings for classes specified in the command line. Uses system properties for
1437 * token expansion.
1438 * @param args
1439 * @throws Exception
1440 */
1441 @SuppressWarnings("unchecked")
1442 public static void main(String[] args) throws Exception {
1443 System.out.println("Parameters: <output directory> <bus class> <handler classes>");
1444 JavaBinderCompiler compiler = new JavaBinderCompiler(new File(args[0]));
1445 Class<EventBus> busClass = (Class<EventBus>) Class.forName(args[1]);
1446 TokenExpander tokenExpander = new TokenExpander(new TokenSource() {
1447
1448 @Override
1449 public String getToken(String name) {
1450 return System.getProperty(name);
1451 }
1452
1453 });
1454 for (int i=2; i<args.length; ++i) {
1455 Class<?> handlerClass = Class.forName(args[i]);
1456 System.out.println("Compiling Java binder for "+handlerClass.getName());
1457 compiler.compileJavaBinder(handlerClass, busClass, null, tokenExpander);
1458 }
1459 }
1460 }