I think Jeremy's point that this might  be an example of using the "wrong 
hammer on the screw" depends on how structured (vs. open) the physical 
model actually is. More generally than just whether SDO is the right 
approach for this particular application, I think it's a question of 
whether it's worth using any Java binding technology on a model that is 
full of open and mixed content - and even worse, the open content is not 
described by a schema (i.e., lax). Whether it's SDO, JAXB, or some other 
XML binding technology, the programming model that results is more 
DOM-like then a nice static model that we'd like. In the SDO case you end 
up doing a lot of DOM-like access using Sequence's (accessing "mixed", 
"any", and "anyAttribute" properties) - hardly a clean and beautiful Java 
binding. I'm not sure if the threshold of where the physical model is too 
loosely defined to map to a clean Java binding has been crossed or not in 
this case, but it looks close anyway. If it wasn't, we wouldn't need a 
logical model.

I think the other problems that Jeremy points out, need to get fixed 
anyway and SDO should be a competitive Java binding technology, as well as 
all the other things.

Frank.




Jeremy Boynes <[EMAIL PROTECTED]> 
03/21/2006 02:44 PM
Please respond to
tuscany-dev


To
[email protected]
cc

Subject
Re: Framework for StAX-based model loading






Jean-Sebastien Delfino wrote:
> Jeremy Boynes wrote:
> 
>> Jim Marino wrote:
>> 
>>
>>> Hi Jeremy,
>>>
>>> Could you briefly enumerate what you see as the benefits to the StAX
>>> framework over alternatives?
>>>
>>> 
>>
>>
>> The final straw that prompted me to do this was the amount of
>> classloader wrangling we ended up doing in the Tomcat code a couple of
>> weeks ago. We need to keep track of context classloader switching
>> between loading the model and loading any application code. There is
>> plenty of room for subtle errors to creep in.
>> 
> 
> The classloader issues we ran into with the current SDO implementation
> need to be solved. I am not sure that they are a sufficient reason for
> stopping to use SDO and moving to a different technology. I'm surprised
> to see that we have a databinding technology in Tuscany but we are
> running away from it when we encounter our first problems with it. I
> think we should spend a little more time trying to fix it instead of
> running away from it. By the way the classloader problems we ran into a
> couple weeks ago were not just caused by SDO, this was a combination of
> SDO, Axis2 and some of the factories used under the cover by Axis2, all
> having different requirements in terms of "current" class loader.
> 

I wouldn't say "running away" (that's a little dramatic) but I do think
it is fair to say that we ran into problems due to the way our SDO
implementation couples the type system to the thread's classloader.

The goal of SDO is not to be just another XML data binding technology,
its purpose is to "simplify data programming so developers can focus on
business logic instead of the underlying technology." It does this
through abstraction of that technology, by providing a data-graph
oriented API and capabilities like containment and change tracking.

We are not using those capabilities. We're actually only using a tiny
fraction of its capabilites. I think it is reasonable to evaluate
whether it is the right hammer to use on this screw.

>> The SDO solution (actually this would be true of any XML->POJO binding)
>> was fine when the logical model was an exact replica of the XML files.
>> However, to support more logical unit testing (and other uses) the 
model
>> has now shifted back to being more of a true configuration model. This
>> means we can't just slurp the XML into objects and use them directly, 
we
>> need to read in the POJOs and then run a transformation on them. This
>> adds an additional phase to the load process that needs maintenance.
>>
>> 
> 
> The logical model was never an exact replica of the XML files. Whatever
> technology you use you'll need to do the following:
> 1. handle the parsing/loading from XML
> 2. transform what you get from the XML into a logical model
> The current SDO based approach separated the two concerns. With this new
> StAX approach we do (1) and (2) together. I think this will create
> complexity over time.
> 

I would describe our problem slightly differently saying we need:
1) to parse the incoming bytestream
2) to use the parse results to build the logical model
The first of these is being handled by StAX, the second the code we
provide that reacts to parse events and builds the model. This seems
like a fairly clear separation of concerns.

I would also break down the SDO-based solution differently:
1) SDO parses the incoming bytestream
2) SDO builds its physical model to represent the XML
3) the SCDLModelContentHandler parses the physical model
   and generates a partial logical model
4) linkers generated in 3) run to complete the logical model

I think this is less separated. The implementation of
SCDLContentModelHandler is tightly coupled to the physical model
generated by SDO. The linkers are also coupled to the element handlers
(the caseXXXX methods) that parse each physical model object.

