View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * 
4    * Copyright (C) 1999-2006, QOS.ch
5    * 
6    * This library is free software, you can redistribute it and/or modify it under
7    * the terms of the GNU Lesser General Public License as published by the Free
8    * Software Foundation.
9    */
10  
11  package ch.qos.logback.classic.net;
12  
13  import javax.jms.ObjectMessage;
14  import javax.jms.Queue;
15  import javax.jms.QueueConnection;
16  import javax.jms.QueueConnectionFactory;
17  import javax.jms.QueueSender;
18  import javax.jms.QueueSession;
19  import javax.jms.Session;
20  import javax.naming.Context;
21  
22  import ch.qos.logback.classic.spi.LoggingEvent;
23  import ch.qos.logback.core.AppenderBase;
24  import ch.qos.logback.core.net.JMSAppenderBase;
25  
26  /**
27   * A simple appender that publishes events to a JMS Queue. The events are
28   * serialized and transmitted as JMS message type {@link
29   * javax.jms.ObjectMessage}.
30   * <p>
31   * For more information about this appender, please refer to:
32   * http://logback.qos.ch/manual/appenders.html#JMSQueueAppender
33   * 
34   * @author Ceki G&uuml;lc&uuml;
35   */
36  public class JMSQueueAppender extends JMSAppenderBase<LoggingEvent> {
37  
38    static int SUCCESSIVE_FAILURE_LIMIT = 3;
39  
40    String queueBindingName;
41    String qcfBindingName;
42    QueueConnection queueConnection;
43    QueueSession queueSession;
44    QueueSender queueSender;
45  
46    int successiveFailureCount = 0;
47  
48    public JMSQueueAppender() {
49    }
50  
51    /**
52     * The <b>QueueConnectionFactoryBindingName</b> option takes a string value.
53     * Its value will be used to lookup the appropriate
54     * <code>QueueConnectionFactory</code> from the JNDI context.
55     */
56    public void setQueueConnectionFactoryBindingName(String qcfBindingName) {
57      this.qcfBindingName = qcfBindingName;
58    }
59  
60    /**
61     * Returns the value of the <b>QueueConnectionFactoryBindingName</b> option.
62     */
63    public String getQueueConnectionFactoryBindingName() {
64      return qcfBindingName;
65    }
66  
67    /**
68     * The <b>QueueBindingName</b> option takes a string value. Its value will be
69     * used to lookup the appropriate <code>Queue</code> from the JNDI context.
70     */
71    public void setQueueBindingName(String queueBindingName) {
72      this.queueBindingName = queueBindingName;
73    }
74  
75    /**
76     * Returns the value of the <b>QueueBindingName</b> option.
77     */
78    public String getQueueBindingName() {
79      return queueBindingName;
80    }
81  
82    /**
83     * Options are activated and become effective only after calling this method.
84     */
85    public void start() {
86      QueueConnectionFactory queueConnectionFactory;
87  
88      try {
89        Context jndi = buildJNDIContext();
90  
91        // addInfo("Looking up [" + qcfBindingName + "]");
92        queueConnectionFactory = (QueueConnectionFactory) lookup(jndi,
93            qcfBindingName);
94        // addInfo("About to create QueueConnection.");
95        if (userName != null) {
96          this.queueConnection = queueConnectionFactory.createQueueConnection(
97              userName, password);
98        } else {
99          this.queueConnection = queueConnectionFactory.createQueueConnection();
100       }
101 
102       // addInfo(
103       // "Creating QueueSession, non-transactional, "
104       // + "in AUTO_ACKNOWLEDGE mode.");
105       this.queueSession = queueConnection.createQueueSession(false,
106           Session.AUTO_ACKNOWLEDGE);
107 
108       // addInfo("Looking up queue name [" + queueBindingName + "].");
109       Queue queue = (Queue) lookup(jndi, queueBindingName);
110 
111       // addInfo("Creating QueueSender.");
112       this.queueSender = queueSession.createSender(queue);
113 
114       // addInfo("Starting QueueConnection.");
115       queueConnection.start();
116 
117       jndi.close();
118     } catch (Exception e) {
119       addError("Error while activating options for appender named [" + name
120           + "].", e);
121     }
122 
123     if (this.queueConnection != null && this.queueSession != null
124         && this.queueSender != null) {
125       super.start();
126     }
127   }
128 
129   /**
130    * Close this JMSAppender. Closing releases all resources used by the
131    * appender. A closed appender cannot be re-opened.
132    */
133   public synchronized void stop() {
134     // The synchronized modifier avoids concurrent append and close operations
135     if (!this.started) {
136       return;
137     }
138 
139     this.started = false;
140 
141     try {
142       if (queueSession != null) {
143         queueSession.close();
144       }
145       if (queueConnection != null) {
146         queueConnection.close();
147       }
148     } catch (Exception e) {
149       addError("Error while closing JMSAppender [" + name + "].", e);
150     }
151 
152     // Help garbage collection
153     queueSender = null;
154     queueSession = null;
155     queueConnection = null;
156   }
157 
158   /**
159    * This method called by {@link AppenderBase#doAppend} method to do most
160    * of the real appending work.
161    */
162   public void append(LoggingEvent event) {
163     if (!isStarted()) {
164       return;
165     }
166 
167     try {
168       ObjectMessage msg = queueSession.createObjectMessage();
169       msg.setObject(event);
170       queueSender.send(msg);
171       successiveFailureCount = 0;
172     } catch (Exception e) {
173       successiveFailureCount++;
174       if (successiveFailureCount > SUCCESSIVE_FAILURE_LIMIT) {
175         stop();
176       }
177       addError("Could not send message in JMSQueueAppender [" + name + "].", e);
178 
179     }
180   }
181 
182   /**
183    * Returns the QueueConnection used for this appender. Only valid after
184    * start() method has been invoked.
185    */
186   protected QueueConnection getQueueConnection() {
187     return queueConnection;
188   }
189 
190   /**
191    * Returns the QueueSession used for this appender. Only valid after start()
192    * method has been invoked.
193    */
194   protected QueueSession getQueueSession() {
195     return queueSession;
196   }
197 
198   /**
199    * Returns the QueueSender used for this appender. Only valid after start()
200    * method has been invoked.
201    */
202   protected QueueSender getQueueSender() {
203     return queueSender;
204   }
205 }