CVS: Tapestry/framework/src/net/sf/tapestry/pageload EnhancedComponentDetachListener.java,NONE,1.1.2.1 EnhancedComponentTemplate.java,NONE,1.1.2.1 IEnhancedComponent.java,NONE,1.1.2.1 ComponentClassLoaderException.java,NONE,1.1.2.1 ComponentClassLoader.java,NONE,1.1.2.1

Mind Bridge <[email protected]>
Newsgroups gmane.comp.java.tapestry.cvs
Message-ID <[email protected]>
Update of /cvsroot/tapestry/Tapestry/framework/src/net/sf/tapestry/pageload
In directory sc8-pr-cvs1:/tmp/cvs-serv12947/framework/src/net/sf/tapestry/pageload

Added Files:
      Tag: mb-2-3
	EnhancedComponentDetachListener.java 
	EnhancedComponentTemplate.java IEnhancedComponent.java 
	ComponentClassLoaderException.java ComponentClassLoader.java 
Log Message:


--- NEW FILE: EnhancedComponentDetachListener.java ---
package net.sf.tapestry.pageload;

import net.sf.tapestry.event.PageDetachListener;
import net.sf.tapestry.event.PageEvent;

/**
 * @author mindbridge
 *
 */
public class EnhancedComponentDetachListener implements PageDetachListener
{
    private IEnhancedComponent _enhancedComponent;
    
    public EnhancedComponentDetachListener(IEnhancedComponent enhancedComponent)
    {
        _enhancedComponent = enhancedComponent;
    }
    
    /**
	 * @see net.sf.tapestry.event.PageDetachListener#pageDetached(PageEvent)
	 */
	public void pageDetached(PageEvent event)
	{
        _enhancedComponent.resetParametersCache();
	}

}

--- NEW FILE: EnhancedComponentTemplate.java ---
package net.sf.tapestry.pageload;

import net.sf.tapestry.AbstractComponent;
import net.sf.tapestry.BaseComponent;
import net.sf.tapestry.IBinding;
import net.sf.tapestry.IMarkupWriter;
import net.sf.tapestry.IRequestCycle;
import net.sf.tapestry.RequestCycleException;
import net.sf.tapestry.event.PageDetachListener;
import net.sf.tapestry.event.PageEvent;

/**
 * @author mindbridge
 *
 */
public class EnhancedComponentTemplate extends BaseComponent 
    implements IEnhancedComponent
{
    private Object _$templateParameterValue;
    private boolean _$templateParameterCached;

    public EnhancedComponentTemplate()
    {
        resetParametersCache();
    }

    /**
	 * @see net.sf.tapestry.AbstractComponent#finishLoad()
	 */
	protected void finishLoad()
	{
		super.finishLoad();
        EnhancedComponentDetachListener detachListener = 
            new EnhancedComponentDetachListener(this);
        getPage().addPageDetachListener(detachListener);
	}

    public void resetParametersCache()
    {
        _$templateParameterCached = false;
    }

    public Object get$TemplateParameter()
    {
        if (!_$templateParameterCached) {
            IBinding binding = getBinding("$TemplateParameter");
            if (binding != null)
                _$templateParameterValue = binding.getObject();
            _$templateParameterCached = true;
        }
        return _$templateParameterValue;
    }
    
    public void set$TemplateParameter(Object value)
    {
        _$templateParameterValue = value;
        IBinding binding = getBinding("$TemplateParameter");
        if (binding != null)
            binding.setObject(value);
        _$templateParameterCached = true;
    }
}


--- NEW FILE: IEnhancedComponent.java ---
package net.sf.tapestry.pageload;

/**
 * @author mindbridge
 *
 */
public interface IEnhancedComponent
{
    void resetParametersCache();
}

--- NEW FILE: ComponentClassLoaderException.java ---
package net.sf.tapestry.pageload;

/**
 * @author mindbridge
 *
 */
public class ComponentClassLoaderException extends Exception
{
    

	/**
	 * Constructor for ComponentClassLoaderException.
	 */
	public ComponentClassLoaderException()
	{
		super();
	}

	/**
	 * Constructor for ComponentClassLoaderException.
	 * @param message
	 */
	public ComponentClassLoaderException(String message)
	{
		super(message);
	}

