/**
* 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.oid;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.CodeVisitor;
import org.objectweb.asm.Constants;
import org.objectweb.asm.Type;
import org.objectweb.asm.Attribute;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.speedo.metadata.SpeedoClass;
import org.objectweb.speedo.metadata.SpeedoField;
import org.objectweb.speedo.generation.enhancer.common.LoggedClassAdapter;
import org.objectweb.speedo.generation.lib.NamingRules;
import org.objectweb.speedo.naming.api.UserId;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.BasicLevel;
import java.util.Iterator;
/**
* It adds the implementation of the UserId and specific PNameGetter interfaces
* in the user identifier.
*
* @author S.Chassande-Barrioz
*/
public class UserIdEnhancer extends LoggedClassAdapter {
protected SpeedoClass speedoClass;
public final static String ADDED_FIELD_NAME = "speedoPersistentClassName";
public final static String ADDED_FIELD_DESC = "Ljava/lang/String;";
private String className ;
public UserIdEnhancer(ClassVisitor classVisitor,
SpeedoClass sClass,
Logger logger,
Personality p) {
super(classVisitor, p, logger);
this.speedoClass = sClass;
}
public void visit(final int version, final int access,
final String cn,
final String superName,
final String[] interfaces,
final String sourceFile) {
className = cn;
String[] itfs;
String pngcn = NamingRules.pngName(speedoClass.identity.objectidClass).replace('.', '/');
boolean alreadyPNG = false;
String sncn = UserId.class.getName().replace('.','/');
if (interfaces == null || interfaces.length==0) {
itfs = new String[]{pngcn, sncn};
} else {
int i=0;
while(i<interfaces.length && !interfaces[i].equals(pngcn)) {
i++;
}
alreadyPNG = i<interfaces.length;
if (alreadyPNG) {
itfs = interfaces;
} else {
itfs = new String[interfaces.length + 2];
System.arraycopy(interfaces, 0, itfs, 2, interfaces.length);
itfs[0] = pngcn;
itfs[1] = UserId.class.getName().replace('.','/');
}
}
if (alreadyPNG) {
logger.log(BasicLevel.DEBUG, "The class " + className
+ " already contains the interface " + pngcn + " and " + sncn);
super.visit(version, access, className, superName, interfaces, sourceFile);
return;
}
logger.log(BasicLevel.DEBUG, "Add to the class " + className
+ " the interface " + pngcn);
logger.log(BasicLevel.DEBUG, "Add to the class " + className
+ " the interface " + sncn);
super.visit(version, access, className, superName, itfs, sourceFile);
SpeedoClass pkFieldClassHolder = speedoClass;
if (speedoClass.getSuperClassName() != null) {
pkFieldClassHolder = speedoClass.getAncestor();
}
for(Iterator it = pkFieldClassHolder.fields.values().iterator(); it.hasNext();) {
SpeedoField sp = (SpeedoField) it.next();
if (sp.primaryKey) {
String methodName = "pnGet" + upperFL(sp.name);
logger.log(BasicLevel.DEBUG, "Add to the class " + className
+ " the method " + methodName);
CodeVisitor _cv = this.cv.visitMethod(
Constants.ACC_PUBLIC,
methodName,
"(Ljava/lang/Object;)" + sp.type,
null,
null);
_cv.visitVarInsn(Constants.ALOAD, 0);
_cv.visitFieldInsn(Constants.GETFIELD, className, sp.name, sp.type);
Type returnType = Type.getType(sp.type);
_cv.visitInsn(returnType.getOpcode(Constants.IRETURN));
_cv.visitMaxs(
(sp.type.equals("J") || sp.type.equals("D")) ? 2 : 1,
2);
}
}
// declare the field speedoPersistentClassName
//int access, String name, String desc, Object value
logger.log(BasicLevel.DEBUG, "Add to the class " + className
+ " the field " + ADDED_FIELD_NAME);
cv.visitField(Constants.ACC_PRIVATE, ADDED_FIELD_NAME,
ADDED_FIELD_DESC, null, null);
//Add the method speedoGetPersistentClassName
String methodName = "speedoGetPersistentClassName";
logger.log(BasicLevel.DEBUG, "Add to the class " + className
+ " the method " + methodName);
CodeVisitor mv = this.cv.visitMethod(
Constants.ACC_PUBLIC,
methodName,
"()Ljava/lang/String;",
null,
null);
mv.visitVarInsn(Constants.ALOAD, 0);
mv.visitFieldInsn(Constants.GETFIELD,
className, ADDED_FIELD_NAME, ADDED_FIELD_DESC);
Type returnType = Type.getType(ADDED_FIELD_DESC);
mv.visitInsn(returnType.getOpcode(Constants.IRETURN));
mv.visitMaxs(1, 2);
//Add the method speedoSetPersistentClassName
methodName = "speedoSetPersistentClassName";
logger.log(BasicLevel.DEBUG, "Add to the class " + className
+ " the method " + methodName);
mv = this.cv.visitMethod(
Constants.ACC_PUBLIC,
methodName,
"(Ljava/lang/String;)V",
null,
null);
mv.visitVarInsn(Constants.ALOAD, 0);
mv.visitVarInsn(Constants.ALOAD, 1);
mv.visitFieldInsn(Constants.PUTFIELD,
className, ADDED_FIELD_NAME, ADDED_FIELD_DESC);
mv.visitInsn(Constants.RETURN);
mv.visitMaxs(2, 2);
}
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("<init>")) {
c.visitVarInsn(Constants.ALOAD, 0);
c.visitLdcInsn(speedoClass.getFQName()); //load a constant
c.visitFieldInsn(Constants.PUTFIELD, className,
ADDED_FIELD_NAME, ADDED_FIELD_DESC);
}
return c;
}
private String upperFL(String str) {
if (str == null || str.length()==0) {
return str;
} else if (str.length() == 1) {
return String.valueOf(Character.toUpperCase(str.charAt(0)));
} else {
return Character.toUpperCase(str.charAt(0)) + str.substring(1);
}
}
}