KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > transform > inlining > deployer > Deployer


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.aspectwerkz.transform.inlining.deployer;
5
6 import java.util.Iterator JavaDoc;
7 import java.util.HashSet JavaDoc;
8 import java.util.Set JavaDoc;
9
10 import com.tc.aspectwerkz.DeploymentModel;
11 import com.tc.aspectwerkz.expression.ExpressionInfo;
12 import com.tc.aspectwerkz.annotation.AspectAnnotationParser;
13 import com.tc.aspectwerkz.definition.AdviceDefinition;
14 import com.tc.aspectwerkz.definition.AspectDefinition;
15 import com.tc.aspectwerkz.definition.DeploymentScope;
16 import com.tc.aspectwerkz.definition.DocumentParser;
17 import com.tc.aspectwerkz.definition.SystemDefinition;
18 import com.tc.aspectwerkz.definition.SystemDefinitionContainer;
19 import com.tc.aspectwerkz.joinpoint.management.AdviceInfoContainer;
20 import com.tc.aspectwerkz.joinpoint.management.JoinPointManager;
21 import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
22 import com.tc.aspectwerkz.reflect.impl.java.JavaClassInfo;
23 import com.tc.aspectwerkz.reflect.ClassInfo;
24 import com.tc.aspectwerkz.transform.inlining.AspectModelManager;
25 import com.tc.aspectwerkz.transform.inlining.compiler.CompilationInfo;
26 import com.tc.aspectwerkz.transform.inlining.compiler.CompilerHelper;
27 import com.tc.aspectwerkz.transform.inlining.compiler.MatchingJoinPointInfo;
28
29 /**
30  * Manages deployment and undeployment of aspects. Aspects can be deployed and undeployed into a running system(s).
31  * <p/>
32  * Supports annotation defined and XML defined aspects.
33  *
34  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
35  */

