You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2003/03/17 14:42:50 UTC
cvs commit: jakarta-tapestry/framework/src/org/apache/tapestry/enhance ComponentClassFactory.java
hlship 2003/03/17 05:42:50
Modified: framework/src/org/apache/tapestry/enhance
ComponentClassFactory.java
Log:
Correct for CVS hickup (revision 1.3 was corrupt).
Revision Changes Path
1.5 +293 -1 jakarta-tapestry/framework/src/org/apache/tapestry/enhance/ComponentClassFactory.java
Index: ComponentClassFactory.java
===================================================================
RCS file: /home/cvs/jakarta-tapestry/framework/src/org/apache/tapestry/enhance/ComponentClassFactory.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- ComponentClassFactory.java 17 Mar 2003 03:25:18 -0000 1.4
+++ ComponentClassFactory.java 17 Mar 2003 13:42:50 -0000 1.5
@@ -378,4 +378,296 @@
/**
* Checks to see that that class either doesn't provide the property, or does
- * but the accessor(s) are abstract.
\ No newline at end of file
+ * but the accessor(s) are abstract. Returns the name of the read accessor,
+ * or null if there is no such accessor (this is helpful if the beanClass
+ * defines a boolean property, where the name of the accessor may be isXXX or
+ * getXXX).
+ *
+ **/
+
+ protected String checkAccessors(String propertyName, Class propertyType)
+ {
+ PropertyDescriptor d = getPropertyDescriptor(propertyName);
+
+ if (d == null)
+ return null;
+
+ if (!d.getPropertyType().equals(propertyType))
+ throw new ApplicationRuntimeException(
+ Tapestry.getString(
+ "ComponentClassFactory.property-type-mismatch",
+ new Object[] {
+ _componentClass.getName(),
+ propertyName,
+ d.getPropertyType().getName(),
+ propertyType.getName()}));
+
+ Method m = d.getWriteMethod();
+
+ if (!isAbstract(m))
+ throw new ApplicationRuntimeException(
+ Tapestry.getString(
+ "ComponentClassFactory.non-abstract-write",
+ m.getDeclaringClass().getName(),
+ propertyName));
+
+ m = d.getReadMethod();
+
+ if (!isAbstract(m))
+ throw new ApplicationRuntimeException(
+ Tapestry.getString(
+ "ComponentClassFactory.non-abstract-read",
+ m.getDeclaringClass().getName(),
+ propertyName));
+
+ return m == null ? null : m.getName();
+ }
+
+ /**
+ * Given an arbitrary type, figures out the correct
+ * argument type (for fireObservedChange()) to use.
+ *
+ **/
+
+ protected Type convertToArgumentType(Type type)
+ {
+ if (type instanceof BasicType)
+ return type;
+
+ return Type.OBJECT;
+ }
+
+ protected void createMutator(
+ Type fieldType,
+ String fieldName,
+ String propertyName,
+ boolean isPersistent)
+ {
+ String methodName = buildMethodName("set", propertyName);
+
+ MethodFabricator mf = _classFabricator.createMethod(methodName);
+ mf.addArgument(fieldType, propertyName);
+
+ InstructionList il = mf.getInstructionList();
+ InstructionFactory factory = _classFabricator.getInstructionFactory();
+
+ il.append(factory.createThis());
+ il.append(factory.createLoad(fieldType, 1));
+ il.append(factory.createPutField(_subclassName, fieldName, fieldType));
+
+ // Persistent properties must invoke fireObservedChange
+
+ if (isPersistent)
+ {
+ il.append(factory.createThis());
+ il.append(new PUSH(_classFabricator.getConstantPool(), propertyName));
+ il.append(factory.createLoad(fieldType, 1));
+
+ Type argumentType = convertToArgumentType(fieldType);
+
+ il.append(
+ factory.createInvoke(
+ _subclassName,
+ "fireObservedChange",
+ Type.VOID,
+ new Type[] { Type.STRING, argumentType },
+ Constants.INVOKEVIRTUAL));
+ }
+
+ il.append(InstructionConstants.RETURN);
+
+ mf.commit();
+ }
+
+ protected void createAccessor(
+ Type fieldType,
+ String fieldName,
+ String propertyName,
+ String readMethodName)
+ {
+ String methodName =
+ readMethodName == null ? buildMethodName("get", propertyName) : readMethodName;
+
+ MethodFabricator mf =
+ _classFabricator.createMethod(Constants.ACC_PUBLIC, fieldType, methodName);
+
+ InstructionList il = mf.getInstructionList();
+ InstructionFactory factory = _classFabricator.getInstructionFactory();
+
+ il.append(factory.createThis());
+ il.append(factory.createGetField(_subclassName, fieldName, fieldType));
+ il.append(factory.createReturn(fieldType));
+
+ mf.commit();
+ }
+
+ /**
+ * Checks that the superclass provides
+ * either abstract accessors or none at all. Creates the file, creates
+ * the accessors, creates initialization code.
+ *
+ **/
+
+ protected void createProperty(
+ String propertyName,
+ String type,
+ boolean persistent,
+ Location location)
+ {
+ Class propertyType = convertPropertyType(type, location);
+
+ String readMethodName = checkAccessors(propertyName, propertyType);
+
+ String fieldName = "_$" + propertyName;
+
+ Type fieldType = getObjectType(type);
+
+ _classFabricator.addField(fieldType, fieldName);
+
+ createAccessor(fieldType, fieldName, propertyName, readMethodName);
+ createMutator(fieldType, fieldName, propertyName, persistent);
+ }
+
+ protected boolean isMissingProperty(String propertyName)
+ {
+ PropertyDescriptor pd = getPropertyDescriptor(propertyName);
+
+ return isAbstract(pd);
+ }
+
+ /**
+ * Creates a property for a connected
+ * parameter from a parameter specification.
+ *
+ **/
+
+ protected void createConnectedParameterProperty(ParameterSpecification ps)
+ {
+ if (ps.getDirection() == Direction.CUSTOM)
+ return;
+
+ String propertyName = ps.getPropertyName();
+
+ // Yes, but does it *need* a property created?
+
+ if (!isMissingProperty(propertyName))
+ return;
+
+ if (LOG.isDebugEnabled())
+ LOG.debug("Establishing connected parameter property " + propertyName);
+
+ createProperty(propertyName, ps.getType(), false, ps.getLocation());
+ }
+
+ /**
+ * Invoked to create a specified property.
+ *
+ **/
+
+ protected void createSpecifiedProperty(PropertySpecification ps)
+ {
+ String propertyName = ps.getName();
+
+ if (LOG.isDebugEnabled())
+ LOG.debug("Establishing specified property " + propertyName);
+
+ createProperty(propertyName, ps.getType(), ps.isPersistent(), ps.getLocation());
+ }
+
+ /**
+ * Invoked by {@link org.apache.tapestry.enhance.DefaultComponentClassEnhancer} to
+ * create, as a {@link org.apache.bcel.classfile.JavaClass}, an enahanced
+ * subclass of the component class. This means creating a default constructor,
+ * new fields, and new accessor and mutator methods. Properties are created
+ * for connected parameters, for all formal parameters (the binding property),
+ * and for all specified parameters (which may be transient or persistent).
+ *
+ **/
+
+ public JavaClass createEnhancedSubclass()
+ {
+ String startClassName = _componentClass.getName();
+
+ if (LOG.isDebugEnabled())
+ LOG.debug(
+ "Enhancing subclass of "
+ + startClassName
+ + " for "
+ + _specification.getSpecificationLocation());
+
+ _subclassName = startClassName + "$Enhance_" + _uid++;
+
+ _classFabricator = new ClassFabricator(_subclassName, startClassName);
+
+ _classFabricator.addDefaultConstructor();
+
+ createPropertySpecificationEnhancements();
+
+ createParameterEnhancements();
+
+ JavaClass result = _classFabricator.commit();
+
+ if (LOG.isDebugEnabled())
+ LOG.debug("Finished creating enhanced class " + _subclassName);
+
+ return result;
+ }
+
+ private void createParameterBindingProperty(String parameterName, Location location)
+ {
+ String propertyName = parameterName + Tapestry.PARAMETER_PROPERTY_NAME_SUFFIX;
+
+ if (!isMissingProperty(propertyName))
+ return;
+
+ if (LOG.isDebugEnabled())
+ LOG.debug("Establishing parameter binding property " + propertyName);
+
+ createProperty(propertyName, IBinding.class.getName(), false, location);
+ }
+
+ /**
+ * Creates any properties related to
+ * {@link org.apache.tapestry.spec.PropertySpecification property specifications}.
+ *
+ **/
+
+ protected void createPropertySpecificationEnhancements()
+ {
+ List names = _specification.getPropertySpecificationNames();
+ int count = names.size();
+
+ for (int i = 0; i < count; i++)
+ {
+ String name = (String) names.get(i);
+
+ PropertySpecification ps = _specification.getPropertySpecification(name);
+
+ createSpecifiedProperty(ps);
+ }
+ }
+
+ /**
+ * Creates new properties related to formal parameters. This is one
+ * property to store the binding, and a second property if the parameter
+ * is connected.
+ *
+ **/
+
+ protected void createParameterEnhancements()
+ {
+ List names = _specification.getParameterNames();
+ int count = names.size();
+
+ for (int i = 0; i < count; i++)
+ {
+ String name = (String) names.get(i);
+
+ ParameterSpecification ps = _specification.getParameter(name);
+
+ createParameterBindingProperty(name, ps.getLocation());
+
+ createConnectedParameterProperty(ps);
+ }
+ }
+}
\ No newline at end of file