1 /***************************************************************************************
2 * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved. *
3 * http://aspectwerkz.codehaus.org *
4 * ---------------------------------------------------------------------------------- *
5 * The software in this package is published under the terms of the LGPL license *
6 * a copy of which has been included with this distribution in the license.txt file. *
7 **************************************************************************************/
8 package org.codehaus.aspectwerkz.aspect;
9
10 import java.util.HashMap;
11 import java.util.Map;
12 import java.util.WeakHashMap;
13
14 import org.codehaus.aspectwerkz.AspectContext;
15
16
17 /***
18 * Abstract base class for the aspect container implementations.
19 *
20 * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
21 * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
22 * @TODO: allow any type of constructor, to support ctor based dependency injection
23 */
24 public abstract class AbstractAspectContainer implements AspectContainer {
25
26 public static final int ASPECT_CONSTRUCTION_TYPE_UNKNOWN = 0;
27 public static final int ASPECT_CONSTRUCTION_TYPE_DEFAULT = 1;
28 public static final int ASPECT_CONSTRUCTION_TYPE_ASPECT_CONTEXT = 2;
29 public static final Object[] EMPTY_OBJECT_ARRAY = new Object[]{};
30
31 /***
32 * An array with the single aspect context, needed to save one array creation per invocation.
33 */
34 protected final Object[] ARRAY_WITH_SINGLE_ASPECT_CONTEXT = new Object[1];
35
36 /***
37 * The aspect construction type.
38 */
39 protected int m_constructionType = ASPECT_CONSTRUCTION_TYPE_UNKNOWN;
40
41 /***
42 * The aspect context prototype.
43 */
44 protected final AspectContext m_aspectContext;
45
46 /***
47 * Holds a reference to the sole per JVM aspect instance.
48 */
49 protected Object m_perJvm;
50
51 /***
52 * Holds references to the per class aspect instances.
53 */
54 protected final Map m_perClass = new WeakHashMap();
55
56 /***
57 * Holds references to the per instance aspect instances.
58 */
59 protected final Map m_perInstance = new WeakHashMap();
60
61 /***
62 * Holds references to the per thread aspect instances.
63 */
64 protected final Map m_perThread = new WeakHashMap();
65
66 /***
67 * Maps the advice infos to the hash codes of the the matching advice method.
68 */
69 protected final Map m_adviceInfos = new HashMap();
70
71 /***
72 * Creates a new aspect container strategy.
73 *
74 * @param aspectContext the context
75 */
76 public AbstractAspectContainer(final AspectContext aspectContext) {
77 if (aspectContext == null) {
78 throw new IllegalArgumentException("cross-cutting info can not be null");
79 }
80
81 m_aspectContext = aspectContext;
82 ARRAY_WITH_SINGLE_ASPECT_CONTEXT[0] = m_aspectContext;
83 }
84
85 /***
86 * Returns the context.
87 *
88 * @return the context
89 */
90 public AspectContext getContext() {
91 return m_aspectContext;
92 }
93
94 /***
95 * asm
96 * Creates a new perJVM cross-cutting instance, if it already exists then return it.
97 *
98 * @return the cross-cutting instance
99 */
100 public Object aspectOf() {
101 if (m_perJvm == null) {
102 m_perJvm = createAspect();
103 }
104 return m_perJvm;
105 }
106
107 /***
108 * Creates a new perClass cross-cutting instance, if it already exists then return it.
109 *
110 * @param klass
111 * @return the cross-cutting instance
112 */
113 public Object aspectOf(final Class klass) {
114 synchronized (m_perClass) {
115 if (!m_perClass.containsKey(klass)) {
116 m_perClass.put(klass, createAspect());
117 }
118 }
119 return m_perClass.get(klass);
120 }
121
122 /***
123 * Creates a new perInstance cross-cutting instance, if it already exists then return it.
124 *
125 * @param instance
126 * @return the cross-cutting instance
127 */
128 public Object aspectOf(final Object instance) {
129 synchronized (m_perInstance) {
130 if (!m_perInstance.containsKey(instance)) {
131 m_perInstance.put(instance, createAspect());
132 }
133 }
134 return m_perInstance.get(instance);
135 }
136
137 /***
138 * Creates a new perThread cross-cutting instance, if it already exists then return it.
139 *
140 * @param thread the thread for the aspect
141 * @return the cross-cutting instance
142 */
143 public Object aspectOf(final Thread thread) {
144 synchronized (m_perThread) {
145 if (!m_perThread.containsKey(thread)) {
146 m_perThread.put(thread, createAspect());
147 }
148 }
149 return m_perThread.get(thread);
150 }
151
152 /***
153 * To be implemented by the concrete aspect containers. <p/>Should return a new aspect instance.
154 *
155 * @return a new aspect instance
156 */
157 protected abstract Object createAspect();
158 }