36 public class Deployer {
37
38   /**
39    * Deploys an annotation defined aspect.
40    * <p/>
41    * Deploys the aspect in all systems in the class loader that has loaded the aspect class.
42    * <p/>
43    * <b>CAUTION</b>: use a to own risk, the aspect might have a wider scope than your set of instrumented join points,
44    * then the aspect will not be applied to all intended points, to play safe -
45    * use <code>deploy(final Class aspect, final DeploymentScope deploymentScope)</code>
46    *
47    * @param aspect the aspect class
48    * @return a unique deployment handle for this deployment
49    */

50   public static DeploymentHandle deploy(final Class JavaDoc aspect) {
51     return deploy(aspect, DeploymentScope.MATCH_ALL);
52   }
53
54   /**
55    * Deploys an annotation defined aspect.
56    * <p/>
57    * Deploys the aspect in all systems in the class loader that has loaded the aspect class.
58    * <p/>
59    * <b>CAUTION</b>: use a to own risk, the aspect might have a wider scope than your set of instrumented join points,
60    * then the aspect will not be applied to all intended points, to play safe -
61    * use <code>deploy(final Class aspect, final DeploymentScope preparedPointcut)</code>
62    *
63    * @param aspectClassName the aspect class name
64    * @return a unique deployment handle for this deployment
65    */

66   public static DeploymentHandle deploy(final String JavaDoc aspectClassName) {
67     return deploy(aspectClassName, DeploymentScope.MATCH_ALL);
68   }
69
70   /**
71    * Deploys an annotation defined aspect.
72    * <p/>
73    * Deploys the aspect in all systems in the class loader that is specified.
74    * <p/>
75    * <b>CAUTION</b>: use a to own risk, the aspect might have a wider scope than your set of instrumented join points,
76    * then the aspect will not be applied to all intended points, to play safe -
77    * use <code>deploy(final Class aspect, final DeploymentScope preparedPointcut)</code>
78    *
79    * @param aspect the aspect class
80    * @param deployLoader
81    * @return a unique deployment handle for this deployment
82    */

83   public static DeploymentHandle deploy(final Class JavaDoc aspect, final ClassLoader JavaDoc deployLoader) {
84     return deploy(aspect, DeploymentScope.MATCH_ALL, deployLoader);
85   }
86
87   /**
88    * Deploys an annotation defined aspect.
89    * <p/>
90    * Deploys the aspect in all systems in the class loader that is specified.
91    * <p/>
92    * <b>CAUTION</b>: use a to own risk, the aspect might have a wider scope than your set of instrumented join points,
93    * then the aspect will not be applied to all intended points, to play safe -
94    * use <code>deploy(final Class aspect, final DeploymentScope preparedPointcut)</code>
95    *
96    * @param aspectClassName the aspect class name
97    * @param deployLoader
98    * @return a unique deployment handle for this deployment
99    */

100   public static DeploymentHandle deploy(final String JavaDoc aspectClassName, final ClassLoader JavaDoc deployLoader) {
101     return deploy(aspectClassName, DeploymentScope.MATCH_ALL, deployLoader);
102   }
103
104   /**
105    * Deploys an annotation defined aspect in the scope defined by the prepared pointcut.
106    * <p/>
107    * Deploys the aspect in all systems in the class loader that has loaded the aspect class.
108    *
109    * @param aspect the aspect class
110    * @param deploymentScope
111    * @return a unique deployment handle for this deployment
112    */

113   public static DeploymentHandle deploy(final Class JavaDoc aspect, final DeploymentScope deploymentScope) {
114     return deploy(aspect, deploymentScope, Thread.currentThread().getContextClassLoader());
115   }
116
117   /**
118    * Deploys an annotation defined aspect in the scope defined by the prepared pointcut.
119    * <p/>
120    * Deploys the aspect in all systems in the class loader that has loaded the aspect class.
121    *
122    * @param aspectClassName the aspect class name
123    * @param deploymentScope
124    * @return a unique deployment handle for this deployment
125    */

126   public static DeploymentHandle deploy(final String JavaDoc aspectClassName, final DeploymentScope deploymentScope) {
127     return deploy(aspectClassName, deploymentScope, Thread.currentThread().getContextClassLoader());
128   }
129
130   /**
131    * TODO allow deployment in other systems than virtual system?
132    * <p/>
133    * Deploys an annotation defined aspect in the scope defined by the prepared pointcut.
134    * <p/>
135    * Deploys the aspect in the class loader that is specified.
136    *
137    * @param aspect the aspect class
138    * @param deployLoader the loader to deploy the aspect in
139    * @param deploymentScope the prepared pointcut
140    * @return a unique deployment handle for this deployment
141    */

142   public static DeploymentHandle deploy(final Class JavaDoc aspect,
143                                         final DeploymentScope deploymentScope,
144                                         final ClassLoader JavaDoc deployLoader) {
145     if (aspect == null) {
146       throw new IllegalArgumentException JavaDoc("aspect to deploy can not be null");
147     }
148     if (deploymentScope == null) {
149       throw new IllegalArgumentException JavaDoc("prepared pointcut can not be null");
150     }
151     if (deployLoader == null) {
152       throw new IllegalArgumentException JavaDoc("class loader to deploy aspect in can not be null");
153     }
154
155     final String JavaDoc className = aspect.getName();
156     return deploy(className, deploymentScope, deployLoader);
157
158   }
159
160   /**
161    * Deploys an annotation defined aspect in the scope defined by the prepared pointcut.
162    * <p/>
163    * Deploys the aspect in the class loader that is specified.
164    *
165    * @param className
166    * @param deploymentScope
167    * @param deployLoader
168    * @return
169    */

170   public synchronized static DeploymentHandle deploy(final String JavaDoc className,
171                                                      final DeploymentScope deploymentScope,
172                                                      final ClassLoader JavaDoc deployLoader) {
173     logDeployment(className, deployLoader);
174
175     Class JavaDoc aspectClass = null;
176     try {
177       aspectClass = Class.forName(className, false, deployLoader);
178     } catch (ClassNotFoundException JavaDoc e) {
179       throw new RuntimeException JavaDoc(
180               "could not load class [" + className + "] in class loader [" + deployLoader + "]"
181       );
182     }
183
184     final DeploymentHandle deploymentHandle = new DeploymentHandle(aspectClass, deployLoader);
185
186     final ClassInfo aspectClassInfo = JavaClassInfo.getClassInfo(aspectClass);
187
188     // create a new aspect def and fill it up with the annotation def from the aspect class
189
final SystemDefinition systemDef = SystemDefinitionContainer.getVirtualDefinitionFor(deployLoader);
190     final AspectDefinition newAspectDef = new AspectDefinition(className, aspectClassInfo, systemDef);
191     final Set JavaDoc newExpressions = getNewExpressionsForAspect(
192             aspectClass, newAspectDef, systemDef, deploymentScope, deploymentHandle
193     );
194
195     redefine(newExpressions);
196     return deploymentHandle;
197   }
198
199   /**
200    * Deploys an XML defined aspect in the scope defined by the prepared pointcut.
201    * <p/>
202    * If the aspect class has annotations, those will be read but the XML definition will override the
203    * annotation definition.
204    * <p/>
205    * Deploys the aspect in the class loader that has loaded the aspect.
206    *
207    * @param aspect the aspect class
208    * @param xmlDef
209    * @return
210    */

211   public static DeploymentHandle deploy(final Class JavaDoc aspect, final String JavaDoc xmlDef) {
212     return deploy(aspect, xmlDef, DeploymentScope.MATCH_ALL);
213   }
214
215   /**
216    * Deploys an XML defined aspect in the scope defined by the prepared pointcut.
217    * <p/>
218    * If the aspect class has annotations, those will be read but the XML definition will override the
219    * annotation definition.
220    * <p/>
221    * Deploys the aspect in the class loader that has loaded the aspect.
222    *
223    * @param aspect the aspect class
224    * @param xmlDef
225    * @param deploymentScope
226    * @return
227    */

228   public static DeploymentHandle deploy(final Class JavaDoc aspect,
229                                         final String JavaDoc xmlDef,
230                                         final DeploymentScope deploymentScope) {
231     return deploy(aspect, xmlDef, deploymentScope, aspect.getClassLoader());
232   }
233
234   /**
235    * Deploys an XML defined aspect in the scope defined by the prepared pointcut.
236    * <p/>
237    * If the aspect class has annotations, those will be read but the XML definition will override the
238    * annotation definition.
239    * <p/>
240    * Deploys the aspect in the class loader that is specified.
241    *
242    * @param aspect the aspect class
243    * @param xmlDef
244    * @param deployLoader
245    * @return
246    */

247   public static DeploymentHandle deploy(final Class JavaDoc aspect, final String JavaDoc xmlDef, final ClassLoader JavaDoc deployLoader) {
248     return deploy(aspect, xmlDef, DeploymentScope.MATCH_ALL, deployLoader);
249   }
250
251   /**
252    * TODO allow deployment in other systems than virtual system?
253    * <p/>
254    * Deploys an XML defined aspect in the scope defined by the prepared pointcut.
255    * <p/>
256    * If the aspect class has annotations, those will be read but the XML definition will override the
257    * annotation definition.
258    * <p/>
259    * Deploys the aspect in the class loader that is specified.
260    *
261    * @param aspect the aspect class
262    * @param deploymentScope
263    * @param xmlDef
264    * @param deployLoader
265    * @return
266    */

267   public synchronized static DeploymentHandle deploy(final Class JavaDoc aspect,
268                                                      final String JavaDoc xmlDef,
269                                                      final DeploymentScope deploymentScope,
270                                                      final ClassLoader JavaDoc deployLoader) {
271     if (aspect == null) {
272       throw new IllegalArgumentException JavaDoc("aspect to deploy can not be null");
273     }
274     if (deploymentScope == null) {
275       throw new IllegalArgumentException JavaDoc("prepared pointcut can not be null");
276     }
277     if (xmlDef == null) {
278       throw new IllegalArgumentException JavaDoc("xml definition can not be null");
279     }
280     if (deployLoader == null) {
281       throw new IllegalArgumentException JavaDoc("class loader to deploy aspect in can not be null");
282     }
283     final String JavaDoc className = aspect.getName();
284     logDeployment(className, deployLoader);
285
286     final DeploymentHandle deploymentHandle = new DeploymentHandle(aspect, deployLoader);
287
288     final SystemDefinition systemDef = SystemDefinitionContainer.getVirtualDefinitionFor(deployLoader);
289
290     final AspectDefinition newAspectDef = DocumentParser.parseAspectDefinition(xmlDef, systemDef, aspect);
291     systemDef.addAspect(newAspectDef);
292     final Set JavaDoc newExpressions = getNewExpressionsForAspect(aspect, newAspectDef, systemDef, deploymentScope,
293                                                           deploymentHandle);
294     redefine(newExpressions);
295     return deploymentHandle;
296   }
297
298   /**
299    * Undeploys an aspect from the same loader that has loaded the class.
300    *
301    * @param aspect the aspect class
302    */

303   public static void undeploy(final Class JavaDoc aspect) {
304     undeploy(aspect, aspect.getClassLoader());
305   }
306
307   /**
308    * Undeploys an aspect from a specific class loader.
309    *
310    * @param aspect the aspect class
311    * @param loader the loader that you want to undeploy the aspect from
312    */

313   public static void undeploy(final Class JavaDoc aspect, final ClassLoader JavaDoc loader) {
314     if (aspect == null) {
315       throw new IllegalArgumentException JavaDoc("aspect to undeploy can not be null");
316     }
317     if (loader == null) {
318       throw new IllegalArgumentException JavaDoc("loader to undeploy aspect from can not be null");
319     }
320     undeploy(aspect.getName(), loader);
321   }
322
323   /**
324    * Undeploys an aspect from a specific class loader.
325    *
326    * @param className the aspect class name
327    * @param loader the loader that you want to undeploy the aspect from
328    */

329   public static void undeploy(final String JavaDoc className, final ClassLoader JavaDoc loader) {
330     logUndeployment(className, loader);
331
332     //TODO: this one should acquire lock or something
333

334     // lookup only in the given classloader scope
335
// since the system hierarchy holds reference, they will see the change
336
Set JavaDoc systemDefs = SystemDefinitionContainer.getAllDefinitionsFor(loader);
337
338     for (Iterator JavaDoc it = systemDefs.iterator(); it.hasNext();) {
339       SystemDefinition systemDef = (SystemDefinition) it.next();
340       final AspectDefinition aspectDef = systemDef.getAspectDefinition(className);
341       if (aspectDef != null) {
342
343         final Set JavaDoc newExpressions = new HashSet JavaDoc();
344         for (Iterator JavaDoc it2 = aspectDef.getAdviceDefinitions().iterator(); it2.hasNext();) {
345           AdviceDefinition adviceDef = (AdviceDefinition) it2.next();
346           ExpressionInfo oldExpression = adviceDef.getExpressionInfo();
347           if (oldExpression == null) { // if null, then already undeployed
348
continue;
349           }
350           adviceDef.setExpressionInfo(null);
351           newExpressions.add(oldExpression);
352         }
353         redefine(newExpressions);
354       }
355     }
356   }
357
358   /**
359    * Undeploys an aspect in the same way that it has been deployed in in the previous deploy event
360    * defined by the deployment handle.
361    *
362    * @param deploymentHandle the handle to the previous deployment event
363    */

364   public static void undeploy(final DeploymentHandle deploymentHandle) {
365     if (deploymentHandle == null) {
366       throw new IllegalArgumentException JavaDoc("deployment handle can not be null");
367     }
368
369     deploymentHandle.revertChanges();
370
371     final Class JavaDoc aspectClass = deploymentHandle.getAspectClass();
372     if (aspectClass == null) {
373       return; // already undeployed
374
}
375     undeploy(aspectClass);
376   }
377
378   /**
379    * Redefines all join points that are affected by the system redefinition.
380    *
381    * @param expressions the expressions that will pick out the join points that are affected
382    */

383   private static void redefine(final Set JavaDoc expressions) {
384     final Set JavaDoc allMatchingJoinPoints = new HashSet JavaDoc();
385     for (Iterator JavaDoc itExpr = expressions.iterator(); itExpr.hasNext();) {
386       ExpressionInfo expression = (ExpressionInfo) itExpr.next();
387       Set JavaDoc matchingJoinPoints = CompilerHelper.getJoinPointsMatching(expression);
388       allMatchingJoinPoints.addAll(matchingJoinPoints);
389     }
390
391     final ChangeSet changeSet = new ChangeSet();
392     for (Iterator JavaDoc it = allMatchingJoinPoints.iterator(); it.hasNext();) {
393       final MatchingJoinPointInfo joinPointInfo = (MatchingJoinPointInfo) it.next();
394
395       final CompilationInfo compilationInfo = joinPointInfo.getCompilationInfo();
396       compilationInfo.incrementRedefinitionCounter();
397
398       changeSet.addElement(new ChangeSet.Element(compilationInfo, joinPointInfo));
399     }
400
401     doRedefine(changeSet);
402   }
403
404   /**
405    * Do the redefinition of the existing join point and the compilation of the new join point.
406    *
407    * @param changeSet
408    */

409   private static void doRedefine(final ChangeSet changeSet) {
410     for (Iterator JavaDoc it = changeSet.getElements().iterator(); it.hasNext();) {
411       compileNewJoinPoint((ChangeSet.Element) it.next());
412     }
413     redefineInitialJoinPoints(changeSet);
414   }
415
416   /**
417    * Compiles a completely new join point instance based on the new redefined model.
418    *
419    * @param changeSetElement the change set item
420    */

421   private static void compileNewJoinPoint(final ChangeSet.Element changeSetElement) {
422     final CompilationInfo compilationInfo = changeSetElement.getCompilationInfo();
423     final MatchingJoinPointInfo joinPointInfo = changeSetElement.getJoinPointInfo();
424     final ClassLoader JavaDoc loader = joinPointInfo.getJoinPointClass().getClassLoader();
425     final AdviceInfoContainer newAdviceContainer = JoinPointManager.getAdviceInfoContainerForJoinPoint(
426             joinPointInfo.getExpressionContext(), loader, null
427     );
428     final CompilationInfo.Model redefinedModel = new CompilationInfo.Model(
429             compilationInfo.getInitialModel().getEmittedJoinPoint(), // copy the reference since it is the same
430
newAdviceContainer,
431             compilationInfo.getRedefinitionCounter(),
432             compilationInfo.getInitialModel().getThisClassInfo()
433     );
434     CompilerHelper.compileJoinPointAndAttachToClassLoader(redefinedModel, loader);
435
436     compilationInfo.setRedefinedModel(redefinedModel);
437     CompilerHelper.addCompilationInfo(joinPointInfo.getJoinPointClass(), compilationInfo);
438   }
439
440   /**
441    * Redefines the intial (weaved in) join point to delegate to the newly compiled "real" join point which is
442    * based on the new redefined model.
443    *
444    * @param changeSet the change set
445    */

446   private static void redefineInitialJoinPoints(final ChangeSet changeSet) {
447     // TODO type should be pluggable
448
RedefinerFactory.newRedefiner(RedefinerFactory.Type.HOTSWAP).redefine(changeSet);
449   }
450
451   /**
452    * Returns a set with the new expressions for the advice in the aspect to deploy.
453    *
454    * @param aspectClass
455    * @param newAspectDef
456    * @param systemDef
457    * @param deploymentScope
458    * @param deploymentHandle
459    * @return a set with the new expressions
460    */

461   private static Set JavaDoc getNewExpressionsForAspect(final Class JavaDoc aspectClass,
462                                                 final AspectDefinition newAspectDef,
463                                                 final SystemDefinition systemDef,
464                                                 final DeploymentScope deploymentScope,
465                                                 final DeploymentHandle deploymentHandle) {
466     final ClassLoader JavaDoc aspectLoader = aspectClass.getClassLoader();
467     final String JavaDoc aspectName = aspectClass.getName();
468
469     // keep XML settings so that they don't get changed when we read the annotations
470
String JavaDoc keptContainerClassName = newAspectDef.getContainerClassName();
471     DeploymentModel keptModel = newAspectDef.getDeploymentModel();
472
473     final ClassInfo classInfo = AsmClassInfo.getClassInfo(aspectName, aspectLoader);
474     AspectModelManager.defineAspect(classInfo, newAspectDef, aspectLoader);
475     AspectAnnotationParser.parse(classInfo, newAspectDef, aspectLoader);
476
477     AspectDefinition aspectDef = systemDef.getAspectDefinition(aspectName);
478     if (aspectDef != null) {
479       // if in def already reuse some of the settings that can have been overridded by XML def
480
//AW-461
481
newAspectDef.setContainerClassName(keptContainerClassName);//aspectDef.getContainerClassName());
482
newAspectDef.setDeploymentModel(keptModel);//aspectDef.getDeploymentModel());
483
}
484
485     systemDef.addAspectOverwriteIfExists(newAspectDef);
486
487     final Set JavaDoc newExpressions = new HashSet JavaDoc();
488     for (Iterator JavaDoc it2 = newAspectDef.getAdviceDefinitions().iterator(); it2.hasNext();) {
489       AdviceDefinition adviceDef = (AdviceDefinition) it2.next();
490       ExpressionInfo oldExpression = adviceDef.getExpressionInfo();
491       if (oldExpression == null) {
492         continue;
493       }
494       deploymentHandle.registerDefinitionChange(adviceDef, oldExpression);
495
496       final ExpressionInfo newExpression = deploymentScope.newExpressionInfo(oldExpression);
497       adviceDef.setExpressionInfo(newExpression);
498       newExpressions.add(newExpression);
499     }
500     return newExpressions;
501   }
502
503   /**
504    * Imports a class from one class loader to another one.
505    *
506    * @param clazz the class to import
507    * @param toLoader the loader to import to
508    */

509 // private static void importClassIntoLoader(final Class clazz, final ClassLoader toLoader) {
510
// final ClassLoader fromLoader = clazz.getClassLoader();
511
// if (toLoader == fromLoader) {
512
// return;
513
// }
514
// final String className = clazz.getName();
515
// try {
516
// Class.forName(className, false, toLoader);
517
// } catch (ClassNotFoundException cnfe) {
518
// try {
519
// InputStream stream = null;
520
// byte[] bytes;
521
// try {
522
// stream = fromLoader.getResourceAsStream(className.replace('.', '/') + ".class");
523
// bytes = new ClassReader(stream).b;
524
// } finally {
525
// try {
526
// stream.close();
527
// } catch (Exception e) {
528
// // ignore
529
// }
530
// }
531
// Class klass = Class.forName("java.lang.ClassLoader", false, toLoader);
532
// Method method = klass.getDeclaredMethod(
533
// "defineClass",
534
// new Class[]{String.class, byte[].class, int.class, int.class}
535
// );
536
// method.setAccessible(true);
537
// Object[] args = new Object[]{
538
// clazz.getName(), bytes, new Integer(0), new Integer(bytes.length)
539
// };
540
// method.invoke(toLoader, args);
541
// method.setAccessible(false);
542
// } catch (Exception e) {
543
// throw new RuntimeException(
544
// new StringBuffer().append("could not deploy aspect [").
545
// append(className).append("] in class loader [").append(toLoader)
546
// .append(']').toString()
547
// );
548
// }
549
// }
550
// }
551

552   /**
553    * Logs undeployment.
554    * <p/>
555    * TODO unified way or at least format for logging
556    *
557    * @param className
558    * @param loader
559    */

560   private static void logUndeployment(final String JavaDoc className, final ClassLoader JavaDoc loader) {
561     System.out.println(
562             new StringBuffer JavaDoc().append("Deployer::INFO - undeploying aspect [").
563                     append(className).append("] from class loader [").
564                     append(loader).append(']').toString()
565     );
566   }
567
568   /**
569    * Logs deployment.
570    * <p/>
571    * TODO unified way or at least format for logging
572    *
573    * @param className
574    * @param loader
575    */

576   private static void logDeployment(final String JavaDoc className, final ClassLoader JavaDoc loader) {
577     System.out.println(
578             new StringBuffer JavaDoc().append("Deployer::INFO - deploying aspect [").
579                     append(className).append("] in class loader [").
580                     append(loader).append(']').toString()
581     );
582   }
583 }
584
Popular Tags