/**
* Copyright (C) 2001-2005 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.objectweb.speedo.generation.enhancer.pc.jdo;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.CodeVisitor;
import org.objectweb.asm.Constants;
import org.objectweb.asm.Label;
import org.objectweb.speedo.generation.enhancer.common.LoggedClassAdapter;
import org.objectweb.speedo.generation.lib.NamingRules;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.speedo.tools.StringReplace;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
/**
* Add the registration to the JDOImplHelper in a static code area
*
* The added code use the class$(String)Class method and the field
* class$classname which can exist or not. Therefore they are added if they do
* not already exist.
*
* @author S.Chassande-Barrioz
*/
public class JDOImplRegistrationAdder extends LoggedClassAdapter {
private final static String FIELD_PREFIX = "class$";
private final static String CLASS_METH = "class$";
/**
* Class name of the current visited class (with slash separator)
*/
private final String classToWrite;
/**
* indicates if the field already exists in the current class
*/
boolean clinitfound = false;
/**
* indicates if a static area class$classname already exists in the
* current class.
*/
boolean classFieldfound = false;
/**
* indicates if the class$ method already exists in the current class
*/
boolean classMethodfound = false;
/**
* is the name of the static field referencing the java.lang.Class of
* the current class.
*/
private final String fieldName;
private boolean generationAllowed = false;
public JDOImplRegistrationAdder(ClassVisitor classVisitor,
String className,
Logger logger) {
super(classVisitor, Personality.JDO, logger);
this.classToWrite = getJVMClassName(className);
this.fieldName = FIELD_PREFIX + classToWrite.replace('/', '$');
}
public boolean isGenerationAllowed() {
return generationAllowed;
}
public void setGenerationAllowed(boolean v) {
this.generationAllowed = v;
}
public void visit(final int version, final int access,
final String name,
final String superName,
final String[] interfaces,
final String sourceFile) {
super.visit(version, access, name, superName, interfaces, sourceFile);
}
public void visitField(int i, String s, String s1, Object o, Attribute attribute) {
super.visitField(i, s, s1, o, attribute);
classFieldfound |= s.equals(fieldName);
}
public CodeVisitor visitMethod(final int access,
final String name,
final String desc,
final String[] exceptions,
final Attribute attrs) {
CodeVisitor c = cv.visitMethod(access, name, desc, exceptions, attrs);
if (name.equals("<clinit>")) {
clinitfound = true;
addClassRegistrationCode(c);
} else if (name.equals(CLASS_METH)) {
classMethodfound = true;
}
return c;
}
public void visitEnd() {
if (generationAllowed) {
if (!clinitfound) {
logger.log(BasicLevel.DEBUG, "Adding static area in " + classToWrite);
CodeVisitor c = cv.visitMethod(Constants.ACC_STATIC,
"<clinit>", "()V", null, null);
addClassRegistrationCode(c);
c.visitInsn(RETURN);
c.visitMaxs(0, 0);
clinitfound = true;
}
if (!classMethodfound) {
classMethodfound = true;
logger.log(BasicLevel.DEBUG, "Adding static method class$(String)Class in " + classToWrite);
CodeVisitor c = cv.visitMethod(ACC_STATIC + ACC_SYNTHETIC, CLASS_METH,
"(Ljava/lang/String;)Ljava/lang/Class;", null, null);
//try {
final Label l0 = new Label();
c.visitLabel(l0);
//return Class.forName(str)
c.visitVarInsn(ALOAD, 0);
c.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;)Ljava/lang/Class;");
final Label l1 = new Label();
c.visitLabel(l1);
c.visitInsn(ARETURN);
final Label l2 = new Label();
c.visitLabel(l2);
c.visitVarInsn(ASTORE, 1);
c.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
c.visitInsn(DUP);
c.visitVarInsn(ALOAD, 1);
c.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassNotFoundException",
"getMessage", "()Ljava/lang/String;");
c.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError",
"<init>", "(Ljava/lang/String;)V");
c.visitInsn(ATHROW);
c.visitTryCatchBlock(l0, l1, l2, "java/lang/ClassNotFoundException");
c.visitMaxs(0, 0);
}
if (!classFieldfound) {
classFieldfound = true;
logger.log(BasicLevel.DEBUG, "Adding static field '"
+ fieldName + " in " + classToWrite);
cv.visitField(ACC_STATIC + ACC_SYNTHETIC, fieldName,
"Ljava/lang/Class;", null, null);
}
}
super.visitEnd();
}
/**
* Add registration code of the class into the JDOImplHelper
* @param c
*/
private void addClassRegistrationCode(CodeVisitor c) {
//Class thepc
c.visitFieldInsn(Constants.GETSTATIC,
classToWrite,
fieldName,
"Ljava/lang/Class;");
final Label l1 = new Label();
c.visitJumpInsn(Constants.IFNONNULL, l1);
c.visitLdcInsn(StringReplace.replaceChar('/', '.', classToWrite));
c.visitMethodInsn(Constants.INVOKESTATIC, classToWrite, CLASS_METH,
"(Ljava/lang/String;)Ljava/lang/Class;");
c.visitInsn(Constants.DUP);
c.visitFieldInsn(Constants.PUTSTATIC,
classToWrite,
fieldName,
"Ljava/lang/Class;");
final Label l2 = new Label();
c.visitJumpInsn(Constants.GOTO, l2);
c.visitLabel(l1);
c.visitFieldInsn(Constants.GETSTATIC,
classToWrite,
fieldName,
"Ljava/lang/Class;");
c.visitLabel(l2);
final String homeClassName = NamingRules.homeName(classToWrite);
//String[] field names
c.visitFieldInsn(GETSTATIC, homeClassName, "FIELD_NAMES", "[Ljava/lang/String;");
//Class[] fieldTypes
c.visitFieldInsn(GETSTATIC, homeClassName, "FIELD_TYPES", "[Ljava/lang/Class;");
//byte[] fieldFlags
c.visitFieldInsn(GETSTATIC, homeClassName, "FIELD_FLAGS", "[B");
//Class superClass
c.visitFieldInsn(GETSTATIC, homeClassName, "SUPER_CLASS", "Ljava/lang/Class;");
//PersistentCapable
c.visitInsn(ACONST_NULL);
c.visitMethodInsn(Constants.INVOKESTATIC,
"javax/jdo/spi/JDOImplHelper",
"registerClass",
"(Ljava/lang/Class;[Ljava/lang/String;[Ljava/lang/Class;[BLjava/lang/Class;Ljavax/jdo/spi/PersistenceCapable;)V");
}
}