001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.config;
006:
007: import com.tc.asm.ClassVisitor;
008: import com.tc.aspectwerkz.reflect.ClassInfo;
009: import com.tc.aspectwerkz.reflect.FieldInfo;
010: import com.tc.aspectwerkz.reflect.MemberInfo;
011: import com.tc.aspectwerkz.reflect.MethodInfo;
012: import com.tc.object.bytecode.ByteCodeUtil;
013: import com.tc.object.bytecode.ClassAdapterFactory;
014: import com.tc.object.bytecode.DateMethodAdapter;
015: import com.tc.object.bytecode.DistributedMethodCallAdapter;
016: import com.tc.object.bytecode.LogicalMethodAdapter;
017: import com.tc.object.bytecode.ManagerHelper;
018: import com.tc.object.bytecode.MethodAdapter;
019: import com.tc.object.bytecode.MethodCreator;
020: import com.tc.object.config.schema.IncludeOnLoad;
021: import com.tc.object.logging.InstrumentationLogger;
022:
023: import java.lang.reflect.Modifier;
024: import java.util.Collections;
025: import java.util.HashMap;
026: import java.util.HashSet;
027: import java.util.Iterator;
028: import java.util.LinkedList;
029: import java.util.List;
030: import java.util.Map;
031: import java.util.Set;
032:
033: /**
034: * Describe the Custom adaption of a class
035: */
036: public class TransparencyClassSpecImpl implements TransparencyClassSpec {
037:
038: private static final Object HONOR_TRANSIENT_KEY = "honor-transient";
039: private static final Object HONOR_VOLATILE_KEY = "honor-volatile";
040:
041: private final DSOClientConfigHelper configuration;
042: private final String className;
043: private final List supportMethodCreators = new LinkedList();
044: private final Map methodAdapters = new HashMap();
045: private final Map flags = new HashMap();
046: private final Map codeSpecs = new HashMap();
047: private final Set nonInstrumentedMethods = Collections
048: .synchronizedSet(new HashSet());
049: private String changeApplicatorClassName;
050: private ChangeApplicatorSpec changeApplicatorSpec;
051: private boolean isLogical;
052: private final IncludeOnLoad onLoad = new IncludeOnLoad();
053: private boolean preInstrumented;
054:
055: private boolean useNonDefaultConstructor = false;
056: private boolean honorJDKSubVersionSpecific = false;
057:
058: private byte instrumentationAction = NOT_SET;
059:
060: private String postCreateMethod = null;
061: private String preCreateMethod = null;
062: private String logicalExtendingClassName = null;
063: private ClassAdapterFactory customClassAdapter = null;
064:
065: public TransparencyClassSpecImpl(String className,
066: DSOClientConfigHelper configuration,
067: String changeApplicatorClassName) {
068: this .configuration = configuration;
069: this .className = className;
070: this .changeApplicatorClassName = changeApplicatorClassName;
071: this .changeApplicatorSpec = new DSOChangeApplicatorSpec(
072: changeApplicatorClassName);
073: this .isLogical = true;
074: }
075:
076: public TransparencyClassSpecImpl(String className,
077: DSOClientConfigHelper configuration) {
078: this .className = className;
079: this .configuration = configuration;
080: this .isLogical = false;
081: this .changeApplicatorClassName = null;
082: this .changeApplicatorSpec = null;
083: this .changeApplicatorSpec = null;
084: }
085:
086: public TransparencyClassSpec getClassSpec(String clazzName) {
087: String name = clazzName.replace('/', '.');
088: return configuration.getSpec(name);
089: }
090:
091: public boolean hasPhysicallyPortableSpecs(ClassInfo classInfo) {
092: String name = classInfo.getName();
093: return configuration.shouldBeAdapted(classInfo)
094: && !configuration.isLogical(name)
095: && (configuration.getSpec(name) != null)
096: && (configuration.getSpec(name)
097: .getInstrumentationAction() != ADAPTABLE);
098: }
099:
100: public TransparencyClassSpec addRoot(String variableName,
101: String rootName) {
102: configuration.addRoot(new Root(className, variableName,
103: rootName), false);
104: return this ;
105: }
106:
107: public TransparencyClassSpec addRoot(String variableName,
108: String rootName, boolean dsoFinal) {
109: configuration.addRoot(new Root(className, variableName,
110: rootName, dsoFinal), false);
111: return this ;
112: }
113:
114: public void addDoNotInstrument(String methodName) {
115: nonInstrumentedMethods.add(methodName);
116: }
117:
118: public boolean doNotInstrument(String methodName) {
119: return nonInstrumentedMethods.contains(methodName);
120: }
121:
122: public TransparencyClassSpec markPreInstrumented() {
123: preInstrumented = true;
124: return this ;
125: }
126:
127: public boolean isPreInstrumented() {
128: return preInstrumented;
129: }
130:
131: public synchronized LockDefinition[] lockDefinitionsFor(
132: MemberInfo memberInfo) {
133: return configuration.lockDefinitionsFor(memberInfo);
134: }
135:
136: public synchronized LockDefinition autoLockDefinitionFor(
137: MethodInfo methodInfo) {
138: LockDefinition[] lds = lockDefinitionsFor(methodInfo);
139: for (int i = 0; i < lds.length; i++) {
140: if (lds[i].isAutolock()) {
141: return lds[i];
142: }
143: }
144: throw new AssertionError(
145: "Can't be an autolock and not have an autolock def:" //
146: + methodInfo.getName()
147: + methodInfo.getSignature()
148: + " className:"
149: + className);
150: }
151:
152: /**
153: * returns null if no LockDefinitions exists that makes the method autolocked.
154: */
155: public LockDefinition getAutoLockDefinition(LockDefinition lds[]) {
156: if (lds == null)
157: return null;
158: for (int i = 0; i < lds.length; i++) {
159: if (lds[i].isAutolock()) {
160: return lds[i];
161: }
162: }
163: return null;
164: }
165:
166: public LockDefinition getNonAutoLockDefinition(LockDefinition lds[]) {
167: if (lds == null)
168: return null;
169: for (int i = 0; i < lds.length; i++) {
170: if (!lds[i].isAutolock()) {
171: return lds[i];
172: }
173: }
174: return null;
175: }
176:
177: public TransparencyClassSpec addSupportMethodCreator(
178: MethodCreator creator) {
179: supportMethodCreators.add(creator);
180: return this ;
181: }
182:
183: public TransparencyClassSpec addDistributedMethodCall(
184: String methodName, String description, boolean runOnAllNodes) {
185: if ("<init>".equals(methodName)
186: || "<clinit>".equals(methodName)) {
187: throw new AssertionError(
188: "Initializers of class "
189: + className
190: + " cannot be participated in distrbuted method call and are ignored.");
191: }
192: StringBuffer sb = new StringBuffer("* ");
193: sb.append(className);
194: sb.append(".");
195: sb.append(methodName);
196: String arguments = ByteCodeUtil
197: .methodDescriptionToMethodArgument(description);
198: sb.append(arguments);
199: final DistributedMethodSpec dms = new DistributedMethodSpec(sb
200: .toString(), runOnAllNodes);
201: configuration.addDistributedMethodCall(dms);
202: return this ;
203: }
204:
205: public TransparencyClassSpec addTransient(String variableName) {
206: configuration.addTransient(className, variableName);
207: return this ;
208: }
209:
210: public TransparencyClassSpec addMethodAdapter(String method,
211: MethodAdapter adapter) {
212: methodAdapters.put(method, adapter);
213: return this ;
214: }
215:
216: public String getClassName() {
217: return className;
218: }
219:
220: public void createClassSupportMethods(ClassVisitor classVisitor) {
221: for (Iterator i = supportMethodCreators.iterator(); i.hasNext();) {
222: MethodCreator mc = (MethodCreator) i.next();
223: mc.createMethods(classVisitor);
224: }
225: }
226:
227: public boolean isLogical() {
228: return isLogical;
229: }
230:
231: public boolean isPhysical() {
232: return !isLogical;
233: }
234:
235: public boolean ignoreChecks() {
236: return TransparencyClassSpecUtil.ignoreChecks(className);
237: }
238:
239: public boolean isRootInThisClass(FieldInfo fieldInfo) {
240: return configuration.isRoot(fieldInfo);
241: }
242:
243: public boolean isRoot(FieldInfo fieldInfo) {
244: return configuration.isRoot(fieldInfo);
245: }
246:
247: public boolean isRootDSOFinal(FieldInfo fieldInfo) {
248: return configuration.isRootDSOFinal(fieldInfo);
249: }
250:
251: public boolean isTransient(int access, ClassInfo classInfo,
252: String fieldName) {
253: return configuration.isTransient(access, classInfo, fieldName);
254: }
255:
256: public boolean isVolatile(int access, ClassInfo classInfo,
257: String fieldName) {
258: return configuration.isVolatile(access, classInfo, fieldName);
259: }
260:
261: public String rootNameFor(FieldInfo fieldInfo) {
262: return configuration.rootNameFor(fieldInfo);
263: }
264:
265: public boolean isLockMethod(MemberInfo memberInfo) {
266: return configuration.isLockMethod(memberInfo);
267: }
268:
269: /**
270: * returns null if no LockDefinitions exists that makes the method locked.
271: */
272: public LockDefinition getLockMethodLockDefinition(int access,
273: LockDefinition lds[]) {
274: if (lds == null)
275: return null;
276: for (int i = 0; i < lds.length; i++) {
277: if ((lds[i].isAutolock() && Modifier.isSynchronized(access) && !Modifier
278: .isStatic(access))
279: || !lds[i].isAutolock()) {
280: return lds[i];
281: }
282: }
283: return null;
284: }
285:
286: public boolean hasCustomMethodAdapter(MemberInfo memberInfo) {
287: return memberInfo != null
288: && getMethodAdapter(memberInfo) != null;
289: }
290:
291: public MethodAdapter customMethodAdapterFor(
292: ManagerHelper managerHelper, int access, String methodName,
293: String origMethodName, String description,
294: String signature, String[] exceptions,
295: InstrumentationLogger logger, MemberInfo memberInfo) {
296: MethodAdapter ma = getMethodAdapter(memberInfo);
297: ma.initialize(managerHelper, access, className, methodName,
298: origMethodName, description, signature, exceptions,
299: logger, memberInfo);
300: return ma;
301: }
302:
303: private MethodAdapter getMethodAdapter(MemberInfo memberInfo) {
304: if (memberInfo == null) {
305: return null;
306: }
307: DistributedMethodSpec dms = configuration
308: .getDmiSpec(memberInfo);
309: if (dms != null) {
310: return new DistributedMethodCallAdapter(dms.runOnAllNodes());
311: }
312: return (MethodAdapter) methodAdapters.get(memberInfo.getName()
313: + memberInfo.getSignature());
314: }
315:
316: public ChangeApplicatorSpec getChangeApplicatorSpec() {
317: return changeApplicatorSpec;
318: }
319:
320: public String getLogicalExtendingClassName() {
321: return this .logicalExtendingClassName;
322: }
323:
324: public void moveToLogical(TransparencyClassSpec super ClassSpec) {
325: this .isLogical = true;
326: String super ClassLogicalExtendingClassName = super ClassSpec
327: .getLogicalExtendingClassName();
328: if (super ClassLogicalExtendingClassName == null) {
329: super ClassLogicalExtendingClassName = super ClassSpec
330: .getClassName();
331: }
332: this .changeApplicatorClassName = super ClassSpec
333: .getChangeApplicatorClassName();
334: this .changeApplicatorSpec = new DSOChangeApplicatorSpec(
335: super ClassSpec.getChangeApplicatorClassName());
336: this .logicalExtendingClassName = super ClassLogicalExtendingClassName;
337: }
338:
339: public void addAlwaysLogSpec(String name) {
340: methodAdapters.put(name, new LogicalMethodAdapter(name,
341: MethodSpec.ALWAYS_LOG));
342: }
343:
344: public void addIfTrueLogSpec(String name) {
345: methodAdapters.put(name, new LogicalMethodAdapter(name,
346: MethodSpec.IF_TRUE_LOG));
347: }
348:
349: public void addSetIteratorWrapperSpec(String name) {
350: methodAdapters.put(name, new LogicalMethodAdapter(name,
351: MethodSpec.SET_ITERATOR_WRAPPER_LOG));
352: }
353:
354: public void addViewSetWrapperSpec(String name) {
355: methodAdapters.put(name, new LogicalMethodAdapter(name,
356: MethodSpec.SORTED_SET_VIEW_WRAPPER_LOG));
357: }
358:
359: public void addEntrySetWrapperSpec(String name) {
360: methodAdapters.put(name, new LogicalMethodAdapter(name,
361: MethodSpec.ENTRY_SET_WRAPPER_LOG));
362: }
363:
364: public void addKeySetWrapperSpec(String name) {
365: methodAdapters.put(name, new LogicalMethodAdapter(name,
366: MethodSpec.KEY_SET_WRAPPER_LOG));
367: }
368:
369: public void addValuesWrapperSpec(String name) {
370: methodAdapters.put(name, new LogicalMethodAdapter(name,
371: MethodSpec.VALUES_WRAPPER_LOG));
372: }
373:
374: public void addHashMapPutLogSpec(String name) {
375: methodAdapters.put(name, new LogicalMethodAdapter(name,
376: MethodSpec.HASHMAP_PUT_LOG));
377: }
378:
379: public void addHashtablePutLogSpec(String name) {
380: methodAdapters.put(name, new LogicalMethodAdapter(name,
381: MethodSpec.HASHTABLE_PUT_LOG));
382: }
383:
384: public void addTHashMapPutLogSpec(String name) {
385: methodAdapters.put(name, new LogicalMethodAdapter(name,
386: MethodSpec.THASHMAP_PUT_LOG));
387: }
388:
389: public void addTHashSetAddLogSpec(String name) {
390: methodAdapters.put(name, new LogicalMethodAdapter(name,
391: MethodSpec.THASHSET_ADD_LOG));
392: }
393:
394: public void addTHashRemoveAtLogSpec(String name) {
395: methodAdapters.put(name, new LogicalMethodAdapter(name,
396: MethodSpec.THASH_REMOVE_AT_LOG));
397: }
398:
399: public void addTHashSetRemoveAtLogSpec(String name) {
400: // Do nothing it's taken care of in the add method
401: }
402:
403: public void addHashtableClearLogSpec(String name) {
404: methodAdapters.put(name, new LogicalMethodAdapter(name,
405: MethodSpec.HASHTABLE_CLEAR_LOG));
406: }
407:
408: public void addHashtableRemoveLogSpec(String name) {
409: methodAdapters.put(name, new LogicalMethodAdapter(name,
410: MethodSpec.HASHTABLE_REMOVE_LOG));
411: }
412:
413: public void addHashMapRemoveLogSpec(String name) {
414: methodAdapters.put(name, new LogicalMethodAdapter(name,
415: MethodSpec.HASHMAP_REMOVE_LOG));
416: }
417:
418: public void addArrayCopyMethodCodeSpec(String name) {
419: TransparencyCodeSpec codeSpec = new TransparencyCodeSpecImpl();
420: codeSpec.setArraycopyInstrumentationReq(true);
421: codeSpec.setArrayOperatorInstrumentationReq(true);
422: codeSpecs.put(name, codeSpec);
423: }
424:
425: public void disableWaitNotifyCodeSpec(String name) {
426: TransparencyCodeSpec codeSpec = TransparencyCodeSpecImpl
427: .getDefaultPhysicalCodeSpec();
428: codeSpec.setWaitNotifyInstrumentationReq(false);
429: codeSpecs.put(name, codeSpec);
430: }
431:
432: public void addDateMethodLogSpec(String name) {
433: methodAdapters.put(name, new DateMethodAdapter(name,
434: MethodSpec.DATE_ADD_SET_TIME_WRAPPER_LOG));
435: }
436:
437: public void addDateMethodLogSpec(String name, int methodSpec) {
438: methodAdapters.put(name,
439: new DateMethodAdapter(name, methodSpec));
440: }
441:
442: public void addMethodCodeSpec(String name,
443: TransparencyCodeSpec codeSpec) {
444: codeSpecs.put(name, codeSpec);
445: }
446:
447: public TransparencyClassSpec setHonorVolatile(boolean b) {
448: flags.put(HONOR_VOLATILE_KEY, new Boolean(b));
449: return this ;
450: }
451:
452: public boolean isHonorVolatileSet() {
453: return flags.containsKey(HONOR_VOLATILE_KEY);
454: }
455:
456: public boolean isHonorVolatile() {
457: Object flag = flags.get(HONOR_VOLATILE_KEY);
458: if (flag == null)
459: return false;
460: return ((Boolean) flag).booleanValue();
461: }
462:
463: public TransparencyClassSpec setHonorTransient(boolean b) {
464: flags.put(HONOR_TRANSIENT_KEY, new Boolean(b));
465: return this ;
466: }
467:
468: public TransparencyClassSpec setCallConstructorOnLoad(boolean b) {
469: onLoad.setToCallConstructorOnLoad(b);
470: return this ;
471: }
472:
473: public TransparencyClassSpec setExecuteScriptOnLoad(String script) {
474: onLoad.setExecuteScriptOnLoad(script);
475: return this ;
476: }
477:
478: public TransparencyClassSpec setCallMethodOnLoad(String method) {
479: onLoad.setMethodCallOnLoad(method);
480: return this ;
481: }
482:
483: private boolean basicIsHonorJavaTransient() {
484: return ((Boolean) flags.get(HONOR_TRANSIENT_KEY))
485: .booleanValue();
486: }
487:
488: public boolean isCallConstructorSet() {
489: return onLoad.isCallConstructorOnLoadType();
490: }
491:
492: public boolean isHonorJavaTransient() {
493: return basicIsHonorJavaTransient();
494: }
495:
496: public boolean isCallConstructorOnLoad() {
497: return onLoad.isCallConstructorOnLoad();
498: }
499:
500: public boolean isHonorTransientSet() {
501: return flags.containsKey(HONOR_TRANSIENT_KEY);
502: }
503:
504: public TransparencyCodeSpec getCodeSpec(String methodName,
505: String description, boolean isAutolock) {
506: Object o = codeSpecs.get(methodName + description);
507: if (o == null) {
508: return TransparencyCodeSpecImpl.getDefaultCodeSpec(
509: className, isLogical, isAutolock);
510: }
511: return (TransparencyCodeSpec) o;
512: }
513:
514: public boolean isExecuteScriptOnLoadSet() {
515: return onLoad.isExecuteScriptOnLoadType();
516: }
517:
518: public boolean isCallMethodOnLoadSet() {
519: return onLoad.isCallMethodOnLoadType();
520: }
521:
522: public String getOnLoadMethod() {
523: return onLoad.getMethod();
524: }
525:
526: public String getOnLoadExecuteScript() {
527: return onLoad.getExecuteScript();
528: }
529:
530: public boolean isUseNonDefaultConstructor() {
531: return this .useNonDefaultConstructor;
532: }
533:
534: public void setUseNonDefaultConstructor(
535: boolean useNonDefaultConstructor) {
536: this .useNonDefaultConstructor = useNonDefaultConstructor;
537: }
538:
539: public void setInstrumentationAction(byte action) {
540: this .instrumentationAction = action;
541: }
542:
543: public byte getInstrumentationAction() {
544: return this .instrumentationAction;
545: }
546:
547: public boolean isHonorJDKSubVersionSpecific() {
548: return honorJDKSubVersionSpecific;
549: }
550:
551: public void setHonorJDKSubVersionSpecific(
552: boolean honorJDKSubVersionSpecific) {
553: this .honorJDKSubVersionSpecific = honorJDKSubVersionSpecific;
554: }
555:
556: public String getPreCreateMethod() {
557: return preCreateMethod;
558: }
559:
560: public String getPostCreateMethod() {
561: return postCreateMethod;
562: }
563:
564: public void setPreCreateMethod(String preCreateMethod) {
565: this .preCreateMethod = preCreateMethod;
566: }
567:
568: public void setPostCreateMethod(String postCreateMethod) {
569: this .postCreateMethod = postCreateMethod;
570: }
571:
572: public void setCustomClassAdapter(
573: ClassAdapterFactory customClassAdapter) {
574: this .customClassAdapter = customClassAdapter;
575: }
576:
577: public ClassAdapterFactory getCustomClassAdapter() {
578: return customClassAdapter;
579: }
580:
581: public String getChangeApplicatorClassName() {
582: return this.changeApplicatorClassName;
583: }
584:
585: }
|