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.transform.inlining;
9
10 import org.codehaus.aspectwerkz.definition.SystemDefinitionContainer;
11 import org.codehaus.aspectwerkz.transform.AspectWerkzPreProcessor;
12 import org.codehaus.aspectwerkz.transform.Context;
13 import org.objectweb.asm.Label;
14
15 import java.io.File;
16 import java.io.FileOutputStream;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.ArrayList;
21 import java.util.Set;
22
23 import gnu.trove.TObjectIntHashMap;
24
25 /***
26 * Implementation of the transformation context interface for the delegation weaving.
27 *
28 * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
29 * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
30 */
31 public class ContextImpl implements Context {
32 /***
33 * The name of the class.
34 */
35 private final String m_className;
36
37 /***
38 * The initial bytecode of the class
39 */
40 private final byte[] m_initialBytecode;
41
42 /***
43 * The current bytecode of the class
44 */
45 private byte[] m_currentBytecode;
46
47 /***
48 * The class loader for the class being transformed.
49 */
50 private final ClassLoader m_loader;
51
52 /***
53 * Marks the class being transformed as advised.
54 */
55 private boolean m_advised = false;
56
57 /***
58 * Marks the class being transformed as made advisable for interceptor support.
59 */
60 private boolean m_madeAdvisable = false;
61
62 /***
63 * Marks the context as read-only.
64 */
65 private boolean m_readOnly = false;
66
67 /***
68 * Meta-data for the transformation.
69 */
70 private Map m_metaData = new HashMap();
71
72 /***
73 * The contextual set of SystemDefinitions
74 */
75 private final Set m_definitions;
76
77 /***
78 * The emitted join points.
79 */
80 private final List m_emittedJoinPoints = new ArrayList();
81
82 /***
83 * A map of line number per label.
84 * Note: labels are valid in the scope of one single ASM accept() only (one phase)
85 */
86 private final TObjectIntHashMap m_labelTolineNumbers = new TObjectIntHashMap();
87
88 private long m_serialVerUid;
89 /***
90 * Creates a new context.
91 *
92 * @param loader the class loader
93 */
94 public ContextImpl(final String className, final byte[] bytecode, final ClassLoader loader) {
95 m_className = className.replace('.', '/');
96 m_loader = loader;
97 m_initialBytecode = bytecode;
98 m_currentBytecode = bytecode;
99 m_definitions = SystemDefinitionContainer.getDefinitionsFor(m_loader);
100 }
101
102 public String getClassName() {
103 return m_className;
104 }
105
106 /***
107 * Returns the initial bytecode.
108 *
109 * @return bytecode
110 */
111 public byte[] getInitialBytecode() {
112 return m_initialBytecode;
113 }
114
115 /***
116 * Returns the current bytecode.
117 *
118 * @return bytecode
119 */
120 public byte[] getCurrentBytecode() {
121 return m_currentBytecode;
122 }
123
124 /***
125 * Sets the current bytecode.
126 *
127 * @param bytecode
128 */
129 public void setCurrentBytecode(final byte[] bytecode) {
130 m_currentBytecode = bytecode;
131 }
132
133 /***
134 * Returns the class loader.
135 *
136 * @return the class loader
137 */
138 public ClassLoader getLoader() {
139 return m_loader;
140 }
141
142 /***
143 * The definitions context (with hierarchical structure)
144 *
145 * @return
146 */
147 public Set getDefinitions() {
148 return m_definitions;
149 }
150
151 /***
152 * Marks the class being transformed as advised. The marker can at most be set once per class per transformer
153 */
154 public void markAsAdvised() {
155 m_advised = true;
156 }
157
158 /***
159 * Marks the class as made advisable.
160 */
161 public void markMadeAdvisable() {
162 m_madeAdvisable = true;
163 }
164
165 /***
166 * Resets the isAdviced flag.
167 */
168 public void resetAdvised() {
169 m_advised = false;
170 }
171
172 /***
173 * Checks if the class being transformed has beed advised.
174 *
175 * @return boolean
176 */
177 public boolean isAdvised() {
178 return m_advised;
179 }
180
181 /***
182 * Checks if the class has been made advisable.
183 *
184 * @return
185 */
186 public boolean isMadeAdvisable() {
187 return m_madeAdvisable;
188 }
189
190 /***
191 * Marks the context as read-only.
192 */
193 public void markAsReadOnly() {
194 m_readOnly = true;
195 }
196
197 /***
198 * Checks if the context is read-only.
199 *
200 * @return boolean
201 */
202 public boolean isReadOnly() {
203 return m_readOnly;
204 }
205
206 /***
207 * Returns meta-data for the transformation.
208 *
209 * @param key the key
210 * @return the value
211 */
212 public Object getMetaData(final Object key) {
213 return m_metaData.get(key);
214 }
215
216 /***
217 * Adds new meta-data for the transformation.
218 *
219 * @param key the key
220 * @param value the value
221 */
222 public void addMetaData(final Object key, final Object value) {
223 if (m_readOnly) {
224 throw new IllegalStateException("context is read only");
225 }
226 m_metaData.put(key, value);
227 }
228
229 /***
230 * Dumps the class to specific directory.
231 *
232 * @param dumpDir
233 */
234 public void dump(final String dumpDir) {
235 try {
236 int lastSegmentIndex = m_className.lastIndexOf('/');
237 if (lastSegmentIndex < 0) {
238 lastSegmentIndex = 0;
239 }
240 File dir = new File(dumpDir + File.separator + m_className.substring(0, lastSegmentIndex));
241 dir.mkdirs();
242 FileOutputStream os = new FileOutputStream(
243 dumpDir
244 + File.separator
245 + m_className.replace('.', '/')
246 + ".class"
247 );
248 os.write(m_currentBytecode);
249 os.close();
250 } catch (Exception e) {
251 AspectWerkzPreProcessor.log("failed to dump " + m_className);
252 e.printStackTrace();
253 }
254 }
255
256 /***
257 * Adds a new EmittedJoinPoint
258 *
259 * @param jp
260 */
261 public void addEmittedJoinPoint(final EmittedJoinPoint jp) {
262 m_emittedJoinPoints.add(jp);
263 }
264
265 /***
266 * Returns all the EmittedJoinPoints
267 *
268 * @return
269 */
270 public List getEmittedJoinPoints() {
271 return m_emittedJoinPoints;
272 }
273
274 public void setSerialVerUid(long initialSerialVerUid) {
275 m_serialVerUid = initialSerialVerUid;
276 }
277
278 public long getSerialVerUid() {
279 return m_serialVerUid;
280 }
281
282 public void addLineNumberInfo(Label label, int lineNumber) {
283 m_labelTolineNumbers.put(label, lineNumber);
284 }
285
286 /***
287 * Tries to resolve the line number from the given label
288 *
289 * @param label
290 * @return
291 */
292 public int resolveLineNumberInfo(Label label) {
293 if (m_labelTolineNumbers.containsKey(label)) {
294 return m_labelTolineNumbers.get(label);
295 } else {
296 return 0;
297 }
298 }
299
300 }