001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.transform;
005:
006: import com.tc.asm.Label;
007:
008: import com.tc.aspectwerkz.definition.SystemDefinitionContainer;
009: import com.tc.aspectwerkz.proxy.ProxyDelegationStrategy;
010: import com.tc.aspectwerkz.proxy.ProxySubclassingStrategy;
011: import com.tc.aspectwerkz.transform.inlining.EmittedJoinPoint;
012:
013: import java.io.File;
014: import java.io.FileOutputStream;
015: import java.util.HashMap;
016: import java.util.List;
017: import java.util.Map;
018: import java.util.ArrayList;
019: import java.util.Set;
020:
021: /**
022: * Implementation of the transformation context interface for the delegation weaving.
023: *
024: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
025: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
026: */
027: public class InstrumentationContext {
028: /**
029: * The name of the class.
030: */
031: private final String m_className;
032:
033: /**
034: * The initial bytecode of the class
035: */
036: private final byte[] m_initialBytecode;
037:
038: /**
039: * The current bytecode of the class
040: */
041: private byte[] m_currentBytecode;
042:
043: /**
044: * The class loader for the class being transformed.
045: */
046: private final ClassLoader m_loader;
047:
048: /**
049: * Marks the class being transformed as advised.
050: */
051: private boolean m_advised = false;
052:
053: /**
054: * Marks the class being transformed as made advisable for interceptor support.
055: */
056: private boolean m_madeAdvisable = false;
057:
058: /**
059: * Is the class being transformed a proxy or not?
060: */
061: private boolean m_isProxy = false;
062:
063: /**
064: * Marks the context as read-only.
065: */
066: private boolean m_readOnly = false;
067:
068: /**
069: * Meta-data for the transformation.
070: */
071: private Map m_metaData = new HashMap();
072:
073: /**
074: * The contextual set of SystemDefinitions
075: */
076: private final Set m_definitions;
077:
078: /**
079: * The emitted join points.
080: */
081: private final List m_emittedJoinPoints = new ArrayList();
082:
083: /**
084: * A map of line number per label.
085: * Note: labels are valid in the scope of one single ASM accept() only (one phase)
086: */
087: private final HashMap m_labelTolineNumbers = new HashMap();
088:
089: private long m_serialVerUid;
090:
091: /**
092: * Creates a new context.
093: */
094: public InstrumentationContext(final String className,
095: final byte[] bytecode, final ClassLoader loader,
096: final Set definitions) {
097: m_className = className.replace('.', '/');
098: m_loader = loader;
099: m_initialBytecode = bytecode;
100: m_currentBytecode = bytecode;
101: m_definitions = definitions;
102: if (isAWProxy(className) || isCGLIBProxy(className)
103: || isDynamicProxy(className)) {
104: markAsProxy();
105: }
106: }
107:
108: /**
109: * Creates a new context.
110: */
111: public InstrumentationContext(final String className,
112: final byte[] bytecode, final ClassLoader loader) {
113: this (className, bytecode, loader, SystemDefinitionContainer
114: .getDefinitionsFor(loader));
115: }
116:
117: public String getClassName() {
118: return m_className;
119: }
120:
121: /**
122: * Returns the initial bytecode.
123: *
124: * @return bytecode
125: */
126: public byte[] getInitialBytecode() {
127: return m_initialBytecode;
128: }
129:
130: /**
131: * Returns the current bytecode.
132: *
133: * @return bytecode
134: */
135: public byte[] getCurrentBytecode() {
136: return m_currentBytecode;
137: }
138:
139: /**
140: * Sets the current bytecode.
141: *
142: * @param bytecode
143: */
144: public void setCurrentBytecode(final byte[] bytecode) {
145: m_currentBytecode = bytecode;
146: }
147:
148: /**
149: * Returns the class loader.
150: *
151: * @return the class loader
152: */
153: public ClassLoader getLoader() {
154: return m_loader;
155: }
156:
157: /**
158: * The definitions context (with hierarchical structure)
159: *
160: * @return
161: */
162: public Set getDefinitions() {
163: return m_definitions;
164: }
165:
166: /**
167: * Marks the class being transformed as advised. The marker can at most be set once per class per transformer
168: */
169: public void markAsAdvised() {
170: m_advised = true;
171: }
172:
173: /**
174: * Marks the class as made advisable.
175: */
176: public void markMadeAdvisable() {
177: m_madeAdvisable = true;
178: }
179:
180: /**
181: * Resets the isAdviced flag.
182: */
183: public void resetAdvised() {
184: m_advised = false;
185: }
186:
187: /**
188: * Is the class being transformed a proxy or not?
189: */
190: public boolean isProxy() {
191: return m_isProxy;
192: }
193:
194: /**
195: * Marks the class being transformed as a proxy.
196: */
197: public void markAsProxy() {
198: m_isProxy = true;
199: }
200:
201: /**
202: * Checks if the class being transformed has beed advised.
203: *
204: * @return boolean
205: */
206: public boolean isAdvised() {
207: return m_advised;
208: }
209:
210: /**
211: * Checks if the class has been made advisable.
212: *
213: * @return
214: */
215: public boolean isMadeAdvisable() {
216: return m_madeAdvisable;
217: }
218:
219: /**
220: * Marks the context as read-only.
221: */
222: public void markAsReadOnly() {
223: m_readOnly = true;
224: }
225:
226: /**
227: * Checks if the context is read-only.
228: *
229: * @return boolean
230: */
231: public boolean isReadOnly() {
232: return m_readOnly;
233: }
234:
235: /**
236: * Returns meta-data for the transformation.
237: *
238: * @param key the key
239: * @return the value
240: */
241: public Object getMetaData(final Object key) {
242: return m_metaData.get(key);
243: }
244:
245: /**
246: * Adds new meta-data for the transformation.
247: *
248: * @param key the key
249: * @param value the value
250: */
251: public void addMetaData(final Object key, final Object value) {
252: if (m_readOnly) {
253: throw new IllegalStateException("context is read only");
254: }
255: m_metaData.put(key, value);
256: }
257:
258: /**
259: * Dumps the class to specific directory.
260: *
261: * @param dumpDir
262: */
263: public void dump(final String dumpDir) {
264: try {
265: int lastSegmentIndex = m_className.lastIndexOf('/');
266: if (lastSegmentIndex < 0) {
267: lastSegmentIndex = 0;
268: }
269: File dir = new File(dumpDir + File.separator
270: + m_className.substring(0, lastSegmentIndex));
271: dir.mkdirs();
272: FileOutputStream os = new FileOutputStream(dumpDir
273: + File.separator + m_className.replace('.', '/')
274: + ".class");
275: os.write(m_currentBytecode);
276: os.close();
277: } catch (Exception e) {
278: System.err.println("failed to dump " + m_className);
279: e.printStackTrace();
280: }
281: }
282:
283: /**
284: * Adds a new EmittedJoinPoint
285: *
286: * @param jp
287: */
288: public void addEmittedJoinPoint(final EmittedJoinPoint jp) {
289: m_emittedJoinPoints.add(jp);
290: }
291:
292: /**
293: * Returns all the EmittedJoinPoints
294: *
295: * @return
296: */
297: public List getEmittedJoinPoints() {
298: return m_emittedJoinPoints;
299: }
300:
301: public void setSerialVerUid(long initialSerialVerUid) {
302: m_serialVerUid = initialSerialVerUid;
303: }
304:
305: public long getSerialVerUid() {
306: return m_serialVerUid;
307: }
308:
309: public void addLineNumberInfo(Label label, int lineNumber) {
310: m_labelTolineNumbers.put(label, new Integer(lineNumber));
311: }
312:
313: /**
314: * Tries to resolve the line number from the given label
315: *
316: * @param label
317: * @return
318: */
319: public int resolveLineNumberInfo(Label label) {
320: Integer info = (Integer) m_labelTolineNumbers.get(label);
321: return info == null ? 0 : info.intValue();
322: }
323:
324: public static boolean isAWProxy(final String className) {
325: return className.indexOf(ProxySubclassingStrategy.PROXY_SUFFIX) != -1
326: || className
327: .indexOf(ProxyDelegationStrategy.PROXY_SUFFIX) != -1;
328: }
329:
330: public static boolean isCGLIBProxy(final String className) {
331: return className.indexOf("$$EnhancerByCGLIB$$") != -1
332: || className.indexOf("$$FastClassByCGLIB$$") != -1;
333: }
334:
335: private boolean isDynamicProxy(final String className) {
336: return className.startsWith("$Proxy");
337: }
338: }
|