Rename log4j-mom to log4j-jms.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/89304e88 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/89304e88 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/89304e88 Branch: refs/heads/messaging-module Commit: 89304e886075dffefd53ca5430d98ee4994fe2e3 Parents: e1db6e2 Author: Matt Sicker <[email protected]> Authored: Sat Aug 30 17:18:04 2014 -0500 Committer: Matt Sicker <[email protected]> Committed: Sat Aug 30 17:18:04 2014 -0500 ---------------------------------------------------------------------- log4j-jms/pom.xml | 69 ++++++ .../log4j/mom/jms/appender/JmsAppender.java | 195 +++++++++++++++ .../mom/jms/appender/JmsQueueAppender.java | 113 +++++++++ .../mom/jms/appender/JmsTopicAppender.java | 114 +++++++++ .../log4j/mom/jms/appender/package-info.java | 20 ++ .../mom/jms/manager/AbstractJmsManager.java | 156 ++++++++++++ .../log4j/mom/jms/manager/JmsManager.java | 169 +++++++++++++ .../log4j/mom/jms/manager/JmsQueueManager.java | 237 +++++++++++++++++++ .../log4j/mom/jms/manager/JmsTopicManager.java | 237 +++++++++++++++++++ .../log4j/mom/jms/manager/JndiManager.java | 125 ++++++++++ .../mom/jms/receiver/AbstractJmsReceiver.java | 83 +++++++ .../mom/jms/receiver/JmsQueueReceiver.java | 107 +++++++++ .../mom/jms/receiver/JmsTopicReceiver.java | 105 ++++++++ .../log4j/mom/jms/receiver/package-info.java | 25 ++ .../log4j/mom/jms/appender/JmsAppenderIT.java | 126 ++++++++++ .../log4j/mom/jms/appender/JmsAppenderTest.java | 79 +++++++ .../mom/jms/appender/JmsQueueAppenderTest.java | 85 +++++++ .../mom/jms/appender/JmsQueueFailoverTest.java | 122 ++++++++++ .../log4j/mom/jms/appender/JmsQueueTest.java | 147 ++++++++++++ .../mom/jms/appender/JmsTopicFailoverTest.java | 121 ++++++++++ .../log4j/mom/jms/appender/JmsTopicTest.java | 147 ++++++++++++ .../src/test/resources/JmsAppenderTest.xml | 32 +++ .../test/resources/log4j-jmsqueue-failover.xml | 52 ++++ log4j-jms/src/test/resources/log4j-jmsqueue.xml | 30 +++ .../test/resources/log4j-jmstopic-failover.xml | 52 ++++ log4j-mom/pom.xml | 73 ------ .../log4j/mom/jms/appender/JmsAppender.java | 195 --------------- .../mom/jms/appender/JmsQueueAppender.java | 113 --------- .../mom/jms/appender/JmsTopicAppender.java | 114 --------- .../log4j/mom/jms/appender/package-info.java | 20 -- .../mom/jms/manager/AbstractJmsManager.java | 156 ------------ .../log4j/mom/jms/manager/JmsManager.java | 169 ------------- .../log4j/mom/jms/manager/JmsQueueManager.java | 237 ------------------- .../log4j/mom/jms/manager/JmsTopicManager.java | 237 ------------------- .../log4j/mom/jms/manager/JndiManager.java | 125 ---------- .../mom/jms/receiver/AbstractJmsReceiver.java | 83 ------- .../mom/jms/receiver/JmsQueueReceiver.java | 107 --------- .../mom/jms/receiver/JmsTopicReceiver.java | 105 -------- .../log4j/mom/jms/receiver/package-info.java | 25 -- .../log4j/mom/jms/appender/JmsAppenderIT.java | 126 ---------- .../log4j/mom/jms/appender/JmsAppenderTest.java | 79 ------- .../mom/jms/appender/JmsQueueAppenderTest.java | 85 ------- .../mom/jms/appender/JmsQueueFailoverTest.java | 122 ---------- .../log4j/mom/jms/appender/JmsQueueTest.java | 147 ------------ .../mom/jms/appender/JmsTopicFailoverTest.java | 121 ---------- .../log4j/mom/jms/appender/JmsTopicTest.java | 147 ------------ .../src/test/resources/JmsAppenderTest.xml | 32 --- .../test/resources/log4j-jmsqueue-failover.xml | 52 ---- log4j-mom/src/test/resources/log4j-jmsqueue.xml | 30 --- .../test/resources/log4j-jmstopic-failover.xml | 52 ---- pom.xml | 7 +- 51 files changed, 2749 insertions(+), 2758 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/89304e88/log4j-jms/pom.xml ---------------------------------------------------------------------- diff --git a/log4j-jms/pom.xml b/log4j-jms/pom.xml new file mode 100644 index 0000000..21bbb42 --- /dev/null +++ b/log4j-jms/pom.xml @@ -0,0 +1,69 @@ +<?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.1-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>log4j-jms</artifactId> + <name>Log4j 2 JMS Plugins</name> + <description>JMS appender 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> + + <!-- tests --> + <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>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <scope>test</scope> + </dependency> + <!-- integration tests --> + <dependency> + <groupId>org.apache.activemq</groupId> + <artifactId>activemq-broker</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-core</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsAppender.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsAppender.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsAppender.java new file mode 100644 index 0000000..c98e2a1 --- /dev/null +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsAppender.java @@ -0,0 +1,195 @@ +/* + * 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 javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; + +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.PluginBuilderAttribute; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; +import org.apache.logging.log4j.core.config.plugins.PluginElement; +import org.apache.logging.log4j.core.layout.SerializedLayout; +import org.apache.logging.log4j.mom.jms.manager.JmsManager; +import org.apache.logging.log4j.mom.jms.manager.JndiManager; + +/** + * Generic JMS appender plugin for both queues and topics. + */ +@Plugin(name = "JMS", category = "Core", elementType = "appender", printObject = true) +// TODO: use @PluginAliases to make the separated plugins work through this one +public class JmsAppender extends AbstractAppender { + + private final JmsManager manager; + private final MessageProducer producer; + + protected JmsAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout, + final boolean ignoreExceptions, final JmsManager manager) + throws JMSException { + super(name, filter, layout, ignoreExceptions); + this.manager = manager; + this.producer = this.manager.createMessageProducer(); + } + + @Override + public void append(LogEvent event) { + try { + final Message message = this.manager.createMessage(getLayout().toSerializable(event)); + message.setJMSTimestamp(event.getTimeMillis()); + this.producer.send(message); + } catch (JMSException e) { + throw new AppenderLoggingException(e); + } + } + + @PluginBuilderFactory + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder implements org.apache.logging.log4j.core.util.Builder<JmsAppender> { + + @PluginBuilderAttribute + private String name; + + @PluginBuilderAttribute + private String factoryName; + + @PluginBuilderAttribute + private String providerUrl; + + @PluginBuilderAttribute + private String urlPkgPrefixes; + + @PluginBuilderAttribute + private String securityPrincipalName; + + @PluginBuilderAttribute(sensitive = true) + private String securityCredentials; + + @PluginBuilderAttribute + private String factoryBindingName; + + @PluginBuilderAttribute + private String destinationBindingName; + + @PluginBuilderAttribute + private String username; + + @PluginBuilderAttribute(sensitive = true) + private String password; + + @PluginElement("Layout") + private Layout<? extends Serializable> layout = SerializedLayout.createLayout(); + + @PluginElement("Filter") + private Filter filter; + + @PluginBuilderAttribute + private boolean ignoreExceptions = true; + + private Builder() { + } + + public Builder setName(final String name) { + this.name = name; + return this; + } + + public Builder setFactoryName(final String factoryName) { + this.factoryName = factoryName; + return this; + } + + public Builder setProviderUrl(final String providerUrl) { + this.providerUrl = providerUrl; + return this; + } + + public Builder setUrlPkgPrefixes(final String urlPkgPrefixes) { + this.urlPkgPrefixes = urlPkgPrefixes; + return this; + } + + public Builder setSecurityPrincipalName(final String securityPrincipalName) { + this.securityPrincipalName = securityPrincipalName; + return this; + } + + public Builder setSecurityCredentials(final String securityCredentials) { + this.securityCredentials = securityCredentials; + return this; + } + + public Builder setFactoryBindingName(final String factoryBindingName) { + this.factoryBindingName = factoryBindingName; + return this; + } + + public Builder setDestinationBindingName(final String destinationBindingName) { + this.destinationBindingName = destinationBindingName; + return this; + } + + public Builder setUsername(final String username) { + this.username = username; + return this; + } + + public Builder setPassword(final String password) { + this.password = password; + return this; + } + + public Builder setLayout(final Layout<? extends Serializable> layout) { + this.layout = layout; + return this; + } + + public Builder setFilter(final Filter filter) { + this.filter = filter; + return this; + } + + public Builder setIgnoreExceptions(final boolean ignoreExceptions) { + this.ignoreExceptions = ignoreExceptions; + return this; + } + + @Override + public JmsAppender build() { + final JndiManager jndiManager = JndiManager.getJndiManager(factoryName, providerUrl, urlPkgPrefixes, + securityPrincipalName, securityCredentials, null); + final JmsManager jmsManager = JmsManager.getJmsManager(name, jndiManager, factoryBindingName, + destinationBindingName, username, password); + try { + return new JmsAppender(name, filter, layout, ignoreExceptions, jmsManager); + } catch (final JMSException e) { + LOGGER.error("Error creating JmsAppender [{}].", name, e); + return null; + } + } + } + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java new file mode 100644 index 0000000..4a544e4 --- /dev/null +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java @@ -0,0 +1,113 @@ +/* + * 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.manager.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 static final long serialVersionUID = 1L; + + 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/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java new file mode 100644 index 0000000..1b000ce --- /dev/null +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java @@ -0,0 +1,114 @@ +/* + * 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.manager.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 static final long serialVersionUID = 1L; + + 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("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 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/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java new file mode 100644 index 0000000..0c7a4ff --- /dev/null +++ b/log4j-jms/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/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/AbstractJmsManager.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/AbstractJmsManager.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/AbstractJmsManager.java new file mode 100644 index 0000000..e53b175 --- /dev/null +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/AbstractJmsManager.java @@ -0,0 +1,156 @@ +/* + * 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.manager; + +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. + * @see javax.naming.Context + */ + 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.setProperty(Context.INITIAL_CONTEXT_FACTORY, factoryName); + if (providerURL != null) { + props.setProperty(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.setProperty(Context.URL_PKG_PREFIXES, urlPkgPrefixes); + } + if (securityPrincipalName != null) { + props.setProperty(Context.SECURITY_PRINCIPAL, securityPrincipalName); + if (securityCredentials != null) { + props.setProperty(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/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JmsManager.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JmsManager.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JmsManager.java new file mode 100644 index 0000000..d3ce550 --- /dev/null +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JmsManager.java @@ -0,0 +1,169 @@ +/* + * 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.manager; + +import java.io.Serializable; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.naming.NamingException; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.appender.AbstractManager; +import org.apache.logging.log4j.core.appender.ManagerFactory; +import org.apache.logging.log4j.status.StatusLogger; + +/** + * JMS connection and session manager. Can be used to access MessageProducer, MessageConsumer, and Message objects + * involving a configured ConnectionFactory and Destination. + */ +public class JmsManager extends AbstractManager { + + private static final Logger LOGGER = StatusLogger.getLogger(); + + private static final JmsManagerFactory FACTORY = new JmsManagerFactory(); + + private final JndiManager jndiManager; + private final Connection connection; + private final Session session; + private final Destination destination; + + private JmsManager(final String name, final JndiManager jndiManager, final String connectionFactoryName, + final String destinationName, final String username, final String password) + throws NamingException, JMSException { + super(name); + this.jndiManager = jndiManager; + final ConnectionFactory connectionFactory = this.jndiManager.lookup(connectionFactoryName); + if (username != null && password != null) { + this.connection = connectionFactory.createConnection(username, password); + } else { + this.connection = connectionFactory.createConnection(); + } + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + this.destination = this.jndiManager.lookup(destinationName); + this.connection.start(); + } + + /** + * Gets a JmsManager using the specified configuration parameters. + * + * @param name The name to use for this JmsManager. + * @param jndiManager The JndiManager to look up JMS information through. + * @param connectionFactoryName The binding name for the {@link javax.jms.ConnectionFactory}. + * @param destinationName The binding name for the {@link javax.jms.Destination}. + * @param username The username to connect with or {@code null} for no authentication. + * @param password The password to use with the given username or {@code null} for no authentication. + * @return The JmsManager as configured. + */ + public static JmsManager getJmsManager(final String name, final JndiManager jndiManager, + final String connectionFactoryName, final String destinationName, + final String username, final String password) { + final JmsConfiguration configuration = new JmsConfiguration(jndiManager, connectionFactoryName, destinationName, + username, password); + return FACTORY.createManager(name, configuration); + } + + /** + * Creates a MessageConsumer on this Destination using the current Session. + * + * @return A MessageConsumer on this Destination. + * @throws JMSException + */ + public MessageConsumer createMessageConsumer() throws JMSException { + return this.session.createConsumer(this.destination); + } + + /** + * Creates a MessageProducer on this Destination using the current Session. + * + * @return A MessageProducer on this Destination. + * @throws JMSException + */ + public MessageProducer createMessageProducer() throws JMSException { + return this.session.createProducer(this.destination); + } + + /** + * Creates a TextMessage or ObjectMessage from a Serializable object. For instance, when using a text-based + * {@link org.apache.logging.log4j.core.Layout} such as {@link org.apache.logging.log4j.core.layout.PatternLayout}, + * the {@link org.apache.logging.log4j.core.LogEvent} message will be serialized to a String. When using a + * layout such as {@link org.apache.logging.log4j.core.layout.SerializedLayout}, the LogEvent message will be + * serialized as a Java object. + * + * @param object The LogEvent or String message to wrap. + * @return A new JMS message containing the provided object. + * @throws JMSException + */ + public Message createMessage(final Serializable object) throws JMSException { + if (object instanceof String) { + return this.session.createTextMessage((String) object); + } else { + return this.session.createObjectMessage(object); + } + } + + @Override + protected void releaseSub() { + try { + this.session.close(); + } catch (final JMSException ignored) { + } + try { + this.connection.close(); + } catch (final JMSException ignored) { + } + this.jndiManager.release(); + } + + private static class JmsConfiguration { + private final JndiManager jndiManager; + private final String connectionFactoryName; + private final String destinationName; + private final String username; + private final String password; + + private JmsConfiguration(JndiManager jndiManager, String connectionFactoryName, String destinationName, + String username, String password) { + this.jndiManager = jndiManager; + this.connectionFactoryName = connectionFactoryName; + this.destinationName = destinationName; + this.username = username; + this.password = password; + } + } + + private static class JmsManagerFactory implements ManagerFactory<JmsManager, JmsConfiguration> { + + @Override + public JmsManager createManager(String name, JmsConfiguration data) { + try { + return new JmsManager(name, data.jndiManager, data.connectionFactoryName, data.destinationName, + data.username, data.password); + } catch (final Exception e) { + LOGGER.error("Error creating JmsManager using ConnectionFactory [{}] and Destination [{}].", + data.connectionFactoryName, data.destinationName, e); + return null; + } + } + } + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JmsQueueManager.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JmsQueueManager.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JmsQueueManager.java new file mode 100644 index 0000000..fd00c03 --- /dev/null +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/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.manager; + +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/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JmsTopicManager.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JmsTopicManager.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JmsTopicManager.java new file mode 100644 index 0000000..9f45b72 --- /dev/null +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/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.manager; + +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; + } + } + + private static TopicInfo connect(final Context context, final String factoryBindingName, + final String queueBindingName, final String userName, final String password, + final boolean suppress) throws Exception { + try { + final TopicConnectionFactory factory = (TopicConnectionFactory) lookup(context, factoryBindingName); + TopicConnection conn; + if (userName != null) { + conn = factory.createTopicConnection(userName, password); + } else { + conn = factory.createTopicConnection(); + } + final TopicSession sess = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + final Topic topic = (Topic) lookup(context, queueBindingName); + final TopicPublisher publisher = sess.createPublisher(topic); + conn.start(); + return new TopicInfo(conn, sess, publisher); + } 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; + } + + /** Topic connection information */ + private static class TopicInfo { + private final TopicConnection conn; + private final TopicSession session; + private final TopicPublisher publisher; + + public TopicInfo(final TopicConnection conn, final TopicSession session, final TopicPublisher publisher) { + this.conn = conn; + this.session = session; + this.publisher = publisher; + } + } + + /** + * Factory to create the JmsQueueManager. + */ + private static class JMSTopicManagerFactory implements ManagerFactory<JmsTopicManager, FactoryData> { + + @Override + public JmsTopicManager createManager(final String name, final FactoryData data) { + try { + final Context ctx = createContext(data.factoryName, data.providerURL, data.urlPkgPrefixes, + data.securityPrincipalName, data.securityCredentials); + final TopicInfo info = connect(ctx, data.factoryBindingName, data.topicBindingName, data.userName, + data.password, true); + return new JmsTopicManager(name, ctx, data.factoryBindingName, data.topicBindingName, + 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/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JndiManager.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JndiManager.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JndiManager.java new file mode 100644 index 0000000..f56e28f --- /dev/null +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/manager/JndiManager.java @@ -0,0 +1,125 @@ +/* + * 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.manager; + +import java.util.Properties; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.appender.AbstractManager; +import org.apache.logging.log4j.core.appender.ManagerFactory; +import org.apache.logging.log4j.core.util.Closer; +import org.apache.logging.log4j.status.StatusLogger; + +/** + * JNDI context manager. Mainly useful for finding JMS objects and configuring the InitialContext. + */ +public class JndiManager extends AbstractManager { + + private static final Logger LOGGER = StatusLogger.getLogger(); + + private static final JndiManagerFactory FACTORY = new JndiManagerFactory(); + + private final Context context; + + private JndiManager(String name, Context context) { + super(name); + this.context = context; + } + + /** + * Gets a JndiManager with the provided configuration information. + * + * @param initialContextFactoryName Fully qualified class name of an implementation of + * {@link javax.naming.spi.InitialContextFactory}. + * @param providerURL The provider URL to use for the JNDI connection (specific to the above factory). + * @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 securityPrincipal The name of the identity of the Principal. + * @param securityCredentials The security credentials of the Principal. + * @param additionalProperties Any additional JNDI environment properties to set or {@code null} for none. + * @return the JndiManager for the provided parameters. + */ + public static JndiManager getJndiManager(final String initialContextFactoryName, + final String providerURL, + final String urlPkgPrefixes, + final String securityPrincipal, + final String securityCredentials, + final Properties additionalProperties) { + final String name = JndiManager.class.getName() + '@' + JndiManager.class.hashCode(); + if (initialContextFactoryName == null) { + return getManager(name, FACTORY, null); + } + final Properties properties = new Properties(); + properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, initialContextFactoryName); + if (providerURL != null) { + properties.setProperty(Context.PROVIDER_URL, providerURL); + } else { + LOGGER.warn("The JNDI InitialContextFactory class name [{}] was provided, but there was no associated " + + "provider URL. This is likely to cause problems.", initialContextFactoryName); + } + if (urlPkgPrefixes != null) { + properties.setProperty(Context.URL_PKG_PREFIXES, urlPkgPrefixes); + } + if (securityPrincipal != null) { + properties.setProperty(Context.SECURITY_PRINCIPAL, securityPrincipal); + if (securityCredentials != null) { + properties.setProperty(Context.SECURITY_CREDENTIALS, securityCredentials); + } else { + LOGGER.warn("A security principal [{}] was provided, but with no corresponding security credentials.", + securityPrincipal); + } + } + if (additionalProperties != null) { + properties.putAll(additionalProperties); + } + return getManager(name, FACTORY, properties); + } + + @Override + protected void releaseSub() { + Closer.closeSilently(this.context); + } + + /** + * Looks up a named object through this JNDI context. + * + * @param name name of the object to look up. + * @param <T> the type of the object. + * @return the named object if it could be located. + * @throws NamingException + */ + @SuppressWarnings("unchecked") + public <T> T lookup(final String name) throws NamingException { + return (T) this.context.lookup(name); + } + + private static class JndiManagerFactory implements ManagerFactory<JndiManager, Properties> { + + @Override + public JndiManager createManager(String name, Properties data) { + try { + return new JndiManager(name, new InitialContext(data)); + } catch (final NamingException e) { + LOGGER.error("Error creating JNDI InitialContext.", e); + return null; + } + } + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java new file mode 100644 index 0000000..bf86c65 --- /dev/null +++ b/log4j-jms/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/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java new file mode 100644 index 0000000..b231489 --- /dev/null +++ b/log4j-jms/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/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTopicReceiver.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTopicReceiver.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTopicReceiver.java new file mode 100644 index 0000000..0149ee5 --- /dev/null +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTopicReceiver.java @@ -0,0 +1,105 @@ +/* + * 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.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.NamingException; + +/** + * Receives Topic messages that contain LogEvents. This implementation expects that all messages + * are serialized log events. + */ +public class JmsTopicReceiver extends AbstractJmsReceiver { + + /** + * Constructor. + * @param tcfBindingName The TopicConnectionFactory binding name. + * @param topicBindingName The Topic binding name. + * @param username The userid to connect to the topic. + * @param password The password to connect to the topic. + */ + public JmsTopicReceiver(final String tcfBindingName, final String topicBindingName, final String username, + final String password) { + try { + final Context ctx = new InitialContext(); + TopicConnectionFactory topicConnectionFactory; + topicConnectionFactory = (TopicConnectionFactory) lookup(ctx, tcfBindingName); + final TopicConnection topicConnection = topicConnectionFactory.createTopicConnection(username, password); + topicConnection.start(); + final TopicSession topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + final Topic topic = (Topic) ctx.lookup(topicBindingName); + final TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic); + topicSubscriber.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 tcfBindingName = args[0]; + final String topicBindingName = args[1]; + final String username = args[2]; + final String password = args[3]; + + new JmsTopicReceiver(tcfBindingName, topicBindingName, 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 JmsTopicReceiver."); + 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 " + JmsTopicReceiver.class.getName() + + " TopicConnectionFactoryBindingName TopicBindingName username password"); + System.exit(1); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/89304e88/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/package-info.java ---------------------------------------------------------------------- diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/package-info.java b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/package-info.java new file mode 100644 index 0000000..1f233e8 --- /dev/null +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/mom/jms/receiver/package-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ +/** + * Supporting network code for JMS appenders. + * <p/> + * Note that you can use JmsQueueReceiver or JmsTopicReceiver as executable main classes to receive log events over + * JMS (sent via the appropriate JMS appender) that can be subsequently logged according to the configuration given to + * the running process. Of course, use of these classes as standalone executables are entirely optional and can + * be used directly in your application (e.g., through your Spring {@code beans.xml} configuration). + */ +package org.apache.logging.log4j.mom.jms.receiver; \ No newline at end of file
