001: /**************************************************************************************
002: * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved. *
003: * http://aspectwerkz.codehaus.org *
004: * ---------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of the LGPL license *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: **************************************************************************************/package org.codehaus.aspectwerkz.definition;
008:
009: import org.codehaus.aspectwerkz.expression.ExpressionContext;
010: import org.codehaus.aspectwerkz.expression.ExpressionInfo;
011: import org.codehaus.aspectwerkz.expression.ExpressionVisitor;
012: import org.codehaus.aspectwerkz.util.SequencedHashMap;
013: import org.codehaus.aspectwerkz.transform.AspectWerkzPreProcessor;
014: import org.codehaus.aspectwerkz.cflow.CflowBinding;
015:
016: import java.util.ArrayList;
017: import java.util.Collection;
018: import java.util.HashMap;
019: import java.util.HashSet;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Map;
023: import java.util.Set;
024:
025: /**
026: * TODO clean up - remove methods not used, refactor etc.
027: * <p/>
028: * Abstraction of the system definition, defines the aspect system.
029: *
030: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
031: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
032: */
033: public class SystemDefinition {
034:
035: /**
036: * Empty hash map.
037: */
038: public static final Map EMPTY_HASH_MAP = new HashMap();
039:
040: /**
041: * Maps the aspects to it's name.
042: */
043: private final Map m_aspectMap = new SequencedHashMap();
044:
045: /**
046: * Maps the mixins to it's name.
047: */
048: private final Map m_mixinMap = new SequencedHashMap();
049:
050: /**
051: * The UUID for this definition.
052: */
053: private String m_uuid = "default";
054:
055: /**
056: * The include packages.
057: */
058: private final Set m_includePackages = new HashSet();
059:
060: /**
061: * The exclude packages.
062: */
063: private final Set m_excludePackages = new HashSet();
064:
065: /**
066: * The prepare packages.
067: */
068: private final Set m_preparePackages = new HashSet();
069:
070: /**
071: * All prepared pointcuts defined in the system.
072: */
073: private final Map m_deploymentScopes = new HashMap();
074:
075: /**
076: * Creates a new instance, creates and sets the system cflow aspect.
077: */
078: public SystemDefinition(final String uuid) {
079: setUuid(uuid);
080: //TODO REMOVE below
081: // AspectDefinition systemAspect = new AspectDefinition(
082: // CFlowSystemAspect.class.getName(),
083: // JavaClassInfo.getClassInfo(CFlowSystemAspect.class),
084: // this
085: // );
086: // systemAspect.setDeploymentModel(CFlowSystemAspect.DEPLOYMENT_MODEL);
087: // m_aspectMap.put(CFlowSystemAspect.CLASS_NAME, systemAspect);
088: }
089:
090: /**
091: * Sets the UUID for the definition.
092: *
093: * @param uuid the UUID
094: */
095: private void setUuid(final String uuid) {
096: m_uuid = uuid;
097: }
098:
099: /**
100: * Returns the UUID for the definition.
101: *
102: * @return the UUID
103: */
104: public String getUuid() {
105: return m_uuid;
106: }
107:
108: /**
109: * Returns the include packages.
110: *
111: * @return the include packages
112: */
113: public Set getIncludePackages() {
114: return m_includePackages;
115: }
116:
117: /**
118: * Returns the exclude packages.
119: *
120: * @return the exclude packages
121: */
122: public Set getExcludePackages() {
123: return m_excludePackages;
124: }
125:
126: /**
127: * Returns a collection with the aspect definitions registered.
128: *
129: * @return the aspect definitions
130: */
131: public Collection getAspectDefinitions() {
132: Collection clone = new ArrayList(m_aspectMap.size());
133: for (Iterator it = m_aspectMap.values().iterator(); it
134: .hasNext();) {
135: clone.add(it.next());
136: }
137: return clone;
138: }
139:
140: /**
141: * Returns a collection with the mixin definitions registered.
142: *
143: * @return the mixin definitions
144: */
145: public Collection getMixinDefinitions() {
146: Collection clone = new ArrayList(m_mixinMap.size());
147: for (Iterator it = m_mixinMap.values().iterator(); it.hasNext();) {
148: clone.add(it.next());
149: }
150: return clone;
151: }
152:
153: /**
154: * Returns a collection with the advice definitions registered.
155: *
156: * @return the advice definitions
157: */
158: public Collection getAdviceDefinitions() {
159: final Collection adviceDefs = new ArrayList();
160: for (Iterator it = m_aspectMap.values().iterator(); it
161: .hasNext();) {
162: AspectDefinition aspectDef = (AspectDefinition) it.next();
163: adviceDefs.addAll(aspectDef.getAroundAdviceDefinitions());
164: adviceDefs.addAll(aspectDef.getBeforeAdviceDefinitions());
165: adviceDefs.addAll(aspectDef.getAfterAdviceDefinitions());
166: }
167: return adviceDefs;
168: }
169:
170: /**
171: * Returns a specific aspect definition.
172: *
173: * @param name the name of the aspect definition
174: * @return the aspect definition
175: */
176: public AspectDefinition getAspectDefinition(final String name) {
177: return (AspectDefinition) m_aspectMap.get(name);
178: }
179:
180: /**
181: * Returns the mixin definitions matching a specfic expression.
182: *
183: * @param ctx the expression context
184: * @return a list with the mixin definitions
185: */
186: public List getMixinDefinitions(final ExpressionContext ctx) {
187: final List introDefs = new ArrayList();
188: for (Iterator it = m_mixinMap.values().iterator(); it.hasNext();) {
189: MixinDefinition introDef = (MixinDefinition) it.next();
190: for (int i = 0; i < introDef.getExpressionInfos().length; i++) {
191: if (introDef.getExpressionInfos()[i].getExpression()
192: .match(ctx)) {
193: introDefs.add(introDef);
194: }
195: }
196: }
197: return introDefs;
198: }
199:
200: /**
201: * Returns the interface introductions for a certain class merged with the implementation based introductions as
202: * well.
203: *
204: * @param ctx the expression context
205: * @return the names
206: */
207: public List getInterfaceIntroductionDefinitions(
208: final ExpressionContext ctx) {
209: if (ctx == null) {
210: throw new IllegalArgumentException(
211: "context can not be null");
212: }
213: List interfaceIntroductionDefs = new ArrayList();
214: for (Iterator iterator = m_aspectMap.values().iterator(); iterator
215: .hasNext();) {
216: AspectDefinition aspectDef = (AspectDefinition) iterator
217: .next();
218: for (Iterator it = aspectDef
219: .getInterfaceIntroductionDefinitions().iterator(); it
220: .hasNext();) {
221: InterfaceIntroductionDefinition introDef = (InterfaceIntroductionDefinition) it
222: .next();
223: ExpressionInfo[] expressionInfos = introDef
224: .getExpressionInfos();
225: for (int i = 0; i < expressionInfos.length; i++) {
226: ExpressionInfo expressionInfo = expressionInfos[i];
227: ExpressionVisitor expression = expressionInfo
228: .getExpression();
229: if (expression.match(ctx)) {
230: interfaceIntroductionDefs.add(introDef);
231: }
232: }
233: }
234: }
235: return interfaceIntroductionDefs;
236: }
237:
238: /**
239: * Adds a new aspect definition
240: * For each of its bounded pointcut, register cflow aspects as necessary.
241: *
242: * @param aspectDef the aspect definition
243: */
244: public void addAspect(final AspectDefinition aspectDef) {
245: if (aspectDef == null) {
246: throw new IllegalArgumentException(
247: "aspect definition can not be null");
248: }
249:
250: synchronized (m_aspectMap) {
251: if (m_aspectMap.containsKey(aspectDef.getName())) {
252: return;
253: }
254:
255: // register the "cflow" aspects for this aspect bindings
256: // note: this one will even support cflow(xx && cflow())
257: // note: the cflow aspect MUST be registered FIRST for precedence purpose
258: // so that pcX && cflow(pcX) match on pcX
259: for (Iterator iterator = aspectDef.getAdviceDefinitions()
260: .iterator(); iterator.hasNext();) {
261: AdviceDefinition adviceDefinition = (AdviceDefinition) iterator
262: .next();
263: List cflowBindings = CflowBinding
264: .getCflowBindingsForCflowOf(adviceDefinition
265: .getExpressionInfo());
266: for (Iterator cflows = cflowBindings.iterator(); cflows
267: .hasNext();) {
268: CflowBinding cflowBinding = (CflowBinding) cflows
269: .next();
270: if (!cflowBinding.isCflowBelow()) {
271: addAspect(cflowBinding.getAspectDefinition(
272: this , aspectDef.getClassInfo()
273: .getClassLoader()));
274: }
275: }
276: }
277:
278: // register the aspect itself
279: m_aspectMap.put(aspectDef.getName(), aspectDef);
280:
281: // register the "cflowbelow" aspects for this aspect bindings
282: // note: this one will even support cflowbelow(xx && cflowbelow())
283: // note: the cflowbelow aspect MUST be registered LAST for precedence purpose
284: // so that pcX && cflowbelow(pcX) does not match on just the pcX joinpoint
285: for (Iterator iterator = aspectDef.getAdviceDefinitions()
286: .iterator(); iterator.hasNext();) {
287: AdviceDefinition adviceDefinition = (AdviceDefinition) iterator
288: .next();
289: List cflowBindings = CflowBinding
290: .getCflowBindingsForCflowOf(adviceDefinition
291: .getExpressionInfo());
292: for (Iterator cflows = cflowBindings.iterator(); cflows
293: .hasNext();) {
294: CflowBinding cflowBinding = (CflowBinding) cflows
295: .next();
296: if (cflowBinding.isCflowBelow()) {
297: addAspect(cflowBinding.getAspectDefinition(
298: this , aspectDef.getClassInfo()
299: .getClassLoader()));
300: }
301: }
302: }
303: }
304: }
305:
306: /**
307: * Adds a new aspect definition, overwrites the previous one with the same name (if there is one).
308: *
309: * @param aspectDef the aspect definition
310: */
311: public void addAspectOverwriteIfExists(
312: final AspectDefinition aspectDef) {
313: if (aspectDef == null) {
314: throw new IllegalArgumentException(
315: "aspect definition can not be null");
316: }
317: synchronized (m_aspectMap) {
318: m_aspectMap.put(aspectDef.getName(), aspectDef);
319: }
320: }
321:
322: /**
323: * Adds a new mixin definition.
324: *
325: * @param mixinDef the mixin definition
326: */
327: public void addMixinDefinition(final MixinDefinition mixinDef) {
328: if (mixinDef == null) {
329: throw new IllegalArgumentException(
330: "mixin definition can not be null");
331: }
332: synchronized (m_mixinMap) {
333: if (m_mixinMap.containsKey(mixinDef.getMixinImpl()
334: .getName())) {
335: MixinDefinition def = (MixinDefinition) m_mixinMap
336: .get(mixinDef.getMixinImpl().getName());
337: def.addExpressionInfos(mixinDef.getExpressionInfos());
338: return;
339: }
340: m_mixinMap.put(mixinDef.getMixinImpl().getName(), mixinDef);
341: }
342: }
343:
344: /**
345: * Adds a new include package.
346: *
347: * @param includePackage the new include package
348: */
349: public void addIncludePackage(final String includePackage) {
350: synchronized (m_includePackages) {
351: m_includePackages.add(includePackage + '.');
352: }
353: }
354:
355: /**
356: * Adds a new exclude package.
357: *
358: * @param excludePackage the new exclude package
359: */
360: public void addExcludePackage(final String excludePackage) {
361: synchronized (m_excludePackages) {
362: m_excludePackages.add(excludePackage + '.');
363: }
364: }
365:
366: /**
367: * Adds a new prepare package.
368: *
369: * @param preparePackage the new prepare package
370: */
371: public void addPreparePackage(final String preparePackage) {
372: synchronized (m_preparePackages) {
373: m_preparePackages.add(preparePackage + '.');
374: }
375: }
376:
377: /**
378: * Returns the prepare packages.
379: *
380: * @return
381: */
382: public Set getPreparePackages() {
383: return m_preparePackages;
384: }
385:
386: /**
387: * Checks if a class should be included.
388: *
389: * @param className the name or the class
390: * @return boolean
391: */
392: public boolean inIncludePackage(final String className) {
393: if (className == null) {
394: throw new IllegalArgumentException(
395: "class name can not be null");
396: }
397: if (m_includePackages.isEmpty()) {
398: return true;
399: }
400: for (Iterator it = m_includePackages.iterator(); it.hasNext();) {
401: String packageName = (String) it.next();
402: if (className.startsWith(packageName)) {
403: return true;
404: }
405: }
406: return false;
407: }
408:
409: /**
410: * Checks if a class should be excluded.
411: *
412: * @param className the name or the class
413: * @return boolean
414: */
415: public boolean inExcludePackage(final String className) {
416: if (className == null) {
417: throw new IllegalArgumentException(
418: "class name can not be null");
419: }
420: for (Iterator it = m_excludePackages.iterator(); it.hasNext();) {
421: String packageName = (String) it.next();
422: if (className.startsWith(packageName)) {
423: return true;
424: }
425: }
426: return false;
427: }
428:
429: /**
430: * Checks if a class is in prepare declaration
431: *
432: * @param className the name or the class
433: * @return boolean
434: */
435: public boolean inPreparePackage(String className) {
436: if (className == null) {
437: throw new IllegalArgumentException(
438: "class name can not be null");
439: }
440: for (Iterator it = m_preparePackages.iterator(); it.hasNext();) {
441: String packageName = (String) it.next();
442: if (className.startsWith(packageName)) {
443: return true;
444: }
445: }
446: return false;
447: }
448:
449: /**
450: * Checks if a context has a pointcut.
451: *
452: * @param ctx the expression context
453: * @return boolean
454: */
455: public boolean hasPointcut(final ExpressionContext ctx) {
456: if (ctx == null) {
457: throw new IllegalArgumentException(
458: "context can not be null");
459: }
460: for (Iterator it = m_aspectMap.values().iterator(); it
461: .hasNext();) {
462: AspectDefinition aspectDef = (AspectDefinition) it.next();
463: for (Iterator it2 = aspectDef.getAdviceDefinitions()
464: .iterator(); it2.hasNext();) {
465: AdviceDefinition adviceDef = (AdviceDefinition) it2
466: .next();
467: final ExpressionInfo expressionInfo = adviceDef
468: .getExpressionInfo();
469: if (expressionInfo == null) {
470: continue;
471: }
472: ExpressionVisitor expression = expressionInfo
473: .getExpression();
474:
475: if (expression.match(ctx)) {
476: if (AspectWerkzPreProcessor.DETAILS) {
477: System.out.println("[TRACE - match: "
478: + expression + " @ "
479: + aspectDef.getQualifiedName() + "/"
480: + adviceDef.getName());
481: System.out.println("[ for "
482: + ctx.getReflectionInfo());
483: System.out.println("[ within "
484: + ctx.getWithinReflectionInfo());
485: System.out.println("[ type "
486: + ctx.getPointcutType().toString());
487: }
488: return true;
489: }
490: }
491: }
492: return false;
493: }
494:
495: /**
496: * Checks if a class is advised.
497: *
498: * @param ctxs an array with the expression contexts
499: * @return boolean
500: */
501: public boolean isAdvised(final ExpressionContext[] ctxs) {
502: if (ctxs == null) {
503: throw new IllegalArgumentException(
504: "context array can not be null");
505: }
506: for (Iterator it = m_aspectMap.values().iterator(); it
507: .hasNext();) {
508: AspectDefinition aspectDef = (AspectDefinition) it.next();
509: List advices = aspectDef.getAdviceDefinitions();
510: for (Iterator it2 = advices.iterator(); it2.hasNext();) {
511: AdviceDefinition adviceDef = (AdviceDefinition) it2
512: .next();
513: for (int i = 0; i < ctxs.length; i++) {
514: ExpressionContext ctx = ctxs[i];
515: final ExpressionInfo expressionInfo = adviceDef
516: .getExpressionInfo();
517: if (expressionInfo == null) {
518: continue;
519: }
520: if (expressionInfo
521: .getAdvisedClassFilterExpression().match(
522: ctx)) {
523: if (AspectWerkzPreProcessor.DETAILS) {
524: System.out.println("[TRACE - earlymatch: "
525: + expressionInfo + " @ "
526: + aspectDef.getQualifiedName()
527: + "/" + adviceDef.getName());
528: System.out.println("[ for "
529: + ctx.getReflectionInfo());
530: System.out.println("[ within "
531: + ctx.getWithinReflectionInfo());
532: System.out.println("[ type "
533: + ctx.getPointcutType().toString());
534: }
535: return true;
536: }
537: }
538: }
539: }
540: return false;
541: }
542:
543: /**
544: * Checks if a class is advised.
545: *
546: * @param ctx the expression context
547: * @return boolean
548: */
549: public boolean isAdvised(final ExpressionContext ctx) {
550: if (ctx == null) {
551: throw new IllegalArgumentException(
552: "context can not be null");
553: }
554: for (Iterator it = m_aspectMap.values().iterator(); it
555: .hasNext();) {
556: AspectDefinition aspectDef = (AspectDefinition) it.next();
557: List advices = aspectDef.getAdviceDefinitions();
558: for (Iterator it2 = advices.iterator(); it2.hasNext();) {
559: AdviceDefinition adviceDef = (AdviceDefinition) it2
560: .next();
561: final ExpressionInfo expressionInfo = adviceDef
562: .getExpressionInfo();
563: if (expressionInfo == null) {
564: continue;
565: }
566: if (expressionInfo.getAdvisedClassFilterExpression()
567: .match(ctx) /*||
568: expressionInfo.getAdvisedCflowClassFilterExpression().match(ctx) ALEX XXX CFLOW*/) {
569: return true;
570: }
571: }
572: }
573: return false;
574: }
575:
576: /**
577: * Checks if a class has an mixin.
578: *
579: * @param ctxs an array with the expression contexts
580: * @return boolean
581: */
582: public boolean hasMixin(final ExpressionContext[] ctxs) {
583: if (ctxs == null) {
584: throw new IllegalArgumentException(
585: "context array can not be null");
586: }
587: for (Iterator it = m_mixinMap.values().iterator(); it.hasNext();) {
588: MixinDefinition introDef = (MixinDefinition) it.next();
589: ExpressionInfo[] expressionInfos = introDef
590: .getExpressionInfos();
591: for (int i = 0; i < expressionInfos.length; i++) {
592: ExpressionInfo expressionInfo = expressionInfos[i];
593: for (int j = 0; j < ctxs.length; j++) {
594: if (expressionInfo.getExpression().match(ctxs[j])) {
595: return true;
596: }
597: }
598: }
599: }
600: return false;
601: }
602:
603: /**
604: * Checks if a class has an mixin.
605: *
606: * @param ctx the expression context
607: * @return boolean
608: */
609: public boolean hasMixin(final ExpressionContext ctx) {
610: if (ctx == null) {
611: throw new IllegalArgumentException(
612: "context can not be null");
613: }
614: for (Iterator it = m_mixinMap.values().iterator(); it.hasNext();) {
615: MixinDefinition introDef = (MixinDefinition) it.next();
616: ExpressionInfo[] expressionInfos = introDef
617: .getExpressionInfos();
618: for (int i = 0; i < expressionInfos.length; i++) {
619: ExpressionInfo expressionInfo = expressionInfos[i];
620: if (expressionInfo.getExpression().match(ctx)) {
621: return true;
622: }
623: }
624: }
625: return false;
626: }
627:
628: /**
629: * Checks if a class is advised with an interface introduction.
630: *
631: * @param ctxs the expression contexts
632: * @return boolean
633: */
634: public boolean hasIntroducedInterface(final ExpressionContext[] ctxs) {
635: if (ctxs == null) {
636: throw new IllegalArgumentException(
637: "context array can not be null");
638: }
639: for (Iterator iterator = m_aspectMap.values().iterator(); iterator
640: .hasNext();) {
641: AspectDefinition aspectDef = (AspectDefinition) iterator
642: .next();
643: for (Iterator it = aspectDef
644: .getInterfaceIntroductionDefinitions().iterator(); it
645: .hasNext();) {
646: InterfaceIntroductionDefinition introDef = (InterfaceIntroductionDefinition) it
647: .next();
648: ExpressionInfo[] expressionInfos = introDef
649: .getExpressionInfos();
650: for (int i = 0; i < expressionInfos.length; i++) {
651: ExpressionInfo expressionInfo = expressionInfos[i];
652: for (int j = 0; j < ctxs.length; j++) {
653: if (expressionInfo.getExpression().match(
654: ctxs[i])) {
655: return true;
656: }
657: }
658: }
659: }
660: }
661: return false;
662: }
663:
664: /**
665: * Checks if a class is advised with an interface introduction.
666: *
667: * @param ctx the expression context
668: * @return boolean
669: */
670: public boolean hasIntroducedInterface(final ExpressionContext ctx) {
671: if (ctx == null) {
672: throw new IllegalArgumentException(
673: "context can not be null");
674: }
675: for (Iterator iterator = m_aspectMap.values().iterator(); iterator
676: .hasNext();) {
677: AspectDefinition aspectDefinition = (AspectDefinition) iterator
678: .next();
679: for (Iterator it = aspectDefinition
680: .getInterfaceIntroductionDefinitions().iterator(); it
681: .hasNext();) {
682: InterfaceIntroductionDefinition introDef = (InterfaceIntroductionDefinition) it
683: .next();
684: ExpressionInfo[] expressionInfos = introDef
685: .getExpressionInfos();
686: for (int i = 0; i < expressionInfos.length; i++) {
687: ExpressionInfo expressionInfo = expressionInfos[i];
688: if (expressionInfo.getExpression().match(ctx)) {
689: return true;
690: }
691: }
692: }
693: }
694: return false;
695: }
696:
697: /**
698: * Returns a collection with all deployment scopes in the system.
699: *
700: * @return a collection with all deployment scopes in the system
701: */
702: public Collection getDeploymentScopes() {
703: return m_deploymentScopes.values();
704: }
705:
706: /**
707: * Returns the deployment scope with the name specified.
708: *
709: * @param name the name of the deployment scope
710: * @return the deployment scope with the name specified
711: */
712: public DeploymentScope getDeploymentScope(final String name) {
713: return (DeploymentScope) m_deploymentScopes.get(name);
714: }
715:
716: /**
717: * Adds a deployment scope to the system.
718: *
719: * @param deploymentScope the deployment scope
720: */
721: public void addDeploymentScope(final DeploymentScope deploymentScope) {
722: m_deploymentScopes.put(deploymentScope.getName(),
723: deploymentScope);
724:
725: //TODO do we need to take care of cflow aspects
726: }
727:
728: public boolean equals(Object o) {
729: return ((SystemDefinition) o).m_uuid.equals(m_uuid);
730: }
731:
732: public int hashCode() {
733: return m_uuid.hashCode();
734: }
735:
736: /**
737: * Create a new virtual system definition for the given loader and add the virtual aspect in it.
738: *
739: * @param loader
740: * @return
741: */
742: public static SystemDefinition createVirtualDefinitionAt(
743: ClassLoader loader) {
744: SystemDefinition def = new SystemDefinition(
745: SystemDefinitionContainer
746: .getVirtualDefinitionUuid(loader));
747: DocumentParser.addVirtualAspect(def);
748: return def;
749: }
750: }
|