svn commit: r1192 - in logback/trunk/logback-classic: . src/main/java/ch/qos/logback/classic/net src/test/java/ch/qos/logback/classic/net src/test/java/ch/qos/logback/classic/net/mock

Author: seb Date: Wed Jan 10 21:47:21 2007 New Revision: 1192 Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/JMSQueueAppender.java logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/JMSQueueSink.java logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/JMSTopicAppender.java logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/JMSTopicSink.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/JMSQueueAppenderTestApp.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/JMSTopicAppenderTest.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/JMSTopicAppenderTestApp.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockInitialContext.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockInitialContextFactory.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockObjectMessage.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockSocketServer.java - copied, changed from r1184, /logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/MockSocketServer.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockSyslogServer.java - copied, changed from r1184, /logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/MockSyslogServer.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopic.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopicConnection.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopicConnectionFactory.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopicPublisher.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopicSession.java Removed: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/MockSocketServer.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/MockSyslogServer.java Modified: logback/trunk/logback-classic/pom.xml logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/PackageTest.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SocketAppenderTest.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SyslogAppenderTest.java Log: Moved MockSocketServer and MockSyslogServer to mock package Added mock objects to test JMSTopicAppender Modified: logback/trunk/logback-classic/pom.xml ============================================================================== --- logback/trunk/logback-classic/pom.xml (original) +++ logback/trunk/logback-classic/pom.xml Wed Jan 10 21:47:21 2007 @@ -70,12 +70,12 @@ <classifier>tests</classifier> <scope>test</scope> </dependency> - <!-- + <dependency> <groupId>javax.jms</groupId> <artifactId>jms</artifactId> </dependency> - --> + </dependencies> <build> Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/JMSQueueAppender.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/JMSQueueAppender.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,414 @@ +/** + * Logback: the reliable, generic, fast and flexible logging framework. + * + * Copyright (C) 1999-2006, QOS.ch + * + * This library is free software, you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation. + */ + +package ch.qos.logback.classic.net; + +import java.util.Hashtable; +import java.util.Properties; + +import javax.jms.ObjectMessage; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.QueueSender; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NameNotFoundException; +import javax.naming.NamingException; + +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.AppenderBase; + +/** + * A simple appender that publishes events to a JMS Queue. The events are + * serialized and transmitted as JMS message type {@link + * javax.jms.ObjectMessage}. + * + * <p> + * JMS {@link javax.jms.Queue queues} and + * {@link javax.jms.QueueConnectionFactory queue connection factories} are + * administered objects that are retrieved using JNDI messaging which in turn + * requires the retreival of a JNDI {@link Context}. + * + * <p> + * There are two common methods for retrieving a JNDI {@link Context}. If a file + * resource named <em>jndi.properties</em> is available to the JNDI API, it + * will use the information found therein to retrieve an initial JNDI context. + * To obtain an initial context, your code will simply call: + * + * <pre> + * InitialContext jndiContext = new InitialContext(); + * </pre> + * + * <p> + * Calling the no-argument <code>InitialContext()</code> method will also work + * from within Enterprise Java Beans (EJBs) because it is part of the EJB + * contract for application servers to provide each bean an environment naming + * context (ENC). + * + * <p> + * In the second approach, several predetermined properties are set and these + * properties are passed to the <code>InitialContext</code> contructor to + * connect to the naming service provider. For example, to connect to JBoss + * naming service one would write: + * + * <pre> + * Properties env = new Properties(); + * env.put(Context.INITIAL_CONTEXT_FACTORY, + * "org.jnp.interfaces.NamingContextFactory"); + * env.put(Context.PROVIDER_URL, "jnp://hostname:1099"); + * env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); + * InitialContext jndiContext = new InitialContext(env); + * </pre> + * + * where <em>hostname</em> is the host where the JBoss applicaiton server is + * running. + * + * <p> + * To connect to the the naming service of Weblogic application server one would + * write: + * + * <pre> + * Properties env = new Properties(); + * env.put(Context.INITIAL_CONTEXT_FACTORY, + * "weblogic.jndi.WLInitialContextFactory"); + * env.put(Context.PROVIDER_URL, "t3://localhost:7001"); + * InitialContext jndiContext = new InitialContext(env); + * </pre> + * + * <p> + * Other JMS providers will obviously require different values. + * + * The initial JNDI context can be obtained by calling the no-argument + * <code>InitialContext()</code> method in EJBs. Only clients running in a + * separate JVM need to be concerned about the <em>jndi.properties</em> file + * and calling {@link InitialContext#InitialContext()} or alternatively + * correctly setting the different properties before calling {@link + * InitialContext#InitialContext(java.util.Hashtable)} method. + * + * + * @author Ceki Gülcü + */ +public class JMSQueueAppender extends AppenderBase<LoggingEvent> { + + static int SUCCESSIVE_FAILURE_LIMIT = 3; + + String securityPrincipalName; + String securityCredentials; + String initialContextFactoryName; + String urlPkgPrefixes; + String providerURL; + String queueBindingName; + String qcfBindingName; + String userName; + String password; + QueueConnection queueConnection; + QueueSession queueSession; + QueueSender queueSender; + + boolean inOrder = false; + int successiveFailureCount = 0; + + public JMSQueueAppender() { + } + + /** + * 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 tcfBindingName) { + this.qcfBindingName = tcfBindingName; + } + + /** + * Returns the value of the <b>QueueConnectionFactoryBindingName</b> option. + */ + public String getQueueConnectionFactoryBindingName() { + return qcfBindingName; + } + + /** + * The <b>QueueBindingName</b> option takes a string value. Its value will be + * used to lookup the appropriate <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; + } + + /** + * Options are activated and become effective only after calling this method. + */ + public void start() { + QueueConnectionFactory queueConnectionFactory; + + try { + Context jndi; + + //addInfo("Getting initial context."); + if (initialContextFactoryName != null) { + Properties env = new Properties(); + env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactoryName); + if (providerURL != null) { + env.put(Context.PROVIDER_URL, providerURL); + } else { + addWarn( + "You have set InitialContextFactoryName option but not the " + + "ProviderURL. This is likely to cause problems."); + } + if (urlPkgPrefixes != null) { + env.put(Context.URL_PKG_PREFIXES, urlPkgPrefixes); + } + + if (securityPrincipalName != null) { + env.put(Context.SECURITY_PRINCIPAL, securityPrincipalName); + if (securityCredentials != null) { + env.put(Context.SECURITY_CREDENTIALS, securityCredentials); + } else { + addWarn( + "You have set SecurityPrincipalName option but not the " + + "SecurityCredentials. This is likely to cause problems."); + } + } + jndi = new InitialContext(env); + } else { + jndi = new InitialContext(); + } + + //addInfo("Looking up [" + qcfBindingName + "]"); + queueConnectionFactory = + (QueueConnectionFactory) lookup(jndi, qcfBindingName); + //addInfo("About to create QueueConnection."); + if (userName != null) { + this.queueConnection = + queueConnectionFactory.createQueueConnection(userName, password); + } else { + this.queueConnection = queueConnectionFactory.createQueueConnection(); + } + + //addInfo( + // "Creating QueueSession, non-transactional, " + // + "in AUTO_ACKNOWLEDGE mode."); + this.queueSession = + queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + + //addInfo("Looking up queue name [" + queueBindingName + "]."); + Queue queue = (Queue) lookup(jndi, queueBindingName); + + //addInfo("Creating QueueSender."); + this.queueSender = queueSession.createSender(queue); + + //addInfo("Starting QueueConnection."); + queueConnection.start(); + + jndi.close(); + } catch (Exception e) { + addError( + "Error while activating options for appender named [" + name + "].", e); + } + + + if (this.queueConnection != null && this.queueSession != null && this.queueSender != null) { + inOrder = true; + } else { + inOrder = false; + } + if(inOrder) { + super.start(); + } + } + + protected Object lookup(Context ctx, String name) throws NamingException { + try { + return ctx.lookup(name); + } catch (NameNotFoundException e) { + addError("Could not find name [" + name + "]."); + throw e; + } + } + + /** + * Close this JMSAppender. Closing releases all resources used by the + * appender. A closed appender cannot be re-opened. + */ + public synchronized void stop() { + // The synchronized modifier avoids concurrent append and close operations + if (!this.started) { + return; + } + + this.started = false; + + try { + if (queueSession != null) { + queueSession.close(); + } + if (queueConnection != null) { + queueConnection.close(); + } + } catch (Exception e) { + addError("Error while closing JMSAppender [" + name + "].", e); + } + + // Help garbage collection + queueSender = null; + queueSession = null; + queueConnection = null; + } + + /** + * Gets whether appender is properly configured to append messages. + * + * @return true if properly configured. + */ + protected boolean checkEntryConditions() { + return inOrder; + } + + /** + * This method called by {@link AppenderSkeleton#doAppend} method to do most + * of the real appending work. + */ + public void append(LoggingEvent event) { + if (!checkEntryConditions()) { + return; + } + + try { + ObjectMessage msg = queueSession.createObjectMessage(); + + // manage caller data + + msg.setObject(event); + queueSender.send(msg); + successiveFailureCount = 0; + } catch (Exception e) { + successiveFailureCount++; + if (successiveFailureCount > SUCCESSIVE_FAILURE_LIMIT) { + inOrder = false; + } + addError("Could not send message in JMSAppender [" + name + "].", e); + + } + } + + /** + * Returns the value of the <b>InitialContextFactoryName</b> option. See + * {@link #setInitialContextFactoryName} for more details on the meaning of + * this option. + */ + public String getInitialContextFactoryName() { + return initialContextFactoryName; + } + + /** + * Setting the <b>InitialContextFactoryName</b> method will cause this + * <code>JMSAppender</code> instance to use the {@link + * InitialContext#InitialContext(Hashtable)} method instead of the no-argument + * constructor. If you set this option, you should also at least set the + * <b>ProviderURL</b> option. + * + * <p> + * See also {@link #setProviderURL(String)}. + */ + public void setInitialContextFactoryName(String initialContextFactoryName) { + this.initialContextFactoryName = initialContextFactoryName; + } + + public String getProviderURL() { + return providerURL; + } + + public void setProviderURL(String providerURL) { + this.providerURL = providerURL; + } + + String getURLPkgPrefixes() { + return urlPkgPrefixes; + } + + public void setURLPkgPrefixes(String urlPkgPrefixes) { + this.urlPkgPrefixes = urlPkgPrefixes; + } + + public String getSecurityCredentials() { + return securityCredentials; + } + + public void setSecurityCredentials(String securityCredentials) { + this.securityCredentials = securityCredentials; + } + + public String getSecurityPrincipalName() { + return securityPrincipalName; + } + + public void setSecurityPrincipalName(String securityPrincipalName) { + this.securityPrincipalName = securityPrincipalName; + } + + public String getUserName() { + return userName; + } + + /** + * The user name to use when {@link + * javax.jms.TopicConnectionFactory#createTopicConnection(String, String)} + * creating a topic session}. If you set this option, you should also set the + * <b>Password</b> option. See {@link #setPassword(String)}. + */ + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + /** + * The paswword to use when creating a topic session. + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Returns the QueueConnection used for this appender. Only valid after + * start() method has been invoked. + */ + protected QueueConnection getQueueConnection() { + return queueConnection; + } + + /** + * Returns the QueueSession used for this appender. Only valid after + * start() method has been invoked. + */ + protected QueueSession getQueueSession() { + return queueSession; + } + + /** + * Returns the QueueSender used for this appender. Only valid after + * start() method has been invoked. + */ + protected QueueSender getQueueSender() { + return queueSender; + } +} Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/JMSQueueSink.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/JMSQueueSink.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,144 @@ +/** + * Logback: the reliable, generic, fast and flexible logging framework. + * + * Copyright (C) 1999-2006, QOS.ch + * + * This library is free software, you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation. + */ + +package ch.qos.logback.classic.net; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.Properties; + +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.ObjectMessage; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NameNotFoundException; +import javax.naming.NamingException; + +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.classic.util.ContextInitializer; + +/** + * A simple application that consumes logging events sent by a {@link + * JMSQueueAppender}. + * + * @author Ceki Gülcü + */ +public class JMSQueueSink implements javax.jms.MessageListener { + + private Logger logger = (Logger)LoggerFactory.getLogger(JMSTopicSink.class); + + static public void main(String[] args) throws Exception { + if (args.length != 4) { + usage("Wrong number of arguments."); + } + + String qcfBindingName = args[0]; + String queueBindingName = args[1]; + String username = args[2]; + String password = args[3]; + + LoggerContext loggerContext = (LoggerContext) LoggerFactory + .getILoggerFactory(); + ContextInitializer.autoConfig(loggerContext); + + new JMSQueueSink(qcfBindingName, queueBindingName, username, password); + + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + // Loop until the word "exit" is typed + System.out.println("Type \"exit\" to quit JMSSink."); + while (true) { + String s = stdin.readLine(); + if (s.equalsIgnoreCase("exit")) { + System.out.println("Exiting. Kill the application if it does not exit " + + "due to daemon threads."); + return; + } + } + } + + public JMSQueueSink(String qcfBindingName, String queueBindingName, + String username, String password) { + + try { + Properties env = new Properties(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory"); + env.put(Context.PROVIDER_URL, "tcp://localhost:61616"); + Context ctx = new InitialContext(env); + QueueConnectionFactory queueConnectionFactory; + queueConnectionFactory = (QueueConnectionFactory) lookup(ctx, + qcfBindingName); + System.out.println("Queue Cnx Factory found"); + Queue queue = (Queue) ctx.lookup(queueBindingName); + System.out.println("Queue found: " + queue.getQueueName()); + + QueueConnection queueConnection = queueConnectionFactory + .createQueueConnection(); + System.out.println("Queue Connection created"); + + QueueSession queueSession = queueConnection.createQueueSession(false, + Session.AUTO_ACKNOWLEDGE); + + MessageConsumer queueConsumer = queueSession.createConsumer(queue); + + queueConsumer.setMessageListener(this); + + queueConnection.start(); + System.out.println("Queue Connection started"); + + } catch (Exception e) { + logger.error("Could not read JMS message.", e); + } + } + + public void onMessage(javax.jms.Message message) { + LoggingEvent event; + try { + if (message instanceof ObjectMessage) { + ObjectMessage objectMessage = (ObjectMessage) message; + event = (LoggingEvent) objectMessage.getObject(); + logger.callAppenders(event); + } else { + logger.warn("Received message is of type " + message.getJMSType() + + ", was expecting ObjectMessage."); + } + } catch (JMSException jmse) { + logger.error("Exception thrown while processing incoming message.", jmse); + } + } + + protected Object lookup(Context ctx, String name) + throws NamingException { + try { + return ctx.lookup(name); + } catch (NameNotFoundException e) { + logger.error("Could not find name [" + name + "]."); + throw e; + } + } + + static void usage(String msg) { + System.err.println(msg); + System.err + .println("Usage: java " + + JMSTopicSink.class.getName() + + " QueueConnectionFactoryBindingName QueueBindingName username password"); + System.exit(1); + } +} Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/JMSTopicAppender.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/JMSTopicAppender.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,405 @@ +/** + * Logback: the reliable, generic, fast and flexible logging framework. + * + * Copyright (C) 1999-2006, QOS.ch + * + * This library is free software, you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation. + */ + +package ch.qos.logback.classic.net; + +import java.util.Hashtable; +import java.util.Properties; + +import javax.jms.ObjectMessage; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicConnectionFactory; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NameNotFoundException; +import javax.naming.NamingException; + +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.AppenderBase; + +/** + * A simple appender that publishes events to a JMS Topic. The events are + * serialized and transmitted as JMS message type {@link + * javax.jms.ObjectMessage}. + * + * <p> + * JMS {@link javax.jms.Topic topics} and + * {@link javax.jms.TopicConnectionFactory topic connection factories} are + * administered objects that are retrieved using JNDI messaging which in turn + * requires the retreival of a JNDI {@link Context}. + * + * <p> + * There are two common methods for retrieving a JNDI {@link Context}. If a + * file resource named <em>jndi.properties</em> is available to the JNDI API, + * it will use the information found therein to retrieve an initial JNDI + * context. To obtain an initial context, your code will simply call: + * + * <pre> + * InitialContext jndiContext = new InitialContext(); + * </pre> + * + * <p> + * Calling the no-argument <code>InitialContext()</code> method will also work + * from within Enterprise Java Beans (EJBs) because it is part of the EJB + * contract for application servers to provide each bean an environment naming + * context (ENC). + * + * <p> + * In the second approach, several predetermined properties are set and these + * properties are passed to the <code>InitialContext</code> contructor to + * connect to the naming service provider. For example, to connect to JBoss + * naming service one would write: + * + * <pre> + * Properties env = new Properties(); + * env.put(Context.INITIAL_CONTEXT_FACTORY, + * "org.jnp.interfaces.NamingContextFactory"); + * env.put(Context.PROVIDER_URL, "jnp://hostname:1099"); + * env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); + * InitialContext jndiContext = new InitialContext(env); + * </pre> + * + * where <em>hostname</em> is the host where the JBoss applicaiton server is + * running. + * + * <p> + * To connect to the the naming service of Weblogic application server one would + * write: + * + * <pre> + * Properties env = new Properties(); + * env.put(Context.INITIAL_CONTEXT_FACTORY, + * "weblogic.jndi.WLInitialContextFactory"); + * env.put(Context.PROVIDER_URL, "t3://localhost:7001"); + * InitialContext jndiContext = new InitialContext(env); + * </pre> + * + * <p> + * Other JMS providers will obviously require different values. + * + * The initial JNDI context can be obtained by calling the no-argument + * <code>InitialContext()</code> method in EJBs. Only clients running in a + * separate JVM need to be concerned about the <em>jndi.properties</em> file + * and calling {@link InitialContext#InitialContext()} or alternatively + * correctly setting the different properties before calling {@link + * InitialContext#InitialContext(java.util.Hashtable)} method. + * + * + * @author Ceki Gülcü + */ +public class JMSTopicAppender extends AppenderBase<LoggingEvent> { + + static int SUCCESSIVE_FAILURE_LIMIT = 3; + + String securityPrincipalName; + String securityCredentials; + String initialContextFactoryName; + String urlPkgPrefixes; + String providerURL; + String topicBindingName; + String tcfBindingName; + String userName; + String password; + TopicConnection topicConnection; + TopicSession topicSession; + TopicPublisher topicPublisher; + + int successiveFailureCount = 0; + + public JMSTopicAppender() { + } + + /** + * The <b>TopicConnectionFactoryBindingName</b> option takes a string value. + * Its value will be used to lookup the appropriate + * <code>TopicConnectionFactory</code> from the JNDI context. + */ + public void setTopicConnectionFactoryBindingName(String tcfBindingName) { + this.tcfBindingName = tcfBindingName; + } + + /** + * Returns the value of the <b>TopicConnectionFactoryBindingName</b> option. + */ + public String getTopicConnectionFactoryBindingName() { + return tcfBindingName; + } + + /** + * The <b>TopicBindingName</b> option takes a string value. Its value will be + * used to lookup the appropriate <code>Topic</code> from the JNDI context. + */ + public void setTopicBindingName(String topicBindingName) { + this.topicBindingName = topicBindingName; + } + + /** + * Returns the value of the <b>TopicBindingName</b> option. + */ + public String getTopicBindingName() { + return topicBindingName; + } + + /** + * Options are activated and become effective only after calling this method. + */ + public void start() { + TopicConnectionFactory topicConnectionFactory; + + try { + Context jndi = buildJNDIContext(); + + // addInfo("Looking up [" + tcfBindingName + "]"); + topicConnectionFactory = (TopicConnectionFactory) lookup(jndi, + tcfBindingName); + // addInfo("About to create TopicConnection."); + if (userName != null) { + this.topicConnection = topicConnectionFactory.createTopicConnection( + userName, password); + } else { + this.topicConnection = topicConnectionFactory.createTopicConnection(); + } + + // addInfo( + // "Creating TopicSession, non-transactional, " + // + "in AUTO_ACKNOWLEDGE mode."); + this.topicSession = topicConnection.createTopicSession(false, + Session.AUTO_ACKNOWLEDGE); + + // addInfo("Looking up topic name [" + topicBindingName + "]."); + Topic topic = (Topic) lookup(jndi, topicBindingName); + + // addInfo("Creating TopicPublisher."); + this.topicPublisher = topicSession.createPublisher(topic); + + // addInfo("Starting TopicConnection."); + topicConnection.start(); + + jndi.close(); + } catch (Exception e) { + addError("Error while activating options for appender named [" + name + + "].", e); + } + + if (this.topicConnection != null && this.topicSession != null + && this.topicPublisher != null) { + super.start(); + } + } + + public Context buildJNDIContext() throws NamingException { + Context jndi = null; + + // addInfo("Getting initial context."); + if (initialContextFactoryName != null) { + Properties env = buildEnvProperties(); + jndi = new InitialContext(env); + } else { + jndi = new InitialContext(); + } + return jndi; + } + + public Properties buildEnvProperties() { + Properties env = new Properties(); + env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactoryName); + if (providerURL != null) { + env.put(Context.PROVIDER_URL, providerURL); + } else { + addWarn("You have set InitialContextFactoryName option but not the " + + "ProviderURL. This is likely to cause problems."); + } + if (urlPkgPrefixes != null) { + env.put(Context.URL_PKG_PREFIXES, urlPkgPrefixes); + } + + if (securityPrincipalName != null) { + env.put(Context.SECURITY_PRINCIPAL, securityPrincipalName); + if (securityCredentials != null) { + env.put(Context.SECURITY_CREDENTIALS, securityCredentials); + } else { + addWarn("You have set SecurityPrincipalName option but not the " + + "SecurityCredentials. This is likely to cause problems."); + } + } + return env; + } + + protected Object lookup(Context ctx, String name) throws NamingException { + try { + return ctx.lookup(name); + } catch (NameNotFoundException e) { + addError("Could not find name [" + name + "]."); + throw e; + } + } + + /** + * Close this JMSAppender. Closing releases all resources used by the + * appender. A closed appender cannot be re-opened. + */ + public synchronized void stop() { + // The synchronized modifier avoids concurrent append and close operations + if (!this.started) { + return; + } + + this.started = false; + + try { + if (topicSession != null) { + topicSession.close(); + } + if (topicConnection != null) { + topicConnection.close(); + } + } catch (Exception e) { + addError("Error while closing JMSAppender [" + name + "].", e); + } + + // Help garbage collection + topicPublisher = null; + topicSession = null; + topicConnection = null; + } + + + /** + * This method called by {@link AppenderSkeleton#doAppend} method to do most + * of the real appending work. + */ + public void append(LoggingEvent event) { + if (!isStarted()) { + return; + } + + try { + ObjectMessage msg = topicSession.createObjectMessage(); + + msg.setObject(event); + topicPublisher.publish(msg); + successiveFailureCount = 0; + } catch (Exception e) { + successiveFailureCount++; + if (successiveFailureCount > SUCCESSIVE_FAILURE_LIMIT) { + stop(); + } + addError("Could not publish message in JMSTopicAppender [" + name + "].", e); + } + } + + /** + * Returns the value of the <b>InitialContextFactoryName</b> option. See + * {@link #setInitialContextFactoryName} for more details on the meaning of + * this option. + */ + public String getInitialContextFactoryName() { + return initialContextFactoryName; + } + + /** + * Setting the <b>InitialContextFactoryName</b> method will cause this + * <code>JMSAppender</code> instance to use the {@link + * InitialContext#InitialContext(Hashtable)} method instead of the no-argument + * constructor. If you set this option, you should also at least set the + * <b>ProviderURL</b> option. + * + * <p> + * See also {@link #setProviderURL(String)}. + */ + public void setInitialContextFactoryName(String initialContextFactoryName) { + this.initialContextFactoryName = initialContextFactoryName; + } + + public String getProviderURL() { + return providerURL; + } + + public void setProviderURL(String providerURL) { + this.providerURL = providerURL; + } + + String getURLPkgPrefixes() { + return urlPkgPrefixes; + } + + public void setURLPkgPrefixes(String urlPkgPrefixes) { + this.urlPkgPrefixes = urlPkgPrefixes; + } + + public String getSecurityCredentials() { + return securityCredentials; + } + + public void setSecurityCredentials(String securityCredentials) { + this.securityCredentials = securityCredentials; + } + + public String getSecurityPrincipalName() { + return securityPrincipalName; + } + + public void setSecurityPrincipalName(String securityPrincipalName) { + this.securityPrincipalName = securityPrincipalName; + } + + public String getUserName() { + return userName; + } + + /** + * The user name to use when {@link + * javax.jms.TopicConnectionFactory#createTopicConnection(String, String)} + * creating a topic session}. If you set this option, you should also set the + * <b>Password</b> option. See {@link #setPassword(String)}. + */ + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + /** + * The paswword to use when creating a topic session. + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Returns the TopicConnection used for this appender. Only valid after + * start() method has been invoked. + */ + protected TopicConnection getTopicConnection() { + return topicConnection; + } + + /** + * Returns the TopicSession used for this appender. Only valid after start() + * method has been invoked. + */ + protected TopicSession getTopicSession() { + return topicSession; + } + + /** + * Returns the TopicPublisher used for this appender. Only valid after start() + * method has been invoked. + */ + protected TopicPublisher getTopicPublisher() { + return topicPublisher; + } +} Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/JMSTopicSink.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/JMSTopicSink.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,145 @@ +/** + * Logback: the reliable, generic, fast and flexible logging framework. + * + * Copyright (C) 1999-2006, QOS.ch + * + * This library is free software, you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation. + */ + +package ch.qos.logback.classic.net; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.Properties; + +import javax.jms.JMSException; +import javax.jms.ObjectMessage; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicConnectionFactory; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NameNotFoundException; +import javax.naming.NamingException; + +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.classic.util.ContextInitializer; + +/** + * A simple application that consumes logging events sent by a {@link + * JMSTopicAppender}. + * + * @author Ceki Gülcü + */ +public class JMSTopicSink implements javax.jms.MessageListener { + + private Logger logger = (Logger)LoggerFactory.getLogger(JMSTopicSink.class); + + static public void main(String[] args) throws Exception { + if (args.length != 4) { + usage("Wrong number of arguments."); + } + + String tcfBindingName = args[0]; + String topicBindingName = args[1]; + String username = args[2]; + String password = args[3]; + + LoggerContext loggerContext = (LoggerContext) LoggerFactory + .getILoggerFactory(); + ContextInitializer.autoConfig(loggerContext); + + new JMSTopicSink(tcfBindingName, topicBindingName, username, password); + + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + // Loop until the word "exit" is typed + System.out.println("Type \"exit\" to quit JMSSink."); + while (true) { + String s = stdin.readLine(); + if (s.equalsIgnoreCase("exit")) { + System.out.println("Exiting. Kill the application if it does not exit " + + "due to daemon threads."); + return; + } + } + } + + public JMSTopicSink(String tcfBindingName, String topicBindingName, + String username, String password) { + + try { + Properties env = new Properties(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory"); + env.put(Context.PROVIDER_URL, "tcp://localhost:61616"); + Context ctx = new InitialContext(env); + TopicConnectionFactory topicConnectionFactory; + topicConnectionFactory = (TopicConnectionFactory) lookup(ctx, + tcfBindingName); + System.out.println("Topic Cnx Factory found"); + Topic topic = (Topic) ctx.lookup(topicBindingName); + System.out.println("Topic found: " + topic.getTopicName()); + + TopicConnection topicConnection = topicConnectionFactory + .createTopicConnection(); + System.out.println("Topic Connection created"); + + TopicSession topicSession = topicConnection.createTopicSession(false, + Session.AUTO_ACKNOWLEDGE); + + TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic); + + topicSubscriber.setMessageListener(this); + + topicConnection.start(); + System.out.println("Topic Connection started"); + + } catch (Exception e) { + logger.error("Could not read JMS message.", e); + } + } + + public void onMessage(javax.jms.Message message) { + LoggingEvent event; + System.out.println("xxxx onMessage called"); + try { + if (message instanceof ObjectMessage) { + ObjectMessage objectMessage = (ObjectMessage) message; + event = (LoggingEvent) objectMessage.getObject(); + logger.callAppenders(event); + } else { + logger.warn("Received message is of type " + message.getJMSType() + + ", was expecting ObjectMessage."); + } + } catch (JMSException jmse) { + logger.error("Exception thrown while processing incoming message.", jmse); + } + } + + protected Object lookup(Context ctx, String name) + throws NamingException { + try { + return ctx.lookup(name); + } catch (NameNotFoundException e) { + logger.error("Could not find name [" + name + "]."); + throw e; + } + } + + static void usage(String msg) { + System.err.println(msg); + System.err + .println("Usage: java " + + JMSTopicSink.class.getName() + + " TopicConnectionFactoryBindingName TopicBindingName username password"); + System.exit(1); + } +} Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/JMSQueueAppenderTestApp.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/JMSQueueAppenderTestApp.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,40 @@ +package ch.qos.logback.classic.net; + +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.core.util.StatusPrinter; + +public class JMSQueueAppenderTestApp { + + public static void main(String[] args) { + Logger logger = (Logger)LoggerFactory.getLogger(JMSTopicAppenderTestApp.class); + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + lc.shutdownAndReset(); + + JMSQueueAppender appender = new JMSQueueAppender(); + appender.setContext(lc); + appender.setName("jmsQueue"); + appender.setInitialContextFactoryName("org.apache.activemq.jndi.ActiveMQInitialContextFactory"); + //appender.setPassword(""); + appender.setProviderURL("tcp://localhost:61616"); + //appender.setSecurityCredentials(""); + //appender.setSecurityPrincipalName(""); + appender.setQueueBindingName("MyQueue"); + appender.setQueueConnectionFactoryBindingName("ConnectionFactory"); + //appender.setURLPkgPrefixes(""); + //appender.setUserName(""); + + appender.start(); + + logger.addAppender(appender); + + for (int i = 0; i < 10; i++) { + logger.debug("** Hello world. n=" + i); + } + + StatusPrinter.print(lc.getStatusManager()); + } + +} Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/JMSTopicAppenderTest.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/JMSTopicAppenderTest.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,213 @@ +package ch.qos.logback.classic.net; + +import java.util.Properties; + +import javax.jms.ObjectMessage; +import javax.naming.Context; + +import junit.framework.TestCase; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.net.mock.MockInitialContext; +import ch.qos.logback.classic.net.mock.MockInitialContextFactory; +import ch.qos.logback.classic.net.mock.MockTopic; +import ch.qos.logback.classic.net.mock.MockTopicConnectionFactory; +import ch.qos.logback.classic.net.mock.MockTopicPublisher; +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.ContextBase; + +public class JMSTopicAppenderTest extends TestCase { + + ch.qos.logback.core.Context context; + JMSTopicAppender appender; + + @Override + protected void setUp() throws Exception { + context = new ContextBase(); + appender = new JMSTopicAppender(); + appender.setContext(context); + appender.setName("jmsTopic"); + appender.tcfBindingName = "topicCnxFactory"; + appender.topicBindingName = "testTopic"; + appender.providerURL = "url"; + appender.initialContextFactoryName = MockInitialContextFactory.class.getName(); + + MockInitialContext mic = MockInitialContextFactory.getContext(); + mic.map.put(appender.tcfBindingName, new MockTopicConnectionFactory()); + mic.map.put(appender.topicBindingName, new MockTopic(appender.topicBindingName)); + + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + appender = null; + context = null; + super.tearDown(); + } + + public void testAppendOk() { + appender.start(); + + LoggingEvent le = createLoggingEvent(); + appender.append(le); + + MockTopicPublisher tp = (MockTopicPublisher)appender.topicPublisher; + assertEquals(1, tp.getMessageList().size()); + ObjectMessage message = (ObjectMessage) tp.getMessageList().get(0); + try { + assertEquals(le, message.getObject()); + } catch (Exception e) { + fail(); + } + } + + public void testAppendFailure() { + appender.start(); + + //make sure the append method does not work + appender.topicPublisher = null; + + LoggingEvent le = createLoggingEvent(); + for (int i = 1; i <= 3; i++) { + appender.append(le); + assertEquals(i, context.getStatusManager().getCount()); + assertTrue(appender.isStarted()); + } + appender.append(le); + assertEquals(4, context.getStatusManager().getCount()); + assertFalse(appender.isStarted()); + } + + public void testBuildEnvProperties() { + appender.initialContextFactoryName = "icfn"; + appender.providerURL = "url"; + appender.urlPkgPrefixes = "pkgPref"; + appender.securityPrincipalName = "user"; + appender.securityCredentials = "cred"; + + Properties props = appender.buildEnvProperties(); + assertEquals(5, props.size()); + assertEquals(appender.initialContextFactoryName, props + .getProperty(Context.INITIAL_CONTEXT_FACTORY)); + assertEquals(appender.providerURL, props.getProperty(Context.PROVIDER_URL)); + assertEquals(appender.urlPkgPrefixes, props + .getProperty(Context.URL_PKG_PREFIXES)); + assertEquals(appender.securityPrincipalName, props + .getProperty(Context.SECURITY_PRINCIPAL)); + assertEquals(appender.securityCredentials, props + .getProperty(Context.SECURITY_CREDENTIALS)); + } + + public void testBuildEnvPropertiesWithNullProviderURL() { + appender.initialContextFactoryName = "icfn"; + appender.providerURL = null; + appender.urlPkgPrefixes = "pkgPref"; + appender.securityPrincipalName = "user"; + appender.securityCredentials = "cred"; + + Properties props = appender.buildEnvProperties(); + assertEquals(4, props.size()); + assertEquals(appender.initialContextFactoryName, props + .getProperty(Context.INITIAL_CONTEXT_FACTORY)); + assertEquals(null, props.getProperty(Context.PROVIDER_URL)); + assertEquals(appender.urlPkgPrefixes, props + .getProperty(Context.URL_PKG_PREFIXES)); + assertEquals(appender.securityPrincipalName, props + .getProperty(Context.SECURITY_PRINCIPAL)); + assertEquals(appender.securityCredentials, props + .getProperty(Context.SECURITY_CREDENTIALS)); + + assertEquals(1, context.getStatusManager().getCount()); + } + + public void testBuildEnvPropertiesWithNullCredentials() { + appender.initialContextFactoryName = "icfn"; + appender.providerURL = "url"; + appender.urlPkgPrefixes = "pkgPref"; + appender.securityPrincipalName = "user"; + appender.securityCredentials = null; + + Properties props = appender.buildEnvProperties(); + assertEquals(4, props.size()); + assertEquals(appender.initialContextFactoryName, props + .getProperty(Context.INITIAL_CONTEXT_FACTORY)); + assertEquals(appender.providerURL, props.getProperty(Context.PROVIDER_URL)); + assertEquals(appender.urlPkgPrefixes, props + .getProperty(Context.URL_PKG_PREFIXES)); + assertEquals(appender.securityPrincipalName, props + .getProperty(Context.SECURITY_PRINCIPAL)); + assertEquals(null, props + .getProperty(Context.SECURITY_CREDENTIALS)); + + assertEquals(1, context.getStatusManager().getCount()); + } + + public void testBuildEnvPropertiesWithPkgNull() { + appender.initialContextFactoryName = "icfn"; + appender.providerURL = "url"; + appender.urlPkgPrefixes = null; + appender.securityPrincipalName = "user"; + appender.securityCredentials = "cred"; + + Properties props = appender.buildEnvProperties(); + assertEquals(4, props.size()); + assertEquals(appender.initialContextFactoryName, props + .getProperty(Context.INITIAL_CONTEXT_FACTORY)); + assertEquals(appender.providerURL, props.getProperty(Context.PROVIDER_URL)); + assertEquals(null, props + .getProperty(Context.URL_PKG_PREFIXES)); + assertEquals(appender.securityPrincipalName, props + .getProperty(Context.SECURITY_PRINCIPAL)); + assertEquals(appender.securityCredentials, props + .getProperty(Context.SECURITY_CREDENTIALS)); + + assertEquals(0, context.getStatusManager().getCount()); + } + + public void testStartMinimalInfo() { + //let's leave only what's in the setup() + //method, minus the providerURL + appender.providerURL = "url"; + appender.start(); + + assertTrue(appender.isStarted()); + + try { + assertEquals(appender.topicBindingName, appender.topicPublisher.getTopic().getTopicName()); + } catch (Exception e) { + fail(); + } + } + + public void testStartUserPass() { + appender.userName = ""; + appender.password = ""; + + appender.start(); + + assertTrue(appender.isStarted()); + + try { + assertEquals(appender.topicBindingName, appender.topicPublisher.getTopic().getTopicName()); + } catch (Exception e) { + fail(); + } + } + + public void testStartFails() { + appender.topicBindingName = null; + + appender.start(); + + assertFalse(appender.isStarted()); + } + + private LoggingEvent createLoggingEvent() { + LoggingEvent le = new LoggingEvent(); + le.setLevel(Level.DEBUG); + le.setMessage("test message"); + le.setTimeStamp(System.currentTimeMillis()); + le.setThreadName(Thread.currentThread().getName()); + return le; + } +} Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/JMSTopicAppenderTestApp.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/JMSTopicAppenderTestApp.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,40 @@ +package ch.qos.logback.classic.net; + +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.core.util.StatusPrinter; + +public class JMSTopicAppenderTestApp { + + public static void main(String[] args) { + Logger logger = (Logger)LoggerFactory.getLogger(JMSTopicAppenderTestApp.class); + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + lc.shutdownAndReset(); + + JMSTopicAppender appender = new JMSTopicAppender(); + appender.setContext(lc); + appender.setName("jmsTopic"); + appender.setInitialContextFactoryName("org.apache.activemq.jndi.ActiveMQInitialContextFactory"); + //appender.setPassword(""); + appender.setProviderURL("tcp://localhost:61616"); + //appender.setSecurityCredentials(""); + //appender.setSecurityPrincipalName(""); + appender.setTopicBindingName("MyTopic"); + appender.setTopicConnectionFactoryBindingName("ConnectionFactory"); + //appender.setURLPkgPrefixes(""); + //appender.setUserName(""); + + appender.start(); + + logger.addAppender(appender); + + for (int i = 0; i <= 10; i++) { + logger.debug("** Hello world. n=" + i); + } + + StatusPrinter.print(lc.getStatusManager()); + } + +} Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/PackageTest.java ============================================================================== --- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/PackageTest.java (original) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/PackageTest.java Wed Jan 10 21:47:21 2007 @@ -21,6 +21,7 @@ suite.addTestSuite(SyslogAppenderTest.class); suite.addTestSuite(SMTPAppenderTest.class); suite.addTestSuite(SocketAppenderTest.class); + suite.addTestSuite(JMSTopicAppenderTest.class); return suite; } } \ No newline at end of file Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SocketAppenderTest.java ============================================================================== --- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SocketAppenderTest.java (original) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SocketAppenderTest.java Wed Jan 10 21:47:21 2007 @@ -16,6 +16,7 @@ import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.MDC; +import ch.qos.logback.classic.net.mock.MockSocketServer; import ch.qos.logback.classic.spi.LoggerContextRemoteView; import ch.qos.logback.classic.spi.LoggerRemoteView; import ch.qos.logback.classic.spi.LoggingEvent; @@ -44,10 +45,10 @@ // Wait max 2 seconds for mock server to finish. However, it should // finish much sooner than that. mockSocketServer.join(2000); - assertTrue(mockSocketServer.finished); - assertEquals(1, mockSocketServer.loggingEventList.size()); + assertTrue(mockSocketServer.isFinished()); + assertEquals(1, mockSocketServer.getEventsList().size()); - LoggingEvent remoteEvent = mockSocketServer.loggingEventList.get(0); + LoggingEvent remoteEvent = mockSocketServer.getEventsList().get(0); assertEquals("test msg", remoteEvent.getMessage()); assertEquals(Level.DEBUG, remoteEvent.getLevel()); } @@ -62,10 +63,10 @@ // Wait max 2 seconds for mock server to finish. However, it should // finish much sooner than that. mockSocketServer.join(2000); - assertTrue(mockSocketServer.finished); - assertEquals(1, mockSocketServer.loggingEventList.size()); + assertTrue(mockSocketServer.isFinished()); + assertEquals(1, mockSocketServer.getEventsList().size()); - LoggingEvent remoteEvent = mockSocketServer.loggingEventList.get(0); + LoggingEvent remoteEvent = mockSocketServer.getEventsList().get(0); LoggerRemoteView loggerRemoteView = remoteEvent.getLoggerRemoteView(); assertNotNull(loggerRemoteView); @@ -91,10 +92,10 @@ // Wait max 2 seconds for mock server to finish. However, it should // finish much sooner than that. mockSocketServer.join(2000); - assertTrue(mockSocketServer.finished); - assertEquals(1, mockSocketServer.loggingEventList.size()); + assertTrue(mockSocketServer.isFinished()); + assertEquals(1, mockSocketServer.getEventsList().size()); - LoggingEvent remoteEvent = mockSocketServer.loggingEventList.get(0); + LoggingEvent remoteEvent = mockSocketServer.getEventsList().get(0); Map<String, String> MDCPropertyMap = remoteEvent.getMDCPropertyMap(); assertEquals("testValue", MDCPropertyMap.get("key")); } @@ -114,12 +115,12 @@ // Wait max 2 seconds for mock server to finish. However, it should // finish much sooner than that. mockSocketServer.join(2000); - assertTrue(mockSocketServer.finished); - assertEquals(2, mockSocketServer.loggingEventList.size()); + assertTrue(mockSocketServer.isFinished()); + assertEquals(2, mockSocketServer.getEventsList().size()); // We observe the second logging event. It should provide us with // the updated MDC property. - LoggingEvent remoteEvent = mockSocketServer.loggingEventList.get(1); + LoggingEvent remoteEvent = mockSocketServer.getEventsList().get(1); Map<String, String> MDCPropertyMap = remoteEvent.getMDCPropertyMap(); assertEquals("updatedTestValue", MDCPropertyMap.get("key")); } Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SyslogAppenderTest.java ============================================================================== --- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SyslogAppenderTest.java (original) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SyslogAppenderTest.java Wed Jan 10 21:47:21 2007 @@ -12,6 +12,7 @@ import junit.framework.TestCase; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.net.mock.MockSyslogServer; import ch.qos.logback.core.net.SyslogConstants; public class SyslogAppenderTest extends TestCase { @@ -57,9 +58,9 @@ // wait max 2 seconds for mock server to finish. However, it should // much sooner than that. mockServer.join(8000); - assertTrue(mockServer.finished); - assertEquals(1, mockServer.msgList.size()); - String msg = mockServer.msgList.get(0); + assertTrue(mockServer.isFinished()); + assertEquals(1, mockServer.getMessageList().size()); + String msg = mockServer.getMessageList().get(0); String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">"; @@ -102,16 +103,16 @@ // wait max 2 seconds for mock server to finish. However, it should // much sooner than that. mockServer.join(8000); - assertTrue(mockServer.finished); + assertTrue(mockServer.isFinished()); //message + 20 lines of stacktrace - assertEquals(21, mockServer.msgList.size()); + assertEquals(21, mockServer.getMessageList().size()); // int i = 0; // for (String line: mockServer.msgList) { // System.out.println(i++ + ": " + line); // } - String msg = mockServer.msgList.get(0); + String msg = mockServer.getMessageList().get(0); String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">"; assertTrue(msg.startsWith(expected)); Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockInitialContext.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockInitialContext.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,26 @@ +package ch.qos.logback.classic.net.mock; + +import java.util.HashMap; +import java.util.Map; + +import javax.naming.InitialContext; +import javax.naming.NamingException; + +public class MockInitialContext extends InitialContext { + + public Map<String, Object> map = new HashMap<String, Object>(); + + public MockInitialContext() throws NamingException { + super(); + } + + @Override + public Object lookup(String name) throws NamingException { + if (name == null) { + return null; + } + + return map.get(name); + } + +} Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockInitialContextFactory.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockInitialContextFactory.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,30 @@ +package ch.qos.logback.classic.net.mock; + +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.spi.InitialContextFactory; + +public class MockInitialContextFactory implements InitialContextFactory { + static MockInitialContext mic; + + static { + try { + mic = new MockInitialContext(); + } catch (NamingException e) { + e.printStackTrace(); + } + + } + + public Context getInitialContext(Hashtable<?, ?> environment) + throws NamingException { + return mic; + } + + public static MockInitialContext getContext() { + return mic; + } + +} Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockObjectMessage.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockObjectMessage.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,247 @@ +package ch.qos.logback.classic.net.mock; + +import java.io.Serializable; +import java.util.Enumeration; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.ObjectMessage; + +public class MockObjectMessage implements ObjectMessage { + + Serializable object; + + public Serializable getObject() throws JMSException { + return object; + } + + public void setObject(Serializable object) throws JMSException { + this.object = object; + } + + public void acknowledge() throws JMSException { + + + } + + public void clearBody() throws JMSException { + + + } + + public void clearProperties() throws JMSException { + + + } + + public boolean getBooleanProperty(String arg0) throws JMSException { + + return false; + } + + public byte getByteProperty(String arg0) throws JMSException { + + return 0; + } + + public double getDoubleProperty(String arg0) throws JMSException { + + return 0; + } + + public float getFloatProperty(String arg0) throws JMSException { + + return 0; + } + + public int getIntProperty(String arg0) throws JMSException { + + return 0; + } + + public String getJMSCorrelationID() throws JMSException { + + return null; + } + + public byte[] getJMSCorrelationIDAsBytes() throws JMSException { + + return null; + } + + public int getJMSDeliveryMode() throws JMSException { + + return 0; + } + + public Destination getJMSDestination() throws JMSException { + + return null; + } + + public long getJMSExpiration() throws JMSException { + + return 0; + } + + public String getJMSMessageID() throws JMSException { + + return null; + } + + public int getJMSPriority() throws JMSException { + + return 0; + } + + public boolean getJMSRedelivered() throws JMSException { + + return false; + } + + public Destination getJMSReplyTo() throws JMSException { + + return null; + } + + public long getJMSTimestamp() throws JMSException { + + return 0; + } + + public String getJMSType() throws JMSException { + + return null; + } + + public long getLongProperty(String arg0) throws JMSException { + + return 0; + } + + public Object getObjectProperty(String arg0) throws JMSException { + + return null; + } + + public Enumeration getPropertyNames() throws JMSException { + + return null; + } + + public short getShortProperty(String arg0) throws JMSException { + + return 0; + } + + public String getStringProperty(String arg0) throws JMSException { + + return null; + } + + public boolean propertyExists(String arg0) throws JMSException { + + return false; + } + + public void setBooleanProperty(String arg0, boolean arg1) throws JMSException { + + + } + + public void setByteProperty(String arg0, byte arg1) throws JMSException { + + + } + + public void setDoubleProperty(String arg0, double arg1) throws JMSException { + + + } + + public void setFloatProperty(String arg0, float arg1) throws JMSException { + + + } + + public void setIntProperty(String arg0, int arg1) throws JMSException { + + + } + + public void setJMSCorrelationID(String arg0) throws JMSException { + + + } + + public void setJMSCorrelationIDAsBytes(byte[] arg0) throws JMSException { + + + } + + public void setJMSDeliveryMode(int arg0) throws JMSException { + + + } + + public void setJMSDestination(Destination arg0) throws JMSException { + + + } + + public void setJMSExpiration(long arg0) throws JMSException { + + + } + + public void setJMSMessageID(String arg0) throws JMSException { + + + } + + public void setJMSPriority(int arg0) throws JMSException { + + + } + + public void setJMSRedelivered(boolean arg0) throws JMSException { + + + } + + public void setJMSReplyTo(Destination arg0) throws JMSException { + + + } + + public void setJMSTimestamp(long arg0) throws JMSException { + + + } + + public void setJMSType(String arg0) throws JMSException { + + + } + + public void setLongProperty(String arg0, long arg1) throws JMSException { + + + } + + public void setObjectProperty(String arg0, Object arg1) throws JMSException { + + + } + + public void setShortProperty(String arg0, short arg1) throws JMSException { + + + } + + public void setStringProperty(String arg0, String arg1) throws JMSException { + + + } + +} Copied: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockSocketServer.java (from r1184, /logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/MockSocketServer.java) ============================================================================== --- /logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/MockSocketServer.java (original) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockSocketServer.java Wed Jan 10 21:47:21 2007 @@ -7,7 +7,7 @@ * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation. */ -package ch.qos.logback.classic.net; +package ch.qos.logback.classic.net.mock; import java.io.BufferedInputStream; import java.io.ObjectInputStream; @@ -25,49 +25,65 @@ */ public class MockSocketServer extends Thread { - static final int PORT = 4560; + static final int PORT = 4560; - final int loopLen; + final int loopLen; - List<LoggingEvent> loggingEventList = new ArrayList<LoggingEvent>(); - boolean finished = false; + List<LoggingEvent> loggingEventList = new ArrayList<LoggingEvent>(); + boolean finished = false; - MockSocketServer(int loopLen) { - super(); - this.loopLen = loopLen; - } - - @Override - public void run() { - ObjectInputStream ois = null; - ServerSocket serverSocket = null; - //Object readObject; - LoggingEvent event; - try { - //System.out.println("Listening on port " + PORT); - serverSocket = new ServerSocket(PORT); - //System.out.println("Waiting to accept a new client."); - Socket socket = serverSocket.accept(); - //System.out.println("Connected to client at " + socket.getInetAddress()); - ois = new ObjectInputStream(new BufferedInputStream(socket - .getInputStream())); - for (int i = 0; i < loopLen; i++) { - event = (LoggingEvent)ois.readObject(); -// System.out.println("* LoggerName:" + event.getLogger().getName()); -// System.out.println("* Context Name: " + event.getLogger().getLoggerContext().getName()); - loggingEventList.add(event); - } - } catch (Exception se) { - se.printStackTrace(); - } finally { - - if(ois != null) { - try{ois.close(); } catch(Exception e) {} - } - if(serverSocket != null) { - try{ serverSocket.close(); } catch(Exception e) {} - } - } - finished = true; - } + public MockSocketServer(int loopLen) { + super(); + this.loopLen = loopLen; + } + + @Override + public void run() { + ObjectInputStream ois = null; + ServerSocket serverSocket = null; + // Object readObject; + LoggingEvent event; + try { + // System.out.println("Listening on port " + PORT); + serverSocket = new ServerSocket(PORT); + // System.out.println("Waiting to accept a new client."); + Socket socket = serverSocket.accept(); + // System.out.println("Connected to client at " + + // socket.getInetAddress()); + ois = new ObjectInputStream(new BufferedInputStream(socket + .getInputStream())); + for (int i = 0; i < loopLen; i++) { + event = (LoggingEvent) ois.readObject(); + // System.out.println("* LoggerName:" + event.getLogger().getName()); + // System.out.println("* Context Name: " + + // event.getLogger().getLoggerContext().getName()); + loggingEventList.add(event); + } + } catch (Exception se) { + se.printStackTrace(); + } finally { + + if (ois != null) { + try { + ois.close(); + } catch (Exception e) { + } + } + if (serverSocket != null) { + try { + serverSocket.close(); + } catch (Exception e) { + } + } + } + finished = true; + } + + public boolean isFinished() { + return finished; + } + + public List<LoggingEvent> getEventsList() { + return loggingEventList; + } } Copied: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockSyslogServer.java (from r1184, /logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/MockSyslogServer.java) ============================================================================== --- /logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/MockSyslogServer.java (original) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockSyslogServer.java Wed Jan 10 21:47:21 2007 @@ -7,7 +7,7 @@ * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation. */ -package ch.qos.logback.classic.net; +package ch.qos.logback.classic.net.mock; import java.net.DatagramPacket; import java.net.DatagramSocket; @@ -20,15 +20,15 @@ */ public class MockSyslogServer extends Thread { - static final int PORT = 14500; + public static final int PORT = 14500; final int loopLen; - final int port; + final int port; List<String> msgList = new ArrayList<String>(); boolean finished = false; - MockSyslogServer(int loopLen, int port) { + public MockSyslogServer(int loopLen, int port) { super(); this.loopLen = loopLen; this.port = port; @@ -59,4 +59,12 @@ } finished = true; } + + public boolean isFinished() { + return finished; + } + + public List<String> getMessageList() { + return msgList; + } } Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopic.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopic.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,18 @@ +package ch.qos.logback.classic.net.mock; + +import javax.jms.JMSException; +import javax.jms.Topic; + +public class MockTopic implements Topic { + + String name; + + public MockTopic(String name) { + this.name = name; + } + + public String getTopicName() throws JMSException { + return name; + } + +} Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopicConnection.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopicConnection.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,82 @@ +package ch.qos.logback.classic.net.mock; + +import javax.jms.ConnectionConsumer; +import javax.jms.ConnectionMetaData; +import javax.jms.Destination; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.ServerSessionPool; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicSession; + +public class MockTopicConnection implements TopicConnection { + + MockTopicSession session = new MockTopicSession(); + + public TopicSession createTopicSession(boolean arg0, int arg1) throws JMSException { + return session; + } + + public ConnectionConsumer createConnectionConsumer(Topic arg0, String arg1, ServerSessionPool arg2, int arg3) throws JMSException { + + return null; + } + + public ConnectionConsumer createDurableConnectionConsumer(Topic arg0, String arg1, String arg2, ServerSessionPool arg3, int arg4) throws JMSException { + + return null; + } + + public void close() throws JMSException { + + + } + + public ConnectionConsumer createConnectionConsumer(Destination arg0, String arg1, ServerSessionPool arg2, int arg3) throws JMSException { + + return null; + } + + public Session createSession(boolean arg0, int arg1) throws JMSException { + + return null; + } + + public String getClientID() throws JMSException { + + return null; + } + + public ExceptionListener getExceptionListener() throws JMSException { + + return null; + } + + public ConnectionMetaData getMetaData() throws JMSException { + + return null; + } + + public void setClientID(String arg0) throws JMSException { + + + } + + public void setExceptionListener(ExceptionListener arg0) throws JMSException { + + + } + + public void start() throws JMSException { + + + } + + public void stop() throws JMSException { + + + } + +} Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopicConnectionFactory.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopicConnectionFactory.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,29 @@ +package ch.qos.logback.classic.net.mock; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.TopicConnection; +import javax.jms.TopicConnectionFactory; + +public class MockTopicConnectionFactory implements TopicConnectionFactory { + + MockTopicConnection cnx = new MockTopicConnection(); + + public TopicConnection createTopicConnection() throws JMSException { + return cnx; + } + + public TopicConnection createTopicConnection(String user, String pass) throws JMSException { + + return cnx; + } + + public Connection createConnection() throws JMSException { + return null; + } + + public Connection createConnection(String arg0, String arg1) throws JMSException { + return null; + } + +} Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopicPublisher.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopicPublisher.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,127 @@ +package ch.qos.logback.classic.net.mock; + +import java.util.ArrayList; +import java.util.List; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Topic; +import javax.jms.TopicPublisher; + +public class MockTopicPublisher implements TopicPublisher { + + List<Message> messageList = new ArrayList<Message>(); + Topic topic; + + public MockTopicPublisher(Topic topic) { + this.topic = topic; + } + + public void publish(Message message) throws JMSException { + messageList.add(message); + } + + public List<Message> getMessageList() { + return messageList; + } + + public Topic getTopic() throws JMSException { + return topic; + } + + public void publish(Message arg0, int arg1, int arg2, long arg3) throws JMSException { + + } + + public void publish(Topic arg0, Message arg1, int arg2, int arg3, long arg4) throws JMSException { + + + } + + public void publish(Topic arg0, Message arg1) throws JMSException { + + + } + + public void close() throws JMSException { + + + } + + public int getDeliveryMode() throws JMSException { + + return 0; + } + + public Destination getDestination() throws JMSException { + + return null; + } + + public boolean getDisableMessageID() throws JMSException { + + return false; + } + + public boolean getDisableMessageTimestamp() throws JMSException { + + return false; + } + + public int getPriority() throws JMSException { + + return 0; + } + + public long getTimeToLive() throws JMSException { + + return 0; + } + + public void send(Destination arg0, Message arg1, int arg2, int arg3, long arg4) throws JMSException { + + + } + + public void send(Destination arg0, Message arg1) throws JMSException { + + + } + + public void send(Message arg0, int arg1, int arg2, long arg3) throws JMSException { + + + } + + public void send(Message arg0) throws JMSException { + + + } + + public void setDeliveryMode(int arg0) throws JMSException { + + + } + + public void setDisableMessageID(boolean arg0) throws JMSException { + + + } + + public void setDisableMessageTimestamp(boolean arg0) throws JMSException { + + + } + + public void setPriority(int arg0) throws JMSException { + + + } + + public void setTimeToLive(long arg0) throws JMSException { + + + } + +} Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopicSession.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockTopicSession.java Wed Jan 10 21:47:21 2007 @@ -0,0 +1,185 @@ +package ch.qos.logback.classic.net.mock; + +import java.io.Serializable; + +import javax.jms.BytesMessage; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MapMessage; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Queue; +import javax.jms.QueueBrowser; +import javax.jms.StreamMessage; +import javax.jms.TemporaryQueue; +import javax.jms.TemporaryTopic; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; + +public class MockTopicSession implements TopicSession { + + public ObjectMessage createObjectMessage() throws JMSException { + return new MockObjectMessage(); + } + + public TopicPublisher createPublisher(Topic topic) throws JMSException { + if (topic == null) { + return null; + } + return new MockTopicPublisher(topic); + } + + + public TopicSubscriber createDurableSubscriber(Topic arg0, String arg1) throws JMSException { + return null; + } + + public TopicSubscriber createDurableSubscriber(Topic arg0, String arg1, String arg2, boolean arg3) throws JMSException { + return null; + } + + public TopicSubscriber createSubscriber(Topic arg0) throws JMSException { + return null; + } + + public TopicSubscriber createSubscriber(Topic arg0, String arg1, boolean arg2) throws JMSException { + return null; + } + + public TemporaryTopic createTemporaryTopic() throws JMSException { + return null; + } + + public Topic createTopic(String arg0) throws JMSException { + return null; + } + + public void unsubscribe(String arg0) throws JMSException { + + } + + public void close() throws JMSException { + + } + + public void commit() throws JMSException { + + } + + public QueueBrowser createBrowser(Queue arg0) throws JMSException { + + return null; + } + + public QueueBrowser createBrowser(Queue arg0, String arg1) throws JMSException { + + return null; + } + + public BytesMessage createBytesMessage() throws JMSException { + + return null; + } + + public MessageConsumer createConsumer(Destination arg0) throws JMSException { + + return null; + } + + public MessageConsumer createConsumer(Destination arg0, String arg1) throws JMSException { + + return null; + } + + public MessageConsumer createConsumer(Destination arg0, String arg1, boolean arg2) throws JMSException { + + return null; + } + + public MapMessage createMapMessage() throws JMSException { + + return null; + } + + public Message createMessage() throws JMSException { + + return null; + } + + public ObjectMessage createObjectMessage(Serializable arg0) throws JMSException { + + return null; + } + + public MessageProducer createProducer(Destination arg0) throws JMSException { + + return null; + } + + public Queue createQueue(String arg0) throws JMSException { + + return null; + } + + public StreamMessage createStreamMessage() throws JMSException { + + return null; + } + + public TemporaryQueue createTemporaryQueue() throws JMSException { + + return null; + } + + public TextMessage createTextMessage() throws JMSException { + + return null; + } + + public TextMessage createTextMessage(String arg0) throws JMSException { + + return null; + } + + public int getAcknowledgeMode() throws JMSException { + + return 0; + } + + public MessageListener getMessageListener() throws JMSException { + + return null; + } + + public boolean getTransacted() throws JMSException { + + return false; + } + + public void recover() throws JMSException { + + + } + + public void rollback() throws JMSException { + + + } + + public void run() { + + + } + + public void setMessageListener(MessageListener arg0) throws JMSException { + + + } + +}
participants (1)
-
noreply.seb@qos.ch