001: /**
002: * Copyright (C) 2001-2005 France Telecom R&D
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */package org.objectweb.speedo.generation.enhancer.pc.jdo;
018:
019: import org.objectweb.asm.Attribute;
020: import org.objectweb.asm.ClassVisitor;
021: import org.objectweb.asm.CodeVisitor;
022: import org.objectweb.asm.Constants;
023: import org.objectweb.asm.Label;
024: import org.objectweb.speedo.generation.enhancer.common.LoggedClassAdapter;
025: import org.objectweb.speedo.generation.lib.NamingRules;
026: import org.objectweb.speedo.lib.Personality;
027: import org.objectweb.speedo.tools.StringReplace;
028: import org.objectweb.util.monolog.api.BasicLevel;
029: import org.objectweb.util.monolog.api.Logger;
030:
031: /**
032: * Add the registration to the JDOImplHelper in a static code area
033: *
034: * The added code use the class$(String)Class method and the field
035: * class$classname which can exist or not. Therefore they are added if they do
036: * not already exist.
037: *
038: * @author S.Chassande-Barrioz
039: */
040: public class JDOImplRegistrationAdder extends LoggedClassAdapter {
041: private final static String FIELD_PREFIX = "class$";
042: private final static String CLASS_METH = "class$";
043: /**
044: * Class name of the current visited class (with slash separator)
045: */
046: private final String classToWrite;
047: /**
048: * indicates if the field already exists in the current class
049: */
050: boolean clinitfound = false;
051: /**
052: * indicates if a static area class$classname already exists in the
053: * current class.
054: */
055: boolean classFieldfound = false;
056: /**
057: * indicates if the class$ method already exists in the current class
058: */
059: boolean classMethodfound = false;
060: /**
061: * is the name of the static field referencing the java.lang.Class of
062: * the current class.
063: */
064: private final String fieldName;
065: private boolean generationAllowed = false;
066:
067: public JDOImplRegistrationAdder(ClassVisitor classVisitor,
068: String className, Logger logger) {
069: super (classVisitor, Personality.JDO, logger);
070: this .classToWrite = getJVMClassName(className);
071: this .fieldName = FIELD_PREFIX + classToWrite.replace('/', '$');
072: }
073:
074: public boolean isGenerationAllowed() {
075: return generationAllowed;
076: }
077:
078: public void setGenerationAllowed(boolean v) {
079: this .generationAllowed = v;
080: }
081:
082: public void visit(final int version, final int access,
083: final String name, final String super Name,
084: final String[] interfaces, final String sourceFile) {
085: super .visit(version, access, name, super Name, interfaces,
086: sourceFile);
087: }
088:
089: public void visitField(int i, String s, String s1, Object o,
090: Attribute attribute) {
091: super .visitField(i, s, s1, o, attribute);
092: classFieldfound |= s.equals(fieldName);
093: }
094:
095: public CodeVisitor visitMethod(final int access, final String name,
096: final String desc, final String[] exceptions,
097: final Attribute attrs) {
098: CodeVisitor c = cv.visitMethod(access, name, desc, exceptions,
099: attrs);
100: if (name.equals("<clinit>")) {
101: clinitfound = true;
102: addClassRegistrationCode(c);
103: } else if (name.equals(CLASS_METH)) {
104: classMethodfound = true;
105: }
106: return c;
107: }
108:
109: public void visitEnd() {
110: if (generationAllowed) {
111: if (!clinitfound) {
112: logger.log(BasicLevel.DEBUG, "Adding static area in "
113: + classToWrite);
114: CodeVisitor c = cv.visitMethod(Constants.ACC_STATIC,
115: "<clinit>", "()V", null, null);
116: addClassRegistrationCode(c);
117: c.visitInsn(RETURN);
118: c.visitMaxs(0, 0);
119: clinitfound = true;
120: }
121:
122: if (!classMethodfound) {
123: classMethodfound = true;
124: logger.log(BasicLevel.DEBUG,
125: "Adding static method class$(String)Class in "
126: + classToWrite);
127: CodeVisitor c = cv.visitMethod(ACC_STATIC
128: + ACC_SYNTHETIC, CLASS_METH,
129: "(Ljava/lang/String;)Ljava/lang/Class;", null,
130: null);
131: //try {
132: final Label l0 = new Label();
133: c.visitLabel(l0);
134: //return Class.forName(str)
135: c.visitVarInsn(ALOAD, 0);
136: c.visitMethodInsn(INVOKESTATIC, "java/lang/Class",
137: "forName",
138: "(Ljava/lang/String;)Ljava/lang/Class;");
139: final Label l1 = new Label();
140: c.visitLabel(l1);
141: c.visitInsn(ARETURN);
142: final Label l2 = new Label();
143: c.visitLabel(l2);
144: c.visitVarInsn(ASTORE, 1);
145: c.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
146: c.visitInsn(DUP);
147: c.visitVarInsn(ALOAD, 1);
148: c.visitMethodInsn(INVOKEVIRTUAL,
149: "java/lang/ClassNotFoundException",
150: "getMessage", "()Ljava/lang/String;");
151: c.visitMethodInsn(INVOKESPECIAL,
152: "java/lang/NoClassDefFoundError", "<init>",
153: "(Ljava/lang/String;)V");
154: c.visitInsn(ATHROW);
155: c.visitTryCatchBlock(l0, l1, l2,
156: "java/lang/ClassNotFoundException");
157: c.visitMaxs(0, 0);
158: }
159: if (!classFieldfound) {
160: classFieldfound = true;
161: logger.log(BasicLevel.DEBUG, "Adding static field '"
162: + fieldName + " in " + classToWrite);
163: cv.visitField(ACC_STATIC + ACC_SYNTHETIC, fieldName,
164: "Ljava/lang/Class;", null, null);
165: }
166: }
167: super .visitEnd();
168: }
169:
170: /**
171: * Add registration code of the class into the JDOImplHelper
172: * @param c
173: */
174: private void addClassRegistrationCode(CodeVisitor c) {
175: //Class thepc
176: c.visitFieldInsn(Constants.GETSTATIC, classToWrite, fieldName,
177: "Ljava/lang/Class;");
178:
179: final Label l1 = new Label();
180: c.visitJumpInsn(Constants.IFNONNULL, l1);
181: c.visitLdcInsn(StringReplace
182: .replaceChar('/', '.', classToWrite));
183: c.visitMethodInsn(Constants.INVOKESTATIC, classToWrite,
184: CLASS_METH, "(Ljava/lang/String;)Ljava/lang/Class;");
185: c.visitInsn(Constants.DUP);
186: c.visitFieldInsn(Constants.PUTSTATIC, classToWrite, fieldName,
187: "Ljava/lang/Class;");
188: final Label l2 = new Label();
189: c.visitJumpInsn(Constants.GOTO, l2);
190: c.visitLabel(l1);
191: c.visitFieldInsn(Constants.GETSTATIC, classToWrite, fieldName,
192: "Ljava/lang/Class;");
193: c.visitLabel(l2);
194: final String homeClassName = NamingRules.homeName(classToWrite);
195: //String[] field names
196: c.visitFieldInsn(GETSTATIC, homeClassName, "FIELD_NAMES",
197: "[Ljava/lang/String;");
198: //Class[] fieldTypes
199: c.visitFieldInsn(GETSTATIC, homeClassName, "FIELD_TYPES",
200: "[Ljava/lang/Class;");
201: //byte[] fieldFlags
202: c.visitFieldInsn(GETSTATIC, homeClassName, "FIELD_FLAGS", "[B");
203: //Class superClass
204: c.visitFieldInsn(GETSTATIC, homeClassName, "SUPER_CLASS",
205: "Ljava/lang/Class;");
206: //PersistentCapable
207: c.visitInsn(ACONST_NULL);
208: c
209: .visitMethodInsn(
210: Constants.INVOKESTATIC,
211: "javax/jdo/spi/JDOImplHelper",
212: "registerClass",
213: "(Ljava/lang/Class;[Ljava/lang/String;[Ljava/lang/Class;[BLjava/lang/Class;Ljavax/jdo/spi/PersistenceCapable;)V");
214: }
215: }
|