I'd also point out that the implementation of the content handler for
the core assembly model is different from other extensions: the former
uses a (code-generated) case dispatcher, the others tend to use a single
method with manually coded instanceof tests.

>> Having a container system there able to manage the loaders means
>> extending the model is easy - an extension just needs to contribute its
>> model elements and a XML handler. There is no need to codegen a 
separate
>> XML model and write a transformer. There is also only one extension
>> registry rather than two (the SDO type registry and the SCDL loader
>> registry).
>>
>> 
> 
> I don't see why codegen is a problem. In general I'd rather get some
> code generated than write it myself. I agree that with the SDO approach
> you have to register the generated model and your handler/transformer. I
> don't really understand the difference you make between a handler and a
> transformer and why it's easier to write a handler than to codegen a
> model and write a transformer. With the SDO based approach you need to
> write code that gets data out of an SDO model with nice generated getter
> methods. With a StAX based approach (and it would be very similar with a
> DOM or SAX based approach) you get the data out of a more weakly typed
> model. Frankly I prefer to write:
> String name=component.getName();
> than
> String name=reader.getAttributeValue(null, "name");
> 

I wouldn't have such a big issue with codegen if it generated the code
that we wanted. However, the codegen here is generating objects that
represent the physical structure of the XML rather than ones that map to
the logical model. This leads to the need for another parser/transform
(the SCDLModelContentHandler) to convert from the physical
representation to the logical one.

The result is we have both the complexity of code generation *and* the
complexity of a manually coded parser/transformer.

>> The XML handling is pluggable - it just uses the standard StAX APIs
>> rather than internal hooks to our SDO implementation and/or EMF. A
>> validating StAX parser can be used if required; semantic validation is
>> still being performed in the model and builders.
>> 
> 
> We have been working to remove the dependencies on EMF, so again I don't
> see how this can motivate moving to StAX. One of the goals of Tuscany is
> to provide a good SDO story anyway to people who want to load an XML
> document into an SDO model, without requiring any hooks into our SDO
> implementation or EMF. Again I think we should all work to improve our
> SDO story instead of using something else. For example I think that we
> should improve SDO to provide a good integration with StAX.
> 

The point I was making here is that there are multiple implementations
of StAX available that can be used and that the loader is not tied to
one of them. This may be useful for people embedding Tuscany in other
environments where they have some preference over which implementation
should be used.

We are already working to integrate StAX support with SDO to allow SDO's
to be (de)-serialized from/to StAX event streams. We are already using
this for better AXIOM integration in the web-services stack.

Having a good SDO implementation is a primary objective for the project.
However, as I pointed out at the start, SDO is more than just an XML
binding technology and we need to make sure its SDO-ness excels. We also
need to realize that it is not the universal solution for data binding
and that other technologies may work better in specific scenarios. I
think we have one of those scenarios.

>> Code footprint is better as there is no intermediate form. Performance
>> and memory footprint are probably better too. However, I don't see that
>> as a major factor as we are only reading config data here (i.e. it's
>> once per deployment not once per request).
>> 
> 
> I agree, code and memory footprint are better with the StAX approach.
> 
>> On the downside, StAX is a technology that may not be as familiar to
>> people. However, I think it has enough similarity to DOM/SAX to be
>> readily understood. It is also heavily used in Axis2 so we will be
>> seeing it anyway.
>>   We will need to modify the parsing code if the XML changes whereas 
with
>> SDO or another XML->POJO solution that would be handled by generation.
>> However, the need to transform the model after load means that we have
>> custom parsing code anyway just running on the POJOs (see
>> SCDLModelContentHandler).
>> 
> 
> This is the point that raises the biggest concern for me. I have been
> there before multiple times, implemented models and loaders for changing
> XML specifications. Usually the kind of approach demonstrated by this
> StAX loader looks very simple and very tempting at the beginning of the
> project, but ends up in a mess and maintenance nightmare in the longer
> term.
> 

Unfortunately I think that just an aspect of this problem. I have seen
XML-binding based solutions used in other projects and they have also
proved to be very fragile even in the face of static schemas. If we had
a pure SDO solution I would be less concerned; my concern here is about
the parse/transform code that we have to maintain to convert the
physical to the logical model.

> If we want to avoid that we need the following:
> - more work on this StAX loader to clearly separate the pure
> loading/de-serialization aspect from the physical -> logical
> transformation aspects, if you mix the two aspects it will be a recipe
> for disaster after a year of maintenance adjusting to changes in the XML

