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