	/**
	 * Constructor for ComponentClassLoaderException.
	 * @param message
	 * @param cause
	 */
	public ComponentClassLoaderException(String message, Throwable cause)
	{
		super(message, cause);
	}

	/**
	 * Constructor for ComponentClassLoaderException.
	 * @param cause
	 */
	public ComponentClassLoaderException(Throwable cause)
	{
		super(cause);
	}

}

--- NEW FILE: ComponentClassLoader.java ---
package net.sf.tapestry.pageload;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sf.tapestry.DefaultResourceResolver;
import net.sf.tapestry.IResourceResolver;
import net.sf.tapestry.parse.SpecificationParser;
import net.sf.tapestry.spec.ComponentSpecification;
import net.sf.tapestry.spec.Direction;
import net.sf.tapestry.spec.ParameterSpecification;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantClass;
import org.apache.bcel.classfile.ConstantFieldref;
import org.apache.bcel.classfile.ConstantNameAndType;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.ConstantString;
import org.apache.bcel.classfile.ConstantUtf8;
import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.FieldInstruction;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.LDC;
import org.apache.bcel.generic.TargetLostException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author mindbridge
 *
 */
public class ComponentClassLoader extends ClassLoader
{
	private static final Log LOG =
		LogFactory.getLog(ComponentClassLoader.class);

	private static final String TEMPLATE_CLASS_NAME =
		EnhancedComponentTemplate.class.getName();

	private static final String TEMPLATE_VALUE_FIELD =
		"_$templateParameterValue";
	private static final String TEMPLATE_CACHED_FIELD =
		"_$templateParameterCached";
	private static final String TEMPLATE_RESET_METHOD = "resetParametersCache";
	private static final String TEMPLATE_GET_METHOD = "get$TemplateParameter";
	private static final String TEMPLATE_SET_METHOD = "set$TemplateParameter";
	private static final String TEMPLATE_PROPERTY_NAME = "$TemplateParameter";

	private static final String CONTEXT_CONSTANTS_KEY = "constants";
	private static final String CONTEXT_FIELDS_KEY = "fields";
	private static final String CONTEXT_METHODS_KEY = "methods";
	private static final String CONTEXT_VALUE_FIELD_KEY = "valueField";
	private static final String CONTEXT_CACHED_FIELD_KEY = "cachedField";
	private static final String CONTEXT_RESET_METHOD_KEY = "resetMethod";
	private static final String CONTEXT_RESET_CODE_KEY = "resetCode";
	private static final String CONTEXT_RESET_TEMPLATE_KEY = "resetTemplate";
	private static final String CONTEXT_GET_METHOD_KEY = "getMethod";
	private static final String CONTEXT_SET_METHOD_KEY = "setMethod";

	private IResourceResolver _resolver;
	private byte[] _templateClassData;

	public ComponentClassLoader(IResourceResolver resolver)
	{
		setResolver(resolver);
		setTemplateClassData(loadClassData(TEMPLATE_CLASS_NAME));
	}

	/**
	 * @see java.lang.ClassLoader#loadClass(String)
	 */
	public Class loadClass(String name) throws ClassNotFoundException
	{
		//System.out.println("loading class: " + name);
		return getResolver().findClass(name);
	}

	/**
	 * Returns the resolver.
	 * @return IResourceResolver
	 */
	public IResourceResolver getResolver()
	{
		return _resolver;
	}

	/**
	 * Sets the resolver.
	 * @param resolver The resolver to set
	 */
	public void setResolver(IResourceResolver resolver)
	{
		_resolver = resolver;
	}

	/**
	 * Returns the templateClassData.
	 * @return byte[]
	 */
	protected byte[] getTemplateClassData()
	{
		return _templateClassData;
	}

	/**
	 * Sets the templateClassData.
	 * @param templateClassData The templateClassData to set
	 */
	protected void setTemplateClassData(byte[] templateClassData)
	{
		_templateClassData = templateClassData;
	}

	public Class findComponentClass(ComponentSpecification spec)
		throws ComponentClassLoaderException
	{
		String className = spec.getComponentClassName();

		Class originalClass = getResolver().findClass(className);

		// check whether enhancement is necessary
		if (getTemplateClassData() == null)
			return originalClass;

		List cachedParameters = getCachedParameters(spec);
		//if (cachedParameters.isEmpty())
		//    return originalClass;

		// okay, enhance
		Class componentClass =
			generateComponentClass(originalClass, cachedParameters);

		return componentClass;
	}

