>From Delegator.java

 139     public GenericDelegator cloneDelegator();
 140
 141     public GenericDelegator cloneDelegator(String delegatorName);


This has to be changed. Delegator is an interface, and it has a
reference to its implementation "GenericDelegator".

Anyone knows of anything that might break, or a reason not to change this ?

I will open an issue, for this.



On Tue, Mar 27, 2012 at 4:02 PM, Mansour Al Akeel
<mansour.alak...@gmail.com> wrote:
> Jacopo,
> I am still thinking about your suggestion to change the Delegator
> interface and use only subset of the methods.
> If you have some thought ready, please share them and discuss.
>
> If you have some plan to introduce these changes, then let me know about them.
>
> I think we will have to change many things anyway if we need to refactor.
> It's not like what I initially thought, just moving code around will be 
> enough.
>
>
>
> On Tue, Mar 27, 2012 at 3:40 AM, Jacopo Cappellato
> <jacopo.cappell...@hotwaxmedia.com> wrote:
>> Mansour,
>>
>> it is interesting.
>> Maybe it would be easier if we simplify the existing classes (and 
>> application code that uses them) to use only a subset of the methods 
>> available (some of them are already deprecated); the refactoring based on 
>> design patterns will be easier at that point.
>>
>> Jacopo
>>
>> On Mar 26, 2012, at 11:25 PM, Mansour Al Akeel wrote:
>>
>>> Hello all,
>>> I am looking at the code for the GenericDelegator. We have 2913 line
>>> of code in one class !!!
>>> This class handles a lot of functions and I think it's the most
>>> critical to the application. These functions can
>>> be distributed among more classes, providing better maintainability
>>> and extensibility. I can see the best pattern to
>>> be used here are chain of responsibilities and decorator, where each
>>> class provide a defined set of functionality and implement the
>>> Delegator interface.
>>>
>>> For example, currently this class handles caching, configurations,
>>> model Reading, encryption, logging, and the main function of accessing
>>> data.
>>> It's true that the interface it implements is huge (1217 line of code)
>>> but mostly comments and documentation. CoR design pattern will allow
>>> easier
>>> unit testing, and better maintainability and allow to extend. So let's say:
>>>
>>> GenericDelegator implements Delegator (Interfaces with the external world )
>>> ===> passes calls to SQLQueriesDelegator (build the sql through
>>> implementing findXXX())
>>>   =====> passes calls to LoggingDelegator
>>>     =====> passes calls to ModuleReaderDelegator
>>>      ======> MultiTenantDelegator
>>>       ========> CachingDelegator
>>>        ==========> EncryptionDelegator
>>>         ============> etc
>>>
>>> Each delegator does some work and calls the next one in chain until
>>> the final functionality is achieved. Of course customization will be
>>> easier.
>>> For example, if I want to swap the current caching implementation with
>>> something like memcahe or ecache, I have to change in many places in
>>> the single 2913 line-of-code class !! With CoR all I do is swap the
>>> current CachingDelegator class with my own. Let's say I want to access
>>> the file system
>>> or jcr nodes in the same unified way I access the db. In this case all
>>> I need to do is add some thing like "RequestRoutingDelegator", and
>>> JCRDelegator.
>>> The RequestRouting decides how to access the entity in hand and based
>>> on that uses either the SQLDelegator or JCRDelegator.
>>> Those who did xml processing with SAX2 filters (CoR) or worked with
>>> java IO streams (Decorator Pattern) will appreciate the concept of
>>> separating functionality. An example in JavaIO, if one needs to ecrypt
>>> a stream,  unzip the input, or zip the output .... etc. All these is
>>> done though decorator pattern.
>>>
>>> The whole chain can be created and constructed in the factory method
>>> (or using a container config in the future), so existing applications
>>> should not see any changes, as all of these delegators will be hidden
>>> by package visibility (except for the first one in the chain).
>>> In the factory method (hopefully in the future called through a
>>> service locator), we can do something like:
>>>
>>> Delegator encryptionDelegator = new EncryptionDelegator();
>>> Delegator cachingDel = new CachingDelegator( encryptiongDelegaort);
>>> .....
>>> ..... // may be do some configuration as we dont want every delegator
>>> to configure itself by reading a file or looking up a
>>>    // of a property, in case we used a container in the future.
>>> ....
>>> Delegator realOne = new GenericDelegator();
>>>
>>> static methods can be moved where needed and ensure there's not
>>> duplication of functionality. At some point we may consider
>>> making them instance methods.
>>>
>>> To avoid DRY, we can create a class (implement Delegator) with default
>>> functionality of calling the child (next) delegator.
>>> Then just extend it and override whatever we need. This way we keep
>>> the code minimal, and clean.
>>>
>>> At the end, assuming no advantage gained, who wants to maintain 2913
>>> line of code with some lines more than 100 character wide ??!!
>>>
>>> I am not sure about the amount of work it takes to finalize it, but I
>>> can see some difficulties. For example, assuming two different methods
>>> belongs to two different layers, need one of the static methods in the
>>> GenericDelegator. This will lead to duplicate code, we are going to
>>> call static methods in other classes, and creating a mess again.
>>> Another issue is when an object needs to be accessed in different
>>> layers. This means we need to keep a reference for that object in
>>> multiple places. What if it changed in one of the layers ? For
>>> example, ModelReader is accessed in cloneDelegator and in
>>> decryptField. Both of these methods belongs to different Delegators.
>>> cloneDelegator goes into GenericDelegator, and decryptField goes into
>>> EncryptionDelegator. What if the model reference changed in one of
>>> them ?? Caution needed !
>>>
>>> Another problem is when the order of calls in GeneralDelegator is not
>>> consistent. For example, in one method we accessed the cache then we
>>> did the logging. In another method we did the opposite, we logged,
>>> then we accessed the cache. When done in layers, it will be harder to
>>> do this.
>>>
>>> Another alternative is something close to the composite pattern, where
>>> we have Helper classes with a subset of Delegator implementation. The
>>> GenericDelegator class, instantiates them and keeps a reference to
>>> each of them. Then calls the appropriate method. This really simple,
>>> but less
>>> sexy, as extending the functionality still requires looking between
>>> the lines. It's just breaking the HUGE class into smaller classes.
>>>
>>> Not sure if I missed something. Other patterns could fit better. If
>>> someone captured something, please let us know. Ofbiz team can decide
>>> what path to follow.
>>>
>>> Since this component is critical to the application, some may prefer a
>>> more senior resource on the team and more skilled
>>> with the internals of ofbiz, to handle this task. However, I don't
>>> have a problem giving it a try. This task may sound small, but I don't
>>> know what is a head of us. Someone with deeper knowledge about the
>>> entity engine can comment.
>>> Alternatively, one of the commiters, can adopt this task, and do the
>>> cleaning as needed. For example, every while and then revisit this
>>> huge class, and
>>> break separate the functionality into the corresponding classes.
>>>
>>> I didn't want to open this subject now, as I am aware of the cleaning
>>> being performed by the team. However, if we can not do it now, and we
>>> agreed about the path, it can be added to JIRA for future reference.
>>>
>>> Please discuss and share knowledge.
>>

Reply via email to