package com.googlecode.tawus.internal.transform; import org.apache.tapestry5.model.MutableComponentModel; import org.apache.tapestry5.plastic.FieldHandle; import org.apache.tapestry5.plastic.MethodAdvice; import org.apache.tapestry5.plastic.MethodDescription; import org.apache.tapestry5.plastic.MethodInvocation; import org.apache.tapestry5.plastic.PlasticClass; import org.apache.tapestry5.plastic.PlasticField; import org.apache.tapestry5.plastic.PlasticMethod; import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2; import org.apache.tapestry5.services.transform.TransformationSupport; import com.googlecode.tawus.EntitySelectModel; import com.googlecode.tawus.EntityValueEncoder; import com.googlecode.tawus.SearchCriteria; import com.googlecode.tawus.annotations.InjectEntitySelectSupport; import com.googlecode.tawus.services.EntityDAOLocator; public class InjectEntitySelectSupportWorker implements ComponentClassTransformWorker2 { private EntityDAOLocator locator; public InjectEntitySelectSupportWorker(final EntityDAOLocator locator) { this.locator = locator; } public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model) { for(final PlasticField field : plasticClass.getFieldsWithAnnotation(InjectEntitySelectSupport.class)) { addModelMethod(plasticClass, field); addEncoderMethod(plasticClass, field); } } void addEncoderMethod(PlasticClass plasticClass, PlasticField field) { String name = stripCriteriaIfPresent(field.getName()); PlasticMethod method = createEncoderMethod(plasticClass, name); PlasticField encoderField = plasticClass.introduceField(EntityValueEncoder.class, getFieldName(name, "Encoder")); final FieldHandle handle = field.getHandle(); final FieldHandle encoderHandle = encoderField.getHandle(); method.addAdvice(new MethodAdvice() { @SuppressWarnings({ "unchecked", "rawtypes" }) public void advise(MethodInvocation invocation) { Object instance = invocation.getInstance(); SearchCriteria criteria = (SearchCriteria) handle.get(instance); if(criteria == null) { throw new RuntimeException("SearchCriteria cannot be null when annotated with @" + InjectEntitySelectSupport.class.getSimpleName()); } if(encoderHandle.get(instance) == null) { encoderHandle.set(instance, new EntityValueEncoder(locator.get(criteria.getType()))); } invocation.setReturnValue(encoderHandle.get(instance)); } }); } private PlasticMethod createEncoderMethod(PlasticClass plasticClass, String name) { String methodName = "get" + capitalize(name) + "Encoder"; MethodDescription description = new MethodDescription(EntityValueEncoder.class.getName(), methodName); return plasticClass.introduceMethod(description); } void addModelMethod(PlasticClass plasticClass, PlasticField field) { String name = stripCriteriaIfPresent(field.getName()); PlasticMethod method = createModelMethod(plasticClass, name); PlasticField selectField = plasticClass.introduceField(EntitySelectModel.class, getFieldName(name, "Model")); final FieldHandle handle = field.getHandle(); final FieldHandle selectHandle = selectField.getHandle(); method.addAdvice(new MethodAdvice() { @SuppressWarnings({ "unchecked", "rawtypes" }) public void advise(MethodInvocation invocation) { Object instance = invocation.getInstance(); SearchCriteria criteria = (SearchCriteria) handle.get(instance); if(criteria == null) { throw new RuntimeException("SearchCriteria cannot be null when annotated with @" + InjectEntitySelectSupport.class.getSimpleName()); } if(selectHandle.get(instance) == null) { selectHandle.set(instance, new EntitySelectModel(locator.get(criteria.getType()).list(criteria))); } invocation.setReturnValue(selectHandle.get(instance)); } }); } private PlasticMethod createModelMethod(PlasticClass plasticClass, String name) { String methodName = "get" + capitalize(name) + "Model"; MethodDescription description = new MethodDescription(EntitySelectModel.class.getName(), methodName); return plasticClass.introduceMethod(description); } String stripCriteriaIfPresent(String name) { if(name.endsWith("Criteria") && !name.startsWith("Criteria")) { name = name.replaceAll("Criteria$", ""); } return name; } private String capitalize(String name) { return Character.toUpperCase(name.charAt(0)) + name.substring(1); } private String getFieldName(String name, String prefix) { return "_$" + name + prefix; } }