EMMA Coverage Report (generated Thu Jan 20 11:39:44 EST 2011)
[all classes][com.hammurapi.eventbus]

COVERAGE SUMMARY FOR SOURCE FILE [JavaBinderCompiler.java]

nameclass, %method, %block, %line, %
JavaBinderCompiler.java85%  (22/26)82%  (93/113)73%  (2704/3702)74%  (450.7/613)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JavaBinderCompiler$20%   (0/1)0%   (0/2)0%   (0/6)0%   (0/3)
JavaBinderCompiler$2 (): void 0%   (0/1)0%   (0/3)0%   (0/2)
getToken (String): String 0%   (0/1)0%   (0/3)0%   (0/1)
     
class JavaBinderCompiler$ConvertersBundle$40%   (0/1)0%   (0/2)0%   (0/32)0%   (0/8)
JavaBinderCompiler$ConvertersBundle$4 (JavaBinderCompiler$ConvertersBundle): ... 0%   (0/1)0%   (0/6)0%   (0/2)
render (Writer, Map, Context, String, Locale, File): boolean 0%   (0/1)0%   (0/26)0%   (0/6)
     
class JavaBinderCompiler$ConvertersBundle$70%   (0/1)0%   (0/2)0%   (0/115)0%   (0/20)
JavaBinderCompiler$ConvertersBundle$7 (JavaBinderCompiler$ConvertersBundle, M... 0%   (0/1)0%   (0/9)0%   (0/2)
render (Writer, Map, Context, String, Locale, File): boolean 0%   (0/1)0%   (0/106)0%   (0/18)
     
class JavaBinderCompiler$ConvertersBundle$90%   (0/1)0%   (0/2)0%   (0/32)0%   (0/8)
JavaBinderCompiler$ConvertersBundle$9 (JavaBinderCompiler$ConvertersBundle): ... 0%   (0/1)0%   (0/6)0%   (0/2)
render (Writer, Map, Context, String, Locale, File): boolean 0%   (0/1)0%   (0/26)0%   (0/6)
     
class JavaBinderCompiler$1100% (1/1)50%  (1/2)27%  (6/22)33%  (2/6)
compare (List, List): int 0%   (0/1)0%   (0/16)0%   (0/4)
JavaBinderCompiler$1 (JavaBinderCompiler): void 100% (1/1)100% (6/6)100% (2/2)
     
class JavaBinderCompiler$_TypeVariable100% (1/1)56%  (5/9)49%  (55/112)58%  (19/33)
hashCode (): int 0%   (0/1)0%   (0/19)0%   (0/4)
setName (String): void 0%   (0/1)0%   (0/4)0%   (0/2)
toJavaDeclaration (): String 0%   (0/1)0%   (0/3)0%   (0/1)
toString (): String 0%   (0/1)0%   (0/11)0%   (0/1)
bind (JavaBinderCompiler$_TypeVariable, JavaBinderCompiler$_Type): void 100% (1/1)35%  (7/20)40%  (2/5)
equals (Object): boolean 100% (1/1)81%  (30/37)77%  (10/13)
JavaBinderCompiler$_TypeVariable (String): void 100% (1/1)100% (7/7)100% (3/3)
JavaBinderCompiler$_TypeVariable (TypeVariable): void 100% (1/1)100% (8/8)100% (3/3)
getName (): String 100% (1/1)100% (3/3)100% (1/1)
     
class JavaBinderCompiler$BindMethod100% (1/1)100% (11/11)56%  (168/302)70%  (35/50)
getParameterTypeCast (int): String 100% (1/1)36%  (56/156)43%  (10/23)
inlinePredicate (int): String 100% (1/1)48%  (32/66)75%  (6/8)
JavaBinderCompiler$BindMethod (JavaBinderCompiler, String, IntrospectorBase$I... 100% (1/1)100% (48/48)100% (11/11)
getEventDispatchContext (): JavaBinderCompiler$EventDispatchContextDescriptor 100% (1/1)100% (3/3)100% (1/1)
getHandlerAnnotation (): Handler 100% (1/1)100% (4/4)100% (1/1)
getMethod (): Method 100% (1/1)100% (4/4)100% (1/1)
getName (): String 100% (1/1)100% (3/3)100% (1/1)
getOffset (): int 100% (1/1)100% (4/4)100% (1/1)
getParameterTypes (): Class [] 100% (1/1)100% (4/4)100% (1/1)
getPredicates (): Predicate [] 100% (1/1)100% (4/4)100% (1/1)
isVoid (): boolean 100% (1/1)100% (6/6)100% (1/1)
     
class JavaBinderCompiler$ConvertersBundle$8100% (1/1)100% (2/2)57%  (51/89)64%  (9/14)
render (Writer, Map, Context, String, Locale, File): boolean 100% (1/1)52%  (42/80)58%  (7/12)
JavaBinderCompiler$ConvertersBundle$8 (JavaBinderCompiler$ConvertersBundle, N... 100% (1/1)100% (9/9)100% (2/2)
     
class JavaBinderCompiler$ConvertersBundle$2100% (1/1)100% (2/2)57%  (97/169)69%  (18/26)
render (Writer, Map, Context, String, Locale, File): boolean 100% (1/1)55%  (88/160)67%  (16/24)
JavaBinderCompiler$ConvertersBundle$2 (JavaBinderCompiler$ConvertersBundle, B... 100% (1/1)100% (9/9)100% (2/2)
     
class JavaBinderCompiler$ConvertersBundle$6100% (1/1)100% (2/2)64%  (67/105)69%  (11/16)
render (Writer, Map, Context, String, Locale, File): boolean 100% (1/1)60%  (58/96)64%  (9/14)
JavaBinderCompiler$ConvertersBundle$6 (JavaBinderCompiler$ConvertersBundle, I... 100% (1/1)100% (9/9)100% (2/2)
     
class JavaBinderCompiler$PathEntry100% (1/1)67%  (2/3)66%  (65/98)83%  (15/18)
toString (): String 0%   (0/1)0%   (0/29)0%   (0/2)
JavaBinderCompiler$PathEntry (Type, Class): void 100% (1/1)73%  (11/15)83%  (5/6)
bind (JavaBinderCompiler$_Type []): void 100% (1/1)100% (54/54)100% (10/10)
     
class JavaBinderCompiler$ConvertersBundle$1100% (1/1)100% (2/2)67%  (68/102)74%  (14/19)
render (Writer, Map, Context, String, Locale, File): boolean 100% (1/1)63%  (59/93)71%  (12/17)
JavaBinderCompiler$ConvertersBundle$1 (JavaBinderCompiler$ConvertersBundle, C... 100% (1/1)100% (9/9)100% (2/2)
     
class JavaBinderCompiler$CompileHelper100% (1/1)100% (13/13)76%  (334/440)81%  (60.8/75)
maybeCastParameter (JavaExtractor$Parameter): String 100% (1/1)37%  (59/159)46%  (11/24)
getParameterIndicesCSV (): String 100% (1/1)87%  (26/30)83%  (5/6)
JavaBinderCompiler$CompileHelper (String, String, Class, JavaExtractor): void 100% (1/1)99%  (204/206)100% (34.8/35)
getC (): String 100% (1/1)100% (6/6)100% (1/1)
getClassName (): String 100% (1/1)100% (3/3)100% (1/1)
getEscapedExpression (): String 100% (1/1)100% (5/5)100% (1/1)
getExpression (): String 100% (1/1)100% (4/4)100% (1/1)
getPackageName (): String 100% (1/1)100% (3/3)100% (1/1)
getParameters (): Iterable 100% (1/1)100% (4/4)100% (1/1)
getT (): String 100% (1/1)100% (6/6)100% (1/1)
getV (): String 100% (1/1)100% (6/6)100% (1/1)
isContextDependent (): boolean 100% (1/1)100% (4/4)100% (1/1)
isPredicate (): boolean 100% (1/1)100% (4/4)100% (1/1)
     
class JavaBinderCompiler$ConvertersBundle$3100% (1/1)100% (2/2)76%  (82/108)67%  (14/21)
render (Writer, Map, Context, String, Locale, File): boolean 100% (1/1)74%  (73/99)63%  (12/19)
JavaBinderCompiler$ConvertersBundle$3 (JavaBinderCompiler$ConvertersBundle, C... 100% (1/1)100% (9/9)100% (2/2)
     
class JavaBinderCompiler$ConvertersBundle100% (1/1)77%  (10/13)77%  (55/71)77%  (10/13)
toWriterRenderer (False): WriterRenderer 0%   (0/1)0%   (0/5)0%   (0/1)
toWriterRenderer (MappedExtractor): WriterRenderer 0%   (0/1)0%   (0/6)0%   (0/1)
toWriterRenderer (True): WriterRenderer 0%   (0/1)0%   (0/5)0%   (0/1)
JavaBinderCompiler$ConvertersBundle (): void 100% (1/1)100% (3/3)100% (1/1)
access$0 (Extractor): String 100% (1/1)100% (3/3)100% (1/1)
prefix (Extractor): String 100% (1/1)100% (7/7)100% (1/1)
toWriterRenderer (BinaryExtractor): WriterRenderer 100% (1/1)100% (6/6)100% (1/1)
toWriterRenderer (CompositePredicate): WriterRenderer 100% (1/1)100% (6/6)100% (1/1)
toWriterRenderer (Constant): WriterRenderer 100% (1/1)100% (6/6)100% (1/1)
toWriterRenderer (IndexedExtractor): WriterRenderer 100% (1/1)100% (6/6)100% (1/1)
toWriterRenderer (InstanceOfPredicate): WriterRenderer 100% (1/1)100% (6/6)100% (1/1)
toWriterRenderer (JavaExtractor): WriterRenderer 100% (1/1)100% (6/6)100% (1/1)
toWriterRenderer (Not): WriterRenderer 100% (1/1)100% (6/6)100% (1/1)
     
class JavaBinderCompiler100% (1/1)89%  (8/9)82%  (624/761)79%  (98.2/124)
main (String []): void 0%   (0/1)0%   (0/55)0%   (0/9)
compileJavaBinder (Class, Class, ClassLoader, TokenExpander): void 100% (1/1)84%  (414/493)79%  (62.4/79)
getBinderClassName (Class): String 100% (1/1)88%  (22/25)94%  (1.9/2)
JavaBinderCompiler (File): void 100% (1/1)100% (11/11)100% (4/4)
access$0 (Class, Class): List 100% (1/1)100% (4/4)100% (1/1)
access$1 (JavaBinderCompiler): File 100% (1/1)100% (3/3)100% (1/1)
getBinderClassPackage (Class): String 100% (1/1)100% (4/4)100% (1/1)
inheritancePaths (Class, Class): List 100% (1/1)100% (104/104)100% (19/19)
toJavaDeclaration (Class, JavaBinderCompiler$_Type []): String 100% (1/1)100% (62/62)100% (8/8)
     
class JavaBinderCompiler$ConvertersBundle$5100% (1/1)100% (2/2)83%  (39/47)70%  (7/10)
render (Writer, Map, Context, String, Locale, File): boolean 100% (1/1)79%  (30/38)62%  (5/8)
JavaBinderCompiler$ConvertersBundle$5 (JavaBinderCompiler$ConvertersBundle, I... 100% (1/1)100% (9/9)100% (2/2)
     
class JavaBinderCompiler$ConvertersBundle$10100% (1/1)100% (3/3)84%  (342/406)74%  (37.8/51)
render (Writer, Map, Context, String, Locale, File): boolean 100% (1/1)83%  (248/300)73%  (35.9/49)
$SWITCH_TABLE$com$hammurapi$extract$ComparisonResult$Type (): int [] 100% (1/1)88%  (85/97)87%  (0.9/1)
JavaBinderCompiler$ConvertersBundle$10 (JavaBinderCompiler$ConvertersBundle, ... 100% (1/1)100% (9/9)100% (2/2)
     
class JavaBinderCompiler$_ParameterizedType100% (1/1)75%  (3/4)86%  (104/121)87%  (20/23)
toString (): String 0%   (0/1)0%   (0/17)0%   (0/3)
JavaBinderCompiler$_ParameterizedType (ParameterizedType): void 100% (1/1)100% (32/32)100% (7/7)
bind (JavaBinderCompiler$_TypeVariable, JavaBinderCompiler$_Type): void 100% (1/1)100% (30/30)100% (5/5)
toJavaDeclaration (): String 100% (1/1)100% (42/42)100% (8/8)
     
class JavaBinderCompiler$_Type100% (1/1)100% (3/3)89%  (33/37)88%  (7/8)
createType (Type): JavaBinderCompiler$_Type 100% (1/1)87%  (27/31)86%  (6/7)
JavaBinderCompiler$_Type (): void 100% (1/1)100% (3/3)100% (1/1)
JavaBinderCompiler$_Type (JavaBinderCompiler$_Type): void 100% (1/1)100% (3/3)100% (1/1)
     
class JavaBinderCompiler$_Class100% (1/1)80%  (4/5)91%  (109/120)96%  (22/23)
toString (): String 0%   (0/1)0%   (0/11)0%   (0/1)
JavaBinderCompiler$_Class (Class): void 100% (1/1)100% (31/31)100% (7/7)
access$0 (JavaBinderCompiler$_Class): Class 100% (1/1)100% (3/3)100% (1/1)
bind (JavaBinderCompiler$_TypeVariable, JavaBinderCompiler$_Type): void 100% (1/1)100% (30/30)100% (5/5)
toJavaDeclaration (): String 100% (1/1)100% (45/45)100% (9/9)
     
class JavaBinderCompiler$EventDispatchContextDescriptor$1100% (1/1)100% (2/2)91%  (20/22)83%  (5/6)
compare (List, List): int 100% (1/1)88%  (14/16)75%  (3/4)
JavaBinderCompiler$EventDispatchContextDescriptor$1 (JavaBinderCompiler$Event... 100% (1/1)100% (6/6)100% (2/2)
     
class JavaBinderCompiler$BindHelper100% (1/1)100% (4/4)100% (99/99)100% (18/18)
JavaBinderCompiler$BindHelper (JavaBinderCompiler, Collection, Class, JavaBin... 100% (1/1)100% (90/90)100% (15/15)
getBindMethods (): Collection 100% (1/1)100% (3/3)100% (1/1)
getContextType (): Class 100% (1/1)100% (3/3)100% (1/1)
getJavaExtractorEntries (): Collection 100% (1/1)100% (3/3)100% (1/1)
     
class JavaBinderCompiler$CompileHelper$1100% (1/1)100% (2/2)100% (22/22)100% (6/6)
JavaBinderCompiler$CompileHelper$1 (JavaBinderCompiler$CompileHelper): void 100% (1/1)100% (6/6)100% (2/2)
compare (List, List): int 100% (1/1)100% (16/16)100% (4/4)
     
class JavaBinderCompiler$EventDispatchContextDescriptor100% (1/1)100% (6/6)100% (243/243)100% (33/33)
JavaBinderCompiler$EventDispatchContextDescriptor (JavaBinderCompiler, Class,... 100% (1/1)100% (149/149)100% (19/19)
bind (JavaBinderCompiler$_Type [], int, JavaBinderCompiler$_TypeVariable, Jav... 100% (1/1)100% (18/18)100% (4/4)
getEventType (): String 100% (1/1)100% (6/6)100% (1/1)
getStoreType (): String 100% (1/1)100% (6/6)100% (1/1)
getType (): String 100% (1/1)100% (59/59)100% (7/7)
isJoin (): boolean 100% (1/1)100% (5/5)100% (1/1)
     
class JavaBinderCompiler$JavaExtractorEntry100% (1/1)100% (4/4)100% (21/21)100% (8/8)
JavaBinderCompiler$JavaExtractorEntry (JavaExtractor, String, String): void 100% (1/1)100% (12/12)100% (5/5)
getClassName (): String 100% (1/1)100% (3/3)100% (1/1)
getJavaExtractor (): JavaExtractor 100% (1/1)100% (3/3)100% (1/1)
getPackageName (): String 100% (1/1)100% (3/3)100% (1/1)

1package com.hammurapi.eventbus;
2 
3import java.io.File;
4import java.io.FileOutputStream;
5import java.io.FileWriter;
6import java.io.IOException;
7import java.io.ObjectOutputStream;
8import java.io.StringWriter;
9import java.io.Writer;
10import java.lang.reflect.Method;
11import java.lang.reflect.ParameterizedType;
12import java.lang.reflect.Type;
13import java.lang.reflect.TypeVariable;
14import java.util.ArrayList;
15import java.util.Arrays;
16import java.util.Collection;
17import java.util.Collections;
18import java.util.Comparator;
19import java.util.HashMap;
20import java.util.HashSet;
21import java.util.Iterator;
22import java.util.List;
23import java.util.Locale;
24import java.util.Map;
25import java.util.Set;
26 
27import org.apache.commons.lang.StringEscapeUtils;
28import org.onemind.jxp.JxpContext;
29import org.onemind.jxp.JxpPageSource;
30import org.onemind.jxp.JxpProcessor;
31import org.onemind.jxp.ResourceStreamPageSource;
32 
33import com.hammurapi.common.Context;
34import com.hammurapi.common.TokenExpander;
35import com.hammurapi.common.TokenExpander.TokenSource;
36import com.hammurapi.convert.AbstractReflectiveAtomicConvertersBundle;
37import com.hammurapi.convert.ConverterMethod;
38import com.hammurapi.convert.ConvertingService;
39import com.hammurapi.eventbus.IntrospectorBase.IntrospectionResult;
40import com.hammurapi.extract.BinaryExtractor;
41import com.hammurapi.extract.ComparisonResult;
42import com.hammurapi.extract.CompositePredicate;
43import com.hammurapi.extract.Constant;
44import com.hammurapi.extract.Equal;
45import com.hammurapi.extract.Extractor;
46import com.hammurapi.extract.False;
47import com.hammurapi.extract.IndexedExtractor;
48import com.hammurapi.extract.InstanceOfPredicate;
49import com.hammurapi.extract.MappedExtractor;
50import com.hammurapi.extract.Not;
51import com.hammurapi.extract.NotEqual;
52import com.hammurapi.extract.Predicate;
53import com.hammurapi.extract.True;
54import com.hammurapi.extract.java.JavaExtractor;
55import com.hammurapi.render.RenderingException;
56import com.hammurapi.render.WriterRenderer;
57 
58/**
59 * This class generates source code for Java binding class.
60 * By default binder classes are put to the same package as handler classes and have postfix ''JavaBinder''. 
61 * This behavior can be changed by subclassing the compiler. The class keeps track of generated predicate
62 * classes and attempts to reuse them.
63 *  
64 * @author Pavel Vlasov
65 *
66 */
67public class JavaBinderCompiler {
68        
69        protected static final String BINDER_CLASS_PACKAGE = "binderClassPackage";
70        private static final String JAVA_INLINE = "java_inline";
71        private static final String JAVA = "java";
72        private static final String BIND_HELPER = "bindHelper";
73        
74        private class EventDispatchContextDescriptor {
75                
76                private Class<EventDispatchContext> contextClass;
77                private _Type[] contextTypeParameters;
78 
79                public EventDispatchContextDescriptor(Class<EventDispatchContext> contextClass, _Type[] eventBusTypeParameters) {
80                        this.contextClass = contextClass;
81                        
82                        TypeVariable<Class<EventDispatchContext>>[] cctp = EventDispatchContext.class.getTypeParameters();
83                        contextTypeParameters = new _Type[cctp.length];
84                        for (int i=0; i< cctp.length; ++i) {
85                                contextTypeParameters[i] = _Type.createType(cctp[i]);
86                         }
87                        
88                        List<List<PathEntry>> iPaths = inheritancePaths(contextClass, EventDispatchContext.class);
89                        Collections.sort(iPaths, new Comparator<List<PathEntry>>() {
90 
91                                @Override
92                                public int compare(List<PathEntry> o1, List<PathEntry> o2) {
93                                        int sizeDelta =  o1.size() - o2.size();
94                                        if (sizeDelta!=0) {
95                                                return sizeDelta;
96                                        }
97                                        return o1.hashCode() - o2.hashCode();
98                                }
99                        });
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}

[all classes][com.hammurapi.eventbus]
EMMA 2.0.5312 EclEmma Fix 2 (C) Vladimir Roubtsov