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

COVERAGE SUMMARY FOR SOURCE FILE [IntrospectorBase.java]

nameclass, %method, %block, %line, %
IntrospectorBase.java67%  (2/3)59%  (10/17)86%  (604/705)82%  (101.2/123)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class PredicateWrapper0%   (0/1)0%   (0/7)0%   (0/53)0%   (0/11)
PredicateWrapper (Extractor): void 0%   (0/1)0%   (0/6)0%   (0/3)
compareTo (Extractor): ComparisonResult 0%   (0/1)0%   (0/8)0%   (0/1)
equals (Object): boolean 0%   (0/1)0%   (0/19)0%   (0/3)
extract (Object, Map, Object []): Boolean 0%   (0/1)0%   (0/8)0%   (0/1)
getCost (): double 0%   (0/1)0%   (0/4)0%   (0/1)
isContextDependent (): boolean 0%   (0/1)0%   (0/4)0%   (0/1)
parameterIndices (): Set 0%   (0/1)0%   (0/4)0%   (0/1)
     
class IntrospectorBase100% (1/1)100% (4/4)92%  (571/619)89%  (89.2/100)
createPredicate (Class, String, Class [], int, Method): Predicate 100% (1/1)83%  (177/212)81%  (31.4/39)
parameterNames (Method, int): String [] 100% (1/1)88%  (93/106)82%  (14.8/18)
IntrospectorBase (ClassLoader, TokenExpander): void 100% (1/1)100% (9/9)100% (4/4)
introspect (Class, Class): Collection 100% (1/1)100% (292/292)100% (39/39)
     
