During this whole discussion I feel torn back and forth whether to solve this challenge with configuration or in code. One thing we are trying to achieve when going in the configuration direction is the following: Different extensions don't need to know anything of each other and we can (if we are finding the right granularity) selectively choose to use processXXX from extension 1 and processYYY from extension 2 just by configuring this.

I am afraid this will only work in very few cases. First there is the issue, David raises: The following code snippet cannot be configured in XML:

public processActionCreate() {
super(); //do parent behavior
tilesRP.processActionCreate(); // do tiles
// do some custom stuff
someotherRP.processActionCreate();
}

The second issue is: Will processXXX and processYYY always work together without conflicting? I don't think so. But allowing a developer to configure arbitrary request processor methods together implies that they will be compatible among each other.


My third point is: If we decide to only let the methods processXXX be reconfigured, this might not be sufficient, because (look at Tiles) an extension might want to redefine an internal method that is used from several processXXX methods.

The more we are discussing, the more it looks to me that we don't want to give up the flexibility of composition by coding. Therefore, here is a different proposal that requires only a minimum of changes to the request processor and looks very much like the approach I took for the workflow extension:

Look at the UML diagram I attached to this mail (I hope it comes through to the list). It shows the TilesRequestProcessor and the WorkflowRequestProcessor directly being derived from RequestProcessor. If I want to implement a TilesWorkflowRequestProcessor, I have to subclass TilesWorkflowRequestProcessor and add the workflow functionality (in our example processYYY). This is painful if processYYY contains some complex logic, because it would normally require to have a copy of the code in both WorkflowRequestProcessor and TilesWorkflowRequestProcessor. In order to prevent this code duplication, the method processYYY is extracted into a separate class WorkflowRequestProcessorLogic.

Now the method processYYY in WorkflowRequestProcessor and TilesWorkflowRequestProcessor becomes trivial:

public Some_Type processYYY()
{
   return this.getWfLogic().processYYY();
}


The method getWfLogic must look like this:


private WorkflowRequestProcessorLogic getWfLogic()
{
  if (null == this.wfLogic)
  {
       this.wfLogic = new WorkflowRequestProcessorLogic(this);
   }
}

As the instance of WorkflowRequestProcessorLogic receives a reference to the RequestProcessor, its method processYYY can look this way:

public Some_Type processYYY()
{
   ...
   reqProc.processXXX();
   ...
   reqProc.doSomething();
   ...
}

This only works, if all methods in RequestProcessor become public and all members of RequestProcessor become accessible with public setters and getters. But this is the only change needed to enable extension developers to implement this pattern.

What are the consequences?

1. Drawback: For each combination of different extensions, a new subclass needs to be created. But if every extension follows this pattern proposed here, this is a trivial task for all the cases that could also be covered by configuration and does not necessarily need to be done by the creator of an extension but can as well be done by the struts developer who wants to use the extensions A, B and C together. In more sophisticated cases (e. g. when methods need to be chained), the configuration approach does not work anyway, but the coding approach can at least be taken by the people who are knowing what they do.

2. The one who assembles valid combinations of request processors is the one in charge to test whether the extension play well together. Therefore the danger of configuring arbitrary parts of different request processors is banned.

3. One of the extensions (in our diagram TilesRequestProcessor) does not even need to stick to the pattern, i. e. can have the logic embedded in its request processor.

4. Maximum flexibility, because any method can be overwritten by an extension.

Comments?

--- Matthias

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

Reply via email to