Gary Gregory
2014-09-06 12:14:16 UTC
What is the thought behind splitting JMS out of core?
Gary
<div>-------- Original message --------</div><div>From: ***@apache.org </div><div>Date:09/06/2014 00:58 (GMT-05:00) </div><div>To: ***@logging.apache.org </div><div>Subject: [02/29] Split out JMS appender and receiver into new log4j module. </div><div>
</div>http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-mom/pom.xml b/log4j-mom/pom.xml
new file mode 100644
index 0000000..6c3f760
--- /dev/null
+++ b/log4j-mom/pom.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>log4j</artifactId>
+ <groupId>org.apache.logging.log4j</groupId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>log4j-mom</artifactId>
+ <name>Log4j 2 MOM Plugins</name>
+ <description>Message Oriented Middleware plugins for Log4j 2</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.jms</groupId>
+ <artifactId>jboss-jms-api_1.1_spec</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockejb</groupId>
+ <artifactId>mockejb</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java
new file mode 100644
index 0000000..284e1f6
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.appender;
+
+import java.io.Serializable;
+
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.appender.AppenderLoggingException;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.layout.SerializedLayout;
+import org.apache.logging.log4j.mom.jms.receiver.JmsQueueManager;
+import org.apache.logging.log4j.core.util.Booleans;
+
+/**
+ * Appender to write to a JMS Queue.
+ */
+@Plugin(name = "JMSQueue", category = "Core", elementType = "appender", printObject = true)
+public final class JmsQueueAppender extends AbstractAppender {
+
+ private final JmsQueueManager manager;
+
+ private JmsQueueAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout,
+ final JmsQueueManager manager, final boolean ignoreExceptions) {
+ super(name, filter, layout, ignoreExceptions);
+ this.manager = manager;
+ }
+
+ /**
+ * Actual writing occurs here.
+ *
+ * @param event The LogEvent.
+ */
+ @Override
+ public void append(final LogEvent event) {
+ try {
+ manager.send(getLayout().toSerializable(event));
+ } catch (final Exception ex) {
+ throw new AppenderLoggingException(ex);
+ }
+ }
+
+ /**
+ * Create a JmsQueueAppender.
+ * @param name The name of the Appender.
+ * @param factoryName The fully qualified class name of the InitialContextFactory.
+ * @param providerURL The URL of the provider to use.
+ * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
+ * will create a URL context factory
+ * @param securityPrincipalName The name of the identity of the Principal.
+ * @param securityCredentials The security credentials of the Principal.
+ * @param factoryBindingName The name to locate in the Context that provides the QueueConnectionFactory.
+ * @param queueBindingName The name to use to locate the Queue.
+ * @param userName The user ID to use to create the Queue Connection.
+ * @param password The password to use to create the Queue Connection.
+ * @param layout The layout to use (defaults to SerializedLayout).
+ * @param filter The Filter or null.
+ * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
+ * they are propagated to the caller.
+ * @return The JmsQueueAppender.
+ */
+ @PluginFactory
+ public static JmsQueueAppender createAppender(
+ @PluginAttribute("name") final String name,
+ @PluginAttribute("factoryName") final String factoryName,
+ @PluginAttribute("providerURL") final String providerURL,
+ @PluginAttribute("urlPkgPrefixes") final String urlPkgPrefixes,
+ @PluginAttribute("securityPrincipalName") final String securityPrincipalName,
+ @PluginAttribute("securityCredentials") final String securityCredentials,
+ @PluginAttribute("factoryBindingName") final String factoryBindingName,
+ @PluginAttribute("queueBindingName") final String queueBindingName,
+ @PluginAttribute("userName") final String userName,
+ @PluginAttribute("password") final String password,
+ @PluginElement("Layout") Layout<? extends Serializable> layout,
+ @PluginElement("Filter") final Filter filter,
+ @PluginAttribute("ignoreExceptions") final String ignore) {
+ if (name == null) {
+ LOGGER.error("No name provided for JmsQueueAppender");
+ return null;
+ }
+ final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
+ final JmsQueueManager manager = JmsQueueManager.getJmsQueueManager(factoryName, providerURL, urlPkgPrefixes,
+ securityPrincipalName, securityCredentials, factoryBindingName, queueBindingName, userName, password);
+ if (manager == null) {
+ return null;
+ }
+ if (layout == null) {
+ layout = SerializedLayout.createLayout();
+ }
+ return new JmsQueueAppender(name, filter, layout, manager, ignoreExceptions);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java
new file mode 100644
index 0000000..9985746
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.appender;
+
+import java.io.Serializable;
+
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.appender.AppenderLoggingException;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.layout.SerializedLayout;
+import org.apache.logging.log4j.mom.jms.receiver.JmsTopicManager;
+import org.apache.logging.log4j.core.util.Booleans;
+
+/**
+ * Appender to write to a JMS Topic.
+ */
+@Plugin(name = "JMSTopic", category = "Core", elementType = "appender", printObject = true)
+public final class JmsTopicAppender extends AbstractAppender {
+
+ private final JmsTopicManager manager;
+
+ private JmsTopicAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout,
+ final JmsTopicManager manager, final boolean ignoreExceptions) {
+ super(name, filter, layout, ignoreExceptions);
+ this.manager = manager;
+ }
+
+ /**
+ * Actual writing occurs here.
+ * <p/>
+ * @param event The LogEvent.
+ */
+ @Override
+ public void append(final LogEvent event) {
+ try {
+ manager.send(getLayout().toSerializable(event));
+ } catch (final Exception ex) {
+ throw new AppenderLoggingException(ex);
+ }
+ }
+
+ /**
+ * Create a JmsTopicAppender.
+ * @param name The name of the Appender.
+ * @param factoryName The fully qualified class name of the InitialContextFactory.
+ * @param providerURL The URL of the provider to use.
+ * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
+ * will create a URL context factory
+ * @param securityPrincipalName The name of the identity of the Principal.
+ * @param securityCredentials The security credentials of the Principal.
+ * @param factoryBindingName The name to locate in the Context that provides the TopicConnectionFactory.
+ * @param topicBindingName The name to use to locate the Topic.
+ * @param userName The userid to use to create the Topic Connection.
+ * @param password The password to use to create the Topic Connection.
+ * @param layout The layout to use (defaults to SerializedLayout).
+ * @param filter The Filter or null.
+ * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
+ * they are propagated to the caller.
+ * @return The JmsTopicAppender.
+ */
+ @PluginFactory
+ public static JmsTopicAppender createAppender(
+ @PluginAttribute("name") final String name,
+ @PluginAttribute("factoryName") final String factoryName,
+ @PluginAttribute("providerURL") final String providerURL,
+ @PluginAttribute("urlPkgPrefixes") final String urlPkgPrefixes,
+ @PluginAttribute("securityPrincipalName") final String securityPrincipalName,
+ @PluginAttribute("securityCredentials") final String securityCredentials,
+ @PluginAttribute("factoryBindingName") final String factoryBindingName,
+ @PluginAttribute("topicBindingName") final String topicBindingName,
+ @PluginAttribute("userName") final String userName,
+ @PluginAttribute("password") final String password,
+ @PluginElement("Layout") Layout<? extends Serializable> layout,
+ @PluginElement("Filters") final Filter filter,
+ @PluginAttribute("ignoreExceptions") final String ignore) {
+
+ if (name == null) {
+ LOGGER.error("No name provided for JmsQueueAppender");
+ return null;
+ }
+ final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
+ final JmsTopicManager manager = JmsTopicManager.getJmsTopicManager(factoryName, providerURL, urlPkgPrefixes,
+ securityPrincipalName, securityCredentials, factoryBindingName, topicBindingName, userName, password);
+ if (manager == null) {
+ return null;
+ }
+ if (layout == null) {
+ layout = SerializedLayout.createLayout();
+ }
+ return new JmsTopicAppender(name, filter, layout, manager, ignoreExceptions);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java
new file mode 100644
index 0000000..0c7a4ff
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+/**
+ * Appender classes for using JMS. These are directly configured through your log4j2 configuration file.
+ */
+package org.apache.logging.log4j.mom.jms.appender;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsManager.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsManager.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsManager.java
new file mode 100644
index 0000000..d3ae2a3
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsManager.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.receiver;
+
+import java.io.Serializable;
+import java.util.Properties;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+
+import org.apache.logging.log4j.core.appender.AbstractManager;
+
+/**
+ * Base Class for Managers of JMS connections.
+ */
+public abstract class AbstractJmsManager extends AbstractManager {
+
+ /**
+ * The Constructor.
+ * @param name The name of the Appender.
+ */
+ public AbstractJmsManager(final String name) {
+ super(name);
+ }
+
+ /**
+ * Create the InitialContext.
+ * @param factoryName The fully qualified class name of the InitialContextFactory.
+ * @param providerURL The URL of the provider to use.
+ * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
+ * will create a URL context factory
+ * @param securityPrincipalName The name of the identity of the Principal.
+ * @param securityCredentials The security credentials of the Principal.
+ * @return the InitialContext.
+ * @throws NamingException if a naming error occurs.
+ */
+ protected static Context createContext(final String factoryName, final String providerURL,
+ final String urlPkgPrefixes, final String securityPrincipalName,
+ final String securityCredentials)
+ throws NamingException {
+
+ final Properties props = getEnvironment(factoryName, providerURL, urlPkgPrefixes, securityPrincipalName,
+ securityCredentials);
+ return new InitialContext(props);
+ }
+
+ /**
+ * Looks up the name in the context.
+ * @param ctx The Context.
+ * @param name The name to locate.
+ * @return The object to be located.
+ * @throws NamingException If an error occurs locating the name.
+ */
+ protected static Object lookup(final Context ctx, final String name) throws NamingException {
+ try {
+ return ctx.lookup(name);
+ } catch (final NameNotFoundException e) {
+ LOGGER.warn("Could not find name [{}].", name);
+ throw e;
+ }
+ }
+
+ /**
+ * Sets up the properties to pass to the InitialContext.
+ * @param factoryName The fully qualified class name of the InitialContextFactory.
+ * @param providerURL The URL of the provider to use.
+ * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
+ * will create a URL context factory
+ * @param securityPrincipalName The name of the identity of the Principal.
+ * @param securityCredentials The security credentials of the Principal.
+ * @return The Properties.
+ */
+ protected static Properties getEnvironment(final String factoryName, final String providerURL,
+ final String urlPkgPrefixes, final String securityPrincipalName,
+ final String securityCredentials) {
+ final Properties props = new Properties();
+ if (factoryName != null) {
+ props.put(Context.INITIAL_CONTEXT_FACTORY, factoryName);
+ if (providerURL != null) {
+ props.put(Context.PROVIDER_URL, providerURL);
+ } else {
+ LOGGER.warn("The InitialContext factory name has been provided without a ProviderURL. " +
+ "This is likely to cause problems");
+ }
+ if (urlPkgPrefixes != null) {
+ props.put(Context.URL_PKG_PREFIXES, urlPkgPrefixes);
+ }
+ if (securityPrincipalName != null) {
+ props.put(Context.SECURITY_PRINCIPAL, securityPrincipalName);
+ if (securityCredentials != null) {
+ props.put(Context.SECURITY_CREDENTIALS, securityCredentials);
+ } else {
+ LOGGER.warn("SecurityPrincipalName has been set without SecurityCredentials. " +
+ "This is likely to cause problems.");
+ }
+ }
+ return props;
+ }
+ return null;
+ }
+
+ /**
+ * Send the message.
+ * @param object The Object to sent.
+ * @throws Exception if an error occurs.
+ */
+ public abstract void send(Serializable object) throws Exception;
+
+ /**
+ * Send the Object.
+ * @param object The Object to send.
+ * @param session The Session.
+ * @param producer The MessageProducer.
+ * @throws Exception if an error occurs.
+ */
+ public synchronized void send(final Serializable object, final Session session, final MessageProducer producer)
+ throws Exception {
+ try {
+ Message msg;
+ if (object instanceof String) {
+ msg = session.createTextMessage();
+ ((TextMessage) msg).setText((String) object);
+ } else {
+ msg = session.createObjectMessage();
+ ((ObjectMessage) msg).setObject(object);
+ }
+ producer.send(msg);
+ } catch (final JMSException ex) {
+ LOGGER.error("Could not publish message via JMS {}", getName());
+ throw ex;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java
new file mode 100644
index 0000000..bf86c65
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.receiver;
+
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+import javax.jms.ObjectMessage;
+import javax.naming.Context;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LogEventListener;
+
+/**
+ * Abstract base class for receiving LogEvents over JMS. This class expects all messages to be serialized log events.
+ */
+public abstract class AbstractJmsReceiver extends LogEventListener implements javax.jms.MessageListener {
+
+ /**
+ * Logger to capture diagnostics.
+ */
+ protected Logger logger = LogManager.getLogger(this.getClass().getName());
+
+ /**
+ * Listener that receives the event.
+ * @param message The received message.
+ */
+ @Override
+ public void onMessage(final javax.jms.Message message) {
+ try {
+ if (message instanceof ObjectMessage) {
+ final ObjectMessage objectMessage = (ObjectMessage) message;
+ final Serializable object = objectMessage.getObject();
+ if (object instanceof LogEvent) {
+ log((LogEvent) object);
+ } else {
+ logger.warn("Received message is of type " + object.getClass().getName() + ", was expecting LogEvent.");
+ }
+ } else {
+ logger.warn("Received message is of type " + message.getJMSType()
+ + ", was expecting ObjectMessage.");
+ }
+ } catch (final JMSException jmse) {
+ logger.error("Exception thrown while processing incoming message.",
+ jmse);
+ }
+ }
+
+ /**
+ * Looks up an object from the Context.
+ * @param ctx The Context.
+ * @param name The name of the object to locate.
+ * @return The object.
+ * @throws NamingException if an error occurs.
+ */
+ protected Object lookup(final Context ctx, final String name) throws NamingException {
+ try {
+ return ctx.lookup(name);
+ } catch (final NameNotFoundException e) {
+ logger.error("Could not find name [" + name + "].");
+ throw e;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueManager.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueManager.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueManager.java
new file mode 100644
index 0000000..6825282
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueManager.java
@@ -0,0 +1,237 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.receiver;
+
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+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.NamingException;
+
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+
+/**
+ * Manager for a JMS Queue.
+ */
+public class JmsQueueManager extends AbstractJmsManager {
+
+ private static final JMSQueueManagerFactory FACTORY = new JMSQueueManagerFactory();
+
+ private QueueInfo info;
+ private final String factoryBindingName;
+ private final String queueBindingName;
+ private final String userName;
+ private final String password;
+ private final Context context;
+
+ /**
+ * The Constructor.
+ * @param name The unique name of the connection.
+ * @param context The context.
+ * @param factoryBindingName The factory binding name.
+ * @param queueBindingName The queue binding name.
+ * @param userName The user name.
+ * @param password The credentials for the user.
+ * @param info The Queue connection info.
+ */
+ protected JmsQueueManager(final String name, final Context context, final String factoryBindingName,
+ final String queueBindingName, final String userName, final String password,
+ final QueueInfo info) {
+ super(name);
+ this.context = context;
+ this.factoryBindingName = factoryBindingName;
+ this.queueBindingName = queueBindingName;
+ this.userName = userName;
+ this.password = password;
+ this.info = info;
+ }
+
+ /**
+ * Obtain a JmsQueueManager.
+ * @param factoryName The fully qualified class name of the InitialContextFactory.
+ * @param providerURL The URL of the provider to use.
+ * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
+ * will create a URL context factory
+ * @param securityPrincipalName The name of the identity of the Principal.
+ * @param securityCredentials The security credentials of the Principal.
+ * @param factoryBindingName The name to locate in the Context that provides the QueueConnectionFactory.
+ * @param queueBindingName The name to use to locate the Queue.
+ * @param userName The userid to use to create the Queue Connection.
+ * @param password The password to use to create the Queue Connection.
+ * @return The JmsQueueManager.
+ */
+ public static JmsQueueManager getJmsQueueManager(final String factoryName, final String providerURL,
+ final String urlPkgPrefixes, final String securityPrincipalName,
+ final String securityCredentials, final String factoryBindingName,
+ final String queueBindingName, final String userName,
+ final String password) {
+
+ if (factoryBindingName == null) {
+ LOGGER.error("No factory name provided for JmsQueueManager");
+ return null;
+ }
+ if (queueBindingName == null) {
+ LOGGER.error("No topic name provided for JmsQueueManager");
+ return null;
+ }
+
+ final String name = "JMSQueue:" + factoryBindingName + '.' + queueBindingName;
+ return getManager(name, FACTORY, new FactoryData(factoryName, providerURL, urlPkgPrefixes,
+ securityPrincipalName, securityCredentials, factoryBindingName, queueBindingName, userName, password));
+ }
+
+ @Override
+ public synchronized void send(final Serializable object) throws Exception {
+ if (info == null) {
+ info = connect(context, factoryBindingName, queueBindingName, userName, password, false);
+ }
+ try {
+ super.send(object, info.session, info.sender);
+ } catch (final Exception ex) {
+ cleanup(true);
+ throw ex;
+ }
+ }
+
+ @Override
+ public void releaseSub() {
+ if (info != null) {
+ cleanup(false);
+ }
+ }
+
+ private void cleanup(final boolean quiet) {
+ try {
+ info.session.close();
+ } catch (final Exception e) {
+ if (!quiet) {
+ LOGGER.error("Error closing session for " + getName(), e);
+ }
+ }
+ try {
+ info.conn.close();
+ } catch (final Exception e) {
+ if (!quiet) {
+ LOGGER.error("Error closing connection for " + getName(), e);
+ }
+ }
+ info = null;
+ }
+
+ /**
+ * Data for the factory.
+ */
+ private static class FactoryData {
+ private final String factoryName;
+ private final String providerURL;
+ private final String urlPkgPrefixes;
+ private final String securityPrincipalName;
+ private final String securityCredentials;
+ private final String factoryBindingName;
+ private final String queueBindingName;
+ private final String userName;
+ private final String password;
+
+ public FactoryData(final String factoryName, final String providerURL, final String urlPkgPrefixes,
+ final String securityPrincipalName, final String securityCredentials,
+ final String factoryBindingName, final String queueBindingName, final String userName,
+ final String password) {
+ this.factoryName = factoryName;
+ this.providerURL = providerURL;
+ this.urlPkgPrefixes = urlPkgPrefixes;
+ this.securityPrincipalName = securityPrincipalName;
+ this.securityCredentials = securityCredentials;
+ this.factoryBindingName = factoryBindingName;
+ this.queueBindingName = queueBindingName;
+ this.userName = userName;
+ this.password = password;
+ }
+ }
+
+ private static QueueInfo connect(final Context context, final String factoryBindingName,
+ final String queueBindingName, final String userName, final String password,
+ final boolean suppress) throws Exception {
+ try {
+ final QueueConnectionFactory factory = (QueueConnectionFactory) lookup(context, factoryBindingName);
+ QueueConnection conn;
+ if (userName != null) {
+ conn = factory.createQueueConnection(userName, password);
+ } else {
+ conn = factory.createQueueConnection();
+ }
+ final QueueSession sess = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+ final Queue queue = (Queue) lookup(context, queueBindingName);
+ final QueueSender sender = sess.createSender(queue);
+ conn.start();
+ return new QueueInfo(conn, sess, sender);
+ } catch (final NamingException ex) {
+ LOGGER.warn("Unable to locate connection factory " + factoryBindingName, ex);
+ if (!suppress) {
+ throw ex;
+ }
+ } catch (final JMSException ex) {
+ LOGGER.warn("Unable to create connection to queue " + queueBindingName, ex);
+ if (!suppress) {
+ throw ex;
+ }
+ }
+ return null;
+ }
+
+ /** Queue connection information */
+ private static class QueueInfo {
+ private final QueueConnection conn;
+ private final QueueSession session;
+ private final QueueSender sender;
+
+ public QueueInfo(final QueueConnection conn, final QueueSession session, final QueueSender sender) {
+ this.conn = conn;
+ this.session = session;
+ this.sender = sender;
+ }
+ }
+
+ /**
+ * Factory to create the JmsQueueManager.
+ */
+ private static class JMSQueueManagerFactory implements ManagerFactory<JmsQueueManager, FactoryData> {
+
+ @Override
+ public JmsQueueManager createManager(final String name, final FactoryData data) {
+ try {
+ final Context ctx = createContext(data.factoryName, data.providerURL, data.urlPkgPrefixes,
+ data.securityPrincipalName, data.securityCredentials);
+ final QueueInfo info = connect(ctx, data.factoryBindingName, data.queueBindingName, data.userName,
+ data.password, true);
+ return new JmsQueueManager(name, ctx, data.factoryBindingName, data.queueBindingName,
+ data.userName, data.password, info);
+ } catch (final NamingException ex) {
+ LOGGER.error("Unable to locate resource", ex);
+ } catch (final Exception ex) {
+ LOGGER.error("Unable to connect", ex);
+ }
+
+ return null;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java
new file mode 100644
index 0000000..b231489
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.receiver;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueReceiver;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+/**
+ * Receives Log Events over a JMS Queue. This implementation expects that all messages will
+ * contain a serialized LogEvent.
+ */
+public class JmsQueueReceiver extends AbstractJmsReceiver {
+
+ /**
+ * Constructor.
+ * @param qcfBindingName The QueueConnectionFactory binding name.
+ * @param queueBindingName The Queue binding name.
+ * @param username The userid to connect to the queue.
+ * @param password The password to connect to the queue.
+ */
+ public JmsQueueReceiver(final String qcfBindingName, final String queueBindingName, final String username,
+ final String password) {
+
+ try {
+ final Context ctx = new InitialContext();
+ QueueConnectionFactory queueConnectionFactory;
+ queueConnectionFactory = (QueueConnectionFactory) lookup(ctx, qcfBindingName);
+ final QueueConnection queueConnection = queueConnectionFactory.createQueueConnection(username, password);
+ queueConnection.start();
+ final QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+ final Queue queue = (Queue) ctx.lookup(queueBindingName);
+ final QueueReceiver queueReceiver = queueSession.createReceiver(queue);
+ queueReceiver.setMessageListener(this);
+ } catch (final JMSException e) {
+ logger.error("Could not read JMS message.", e);
+ } catch (final NamingException e) {
+ logger.error("Could not read JMS message.", e);
+ } catch (final RuntimeException e) {
+ logger.error("Could not read JMS message.", e);
+ }
+ }
+
+ /**
+ * Main startup for the receiver.
+ * @param args The command line arguments.
+ * @throws Exception if an error occurs.
+ */
+ public static void main(final String[] args) throws Exception {
+ if (args.length != 4) {
+ usage("Wrong number of arguments.");
+ }
+
+ final String qcfBindingName = args[0];
+ final String queueBindingName = args[1];
+ final String username = args[2];
+ final String password = args[3];
+
+ new JmsQueueReceiver(qcfBindingName, queueBindingName, username, password);
+
+ final Charset enc = Charset.defaultCharset();
+ final BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in, enc));
+ // Loop until the word "exit" is typed
+ System.out.println("Type \"exit\" to quit JmsQueueReceiver.");
+ while (true) {
+ final String line = stdin.readLine();
+ if (line == null || line.equalsIgnoreCase("exit")) {
+ System.out.println("Exiting. Kill the application if it does not exit "
+ + "due to daemon threads.");
+ return;
+ }
+ }
+ }
+
+
+ private static void usage(final String msg) {
+ System.err.println(msg);
+ System.err.println("Usage: java " + JmsQueueReceiver.class.getName()
+ + " QueueConnectionFactoryBindingName QueueBindingName username password");
+ System.exit(1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTopicManager.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTopicManager.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTopicManager.java
new file mode 100644
index 0000000..08d7128
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTopicManager.java
@@ -0,0 +1,237 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.receiver;
+
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+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.NamingException;
+
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+
+/**
+ * Manager for JMS Topic connections.
+ */
+public class JmsTopicManager extends AbstractJmsManager {
+
+ private static final JMSTopicManagerFactory FACTORY = new JMSTopicManagerFactory();
+
+ private TopicInfo info;
+ private final String factoryBindingName;
+ private final String topicBindingName;
+ private final String userName;
+ private final String password;
+ private final Context context;
+ /**
+ * Constructor.
+ * @param name The unique name of the connection.
+ * @param context The context.
+ * @param factoryBindingName The factory binding name.
+ * @param topicBindingName The queue binding name.
+ * @param userName The user name.
+ * @param password The credentials for the user.
+ * @param info The Queue connection info.
+ */
+ protected JmsTopicManager(final String name, final Context context, final String factoryBindingName,
+ final String topicBindingName, final String userName, final String password,
+ final TopicInfo info) {
+ super(name);
+ this.context = context;
+ this.factoryBindingName = factoryBindingName;
+ this.topicBindingName = topicBindingName;
+ this.userName = userName;
+ this.password = password;
+ this.info = info;
+ }
+
+ /**
+ * Obtain a JSMTopicManager.
+ * @param factoryName The fully qualified class name of the InitialContextFactory.
+ * @param providerURL The URL of the provider to use.
+ * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
+ * will create a URL context factory
+ * @param securityPrincipalName The name of the identity of the Principal.
+ * @param securityCredentials The security credentials of the Principal.
+ * @param factoryBindingName The name to locate in the Context that provides the TopicConnectionFactory.
+ * @param topicBindingName The name to use to locate the Topic.
+ * @param userName The userid to use to create the Topic Connection.
+ * @param password The password to use to create the Topic Connection.
+ * @return A JmsTopicManager.
+ */
+ public static JmsTopicManager getJmsTopicManager(final String factoryName, final String providerURL,
+ final String urlPkgPrefixes, final String securityPrincipalName,
+ final String securityCredentials, final String factoryBindingName,
+ final String topicBindingName, final String userName,
+ final String password) {
+
+ if (factoryBindingName == null) {
+ LOGGER.error("No factory name provided for JmsTopicManager");
+ return null;
+ }
+ if (topicBindingName == null) {
+ LOGGER.error("No topic name provided for JmsTopicManager");
+ return null;
+ }
+
+ final String name = "JMSTopic:" + factoryBindingName + '.' + topicBindingName;
+ return getManager(name, FACTORY, new FactoryData(factoryName, providerURL, urlPkgPrefixes,
+ securityPrincipalName, securityCredentials, factoryBindingName, topicBindingName, userName, password));
+ }
+
+
+ @Override
+ public void send(final Serializable object) throws Exception {
+ if (info == null) {
+ info = connect(context, factoryBindingName, topicBindingName, userName, password, false);
+ }
+ try {
+ super.send(object, info.session, info.publisher);
+ } catch (final Exception ex) {
+ cleanup(true);
+ throw ex;
+ }
+ }
+
+ @Override
+ public void releaseSub() {
+ if (info != null) {
+ cleanup(false);
+ }
+ }
+
+ private void cleanup(final boolean quiet) {
+ try {
+ info.session.close();
+ } catch (final Exception e) {
+ if (!quiet) {
+ LOGGER.error("Error closing session for " + getName(), e);
+ }
+ }
+ try {
+ info.conn.close();
+ } catch (final Exception e) {
+ if (!quiet) {
+ LOGGER.error("Error closing connection for " + getName(), e);
+ }
+ }
+ info = null;
+ }
+
+ /**
+ * Data for the factory.
+ */
+ private static class FactoryData {
+ private final String factoryName;
+ private final String providerURL;
+ private final String urlPkgPrefixes;
+ private final String securityPrincipalName;
+ private final String securityCredentials;
+ private final String factoryBindingName;
+ private final String topicBindingName;
+ private final String userName;
+ private final String password;
+
+ public FactoryData(final String factoryName, final String providerURL, final String urlPkgPrefixes,
+ final String securityPrincipalName, final String securityCredentials,
+ final String factoryBindingName, final String topicBindingName,
+ final String userName, final String password) {
+ this.factoryName = factoryName;
+ this.providerURL = providerURL;
+ this.urlPkgPrefixes = urlPkgPrefixes;
+ this.securityPrincipalName = securityPrincipalName;
+ this.securityCredentials = securityCredentials;
+ this.factoryBindingName = factoryBindingName;
+ this.topicBindingName = topicBindingName;
+ this.userName = userName;
+ this.password = password;
+ }
Gary
<div>-------- Original message --------</div><div>From: ***@apache.org </div><div>Date:09/06/2014 00:58 (GMT-05:00) </div><div>To: ***@logging.apache.org </div><div>Subject: [02/29] Split out JMS appender and receiver into new log4j module. </div><div>
</div>http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-mom/pom.xml b/log4j-mom/pom.xml
new file mode 100644
index 0000000..6c3f760
--- /dev/null
+++ b/log4j-mom/pom.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>log4j</artifactId>
+ <groupId>org.apache.logging.log4j</groupId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>log4j-mom</artifactId>
+ <name>Log4j 2 MOM Plugins</name>
+ <description>Message Oriented Middleware plugins for Log4j 2</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.jms</groupId>
+ <artifactId>jboss-jms-api_1.1_spec</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockejb</groupId>
+ <artifactId>mockejb</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java
new file mode 100644
index 0000000..284e1f6
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.appender;
+
+import java.io.Serializable;
+
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.appender.AppenderLoggingException;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.layout.SerializedLayout;
+import org.apache.logging.log4j.mom.jms.receiver.JmsQueueManager;
+import org.apache.logging.log4j.core.util.Booleans;
+
+/**
+ * Appender to write to a JMS Queue.
+ */
+@Plugin(name = "JMSQueue", category = "Core", elementType = "appender", printObject = true)
+public final class JmsQueueAppender extends AbstractAppender {
+
+ private final JmsQueueManager manager;
+
+ private JmsQueueAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout,
+ final JmsQueueManager manager, final boolean ignoreExceptions) {
+ super(name, filter, layout, ignoreExceptions);
+ this.manager = manager;
+ }
+
+ /**
+ * Actual writing occurs here.
+ *
+ * @param event The LogEvent.
+ */
+ @Override
+ public void append(final LogEvent event) {
+ try {
+ manager.send(getLayout().toSerializable(event));
+ } catch (final Exception ex) {
+ throw new AppenderLoggingException(ex);
+ }
+ }
+
+ /**
+ * Create a JmsQueueAppender.
+ * @param name The name of the Appender.
+ * @param factoryName The fully qualified class name of the InitialContextFactory.
+ * @param providerURL The URL of the provider to use.
+ * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
+ * will create a URL context factory
+ * @param securityPrincipalName The name of the identity of the Principal.
+ * @param securityCredentials The security credentials of the Principal.
+ * @param factoryBindingName The name to locate in the Context that provides the QueueConnectionFactory.
+ * @param queueBindingName The name to use to locate the Queue.
+ * @param userName The user ID to use to create the Queue Connection.
+ * @param password The password to use to create the Queue Connection.
+ * @param layout The layout to use (defaults to SerializedLayout).
+ * @param filter The Filter or null.
+ * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
+ * they are propagated to the caller.
+ * @return The JmsQueueAppender.
+ */
+ @PluginFactory
+ public static JmsQueueAppender createAppender(
+ @PluginAttribute("name") final String name,
+ @PluginAttribute("factoryName") final String factoryName,
+ @PluginAttribute("providerURL") final String providerURL,
+ @PluginAttribute("urlPkgPrefixes") final String urlPkgPrefixes,
+ @PluginAttribute("securityPrincipalName") final String securityPrincipalName,
+ @PluginAttribute("securityCredentials") final String securityCredentials,
+ @PluginAttribute("factoryBindingName") final String factoryBindingName,
+ @PluginAttribute("queueBindingName") final String queueBindingName,
+ @PluginAttribute("userName") final String userName,
+ @PluginAttribute("password") final String password,
+ @PluginElement("Layout") Layout<? extends Serializable> layout,
+ @PluginElement("Filter") final Filter filter,
+ @PluginAttribute("ignoreExceptions") final String ignore) {
+ if (name == null) {
+ LOGGER.error("No name provided for JmsQueueAppender");
+ return null;
+ }
+ final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
+ final JmsQueueManager manager = JmsQueueManager.getJmsQueueManager(factoryName, providerURL, urlPkgPrefixes,
+ securityPrincipalName, securityCredentials, factoryBindingName, queueBindingName, userName, password);
+ if (manager == null) {
+ return null;
+ }
+ if (layout == null) {
+ layout = SerializedLayout.createLayout();
+ }
+ return new JmsQueueAppender(name, filter, layout, manager, ignoreExceptions);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java
new file mode 100644
index 0000000..9985746
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.appender;
+
+import java.io.Serializable;
+
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.appender.AppenderLoggingException;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.layout.SerializedLayout;
+import org.apache.logging.log4j.mom.jms.receiver.JmsTopicManager;
+import org.apache.logging.log4j.core.util.Booleans;
+
+/**
+ * Appender to write to a JMS Topic.
+ */
+@Plugin(name = "JMSTopic", category = "Core", elementType = "appender", printObject = true)
+public final class JmsTopicAppender extends AbstractAppender {
+
+ private final JmsTopicManager manager;
+
+ private JmsTopicAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout,
+ final JmsTopicManager manager, final boolean ignoreExceptions) {
+ super(name, filter, layout, ignoreExceptions);
+ this.manager = manager;
+ }
+
+ /**
+ * Actual writing occurs here.
+ * <p/>
+ * @param event The LogEvent.
+ */
+ @Override
+ public void append(final LogEvent event) {
+ try {
+ manager.send(getLayout().toSerializable(event));
+ } catch (final Exception ex) {
+ throw new AppenderLoggingException(ex);
+ }
+ }
+
+ /**
+ * Create a JmsTopicAppender.
+ * @param name The name of the Appender.
+ * @param factoryName The fully qualified class name of the InitialContextFactory.
+ * @param providerURL The URL of the provider to use.
+ * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
+ * will create a URL context factory
+ * @param securityPrincipalName The name of the identity of the Principal.
+ * @param securityCredentials The security credentials of the Principal.
+ * @param factoryBindingName The name to locate in the Context that provides the TopicConnectionFactory.
+ * @param topicBindingName The name to use to locate the Topic.
+ * @param userName The userid to use to create the Topic Connection.
+ * @param password The password to use to create the Topic Connection.
+ * @param layout The layout to use (defaults to SerializedLayout).
+ * @param filter The Filter or null.
+ * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
+ * they are propagated to the caller.
+ * @return The JmsTopicAppender.
+ */
+ @PluginFactory
+ public static JmsTopicAppender createAppender(
+ @PluginAttribute("name") final String name,
+ @PluginAttribute("factoryName") final String factoryName,
+ @PluginAttribute("providerURL") final String providerURL,
+ @PluginAttribute("urlPkgPrefixes") final String urlPkgPrefixes,
+ @PluginAttribute("securityPrincipalName") final String securityPrincipalName,
+ @PluginAttribute("securityCredentials") final String securityCredentials,
+ @PluginAttribute("factoryBindingName") final String factoryBindingName,
+ @PluginAttribute("topicBindingName") final String topicBindingName,
+ @PluginAttribute("userName") final String userName,
+ @PluginAttribute("password") final String password,
+ @PluginElement("Layout") Layout<? extends Serializable> layout,
+ @PluginElement("Filters") final Filter filter,
+ @PluginAttribute("ignoreExceptions") final String ignore) {
+
+ if (name == null) {
+ LOGGER.error("No name provided for JmsQueueAppender");
+ return null;
+ }
+ final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
+ final JmsTopicManager manager = JmsTopicManager.getJmsTopicManager(factoryName, providerURL, urlPkgPrefixes,
+ securityPrincipalName, securityCredentials, factoryBindingName, topicBindingName, userName, password);
+ if (manager == null) {
+ return null;
+ }
+ if (layout == null) {
+ layout = SerializedLayout.createLayout();
+ }
+ return new JmsTopicAppender(name, filter, layout, manager, ignoreExceptions);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java
new file mode 100644
index 0000000..0c7a4ff
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+/**
+ * Appender classes for using JMS. These are directly configured through your log4j2 configuration file.
+ */
+package org.apache.logging.log4j.mom.jms.appender;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsManager.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsManager.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsManager.java
new file mode 100644
index 0000000..d3ae2a3
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsManager.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.receiver;
+
+import java.io.Serializable;
+import java.util.Properties;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+
+import org.apache.logging.log4j.core.appender.AbstractManager;
+
+/**
+ * Base Class for Managers of JMS connections.
+ */
+public abstract class AbstractJmsManager extends AbstractManager {
+
+ /**
+ * The Constructor.
+ * @param name The name of the Appender.
+ */
+ public AbstractJmsManager(final String name) {
+ super(name);
+ }
+
+ /**
+ * Create the InitialContext.
+ * @param factoryName The fully qualified class name of the InitialContextFactory.
+ * @param providerURL The URL of the provider to use.
+ * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
+ * will create a URL context factory
+ * @param securityPrincipalName The name of the identity of the Principal.
+ * @param securityCredentials The security credentials of the Principal.
+ * @return the InitialContext.
+ * @throws NamingException if a naming error occurs.
+ */
+ protected static Context createContext(final String factoryName, final String providerURL,
+ final String urlPkgPrefixes, final String securityPrincipalName,
+ final String securityCredentials)
+ throws NamingException {
+
+ final Properties props = getEnvironment(factoryName, providerURL, urlPkgPrefixes, securityPrincipalName,
+ securityCredentials);
+ return new InitialContext(props);
+ }
+
+ /**
+ * Looks up the name in the context.
+ * @param ctx The Context.
+ * @param name The name to locate.
+ * @return The object to be located.
+ * @throws NamingException If an error occurs locating the name.
+ */
+ protected static Object lookup(final Context ctx, final String name) throws NamingException {
+ try {
+ return ctx.lookup(name);
+ } catch (final NameNotFoundException e) {
+ LOGGER.warn("Could not find name [{}].", name);
+ throw e;
+ }
+ }
+
+ /**
+ * Sets up the properties to pass to the InitialContext.
+ * @param factoryName The fully qualified class name of the InitialContextFactory.
+ * @param providerURL The URL of the provider to use.
+ * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
+ * will create a URL context factory
+ * @param securityPrincipalName The name of the identity of the Principal.
+ * @param securityCredentials The security credentials of the Principal.
+ * @return The Properties.
+ */
+ protected static Properties getEnvironment(final String factoryName, final String providerURL,
+ final String urlPkgPrefixes, final String securityPrincipalName,
+ final String securityCredentials) {
+ final Properties props = new Properties();
+ if (factoryName != null) {
+ props.put(Context.INITIAL_CONTEXT_FACTORY, factoryName);
+ if (providerURL != null) {
+ props.put(Context.PROVIDER_URL, providerURL);
+ } else {
+ LOGGER.warn("The InitialContext factory name has been provided without a ProviderURL. " +
+ "This is likely to cause problems");
+ }
+ if (urlPkgPrefixes != null) {
+ props.put(Context.URL_PKG_PREFIXES, urlPkgPrefixes);
+ }
+ if (securityPrincipalName != null) {
+ props.put(Context.SECURITY_PRINCIPAL, securityPrincipalName);
+ if (securityCredentials != null) {
+ props.put(Context.SECURITY_CREDENTIALS, securityCredentials);
+ } else {
+ LOGGER.warn("SecurityPrincipalName has been set without SecurityCredentials. " +
+ "This is likely to cause problems.");
+ }
+ }
+ return props;
+ }
+ return null;
+ }
+
+ /**
+ * Send the message.
+ * @param object The Object to sent.
+ * @throws Exception if an error occurs.
+ */
+ public abstract void send(Serializable object) throws Exception;
+
+ /**
+ * Send the Object.
+ * @param object The Object to send.
+ * @param session The Session.
+ * @param producer The MessageProducer.
+ * @throws Exception if an error occurs.
+ */
+ public synchronized void send(final Serializable object, final Session session, final MessageProducer producer)
+ throws Exception {
+ try {
+ Message msg;
+ if (object instanceof String) {
+ msg = session.createTextMessage();
+ ((TextMessage) msg).setText((String) object);
+ } else {
+ msg = session.createObjectMessage();
+ ((ObjectMessage) msg).setObject(object);
+ }
+ producer.send(msg);
+ } catch (final JMSException ex) {
+ LOGGER.error("Could not publish message via JMS {}", getName());
+ throw ex;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java
new file mode 100644
index 0000000..bf86c65
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.receiver;
+
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+import javax.jms.ObjectMessage;
+import javax.naming.Context;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LogEventListener;
+
+/**
+ * Abstract base class for receiving LogEvents over JMS. This class expects all messages to be serialized log events.
+ */
+public abstract class AbstractJmsReceiver extends LogEventListener implements javax.jms.MessageListener {
+
+ /**
+ * Logger to capture diagnostics.
+ */
+ protected Logger logger = LogManager.getLogger(this.getClass().getName());
+
+ /**
+ * Listener that receives the event.
+ * @param message The received message.
+ */
+ @Override
+ public void onMessage(final javax.jms.Message message) {
+ try {
+ if (message instanceof ObjectMessage) {
+ final ObjectMessage objectMessage = (ObjectMessage) message;
+ final Serializable object = objectMessage.getObject();
+ if (object instanceof LogEvent) {
+ log((LogEvent) object);
+ } else {
+ logger.warn("Received message is of type " + object.getClass().getName() + ", was expecting LogEvent.");
+ }
+ } else {
+ logger.warn("Received message is of type " + message.getJMSType()
+ + ", was expecting ObjectMessage.");
+ }
+ } catch (final JMSException jmse) {
+ logger.error("Exception thrown while processing incoming message.",
+ jmse);
+ }
+ }
+
+ /**
+ * Looks up an object from the Context.
+ * @param ctx The Context.
+ * @param name The name of the object to locate.
+ * @return The object.
+ * @throws NamingException if an error occurs.
+ */
+ protected Object lookup(final Context ctx, final String name) throws NamingException {
+ try {
+ return ctx.lookup(name);
+ } catch (final NameNotFoundException e) {
+ logger.error("Could not find name [" + name + "].");
+ throw e;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueManager.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueManager.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueManager.java
new file mode 100644
index 0000000..6825282
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueManager.java
@@ -0,0 +1,237 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.receiver;
+
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+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.NamingException;
+
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+
+/**
+ * Manager for a JMS Queue.
+ */
+public class JmsQueueManager extends AbstractJmsManager {
+
+ private static final JMSQueueManagerFactory FACTORY = new JMSQueueManagerFactory();
+
+ private QueueInfo info;
+ private final String factoryBindingName;
+ private final String queueBindingName;
+ private final String userName;
+ private final String password;
+ private final Context context;
+
+ /**
+ * The Constructor.
+ * @param name The unique name of the connection.
+ * @param context The context.
+ * @param factoryBindingName The factory binding name.
+ * @param queueBindingName The queue binding name.
+ * @param userName The user name.
+ * @param password The credentials for the user.
+ * @param info The Queue connection info.
+ */
+ protected JmsQueueManager(final String name, final Context context, final String factoryBindingName,
+ final String queueBindingName, final String userName, final String password,
+ final QueueInfo info) {
+ super(name);
+ this.context = context;
+ this.factoryBindingName = factoryBindingName;
+ this.queueBindingName = queueBindingName;
+ this.userName = userName;
+ this.password = password;
+ this.info = info;
+ }
+
+ /**
+ * Obtain a JmsQueueManager.
+ * @param factoryName The fully qualified class name of the InitialContextFactory.
+ * @param providerURL The URL of the provider to use.
+ * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
+ * will create a URL context factory
+ * @param securityPrincipalName The name of the identity of the Principal.
+ * @param securityCredentials The security credentials of the Principal.
+ * @param factoryBindingName The name to locate in the Context that provides the QueueConnectionFactory.
+ * @param queueBindingName The name to use to locate the Queue.
+ * @param userName The userid to use to create the Queue Connection.
+ * @param password The password to use to create the Queue Connection.
+ * @return The JmsQueueManager.
+ */
+ public static JmsQueueManager getJmsQueueManager(final String factoryName, final String providerURL,
+ final String urlPkgPrefixes, final String securityPrincipalName,
+ final String securityCredentials, final String factoryBindingName,
+ final String queueBindingName, final String userName,
+ final String password) {
+
+ if (factoryBindingName == null) {
+ LOGGER.error("No factory name provided for JmsQueueManager");
+ return null;
+ }
+ if (queueBindingName == null) {
+ LOGGER.error("No topic name provided for JmsQueueManager");
+ return null;
+ }
+
+ final String name = "JMSQueue:" + factoryBindingName + '.' + queueBindingName;
+ return getManager(name, FACTORY, new FactoryData(factoryName, providerURL, urlPkgPrefixes,
+ securityPrincipalName, securityCredentials, factoryBindingName, queueBindingName, userName, password));
+ }
+
+ @Override
+ public synchronized void send(final Serializable object) throws Exception {
+ if (info == null) {
+ info = connect(context, factoryBindingName, queueBindingName, userName, password, false);
+ }
+ try {
+ super.send(object, info.session, info.sender);
+ } catch (final Exception ex) {
+ cleanup(true);
+ throw ex;
+ }
+ }
+
+ @Override
+ public void releaseSub() {
+ if (info != null) {
+ cleanup(false);
+ }
+ }
+
+ private void cleanup(final boolean quiet) {
+ try {
+ info.session.close();
+ } catch (final Exception e) {
+ if (!quiet) {
+ LOGGER.error("Error closing session for " + getName(), e);
+ }
+ }
+ try {
+ info.conn.close();
+ } catch (final Exception e) {
+ if (!quiet) {
+ LOGGER.error("Error closing connection for " + getName(), e);
+ }
+ }
+ info = null;
+ }
+
+ /**
+ * Data for the factory.
+ */
+ private static class FactoryData {
+ private final String factoryName;
+ private final String providerURL;
+ private final String urlPkgPrefixes;
+ private final String securityPrincipalName;
+ private final String securityCredentials;
+ private final String factoryBindingName;
+ private final String queueBindingName;
+ private final String userName;
+ private final String password;
+
+ public FactoryData(final String factoryName, final String providerURL, final String urlPkgPrefixes,
+ final String securityPrincipalName, final String securityCredentials,
+ final String factoryBindingName, final String queueBindingName, final String userName,
+ final String password) {
+ this.factoryName = factoryName;
+ this.providerURL = providerURL;
+ this.urlPkgPrefixes = urlPkgPrefixes;
+ this.securityPrincipalName = securityPrincipalName;
+ this.securityCredentials = securityCredentials;
+ this.factoryBindingName = factoryBindingName;
+ this.queueBindingName = queueBindingName;
+ this.userName = userName;
+ this.password = password;
+ }
+ }
+
+ private static QueueInfo connect(final Context context, final String factoryBindingName,
+ final String queueBindingName, final String userName, final String password,
+ final boolean suppress) throws Exception {
+ try {
+ final QueueConnectionFactory factory = (QueueConnectionFactory) lookup(context, factoryBindingName);
+ QueueConnection conn;
+ if (userName != null) {
+ conn = factory.createQueueConnection(userName, password);
+ } else {
+ conn = factory.createQueueConnection();
+ }
+ final QueueSession sess = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+ final Queue queue = (Queue) lookup(context, queueBindingName);
+ final QueueSender sender = sess.createSender(queue);
+ conn.start();
+ return new QueueInfo(conn, sess, sender);
+ } catch (final NamingException ex) {
+ LOGGER.warn("Unable to locate connection factory " + factoryBindingName, ex);
+ if (!suppress) {
+ throw ex;
+ }
+ } catch (final JMSException ex) {
+ LOGGER.warn("Unable to create connection to queue " + queueBindingName, ex);
+ if (!suppress) {
+ throw ex;
+ }
+ }
+ return null;
+ }
+
+ /** Queue connection information */
+ private static class QueueInfo {
+ private final QueueConnection conn;
+ private final QueueSession session;
+ private final QueueSender sender;
+
+ public QueueInfo(final QueueConnection conn, final QueueSession session, final QueueSender sender) {
+ this.conn = conn;
+ this.session = session;
+ this.sender = sender;
+ }
+ }
+
+ /**
+ * Factory to create the JmsQueueManager.
+ */
+ private static class JMSQueueManagerFactory implements ManagerFactory<JmsQueueManager, FactoryData> {
+
+ @Override
+ public JmsQueueManager createManager(final String name, final FactoryData data) {
+ try {
+ final Context ctx = createContext(data.factoryName, data.providerURL, data.urlPkgPrefixes,
+ data.securityPrincipalName, data.securityCredentials);
+ final QueueInfo info = connect(ctx, data.factoryBindingName, data.queueBindingName, data.userName,
+ data.password, true);
+ return new JmsQueueManager(name, ctx, data.factoryBindingName, data.queueBindingName,
+ data.userName, data.password, info);
+ } catch (final NamingException ex) {
+ LOGGER.error("Unable to locate resource", ex);
+ } catch (final Exception ex) {
+ LOGGER.error("Unable to connect", ex);
+ }
+
+ return null;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java
new file mode 100644
index 0000000..b231489
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.receiver;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueReceiver;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+/**
+ * Receives Log Events over a JMS Queue. This implementation expects that all messages will
+ * contain a serialized LogEvent.
+ */
+public class JmsQueueReceiver extends AbstractJmsReceiver {
+
+ /**
+ * Constructor.
+ * @param qcfBindingName The QueueConnectionFactory binding name.
+ * @param queueBindingName The Queue binding name.
+ * @param username The userid to connect to the queue.
+ * @param password The password to connect to the queue.
+ */
+ public JmsQueueReceiver(final String qcfBindingName, final String queueBindingName, final String username,
+ final String password) {
+
+ try {
+ final Context ctx = new InitialContext();
+ QueueConnectionFactory queueConnectionFactory;
+ queueConnectionFactory = (QueueConnectionFactory) lookup(ctx, qcfBindingName);
+ final QueueConnection queueConnection = queueConnectionFactory.createQueueConnection(username, password);
+ queueConnection.start();
+ final QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+ final Queue queue = (Queue) ctx.lookup(queueBindingName);
+ final QueueReceiver queueReceiver = queueSession.createReceiver(queue);
+ queueReceiver.setMessageListener(this);
+ } catch (final JMSException e) {
+ logger.error("Could not read JMS message.", e);
+ } catch (final NamingException e) {
+ logger.error("Could not read JMS message.", e);
+ } catch (final RuntimeException e) {
+ logger.error("Could not read JMS message.", e);
+ }
+ }
+
+ /**
+ * Main startup for the receiver.
+ * @param args The command line arguments.
+ * @throws Exception if an error occurs.
+ */
+ public static void main(final String[] args) throws Exception {
+ if (args.length != 4) {
+ usage("Wrong number of arguments.");
+ }
+
+ final String qcfBindingName = args[0];
+ final String queueBindingName = args[1];
+ final String username = args[2];
+ final String password = args[3];
+
+ new JmsQueueReceiver(qcfBindingName, queueBindingName, username, password);
+
+ final Charset enc = Charset.defaultCharset();
+ final BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in, enc));
+ // Loop until the word "exit" is typed
+ System.out.println("Type \"exit\" to quit JmsQueueReceiver.");
+ while (true) {
+ final String line = stdin.readLine();
+ if (line == null || line.equalsIgnoreCase("exit")) {
+ System.out.println("Exiting. Kill the application if it does not exit "
+ + "due to daemon threads.");
+ return;
+ }
+ }
+ }
+
+
+ private static void usage(final String msg) {
+ System.err.println(msg);
+ System.err.println("Usage: java " + JmsQueueReceiver.class.getName()
+ + " QueueConnectionFactoryBindingName QueueBindingName username password");
+ System.exit(1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTopicManager.java
----------------------------------------------------------------------
diff --git a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTopicManager.java b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTopicManager.java
new file mode 100644
index 0000000..08d7128
--- /dev/null
+++ b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTopicManager.java
@@ -0,0 +1,237 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.mom.jms.receiver;
+
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+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.NamingException;
+
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+
+/**
+ * Manager for JMS Topic connections.
+ */
+public class JmsTopicManager extends AbstractJmsManager {
+
+ private static final JMSTopicManagerFactory FACTORY = new JMSTopicManagerFactory();
+
+ private TopicInfo info;
+ private final String factoryBindingName;
+ private final String topicBindingName;
+ private final String userName;
+ private final String password;
+ private final Context context;
+ /**
+ * Constructor.
+ * @param name The unique name of the connection.
+ * @param context The context.
+ * @param factoryBindingName The factory binding name.
+ * @param topicBindingName The queue binding name.
+ * @param userName The user name.
+ * @param password The credentials for the user.
+ * @param info The Queue connection info.
+ */
+ protected JmsTopicManager(final String name, final Context context, final String factoryBindingName,
+ final String topicBindingName, final String userName, final String password,
+ final TopicInfo info) {
+ super(name);
+ this.context = context;
+ this.factoryBindingName = factoryBindingName;
+ this.topicBindingName = topicBindingName;
+ this.userName = userName;
+ this.password = password;
+ this.info = info;
+ }
+
+ /**
+ * Obtain a JSMTopicManager.
+ * @param factoryName The fully qualified class name of the InitialContextFactory.
+ * @param providerURL The URL of the provider to use.
+ * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
+ * will create a URL context factory
+ * @param securityPrincipalName The name of the identity of the Principal.
+ * @param securityCredentials The security credentials of the Principal.
+ * @param factoryBindingName The name to locate in the Context that provides the TopicConnectionFactory.
+ * @param topicBindingName The name to use to locate the Topic.
+ * @param userName The userid to use to create the Topic Connection.
+ * @param password The password to use to create the Topic Connection.
+ * @return A JmsTopicManager.
+ */
+ public static JmsTopicManager getJmsTopicManager(final String factoryName, final String providerURL,
+ final String urlPkgPrefixes, final String securityPrincipalName,
+ final String securityCredentials, final String factoryBindingName,
+ final String topicBindingName, final String userName,
+ final String password) {
+
+ if (factoryBindingName == null) {
+ LOGGER.error("No factory name provided for JmsTopicManager");
+ return null;
+ }
+ if (topicBindingName == null) {
+ LOGGER.error("No topic name provided for JmsTopicManager");
+ return null;
+ }
+
+ final String name = "JMSTopic:" + factoryBindingName + '.' + topicBindingName;
+ return getManager(name, FACTORY, new FactoryData(factoryName, providerURL, urlPkgPrefixes,
+ securityPrincipalName, securityCredentials, factoryBindingName, topicBindingName, userName, password));
+ }
+
+
+ @Override
+ public void send(final Serializable object) throws Exception {
+ if (info == null) {
+ info = connect(context, factoryBindingName, topicBindingName, userName, password, false);
+ }
+ try {
+ super.send(object, info.session, info.publisher);
+ } catch (final Exception ex) {
+ cleanup(true);
+ throw ex;
+ }
+ }
+
+ @Override
+ public void releaseSub() {
+ if (info != null) {
+ cleanup(false);
+ }
+ }
+
+ private void cleanup(final boolean quiet) {
+ try {
+ info.session.close();
+ } catch (final Exception e) {
+ if (!quiet) {
+ LOGGER.error("Error closing session for " + getName(), e);
+ }
+ }
+ try {
+ info.conn.close();
+ } catch (final Exception e) {
+ if (!quiet) {
+ LOGGER.error("Error closing connection for " + getName(), e);
+ }
+ }
+ info = null;
+ }
+
+ /**
+ * Data for the factory.
+ */
+ private static class FactoryData {
+ private final String factoryName;
+ private final String providerURL;
+ private final String urlPkgPrefixes;
+ private final String securityPrincipalName;
+ private final String securityCredentials;
+ private final String factoryBindingName;
+ private final String topicBindingName;
+ private final String userName;
+ private final String password;
+
+ public FactoryData(final String factoryName, final String providerURL, final String urlPkgPrefixes,
+ final String securityPrincipalName, final String securityCredentials,
+ final String factoryBindingName, final String topicBindingName,
+ final String userName, final String password) {
+ this.factoryName = factoryName;
+ this.providerURL = providerURL;
+ this.urlPkgPrefixes = urlPkgPrefixes;
+ this.securityPrincipalName = securityPrincipalName;
+ this.securityCredentials = securityCredentials;
+ this.factoryBindingName = factoryBindingName;
+ this.topicBindingName = topicBindingName;
+ this.userName = userName;
+ this.password = password;
+ }