/**********************************************************************
Copyright (c) 2007 Erik Bengtson and others. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Contributors:
...
**********************************************************************/
package org.jpox.enhancer.bcel.method;
import javax.jdo.spi.PersistenceCapable;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.BranchInstruction;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.IFEQ;
import org.apache.bcel.generic.IFNULL;
import org.apache.bcel.generic.IF_ICMPEQ;
import org.apache.bcel.generic.InstructionConstants;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.Type;
import org.jpox.enhancer.ClassEnhancer;
import org.jpox.enhancer.bcel.BCELClassEnhancer;
import org.jpox.enhancer.bcel.BCELUtils;
import org.jpox.enhancer.bcel.metadata.BCELClassMetaData;
import org.jpox.enhancer.bcel.metadata.BCELMember;
import org.jpox.enhancer.bcel.metadata.BCELFieldPropertyMetaData;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.util.ClassUtils;
/**
* Enhance a persistent property setter
* @version $Revision: 1.4 $
*/
public class PropertySetterMethod
{
/** target field */
protected BCELFieldPropertyMetaData fieldConfig;
/** InstructionList instance */
protected InstructionList il;
/** MethodGen instance */
protected MethodGen methodGen;
/** is synthetic */
protected boolean synthetic;
/** target ClassGen instance */
protected ClassGen classGen;
/** target class name */
protected String className;
/** target ConstantPoolGen instance */
protected ConstantPoolGen constantPoolGen;
/** ClassMetaData for the class */
protected BCELClassMetaData cmd;
/** Types of the arguments. */
protected Object[] argTypes;
/** InstructionFactory instance */
protected InstructionFactory factory;
/** Method */
protected Method method;
/**
* Constructor
* @param m Method
* @param className Name of class
* @param constantPoolGen BCEL pool gen
* @param newClass the new class
* @param argTypes types of args to the method
* @param fieldConfig metadata for the field/property
* @param enhancer The enhancer
*/
public PropertySetterMethod(
Method m,
String className,
ConstantPoolGen constantPoolGen,
ClassGen newClass,
Type argTypes[],
BCELFieldPropertyMetaData fieldConfig,
BCELClassEnhancer enhancer)
{
this.method = m;
this.fieldConfig = fieldConfig;
this.methodGen = new MethodGen(m, className, constantPoolGen);
this.methodGen.setInstructionList(new InstructionList());
this.methodGen.removeLocalVariables();
this.methodGen.removeLineNumbers();
this.methodGen.removeExceptions();
this.il = methodGen.getInstructionList();
this.factory = new InstructionFactory(newClass);
this.className = className;
this.cmd = (BCELClassMetaData)enhancer.getClassMetaData();
this.classGen = newClass;
this.fieldConfig = fieldConfig;
this.constantPoolGen = constantPoolGen;
}
public void execute()
{
methodGen.setMaxLocals();
methodGen.setMaxStack();
BCELMember targetField = fieldConfig.getEnhanceField();
Type smType = BCELUtils.getJDOMethodType(targetField.getType());
Type nativeType = targetField.getType();
String fieldName;
if(!((AbstractMemberMetaData)fieldConfig).isProperty())
{
fieldName = targetField.getName();
}
else
{
fieldName = ClassUtils.getFieldNameForJavaBeanGetter(targetField.getName());
}
// if( jdoStateManager != null )
InstructionHandle last;
BranchInstruction flgIsZero = null;
if( (fieldConfig.getJdoFieldFlag() & PersistenceCapable.CHECK_WRITE) == PersistenceCapable.CHECK_WRITE)
{
// (flag == 0)
il.append(InstructionConstants.ALOAD_0);
il.append(factory.createGetField(className, ClassEnhancer.FN_Flag, Type.BYTE));
flgIsZero = new IFEQ(null);
il.append(flgIsZero);
}
il.append(InstructionConstants.ALOAD_0);
il.append(factory.createGetField(className, ClassEnhancer.FN_StateManager, BCELClassEnhancer.OT_StateManager));
BranchInstruction hasStateManager = new IFNULL(null);
il.append(hasStateManager);
// {
il.append(InstructionConstants.ALOAD_0);
il.append(factory.createGetField(className, ClassEnhancer.FN_StateManager, BCELClassEnhancer.OT_StateManager));
il.append(InstructionConstants.ALOAD_0);
il.append(BCELUtils.getBIPUSH(fieldConfig.getFieldId()));
if (cmd.getPersistenceCapableSuperclass() != null)
{
il.append(factory.createGetStatic(className, ClassEnhancer.FN_JdoInheritedFieldCount, Type.INT));
il.append(InstructionConstants.IADD);
}
il.append(InstructionConstants.ALOAD_0);
il.append(factory.createInvoke(
className,
"jdo"+BCELUtils.getGetterName(fieldName),
nativeType,
new Type[] {},
Constants.INVOKEVIRTUAL));
il.append(InstructionFactory.createLoad(nativeType, 1));
il.append(factory.createInvoke(ClassEnhancer.CN_StateManager, "set" + BCELUtils.getJDOMethodName(smType) + "Field",
Type.VOID, new Type[]{BCELClassEnhancer.OT_PersistenceCapable, Type.INT, smType, smType}, Constants.INVOKEINTERFACE));
//}
//----detach------
if (cmd.isDetachable())
{
// jdoIsDetached()
last = il.append(InstructionConstants.ALOAD_0);
il.append(factory.createInvoke(ClassEnhancer.CN_PersistenceCapable, ClassEnhancer.MN_JdoIsDetached,
Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEINTERFACE));
// 1
il.append(InstructionConstants.ICONST_1);
// if (jdoIsDetached() == 1)
IF_ICMPEQ ifIsDetached = new IF_ICMPEQ(null);
il.append(ifIsDetached);
// return;
il.append(InstructionConstants.ALOAD_0);
il.append(InstructionFactory.createLoad(nativeType, 1));
il.append(factory.createInvoke(
className,
"jdo"+BCELUtils.getSetterName(fieldName),
Type.VOID,
new Type[] {nativeType},
Constants.INVOKEVIRTUAL));
il.append(InstructionConstants.RETURN);
// ((BitSet)jdoDetachedState[3]).set(?)
// jdoDetachedState[3]
ifIsDetached.setTarget(il.append(InstructionConstants.ALOAD_0));
il.append(factory.createGetField(className, ClassEnhancer.FN_JdoDetachedState, BCELClassEnhancer.OT_ObjectArray));
il.append(InstructionConstants.ICONST_3);
il.append(InstructionConstants.AALOAD);
il.append(factory.createCheckCast(BCELClassEnhancer.OT_BitSet)); // Cast to BitSet
// the field index: 0, 1, 2...
il.append(BCELUtils.getBIPUSH(fieldConfig.getFieldId()));
if (cmd.getPersistenceCapableSuperclass() != null)
{
// add to field index the parentFieldCount
il.append(factory.createGetStatic(className, ClassEnhancer.FN_JdoInheritedFieldCount, Type.INT));
il.append(InstructionConstants.IADD);
}
// set(?)
il.append(factory.createInvoke(ClassEnhancer.CN_BitSet, "set", Type.VOID, new Type[]{Type.INT}, Constants.INVOKEVIRTUAL));
//----detach------
il.append(InstructionConstants.ALOAD_0);
il.append(InstructionFactory.createLoad(nativeType, 1));
il.append(factory.createInvoke(
className,
"jdo"+BCELUtils.getSetterName(fieldName),
Type.VOID,
new Type[] {nativeType},
Constants.INVOKEVIRTUAL));
il.append(InstructionConstants.RETURN);
methodGen.setInstructionList(il);
}
else
{
last = il.append(InstructionConstants.ALOAD_0);
il.append(InstructionFactory.createLoad(nativeType, 1));
il.append(factory.createInvoke(
className,
"jdo"+BCELUtils.getSetterName(fieldName),
Type.VOID,
new Type[] {nativeType},
Constants.INVOKEVIRTUAL));
il.append(InstructionConstants.RETURN);
methodGen.setInstructionList(il);
}
hasStateManager.setTarget(last);
if( (fieldConfig.getJdoFieldFlag() & PersistenceCapable.CHECK_WRITE) == PersistenceCapable.CHECK_WRITE)
{
flgIsZero.setTarget(last);
}
methodGen.setMaxLocals();
methodGen.setMaxStack();
classGen.replaceMethod(method, methodGen.getMethod());
}
}