	protected List getCachedParameters(ComponentSpecification spec)
	{
		ArrayList cachedParameters = new ArrayList();

		List parameterNames = spec.getParameterNames();
		int parameterCount = parameterNames.size();
		for (int i = 0; i < parameterCount; i++)
		{
			ParameterSpecification paramSpec =
				spec.getParameter((String) parameterNames.get(i));
			Direction direction = paramSpec.getDirection();
			if (direction.equals(Direction.CACHED))
				cachedParameters.add(paramSpec);
		}

		return cachedParameters;
	}

	protected Class generateComponentClass(
		Class originalClass,
		List cachedParameters)
		throws ComponentClassLoaderException
	{
		try
		{
			JavaClass javaClass;
			try
			{
				javaClass = loadTemplate(originalClass);
			}
			catch (ClassFormatError e)
			{
				LOG.error("Cannot parse template class", e);
				throw new ComponentClassLoaderException(
					"Cannot parse template class",
					e);
			}

			Map context = createClassContext(javaClass);

			updateCommonTemplateData(javaClass, context, originalClass);

			int cachedParametersCount = cachedParameters.size();
			for (int i = 0; i < cachedParametersCount; i++)
			{
				ParameterSpecification paramSpec =
					(ParameterSpecification) cachedParameters.get(i);
				updateParameterTemplateData(
					javaClass,
					context,
					originalClass,
					paramSpec);
			}

			applyClassContext(javaClass, context);

			System.out.println(javaClass.toString());

			System.out.println("--- constructor:");
			Method initMethod = findClassMethod(javaClass, "<init>");
			InstructionList il =
				new InstructionList(initMethod.getCode().getCode());
			printInstructions(il.getStart());

			ByteArrayOutputStream bouts = new ByteArrayOutputStream();
			javaClass.dump(bouts);
			byte[] classData = bouts.toByteArray();

			Class enhancedClass =
				defineClass(null, classData, 0, classData.length);

			return enhancedClass;
		}
		catch (ClassFormatError e)
		{
			LOG.error("Error in class generation", e);
			throw new ComponentClassLoaderException(
				"Error in class generation",
				e);
		}
		catch (IOException e)
		{
			LOG.error("Cannot load template class", e);
			return null;
		}
	}

	protected JavaClass loadTemplate(Class originalClass)
		throws ClassFormatError, IOException
	{
		ByteArrayInputStream ins =
			new ByteArrayInputStream(getTemplateClassData());
		ClassParser classParser =
			new ClassParser(
				ins,
				fileNameFromClassName(originalClass.getName()));
		return classParser.parse();
	}

	/**
	 * Loads the class file into a byte array.
	 * @param className
	 * @return byte[]
	 */
	protected byte[] loadClassData(String className)
	{
		String classPath = fileNameFromClassName(className);
		try
		{
			URL classUrl = getResolver().getResource(classPath);
			InputStream ins = classUrl.openStream();
			ByteArrayOutputStream outs = new ByteArrayOutputStream();

			int len = 0;
			byte[] buffer = new byte[8192];
			while ((len = ins.read(buffer)) > 0)
				outs.write(buffer, 0, len);

			byte[] classData = outs.toByteArray();
			ins.close();
			outs.close();

			return classData;
		}
		catch (IOException e)
		{
			// NEED TO LOCALIZE MESSAGE!
			LOG.error("Cannot load template class data", e);
			return null;
		}
	}

