Of course, but since I am not very good at javassit, my implementation may be 
ugly and a bit long. Anyone please consummate it.
Like PageActivationContext, I introduce an PageActivationUnitWorker.
The key part is to collect the param fields and add the param map to page class 
in runtime. onActivate and onPassivate would use this map to set value or 
retrieve value.

1. For annotation:

@Target(FIELD)
@Documented
@Retention(RUNTIME)
public @interface PageActivationUnit {
 String value() default "";
}

2. For worker:
public class PageActivationUnitWorker implements ComponentClassTransformWorker {

 private TypeCoercer _typeCoercer;
 
 public PageActivationUnitWorker(TypeCoercer typeCoercer) {
  this._typeCoercer = typeCoercer;
 }
 
 public void transform(ClassTransformation transformation, 
MutableComponentModel model) {
  List<String> fieldNames = 
transformation.findFieldsWithAnnotation(PageActivationUnit.class);
  
  if (fieldNames != null && fieldNames.size() > 0) {
   
   Map<String, String> fieldParamMap = new HashMap<String, String>();
   for (String fieldName : fieldNames) {
    PageActivationUnit annotation = transformation.getFieldAnnotation(fieldName,
      PageActivationUnit.class);
    fieldParamMap.put(fieldName, getParameterName(fieldName, 
annotation.value()));
   }
   
   String typeCoercer = transformation.addInjectedField(TypeCoercer.class, 
"typeCoercer", _typeCoercer);
   
   TransformMethodSignature activate
         = new TransformMethodSignature(Modifier.PROTECTED | Modifier.FINAL, 
"boolean",
                                       "onActivate",
                                       new String[] 
{EventContext.class.getName()}, null);
   
   TransformMethodSignature passivate
             = new TransformMethodSignature(Modifier.PROTECTED | 
Modifier.FINAL, "java.lang.Object[]",
                                           "onPassivate",
                                           null, null);
   
   BodyBuilder activeBuilder = new BodyBuilder().begin();
   activeBuilder.addln("java.util.Map keyValueMap = new java.util.HashMap();");
   activeBuilder.add("for (int i = 0; i < $1.getCount(); i++)");
   activeBuilder.begin();
   activeBuilder.addln("String []keyValue = ((String)$1.get(String.class, 
i)).split(\"-\");");
   activeBuilder.addln("String key = keyValue[0];");
   activeBuilder.addln("String value = (keyValue.length > 1) ? keyValue[1] : 
null;");
   activeBuilder.addln("keyValueMap.put(key, value);");
   activeBuilder.end();
   // end for
   for (int i = 0, size = fieldNames.size(); i < size; i++) {
    String fieldName = fieldNames.get(i);
    String fieldType = transformation.getFieldType(fieldName);
    activeBuilder.addln("String fieldValue=(String)keyValueMap.get(\"%s\");", 
fieldParamMap.get(fieldName));
    activeBuilder.addln("if (fieldValue != null) {");
    activeBuilder.addln("%s=(%s)%s.coerce(fieldValue, Class.forName(\"%s\"));", 
fieldName, fieldType, typeCoercer, fieldType);
    activeBuilder.addln("}");
   }
   activeBuilder.addln("return true;");
   // end method body
   activeBuilder.end();
     
   BodyBuilder deactiveBuilder = new BodyBuilder().begin();
   for (int i = 0, size = fieldNames.size(); i < size; i++) {
    String fieldName = fieldNames.get(i);
    
    if (i == size - 1) {
     deactiveBuilder.add("\"%s-\" +  (%s != null ? (String)%s.coerce(%s, 
String.class) : \"\")", fieldParamMap.get(fieldName), fieldName, typeCoercer, 
fieldName);
    } else {
     deactiveBuilder.add("\"%s-\" +  (%s != null ? (String)%s.coerce(%s, 
String.class) : \"\"),", fieldParamMap.get(fieldName), fieldName, typeCoercer, 
fieldName);
    }
   }
   deactiveBuilder.end();
   
   transformation.addTransformedMethod(activate, activeBuilder.toString());
   transformation.addTransformedMethod(passivate, "return new Object[]" + 
deactiveBuilder.toString() + ";");
  }
 }

 private String getParameterName(String fieldName, String annotatedName)
    {
        if (InternalUtils.isNonBlank(annotatedName)) return annotatedName;

        return InternalUtils.stripMemberName(fieldName);
    }
}

