Peter Donald wrote:
> 
> Hi,
> 
> I have been thinking about how we should handle notification of exceptions
> and events in the kernel and this relates to i18n. First i18n.
> 
> There is a number of ways of doing it. A standard way in the java world is
> to associate each message with a pair. The pair being the name of bundle
> and name of message in bundle. So you would have "kernel.state", "startup"
> as one message and for english it may extract out a string "Entry %s has
> started up". This is stored in separate text files.
> 
> The other approach is to use numeric values ie event 53124 is "Entry %s has
> started up" and these may be held in a constants interface.
> 
> Approach 1 is very good for small systems and is very extensible. It is
> however very difficult to validate it - you end up having to virtually run
> through the code to see if the bundle/message pair actually exists for any
> particular language.
> 
> Approach 2 is much easier to validate but is much harder to extend. It
> scales to massive architectures and many languages.
> 
> Votes/Opinions on either one ?

Having some history with the GNU GetText program, the way they do the change
is similar to #1.  By saying that "Entry %s has ..." is flawed because of
languages that change the form of the word based on its position in the sentence
or plurality is expressed differently.  The GNU coding standards (which say
that for any official product, they have to use GetText) state that the entire
sentence should be keyed.  For example:  We have a resource file with all the
entries for english text, and our code.

// The GetText equivalent way (actually I think the macro converts it to a
// resource number
log.info(resource.get("Entry foo has started up"));

// The unrolled method
log.info(resource.get(Resources.FOO_START));

In the resource, if the foreign lanuage resource does not exist, it falls back
to the english message.  This allows people to contribute by providing 
translations,
and knowing they won't miss one.

Resource.en
-----------
Entry FOO has started up
Entry FOO has shut down
Added extra FOOs
Removed old FOO

Resource.es
-----------
Elemento FOO comence'
Elemento FOO termino'
Incluimo' ma's objectos de FOO
departido FOO viejo

Note: I appologize for the incorrect method of accents, just pretend that
the trailing single quote is over the vowel.  Also notice the last entry:
the ordering of words is different.

This gets even trickier with Russian and Greek where words change based on
grammatical structure.

I vote for a variation of 2 where the whole phrase is included instead of
something that substitute values--unless you want to build a whole inference
engine that will find the right form of the word based on gramatical structure
and plurality.

> The next issue is how to deal with logging/notification/exception. I looked
> at a few architectures and the best of them followed an Aspect Orientated
> Programming approach. They had interface to listeners for each slice
> through the system. So in the end you may have a collection of interfaces
> such as
> 
> ApplicationErrorHandler
> KernelErrorHandler
> BlockErrorHandler
> KernelStatusListener
> ApplicationStatusListener
> BlockStatusListener
> 
> These can be as fine grain or as coarse as is deemed necessary. Now where
> we previously had
> 
> try
> {
> }
> catch( final Exception e )
> {
>   final String message = ...;
>   getLogger().warn( message, e );
>   throw new MyException( message, e );
> }
> 
> it would now be either
> try
> {
> }
> catch( final Exception e )
> {
>   m_errorListener.errorDoingX( ..., e );
> }
> 
> or
> 
> try
> {
> }
> catch( final Exception e )
> {
>   m_errorListener.errorDoingX( ..., e );
>   throw e;
> }
> 
> The second form would force errors to be propogated while the first would
> allow the actual handler to decide the policy. This may be useful if you
> wanted to plough ahead with kernel running even though an application
> failed etc. Policy when responding to such execptions is taken from Fedes
> wishes and is similar to SAX model and discussed Ant model.
> 
> A lot of the logging throughout the kernel/application would also be
> replaced my calling into event listeners. ie instead of
> 
> getLogger().info( "Entry " + name + " did something " );
> 
> It would be
> 
> m_eventListener.somethingOccuredTo( name );
> 
> It would be inside each of these listeners/handlers that the events would
> use a i18n scheme outlined above.

I like that approach.  I would make the listener implement the method like
ErrorListener.error(ErrorListener.ACTION_CONSTANT, Exception e)

so that we can keep the second version of i18n working properly.  This will
also help frameworks like Cocoon in the performance department.  Basically,
I could have a background thread that is the ErrorListener, and asynchronously
log messages without slowing down the performance of the Servlet.  The
integer constant approach will make these evaluations even faster!

+1

Reply via email to