KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > alt > jiapi > util > ChainBuilder


1 package alt.jiapi.util;
2
3 import java.lang.reflect.Constructor JavaDoc;
4 import java.lang.reflect.Field JavaDoc;
5 import java.lang.reflect.InvocationTargetException JavaDoc;
6 import java.util.StringTokenizer JavaDoc;
7
8 import org.apache.log4j.Category;
9
10 import alt.jiapi.instrumentor.ChainInstrumentor;
11 import alt.jiapi.instrumentor.InstrumentorChain;
12 import alt.jiapi.JiapiException;
13 import alt.jiapi.Runtime;
14
15 import alt.jiapi.instrumentor.Strategy;
16 import alt.jiapi.instrumentor.Hook;
17
18 /**
19  * This utility class may be used to create InstrumentorChain from String.
20  * It uses a special String format for specifying how the chain is to be
21  * built. <p>
22  *
23  * <blockquote>
24  * <b>NOTE: This code is experimental at the moment, and may not function
25  * correctly. Furthermore, String specs described below, might change
26  * without a notice.</b>
27  * </blockquote>
28  *
29  * General format of the chainSpec String is :
30  * <blockquote>
31  * <code> instrumentorSpec (| instrumentorSpec)* </code>
32  * </blockquote>
33  *
34  * Each instrumentorSpec represents an Instrumentor in chain that is
35  * to be created. First instrumentor(Spec) in chainSpec forward its output
36  * to the next instrumentor(Spec) and so on. '|' character acts as a marker
37  * between instrumentorSpecs. One may think that marker as a pipe marker
38  * in some operating system shells. <p>
39  *
40  * Format of the instrumentorSpec is :
41  * <blockquote>
42  * <code> instrumentorSymbol(#childSymbol(#childHint)?)?</code>
43  * </blockquote>
44  *
45  * instrumentorSymbol is a symbolic name of the Instrumentor to be used.
46  * It may be a fully qualified class name of the Instrumentor, or it may
47  * be its symbolic equivalence. SymbolMap is used to map symbolic
48  * names to class names.<p>
49  * childSymbol has a similar way of instantiating child; It could be a fully
50  * qualified class name or its symbolic name from SymbolMap.
51  * If child cannot be instantiated, it is considered to be an instance of
52  * String. In that case, child hints make no sense.<p>
53  * Instrumentor gets its child associated with itself through constructor.
54  * Reflection API, <code>Constructor</code> in particular, is
55  * used to instantiate Instrumentor. <p>
56  *
57  * childHint is passed to child the same way, as child gets passed to
58  * Instrumentor. Trough Constructor. This version supports only integer
59  * hints. Child is looked for a field named 'childHint'. If one is found,
60  * it is assumed, that there is a Constructor with same type as its
61  * argument.<p>
62  *
63  * Future versions of this class might slightly modify format described
64  * above. More childHint types might be added if there is need for one.
65  * and different ways of passing childHints and childs to their parents.
66  * Like java beans style get/set methods.<p>
67  *
68  * Samples:
69  * <blockquote>
70  * <code>"GrepInstrumentor#MethodCallStrategy | HeadInstrumentor | MethodCallInstrumentor#DummyHook"</code><br>
71  * If the default SymbolMap is used, chainSpec above would generate a chain
72  * with instrumentors added to it in the following order:
73  *
74  * <ol>
75  * <li>Instatiate <code>alt.jiapi.instrumentor.GrepInstrumentor</code> with
76  * <code>alt.jiapi.instrumentor.MethodCallStrategy</code> as its argument.
77  * This instrumentor is put first in the chain.
78  * <li><code>alt.jiapi.instrumentor.HeadInstrumentor</code> is
79  * instatiated, and added to chain.
80  * <li><code>alt.jiapi.instrumentor.MethodCallInstrumentor</code> is
81  * instatiated with and instance of <code>DummyHook</code> as its
82  * constructor argument. It is then added to chain.
83  * </ol>
84  *
85  * Resulting chain would instrument its input so, that a call is being made
86  * to DummyHook before a method call is being made.
87  * </blockquote>
88  *
89  * @see SymbolMap
90  * @author Mika Riekkinen, Joni Suominen
91  * @version $Revision: 1.5 $ $Date: 2004/03/15 14:47:53 $
92  */