See above - I think the same applies to the SCDLModelContentHandler

> - define intermediate data structures (close to the physical model) to
> avoid polluting the logical model with XML specific info (I'm thinking
> of all the cases where we're going to have to store intermedaite / half
> loaded data and complete/resolve things in a second pass, properties and
> wires are two examples that come to mind); if we don't do that and start
> adding stuff to the logical model to facilitate the loading phase we
> will make a mess of the logical model

I don't think we have needed to populate the logical model with physical
artifacts. I did make some changes to support the StAX loader such as
storing reference targets as pointers rather than using a Reference
object directly. I would contend that is a normalization that better
represents the logical model - it certainly cut out a couple of bugs
that were the result of inconsistent updates to the denormalized 
References.

> - make the StAX loader approach more complete before we jump to switch
> to it, to really understand the impact, for example  the StAX loaders do
> not handle subsystems or property types at the moment, I think that the
> support for properties in particular is going to be interesting and will
> generate some work to integrate between StAX and SDO if we want to
> support SDO properties.

Given subsystems are changing and not really supported yet by the
runtime this does not seem like a major issue. In fact, looking at the
how subsystems are handled in the SCDLModelContentHandler, adding StAX
loader support form them would be trivial. How about you have a go at
doing it and see how hard/easy adding things to the StAX framework
actually is?

For properties, I don't think either solution is fully fleshed out yet
so using that as a basis for comparison is a little unfair. For example,
I would ask how user-defined types are loaded into the SDO type system,
or how non-SDO property type support would be added (e.g. to load
properties as JAXB objects)?

With the StAX solution we have the advantage that by using a standard
technology it will be easier to add in other binding frameworks. We are
already working on a StAX->SDO deserializer that would give us a
solution when the user was using an SDO; further JAXB, XMLBeans and (I
believe) Castor all support StAX sources so it should be trival to
integrate those.

> - come up with brand new solution for serializing/saving models, I am
> sure we will run into use cases where we want to save an assembly, a set
> of wires, a module component configuration etc; StAX only handles the
> loading part, so if we're not using SDO here again we'll have to invent
> something else to handle serialization/saving of the models...
> 

We need to do that anyway. If the logical model was an SDO then we could
just write it out, but it isn't. We would need to develop and maintain a
serializer equivalent to the SCDLModelContentHandler and that is likely
to be just as much manual code to maintain as a StAX serializer.

