[logback-dev] 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

noreply.seb at qos.ch noreply.seb at qos.ch
Wed Jan 10 21:47:22 CET 2007


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,
+ *     &quot;org.jnp.interfaces.NamingContextFactory&quot;);
+ * env.put(Context.PROVIDER_URL, &quot;jnp://hostname:1099&quot;);
+ * env.put(Context.URL_PKG_PREFIXES, &quot;org.jboss.naming:org.jnp.interfaces&quot;);
+ * 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,
+ *     &quot;weblogic.jndi.WLInitialContextFactory&quot;);
+ * env.put(Context.PROVIDER_URL, &quot;t3://localhost:7001&quot;);
+ * 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&uuml;lc&uuml;
+ */
+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&uuml;lc&uuml;
+ */
+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,
+ *     &quot;org.jnp.interfaces.NamingContextFactory&quot;);
+ * env.put(Context.PROVIDER_URL, &quot;jnp://hostname:1099&quot;);
+ * env.put(Context.URL_PKG_PREFIXES, &quot;org.jboss.naming:org.jnp.interfaces&quot;);
+ * 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,
+ *     &quot;weblogic.jndi.WLInitialContextFactory&quot;);
+ * env.put(Context.PROVIDER_URL, &quot;t3://localhost:7001&quot;);
+ * 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&uuml;lc&uuml;
+ */
+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&uuml;lc&uuml;
+ */
+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 {
+    
+    
+  }
+
+}



More information about the logback-dev mailing list