001: package org.uispec4j.extension;
002:
003: import org.objectweb.asm.*;
004:
005: class PanelClassEnhancer extends ClassAdapter implements Constants {
006: private Extension[] extensions;
007:
008: public static byte[] transformClass(ClassReader reader,
009: Extension[] extensions) {
010: ClassWriter writer = new ClassWriter(true, true);
011: PanelClassEnhancer transformer = new PanelClassEnhancer(writer,
012: extensions);
013: reader.accept(transformer, false);
014: return writer.toByteArray();
015: }
016:
017: private PanelClassEnhancer(ClassVisitor cv, Extension[] extensions) {
018: super (cv);
019: this .extensions = extensions;
020: }
021:
022: public CodeVisitor visitMethod(int access, String name,
023: String desc, String[] exceptions, Attribute attrs) {
024:
025: CodeVisitor cd = cv.visitMethod(access, name, desc, exceptions,
026: attrs);
027: if (cd == null) {
028: return null;
029: }
030: if ("<clinit>".equals(name)
031: && ((access & Constants.ACC_STATIC) != 0)) {
032: return new StaticInitEnhancer(cd);
033: }
034: return cd;
035: }
036:
037: private class StaticInitEnhancer extends CodeAdapter {
038: public StaticInitEnhancer(CodeVisitor cd) {
039: super (cd);
040: }
041:
042: public void visitInsn(int opcode) {
043: if (opcode == RETURN) {
044: for (int i = 0; i < extensions.length; i++) {
045: Extension extension = extensions[i];
046: String componentClassName = extension
047: .getComponentClassName();
048: String transformedComponentClassName = transformClassName(componentClassName);
049: addStaticInitializerForExtension(
050: transformedComponentClassName,
051: componentClassName);
052: }
053: }
054: cv.visitInsn(opcode);
055: }
056:
057: private void addStaticInitializerForExtension(
058: String transformedComponentClassName,
059: String componentClassName) {
060: cv.visitFieldInsn(GETSTATIC, "org/uispec4j/Panel",
061: transformedComponentClassName, "Ljava/lang/Class;");
062: Label l12 = new Label();
063: cv.visitJumpInsn(IFNONNULL, l12);
064: cv.visitLdcInsn(componentClassName);
065: cv.visitMethodInsn(INVOKESTATIC, "org/uispec4j/Panel",
066: "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
067: cv.visitInsn(DUP);
068: cv.visitFieldInsn(PUTSTATIC, "org/uispec4j/Panel",
069: transformedComponentClassName, "Ljava/lang/Class;");
070: Label l13 = new Label();
071: cv.visitJumpInsn(GOTO, l13);
072: cv.visitLabel(l12);
073: cv.visitFieldInsn(GETSTATIC, "org/uispec4j/Panel",
074: transformedComponentClassName, "Ljava/lang/Class;");
075: cv.visitLabel(l13);
076: cv.visitMethodInsn(INVOKESTATIC,
077: "org/uispec4j/utils/UIComponentFactory",
078: "addUIComponentClass", "(Ljava/lang/Class;)V");
079: }
080: }
081:
082: public void visitEnd() {
083: for (int i = 0; i < extensions.length; i++) {
084: Extension extension = extensions[i];
085: addExtension(extension.getComponentName(), extension
086: .getComponentClassName());
087: }
088: cv.visitEnd();
089: }
090:
091: private void addExtension(String componentName,
092: String componentClassName) {
093: String methodName = "get" + componentName;
094: String transformedComponentClassName = transformClassName(componentClassName);
095: String slashedComponentClassName = componentClassName.replace(
096: '.', '/');
097:
098: cv.visitField(ACC_STATIC + ACC_SYNTHETIC,
099: transformedComponentClassName, "Ljava/lang/Class;",
100: null, null);
101:
102: {
103: CodeVisitor v = cv
104: .visitMethod(
105: ACC_PUBLIC,
106: methodName,
107: "(Ljava/lang/String;)L"
108: + slashedComponentClassName + ";",
109: new String[] {
110: "org/uispec4j/ItemNotFoundException",
111: "org/uispec4j/ComponentAmbiguityException" },
112: null);
113: Label l0 = new Label();
114: v.visitLabel(l0);
115: v.visitVarInsn(ALOAD, 0);
116: v.visitFieldInsn(GETFIELD, "org/uispec4j/Panel", "finder",
117: "Lorg/uispec4j/finder/ComponentFinder;");
118: v.visitFieldInsn(GETSTATIC, "org/uispec4j/Panel",
119: transformedComponentClassName, "Ljava/lang/Class;");
120: Label l1 = new Label();
121: v.visitJumpInsn(IFNONNULL, l1);
122: v.visitLdcInsn(componentClassName);
123: v.visitMethodInsn(INVOKESTATIC, "org/uispec4j/Panel",
124: "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
125: v.visitInsn(DUP);
126: v.visitFieldInsn(PUTSTATIC, "org/uispec4j/Panel",
127: transformedComponentClassName, "Ljava/lang/Class;");
128: Label l2 = new Label();
129: v.visitJumpInsn(GOTO, l2);
130: v.visitLabel(l1);
131: v.visitFieldInsn(GETSTATIC, "org/uispec4j/Panel",
132: transformedComponentClassName, "Ljava/lang/Class;");
133: v.visitLabel(l2);
134: v.visitVarInsn(ALOAD, 1);
135: v
136: .visitMethodInsn(
137: INVOKESTATIC,
138: "org/uispec4j/Panel",
139: "getComponent",
140: "(Lorg/uispec4j/finder/ComponentFinder;Ljava/lang/Class;Ljava/lang/String;)Lorg/uispec4j/UIComponent;");
141: v.visitTypeInsn(CHECKCAST, slashedComponentClassName);
142: v.visitInsn(ARETURN);
143: v.visitMaxs(3, 2);
144: }
145: {
146: CodeVisitor v = cv
147: .visitMethod(
148: ACC_PUBLIC,
149: methodName,
150: "()L" + slashedComponentClassName + ";",
151: new String[] {
152: "org/uispec4j/ItemNotFoundException",
153: "org/uispec4j/ComponentAmbiguityException" },
154: null);
155: Label l0 = new Label();
156: v.visitLabel(l0);
157: v.visitVarInsn(ALOAD, 0);
158: v.visitFieldInsn(GETFIELD, "org/uispec4j/Panel", "finder",
159: "Lorg/uispec4j/finder/ComponentFinder;");
160: v.visitFieldInsn(GETSTATIC, "org/uispec4j/Panel",
161: transformedComponentClassName, "Ljava/lang/Class;");
162: Label l1 = new Label();
163: v.visitJumpInsn(IFNONNULL, l1);
164: v.visitLdcInsn(componentClassName);
165: v.visitMethodInsn(INVOKESTATIC, "org/uispec4j/Panel",
166: "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
167: v.visitInsn(DUP);
168: v.visitFieldInsn(PUTSTATIC, "org/uispec4j/Panel",
169: transformedComponentClassName, "Ljava/lang/Class;");
170: Label l2 = new Label();
171: v.visitJumpInsn(GOTO, l2);
172: v.visitLabel(l1);
173: v.visitFieldInsn(GETSTATIC, "org/uispec4j/Panel",
174: transformedComponentClassName, "Ljava/lang/Class;");
175: v.visitLabel(l2);
176: v.visitInsn(ACONST_NULL);
177: v
178: .visitMethodInsn(
179: INVOKESTATIC,
180: "org/uispec4j/Panel",
181: "getComponent",
182: "(Lorg/uispec4j/finder/ComponentFinder;Ljava/lang/Class;Ljava/lang/String;)Lorg/uispec4j/UIComponent;");
183: v.visitTypeInsn(CHECKCAST, slashedComponentClassName);
184: v.visitInsn(ARETURN);
185: v.visitMaxs(3, 1);
186: }
187: {
188: CodeVisitor v = cv
189: .visitMethod(
190: ACC_PUBLIC,
191: methodName,
192: "(Lorg/uispec4j/finder/ComponentMatcher;)L"
193: + slashedComponentClassName + ";",
194: new String[] {
195: "org/uispec4j/ItemNotFoundException",
196: "org/uispec4j/ComponentAmbiguityException" },
197: null);
198: Label l0 = new Label();
199: v.visitLabel(l0);
200: v.visitVarInsn(ALOAD, 0);
201: v.visitFieldInsn(GETFIELD, "org/uispec4j/Panel", "finder",
202: "Lorg/uispec4j/finder/ComponentFinder;");
203: v.visitVarInsn(ALOAD, 0);
204: v.visitFieldInsn(GETSTATIC, "org/uispec4j/Panel",
205: transformedComponentClassName, "Ljava/lang/Class;");
206: Label l1 = new Label();
207: v.visitJumpInsn(IFNONNULL, l1);
208: v.visitLdcInsn(componentClassName);
209: v.visitMethodInsn(INVOKESTATIC, "org/uispec4j/Panel",
210: "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
211: v.visitInsn(DUP);
212: v.visitFieldInsn(PUTSTATIC, "org/uispec4j/Panel",
213: transformedComponentClassName, "Ljava/lang/Class;");
214: Label l2 = new Label();
215: v.visitJumpInsn(GOTO, l2);
216: v.visitLabel(l1);
217: v.visitFieldInsn(GETSTATIC, "org/uispec4j/Panel",
218: transformedComponentClassName, "Ljava/lang/Class;");
219: v.visitLabel(l2);
220: v.visitVarInsn(ALOAD, 1);
221: v
222: .visitMethodInsn(
223: INVOKESPECIAL,
224: "org/uispec4j/Panel",
225: "getMatcherByClass",
226: "(Ljava/lang/Class;Lorg/uispec4j/finder/ComponentMatcher;)Lorg/uispec4j/finder/ComponentMatcher;");
227: v
228: .visitMethodInsn(
229: INVOKESTATIC,
230: "org/uispec4j/Panel",
231: "getComponent",
232: "(Lorg/uispec4j/finder/ComponentFinder;Lorg/uispec4j/finder/ComponentMatcher;)Lorg/uispec4j/UIComponent;");
233: v.visitTypeInsn(CHECKCAST, slashedComponentClassName);
234: v.visitInsn(ARETURN);
235: Label l3 = new Label();
236: v.visitLabel(l3);
237: v.visitLineNumber(205, l0);
238: v.visitLocalVariable("this", "Lorg/uispec4j/Panel;", l0,
239: l3, 0);
240: v
241: .visitLocalVariable("matcher",
242: "Lorg/uispec4j/finder/ComponentMatcher;",
243: l0, l3, 1);
244: v.visitMaxs(4, 2);
245: }
246: }
247:
248: private String transformClassName(String componentClassName) {
249: return "class$" + componentClassName.replace('.', '$');
250: }
251: }
|