You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-dev@xmlgraphics.apache.org by Stefano Mazzocchi <st...@apache.org> on 1999/12/02 12:47:46 UTC

Message Handlers

James Tauber wrote:
> 
> I'm just about to move FOP over to using a MessageHandler.
> 
> There seems to be agreement on the design. I'm having trouble with the
> naming :-)

I would like to see the proposed interface/classes or method addictions.
Expecially because all the Apache XML projects should follow the same
APIs or, at least, the same design patterns to allow applications to use
a common way of presenting messages to its users.

For Cocoon in particular, it's a pain to have all the different packages
behave uniformly from a user point of view. Right now, I only catch
exceptions and pretty print them on the HTML page requested, but I would
like to have better inteface to be able to provide information about the
error "context", for example

    <a>
     </b>
    </c>
     ^^_______ element "c" mismatching.

> As I see it, there should be an interface MessageHandler than all message
> handlers implement. 

Ok.

public interface MessageHandler {
     public static final int CRITICAL = 0
     public static final int ERROR = 1
     public static final int WARNING = 2
     public static final int INFO = 3
     public static final int DEBUG = 4

     public void log(String message, int priority);
     public void exception(Throwable exception);
}

[...]

> Now there is the class that simply has two static methods: getMessageHandler
> and setMessageHandler. My question is: WHAT SHOULD THIS CLASS BE CALLED?
> 
> I initially thought MessageHandlerFactory, but it isn't. It doesn't create
> message handlers, it merely provides a globally accessible point to retrieve
> the message handler to use.

I wouldn't like to use static methods for this. Keep in mind that FOP
must also run in concurrent systems. Static things should be used only
for Singleton patterns, but FOP does not (nor should) implement the
singleton pattern.

What about having

 public interface MessageProducer {
    setMessageConsumer(MessageConsumer consumer);
 }

 public interface MessageConsumer {
    void log(...)
    //possible other message consuming methods
 }

this uses the "Producer/Consumer" pattern and

 Driver implements MessageProducer

 MessageHandler implements MessageConsumer

and Cocoon could implement its own MessageConsumer that keeps the
messages hidden in they are lower than a configured priority level, or
it shows them on the requested page for more direct user feedback.

How does it sound?  
-- 
Stefano Mazzocchi      One must still have chaos in oneself to be
                          able to give birth to a dancing star.
<st...@apache.org>                             Friedrich Nietzsche



Locator interface in SAX Parsers [ OFFTOPIC ]

Posted by Arved Sandstrom <Ar...@chebucto.ns.ca>.
I thought this would be about as good a place as any to ask this question.
There isn't a comp.text.xml.programming.java.saxparsers newsgroup that I'm
aware of. :-)

I've been working on a web resource for MacOS XML processing, and as part
of that I set up a little SAX application that ought to be able to use any
SAX parser. Here's the rub - it uses Locator info. SAX doesn't require a
parser to implement Locator, it just strongly encourages it, and XP, for
example, does.

xml4j (I've been using the 2.0.15 version) does _not_. I have to assume
that maybe, in that case, neither does Xerces-J. A Locator _is_ used, but
it's internal, and can beobtained by calling a getLocator() method.

So, the problem is, I want to write a generic app that only imports
org.xml.sax and standard Java. No reference to XP or xml4j or whatever. If
all the parsers implemented Locator I could just cast the parser instance
to Locator, and pass that to setDocumentLocator on the DocumentHandler.
But because of xml4j this is a no-go.

So I looked at reflection. Get the Class object for the parser, get the
name, and if that equals "com.ibm.xml.parsers.SAXParser", for example,
then I use getMethod() on the class, and use invoke() on the method. No
need to hardwire anything that would require imports of specific parser
classes.

Next problem: getLocator() is a protected method. getMethod() only
reflects public methods. So at this point I'm thinking that I can not
actually write a generic SAX application that uses Locator, and that can
handle both XP and xml4j, and _not_ import xml4j.jar at compile time.

Any thoughts on this? Am I missing something here? It also occurred to me
that this is one instance of switching between XP and xml4j (by extension,
Xerces-J) not being so routine. Maybe there are more. Since we are
transitioning FOP over to Xerces-J, _but_ retaining the ability to specify
XP, maybe this won't be as trouble-free as we expect. Just a thought.

Regards, Arved Sandstrom




Re: Message Handlers

Posted by Stefano Mazzocchi <st...@apache.org>.
James Tauber wrote:
> 
> > I wouldn't like to use static methods for this. Keep in mind that FOP
> > must also run in concurrent systems. Static things should be used only
> > for Singleton patterns, but FOP does not (nor should) implement the
> > singleton pattern.
> 
> Actually, I thought it was you that suggested the Singleton pattern in the
> first place :-)