	protected Map createClassContext(JavaClass javaClass)
		throws ComponentClassLoaderException
	{
		Map context = new HashMap();

		// constants to add
		ConstantPool constantPool = javaClass.getConstantPool();
		Constant[] constants = constantPool.getConstantPool();
		List constantList = Arrays.asList(constants);
		ArrayList constantArrayList = new ArrayList(constantList);
		context.put(CONTEXT_CONSTANTS_KEY, constantArrayList);

		// list of fields to update
		List fieldsList = Arrays.asList(javaClass.getFields());
		context.put(CONTEXT_FIELDS_KEY, new ArrayList(fieldsList));

		// list of methods to update
		ArrayList methodList =
			new ArrayList(Arrays.asList(javaClass.getMethods()));
		context.put(CONTEXT_METHODS_KEY, methodList);

		// field templates to use for creation of new fields
		Field valueField = findClassField(javaClass, TEMPLATE_VALUE_FIELD);
		if (valueField == null)
			throw new ComponentClassLoaderException(
				"Invalid template: cannot find field " + TEMPLATE_VALUE_FIELD);
		context.put(CONTEXT_VALUE_FIELD_KEY, valueField);

		Field cachedField = findClassField(javaClass, TEMPLATE_CACHED_FIELD);
		if (valueField == null)
			throw new ComponentClassLoaderException(
				"Invalid template: cannot find field " + TEMPLATE_CACHED_FIELD);
		context.put(CONTEXT_CACHED_FIELD_KEY, cachedField);

		// reset method body to update
		Method resetMethod = findClassMethod(javaClass, TEMPLATE_RESET_METHOD);
		if (resetMethod == null)
			throw new ComponentClassLoaderException(
				"Invalid template: cannot find method "
					+ TEMPLATE_RESET_METHOD);
		context.put(CONTEXT_RESET_METHOD_KEY, resetMethod);

		InstructionList resetMethodInstructionList =
			new InstructionList(resetMethod.getCode().getCode());
		context.put(CONTEXT_RESET_CODE_KEY, resetMethodInstructionList);

		// reset template
		try
		{
			InstructionList resetMethodTemplateList =
				new InstructionList(resetMethod.getCode().getCode());
			resetMethodTemplateList.delete(resetMethodTemplateList.getEnd());
			context.put(CONTEXT_RESET_TEMPLATE_KEY, resetMethodTemplateList);
		}
		catch (TargetLostException e)
		{
			throw new ComponentClassLoaderException(e);
		}

		// get method template
		Method getMethod = findClassMethod(javaClass, TEMPLATE_GET_METHOD);
		if (getMethod == null)
			throw new ComponentClassLoaderException(
				"Invalid template: cannot find method " + TEMPLATE_GET_METHOD);
		context.put(CONTEXT_GET_METHOD_KEY, getMethod);

		// set method template
		Method setMethod = findClassMethod(javaClass, TEMPLATE_SET_METHOD);
		if (setMethod == null)
			throw new ComponentClassLoaderException(
				"Invalid template: cannot find method " + TEMPLATE_SET_METHOD);
		context.put(CONTEXT_SET_METHOD_KEY, setMethod);

		return context;
	}

	protected void applyClassContext(JavaClass javaClass, Map context)
	{
		// update constants
		ConstantPool constantPool = javaClass.getConstantPool();
		List constantList = (List) context.get(CONTEXT_CONSTANTS_KEY);
		int i = 0;
		for (Iterator it = constantList.iterator(); it.hasNext();)
		{
			Object element = (Object) it.next();
			//System.out.println("[" + i + "] " + element);
			i++;
		}
		Constant[] constants =
			(Constant[]) constantList.toArray(
				new Constant[constantList.size()]);
		constantPool.setConstantPool(constants);

		// update fields
		List fieldsList = (List) context.get(CONTEXT_FIELDS_KEY);
		Field[] fields =
			(Field[]) fieldsList.toArray(new Field[fieldsList.size()]);
		javaClass.setFields(fields);

		// update methods
		List methodList = (List) context.get(CONTEXT_METHODS_KEY);
		Method[] methods =
			(Method[]) methodList.toArray(new Method[methodList.size()]);
		javaClass.setMethods(methods);

		/*
		// update reset method
		Method resetMethod = (Method) context.get(CONTEXT_RESET_METHOD_KEY);
		InstructionList resetMethodInstructionList =
			(InstructionList) context.get(CONTEXT_RESET_CODE_KEY);
		byte[] code = resetMethodInstructionList.getByteCode();
		resetMethod.getCode().setCode(code);
		*/

		Method getMethod = findClassMethod(javaClass, TEMPLATE_GET_METHOD);

		InstructionList resetMethodInstructionList =
			new InstructionList(getMethod.getCode().getCode());
		printInstructions(resetMethodInstructionList.getStart());
	}

