/*
* Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
* $Id: LazyLoadMethodAdapter.java 3918 2008-04-14 17:35:35Z gbevin $
*/
package com.uwyn.rife.database.querymanagers.generic.instrument;
import static com.uwyn.rife.database.querymanagers.generic.instrument.LazyLoadAccessorsBytecodeTransformer.GQM_VAR_NAME;
import static com.uwyn.rife.database.querymanagers.generic.instrument.LazyLoadAccessorsBytecodeTransformer.LAZYLOADED_VAR_NAME;
import java.util.Map;
import com.uwyn.rife.asm.*;
class LazyLoadMethodAdapter extends MethodAdapter implements Opcodes
{
private String mClassName = null;
private String mMethodName = null;
private String mMethodDescriptor = null;
private String mPropertyName = null;
private boolean mIsGetter = false;
private boolean mIsSetter = false;
LazyLoadMethodAdapter(String className, String methodName, String methodDescriptor, MethodVisitor visitor)
{
super(visitor);
mClassName = className;
mMethodName = methodName;
mMethodDescriptor = methodDescriptor;
mPropertyName = uncapitalize(methodName.substring(3)); // the length of the get/set accessor prefix
mIsGetter = mMethodName.startsWith("get");
mIsSetter = mMethodName.startsWith("set");
}
private static String uncapitalize(String source)
{
if (source == null || source.length() == 0)
{
return source;
}
if (source.length() > 1 &&
Character.isLowerCase(source.charAt(0)))
{
return source;
}
char chars[] = source.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
public void visitInsn(int opcode)
{
if (ARETURN == opcode &&
mIsGetter)
{
Label label_begin = new Label();
Label label_retrieve = new Label();
Label label_return = new Label();
Label label_end = new Label();
Type type_object = Type.getType(Object.class);
mv.visitLabel(label_begin);
// don't fetch a value if the current returned value is not null
mv.visitInsn(DUP);
mv.visitJumpInsn(IFNONNULL, label_end);
// don't fetch a value if there's no generic query manager stored in the bean
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, mClassName, GQM_VAR_NAME, "Lcom/uwyn/rife/database/querymanagers/generic/GenericQueryManager;");
mv.visitJumpInsn(IFNULL, label_end);
// don't fetch a value if there's already one stored in the map
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, mClassName, LAZYLOADED_VAR_NAME, Type.getDescriptor(Map.class));
mv.visitLdcInsn(mPropertyName);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Map.class), "containsKey", Type.getMethodDescriptor(Type.BOOLEAN_TYPE, new Type[] {type_object}));
mv.visitJumpInsn(IFNE, label_retrieve);
// load the value from the database
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, mClassName, GQM_VAR_NAME, "Lcom/uwyn/rife/database/querymanagers/generic/GenericQueryManager;");
mv.visitVarInsn(ALOAD, 0);
mv.visitLdcInsn(mPropertyName);
mv.visitLdcInsn(Type.getReturnType(mMethodDescriptor).getClassName());
mv.visitMethodInsn(INVOKESTATIC, "com/uwyn/rife/database/querymanagers/generic/GenericQueryManagerRelationalUtils", "restoreLazyManyToOneProperty", "(Lcom/uwyn/rife/database/querymanagers/generic/GenericQueryManager;Lcom/uwyn/rife/site/Constrained;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;");
mv.visitInsn(DUP);
// store the lazily loaded value in the hash map
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, mClassName, LAZYLOADED_VAR_NAME, Type.getDescriptor(Map.class));
mv.visitInsn(SWAP);
mv.visitLdcInsn(mPropertyName);
mv.visitInsn(SWAP);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Map.class), "put", Type.getMethodDescriptor(type_object, new Type[] {type_object, type_object}));
mv.visitInsn(POP);
mv.visitJumpInsn(GOTO, label_return);
// fetch the existing value from the map
mv.visitLabel(label_retrieve);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, mClassName, LAZYLOADED_VAR_NAME, Type.getDescriptor(Map.class));
mv.visitLdcInsn(mPropertyName);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Map.class), "get", Type.getMethodDescriptor(type_object, new Type[] {type_object}));
// return the value
mv.visitLabel(label_return);
mv.visitTypeInsn(CHECKCAST, Type.getReturnType(mMethodDescriptor).getInternalName());
mv.visitInsn(ARETURN);
mv.visitLabel(label_end);
}
super.visitInsn(opcode);
}
public void visitCode()
{
if (mIsSetter)
{
Type type_object = Type.getType(Object.class);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, mClassName, LAZYLOADED_VAR_NAME, Type.getDescriptor(Map.class));
Label l1 = new Label();
mv.visitJumpInsn(IFNULL, l1);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitLineNumber(55, l2);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, mClassName, LAZYLOADED_VAR_NAME, Type.getDescriptor(Map.class));
mv.visitLdcInsn(mPropertyName);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Map.class), "remove", Type.getMethodDescriptor(type_object, new Type[] {type_object}));
mv.visitInsn(POP);
mv.visitLabel(l1);
}
super.visitCode();
}
}