Well, I changed my mind. You must be _really_ careful about using static
stuff in java on the server side (on the client side you could even have
all of your code static, yuck, but you can do it).

A little info for you: a servlet is instantiated once and called by all
requesting clients. Yes, you have just one servlet instance in memory
(per servlet context) and if you have tons of people requesting the same
page, the page gets generated by the same exact servlet.

So, suppose you have something like this:

 service() {
  Fop fop = new FOP();

  // create document

  fop.log("Start formatting...");
  fop.format(document);
  fop.log("End formatting...");
  ...
 }

this turns out to be thread safe since you get different FOP instances
in memory, one for each servlet execution.

But suppose you have fop.log() static. Let's take a look at a possible
log file

  Start formatting
  Start formatting
  Start formatting
  End formatting

Who was done formatting?

True, you could have something like

 public static void log(String message) {
   log(Thread.getCurrentThread() + ": " + message);
 }

or

 public static void log(Object producer, String message);

that keeps track of concurrenty issues, but still...

> > this uses the "Producer/Consumer" pattern and
> >
> >  Driver implements MessageProducer
> >
> >  MessageHandler implements MessageConsumer
> [...]
> > How does it sound?
> 
> Good except that it is unclear to me how an object down in the depths of
> formatting is to know which consumers to inform? 

Ok, right this is the issue.

The "Contextualizable" design patter does the job:

- every "Contextualizable" object should have a constructor which takes
an object as working "Context".
- this context encapsulates the methods needed for the object to
"behave" in respect with the other objects in the same context.
- since the context is pushed, we follow the "inversion of control"
principle which guarantees the object sees only what we want it to see
and the concurrency problems are hidden from the object implementation.

> When
> org.apache.fop.layout.LineArea wants to let those who'll listen that an area
> has overflowed, how does it know who to tell unless either:
> 
> 1) there is a static method on some class that will tell it (which is what
> you are arguing against)

yes. We might not be able to tell, what document generated that error.
Which makes the log totally useless.

> 2) the listeners are registered with lots of different classes (this doesn't
> seem right. Mind you, it isn't as bad as I first thought. All areas, for
> example, know the AreaTree they are part of so listeners would only have to
> register with AreaTree and messages from any area could get to them.)

Right. You could use the "AreaTree" as the object context, or rethink
the internal machinery using a better context-aware approach.

I'm not completely familiar with the FOP internals, so I might state the
obvious here, but you should use static methods only for singleton
stuff.

Mind you, something like this might work as well:

 public static MessageConsumer getMessageConsumer(Object
MessageProducer);

but this is clearly different. On the other hand, you would need
something like

 public void registerMessageConsumer(MessageConsumer consumer);

to allow other programs to use FOP with their own log channels.

What do you think?

-- 
Stefano Mazzocchi      One must still have chaos in oneself to be
                          able to give birth to a dancing star.
<st...@apache.org>                             Friedrich Nietzsche



Re: Message Handlers

Posted by James Tauber <jt...@jtauber.com>.
> I wouldn't like to use static methods for this. Keep in mind that FOP
> must also run in concurrent systems. Static things should be used only
> for Singleton patterns, but FOP does not (nor should) implement the
> singleton pattern.

Actually, I thought it was you that suggested the Singleton pattern in the
first place :-)

> this uses the "Producer/Consumer" pattern and
>
>  Driver implements MessageProducer
>
>  MessageHandler implements MessageConsumer
[...]
> How does it sound?

Good except that it is unclear to me how an object down in the depths of
formatting is to know which consumers to inform? When
org.apache.fop.layout.LineArea wants to let those who'll listen that an area
has overflowed, how does it know who to tell unless either:

1) there is a static method on some class that will tell it (which is what
you are arguing against)
2) the listeners are registered with lots of different classes (this doesn't
seem right. Mind you, it isn't as bad as I first thought. All areas, for
example, know the AreaTree they are part of so listeners would only have to
register with AreaTree and messages from any area could get to them.)

?

James