3. In app module

public static void contributeComponentClassTransformWorker(
            OrderedConfiguration<ComponentClassTransformWorker> configuration, 
TypeCoercer typeCoercer) {
     configuration.add("PageActivationUnit", new 
PageActivationUnitWorker(typeCoercer), "before:OnEvent");
    }

That's all.
One disadvantage is that you can't use primitive type for param field, so use 
Integer instead of int.

DH
http://www.gaonline.com.cn
----- Original Message ----- 
From: "Inge Solvoll" 
To: "Tapestry users" <users@tapestry.apache.org>
Sent: Tuesday, December 08, 2009 4:14 PM
Subject: Re: Best practice for initializing page to default context


> Would it be possible for you to share that code with us? I don't necessarily
> want to use that approach, but it would be very helpful to see how you
> implemented it.
> 
> Inge
> 
> On Tue, Dec 8, 2009 at 9:10 AM, DH <ningd...@gmail.com> wrote:
> 
>> Once I found it difficult too, and I never used  EventContext because I
>> think it is not better than multiple onActivate.
>>
>> Finally I wrote my own PageActivationContext called PageActivationUnit, the
>> difference is that PageActivationContext only can occur once, but
>> PageActivationUnit can be used in multiple fields.
>>
>> For example, a product search page, it has params like
>> category,keyword,pagesize,pageno,brand and so on. If using
>> PageActivationUnit, the java would be like:
>>
>> @PageActivationUnit
>> private Category category;
>>
>> @PageActivationUnit
>> private String keyword;
>>
>> @PageActivationUnit
>> private Integer pagesize;
>>
>> @PageActivationUnit
>> private Integer pageNo;
>>
>> @PageActivationUnit
>> private Brand brand;
>>
>> PageActivationUnit will handle all the activate and passivate event for me,
>> and the url requested would be like
>> '/searchpage/category-value/keyword-value/pagesize-10/pageNo-2/brand-value'.
>> Yes, I encode the field name in the url and its value in a pair.
>> Another advantage is if later another param 'orderBy' is added, I don't
>> have to change any code at all.
>>
>> DH
>> http://www.gaonline.com.cn
>>
>> ----- Original Message -----
>> From: "Kalle Korhonen"
>> To: "Tapestry users" <users@tapestry.apache.org>
>> Sent: Tuesday, December 08, 2009 2:22 PM
>> Subject: Best practice for initializing page to default context
>>
>>
>> > Most things in T5 are delightfully simple, but I find this
>> > surprisingly difficult: how to best initialize a page to default
>> > context (and redirect to it). Imagine you have a search & result page.
>> > If I access the page without any context I want all records to be
>> > displayed. In onActivate() without parameters I set the context to
>> > *all* and return this to redirect, then I query the database in
>> > setupRender() to initialize the data for the grid. However, sorting
>> > the grid will also cause a call to onActivate() without parameters,
>> > resetting my data to the default context. The parameter-less call to
>> > onActivate() would be harmless if I didn't do a redirect from
>> > onActivate() but then I cannot set the default context and redirect.
>> > In setupRender() I could decide whether redirect is needed or not but
>> > at that time, I'm already committed to rendering the request.
>> >
>> > Because events cause a parameterless onActivate()  call, I tend to
>> > reserve onActivate() for possible component/event initialization needs
>> > only and always link to pages with initial context already set. I also
>> > find it roughly impossible to use overloaded versions of onActivate()
>> > and subsequently, if my page has multiple entry points, I typically
>> > resort to implementing it in a single onActivate(EventContext
>> > eventContext) operation containing a big if-else clause. Since the
>> > activation context is anyway sent with an event request (as in
>> > ?t:ac=mycontext), rather than using the encoded context for rendering,
>> > wouldn't it be just simpler if that context was used for activating
>> > the page for the event request and the following redirect for
>> > rendering would just use whatever context onPassivate() returns? What
>> > do others think, how do you handle this?
>> >
>> > Kalle
>> >
>> > ---------------------------------------------------------------------
>> > To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
>> > For additional commands, e-mail: users-h...@tapestry.apache.org
>> >
>> >
>>
>

Reply via email to