You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2017/06/24 21:28:16 UTC
logging-log4j2 git commit: [LOG4J2-1934] JMS Appender does not know
how to recover from a broken connection. Refactor JMS Appender tests for
Apache ActiveMQ and add new tests that demonstrate the issue. Failing tests
are annotated with @Ignore.
Repository: logging-log4j2
Updated Branches:
refs/heads/master 1bf75bd5a -> c9ae6a85f
[LOG4J2-1934]
JMS Appender does not know how to recover from a broken connection.
Refactor JMS Appender tests for Apache ActiveMQ and add new tests that
demonstrate the issue. Failing tests are annotated with @Ignore.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/c9ae6a85
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/c9ae6a85
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/c9ae6a85
Branch: refs/heads/master
Commit: c9ae6a85f46c5083f5b63c3442afd4e778291429
Parents: 1bf75bd
Author: Gary Gregory <gg...@apache.org>
Authored: Sat Jun 24 14:28:13 2017 -0700
Committer: Gary Gregory <gg...@apache.org>
Committed: Sat Jun 24 14:28:13 2017 -0700
----------------------------------------------------------------------
.../org/apache/logging/log4j/TestMarkers.java | 31 +++
.../mom/activemq/AbstractJmsAppenderIT.java | 180 ++++++++++++++++
.../activemq/ActiveMqBrokerServiceHelper.java | 48 +++++
.../mom/activemq/ActiveMqBrokerServiceRule.java | 96 +++++++++
.../activemq/JmsAppenderConnectReConnectIT.java | 92 +++++++++
.../appender/mom/activemq/JmsAppenderIT.java | 183 -----------------
.../activemq/JmsAppenderITcpConnectionIT.java | 76 +++++++
.../activemq/JmsAppenderIVmConnectionIT.java | 59 ++++++
.../mom/activemq/JmsAppenderReConnectionIT.java | 79 +++++++
.../mom/activemq/JmsClientTestConfig.java | 95 +++++++++
.../mom/activemq/JmsClientTestConfigRule.java | 88 ++++++++
.../core/appender/AbstractFileAppender.java | 204 +++++++++++++++++++
.../test/AvailablePortSystemPropertyRule.java | 81 ++++++++
.../logging/log4j/test/RuleChainFactory.java | 44 ++++
14 files changed, 1173 insertions(+), 183 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core-its/src/test/java/org/apache/logging/log4j/TestMarkers.java
----------------------------------------------------------------------
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/TestMarkers.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/TestMarkers.java
new file mode 100644
index 0000000..29ba32c
--- /dev/null
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/TestMarkers.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+/**
+ * Markers useful in tests.
+ */
+public class TestMarkers {
+
+ public static final Marker LIFE_CYCLE = MarkerManager.getMarker("LIFECYCLE");
+ public static final Marker TEST = MarkerManager.getMarker("TEST");
+ public static final Marker TEST_RULE = MarkerManager.getMarker("TEST_RULE").addParents(TEST);
+ public static final Marker TEST_RULE_LIFE_CYCLE = MarkerManager.getMarker("TEST_RULE_LIFE_CYCLE")
+ .addParents(TEST_RULE).addParents(LIFE_CYCLE);
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/AbstractJmsAppenderIT.java
----------------------------------------------------------------------
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/AbstractJmsAppenderIT.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/AbstractJmsAppenderIT.java
new file mode 100644
index 0000000..135f568
--- /dev/null
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/AbstractJmsAppenderIT.java
@@ -0,0 +1,180 @@
+/*
+ * 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.core.appender.mom.activemq;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.ObjectMessage;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.mom.JmsAppender;
+import org.apache.logging.log4j.core.appender.mom.JmsManager;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.layout.MessageLayout;
+import org.apache.logging.log4j.core.layout.SerializedLayout;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.message.StringMapMessage;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Abstracts services for integration test for the JmsAppender using an embedded
+ * ActiveMQ broker. The client (appender) is set up once for the whole class.
+ * Subclasses decide whether the broker is reinitialized for each test method.
+ * This allows to test the ability of the JmsAppender to reconnect.
+ *
+ * The subclasses cannot be run in parallel.
+ */
+public abstract class AbstractJmsAppenderIT {
+
+ static class JmsQueueConsumer implements MessageListener {
+
+ private final CountDownLatch countDownLatch;
+ private final Collection<Object> events;
+ private final Class<? extends Message> messageClass;
+ private final int messageCount;
+
+ JmsQueueConsumer(final int messageCount, final Class<? extends Message> messageClass) {
+ this.messageCount = messageCount;
+ this.messageClass = messageClass;
+ this.countDownLatch = new CountDownLatch(messageCount);
+ this.events = new ArrayList<>(messageCount);
+ }
+
+ public void awaitAndAssertAllMessagesConsumed() throws InterruptedException {
+ countDownLatch.await(5, TimeUnit.SECONDS);
+ assertEquals(messageCount, events.size());
+ }
+
+ @Override
+ public void onMessage(final Message message) {
+ try {
+ try {
+ final Object event;
+ Assert.assertTrue(String.format("Expected type '%s' to be an instance of %s", message.getClass(),
+ messageClass), messageClass.isAssignableFrom(message.getClass()));
+ if (message instanceof ObjectMessage) {
+ event = ((ObjectMessage) message).getObject();
+ } else if (message instanceof javax.jms.MapMessage) {
+ event = message;
+ } else {
+ Assert.fail("Unexpected Message type: " + message);
+ event = null;
+ }
+ events.add(event);
+ } finally {
+ countDownLatch.countDown();
+ }
+ } catch (final JMSException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ static final String KEY_SERIALIZABLE_PACKAGES = "org.apache.activemq.SERIALIZABLE_PACKAGES";
+
+ private final JmsClientTestConfigRule jmsTestConfigRule;
+
+ public AbstractJmsAppenderIT(final JmsClientTestConfigRule jmsTestConfigRule) {
+ this.jmsTestConfigRule = jmsTestConfigRule;
+ }
+
+ protected JmsAppender getJmsAppender() {
+ return getJmsTestConfig().getJmsAppender();
+ }
+
+ protected JmsManager getJmsManager() {
+ return getJmsTestConfig().getJmsManager();
+ }
+
+ private JmsClientTestConfig getJmsTestConfig() {
+ return jmsTestConfigRule.getJmsClientTestConfig();
+ }
+
+ @Test
+ public void testLogMapMessageToQueue() throws Exception {
+ getJmsTestConfig().createAppender(MessageLayout.createLayout());
+ final int messageCount = 100;
+ final MessageConsumer messageConsumer = getJmsManager().createMessageConsumer();
+ try {
+ final JmsQueueConsumer consumer = new JmsQueueConsumer(messageCount, javax.jms.MapMessage.class);
+ messageConsumer.setMessageListener(consumer);
+ final String messageText = "Hello, World!";
+ final String loggerName = this.getClass().getName();
+ for (int i = 0; i < messageCount; i++) {
+ final Map<String, String> map = new HashMap<>();
+ map.put("messageText", messageText);
+ map.put("threadName", Thread.currentThread().getName());
+ // @formatter:off
+ final LogEvent event = Log4jLogEvent.newBuilder()
+ .setLoggerName(loggerName)
+ .setLoggerFqcn(loggerName)
+ .setLevel(Level.INFO)
+ .setMessage(new StringMapMessage(map))
+ .setTimeMillis(System.currentTimeMillis())
+ .build();
+ // @formatter:on
+ getJmsAppender().append(event);
+ }
+ consumer.awaitAndAssertAllMessagesConsumed();
+ } finally {
+ messageConsumer.close();
+ }
+ }
+
+ @Test
+ public void testLogObjectMessageToQueue() throws Exception {
+ getJmsTestConfig().createAppender(SerializedLayout.createLayout());
+ final int messageCount = 100;
+ final MessageConsumer messageConsumer = getJmsManager().createMessageConsumer();
+ try {
+ final JmsQueueConsumer consumer = new JmsQueueConsumer(messageCount, ObjectMessage.class);
+ messageConsumer.setMessageListener(consumer);
+ final String messageText = "Hello, World!";
+ final String loggerName = this.getClass().getName();
+ for (int i = 0; i < messageCount; i++) {
+ // @formatter:off
+ final LogEvent event = Log4jLogEvent.newBuilder()
+ .setLoggerName(loggerName)
+ .setLoggerFqcn(loggerName)
+ .setLevel(Level.INFO)
+ .setMessage(new SimpleMessage(messageText))
+ .setThreadName(Thread.currentThread().getName())
+ .setTimeMillis(System.currentTimeMillis())
+ .build();
+ // @formatter:on
+ getJmsAppender().append(event);
+ }
+ consumer.awaitAndAssertAllMessagesConsumed();
+ } finally {
+ messageConsumer.close();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/ActiveMqBrokerServiceHelper.java
----------------------------------------------------------------------
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/ActiveMqBrokerServiceHelper.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/ActiveMqBrokerServiceHelper.java
new file mode 100644
index 0000000..6f6949d
--- /dev/null
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/ActiveMqBrokerServiceHelper.java
@@ -0,0 +1,48 @@
+/*
+ * 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.core.appender.mom.activemq;
+
+import java.io.IOException;
+
+import org.apache.activemq.broker.BrokerService;
+
+/**
+ * Helps starts an embedded Apache ActiveMQ service broker.
+ */
+public class ActiveMqBrokerServiceHelper {
+
+ static BrokerService startBrokerService(final String brokerName, String brokerUrlString, final int port) throws Exception {
+ // TODO Abstract out scheme
+ brokerUrlString = "tcp://localhost:" + port;
+ final BrokerService broker = new BrokerService();
+ // configure the Broker
+ broker.setBrokerName(brokerName);
+ broker.addConnector(brokerUrlString);
+ broker.setPersistent(false);
+ broker.start();
+ broker.waitUntilStarted();
+ return broker;
+ }
+
+ static void stopBrokerService(final BrokerService broker) throws IOException, Exception {
+ broker.deleteAllMessages();
+ broker.stop();
+ broker.waitUntilStopped();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/ActiveMqBrokerServiceRule.java
----------------------------------------------------------------------
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/ActiveMqBrokerServiceRule.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/ActiveMqBrokerServiceRule.java
new file mode 100644
index 0000000..445172e
--- /dev/null
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/ActiveMqBrokerServiceRule.java
@@ -0,0 +1,96 @@
+/*
+ * 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.core.appender.mom.activemq;
+
+import org.apache.activemq.broker.BrokerService;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.TestMarkers;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * JUnit {@link TestRule} to manage an in-JVM Apache ActiveMQ broker with socket
+ * communications between clients and broker.
+ *
+ * @author <a href="mailto:ggregory@rocketsoftware.com">Gary Gregory</a>
+ */
+public class ActiveMqBrokerServiceRule implements TestRule {
+
+ static final Logger logger = LogManager.getLogger(ActiveMqBrokerServiceRule.class);
+
+ /**
+ * Apache Active MQ uses this property name to lookup which port to use to
+ * connect to a broker.
+ */
+ static final String PORT_PROPERTY_NAME = "org.apache.activemq.AMQ_PORT";
+
+ private final String brokerName;
+
+ private String brokerUrlString;
+
+ private final String portPropertyName;
+
+ public ActiveMqBrokerServiceRule(final String brokerName, final String portPropertyName) {
+ this.brokerName = brokerName;
+ this.portPropertyName = portPropertyName;
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ final BrokerService broker = ActiveMqBrokerServiceHelper.startBrokerService(brokerName, brokerUrlString,
+ Integer.parseInt(System.getProperty(portPropertyName)));
+ logger.debug(TestMarkers.TEST_RULE_LIFE_CYCLE, "{} started Apache Active MQ {}",
+ this.getClass().getSimpleName(), this);
+ try {
+ base.evaluate();
+ } finally {
+ ActiveMqBrokerServiceHelper.stopBrokerService(broker);
+ logger.debug(TestMarkers.TEST_RULE_LIFE_CYCLE, "{} stopped Apache Active MQ {}",
+ this.getClass().getSimpleName(), this);
+ }
+ }
+
+ };
+ }
+
+ public String getBrokerName() {
+ return brokerName;
+ }
+
+ public String getBrokerUrlString() {
+ return brokerUrlString;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("ActiveMqBrokerServiceRule [brokerName=");
+ builder.append(brokerName);
+ builder.append(", bindAddress=");
+ builder.append(brokerUrlString);
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderConnectReConnectIT.java
----------------------------------------------------------------------
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderConnectReConnectIT.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderConnectReConnectIT.java
new file mode 100644
index 0000000..7e53171
--- /dev/null
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderConnectReConnectIT.java
@@ -0,0 +1,92 @@
+/*
+ * 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.core.appender.mom.activemq;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.jndi.ActiveMQInitialContextFactory;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.categories.Appenders;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.mom.JmsAppender;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.layout.MessageLayout;
+import org.apache.logging.log4j.message.StringMapMessage;
+import org.apache.logging.log4j.test.AvailablePortFinder;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+/**
+ * Tests that a JMS Appender can reconnect to a JMS broker after it has been
+ * recycled.
+ * <p>
+ * LOG4J2-1934 JMS Appender does not know how to recover from a broken
+ * connection. See https://issues.apache.org/jira/browse/LOG4J2-1934
+ * </p>
+ */
+@Ignore
+@Category(Appenders.Jms.class)
+public class JmsAppenderConnectReConnectIT {
+
+ private void appendEvent(final JmsAppender appender) {
+ final Map<String, String> map = new HashMap<>();
+ final String messageText = "Hello, World!";
+ final String loggerName = this.getClass().getName();
+ map.put("messageText", messageText);
+ map.put("threadName", Thread.currentThread().getName());
+ // @formatter:off
+ final LogEvent event = Log4jLogEvent.newBuilder()
+ .setLoggerName(loggerName)
+ .setLoggerFqcn(loggerName)
+ .setLevel(Level.INFO)
+ .setMessage(new StringMapMessage(map))
+ .setTimeMillis(System.currentTimeMillis())
+ .build();
+ // @formatter:on
+ appender.append(event);
+ }
+
+ @Test
+ @Ignore
+ public void testConnectReConnect() throws Exception {
+ // Start broker
+ final int port = AvailablePortFinder.getNextAvailable();
+ final String brokerUrlString = "tcp://localhost:" + port;
+ BrokerService brokerService = ActiveMqBrokerServiceHelper
+ .startBrokerService(JmsAppenderConnectReConnectIT.class.getName(), brokerUrlString, port);
+ // Start appender
+ final JmsClientTestConfig jmsClientTestConfig = new JmsClientTestConfig(ActiveMQInitialContextFactory.class.getName(),
+ brokerUrlString, "admin", "admin");
+ jmsClientTestConfig.start();
+ final JmsAppender appender = jmsClientTestConfig.createAppender(MessageLayout.createLayout());
+ // Log message
+ appendEvent(appender);
+ // Stop broker
+ ActiveMqBrokerServiceHelper.stopBrokerService(brokerService);
+ // Restart broker
+ brokerService = ActiveMqBrokerServiceHelper.startBrokerService(JmsAppenderConnectReConnectIT.class.getName(),
+ brokerUrlString, port);
+ // Logging again should cause the appender to reconnect
+ appendEvent(appender);
+ // Stop broker
+ ActiveMqBrokerServiceHelper.stopBrokerService(brokerService);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIT.java
----------------------------------------------------------------------
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIT.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIT.java
deleted file mode 100644
index 25b3252..0000000
--- a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIT.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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.core.appender.mom.activemq;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageListener;
-import javax.jms.ObjectMessage;
-
-import org.apache.activemq.jndi.ActiveMQInitialContextFactory;
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.categories.Appenders;
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.appender.mom.JmsAppender;
-import org.apache.logging.log4j.core.appender.mom.JmsManager;
-import org.apache.logging.log4j.core.impl.Log4jLogEvent;
-import org.apache.logging.log4j.core.layout.MessageLayout;
-import org.apache.logging.log4j.core.layout.SerializedLayout;
-import org.apache.logging.log4j.core.net.JndiManager;
-import org.apache.logging.log4j.message.StringMapMessage;
-import org.apache.logging.log4j.message.SimpleMessage;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-/**
- * Integration test for JmsAppender using an embedded ActiveMQ broker.
- */
-@Category(Appenders.Jms.class)
-public class JmsAppenderIT {
-
- private static final String KEY_SERIALIZABLE_PACKAGES = "org.apache.activemq.SERIALIZABLE_PACKAGES";
-
- private JmsManager jmsManager;
-
- private JmsAppender appender;
-
- @Before
- public void setUpClass() {
- System.setProperty(KEY_SERIALIZABLE_PACKAGES,
- "org.apache.logging.log4j.core.impl,org.apache.logging.log4j.util,org.apache.logging.log4j,java.rmi");
- final Properties additional = new Properties();
- additional.setProperty("queue.TestQueue", "TestQueue");
- @SuppressWarnings("resource") // jndiManager is closed in tearDownClass() through the jmsManager
- final JndiManager jndiManager = JndiManager.getJndiManager(ActiveMQInitialContextFactory.class.getName(),
- "vm://localhost?broker.persistent=false", null, null, null, additional);
- jmsManager = JmsManager.getJmsManager("JmsManager", jndiManager, "ConnectionFactory", "TestQueue", null, null);
- }
-
- @After
- public void tearDownClass() {
- if (jmsManager != null) {
- jmsManager.close();
- }
- System.getProperties().remove(KEY_SERIALIZABLE_PACKAGES);
- }
-
- private void setUp(Layout<?> layout) throws Exception {
- // @formatter:off
- appender = JmsAppender.newBuilder()
- .setName("JmsAppender")
- .setLayout(layout)
- .setIgnoreExceptions(true)
- .setJmsManager(jmsManager)
- .build();
- // @formatter:off
- appender.start();
- }
-
- @Test
- public void testLogMapMessageToQueue() throws Exception {
- setUp(MessageLayout.createLayout());
- final int messageCount = 100;
- final MessageConsumer messageConsumer = jmsManager.createMessageConsumer();
- final JmsQueueConsumer consumer = new JmsQueueConsumer(messageCount, javax.jms.MapMessage.class);
- messageConsumer.setMessageListener(consumer);
- final String messageText = "Hello, World!";
- final String loggerName = this.getClass().getName();
- for (int i = 0; i < messageCount; i++) {
- Map<String, String> map = new HashMap<>();
- map.put("messageText", messageText);
- map.put("threadName", Thread.currentThread().getName());
- final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName(loggerName) //
- .setLoggerFqcn(loggerName).setLevel(Level.INFO) //
- .setMessage(new StringMapMessage(map)) //
- .setTimeMillis(System.currentTimeMillis()).build();
- appender.append(event);
- }
- consumer.awaitAndAssertAllMessagesConsumed();
- }
-
- @Test
- public void testLogObjectMessageToQueue() throws Exception {
- setUp(SerializedLayout.createLayout());
- final int messageCount = 100;
- final MessageConsumer messageConsumer = jmsManager.createMessageConsumer();
- final JmsQueueConsumer consumer = new JmsQueueConsumer(messageCount, ObjectMessage.class);
- messageConsumer.setMessageListener(consumer);
- final String messageText = "Hello, World!";
- final String loggerName = this.getClass().getName();
- for (int i = 0; i < messageCount; i++) {
- final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName(loggerName) //
- .setLoggerFqcn(loggerName).setLevel(Level.INFO) //
- .setMessage(new SimpleMessage(messageText)).setThreadName(Thread.currentThread().getName()) //
- .setTimeMillis(System.currentTimeMillis()).build();
- appender.append(event);
- }
- consumer.awaitAndAssertAllMessagesConsumed();
- }
-
- private static class JmsQueueConsumer implements MessageListener {
-
- private final int messageCount;
- private final Class<? extends Message> messageClass;
- private final CountDownLatch countDownLatch;
- private final Collection<Object> events;
-
- private JmsQueueConsumer(final int messageCount, Class<? extends Message> messageClass) {
- this.messageCount = messageCount;
- this.messageClass = messageClass;
- this.countDownLatch = new CountDownLatch(messageCount);
- this.events = new ArrayList<>(messageCount);
- }
-
- @Override
- public void onMessage(final Message message) {
- try {
- try {
- final Object event;
- Assert.assertTrue(String.format("Expected type '%s' to be an instance of %s", message.getClass(), messageClass),
- messageClass.isAssignableFrom(message.getClass()));
- if (message instanceof ObjectMessage) {
- event = ((ObjectMessage) message).getObject();
- } else if (message instanceof javax.jms.MapMessage) {
- event = message;
- } else {
- Assert.fail("Unexpected Message type: " + message);
- event = null;
- }
- events.add(event);
- } finally {
- countDownLatch.countDown();
- }
- } catch (final JMSException e) {
- e.printStackTrace();
- }
- }
-
- public void awaitAndAssertAllMessagesConsumed() throws InterruptedException {
- countDownLatch.await(5, TimeUnit.SECONDS);
- assertEquals(messageCount, events.size());
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderITcpConnectionIT.java
----------------------------------------------------------------------
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderITcpConnectionIT.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderITcpConnectionIT.java
new file mode 100644
index 0000000..c32f911
--- /dev/null
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderITcpConnectionIT.java
@@ -0,0 +1,76 @@
+/*
+ * 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.core.appender.mom.activemq;
+
+import org.apache.activemq.jndi.ActiveMQInitialContextFactory;
+import org.apache.logging.log4j.categories.Appenders;
+import org.apache.logging.log4j.test.AvailablePortSystemPropertyRule;
+import org.apache.logging.log4j.test.RuleChainFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.RuleChain;
+
+/**
+ * Integration test for JmsAppender using an embedded ActiveMQ broker with in
+ * socket communications between clients and broker. This test manages a client
+ * connection to JMS like an Appender would. This test appender is managed at
+ * the class level by a JmsTestConfigRule.
+ * <p>
+ * The test manages an Apache ActiveMQ broken embedded in this test. A new
+ * broker is started and stopped for each test method on the same port, which
+ * means that the JMS Appender needs to reconnect to JMS for the second test
+ * run, which ever that test maybe.
+ * </p>
+ */
+@Category(Appenders.Jms.class)
+public class JmsAppenderITcpConnectionIT extends AbstractJmsAppenderIT {
+
+ public static final AvailablePortSystemPropertyRule portRule = AvailablePortSystemPropertyRule
+ .create(ActiveMqBrokerServiceRule.PORT_PROPERTY_NAME);
+
+ public static final ActiveMqBrokerServiceRule activeMqBrokerServiceRule = new ActiveMqBrokerServiceRule(
+ JmsAppenderITcpConnectionIT.class.getName(), portRule.getName());
+
+ // "admin"/"admin" are the default Apache Active MQ creds.
+ public static final JmsClientTestConfigRule jmsClientTestConfigRule = new JmsClientTestConfigRule(
+ activeMqBrokerServiceRule, ActiveMQInitialContextFactory.class.getName(), "admin", "admin");
+
+ /**
+ * We assign a port only ONCE ands start the broker ONCE for the whole test
+ * suite.
+ */
+ @ClassRule
+ public static final RuleChain ruleChain = RuleChainFactory.create(portRule, activeMqBrokerServiceRule,
+ jmsClientTestConfigRule);
+
+ @AfterClass
+ public static void afterClass() {
+ jmsClientTestConfigRule.getJmsClientTestConfig().stop();
+ }
+
+ @BeforeClass
+ public static void beforeClass() {
+ jmsClientTestConfigRule.getJmsClientTestConfig().start();
+ }
+
+ public JmsAppenderITcpConnectionIT() {
+ super(jmsClientTestConfigRule);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIVmConnectionIT.java
----------------------------------------------------------------------
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIVmConnectionIT.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIVmConnectionIT.java
new file mode 100644
index 0000000..0178ea3
--- /dev/null
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIVmConnectionIT.java
@@ -0,0 +1,59 @@
+/*
+ * 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.core.appender.mom.activemq;
+
+import org.apache.activemq.jndi.ActiveMQInitialContextFactory;
+import org.apache.logging.log4j.categories.Appenders;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.experimental.categories.Category;
+
+/**
+ * Integration test for JmsAppender using an embedded ActiveMQ broker with in
+ * direct VM communication between clients and broker.
+ * <p>
+ * This test manages a client connection to JMS like an Appender would. This
+ * test appender is managed at the class level by a JmsTestConfigRule.
+ * </p>
+ * <p>
+ * This test does not manage an Apache ActiveMQ broker explicitly, rather it
+ * lets ActiveMQ use its "vm" protocol.
+ * </p>
+ */
+@Category(Appenders.Jms.class)
+public class JmsAppenderIVmConnectionIT extends AbstractJmsAppenderIT {
+
+ @ClassRule
+ public static final JmsClientTestConfigRule jmsClientTestConfigRule = new JmsClientTestConfigRule(
+ ActiveMQInitialContextFactory.class.getName(), "vm://localhost?broker.persistent=false", null, null);
+
+ @AfterClass
+ public static void afterClass() {
+ jmsClientTestConfigRule.getJmsClientTestConfig().stop();
+ }
+
+ @BeforeClass
+ public static void beforeClass() {
+ jmsClientTestConfigRule.getJmsClientTestConfig().start();
+ }
+
+ public JmsAppenderIVmConnectionIT() {
+ super(jmsClientTestConfigRule);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderReConnectionIT.java
----------------------------------------------------------------------
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderReConnectionIT.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderReConnectionIT.java
new file mode 100644
index 0000000..262a3da
--- /dev/null
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderReConnectionIT.java
@@ -0,0 +1,79 @@
+/*
+ * 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.core.appender.mom.activemq;
+
+import org.apache.activemq.jndi.ActiveMQInitialContextFactory;
+import org.apache.logging.log4j.categories.Appenders;
+import org.apache.logging.log4j.test.AvailablePortSystemPropertyRule;
+import org.apache.logging.log4j.test.RuleChainFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.RuleChain;
+
+/**
+ * Integration test for JmsAppender using an embedded ActiveMQ broker with in
+ * socket communications between clients and broker. This test manages a client
+ * connection to JMS like a Appender would. This test appender is managed at the
+ * class level by a JmsTestConfigRule.
+ * <p>
+ * Tests that a JMS appender can connect to a broker AFTER Log4j startup.
+ * </p>
+ * <p>
+ * LOG4J2-1934 JMS Appender does not know how to recover from a broken
+ * connection. See https://issues.apache.org/jira/browse/LOG4J2-1934
+ * </p>
+ */
+@Ignore
+@Category(Appenders.Jms.class)
+public class JmsAppenderReConnectionIT extends AbstractJmsAppenderIT {
+
+ public static final AvailablePortSystemPropertyRule portRule = AvailablePortSystemPropertyRule
+ .create(ActiveMqBrokerServiceRule.PORT_PROPERTY_NAME);
+
+ @Rule
+ public final ActiveMqBrokerServiceRule activeMqBrokerServiceRule = new ActiveMqBrokerServiceRule(
+ JmsAppenderReConnectionIT.class.getName(), portRule.getName());
+
+ // "admin"/"admin" are the default Apache Active MQ creds.
+ private static final JmsClientTestConfigRule jmsClientTestConfigRule = new JmsClientTestConfigRule(
+ ActiveMQInitialContextFactory.class.getName(), "tcp://localhost:" + portRule.getPort(), "admin", "admin");
+
+ /**
+ * Assign the port and client ONCE for the whole test suite.
+ */
+ @ClassRule
+ public static final RuleChain ruleChain = RuleChainFactory.create(portRule, jmsClientTestConfigRule);
+
+ @AfterClass
+ public static void afterClass() {
+ jmsClientTestConfigRule.getJmsClientTestConfig().stop();
+ }
+
+ @BeforeClass
+ public static void beforeClass() {
+ jmsClientTestConfigRule.getJmsClientTestConfig().start();
+ }
+
+ public JmsAppenderReConnectionIT() {
+ super(jmsClientTestConfigRule);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsClientTestConfig.java
----------------------------------------------------------------------
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsClientTestConfig.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsClientTestConfig.java
new file mode 100644
index 0000000..17ac788
--- /dev/null
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsClientTestConfig.java
@@ -0,0 +1,95 @@
+package org.apache.logging.log4j.core.appender.mom.activemq;
+
+import java.util.Properties;
+
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.appender.mom.JmsAppender;
+import org.apache.logging.log4j.core.appender.mom.JmsManager;
+import org.apache.logging.log4j.core.net.JndiManager;
+
+/**
+ * All the JMS information and state needed to configure and get a test
+ * going.
+ */
+class JmsClientTestConfig {
+
+ private JmsAppender jmsAppender;
+ private final String jmsInitialContextFactoryClassName;
+ private JmsManager jmsManager;
+ private final String jmsPassword;
+ private final String jmsProviderUrlStr;
+ private final String jmsUserName;
+
+ JmsClientTestConfig(final String jmsInitialContextFactoryClassName, final String jmsProviderUrlStr, final String jmsUserName, final String jmsPassword) {
+ this.jmsInitialContextFactoryClassName = jmsInitialContextFactoryClassName;
+ this.jmsProviderUrlStr = jmsProviderUrlStr;
+ this.jmsUserName = jmsUserName;
+ this.jmsPassword = jmsPassword;
+ }
+
+ JmsAppender createAppender(final Layout<?> layout) {
+ // @formatter:off
+ jmsAppender = JmsAppender.newBuilder()
+ .setName("JmsAppender")
+ .setLayout(layout)
+ .setIgnoreExceptions(true)
+ .setJmsManager(jmsManager)
+ .build();
+ // @formatter:off
+ jmsAppender.start();
+ return jmsAppender;
+ }
+
+ JmsAppender getJmsAppender() {
+ return jmsAppender;
+ }
+
+ String getJmsInitialContextFactoryClassName() {
+ return jmsInitialContextFactoryClassName;
+ }
+
+ JmsManager getJmsManager() {
+ return jmsManager;
+ }
+
+ String getJmsPassword() {
+ return jmsPassword;
+ }
+
+ String getJmsProviderUrlStr() {
+ return jmsProviderUrlStr;
+ }
+
+ String getJmsUserName() {
+ return jmsUserName;
+ }
+
+ void setJmsAppender(final JmsAppender jmsAppender) {
+ this.jmsAppender = jmsAppender;
+ }
+
+ void setJmsManager(final JmsManager jmsManager) {
+ this.jmsManager = jmsManager;
+ }
+
+ void start() {
+ System.setProperty(AbstractJmsAppenderIT.KEY_SERIALIZABLE_PACKAGES,
+ "org.apache.logging.log4j.core.impl,org.apache.logging.log4j.util,org.apache.logging.log4j,java.rmi");
+ final Properties additional = new Properties();
+ additional.setProperty("queue.TestQueue", "TestQueue");
+ // jndiManager is closed in stop() through the jmsManager
+ @SuppressWarnings("resource")
+ final JndiManager jndiManager = JndiManager.getJndiManager(jmsInitialContextFactoryClassName,
+ jmsProviderUrlStr, null, null, null, additional);
+ jmsManager = JmsManager.getJmsManager("JmsManager", jndiManager, "ConnectionFactory", "TestQueue",
+ jmsUserName, jmsPassword);
+ }
+
+ void stop() {
+ if (jmsManager != null) {
+ jmsManager.close();
+ jmsManager = null;
+ }
+ System.getProperties().remove(AbstractJmsAppenderIT.KEY_SERIALIZABLE_PACKAGES);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsClientTestConfigRule.java
----------------------------------------------------------------------
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsClientTestConfigRule.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsClientTestConfigRule.java
new file mode 100644
index 0000000..9cb2e8f
--- /dev/null
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsClientTestConfigRule.java
@@ -0,0 +1,88 @@
+package org.apache.logging.log4j.core.appender.mom.activemq;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * A JUnit {@link TestRule} that builds a JmsTestConfig by getting a JMS broker
+ * URL string from either a ActiveMqBrokerServiceRule or the one it was given in
+ * the constructor.
+ */
+class JmsClientTestConfigRule implements TestRule {
+
+ final ActiveMqBrokerServiceRule activeMqBrokerServiceRule;
+ final String brokerUrlStr;
+ private JmsClientTestConfig jmsClientTestConfig;
+ final String jmsInitialContextFactoryClassName;
+ final String password;
+ final String userName;
+
+ public JmsClientTestConfigRule(final ActiveMqBrokerServiceRule activeMqBrokerServiceRule,
+ final String jmsInitialContextFactoryClassName, final String userName, final String password) {
+ this.activeMqBrokerServiceRule = activeMqBrokerServiceRule;
+ this.jmsInitialContextFactoryClassName = jmsInitialContextFactoryClassName;
+ this.brokerUrlStr = null;
+ this.userName = userName;
+ this.password = password;
+ }
+
+ public JmsClientTestConfigRule(final String jmsInitialContextFactoryClassName, final String brokerUrlStr, final String userName,
+ final String password) {
+ this.activeMqBrokerServiceRule = null;
+ this.jmsInitialContextFactoryClassName = jmsInitialContextFactoryClassName;
+ this.brokerUrlStr = brokerUrlStr;
+ this.userName = userName;
+ this.password = password;
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ jmsClientTestConfig = new JmsClientTestConfig(jmsInitialContextFactoryClassName, getBrokerUrlString(),
+ userName, password);
+ try {
+ base.evaluate();
+ } finally {
+ // no tear down.
+ }
+ }
+
+ private String getBrokerUrlString() {
+ return brokerUrlStr != null ? brokerUrlStr : activeMqBrokerServiceRule.getBrokerUrlString();
+ }
+ };
+ }
+
+ ActiveMqBrokerServiceRule getActiveMqBrokerServiceRule() {
+ return activeMqBrokerServiceRule;
+ }
+
+ String getBrokerUrlStr() {
+ return brokerUrlStr;
+ }
+
+ JmsClientTestConfig getJmsClientTestConfig() {
+ return jmsClientTestConfig;
+ }
+
+ String getJmsInitialContextFactoryClassName() {
+ return jmsInitialContextFactoryClassName;
+ }
+
+ String getPassword() {
+ return password;
+ }
+
+ String getUserName() {
+ return userName;
+ }
+
+ void setJmsClientTestConfig(final JmsClientTestConfig jmsClientTestConfig) {
+ this.jmsClientTestConfig = jmsClientTestConfig;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractFileAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractFileAppender.java
new file mode 100644
index 0000000..7cad49c
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractFileAppender.java
@@ -0,0 +1,204 @@
+/*
+ * 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.core.appender;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Core;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.Builder;
+import org.apache.logging.log4j.core.config.Configuration;
+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.validation.constraints.Required;
+import org.apache.logging.log4j.core.net.Advertiser;
+import org.apache.logging.log4j.core.util.Booleans;
+import org.apache.logging.log4j.core.util.Integers;
+
+/**
+ * Abstract File Appender.
+ */
+public abstract class AbstractFileAppender<M extends OutputStreamManager> extends AbstractOutputStreamAppender<M> {
+
+ /**
+ * Builds FileAppender instances.
+ *
+ * @param <B>
+ * The type to build
+ */
+ public abstract static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B> {
+
+ @PluginBuilderAttribute
+ @Required
+ private String fileName;
+
+ @PluginBuilderAttribute
+ private boolean append = true;
+
+ @PluginBuilderAttribute
+ private boolean locking;
+
+ @PluginBuilderAttribute
+ private boolean advertise;
+
+ @PluginBuilderAttribute
+ private String advertiseUri;
+
+ @PluginBuilderAttribute
+ private boolean createOnDemand;
+
+ @PluginBuilderAttribute
+ private String filePermissions;
+
+ @PluginBuilderAttribute
+ private String fileOwner;
+
+ @PluginBuilderAttribute
+ private String fileGroup;
+
+ public String getAdvertiseUri() {
+ return advertiseUri;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public boolean isAdvertise() {
+ return advertise;
+ }
+
+ public boolean isAppend() {
+ return append;
+ }
+
+ public boolean isCreateOnDemand() {
+ return createOnDemand;
+ }
+
+ public boolean isLocking() {
+ return locking;
+ }
+
+ public String getFilePermissions() {
+ return filePermissions;
+ }
+
+ public String getFileOwner() {
+ return fileOwner;
+ }
+
+ public String getFileGroup() {
+ return fileGroup;
+ }
+
+ public B withAdvertise(final boolean advertise) {
+ this.advertise = advertise;
+ return asBuilder();
+ }
+
+ public B withAdvertiseUri(final String advertiseUri) {
+ this.advertiseUri = advertiseUri;
+ return asBuilder();
+ }
+
+ public B withAppend(final boolean append) {
+ this.append = append;
+ return asBuilder();
+ }
+
+ public B withFileName(final String fileName) {
+ this.fileName = fileName;
+ return asBuilder();
+ }
+
+ public B withCreateOnDemand(final boolean createOnDemand) {
+ this.createOnDemand = createOnDemand;
+ return asBuilder();
+ }
+
+ public B withLocking(final boolean locking) {
+ this.locking = locking;
+ return asBuilder();
+ }
+
+ public B withFilePermissions(final String filePermissions) {
+ this.filePermissions = filePermissions;
+ return asBuilder();
+ }
+
+ public B withFileOwner(final String fileOwner) {
+ this.fileOwner = fileOwner;
+ return asBuilder();
+ }
+
+ public B withFileGroup(final String fileGroup) {
+ this.fileGroup = fileGroup;
+ return asBuilder();
+ }
+
+ }
+
+ private final String fileName;
+
+ private final Advertiser advertiser;
+
+ private final Object advertisement;
+
+ private AbstractFileAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
+ final M manager, final String filename, final boolean ignoreExceptions,
+ final boolean immediateFlush, final Advertiser advertiser) {
+
+ super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
+ if (advertiser != null) {
+ final Map<String, String> configuration = new HashMap<>(layout.getContentFormat());
+ configuration.putAll(manager.getContentFormat());
+ configuration.put("contentType", layout.getContentType());
+ configuration.put("name", name);
+ advertisement = advertiser.advertise(configuration);
+ } else {
+ advertisement = null;
+ }
+ this.fileName = filename;
+ this.advertiser = advertiser;
+ }
+
+ /**
+ * Returns the file name this appender is associated with.
+ * @return The File name.
+ */
+ public String getFileName() {
+ return this.fileName;
+ }
+
+ @Override
+ public boolean stop(final long timeout, final TimeUnit timeUnit) {
+ setStopping();
+ super.stop(timeout, timeUnit, false);
+ if (advertiser != null) {
+ advertiser.unadvertise(advertisement);
+ }
+ setStopped();
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core/src/test/java/org/apache/logging/log4j/test/AvailablePortSystemPropertyRule.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/AvailablePortSystemPropertyRule.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/AvailablePortSystemPropertyRule.java
new file mode 100644
index 0000000..0098057
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/AvailablePortSystemPropertyRule.java
@@ -0,0 +1,81 @@
+/*
+ * 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.test;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * A JUnit TestRule to discover an available port and save it in a system property. Useful for setting up tests using
+ * Apache Active MQ.
+ */
+public class AvailablePortSystemPropertyRule implements TestRule {
+
+ public static AvailablePortSystemPropertyRule create(final String name) {
+ return new AvailablePortSystemPropertyRule(name);
+ }
+
+ protected final String name;
+ protected int port;
+
+ protected AvailablePortSystemPropertyRule(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ final String oldValue = System.getProperty(name);
+ try {
+ port = AvailablePortFinder.getNextAvailable();
+ System.setProperty(name, Integer.toString(port));
+ base.evaluate();
+ } finally {
+ // Restore if previously set
+ if (oldValue != null) {
+ System.setProperty(name, oldValue);
+ }
+ }
+ }
+ };
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("AvailablePortSystemPropertyRule [name=");
+ builder.append(name);
+ builder.append(", port=");
+ builder.append(port);
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c9ae6a85/log4j-core/src/test/java/org/apache/logging/log4j/test/RuleChainFactory.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/RuleChainFactory.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/RuleChainFactory.java
new file mode 100644
index 0000000..6f601df
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/RuleChainFactory.java
@@ -0,0 +1,44 @@
+/*
+ * 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.test;
+
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+
+/**
+ * Builds JUnit {@link RuleChain}s.
+ */
+public class RuleChainFactory {
+
+ /**
+ * Creates a {@link RuleChain} where the rules are evaluated in the order you pass in.
+ *
+ * @param testRules
+ * test rules to evaluate
+ * @return a new rule chain.
+ */
+ public static RuleChain create(final TestRule... testRules) {
+ RuleChain ruleChain = RuleChain.outerRule(testRules[0]);
+ for (int idx = 1; idx < testRules.length; idx++) {
+ if (ruleChain != null) {
+ ruleChain = ruleChain.around(testRules[idx]);
+ }
+ }
+ return ruleChain;
+ }
+}