/**
* Copyright (C) 2001-2004 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.generator.home;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.CodeVisitor;
import org.objectweb.asm.Constants;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import org.objectweb.jorm.lib.JormPathHelper;
import org.objectweb.jorm.metainfo.api.Class;
import org.objectweb.jorm.metainfo.api.ClassRef;
import org.objectweb.jorm.metainfo.api.GenClassMapping;
import org.objectweb.jorm.metainfo.api.GenClassRef;
import org.objectweb.jorm.metainfo.api.MetaObject;
import org.objectweb.jorm.metainfo.api.NameDef;
import org.objectweb.jorm.metainfo.api.ReferenceMapping;
import org.objectweb.jorm.type.api.PType;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.api.SpeedoProperties;
import org.objectweb.speedo.generation.enhancer.common.Util;
import org.objectweb.speedo.generation.generator.lib.AbstractSpeedoGenerator;
import org.objectweb.speedo.generation.lib.NamingRules;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.speedo.mapper.lib.Object2StringSerializer;
import org.objectweb.speedo.metadata.SpeedoClass;
import org.objectweb.speedo.metadata.SpeedoField;
import org.objectweb.speedo.metadata.SpeedoPredefinedQuery;
import org.objectweb.speedo.metadata.SpeedoXMLDescriptor;
import org.objectweb.speedo.mim.api.StateItf;
import org.objectweb.speedo.mim.api.PersistentObjectItf;
import org.objectweb.speedo.tools.StringReplace;
import java.io.FileOutputStream;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
*
* @author S.Chassande-Barrioz
*/
public abstract class HomeGenerator extends AbstractSpeedoGenerator implements Constants {
public final static String LOGGER_NAME = SpeedoProperties.LOGGER_NAME
+ ".generation.generator.homes";
public final static String TEMPLATE_NAME = TEMPLATE_DIR + ".home.Home";
/**
* Provides the class to be inherited by the generated Home.
* @return The Java Class metaobject.
*/
protected abstract java.lang.Class getSuperClass();
/**
* Provides the class to be used by the generated Home for query creation.
* @return The Java Class metaobject.
*/
protected abstract java.lang.Class getQueryClass();
public HomeGenerator(Personality p) {
super(p);
}
// IMPLEMENTATION OF THE GeneratorComponent INTERFACE //
//----------------------------------------------------//
public boolean init() throws SpeedoException {
logger = scp.loggerFactory.getLogger(LOGGER_NAME);
return !scp.getXmldescriptor().isEmpty();
}
public void generate(SpeedoClass sClass, String fileName)
throws SpeedoException {
final ClassWriter cv = new ClassWriter(true);
Map ctx = getContextAsMap(sClass);
HomeContext gc = new HomeContext(sClass, cv, ctx);
//create the class
cv.visit(V1_1, ACC_PUBLIC + ACC_SUPER + ACC_ABSTRACT,
gc.xHomeJCN,
gc.superClassJCN,
new String[]{}, gc.xHomeJCN);
generateFinalStaticFields(gc);
generateStaticClause(gc);
generateClassMethod(gc);
generatePersonalityMethods(gc);
generateNoArgConstructor(gc);
generateNewSpeedoPOInstance(gc);
generateGetVersioningStrategy(gc);
generateIsDetachable(gc);
generateIsAbstract(gc);
generateGetClassProperties(gc);
generateWriteIntention(gc);
generateActiveUserCache(gc);
generateIniSHMethod(gc);
cv.visitEnd();
try {
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(cv.toByteArray());
fos.close();
} catch (Exception e) {
throw new SpeedoException("Problem while generating PAccessor.", e);
}
}
private void getJormConfig(SpeedoClass sc, Properties classProperties)
throws SpeedoException {
//Build the map
// Put the binder class name of the current persistent class
String id = JormPathHelper.getPath(sc.jormclass);
NameDef nd = getClassNameDef(sc.jormclass);
jormConfigs(nd, sc, sc.jormclass, id, classProperties);
//Put the binder class name for each reference field
SpeedoXMLDescriptor xml = sc.moPackage.xmlDescriptor;
for (Iterator it = sc.jormclass.getAllFields().iterator(); it
.hasNext();) {
Object o = it.next();
if (o instanceof ClassRef) {
nd = getRefNameDef((ClassRef) o, sc.jormclass);
id = JormPathHelper.getPath(((ClassRef) o));
SpeedoClass tsc = xml.getSpeedoClass(((ClassRef) o)
.getMOClass().getFQName(), true);
jormConfigs(nd, tsc, sc.jormclass, id, classProperties);
} else if (o instanceof GenClassRef) {
GenClassRef gcr = (GenClassRef) o;
nd = getRefNameDef(gcr, sc.jormclass);
id = JormPathHelper.getPath((GenClassRef) o, false);
jormConfigs(nd, sc, gcr, id, classProperties);
while (gcr.isGenClassRef()) {
gcr = gcr.getGenClassRef();
nd = getElemNameDef(gcr, sc.jormclass);
id = JormPathHelper.getPath(gcr, false);
jormConfigs(nd, sc, gcr, id, classProperties);
}
if (gcr.isClassRef()) {
ClassRef cr = gcr.getClassRef();
nd = getElemNameDef(gcr, sc.jormclass);
id = JormPathHelper.getPath(cr);
SpeedoClass tsc = xml.getSpeedoClass(cr.getMOClass()
.getFQName(), true);
jormConfigs(nd, tsc, cr, id, classProperties);
}
}
}
}
private void jormConfigs(NameDef nd, SpeedoClass targetClass,
MetaObject sourceMO, String key, Properties jormProp)
throws SpeedoException {
scp.nmf.getNamingManager(targetClass).getJormNamingConfig(nd,
targetClass, sourceMO, key, jormProp);
}
private GenClassMapping getGenClassMapping(GenClassRef gcr, Class clazz)
throws SpeedoException {
String gcid = gcr.getGenClassId();
GenClassMapping gcm = getMapping(clazz).getGenClassMapping(gcid);
if (gcm == null) {
Class klass = clazz;
Collection superclasses = klass.getSuperClasses();
while (gcm == null && !superclasses.isEmpty()) {
klass = (Class) superclasses.iterator().next();
gcm = getMapping(klass).getGenClassMapping(gcid);
superclasses = klass.getSuperClasses();
}
}
if (gcm == null) {
throw new SpeedoException("No GenClassMapping found for the field "
+ gcid);
}
return gcm;
}
private NameDef getRefNameDef(GenClassRef gcr, Class clazz)
throws SpeedoException {
return (NameDef) getGenClassMapping(gcr, clazz).getIdentifierMapping()
.getLinkedMO();
}
private NameDef getElemNameDef(GenClassRef gcr, Class clazz)
throws SpeedoException {
return (NameDef) getGenClassMapping(gcr, clazz).getReferenceMapping()
.getLinkedMO();
}
private ReferenceMapping getReferenceMapping(ClassRef cr, Class clazz)
throws SpeedoException {
String rid = cr.getName();
ReferenceMapping rm = getMapping(clazz).getClassMapping()
.getReferenceMapping(rid);
if (rm == null) {
Class klass = clazz;
Collection superclasses = klass.getSuperClasses();
while (rm == null && !superclasses.isEmpty()) {
klass = (Class) superclasses.iterator().next();
rm = getMapping(klass).getClassMapping().getReferenceMapping(
rid);
superclasses = klass.getSuperClasses();
}
}
if (rm == null) {
throw new SpeedoException(
"No ReferenceMapping found for the field " + rid);
}
return rm;
}
private NameDef getRefNameDef(ClassRef cr, Class clazz)
throws SpeedoException {
return (NameDef) getReferenceMapping(cr, clazz).getLinkedMO();
}
private void generateFinalStaticFields(HomeContext gc) {
//protected static final byte VERSIONING_STRATEGY = ${versioningStrategy.byteValue()};
gc.cv.visitField(ACC_PROTECTED + ACC_FINAL + ACC_STATIC,
"VERSIONING_STRATEGY", "B", gc.ctx.get("versioningStrategy"), null);
//public static final boolean DETACHABLE = $detachable;
gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "DETACHABLE", "Z",
new Integer(gc.sc.isDetachable ? 1 : 0), null);
//public static final String[] FIELD_NAMES = ${fieldsNamesArray};
gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "FIELD_NAMES", "[Ljava/lang/String;", null, null);
//public static final Class[] FIELD_TYPES = ${fieldsTypesArray};
gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "FIELD_TYPES", "[Ljava/lang/Class;", null, null);
//public static final byte[] FIELD_FLAGS = new byte[0];
gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "FIELD_FLAGS", "[B", null, null);
//public static final Class SUPER_CLASS = #if($hasSuperclass)#**#${superClassName}.class#else#**#null#end#**#;
gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "SUPER_CLASS", "Ljava/lang/Class;", null, null);
for (int ucIdx = 0; ucIdx < gc.userCacheNames.length; ucIdx++) {
gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC,
gc.userCacheNames[ucIdx] + "_USER_CACHE_ID",
"I", new Integer(ucIdx), null);
}
}
private void generateStaticClause(HomeContext gc) {
CodeVisitor cv = gc.cv.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
final HashSet staticfieldNames = new HashSet();
generateFieldNamesInit(gc, cv);
generateFieldTypesInit(gc, staticfieldNames, cv);
// Field flags
cv.visitInsn(ICONST_0);
cv.visitIntInsn(NEWARRAY, T_BYTE);
cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, "FIELD_FLAGS", "[B");
//Super class
if (gc.sc.getSuperClassName() == null) {
cv.visitInsn(ACONST_NULL);
} else {
generateDotClass(gc.sc.getSuperClassName(), gc, staticfieldNames, cv);
}
cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, "SUPER_CLASS", "Ljava/lang/Class;");
cv.visitInsn(RETURN);
cv.visitMaxs(0, 0);
for (Iterator iter = staticfieldNames.iterator(); iter.hasNext();) {
String fn = (String) iter.next();
gc.cv.visitField(ACC_STATIC + ACC_SYNTHETIC, fn, gc.classJT, null, null);
}
}
private void generateFieldNamesInit(HomeContext gc, CodeVisitor cv) {
Collection fields = gc.sc.fields.values();
cv.visitIntInsn(BIPUSH, fields.size());
cv.visitTypeInsn(ANEWARRAY, "java/lang/String");
int idx = 0;
for(Iterator it = fields.iterator(); it.hasNext();) {
SpeedoField sf = (SpeedoField) it.next();
cv.visitInsn(DUP);
Util.visitIntConstant(cv, idx);
cv.visitLdcInsn(sf.name);
cv.visitInsn(AASTORE);
idx ++;
}
cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, "FIELD_NAMES", "[Ljava/lang/String;");
}
private void generateFieldTypesInit(HomeContext gc, final HashSet staticfieldNames, CodeVisitor cv) {
Collection fields = gc.sc.fields.values();
cv.visitIntInsn(BIPUSH, fields.size());
cv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
final String fieldType = "TYPE";
int idx = 0;
for(Iterator it = fields.iterator(); it.hasNext();) {
cv.visitInsn(DUP);
Util.visitIntConstant(cv, idx);
idx ++;
SpeedoField sf = (SpeedoField) it.next();
Type t = Type.getType(sf.type);
switch (t.getSort()) {
case Type.BOOLEAN:
cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", fieldType, gc.classJT);
break;
case Type.BYTE:
cv.visitFieldInsn(GETSTATIC, "java/lang/Byte", fieldType, gc.classJT);
break;
case Type.CHAR:
cv.visitFieldInsn(GETSTATIC, "java/lang/Character", fieldType, gc.classJT);
break;
case Type.DOUBLE:
cv.visitFieldInsn(GETSTATIC, "java/lang/Double", fieldType, gc.classJT);
break;
case Type.FLOAT:
cv.visitFieldInsn(GETSTATIC, "java/lang/Float", fieldType, gc.classJT);
break;
case Type.INT:
cv.visitFieldInsn(GETSTATIC, "java/lang/Integer", fieldType, gc.classJT);
break;
case Type.LONG:
cv.visitFieldInsn(GETSTATIC, "java/lang/Long", fieldType, gc.classJT);
break;
case Type.SHORT:
cv.visitFieldInsn(GETSTATIC, "java/lang/Short", fieldType, gc.classJT);
break;
case Type.ARRAY:
String cn ;
switch (t.getElementType().getSort()) {
case Type.BOOLEAN:
case Type.BYTE:
case Type.CHAR:
case Type.DOUBLE:
case Type.FLOAT:
case Type.INT:
case Type.LONG:
case Type.SHORT:
cn = t.getDescriptor();
break;
default:
cn = t.getElementType().getClassName();
break;
}
generateDotClass(cn, gc, staticfieldNames, cv);
break;
default:
generateDotClass(t.getClassName(), gc, staticfieldNames, cv);
break;
}
cv.visitInsn(AASTORE);
}
cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, "FIELD_TYPES", "[Ljava/lang/Class;");
}
private void generateDotClass(final String className,
final HomeContext gc,
final HashSet staticfieldNames ,
final CodeVisitor cv) {
final String staticFieldName = "class$"
+ StringReplace.replaceString("[", "array$", className)
.replace('.', '$');
cv.visitFieldInsn(GETSTATIC, gc.classToWriteJCN, staticFieldName, gc.classJT);
staticfieldNames.add(staticFieldName);
//this type has not been already met
Label labelElse = new Label();
Label labelEnd = new Label();
cv.visitJumpInsn(IFNONNULL, labelElse);
{
cv.visitLdcInsn(className);
cv.visitMethodInsn(INVOKESTATIC, gc.classToWriteJCN, "class$", "(Ljava/lang/String;)" + gc.classJT);
cv.visitInsn(DUP);
cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, staticFieldName, gc.classJT);
cv.visitJumpInsn(GOTO, labelEnd);
}
cv.visitLabel(labelElse);
{
cv.visitFieldInsn(GETSTATIC, gc.classToWriteJCN, staticFieldName, gc.classJT);
}
cv.visitLabel(labelEnd);
}
private void generateClassMethod(HomeContext gc) {
CodeVisitor cv = gc.cv.visitMethod(ACC_STATIC + ACC_SYNTHETIC, "class$",
"(Ljava/lang/String;)Ljava/lang/Class;", null, null);
Label labelTry = new Label();
cv.visitLabel(labelTry);
cv.visitVarInsn(ALOAD, 0);
cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;)Ljava/lang/Class;");
Label labelEndTry = new Label();
cv.visitLabel(labelEndTry);
cv.visitInsn(ARETURN);
Label labelCatch = new Label();
cv.visitLabel(labelCatch);
cv.visitVarInsn(ASTORE, 1);
cv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
cv.visitInsn(DUP);
cv.visitVarInsn(ALOAD, 1);
cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassNotFoundException",
"getMessage", "()Ljava/lang/String;");
cv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError",
"<init>", "(Ljava/lang/String;)V");
cv.visitInsn(ATHROW);
cv.visitTryCatchBlock(labelTry, labelEndTry, labelCatch, "java/lang/ClassNotFoundException");
cv.visitMaxs(0, 0);
}
protected void generateNoArgConstructor(HomeContext gc) {
CodeVisitor mv = gc.cv.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, gc.superClassJCN, "<init>", "()V");
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
}
private void generateNewSpeedoPOInstance(HomeContext gc) {
//protected PersistentObjectItf newSpeedoPOInstance(Class clazz) {
CodeVisitor cv = gc.cv.visitMethod(ACC_PROTECTED, "newSpeedoPOInstance",
"(Ljava/lang/Class;)Lorg/objectweb/speedo/mim/api/PersistentObjectItf;", null, null);
if (gc.sc.isAbstract) {
cv.visitInsn(ACONST_NULL);
cv.visitInsn(ARETURN);
} else {
Label l0 = new Label();
cv.visitLabel(l0);
cv.visitTypeInsn(NEW, gc.xJCN);
cv.visitInsn(DUP);
cv.visitMethodInsn(INVOKESPECIAL, gc.xJCN, "<init>", "()V");
// cv.visitVarInsn(ASTORE, 2);
// cv.visitVarInsn(ALOAD, 2);
cv.visitTypeInsn(CHECKCAST, "org/objectweb/speedo/mim/api/PersistentObjectItf");
Label l1 = new Label();
cv.visitLabel(l1);
cv.visitInsn(ARETURN);
Label l2 = new Label();
cv.visitLabel(l2);
cv.visitVarInsn(ASTORE, 2);
cv.visitTypeInsn(NEW, personality.getUserRuntimeExceptionClassNameSlash());
cv.visitInsn(DUP);
cv.visitLdcInsn("Impossible to instanciate the class " + gc.classToWriteJCN + ": ");
cv.visitVarInsn(ALOAD, 2);
cv.visitMethodInsn(INVOKESPECIAL,
personality.getUserRuntimeExceptionClassNameSlash(),
"<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
cv.visitInsn(ATHROW);
cv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception");
}
cv.visitMaxs(0, 0);
}
private void generateGetVersioningStrategy(HomeContext gc) {
CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC + ACC_FINAL,
"getVersioningStrategy", "()B", null, null);
cv.visitFieldInsn(GETSTATIC, gc.classToWriteJCN, "VERSIONING_STRATEGY", "B");
cv.visitInsn(IRETURN);
cv.visitMaxs(1, 1);
}
private void generateIsDetachable(HomeContext gc) {
CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC + ACC_FINAL,
"isDetachable", "()Z", null, null);
cv.visitFieldInsn(GETSTATIC, gc.classToWriteJCN, "DETACHABLE", "Z");
cv.visitInsn(IRETURN);
cv.visitMaxs(1, 1);
}
private void generateIsAbstract(HomeContext gc) {
if (gc.sc.isAbstract) {
CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC + ACC_FINAL,
"isAbstract", "()Z", null, null);
cv.visitInsn(ICONST_1);
cv.visitInsn(IRETURN);
cv.visitMaxs(1, 1);
}
}
private void generateGetClassProperties(HomeContext gc) throws SpeedoException {
CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC + ACC_FINAL, "getClassProperties",
"()Ljava/util/Properties;", null, null);
cv.visitTypeInsn(NEW, "java/util/Properties");
cv.visitInsn(DUP);
cv.visitMethodInsn(INVOKESPECIAL, "java/util/Properties", "<init>", "()V");
cv.visitVarInsn(ASTORE, 1);
Properties classProperties = new Properties();
getJormConfig(gc.sc, classProperties);
String xmlFileName = gc.sc.moPackage.xmlDescriptor.xmlFile;
xmlFileName = StringReplace.replaceChar('/', '.', xmlFileName);
xmlFileName = StringReplace.replaceChar(fs, '.', xmlFileName);
classProperties.setProperty(
Object2StringSerializer.DESC_FILE_NAME_PROP,
xmlFileName);
for (Iterator it = classProperties.entrySet().iterator(); it.hasNext();) {
Map.Entry me = (Map.Entry) it.next();
cv.visitVarInsn(ALOAD, 1);
cv.visitLdcInsn(me.getKey());
cv.visitLdcInsn(me.getValue());
cv.visitMethodInsn(INVOKEVIRTUAL, "java/util/Properties", "setProperty",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;");
cv.visitInsn(POP); //remove the result of the setProperty method
}
cv.visitVarInsn(ALOAD, 1);
cv.visitInsn(ARETURN);
cv.visitMaxs(3, 2);
}
private void generateWriteIntention(HomeContext gc) {
if (gc.userCacheNames.length == 0) {
return;
}
//public StateItf writeIntention(PersistentObjectItf sp, long[] fields, Object thinLock)
final String methodDesc = "("
+ getJVMType(PersistentObjectItf.class)
+ "[J"
+ getJVMType(Object.class)
+ ")" + getJVMType(StateItf.class);
CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC, "writeIntention",
methodDesc, null, null);
//StateItf sa = super.writeIntention(sp, fields, thinLock);
cv.visitVarInsn(ALOAD, 0);
cv.visitVarInsn(ALOAD, 1);
cv.visitVarInsn(ALOAD, 2);
cv.visitVarInsn(ALOAD, 3);
cv.visitMethodInsn(INVOKESPECIAL, gc.superClassJCN, "writeIntention", methodDesc);
cv.visitVarInsn(ASTORE, 4);
//if (fields == null) {
cv.visitVarInsn(ALOAD, 2);
Label labelElse = new Label();
cv.visitJumpInsn(IFNONNULL, labelElse);
Label labelEnd = new Label();
{
//sa.indexFieldModified(0xffffffff, false);
cv.visitVarInsn(ALOAD, 4);
cv.visitLdcInsn(new Integer(0xffffffff));
cv.visitInsn(ICONST_0);
cv.visitMethodInsn(INVOKEINTERFACE,
getJVMClassName(StateItf.class),
"indexFieldModified", "(IZ)V");
cv.visitJumpInsn(GOTO, labelEnd);
}
cv.visitLabel(labelElse);
{
for (int ucIdx = 0; ucIdx < gc.userCacheNames.length; ucIdx++) {
String ucn = gc.userCacheNames[ucIdx];
List fields = (List) gc.ucn2sfs.get(ucn);
for(Iterator itf = fields.iterator(); itf.hasNext();) {
SpeedoField sf = (SpeedoField) itf.next();
//if ((fields[${f.jormFieldIdLongPos}] & ${f.jormFieldId}L) != 0) {
cv.visitVarInsn(ALOAD, 2);
Util.visitIntConstant(cv, sf.number / 64);
cv.visitInsn(LALOAD);
Util.visitLongConstant(cv, 1L << (sf.number % 64));
cv.visitInsn(LAND);
cv.visitInsn(LCONST_0);
cv.visitInsn(LCMP);
Label labelNext = new Label();
cv.visitJumpInsn(IFEQ, labelNext);
{
//sa.indexFieldModified(${ucn}_USER_CACHE_ID, false);
cv.visitVarInsn(ALOAD, 4);
Util.visitIntConstant(cv, ucIdx);
cv.visitInsn(ICONST_0);
cv.visitMethodInsn(INVOKEINTERFACE,
getJVMClassName(StateItf.class),
"indexFieldModified", "(IZ)V");
}
cv.visitLabel(labelNext);
}
}
}
cv.visitLabel(labelEnd);
//return sa;
cv.visitVarInsn(ALOAD, 4);
cv.visitInsn(ARETURN);
cv.visitMaxs(0, 0);
}
private void generateActiveUserCache(HomeContext gc) {
if (gc.userCacheNames.length == 0) {
return;
}
CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC, "activeUserCache",
"(Ljava/lang/String;)Z", null, null);
//if (cacheName == null) {
cv.visitVarInsn(ALOAD, 1);
Label l0 = new Label();
cv.visitJumpInsn(IFNONNULL, l0);
{
//return false;
cv.visitInsn(ICONST_0);
cv.visitInsn(IRETURN);
}
cv.visitLabel(l0);
//} else if ("*".equals(cacheName)) {
cv.visitLdcInsn("*");
cv.visitVarInsn(ALOAD, 1);
cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
Label labelElse = new Label();
cv.visitJumpInsn(IFEQ, labelElse);
{
//foreach($ucn in $userCacheNames)
for (int ucIdx = 0; ucIdx < gc.userCacheNames.length; ucIdx++) {
//activeUserCache("$ucn");
cv.visitVarInsn(ALOAD, 0);
cv.visitLdcInsn(gc.userCacheNames[ucIdx]);
cv.visitMethodInsn(INVOKEVIRTUAL,
gc.classToWriteJCN,
"activeUserCache", "(Ljava/lang/String;)Z");
cv.visitInsn(POP);
}
//return true;
cv.visitInsn(ICONST_1);
cv.visitInsn(IRETURN);
}
cv.visitLabel(labelElse);
for (int ucIdx = 0; ucIdx < gc.userCacheNames.length; ucIdx++) {
final String ucn = gc.userCacheNames[ucIdx];
//} else if ("${ucn}".equals(cacheName)) {
cv.visitLdcInsn(ucn);
cv.visitVarInsn(ALOAD, 1);
cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
Label labelNext = new Label();
cv.visitJumpInsn(IFEQ, labelNext);
{
//this.addUserCache(cacheName, ${userCacheFieldNames.get($ucn)}, ${ucn}_USER_CACHE_ID);
cv.visitVarInsn(ALOAD, 0); //this
cv.visitVarInsn(ALOAD, 1); //cacheName parameter
//parameter ${userCacheFieldNames.get($ucn)}
// new String[]{"f1", "f2"}
final List fields = (List) gc.ucn2sfs.get(ucn);
Util.visitIntConstant(cv, fields.size()); //Array size
cv.visitTypeInsn(ANEWARRAY, "java/lang/String");
for (int fieldIdx = 0; fieldIdx < fields.size(); fieldIdx++) {
SpeedoField sf = (SpeedoField) fields.get(fieldIdx);
cv.visitInsn(DUP);
Util.visitIntConstant(cv, fieldIdx); //index
cv.visitLdcInsn(sf.name); //value = field name
cv.visitInsn(AASTORE);
}
Util.visitIntConstant(cv, ucIdx); //${ucn}_USER_CACHE_ID
cv.visitMethodInsn(INVOKEVIRTUAL, gc.classToWriteJCN,
"addUserCache", "(Ljava/lang/String;[Ljava/lang/String;I)Lorg/objectweb/speedo/usercache/api/UserCache;");
cv.visitInsn(POP);
//return true;
cv.visitInsn(ICONST_1);
cv.visitInsn(IRETURN);
}
cv.visitLabel(labelNext);
}
//return false;
cv.visitInsn(ICONST_0);
cv.visitInsn(IRETURN);
cv.visitMaxs(0, 0);
}
private void generateIniSHMethod(HomeContext gc) {
CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC, "initSH", "()V", null, null);
String sqJCN = getJVMClassName(getQueryClass());
for (Iterator it = gc.sc.name2query.values().iterator(); it.hasNext();) {
SpeedoPredefinedQuery q = (SpeedoPredefinedQuery) it.next();
//sq = new SpeedoQuery();
cv.visitTypeInsn(NEW, sqJCN);
cv.visitInsn(DUP);
cv.visitMethodInsn(INVOKESPECIAL, sqJCN, "<init>", "()V");
cv.visitVarInsn(ASTORE, 1); //Always use the same variable 1
if (q.query != null) {
cv.visitVarInsn(ALOAD, 1);
cv.visitLdcInsn(q.query);
cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "defineWith", "(Ljava/lang/String;)V");
}
if (q.filter != null) {
cv.visitVarInsn(ALOAD, 1);
cv.visitLdcInsn(q.filter);
cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setFilter", "(Ljava/lang/String;)V");
}
if (q.declareImports != null) {
cv.visitVarInsn(ALOAD, 1);
cv.visitLdcInsn(q.declareImports);
cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "declareImports", "(Ljava/lang/String;)V");
}
if (q.declareParameters != null) {
cv.visitVarInsn(ALOAD, 1);
cv.visitLdcInsn(q.declareParameters);
cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "declareParameters", "(Ljava/lang/String;)V");
}
if (q.declareVariables != null) {
cv.visitVarInsn(ALOAD, 1);
cv.visitLdcInsn(q.declareVariables);
cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "declareVariables", "(Ljava/lang/String;)V");
}
cv.visitVarInsn(ALOAD, 1);
cv.visitInsn(q.ignoreCache ? ICONST_1 : ICONST_0);
cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setIgnoreCache", "(Z)V");
cv.visitVarInsn(ALOAD, 1);
cv.visitInsn(q.resultUnique ? ICONST_1 : ICONST_0);
cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setUnique", "(Z)V");
cv.visitVarInsn(ALOAD, 1);
Util.visitLongConstant(cv, q.rangeFirst);
Util.visitLongConstant(cv, q.rangeLast);
cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setRange", "(JJ)V");
if (q.ordering != null) {
cv.visitVarInsn(ALOAD, 1);
cv.visitLdcInsn(q.ordering);
cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setOrdering", "(Ljava/lang/String;)V");
}
if (q.resultClass != null) {
cv.visitVarInsn(ALOAD, 1);
cv.visitLdcInsn(q.resultClass);
cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setResultClass", "(Ljava/lang/String;)V");
}
cv.visitVarInsn(ALOAD, 1);
cv.visitInsn(q.includeSubclasses ? ICONST_1 : ICONST_0);
cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setIncludeSubClasses", "(Z)V");
//addNamedQuery("${nq.name}", sq);
cv.visitVarInsn(ALOAD, 0);
cv.visitLdcInsn(q.name);
cv.visitVarInsn(ALOAD, 1);
cv.visitMethodInsn(INVOKEVIRTUAL, gc.classToWriteJCN,
"addNamedQuery", "(Ljava/lang/String;L" + sqJCN + ";)V");
}
cv.visitInsn(RETURN);
cv.visitMaxs(0, 0);
}
protected void generatePersonalityMethods(HomeContext gc) {
}
public final static String getJVMClassName(String className) {
return StringReplace.replaceChar('.', '/', className);
}
public final static String getJVMClassName(java.lang.Class clazz) {
return getJVMClassName(clazz.getName());
}
public final static String getJVMType(java.lang.Class clazz) {
return getJVMType(clazz.getName());
}
public final static String getJVMType(String className) {
return "L" + getJVMClassName(className) + ";";
}
public final static String getJVMType(PType pt) {
return Type.getType(pt.getJavaClass()).getDescriptor();
}
protected class HomeContext {
public final String classToWriteJCN;
public final String xHomeJCN;
public final String xHomeJT;
public final String xJCN;
public final String xJT;
public final String superClassJCN;
public final SpeedoClass sc;
public final ClassVisitor cv;
public final Map ctx;
public final String[] userCacheNames;
public final Map ucn2sfs;
public final String classJT = "Ljava/lang/Class;";
public HomeContext(SpeedoClass scl, ClassVisitor clav, Map context) {
sc = scl;
cv = clav;
ctx = context;
xJCN = getJVMClassName(sc.getFQName());
xJT = getJVMType(xJCN);
xHomeJCN = getJVMClassName(NamingRules.homeName(sc.getFQName()));
xHomeJT = getJVMType(xHomeJCN);
classToWriteJCN = xHomeJCN;
superClassJCN = getJVMClassName(getSuperClass());
ucn2sfs = computeUserCaches(sc);
userCacheNames = (String[]) ucn2sfs.keySet().toArray(
new String[ucn2sfs.size()]);
}
}
}