93 public class ChainBuilder {
94     private static Category log = Runtime.getLogCategory(ChainBuilder.class);
95
96     private static final Class JavaDoc instrumentorClass = ChainInstrumentor.class;
97     private static final Class JavaDoc strategyClass = Strategy.class;
98     private static final Class JavaDoc hookClass = Hook.class;
99
100     private SymbolMap map;
101
102     /**
103      * Used in debugging.
104      */

105     public static void main(String JavaDoc [] args) throws Exception JavaDoc {
106         SymbolMap map = new SymbolMap("alt.jiapi.instrumentor");
107
108         ChainBuilder cb = new ChainBuilder(map);
109         InstrumentorChain chain = cb.createChain(args[0]);
110         System.out.println(chain);
111     }
112
113     public ChainBuilder() {
114         this.map = new SymbolMap("alt.jiapi.instrumentor");
115     }
116
117     public ChainBuilder(SymbolMap map) {
118         this.map = map;
119     }
120
121     /**
122      * Creates a chain from chainSpec and SymbolMap given in constructor.
123      */

124     public InstrumentorChain createChain(String JavaDoc chainSpec) throws JiapiException, ClassNotFoundException JavaDoc, InstantiationException JavaDoc {
125         return createChain(chainSpec, map);
126     }
127
128     /**
129      * Creates a chain from chainSpec and given SymbolMap
130      */

131     public InstrumentorChain createChain(String JavaDoc chainSpec, SymbolMap symbols) throws JiapiException, ClassNotFoundException JavaDoc, InstantiationException JavaDoc {
132         InstrumentorChain chain = new InstrumentorChain();
133
134         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(chainSpec, "|");
135         while (st.hasMoreTokens()) {
136             String JavaDoc instrumentorSpec = st.nextToken().trim();
137
138             ChainInstrumentor i = createInstrumentor(instrumentorSpec, symbols);
139             if (i == null) {
140                 throw new JiapiException("ChainBuilder.createInstrumentor(...) returned null");
141             }
142
143             chain.add(i);
144         }
145
146         return chain;
147     }
148
149     /**
150      * Create an Instrumentor from instrumentorSpec.
151      *
152      * @param instrumentorSpec String spec as defined above
153      * @param symbols SymbolMap used to resolve symbolic names
154      * to Class names.
155      * @return An instance of Instrumentor if instrumentorSpec is valid
156      * @exception JiapiException is thrown if instrumentorSpec does not meet
157      * the basic requirements of its format.
158      * @exception ClassNotFoundException is thrown, if instrumentor class
159      * was not found.
160      * @exception InstantiationException is thrown, if instantiation failes
161      * in any way. This exception also wraps all the other reflection
162      * API exception that might be thrown during instantiation.
163      */

164     public ChainInstrumentor createInstrumentor(String JavaDoc instrumentorSpec,
165                                            SymbolMap symbols) throws JiapiException, ClassNotFoundException JavaDoc, InstantiationException JavaDoc {
166         log.debug("Creating Instrumentor from spec: " + instrumentorSpec);
167
168         ChainInstrumentor instrumentor = null;
169
170         String JavaDoc instrumentorClassName = null;
171         String JavaDoc childClassName = null;
172         String JavaDoc childHints = null;
173
174         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(instrumentorSpec, "#");
175         if (!st.hasMoreTokens()) {
176             throw new JiapiException("Illegal insrumentorSpec " +
177                                      instrumentorSpec);
178         }
179
180         // (Symbolic)Class name of the Instrumentor
181
String JavaDoc instrumentorSymbol = st.nextToken().trim();
182         instrumentorClassName = symbols.getSymbol(instrumentorSymbol);
183         if (instrumentorClassName == null) {
184             instrumentorClassName = instrumentorSymbol;
185         }
186
187         if (st.hasMoreTokens()) {
188             String JavaDoc childSymbol = st.nextToken().trim();
189             childClassName = symbols.getSymbol(childSymbol);
190             if (childClassName == null) {
191                 childClassName = childSymbol;
192             }
193         }
194
195         if (st.hasMoreTokens()) {
196             childHints = st.nextToken().trim();
197         }
198
199
200         // Load relevant classes
201
Class JavaDoc instrumentorClass = null;
202         Class JavaDoc childClass = null;
203         Object JavaDoc child = null;
204
205         instrumentorClass = Class.forName(instrumentorClassName);
206         if (childClassName != null) {
207             try {
208                 childClass = Class.forName(childClassName);
209                 child = createChild(childClass, childHints);
210             }
211             catch (ClassNotFoundException JavaDoc e) {
212                 // ForwardingInstrumentor wants at least a String
213
// in constructor.
214
// Child could be a plain number !!!
215
child = childClassName; // Try String as a child
216
}
217         }
218
219         instrumentor = createInstrumentor(instrumentorClass, child);
220
221         log.info("Created instrumentor: " + instrumentor);
222         return instrumentor;
223     }
224
225
226     private Object JavaDoc createChild(Class JavaDoc child, String JavaDoc childHint) throws InstantiationException JavaDoc {
227         System.out.println("Creating child : " + child);
228         Object JavaDoc childObject = null;
229         log.debug("Creating child: " + child.getName() + ", hints " +
230                   childHint);
231
232         if (childHint == null) {
233             // Use empty constructor
234
try {
235                 childObject = child.newInstance();
236             }
237             catch (IllegalAccessException JavaDoc iae) {
238                 throw new InstantiationException JavaDoc("Illegal access: " +
239                                                  iae.getMessage());
240             }
241         }
242         else {
243             // Try to figure out how hint gets passed to child
244
// Try field:
245
Field JavaDoc hintField = null;
246             try {
247                 hintField = child.getField(childHint);
248             }
249             catch (Exception JavaDoc e) {
250                 log.debug("Exception occured: " + e.getMessage());
251             }
252
253             if (hintField != null) {
254                 log.debug("hint field: " + hintField);
255                 // We have a hint field
256
// Try a matching constructor first
257
Class JavaDoc[] parameterTypes = new Class JavaDoc[1];
258                 parameterTypes[0] = hintField.getType();
259                 try {
260                     Constructor JavaDoc c = child.getConstructor(parameterTypes);
261                     log.debug("Child constructor: " + c);
262
263                     Object JavaDoc[] params = new Object JavaDoc[1];
264                     // Assume integers here
265
params[0] = new Integer JavaDoc(hintField.getInt(null));
266                     childObject = c.newInstance(params);
267                 }
268                 catch (NoSuchMethodException JavaDoc nsme) {
269                     throw new InstantiationException JavaDoc("No such method: " +
270                                                      nsme.getMessage());
271                 }
272                 catch (IllegalAccessException JavaDoc iae) {
273                     throw new InstantiationException JavaDoc("Illegal access: " +
274                                                      iae.getMessage());
275                 }
276                 catch (InvocationTargetException JavaDoc ite) {
277                     throw new InstantiationException JavaDoc("Exception in constructor: "+
278                                                      ite.getMessage());
279                 }
280
281             }
282         }
283
284         return childObject;
285     }
286
287     private ChainInstrumentor createInstrumentor(Class JavaDoc instrumentorClass, Object JavaDoc child) throws InstantiationException JavaDoc {
288         log.debug("Creating Instrumentor: " + instrumentorClass.getName() +
289                   ", child: " + child);
290
291         ChainInstrumentor instrumentor = null;
292
293         if (child == null) {
294             // Use empty constructor
295
try {
296                 instrumentor = (ChainInstrumentor)instrumentorClass.newInstance();
297             }
298             catch (IllegalAccessException JavaDoc iae) {
299                 throw new InstantiationException JavaDoc("Illegal access: " +
300                                                  iae.getMessage());
301             }
302         }
303         else {
304 // Try primitive types in constructor.
305
// if(child instanceof java.lang.Number) {
306
// ...
307
// } else {
308

309             // Use constructor with child as argument
310
Class JavaDoc[] parameterTypes = new Class JavaDoc[1];
311             if (instrumentorClass.isAssignableFrom(child.getClass())) {
312                 parameterTypes[0] = instrumentorClass;
313             }
314             else if (strategyClass.isAssignableFrom(child.getClass())) {
315                 parameterTypes[0] = strategyClass;
316             }
317             else if (hookClass.isAssignableFrom(child.getClass())){
318                 parameterTypes[0] = hookClass;
319             }
320             else {
321                 parameterTypes[0] = child.getClass();
322             }
323
324 // System.out.println("child " + child);
325
// System.out.println(parameterTypes[0]);
326
try {
327                 Constructor JavaDoc c =
328                     instrumentorClass.getConstructor(parameterTypes);
329
330                 log.debug("Using constructor: " + c);
331
332                 Object JavaDoc [] params = new Object JavaDoc[] {child};
333                 instrumentor = (ChainInstrumentor)c.newInstance(params);
334             }
335             catch (NoSuchMethodException JavaDoc nsme) {
336                 // Instead of rethrowing, we could try JavaBean stuff...
337
throw new InstantiationException JavaDoc("No such method: " +
338                                                  nsme.getMessage());
339             }
340             catch (IllegalAccessException JavaDoc iae) {
341                 throw new InstantiationException JavaDoc("Illegal access: " +
342                                                  iae.getMessage());
343             }
344             catch (InvocationTargetException JavaDoc ite) {
345                 throw new InstantiationException JavaDoc("Exception in constructor: "+
346                                                  ite.getMessage());
347             }
348         }
349
350         return instrumentor;
351     }
352 }
353
Popular Tags