001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.ta.instrumentation;
022:
023: import EDU.purdue.cs.bloat.editor.ClassEditor;
024: import EDU.purdue.cs.bloat.editor.FieldEditor;
025: import EDU.purdue.cs.bloat.editor.Label;
026: import EDU.purdue.cs.bloat.editor.LocalVariable;
027: import EDU.purdue.cs.bloat.editor.MemberRef;
028: import EDU.purdue.cs.bloat.editor.MethodEditor;
029: import EDU.purdue.cs.bloat.editor.NameAndType;
030: import EDU.purdue.cs.bloat.editor.Opcode;
031: import EDU.purdue.cs.bloat.editor.Type;
032: import EDU.purdue.cs.bloat.reflect.Modifiers;
033:
034: import com.db4o.activation.Activator;
035: import com.db4o.instrumentation.core.*;
036: import com.db4o.instrumentation.util.*;
037: import com.db4o.ta.Activatable;
038:
039: public class InjectInfrastructureEdit implements BloatClassEdit {
040:
041: private final LocalVariable THIS_VAR = new LocalVariable(0);
042: private final ClassFilter _instrumentedClassesFilter;
043:
044: public InjectInfrastructureEdit(
045: ClassFilter instrumentedClassesFilter) {
046: _instrumentedClassesFilter = instrumentedClassesFilter;
047: }
048:
049: public InstrumentationStatus enhance(ClassEditor ce,
050: ClassLoader origLoader, BloatLoaderContext loaderContext) {
051: try {
052: Class clazz = BloatUtil.classForEditor(ce, origLoader);
053: if (!_instrumentedClassesFilter.accept(clazz)) {
054: return InstrumentationStatus.NOT_INSTRUMENTED;
055: }
056: String super ClassName = BloatUtil.normalizeClassName(ce
057: .super class());
058: Class super Clazz = origLoader.loadClass(super ClassName);
059: if (!(_instrumentedClassesFilter.accept(super Clazz))) {
060: ce.addInterface(Activatable.class);
061: createActivatorField(ce);
062: createBindMethod(ce);
063: createActivateMethod(ce);
064: ce.commit();
065: return InstrumentationStatus.INSTRUMENTED;
066: }
067: return InstrumentationStatus.NOT_INSTRUMENTED;
068: } catch (ClassNotFoundException exc) {
069: return InstrumentationStatus.FAILED;
070: }
071: }
072:
073: private void createActivatorField(ClassEditor ce) {
074: // private transient Activator _activator;
075: FieldEditor fieldEditor = new FieldEditor(
076: ce,
077: Modifiers.PRIVATE | Modifiers.TRANSIENT,
078: Type.getType(Activator.class),
079: TransparentActivationInstrumentationConstants.ACTIVATOR_FIELD_NAME);
080: fieldEditor.commit();
081: }
082:
083: private void createBindMethod(ClassEditor ce) {
084: // public void bind(Activator activator)
085: final Type activatorType = Type.getType(Activator.class);
086: String methodName = TransparentActivationInstrumentationConstants.BIND_METHOD_NAME;
087: Type[] paramTypes = { activatorType };
088: MethodEditor methodEditor = new MethodEditor(ce,
089: Modifiers.PUBLIC, Type.VOID, methodName, paramTypes,
090: new Type[] {});
091: LabelGenerator labelGen = new LabelGenerator();
092: Label startLabel = labelGen.createLabel(true);
093: Label setActivatorLabel = labelGen.createLabel(true);
094: LocalVariable activatorArg = new LocalVariable(1);
095:
096: methodEditor.addLabel(startLabel);
097:
098: // if (null != _activator)
099: loadActivatorFieldOnStack(methodEditor);
100: methodEditor.addInstruction(Opcode.opc_ifnull,
101: setActivatorLabel);
102:
103: // throw new IllegalStateException();
104: throwException(methodEditor, IllegalStateException.class);
105:
106: methodEditor.addLabel(setActivatorLabel);
107:
108: // _activator = activator;
109: loadThisOnStack(methodEditor);
110: methodEditor.addInstruction(Opcode.opc_aload, activatorArg);
111: methodEditor
112: .addInstruction(
113: Opcode.opc_putfield,
114: createFieldReference(
115: ce.type(),
116: TransparentActivationInstrumentationConstants.ACTIVATOR_FIELD_NAME,
117: activatorType));
118: methodEditor.addInstruction(Opcode.opc_return);
119:
120: methodEditor.commit();
121: }
122:
123: private void throwException(MethodEditor methodEditor,
124: Class exceptionType) {
125: Type illegalStateExceptionType = Type.getType(exceptionType);
126: methodEditor.addInstruction(Opcode.opc_new,
127: illegalStateExceptionType);
128: methodEditor.addInstruction(Opcode.opc_dup);
129: methodEditor
130: .addInstruction(
131: Opcode.opc_invokespecial,
132: createMethodReference(
133: illegalStateExceptionType,
134: TransparentActivationInstrumentationConstants.INIT_METHOD_NAME,
135: new Type[0], Type.VOID));
136:
137: methodEditor.addInstruction(Opcode.opcx_athrow);
138: }
139:
140: private void createActivateMethod(ClassEditor ce) {
141: // protected void activate()
142: final Type activatorType = Type.getType(Activator.class);
143: String methodName = TransparentActivationInstrumentationConstants.ACTIVATE_METHOD_NAME;
144: MethodEditor methodEditor = new MethodEditor(ce,
145: Modifiers.PUBLIC, Type.VOID, methodName, new Type[] {},
146: new Type[] {});
147: LabelGenerator labelGen = new LabelGenerator();
148: Label startLabel = labelGen.createLabel(true);
149: Label activateLabel = labelGen.createLabel(true);
150:
151: // if (_activator == null) { return; }
152: methodEditor.addLabel(startLabel);
153: loadActivatorFieldOnStack(methodEditor);
154: methodEditor
155: .addInstruction(Opcode.opc_ifnonnull, activateLabel);
156: methodEditor.addInstruction(Opcode.opc_return);
157:
158: // _activator.activate();
159: methodEditor.addLabel(activateLabel);
160: loadActivatorFieldOnStack(methodEditor);
161: methodEditor
162: .addInstruction(
163: Opcode.opc_invokeinterface,
164: createMethodReference(
165: activatorType,
166: TransparentActivationInstrumentationConstants.ACTIVATOR_ACTIVATE_METHOD_NAME,
167: new Type[] {}, Type.VOID));
168: methodEditor.addInstruction(Opcode.opc_return);
169:
170: methodEditor.commit();
171: }
172:
173: private void loadThisOnStack(MethodEditor methodEditor) {
174: methodEditor.addInstruction(Opcode.opc_aload, THIS_VAR);
175: }
176:
177: private void loadActivatorFieldOnStack(MethodEditor methodEditor) {
178: Type activatorType = Type.getType(Activator.class);
179: loadThisOnStack(methodEditor);
180: methodEditor
181: .addInstruction(
182: Opcode.opc_getfield,
183: createFieldReference(
184: methodEditor.declaringClass().type(),
185: TransparentActivationInstrumentationConstants.ACTIVATOR_FIELD_NAME,
186: activatorType));
187: }
188:
189: private MemberRef createMethodReference(Type parent, String name,
190: Type[] args, Type ret) {
191: NameAndType nameAndType = new NameAndType(name, Type.getType(
192: args, ret));
193: return new MemberRef(parent, nameAndType);
194: }
195:
196: private MemberRef createFieldReference(Type parent, String name,
197: Type type) {
198: NameAndType nameAndType = new NameAndType(name, type);
199: return new MemberRef(parent, nameAndType);
200: }
201:
202: }
|