Ah, I'm glad you bring this up.  I'm very open to alternative designs,
but if a simpler form is possible, I don't see it.  Comments inline:

> From: jim moore [mailto:[EMAIL PROTECTED]]
> 
> So having spent the weekend going though at least the transform
changes to
> the mav 2.1 api, I have a couple comments/questions.
> 
> First, there is the new class TransformStep which basically seems to
do
> the
> work that Transform did under 2.0. The Transform interface now just
has
> one
> method, createStep, making it basically just a factory for a
TransformStep.
> Since TransformFactory is a factory for creating a Transform, it seems
> that
> what we have is a factory (TransformFactory) that creates a factory
> (Transform) that creates a class (TransformStep). Is it not possible
to
> lose
> the middle man? (i.e. is Transform any longer even necessary)?

The Transform is definitely still necessary, because something has to
live in the command object graph to represent that specific transform
node.  The question is whether or not the TransformStep can be dispensed
with.  I really wanted to avoid it but it seems to be necessary:

Lets take the case of going from a document view to a document
transform:

<view type="document" path="start.jsp">
  <transform type="document path="trans.jsp"/>
</view>

This requires start.jsp to be buffered using a
RequestDispatcher.include() into some sort of HttpServletResponse
fa�ade.  After writing is complete, the buffer/step must be triggered to
dump its output to the subsequent step.

This would be easy with simple Writer objects; the trigger for dump is
the close() method.  The HttpServletResponse is more problematic,
especially in the case of RequestDispatcher.include() - I'm pretty
certain that the Writer/OutputStream close() method is not called by the
container.  It's also not possible to determine whether getWriter() or
getOutputStream() was called from the HttpServletResponse interface, so
the preceeding step (or view) can't call
getWriter().close()/getOutputStream().close() manually.

Basically, the start.jsp step needs to trigger processing on the
subsequent step when the include() is finished.  How to make this
happen?

One alternative is to have a Transform interface like this:

public interface Transform
{
    ...
    public MaverickResponse getResponse(TransformContext tctx);
    ...
}

public interface MaverickResponse extends HttpServletResponse
{
        public void done();
}

This adds the ability for the prior step to indicate when it is
finished.  The SAX ContentHandler object already has a sufficient
mechanism [endDocument()], as does the Writer object [close()].

The downside of this approach is that transform implementers would have
to create wrappers for each of the three "streaming" types.  The
equivalent of the current (after you boil out the
AbstractTransformStep.getNext() method)
myTransformContext.getNextStep().getResponse(); would be:
myTransformContext.getNextTransform().getResponse(myTransformContext);

The other alternative (which I took) is to have a Step object with a
close() method.  This is convenient for the SAX ContentHandler and
Writer binding mechanisms as well; those objects can now be the "real"
objects rather than wrappers.
 
I'm not really sure which is better.  The Step system seems a bit
cleaner to me, but it's definitely open for debate.  

> Second, while I did eventually (with Jeff's guidance) get opt-fop
working
> under 2.1, the logic behind getting the result you are supposed to be
> writing to seems a bit confused when using AbstractTransformStep. I
still
> don't think it is clear that if I want to get my outputstream, I need
to
> call this.getNext().getResponse().getOutputStream(). Logically, I want
to
> call this.getResponse(), but because of the way it is set up, that
gives
> me
> the response the previous step wrote to. Why would I ever want the
result
> of
> this.getResponse(), and even if I would, why would I want that to be
the
> default behaviour (wouldn't something like getPreviousResponse() be
> clearer
> for this behaviour)? I think most people would expect when calling
> this.getResponse(), that they would expect to get their response for
> writing
> to. Once Jeff explained to me what was going on, I was able to get it
> working, but I still don't think it is very clear, and I am worried
that
> it
> will lead to a lot of frustration by others trying to write other
> transforms.

The reason you have a this.getResponse() is because you are implementing
the interface that is provided to the previous step... it's a class
interceptor (aka decorator) pattern.  It's more obvious in the case of
simply calling go(String blah) on getNext(), but it's the same idea.
You are never a client to your own getResponse() (other than maybe
because you want to reuse the behavior to provide getWriter()); it's
only there so that previous steps can call it.

Perhaps some additional javadoc comments would help?

> Note. This isn't meant to be a rant. I think the heterogenous
transforms
> are
> amazing--I don't know of any other framework that supports anything
nearly
> this cool. I just wonder if things could be a bit clearer.

I very much appreciate the critical view, and I'm glad to discuss it.  I
also wonder if things could be cleaner, and I'm fully open to the idea
that I may have missed something.  I just don't see it yet.  The
fundamentally different options for binding between transforms makes
this very complicated, unfortunately.

I think the closest framework to this feature set is Cocoon2, but I
believe it is restricted to SAX-only binding between steps.  You can't
do transformations on non-XML data.

Jeff Schnitzer
[EMAIL PROTECTED]

_______________________________________________________________

Don't miss the 2002 Sprint PCS Application Developer's Conference
August 25-28 in Las Vegas - 
http://devcon.sprintpcs.com/adp/index.cfm?source=osdntextlink

_______________________________________________
Mav-user mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/mav-user

Reply via email to