Jeremias Maerki wrote:

> > The answer to your question probably lies in understanding how and why
> > getContentHandler() is used without also using render(). The
> FOTreeListener
> > is only needed if the input document is parsed, and in fact is
> only needed
> > if you want to break out of parsing to go do something at a higher level
> > before returning (the normal SAX events are not affected at all). So:
> > 1) if the process running getContentHandler() doesn't ever parse, don't
> > bother registering the FOTreeListener
>
> Does that ever happen? I would assume that anyone who calls
> getContentHandler() will want to send SAX events. I don't think I
> understand what you're trying to explain. Sorry.

I don't know whether it happens or not. I can't think of a reason for this
to be done. Since I don't understand how this is getting used, I was just
trying to cover all possibilities.

> > 2) if the process running getContentHandler() doesn't care about being
> > notified about the end of a PageSequence (which is the only
> FOTreeListener
> > event that is *unique*), don't bother registering the FOTreeListener
>
> Ok, I guess that is something that was introduced by your LayoutStrategy.
> Would you explain to me what you mean by "process" in this context?

It is only loosely related to LayoutStrategy. It had more to do with trying
to separate the parsing and layout (somewhat foundational to LayoutStrategy,
but useful even apart from that). fo.FOTreeEvent and fo.FOTreeListener kind
of mimic what the SAX events do, but are fired from within FOP as the FOTree
is being built. This allows FOTree to do its thing without needing to know
how it is being used.

By "process" I just mean whatever embedded application is calling
getContentHandler().

> > 3) otherwise, have it wrap its parsing code inside of the
> following (which
> > is what is wrapped around parser.parse in render() now):
> >     <before>
> >             if (foInputHandler instanceof FOTreeHandler) {
> >                 FOTreeHandler foTreeHandler =
> (FOTreeHandler)foInputHandler;
> >                 foTreeHandler.addFOTreeListener(currentDocument);
> >             }
> >     </before>
> >
> >     <after>
> >             if (foInputHandler instanceof FOTreeHandler) {
> >                 FOTreeHandler foTreeHandler =
> (FOTreeHandler)foInputHandler;
> >                 foTreeHandler.removeFOTreeListener(currentDocument);
> >             }
> >     </after>
> >
> > Better yet, refactor both of the above code snippets into
> methods that can
> > be called more simply, since this code would now be used more than once.
>
> As methods of Document?

Since the code is in Driver now, I was thinking Driver. However, it will
work from Document also. You'll just need to use getDriver() to get to the
foInputHandler.

> > Just looking at what is left in render(), I don't quite follow
> why it would
> > ever *not* be used if parsing will take place. The only thing
> left in there
> > is parser.parse(), the above code that it is wrapped in, and the code to
> > *not* parse based on the LayoutStrategy's wishes. Since the
> parser itself
> > can be passed as a parameter, it seems like anybody parsing
> could/would use
> > it. If you will describe the use case(s) a bit, I'll try to be
> of more help.
>
> Use cases that are not using render? Most prominent use case is Cocoon
> which build a SAX pipeline where FOP can be the end of that pipeline. So
> Cocoon needs a ContentHandler. Cocoon will not be able to call the
> render() method. Personally, I have never used FOP's render() method as
> a FOP user. I've always worked with getContentHandler(). I guess the
> Cocoon use-case should be enough to convince you that the
> getContentHandler() is necessary.

The only thing going on in render right now is parser.parse(). Based on your
above answer to #1, Cocoon must be doing something like that internally???
And based on your answer immediately above, it absolutely cannot use
render() to do that. Although I don't grasp why this should be true, taking
it at face value, and assuming that we want FOP to layout this document,
here are the options:
1. The equivalent of parser.parse() that exists in the embedded app (Cocoon)
will need to be wrapped in the code that activates the FOTreeListener. The
code in render() that checks to see whether the LayoutStrategy wants to
build an FOTree or not probably needs to be included as well, and again, it
should probably be extracted into a method, or included in the <before>
method. (This was the code I recently added to accommodate alt-design so
that it could create its own data structure instead of using FOTree).
2. The FOTreeListener concept can be abandoned. Simply restore to the
original scheme, which had the FOTree start the layout process for the
PageSequence as parsing was completed for it. I don't remember exactly where
that is, but it is wherever the FOTreeEvent is being fired. Here are the
costs that I can think of to this approach:
  a. Either LayoutStrategy needs to be abandoned, or the LayoutStrategy
implementation needs to be made available to the method mentioned above that
handles the end of a PageSequence. FONode.getFOTreeControl() can be used for
the latter option. (FOTreeControl is the interface from FOTree to Document).
  b. FOTree independence needs to be abandoned. It was never totally
achieved anyway, and AFAICT I am the only one that thought it was very
important. Alternatively, an additional FOTree interface could be created to
which LayoutStrategy should conform.

> > Part of what is making this a bit ugly is that render() really
> belongs in
> > the Document class, but I don't think that can be done until FOP's API
> > issues are resolved.
>
> Another top-priority todo item on my list that I haven't had time for,
> yet. *sigh*

Sorry, that was not meant as a dig at you.

I have deliberately avoided recommending anything above, as 1) I don't have
an interest in the outcome, and 2) I don't want to start any more fights.
However, please let me know if I can help resolve this. And I'm sorry to be
so dense on Cocoon -- I am familiar with its model at a user level, but must
have a false model in my head about how it does its work.

Also, if possible, please let me know what you decide. I am evaluating
in-progress projects right now to determine which ones I should finish and
which ones I should abandon as I exit the project. If LayoutStrategy
survives reasonably intact, I am much inclined to try to complete the port
of the pioneer LS. If not, then it would be unusable.

Victor Mote

Reply via email to