Return-Path: Delivered-To: apmail-jakarta-struts-dev-archive@apache.org Received: (qmail 15796 invoked from network); 4 Jun 2003 08:49:57 -0000 Received: from exchange.sun.com (192.18.33.10) by daedalus.apache.org with SMTP; 4 Jun 2003 08:49:57 -0000 Received: (qmail 25188 invoked by uid 97); 4 Jun 2003 08:52:24 -0000 Delivered-To: qmlist-jakarta-archive-struts-dev@nagoya.betaversion.org Received: (qmail 25181 invoked from network); 4 Jun 2003 08:52:23 -0000 Received: from daedalus.apache.org (HELO apache.org) (208.185.179.12) by nagoya.betaversion.org with SMTP; 4 Jun 2003 08:52:23 -0000 Received: (qmail 13793 invoked by uid 500); 4 Jun 2003 08:49:27 -0000 Mailing-List: contact struts-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Struts Developers List" Reply-To: "Struts Developers List" Delivered-To: mailing list struts-dev@jakarta.apache.org Received: (qmail 13554 invoked from network); 4 Jun 2003 08:49:24 -0000 Received: from isar.livinglogic.de (217.145.101.75) by daedalus.apache.org with SMTP; 4 Jun 2003 08:49:24 -0000 Received: from localhost (isar [127.0.0.1]) by isar.livinglogic.de (Postfix) with ESMTP id 8AA901B00A8 for ; Wed, 4 Jun 2003 10:49:36 +0200 (CEST) Received: from isar.livinglogic.de ([127.0.0.1]) by localhost (isar [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 21272-08 for ; Wed, 4 Jun 2003 10:49:35 +0200 (CEST) Received: from amazonas.intern.livinglogic.de (amazonas.intern.livinglogic.de [10.10.10.100]) by isar.livinglogic.de (Postfix) with ESMTP id E467D1B005E for ; Wed, 4 Jun 2003 10:49:34 +0200 (CEST) Received: from livinglogic.de (niger.intern.livinglogic.de [10.10.10.17]) by amazonas.intern.livinglogic.de (8.11.6/8.11.6) with ESMTP id h548nYR01273; Wed, 4 Jun 2003 10:49:34 +0200 Message-ID: <3EDDB2A5.2090005@livinglogic.de> Date: Wed, 04 Jun 2003 10:49:41 +0200 From: Matthias Bauer Reply-To: Matthias.Bauer@livinglogic.de User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021130 X-Accept-Language: en-us, en MIME-Version: 1.0 To: Struts Developers List Subject: Re: composable RequestProcessor References: <3EDC8E74.3060405@livinglogic.de> In-Reply-To: Content-Type: multipart/mixed; boundary="------------080204050101040103060008" X-Virus-Scanned: by amavisd-new at livinglogic.de X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N --------------080204050101040103060008 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit 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 --------------080204050101040103060008 Content-Type: text/plain; charset=us-ascii --------------------------------------------------------------------- To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org For additional commands, e-mail: struts-dev-help@jakarta.apache.org --------------080204050101040103060008--