class IntrospectorBase$IntrospectionResult100% (1/1)100% (6/6)100% (33/33)100% (12/12)
IntrospectorBase$IntrospectionResult (Method, int, Class [], Handler, Predica... 100% (1/1)100% (18/18)100% (7/7)
getHandlerAnnotation (): Handler 100% (1/1)100% (3/3)100% (1/1)
getMethod (): Method 100% (1/1)100% (3/3)100% (1/1)
getOffset (): int 100% (1/1)100% (3/3)100% (1/1)
getParameterTypes (): Class [] 100% (1/1)100% (3/3)100% (1/1)
getPredicates (): Predicate [] 100% (1/1)100% (3/3)100% (1/1)

1package com.hammurapi.eventbus;
2 
3import java.lang.annotation.Annotation;
4import java.lang.reflect.Method;
5import java.util.ArrayList;
6import java.util.Collection;
7import java.util.Collections;
8import java.util.List;
9import java.util.Map;
10import java.util.Set;
11 
12import org.apache.bcel.classfile.JavaClass;
13import org.apache.bcel.classfile.LocalVariable;
14import org.apache.bcel.classfile.LocalVariableTable;
15import org.apache.bcel.util.ClassLoaderRepository;
16 
17import com.hammurapi.common.Condition;
18import com.hammurapi.common.TokenExpander;
19import com.hammurapi.extract.And;
20import com.hammurapi.extract.CommutativeAnd;
21import com.hammurapi.extract.ComparisonResult;
22import com.hammurapi.extract.Extractor;
23import com.hammurapi.extract.ExtractorFactory;
24import com.hammurapi.extract.IndexedExtractor;
25import com.hammurapi.extract.InstanceOfPredicate;
26import com.hammurapi.extract.Predicate;
27 
28/**
29 * Base class for Introspector and compiler. This class provides introspecting functionality.
30 * @author Pavel Vlasov
31 *
32 */
33public class IntrospectorBase<E,C> {
34        
35        public static class IntrospectionResult<E,C> {
36                
37                private Method method;
38                private Predicate<E,C>[] predicates;
39                private int offset; 
40                private Class<E>[] parameterTypes; 
41                private Handler handlerAnnotation; 
42                
43                public Method getMethod() {
44                        return method;
45                }
46                public Predicate<E, C>[] getPredicates() {
47                        return predicates;
48                }
49                public int getOffset() {
50                        return offset;
51                }
52                public Class<E>[] getParameterTypes() {
53                        return parameterTypes;
54                }
55                public Handler getHandlerAnnotation() {
56                        return handlerAnnotation;
57                }
58                
59                IntrospectionResult(
60                                Method method, 
61                                int offset, 
62                                Class<E>[] parameterTypes, 
63                                Handler handlerAnnotation,
64                                Predicate<E, C>... predicates) {
65                        
66                        super();
67                        this.method = method;
68                        this.predicates = predicates;
69                        this.offset = offset;
70                        this.parameterTypes = parameterTypes;
71                        this.handlerAnnotation = handlerAnnotation;
72                }                
73                
74        }
75        
76        private static final String ARG = "arg";
77        private static final String SEPARATOR = "://";
78        private static final String JAVA = "java(*)";
79        private ClassLoader classLoader;
80        private TokenExpander tokenExpander;        
81        
82        public IntrospectorBase(ClassLoader classLoader, TokenExpander tokenExpander) {
83                this.classLoader = classLoader;
84                this.tokenExpander = tokenExpander;
85        }
86        
87        protected Collection<IntrospectionResult<E,C>> introspect(Class<C> handlerClass, Class<E> eventType) {
88                Collection<IntrospectionResult<E,C>> ret = new ArrayList<IntrospectionResult<E,C>>();
89                for (Method method: handlerClass.getMethods()) {
90                        final Method mthd = method;
91                        final Handler ha = method.getAnnotation(Handler.class);
92                        if (ha!=null) {                                                                                        
93                                Collection<Predicate<E, C>> typeGuards = new ArrayList<Predicate<E, C>>();
94                                List<Predicate<E, C>> conditions = new ArrayList<Predicate<E, C>>();
95                                Class<E>[] pTypes = (Class<E>[]) method.getParameterTypes();
96                                Annotation[][] panna = method.getParameterAnnotations();
97                                boolean hedcp = pTypes.length>1 && EventDispatchContext.class.isAssignableFrom(pTypes[0]);
98                                final int offset = hedcp ? 1 : 0;
99                                
100                                // Adjust parameters                                
101                                final Class<E>[] pt;
102                                if (hedcp) {
103                                        pt = new Class[pTypes.length-1];
104                                        System.arraycopy(pTypes, 1, pt, 0, pt.length);
105                                } else {
106                                        pt = pTypes;
107                                }
108                                for (int i=0; i<pt.length; ++i) {
109                                        Class<? extends E> parameterType = pt[i]; 
110                                        // If parameter is a subclass of bus event type - create instanceof predicate.
111                                        if (!parameterType.equals(eventType)) { 
112                                                // Stupid, but doesn't compile in command line otherwise.
113                                                Object indexedExtractor = new IndexedExtractor<E, C>(i);
114                                                Extractor<E, Object, C> extractor = (Extractor<E, Object, C>) indexedExtractor;
115                                                InstanceOfPredicate<E, C> io = new InstanceOfPredicate<E, C>(extractor, parameterType);
116                                                
117                                                typeGuards.add(io);
118                                        }
119                                        
120                                        for (Annotation pAnn: panna[i+offset]) {
121                                                if (pAnn instanceof Condition) {
122                                                        for (String cnd: ((Condition) pAnn).value()) {
123                                                                conditions.add(createPredicate(handlerClass, cnd, pt, i, method));
124                                                        }
125                                                }
126                                        }
127                                }
128                                for (String cnd: ha.value()) {
129                                        conditions.add(createPredicate(handlerClass, cnd, pt, -1, method));
130                                }
131                                
132                                
133                                if (typeGuards.isEmpty()) {
134                                        Predicate<E, C>[] pa = (Predicate<E, C>[]) conditions.toArray(new Predicate[conditions.size()]);
135                                        ret.add(new IntrospectionResult<E, C>(method, offset, pt, ha, pa));
136                                } else if (conditions.isEmpty()) {
137                                        Predicate<E, C>[] pa = (Predicate<E, C>[]) typeGuards.toArray(new Predicate[typeGuards.size()]);                                
138                                        ret.add(new IntrospectionResult<E, C>(method, offset, pt, ha, pa));
139                                } else {
140                                        CommutativeAnd<E, C> tg = new CommutativeAnd<E, C>(0, null, typeGuards);
141                                        
142                                        Collections.sort(conditions, new PredicateCostCardinalityComparator<E, C>());
143                                        CommutativeAnd<E, C> cnd = new CommutativeAnd<E, C>(0, null, conditions);
144                                        ret.add(new IntrospectionResult<E, C>(method, offset, pt, ha, new And<E, C>(0, null, tg.normalize(), cnd.normalize()).normalize()));
145                                }
146                        }
147                }
148                return ret;
149        }
150 
151        /**
152         * Creates predicate from string representation.
153         * @param instance
154         * @param cnd
155         * @param parameterTypes
156         * @param classLoader
157         * @param parameterIndex Parameter index for parameter level predicates, -1 for method level predicates.
158         * @return
159         */
160        @SuppressWarnings("unchecked")
161        private Predicate<E, C> createPredicate(
162                        Class<C> contextType, 
163                        String cnd, 
164                        final Class<E>[] parameterTypes, 
165                        final int parameterIndex,
166                        Method method) {
167                int separatorIdx = cnd.indexOf(SEPARATOR);
168                if (separatorIdx>0) {
169                        int quoteIdx = cnd.indexOf("\"");
170                        if (quoteIdx>=0 && quoteIdx<separatorIdx) {
171                                separatorIdx = -1;
172                        } else {
173                                quoteIdx = cnd.indexOf("'");
174                                if (quoteIdx>=0 && quoteIdx<separatorIdx) {
175                                        separatorIdx = -1;
176                                }
177                        }
178                }
179                                                
180                String languageName = separatorIdx==-1 ? JAVA : cnd.substring(0, separatorIdx);
181                if (separatorIdx>0) {
182                        cnd = cnd.substring(separatorIdx+SEPARATOR.length());
183                }
184                
185                // Parameter names are in quotes after language name, if it is explicitly specified
186                String[] parameterNames = new String[parameterTypes.length];
187                boolean hasParameterNames = false;
188                int lpidx = languageName.indexOf("(");
189                if (lpidx>0) {
190                        int rpidx = languageName.indexOf(")");
191                        if (rpidx>lpidx) {
192                                hasParameterNames = true;
193                                String[] pNames = parameterIndex==-1 ? languageName.substring(lpidx+1, rpidx).split(",") : new String[] {languageName.substring(lpidx+1, rpidx)};
194                                if (pNames.length>parameterNames.length) {
195                                        throw new DispatchNetworkException("Number of parameter names is greater than number of parameters");
196                                }
197                                if (pNames.length==1 && pNames[0]!=null && "*".equals(pNames[0].trim())) {
198                                        pNames = parameterNames(method, parameterIndex);
199                                }
200                                for (int i=0; i<pNames.length; ++i) {
201                                        if (parameterIndex==-1) {
202                                                String pName = pNames[i].trim();
203                                                if (pName.length()>0) {
204                                                        parameterNames[i] = pName;
205                                                }
206                                        } else if (i==0) {
207                                                parameterNames[parameterIndex] = pNames[i];
208                                        }
209                                }
210                                languageName=languageName.substring(0, lpidx);
211                        }
212                }
213                
214                if (!hasParameterNames && parameterIndex!=-1) {
215                        parameterNames[parameterIndex]=ARG;
216                }
217                
218                Extractor<E, Boolean, C> extractor = ExtractorFactory.INSTANCE.createExtractor(languageName, tokenExpander==null ? cnd : tokenExpander.expand(cnd), parameterNames, parameterTypes, Boolean.class, contextType, classLoader);
219                
220                if (extractor instanceof Predicate) {
221                        return (Predicate<E, C>) extractor;
222                }
223                
224                if (extractor==null) {
225                        throw new DispatchNetworkException("Could not create extractor for language "+languageName);                
226                }
227                                                
228                return new PredicateWrapper<E,C>(extractor);
229        }
230 
231        /**
232         * Extracts parameter names from class file. Requires the class to be compiled with
233         * -g or -g:vars
234         * @param method
235         * @return
236         */
237        private String[] parameterNames(Method method, int parameterIndex) {
238                try {
239                ClassLoaderRepository clr = new ClassLoaderRepository(method.getDeclaringClass().getClassLoader());
240                JavaClass jc = clr.loadClass(method.getDeclaringClass());
241                org.apache.bcel.classfile.Method jmth = jc.getMethod(method);
242                LocalVariableTable lvt = jmth.getLocalVariableTable();
243                if (lvt==null) {
244                        throw new DispatchNetworkException("Cannot retrieve parameter names from the class file, make sure it is compiled with debug information (-g or -g:vars option)");
245                }
246                
247                        Class<?>[] pTypes = method.getParameterTypes();
248                        boolean hasEventDispatchContextParameter = pTypes.length>1 && EventDispatchContext.class.isAssignableFrom(pTypes[0]);
249                        
250                LocalVariable[] alvt = lvt.getLocalVariableTable();
251                String[] ret = new String[hasEventDispatchContextParameter? method.getParameterTypes().length - 1 : method.getParameterTypes().length];
252                int offset = jmth.isStatic() ? 0 : 1;
253                
254                        if (hasEventDispatchContextParameter) {
255                                ++offset;
256                        }
257                        
258                for (int i=0; i<ret.length; ++i) {
259                        ret[i] = alvt[i+offset].getName();
260                }
261                return parameterIndex==-1 ? ret : new String[] {ret[parameterIndex]};
262                } catch (ClassNotFoundException e) {
263                        throw new DispatchNetworkException(e);
264                }
265        }
266 
267}
268 
269class PredicateWrapper<E, C> implements Predicate<E, C> {
270        
271        private Extractor<E, Boolean, C> extractor;
272        
273        public PredicateWrapper(Extractor<E, Boolean, C> extractor) {
274                this.extractor = extractor;
275        }
276 
277        @Override
278        public ComparisonResult compareTo(Extractor<E, Boolean, C> otherPredicate) {
279                return equals(otherPredicate) ? ComparisonResult.EQUAL_NM : ComparisonResult.NOT_EQUAL_NM;
280        }
281 
282        @Override
283        public Boolean extract(
284                        C context,
285                        Map<C, Map<Extractor<E, ? super Boolean, C>, ? super Boolean>> cache,
286                        E... obj) {
287                
288                return extractor.extract(context, cache, obj);
289        }
290 
291        @Override
292        public boolean isContextDependent() {
293                return extractor.isContextDependent();
294        }
295 
296        @Override
297        public Set<Integer> parameterIndices() {
298                return extractor.parameterIndices();
299        }
300 
301        @SuppressWarnings("unchecked")
302        @Override
303        public boolean equals(Object otherPredicate) {
304                if (this==otherPredicate) {
305                        return true;
306                }
307                
308                return otherPredicate instanceof PredicateWrapper && extractor.equals(((PredicateWrapper<E,C>) otherPredicate).extractor);
309        }
310 
311        @Override
312        public double getCost() {
313                return extractor.getCost();
314        }
315        
316}

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