	protected void updateCommonTemplateData(
		JavaClass javaClass,
		Map context,
		Class originalClass)
	{
		String originalClassName = originalClass.getName();

		// generate a unique class name
		String componentClassName =
			javaClass.getClassName()
				+ "$"
				+ originalClassName.replace('.', '$');

		// do some surgery here

		String convertedClassName = componentClassName.replace('.', '/');
		javaClass.setClassName(componentClassName);
		updateClassConstant(
			context,
			javaClass.getClassNameIndex(),
			convertedClassName);

		String convertedSuperclassName = originalClassName.replace('.', '/');
		javaClass.setSuperclassName(originalClassName);
		updateClassConstant(
			context,
			javaClass.getSuperclassNameIndex(),
			convertedSuperclassName);
	}

	protected void updateClassConstant(
		Map context,
		int index,
		String className)
	{
		List constantList = (List) context.get(CONTEXT_CONSTANTS_KEY);
		ConstantClass classConstant = (ConstantClass) constantList.get(index);
		ConstantUtf8 classNameConstant =
			(ConstantUtf8) constantList.get(classConstant.getNameIndex());
		classNameConstant.setBytes(className);
	}

	protected void updateParameterTemplateData(
		JavaClass javaClass,
		Map context,
		Class originalClass,
		ParameterSpecification paramSpec)
		throws ComponentClassLoaderException
	{
		// check if a getter exists
		String propName = paramSpec.getPropertyName();
		String propTypeName = getPropTypeName(originalClass, propName);

		Map fieldMapping = new HashMap();
		Map constantMapping = new HashMap();

		addPropertyFields(
			javaClass,
			context,
			propName,
			propTypeName,
			fieldMapping,
			constantMapping);

		// add field initialization
		addFieldReset(
			javaClass,
			context,
			propName,
			fieldMapping,
			constantMapping);

		// add getter method
		addGetMethod(
			javaClass,
			context,
			propName,
			fieldMapping,
			constantMapping);

		// check if a setter exists
		// add setter method
	}

	protected String getPropTypeName(Class originalClass, String propName)
		throws ComponentClassLoaderException
	{
		java.lang.reflect.Method propMethod =
			findGetMethod(originalClass, propName);

		if (propMethod == null)
			throw new ComponentClassLoaderException(
				"No get method for property " + propName + " has been defined");

		if (propMethod.getModifiers() != (Modifier.PUBLIC | Modifier.ABSTRACT))
			throw new ComponentClassLoaderException(
				"Property "
					+ propName
					+ " is defined as 'cached', but its get method is not 'public abstract'");

		Class returnType = propMethod.getReturnType();
		String propTypeName = returnType.getName();
		if (!returnType.isPrimitive() && !returnType.isArray())
			propTypeName = "L" + propTypeName.replace('.', '/') + ";";

		return propTypeName;
	}

	protected void addPropertyFields(
		JavaClass javaClass,
		Map context,
		String propName,
		String propTypeName,
		Map fieldMapping,
		Map constantMapping)
	{
		// add member variables
		String propValueFieldName = "_$" + propName + "Value";
		Field templateValueField = (Field) context.get(CONTEXT_VALUE_FIELD_KEY);
		int valueFieldId =
			addClassField(
				javaClass,
				context,
				propValueFieldName,
				propTypeName,
				templateValueField);

		String propCachedFieldName = "_$" + propName + "Cached";
		Field templateCachedField =
			(Field) context.get(CONTEXT_CACHED_FIELD_KEY);
		int cachedFieldId =
			addClassField(
				javaClass,
				context,
				propCachedFieldName,
				"Z",
				templateCachedField);

		fieldMapping.put(
			new Integer(templateValueField.getNameIndex()),
			new Integer(valueFieldId));
		fieldMapping.put(
			new Integer(templateCachedField.getNameIndex()),
			new Integer(cachedFieldId));

		int templateParamId =
			findStringConstant(javaClass, TEMPLATE_PROPERTY_NAME);
		int paramId = addStringConstant(context, propName);

		constantMapping.put(new Integer(templateParamId), new Integer(paramId));
	}

	protected String fileNameFromClassName(String className)
	{
		return className.replace('.', '/') + ".class";
	}

	protected java.lang.reflect.Method findGetMethod(
		Class originalClass,
		String propName)
	{
		try
		{
			String getterName = getGetMethodName(propName);
			java.lang.reflect.Method getterMethod =
				originalClass.getMethod(getterName, new Class[0]);

			// another way to do it (but slower)
			//OgnlContext ognlContext = new OgnlContext();
			//Method getterMethod = OgnlRuntime.getGetMethod(ognlContext, originalClass, propName);

			return getterMethod;
		}
		catch (NoSuchMethodException e)
		{
			return null;
		}
	}

