| |
| import org.apache.log4j.AppenderSkeleton; |
| import org.apache.log4j.spi.LoggingEvent; |
| import org.apache.log4j.spi.ErrorHandler; |
| import org.apache.log4j.spi.ErrorCode; |
| import org.apache.log4j.helpers.LogLog; |
| |
| import java.util.Hashtable; |
| import java.util.Properties; |
| import javax.jms.*; |
| import javax.naming.InitialContext; |
| import javax.naming.Context; |
| import javax.naming.NameNotFoundException; |
| import javax.naming.NamingException; |
| |
| /** |
| * A Simple JMS (P2P) Queue Appender. |
| * |
| * @author Ceki Gülcü |
| * @author Jamie Tsao |
| */ |
| public class JMSQueueAppender extends AppenderSkeleton { |
| |
| protected QueueConnection queueConnection; |
| protected QueueSession queueSession; |
| protected QueueSender queueSender; |
| protected Queue queue; |
| |
| String initialContextFactory; |
| String providerUrl; |
| String queueBindingName; |
| String queueConnectionFactoryBindingName; |
| |
| public |
| JMSQueueAppender() { |
| } |
| |
| |
| /** |
| * The <b>InitialContextFactory</b> option takes a string value. |
| * Its value, along with the <b>ProviderUrl</b> option will be used |
| * to get the InitialContext. |
| */ |
| public void setInitialContextFactory(String initialContextFactory) { |
| this.initialContextFactory = initialContextFactory; |
| } |
| |
| /** |
| * Returns the value of the <b>InitialContextFactory</b> option. |
| */ |
| public String getInitialContextFactory() { |
| return initialContextFactory; |
| } |
| |
| /** |
| * The <b>ProviderUrl</b> option takes a string value. |
| * Its value, along with the <b>InitialContextFactory</b> option will be used |
| * to get the InitialContext. |
| */ |
| public void setProviderUrl(String providerUrl) { |
| this.providerUrl = providerUrl; |
| } |
| |
| /** |
| * Returns the value of the <b>ProviderUrl</b> option. |
| */ |
| public String getProviderUrl() { |
| return providerUrl; |
| } |
| |
| /** |
| * The <b>QueueConnectionFactoryBindingName</b> option takes a |
| * string value. Its value will be used to lookup the appropriate |
| * <code>QueueConnectionFactory</code> from the JNDI context. |
| */ |
| public void setQueueConnectionFactoryBindingName(String queueConnectionFactoryBindingName) { |
| this.queueConnectionFactoryBindingName = queueConnectionFactoryBindingName; |
| } |
| |
| /** |
| * Returns the value of the <b>QueueConnectionFactoryBindingName</b> option. |
| */ |
| public String getQueueConnectionFactoryBindingName() { |
| return queueConnectionFactoryBindingName; |
| } |
| |
| /** |
| * The <b>QueueBindingName</b> option takes a |
| * string value. Its value will be used to lookup the appropriate |
| * destination <code>Queue</code> from the JNDI context. |
| */ |
| public void setQueueBindingName(String queueBindingName) { |
| this.queueBindingName = queueBindingName; |
| } |
| |
| /** |
| Returns the value of the <b>QueueBindingName</b> option. |
| */ |
| public String getQueueBindingName() { |
| return queueBindingName; |
| } |
| |
| |
| /** |
| * Overriding this method to activate the options for this class |
| * i.e. Looking up the Connection factory ... |
| */ |
| public void activateOptions() { |
| |
| QueueConnectionFactory queueConnectionFactory; |
| |
| try { |
| |
| Context ctx = getInitialContext(); |
| queueConnectionFactory = (QueueConnectionFactory) ctx.lookup(queueConnectionFactoryBindingName); |
| queueConnection = queueConnectionFactory.createQueueConnection(); |
| |
| queueSession = queueConnection.createQueueSession(false, |
| Session.AUTO_ACKNOWLEDGE); |
| |
| Queue queue = (Queue) ctx.lookup(queueBindingName); |
| queueSender = queueSession.createSender(queue); |
| |
| queueConnection.start(); |
| |
| ctx.close(); |
| |
| } catch(Exception e) { |
| errorHandler.error("Error while activating options for appender named ["+name+ |
| "].", e, ErrorCode.GENERIC_FAILURE); |
| } |
| } |
| |
| protected InitialContext getInitialContext() throws NamingException { |
| try { |
| Hashtable ht = new Hashtable(); |
| |
| //Populate property hashtable with data to retrieve the context. |
| ht.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory); |
| ht.put(Context.PROVIDER_URL, providerUrl); |
| |
| return (new InitialContext(ht)); |
| |
| } catch (NamingException ne) { |
| LogLog.error("Could not get initial context with ["+initialContextFactory + "] and [" + providerUrl + "]."); |
| throw ne; |
| } |
| } |
| |
| |
| protected boolean checkEntryConditions() { |
| |
| String fail = null; |
| |
| if(this.queueConnection == null) { |
| fail = "No QueueConnection"; |
| } else if(this.queueSession == null) { |
| fail = "No QueueSession"; |
| } else if(this.queueSender == null) { |
| fail = "No QueueSender"; |
| } |
| |
| if(fail != null) { |
| errorHandler.error(fail +" for JMSQueueAppender named ["+name+"]."); |
| return false; |
| } else { |
| return true; |
| } |
| } |
| |
| /** |
| * Close this JMSQueueAppender. Closing releases all resources used by the |
| * appender. A closed appender cannot be re-opened. |
| */ |
| public synchronized // avoid concurrent append and close operations |
| void close() { |
| |
| if(this.closed) |
| return; |
| |
| LogLog.debug("Closing appender ["+name+"]."); |
| this.closed = true; |
| |
| try { |
| if(queueSession != null) |
| queueSession.close(); |
| if(queueConnection != null) |
| queueConnection.close(); |
| } catch(Exception e) { |
| LogLog.error("Error while closing JMSQueueAppender ["+name+"].", e); |
| } |
| |
| // Help garbage collection |
| queueSender = null; |
| queueSession = null; |
| queueConnection = null; |
| } |
| |
| /** |
| * This method called by {@link AppenderSkeleton#doAppend} method to |
| * do most of the real appending work. The LoggingEvent will be |
| * be wrapped in an ObjectMessage to be put on the JMS queue. |
| */ |
| public void append(LoggingEvent event) { |
| |
| if(!checkEntryConditions()) { |
| return; |
| } |
| |
| try { |
| |
| ObjectMessage msg = queueSession.createObjectMessage(); |
| msg.setObject(event); |
| queueSender.send(msg); |
| |
| } catch(Exception e) { |
| errorHandler.error("Could not send message in JMSQueueAppender ["+name+"].", e, |
| ErrorCode.GENERIC_FAILURE); |
| } |
| } |
| |
| public boolean requiresLayout() { |
| return false; |
| } |
| } |