Grzegorz Kossakowski pisze:
Hello,

Joerg Heinicke asked[1] me to provide summary of the issue that Daniel raised[2] and outline
possible solutions so we can discuss them.
I think we should do the same for Object Model. I proposed[5] to create new Spring scope (or reuse sitemap scope that must be implemented). Actually, such scope does, behind-the-scene, what I described one paragraph above. It creates new instance (that may inherit properties from old one) of Object Model when entering pipeline components. Then component is safe to modify Object Model according to its needs or even pass it to subsequent, internal requets (like calling service) and can be sure that Object Model contains only data belongs only to the current component. What's very convenient, Spring scope would be completely transparent to the components and even almost transparent to the pipeline's implementation. Pipeline's code would have to only inform when scope
is entered and leaved.

On the other hand, there is a subtle difference between threads ran simultaneously and pipeline's components ran simultaneously. In latter case, we are in charge of component's management and execution. That means we know exactly when one or another component is executed so we can modify the same Object Model instance the way that changes to Object Model performed in one component will be not visible in another one. Since switching between components occurs on every SAX event we would have to adjust Object Model on-the-fly for every SAX event and every component in a pipeline. This solution has been proposed[6] by Daniel that gave more detailed description.

I've done more research and came to conclusion that we will need to combine ideas of custom scope and environment changer. I'm going discuss technical details here.

Implementing custom scope has advantages that were outlined earlier. What I missed before was how class implementing org.springframework.beans.factory.config.Scope interface knows which scope is the active one? How it knows if new bean should be created or there is already one in this scope?

In order to keep this information accurate we need to switch scope every time component is switched, which means effectively for every SAX event that comes along the pipeline. We already expressed concerns about such solution because it may be too heavy but if we only change _scope_ it's really lightweight and I expect it to have almost zero impact on performance. The code of such scope changer would look like:

public class PipelineComponentScopeChanger implements ContentHandler {
  //This map will contain only one attribute "beans", this map is shared 
between all
  //PipelineScopeChanger instances and PipelineScope class
  private Map scopeAttributesHolder;

  //This map holds beans in this scope
  private Map beansInScope;

  private ContentHandler nextPipelineComponent;

public startElement(String namespaceURI, String localName, String qName, 
Attributes atts)  {
  private Map currentBeansInScope = (Map)scopeAttributesHolder.get("beans");
  scopeAttributesHolder.put(beansInScope);
  nextPipelineComponent.startElement(namespaceURI, localName, qName, atts);
  scopeAttributesHolder.put(currentBeansInScope);
}

}

Same goes for all other SAX events. It's actually one extra get and two puts calls on Map. Rather lightweight, yes?

Then code of PipelineComponentScope would look like:

public class PipelineComponentScope implements Scope {

  private Map scopeAttributesHolder;

public Object get(String name, ObjectFactory objectFactory) {
        Map scopedBeans = (Map)scopeAttributesHolder.get("beans");
        Object scopedObject = scopedBeans.get(name);
        if (scopedObject == null) {
            scopedObject = objectFactory.getObject();
            scopedBeans.put(name, scopedObject);
        }

        return scopedObject;
    }

}

You may wonder how this scopedAttributesHolder would be injected into these classes. Before discussing this issue I would like to give you another remark.

I showed to you that PipelineComponentScopeChanger would implement ContentHandler so you could thought that I'm going to follow Daniel suggestion[1] to put this changer between pipeline components. Next idea that comes to mind is that we should create this changers in pipeline's code because it's a place where we are in control of all components and can insert these changer.
Actually, I'm not going this path, or not literally.

I want to create dynamic proxies around pipeline components. Actual wrapping would be performed by class implementing BeanPostProcessor interface. Taking one perspective one could say that this it's almost the way as discussed one paragraph above. However, going with this path makes whole pipeline scope completely *orthogonal* to the pipeline and its components' code. No existing class will be touched and there is no requirement on pipeline components' configuration files. No need for custom namespace in XML config, etc.

I feel proud of this solution as it solves non-trivial problem just in few lines of code and few config files in transparent way. 8-)

Of course I did not mention some corner cases like pipeline component scope behaviour where we are _not_ in pipeline component or how to properly initialize Object Model in pipeline scope. I'm going to start implementing this right know so I'll figure out this issues shortly.

[1] http://article.gmane.org/gmane.text.xml.cocoon.devel/74435

--
Grzegorz Kossakowski
http://reflectingonthevicissitudes.wordpress.com/
*** My Internet Service Provider breaks my internet connection                
***
*** incessantly so I'll not be able to respond to e-mails                     
***
*** regularly and my work will be somehow irregular.                          
***
*** I'm already trying to switch ISP but it will take handful amount of time. 
***

Reply via email to