	protected String getGetMethodName(String propName)
	{
		String getMethodName =
			"get"
				+ propName.substring(0, 1).toUpperCase()
				+ propName.substring(1);
		return getMethodName;
	}

	protected String getSetMethodName(String propName)
	{
		String getMethodName =
			"set"
				+ propName.substring(0, 1).toUpperCase()
				+ propName.substring(1);
		return getMethodName;
	}

	protected Field findClassField(JavaClass javaClass, String fieldName)
	{
		ConstantPool constantPool = javaClass.getConstantPool();
		Field[] classFields = javaClass.getFields();
		for (int i = 0; i < classFields.length; i++)
		{
			Field field = classFields[i];
			if (field.getName().equals(fieldName))
				return field;
		}

		return null;
	}

	protected Method findClassMethod(JavaClass javaClass, String methodName)
	{
		Method[] classMethods = javaClass.getMethods();
		for (int i = 0; i < classMethods.length; i++)
		{
			Method method = classMethods[i];
			if (method.getName().equals(methodName))
				return method;
		}

		return null;
	}

	protected int findStringConstant(JavaClass javaClass, String constValue)
	{
		ConstantPool constantPool = javaClass.getConstantPool();
		int len = constantPool.getLength();
		for (int i = 0; i < len; i++)
		{
			Constant constant = constantPool.getConstant(i);
			if (constant instanceof ConstantString)
			{
				ConstantString stringConstant = (ConstantString) constant;
				String constantValue =
					(String) stringConstant.getConstantValue(constantPool);
				if (constValue.equals(constantValue))
					return i;
			}
		}

		return -1;
	}

	protected int addUtfConstant(Map context, String constant)
	{
		List constantList = (List) context.get(CONTEXT_CONSTANTS_KEY);
		constantList.add(new ConstantUtf8(constant));
		return constantList.size() - 1;
	}

	protected int addStringConstant(Map context, String constant)
	{
		int utfId = addUtfConstant(context, constant);

		List constantList = (List) context.get(CONTEXT_CONSTANTS_KEY);
		constantList.add(new ConstantString(utfId));
		return constantList.size() - 1;
	}

	protected int addNameAndTypeConstant(Map context, String name, String type)
	{
		int nameId = addUtfConstant(context, name);
		int typeId = addUtfConstant(context, type);

		List constantList = (List) context.get(CONTEXT_CONSTANTS_KEY);
		constantList.add(new ConstantNameAndType(nameId, typeId));
		return constantList.size() - 1;
	}

	protected int addFieldRefConstant(
		JavaClass javaClass,
		Map context,
		String name,
		String type)
	{
		int nameAndTypeId = addNameAndTypeConstant(context, name, type);

		List constantList = (List) context.get(CONTEXT_CONSTANTS_KEY);
		constantList.add(
			new ConstantFieldref(javaClass.getClassNameIndex(), nameAndTypeId));
		return constantList.size() - 1;
	}

	protected int addClassConstant(Map context, String constant)
	{
		int utfId = addUtfConstant(context, constant);

		List constantList = (List) context.get(CONTEXT_CONSTANTS_KEY);
		constantList.add(new ConstantClass(utfId));
		return constantList.size() - 1;
	}

	protected int addClassField(
		JavaClass javaClass,
		Map context,
		String fieldName,
		String typeName,
		Field templateField)
	{
		List constantList = (List) context.get(CONTEXT_CONSTANTS_KEY);

		int fieldId =
			addFieldRefConstant(javaClass, context, fieldName, typeName);
		ConstantFieldref fieldConst =
			(ConstantFieldref) constantList.get(fieldId);
		ConstantNameAndType nameAndTypeConst =
			(ConstantNameAndType) constantList.get(
				fieldConst.getNameAndTypeIndex());

		int nameId = nameAndTypeConst.getNameIndex();
		int typeId = nameAndTypeConst.getSignatureIndex();

		Field field = new Field(templateField);
		field.setNameIndex(nameId);
		field.setSignatureIndex(typeId);

		List fieldsList = (List) context.get(CONTEXT_FIELDS_KEY);
		fieldsList.add(field);

		return fieldId;
	}