> My main concern is about the complexity of maintaining all this code.
> Just the (incomplete) support for the core SCDL is already about 750
> lines of code, mixing parsing logic and mapping/construction of the
> logical model, using dynamic APIs like reader.getAttribute(null, "name")
> compared to the 550 lines of model transformation code using strongly
> typed APIs generated from the SCDL XSD in the SCDLModelContentHandler
> (with more complete support for the core SCDL). I anticipate many
> changes in the SCDL XSD and the logical model during the course of this
> year, the StAX based loader approach may look appealing now at the
> beginning of the project, but we will only succeed with it if we have
> committed contributors and committers ready to maintain this code, make
> it complete, and adjust it each time we change the SCDL XSD (and it's
> going to be pretty painful, compared to just rebuild to regen the code
> from XSD and adjust the transformer where it's broken by the changes).
> 

I think the "adjust the transformer" part here is the key phrase. This
is going to be just as much work as maintaining any StAX handler (as
they are essentially doing the same thing).

If you're going to compare lines of code, the honest metric here would
be to compare the number of lines related to parsing and transformation
and to exclude the code used to create the logical model. But lines of
code alone are not the only metric; when I compare blocks out of
SCDLModelContentHandlerImpl with the StAX equivalent the latter seems
less complex (at least to me).

For example, the <service> code in SCDLModelContentHanlderImpl is:

    public Object caseService(Service object) {
        final org.apache.tuscany.model.assembly.Service
service=factory.createService();
        service.setName(object.getName());

        linkers.add(new Runnable() {
            public void run() {
                currentComponentType.getServices().add(service);
            };
        });

        currentService=service;
        return service;
    }

and for the contained <interface.java>

    public Object caseJavaInterface(JavaInterface object) {
        final JavaServiceContract
serviceContract=factory.createJavaServiceContract();
        serviceContract.setScope(Scope.INSTANCE);

        serviceContract.setInterfaceName(object.getInterface());

serviceContract.setCallbackInterfaceName(object.getCallbackInterface());

        linkServiceContract(object, serviceContract);

        return serviceContract;
    }

and

    private void linkServiceContract(Object object, final
ServiceContract serviceContract) {
        Object container=((DataObject)object).getContainer();
        if (container instanceof Service) {

            // Set a service contract on a service
            final org.apache.tuscany.model.assembly.Service
service=currentService;
            linkers.add(new Runnable() {
                public void run() {
                    service.setServiceContract(serviceContract);
                }
            });
        }
        else if (container instanceof Reference) {

            // Set a service contract on a reference
            final org.apache.tuscany.model.assembly.Reference
reference=currentReference;
            linkers.add(new Runnable() {
                public void run() {
                    reference.setServiceContract(serviceContract);
                }
            });
        } else if (container instanceof ExternalService) {

            // Set a service contract on an external service
            final org.apache.tuscany.model.assembly.ExternalService
externalService=currentExternalService;
            linkers.add(new Runnable() {
                public void run() {

externalService.getConfiguredService().getService().setServiceContract(serviceContract);
                }
            });
        } else if (container instanceof EntryPoint) {

            // Set a service contract on an entry point
            final org.apache.tuscany.model.assembly.EntryPoint
entryPoint=currentEntryPoint;
            linkers.add(new Runnable() {
                public void run() {

entryPoint.getConfiguredService().getService().setServiceContract(serviceContract);

entryPoint.getConfiguredReference().getReference().setServiceContract(serviceContract);
                }
            });
        }
    }

whereas in the StAX framework the <service> handler is:

    public Service load(XMLStreamReader reader, ResourceLoader
resourceLoader) throws XMLStreamException, ConfigurationLoadException {
        assert SERVICE.equals(reader.getName());
        Service service = factory.createService();
        service.setName(reader.getAttributeValue(null, "name"));

        while (true) {
            switch (reader.next()) {
            case START_ELEMENT:
                AssemblyModelObject o = registry.load(reader,
resourceLoader);
                if (o instanceof ServiceContract) {
                    service.setServiceContract((ServiceContract) o);
                }
                reader.next();
                break;
            case END_ELEMENT:
                return service;
            }
        }
    }

and the <interface.java> handler is

    public JavaServiceContract load(XMLStreamReader reader,
ResourceLoader resourceLoader) throws XMLStreamException,
ConfigurationLoadException {
        assert AssemblyConstants.INTERFACE_JAVA.equals(reader.getName());
        JavaServiceContract serviceContract =
factory.createJavaServiceContract();
        serviceContract.setScope(Scope.INSTANCE);
        serviceContract.setInterfaceName(reader.getAttributeValue(null,
"interface"));

serviceContract.setCallbackInterfaceName(reader.getAttributeValue(null,
"callbackInterface"));
        return serviceContract;
    }

> I am not completely opposed to a StAX based loader approach. I can even
> see some benefits:
> - smaller code and memory footprint compared to a solution based on
> generated code
> - faster loading (I'm actually not sure how much we'll gain on typical
> SCA module file, but I'm guessing that it'll be faster)
> - and more important IMO... more flexible parsing (for example we could
> relax a little the requirement for some of the namespaces to be
> specified in SCDL, this could help simplify SCDL files a little)
> 
> But I'm concerned that we're going to have to spent a lot of energy to
> make it really work well in the long term (energy which could be spent
> on many other aspects we need to cover in Tuscany). Basically I will be
> OK with this StAX loader approach only if we have enough people in the
> group really volunteering to take responsiblity for it, maintain it, and
> adjust it to all the upcoming changes to the XSD or the logical model.
> People just need to think about it and realize that it's going to be a
> lot of work.
> 

I think we need to take responsibility for whichever option we choose.
Maintaining the loading code in the face of an evolving spec is going to
require work from all of us. The choice here comes down to what are we
willing to look after:

A) an SDO model, code generation, a SCDLContentModelHandler and its
   linker blocks, a set of SCDLModelLoader impls,
   and Thread classloader management code, or

B) a set of StAXElementLoader's

As I said at the start, I wasn't even looking at this until we ran into
the Thread classloader problems during the Tomcat integration. I still
don't think we have resolved all of them and think we are going to run
into a new set of challenges with other property binding frameworks.

I would like to put this to rest soon. Both versions are out there for
folk to look at and they are both complete enough to run our current
examples.

I think the StAX version is simpler yet just as flexible, avoids some of
the problems seen to date, and provides an easy integration path with
other frameworks (including SDO) and unless there is a strong technical
argument against I'd like to switch over.

--
Jeremy


Reply via email to