[refactoring][beans] BeanData should be able to fork
----------------------------------------------------

                 Key: LABS-232
                 URL: https://issues.apache.org/jira/browse/LABS-232
             Project: Labs
          Issue Type: New Feature
          Components: Magma
    Affects Versions: Current
            Reporter: Simone Gianni
            Assignee: Simone Gianni
             Fix For: Future


Currently every class has one BeanData. This class holds all magma specific 
metadata about the class, giving access to PropertyInfo for each property. That 
sums up introspection results, annotations and so on. Every package that needs 
to add stuff will do it adding it to BeanData or PropertyInfo.

Also, all magma component communicate with the bean using a Handler. The 
Handler itself uses BeanData to perform property setting/getting, validation, 
formatting and the like.

Anyway, having a single representation of a class is limiting. There is the 
need to change this data depending on the current context. For example, a 
certain field could be visible or not depending on the role of the current 
user, or the view we want to offer. Also validation could change, making some 
properties required where they where not, or even adding temporary properties. 
Information currently held in this structure is very wide, and goes from 
validation to formatting to structural data (like, if it is or not persisted on 
the database).

Currently there is a system in place, called ViewCustomizer, which is able to 
modify dynamically part of it for a specific need, like hiding or expanding a 
property in a specific view. While this system works correctly, it cannot be 
expanded to also embrace validation, formatting and everything else. So we need 
a different approach.

First of all, we need a way to "fork" different beanDatas, and provide a way to 
define which one to use in a specific "scope". The problem is not forking it (a 
deep clone is okay, prototype pattern), nor modifying the new "branch" 
(ViewCustomizer could be extended, giving it a further extensible API, and 
having people implement it). Defining the scope is a problem.

Unfortunately in java the only thing that is "scope dependent" is the stack. 
So, we will probably have to pass the modified bean data, or the bean data 
modifier, instead of the class/bean where we need to.

So, for example :

return new SmartForm(new WiseModifier(userBean)); 

To display a form using the WiseModifier. The WiseModifier class should be a 
class extending a specific base class, and implementing a specific method. For 
example :

public class WiseModifier extends BeanDataModifier {
  public WiseModifier() {
    super(User.class);
  }
  public void modify() {
    makeRequired("name");
    addFormatter("birthDay", new DateFormatter().setFormat("short"));
  }
}

In this way, the modifiers will be classes, and as such (thru cglib eventually) 
compiler friendly and statically determined. Also, the non modified bean data 
could be obtained with a "null modifier", or simply still passing the Class 
object only (this would also provide backwards compatibility, keep the easy 
way, and provide an incremental way to implement this new system, cause new 
methods would simply be overriding the default, class based ones).

It could also be possible, eventually using a CompoundModifier, to combine 
different modifiers. So, we could have a modifier that hides a certain part of 
a bean, another one that imposes a number of additional checks, and then use 
one, the other, or both in a certain context.

Another important aspect could be caching of the resulting beanData. Creating a 
beanData is an expensive job, cause it involves reflection, annotation parsing, 
creation of a number of (mostly thread safe and stateless) objects like 
converters, formatters, validators etc.. 

Since forking a bean data could be a lighter job (deep cloning as opposed to 
reparsing), proper investigation should be done on the effective timing of the 
deep cloning and manipulations. If caching is necessary, then a number of 
techniques could be exploited to obtain it.

A modifier could a stateless one, thus applying always the same modifications. 
In that case, cache it and stop bothering.

A modifier could have a state that is determinable. For example, a number of 
private fields, and a number of if statements based solely on those private 
fields. In this case, caching is still possible cause we know the state.

A modifier could have a state which is not determinable, for example an if 
statement calling System.currentTimeMillis. In that case no caching is 
possible, and a proper warning should be given to the user.

To limit the possibility of uncachable items, the API should be planned from 
the ground up with minimal connections to the outside world, or a predefined 
way of connecting to it, like getters and setters only, or constructor 
parameters only and so on.

(Note that this is exactly what happens in every do-method of any web handler, 
in fact the same design principles were in place for the web API where caching 
plays an important role. Handlers have a predefined "protocol" with the outside 
world, thru getters and setters, making the state determinable in most cases. 
this means that the same caching system used in the web part could be applied 
to this part if needed)

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to