	protected void addFieldReset(
		JavaClass javaClass,
		Map context,
		String propName,
		Map fieldMapping,
		Map constantMapping)
	{
		InstructionList resetMethodTemplateList =
			(InstructionList) context.get(CONTEXT_RESET_TEMPLATE_KEY);
		InstructionList resetList = resetMethodTemplateList.copy();

		modifyTemplateInstructions(
			javaClass,
			resetList,
			fieldMapping,
			constantMapping);

		// Insert before the return
		InstructionList resetMethodList =
			(InstructionList) context.get(CONTEXT_RESET_CODE_KEY);
		resetMethodList.insert(resetMethodList.getEnd(), resetList);
	}

	protected void addMethod(Map context, Method method)
	{
		List methodList = (List) context.get(CONTEXT_METHODS_KEY);
		methodList.add(method);
	}

	protected void addGetMethod(
		JavaClass javaClass,
		Map context,
		String propName,
		Map fieldMapping,
		Map constantMapping)
	{
		Method templateGetMethod = (Method) context.get(CONTEXT_GET_METHOD_KEY);
		InstructionList getTemplateInstructionList =
			new InstructionList(templateGetMethod.getCode().getCode());

		InstructionList getMethodInstructionList =
			getTemplateInstructionList.copy();

		//System.out.println("get method instructions:");            
		//printInstructions(getMethodInstructionList.getStart());

		modifyTemplateInstructions(
			javaClass,
			getMethodInstructionList,
			fieldMapping,
			constantMapping);

		//System.out.println("new method instructions:");            
		//printInstructions(getMethodInstructionList.getStart());

		String getMethodName = getGetMethodName(propName);
		int getMethodNameId = addUtfConstant(context, getMethodName);

		Method propertyGetMethod =
			templateGetMethod.copy(javaClass.getConstantPool());
		propertyGetMethod.setNameIndex(getMethodNameId);
		propertyGetMethod.getCode().setCode(
			getMethodInstructionList.getByteCode());

		addMethod(context, propertyGetMethod);
	}

	protected void modifyTemplateInstructions(
		JavaClass javaClass,
		InstructionList instList,
		Map fieldMapping,
		Map constantMapping)
	{
		ConstantPool constantPool = javaClass.getConstantPool();

		InstructionHandle handle = instList.getStart();
		while (handle != null)
		{
			Instruction inst = handle.getInstruction();

			if (inst instanceof FieldInstruction)
			{
				FieldInstruction fieldInst = (FieldInstruction) inst;
				int fieldId = fieldInst.getIndex();
				ConstantFieldref fieldConst =
					(ConstantFieldref) constantPool.getConstant(fieldId);
				ConstantNameAndType nameAndTypeConst =
					(ConstantNameAndType) constantPool.getConstant(
						fieldConst.getNameAndTypeIndex());

				Integer newFieldId =
					(Integer) fieldMapping.get(
						new Integer(nameAndTypeConst.getNameIndex()));
				if (newFieldId != null)
					fieldInst.setIndex(newFieldId.intValue());
			}

			if (inst instanceof LDC)
			{
				LDC ldcInstruction = (LDC) inst;
				Integer newConstId =
					(Integer) constantMapping.get(
						new Integer(ldcInstruction.getIndex()));
				if (newConstId != null)
					ldcInstruction.setIndex(newConstId.intValue());
			}

			handle = handle.getNext();
		}

	}

	protected void printInstructions(InstructionHandle handle)
	{
		while (handle != null)
		{
			Instruction inst = handle.getInstruction();
			System.out.println(inst);
			handle = handle.getNext();
		}
	}

	public static void main(String[] arrArgs)
	{
		try
		{
			IResourceResolver res = new DefaultResourceResolver();
			ComponentClassLoader loader = new ComponentClassLoader(res);

			String resPath =
				"net/sf/tapestry/contrib/table/components/TableView.jwc";
			SpecificationParser parser = new SpecificationParser();
			ComponentSpecification spec =
				parser.parseComponentSpecification(
					res.getResource(resPath).openStream(),
					resPath);

			//Class newClass = loader.findComponentClass(spec);
			//TableView testObj = (TableView) newClass.newInstance();

			System.out.println("Done");
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
}



-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.