Project Report: fawkez

Packagesummary org.jcoderz.commons.logging

org.jcoderz.commons.logging.JmsHandler

LineHitsNoteSource
1  /*
2   * $Id: JmsHandler.java 1011 2008-06-16 17:57:36Z amandel $
3   *
4   * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5   *
6   * Redistribution and use in source and binary forms, with or without
7   * modification, are permitted provided that the following conditions are
8   * met:
9   *
10   *    * Redistributions of source code must retain the above copyright
11   *      notice, this list of conditions and the following disclaimer.
12   *    * Redistributions in binary form must reproduce the above
13   *      copyright notice, this list of conditions and the following
14   *      disclaimer in the documentation and/or other materials
15   *      provided with the distribution.
16   *    * Neither the name of the jCoderZ.org Project nor the names of
17   *      its contributors may be used to endorse or promote products
18   *      derived from this software without specific prior written
19   *      permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32   */
33  package org.jcoderz.commons.logging;
34  
35  import java.io.CharArrayWriter;
36  import java.io.PrintWriter;
37  import java.lang.ref.WeakReference;
38  import java.security.AccessController;
39  import java.security.PrivilegedActionException;
40  import java.security.PrivilegedExceptionAction;
41  import java.util.ArrayList;
42  import java.util.List;
43  import java.util.logging.ErrorManager;
44  import java.util.logging.Filter;
45  import java.util.logging.Formatter;
46  import java.util.logging.Handler;
47  import java.util.logging.LogManager;
48  import java.util.logging.LogRecord;
49  
50  import javax.jms.JMSException;
51  import javax.jms.Queue;
52  import javax.jms.QueueConnection;
53  import javax.jms.QueueConnectionFactory;
54  import javax.jms.QueueSender;
55  import javax.jms.QueueSession;
56  import javax.jms.Session;
57  import javax.jms.TextMessage;
58  import javax.naming.Context;
59  import javax.naming.InitialContext;
60  import javax.naming.NamingException;
61  
62  import org.jcoderz.commons.LoggableImpl;
63  
64  
65  /**
66   * This log handler publishes log messages onto a jms queue. Information for the
67   * configuration has to be provided in the logging properties file.
68   * The following configuration can to be provided:<br>
69   *
70   * <code>org.jcoderz.commons.logging.JmsHandler.factory:</code><br>
71   *    Name of the jms connection factory, is mandatory.<br><br>
72   *
73   * <code>org.jcoderz.commons.logging.JmsHandler.queue:</code><br>
74   *    Name of the jms queue, is mandatory.<br><br>
75   *
76   * <code>org.jcoderz.commons.logging.JmsHandler.filter:</code><br>
77   *    Name of class implementing java.util.logging.Filter and which is to
78   *    set as filter for this. If this is not specified, the default filter is
79   *    used, which filters according to the symbol ids.<br><br>
80   *
81   * <code>org.jcoderz.commons.logging.JmsHandler.messageids:</code><br>
82   *    A comma or space separated list of message symbol ids for those
83   *    messages, which are loggable for the default filter. The ids have either
84   *    to be specified as integer values with base 10, or by prefixing with 0x as
85   *    hex values.
86   *
87   */
88 (1)public class JmsHandler
89        extends Handler
90  {
910    private static final String CLASSNAME = JmsHandler.class.getName();
920    private static final String CLIENT_ID
93           = "JmsHandler@" + LoggableImpl.INSTANCE_ID;
94  
950    private static final String JMS_FACTORY_NAME_PROPERTY
96           = CLASSNAME + "." + "factory";
970    private static final String JMS_QUEUE_NAME_PROPERTY
98           = CLASSNAME + "." + "queue";
990    private static final String JMS_FILTER_PROPERTY
100           = CLASSNAME + "." + "filter";
1010    private static final String JMS_FORMATTER_PROPERTY
102           = CLASSNAME + "." + "formatter";
103  
104     /**
105      * The created sessions to not behave transactional, i.e. do not put a tx
106      * boundary around sending several messages.
107      */
108     private static final boolean SESSION_TRANSACTION_MODE = false;
109  
110     /**
111      * The acknowledge mode, is being ignored for senders.
112      */
113     private static final int SESSION_ACKNOWLEDGE_MODE = Session.AUTO_ACKNOWLEDGE;
114  
115     /**
116      * Stores the jms queue session for the current thread. With respect to the
117      * JMS specification a session and the resources it provides must be used by
118      * only one thread.
119      */
1200    private final ThreadLocal mJmsSessions = new ThreadLocal();
121  
122     /**
123      * Stores the jms queue sender for the current thread.
124      */
1250    private final ThreadLocal mJmsSenders = new ThreadLocal();
126  
127     /**
128      * When closing this handler, all sessions have to be closed (closing a
129      * session is the only session method, which is allowed to be called from
130      * another than the session controlling thread). This gives access to all
131      * sessions and will store WeakReferences to allow a session being garbage
132      * collected if the corresponding thread dies.
133      */
1340    private final List mAllSessions = new ArrayList();
135  
1360    private final LogManager mManager = LogManager.getLogManager();
137  
1380    private QueueConnection mJmsConnection = null;
1390    private Queue mJmsQueue = null;
140  
141     private Context mContext;
142  
143     private String mFactoryName;
144     private String mQueueName;
145  
146     /**
147      * This is the formatter to be used for formatting log records before they
148      * are put onto the jms queue.
149      * It formats the log record into a xml message using the
150      * {@link XmlPrinter}. The stack trace of messages and exceptions is
151      * neglected.
152      *
153      */
154     private static final class DefaultFormatter
155           extends Formatter
156     {
157        /** A PrintWriter is used by the XmlPrinter. */
1580       private final ThreadLocal mPrintWriters = new ThreadLocal();
159        /** A CharWriter is used by the PrintWriter. */
1600       private final ThreadLocal mCharWriters = new ThreadLocal();
161  
162        private final XmlPrinter mXmlPrinter;
163        private final DisplayOptions mDisplayOptions;
164  
165        private DefaultFormatter ()
166              throws InstantiationException
1670       {
1680          mXmlPrinter = new XmlPrinter();
1690(2)         mDisplayOptions = new DisplayOptions();
1700          mDisplayOptions.displayMessageStackTrace(false);
1710          mDisplayOptions.displayStackTrace(false);
1720          mXmlPrinter.setDisplayOptions(mDisplayOptions);
1730       }
174  
175        /** {@inheritDoc} */
176        public String format (LogRecord record)
177        {
1780          final CharArrayWriter writer = getCharWriter();
1790          writer.reset();
1800          final PrintWriter printer = getPrintWriter();
1810          mXmlPrinter.print(printer, new LogElement(record));
1820          return writer.toString();
183        }
184  
185        private PrintWriter getPrintWriter ()
186        {
1870          PrintWriter rc = (PrintWriter) mPrintWriters.get();
1880          if (rc == null)
189           {
1900             final CharArrayWriter cw = getCharWriter();
1910             rc = new PrintWriter(cw);
1920             mPrintWriters.set(rc);
193           }
1940          return rc;
195        }
196  
197        private CharArrayWriter getCharWriter ()
198        {
1990          CharArrayWriter rc = (CharArrayWriter) mCharWriters.get();
2000          if (rc == null)
201           {
2020             rc = new CharArrayWriter();
2030             mCharWriters.set(rc);
204           }
2050          return rc;
206        }
207     }
208  
209  
210     /**
211      * Creates a new instance of this and initialises resources. It retrieves
212      * configuration parameters from the LogManagers and connects to the jms
213      * provider.
214      *
215      * @throws SecurityException If no permission to do the tasks.
216      * @throws NamingException If the jms connection factory lookup fails.
217      * @throws InstantiationException If not all required configuration
218      * parameters are specified.
219      * @throws IllegalAccessException If illegal access to a class.
220      * @throws ClassNotFoundException If a specified class name could not be
221      * found.
222      * @throws JMSException If an error connecting to the JmsProvider occurs.
223      */
224     public JmsHandler ()
225           throws SecurityException,
226           NamingException,
227           InstantiationException,
228           IllegalAccessException,
229           ClassNotFoundException,
230           JMSException
231     {
2320       super();
2330       mManager.checkAccess();
2340       configure();
2350       connect();
2360    }
237  
238     /** {@inheritDoc} */
239     public void close ()
240           throws SecurityException
241     {
2420       mManager.checkAccess();
2430       setFormatter(null);
2440       setFilter(null);
2450       synchronized (mAllSessions)
246        {
2470          while (! mAllSessions.isEmpty())
248           {
2490             final WeakReference ref = (WeakReference) mAllSessions.remove(0);
2500             final QueueSession session = (QueueSession) ref.get();
2510             if (session != null)
252              {
253                 try
254                 {
2550                   session.close();
256                 }
2570                catch (Exception ex)
258                 {
2590                   reportError("Error closing jms session: " + session,
260                          ex, ErrorManager.CLOSE_FAILURE);
2610                }
262              }
2630          }
2640       }
265        try
266        {
2670          mJmsConnection.close();
268        }
2690       catch (JMSException jex)
270        {
2710          reportError("Error closing jms connection: " + mJmsConnection,
272                 jex, ErrorManager.CLOSE_FAILURE);
2730       }
2740    }
275  
276     /** {@inheritDoc} */
277     public void flush ()
278     {
279        // nop
2800    }
281  
282     /** {@inheritDoc} */
283     public void publish (final LogRecord record)
284     {
2850       if (getFilter().isLoggable(record))
286        {
2870          sendRecord(record);
288        }
2890    }
290  
291     private void configure ()
292           throws NamingException,
293           SecurityException,
294           InstantiationException,
295           IllegalAccessException,
296           ClassNotFoundException
297     {
2980       configureJndiContext();
2990       configureResources();
3000       configureFilter();
3010       configureFormatter();
3020    }
303  
304     private void configureJndiContext ()
305           throws NamingException
306     {
3070       final Context context = new InitialContext();
3080       mContext = context;
3090    }
310  
311     private void configureFilter ()
312           throws SecurityException,
313           InstantiationException,
314           IllegalAccessException,
315           ClassNotFoundException
316     {
3170       final String filterClass = mManager.getProperty(JMS_FILTER_PROPERTY);
3180       if (filterClass == null || filterClass.length() == 0)
319        {
3200          setFilter(new MessageIdFilter());
321        }
322        else
323        {
324           try
325           {
3260             AccessController.doPrivileged(
327                    new PrivilegedExceptionAction()
3280                   {
329                       public Object run ()
330                             throws SecurityException,
331                             InstantiationException,
332                             IllegalAccessException,
333                             ClassNotFoundException
334                       {
3350                         setFilter((Filter) Class.forName(filterClass)
336                                .newInstance());
3370                         return null;
338                       }
339                    }
340              );
341          }
3420         catch (PrivilegedActionException e)
343          {
3440            final InstantiationException iex = new InstantiationException(
345                   "Could not install the Filter: " + filterClass);
3460            iex.initCause(e);
3470            throw iex;
3480         }
349        }
3500    }
351  
352     private void configureFormatter ()
353           throws SecurityException,
354           InstantiationException,
355           IllegalAccessException,
356           ClassNotFoundException
357     {
3580       final String formatter = mManager.getProperty(JMS_FORMATTER_PROPERTY);
3590       if (formatter == null || formatter.length() == 0)
360        {
3610          setFormatter(new DefaultFormatter());
362        }
363        else
364        {
365           try
366           {
3670             AccessController.doPrivileged(
368                    new PrivilegedExceptionAction()
3690                   {
370                       public Object run ()
371                             throws SecurityException,
372                             InstantiationException,
373                             IllegalAccessException,
374                             ClassNotFoundException
375                       {
3760                         setFormatter((Formatter) Class.forName(formatter)
377                                .newInstance());
3780                         return null;
379                       }
380                    }
381              );
382           }
3830          catch (PrivilegedActionException e)
384           {
3850             final InstantiationException iex
386                    = new InstantiationException(
387                          "Could not install the Formatter: " + formatter);
3880             iex.initCause(e);
3890             throw iex;
3900          }
391        }
3920    }
393  
394     private void configureResources ()
395           throws InstantiationException
396     {
3970       final String factory = mManager.getProperty(JMS_FACTORY_NAME_PROPERTY);
3980       if ((factory == null) || (factory.length() == 0))
399        {
4000          throw new InstantiationException("No jms connection factory configured"
401                 + " in properties file with property: "
402                 + JMS_FACTORY_NAME_PROPERTY);
403        }
4040       final String queue = mManager.getProperty(JMS_QUEUE_NAME_PROPERTY);
4050       if ((queue == null) || (queue.length() == 0))
406        {
4070          throw new InstantiationException("No jms queue configured in "
408                 + "properties file with property: " + JMS_QUEUE_NAME_PROPERTY);
409        }
4100       mFactoryName = factory;
4110       mQueueName = queue;
4120    }
413  
414     /**
415      * Creates a connection to the jms provider and performs a lookup for the
416      * queue, which will receive the log messages.
417      *
418      * @throws NamingException
419    * @throws JMSException
420    */
421     private void connect ()
422           throws NamingException, JMSException
423     {
4240       final QueueConnectionFactory factory
425              = (QueueConnectionFactory) mContext.lookup(mFactoryName);
4260       final Queue queue = (Queue) mContext.lookup(mQueueName);
427  
4280       mJmsConnection = factory.createQueueConnection();
4290       mJmsConnection.setClientID(CLIENT_ID);
4300       mJmsQueue = queue;
4310    }
432  
433     /**
434      * Gets the queue sender for the current thread. If there is no sender yet,
435      * this thread's session is used for creating a new sender.
436      *
437      * @return queue sender for the current thread.
438      *
439      * @throws JMSException if an error occurs.
440      */
441     private QueueSender getSender ()
442           throws JMSException
443     {
4440       QueueSender rc = (QueueSender) mJmsSenders.get();
4450       if (rc == null)
446        {
447           try
448           {
4490             rc = (QueueSender) AccessController.doPrivileged(
450                    new PrivilegedExceptionAction()
4510                   {
452                       public Object run ()
453                             throws JMSException
454                       {
4550                         return installSender();
456                       }
457                    });
458           }
4590          catch (PrivilegedActionException e)
460           {
4610             final JMSException jex
462                    = new JMSException("Could not install a QueueSender:" + e);
4630             jex.initCause(e);
4640             throw jex;
4650          }
466        }
4670       return rc;
468     }
469  
470     /**
471      * Gets the queue session for the current thread. If there is no session yet,
472      * a new session is created and initialized.
473      *
474      * @return queue session for the current thread.
475      *
476      * @throws JMSException if an error occurs.
477      */
478     private QueueSession getSession ()
479           throws JMSException
480     {
4810       QueueSession rc = (QueueSession) mJmsSessions.get();
4820       if (rc == null)
483        {
4840          final QueueSession session = mJmsConnection.createQueueSession(
485                 SESSION_TRANSACTION_MODE, SESSION_ACKNOWLEDGE_MODE);
4860          mJmsSessions.set(session);
4870          synchronized (mAllSessions)
488           {
4890             mAllSessions.add(new WeakReference(session));
4900          }
4910          rc = session;
492        }
4930       return rc;
494     }
495  
496     private QueueSender installSender ()
497           throws JMSException
498     {
4990       final QueueSession session = getSession();
5000       QueueSender sender = null;
501        try
502        {
5030          sender = session.createSender(mJmsQueue);
5040          mJmsSenders.set(sender);
505        }
506        finally
507        {
5080          if (sender == null)
509           {
510              // An error ocurred on this session. Close it, it might occur again.
5110             mJmsSessions.set(null);
5120             session.close();
513           }
514        }
5150       return sender;
516     }
517  
518     private void sendRecord (final LogRecord record)
519     {
5200       String text = null;
521        try
522        {
5230          text = getFormatter().format(record);
524        }
5250       catch (Exception ex)
526        {
5270          reportError("Error formatting the log record",
528                 ex, ErrorManager.FORMAT_FAILURE);
5290       }
5300       if (text != null)
531        {
532           try
533           {
5340             final TextMessage msg = getSession().createTextMessage();
5350             msg.setText(text);
5360             getSender().send(msg);
537           }
5380          catch (JMSException ex)
539           {
5400             reportError("Error publishing a log record", ex,
541                    ErrorManager.WRITE_FAILURE);
5420          }
543        }
5440    }
545  }

Findings in this File

c (3) Got an exception - java.lang.RuntimeException: Unable to get class information for @throws tag 'JMSException'.
c (1) 88 : 0 Type Javadoc comment is missing an @author tag.
w (2) 169 : 0 class org.jcoderz.commons.logging.JmsHandler$DefaultFormatter defines fields that are used only as locals