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 2016/09/07 17:37:53 UTC
[4/7] logging-log4j2 git commit: Properly track resources during
shutdown.
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/78fe32c0/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java
index 1fc08a0..db6e9ae 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java
@@ -1,479 +1,479 @@
-/*
- * 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.rolling;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.Serializable;
-import java.nio.ByteBuffer;
-import java.util.concurrent.Future;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.appender.ConfigurationFactoryData;
-import org.apache.logging.log4j.core.appender.FileManager;
-import org.apache.logging.log4j.core.appender.ManagerFactory;
-import org.apache.logging.log4j.core.appender.rolling.action.AbstractAction;
-import org.apache.logging.log4j.core.appender.rolling.action.Action;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.util.Constants;
-
-/**
- * The Rolling File Manager.
- */
-public class RollingFileManager extends FileManager {
-
- private static RollingFileManagerFactory factory = new RollingFileManagerFactory();
-
- protected long size;
- private long initialTime;
- private final PatternProcessor patternProcessor;
- private final Semaphore semaphore = new Semaphore(1);
- private volatile TriggeringPolicy triggeringPolicy;
- private volatile RolloverStrategy rolloverStrategy;
- private volatile boolean renameEmptyFiles = false;
-
- private static final AtomicReferenceFieldUpdater<RollingFileManager, TriggeringPolicy> triggeringPolicyUpdater =
- AtomicReferenceFieldUpdater.newUpdater(RollingFileManager.class, TriggeringPolicy.class, "triggeringPolicy");
-
- private static final AtomicReferenceFieldUpdater<RollingFileManager, RolloverStrategy> rolloverStrategyUpdater =
- AtomicReferenceFieldUpdater.newUpdater(RollingFileManager.class, RolloverStrategy.class, "rolloverStrategy");
-
- @Deprecated
- protected RollingFileManager(final String fileName, final String pattern, final OutputStream os,
- final boolean append, final long size, final long time, final TriggeringPolicy triggeringPolicy,
- final RolloverStrategy rolloverStrategy, final String advertiseURI,
- final Layout<? extends Serializable> layout, final int bufferSize, final boolean writeHeader) {
- this(fileName, pattern, os, append, size, time, triggeringPolicy, rolloverStrategy, advertiseURI, layout,
- writeHeader, ByteBuffer.wrap(new byte[Constants.ENCODER_BYTE_BUFFER_SIZE]));
- }
-
- @Deprecated
- protected RollingFileManager(final String fileName, final String pattern, final OutputStream os,
- final boolean append, final long size, final long time, final TriggeringPolicy triggeringPolicy,
- final RolloverStrategy rolloverStrategy, final String advertiseURI,
- final Layout<? extends Serializable> layout, final boolean writeHeader, final ByteBuffer buffer) {
- super(fileName, os, append, false, advertiseURI, layout, writeHeader, buffer);
- this.size = size;
- this.initialTime = time;
- this.triggeringPolicy = triggeringPolicy;
- this.rolloverStrategy = rolloverStrategy;
- this.patternProcessor = new PatternProcessor(pattern);
- this.patternProcessor.setPrevFileTime(time);
- }
-
- /**
- * @since 2.7
- */
- protected RollingFileManager(final LoggerContext loggerContext, final String fileName, final String pattern, final OutputStream os,
- final boolean append, final boolean createOnDemand, final long size, final long time,
- final TriggeringPolicy triggeringPolicy, final RolloverStrategy rolloverStrategy,
- final String advertiseURI, final Layout<? extends Serializable> layout, final boolean writeHeader, final ByteBuffer buffer) {
- super(loggerContext, fileName, os, append, false, createOnDemand, advertiseURI, layout, writeHeader, buffer);
- this.size = size;
- this.initialTime = time;
- this.triggeringPolicy = triggeringPolicy;
- this.rolloverStrategy = rolloverStrategy;
- this.patternProcessor = new PatternProcessor(pattern);
- this.patternProcessor.setPrevFileTime(time);
- }
-
- public void initialize() {
- triggeringPolicy.initialize(this);
- }
-
- /**
- * Returns a RollingFileManager.
- * @param fileName The file name.
- * @param pattern The pattern for rolling file.
- * @param append true if the file should be appended to.
- * @param bufferedIO true if data should be buffered.
- * @param policy The TriggeringPolicy.
- * @param strategy The RolloverStrategy.
- * @param advertiseURI the URI to use when advertising the file
- * @param layout The Layout.
- * @param bufferSize buffer size to use if bufferedIO is true
- * @param immediateFlush flush on every write or not
- * @param createOnDemand true if you want to lazy-create the file (a.k.a. on-demand.)
- * @param configuration The configuration.
- * @return A RollingFileManager.
- */
- public static RollingFileManager getFileManager(final String fileName, final String pattern, final boolean append,
- final boolean bufferedIO, final TriggeringPolicy policy, final RolloverStrategy strategy,
- final String advertiseURI, final Layout<? extends Serializable> layout, final int bufferSize,
- final boolean immediateFlush, final boolean createOnDemand, final Configuration configuration) {
-
- return (RollingFileManager) getManager(fileName, new FactoryData(pattern, append,
- bufferedIO, policy, strategy, advertiseURI, layout, bufferSize, immediateFlush, createOnDemand, configuration), factory);
- }
-
- // override to make visible for unit tests
- @Override
- protected synchronized void write(final byte[] bytes, final int offset, final int length,
- final boolean immediateFlush) {
- super.write(bytes, offset, length, immediateFlush);
- }
-
- @Override
- protected synchronized void writeToDestination(final byte[] bytes, final int offset, final int length) {
- size += length;
- super.writeToDestination(bytes, offset, length);
- }
-
- public boolean isRenameEmptyFiles() {
- return renameEmptyFiles;
- }
-
- public void setRenameEmptyFiles(final boolean renameEmptyFiles) {
- this.renameEmptyFiles = renameEmptyFiles;
- }
-
- /**
- * Returns the current size of the file.
- * @return The size of the file in bytes.
- */
- public long getFileSize() {
- return size + byteBuffer.position();
- }
-
- /**
- * Returns the time the file was created.
- * @return The time the file was created.
- */
- public long getFileTime() {
- return initialTime;
- }
-
- /**
- * Determines if a rollover should occur.
- * @param event The LogEvent.
- */
- public synchronized void checkRollover(final LogEvent event) {
- if (triggeringPolicy.isTriggeringEvent(event)) {
- rollover();
- }
- }
-
- @Override
- public void releaseSub(final long timeout, final TimeUnit timeUnit) {
- triggeringPolicy.stop(timeout, timeUnit);
- super.releaseSub(timeout, timeUnit);
- }
-
- public synchronized void rollover() {
- if (rollover(rolloverStrategy)) {
- try {
- size = 0;
- initialTime = System.currentTimeMillis();
- createFileAfterRollover();
- } catch (final IOException e) {
- logError("Failed to create file after rollover", e);
- }
- }
- }
-
- protected void createFileAfterRollover() throws IOException {
- setOutputStream(new FileOutputStream(getFileName(), isAppend()));
- }
-
- /**
- * Returns the pattern processor.
- * @return The PatternProcessor.
- */
- public PatternProcessor getPatternProcessor() {
- return patternProcessor;
- }
-
- public void setTriggeringPolicy(final TriggeringPolicy triggeringPolicy) {
- triggeringPolicy.initialize(this);
- triggeringPolicyUpdater.compareAndSet(this, this.triggeringPolicy, triggeringPolicy);
- }
-
- public void setRolloverStrategy(final RolloverStrategy rolloverStrategy) {
- rolloverStrategyUpdater.compareAndSet(this, this.rolloverStrategy, rolloverStrategy);
- }
-
- /**
- * Returns the triggering policy.
- * @param <T> TriggeringPolicy type
- * @return The TriggeringPolicy
- */
- @SuppressWarnings("unchecked")
- public <T extends TriggeringPolicy> T getTriggeringPolicy() {
- // TODO We could parameterize this class with a TriggeringPolicy instead of type casting here.
- return (T) this.triggeringPolicy;
- }
-
- /**
- * Returns the rollover strategy.
- * @return The RolloverStrategy
- */
- public RolloverStrategy getRolloverStrategy() {
- return this.rolloverStrategy;
- }
-
- private boolean rollover(final RolloverStrategy strategy) {
-
- try {
- // Block until the asynchronous operation is completed.
- semaphore.acquire();
- } catch (final InterruptedException e) {
- logError("Thread interrupted while attempting to check rollover", e);
- return false;
- }
-
- boolean success = false;
- Future<?> future = null;
-
- try {
- final RolloverDescription descriptor = strategy.rollover(this);
- if (descriptor != null) {
- writeFooter();
- closeOutputStream();
- if (descriptor.getSynchronous() != null) {
- LOGGER.debug("RollingFileManager executing synchronous {}", descriptor.getSynchronous());
- try {
- success = descriptor.getSynchronous().execute();
- } catch (final Exception ex) {
- logError("Caught error in synchronous task", ex);
- }
- }
-
- if (success && descriptor.getAsynchronous() != null) {
- LOGGER.debug("RollingFileManager executing async {}", descriptor.getAsynchronous());
- future = LoggerContext.getContext(false).submit(new AsyncAction(descriptor.getAsynchronous(), this));
- }
- return true;
- }
- return false;
- } finally {
- if (future == null || future.isDone() || future.isCancelled()) {
- semaphore.release();
- }
- }
-
- }
-
- /**
- * Performs actions asynchronously.
- */
- private static class AsyncAction extends AbstractAction {
-
- private final Action action;
- private final RollingFileManager manager;
-
- /**
- * Constructor.
- * @param act The action to perform.
- * @param manager The manager.
- */
- public AsyncAction(final Action act, final RollingFileManager manager) {
- this.action = act;
- this.manager = manager;
- }
-
- /**
- * Executes an action.
- *
- * @return true if action was successful. A return value of false will cause
- * the rollover to be aborted if possible.
- * @throws java.io.IOException if IO error, a thrown exception will cause the rollover
- * to be aborted if possible.
- */
- @Override
- public boolean execute() throws IOException {
- try {
- return action.execute();
- } finally {
- manager.semaphore.release();
- }
- }
-
- /**
- * Cancels the action if not already initialized or waits till completion.
- */
- @Override
- public void close() {
- action.close();
- }
-
- /**
- * Determines if action has been completed.
- *
- * @return true if action is complete.
- */
- @Override
- public boolean isComplete() {
- return action.isComplete();
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append(super.toString());
- builder.append("[action=");
- builder.append(action);
- builder.append(", manager=");
- builder.append(manager);
- builder.append(", isComplete()=");
- builder.append(isComplete());
- builder.append(", isInterrupted()=");
- builder.append(isInterrupted());
- builder.append("]");
- return builder.toString();
- }
- }
-
- /**
- * Factory data.
- */
- private static class FactoryData extends ConfigurationFactoryData {
- private final String pattern;
- private final boolean append;
- private final boolean bufferedIO;
- private final int bufferSize;
- private final boolean immediateFlush;
- private final boolean createOnDemand;
- private final TriggeringPolicy policy;
- private final RolloverStrategy strategy;
- private final String advertiseURI;
- private final Layout<? extends Serializable> layout;
-
- /**
- * Creates the data for the factory.
- * @param pattern The pattern.
- * @param append The append flag.
- * @param bufferedIO The bufferedIO flag.
- * @param advertiseURI
- * @param layout The Layout.
- * @param bufferSize the buffer size
- * @param immediateFlush flush on every write or not
- * @param createOnDemand true if you want to lazy-create the file (a.k.a. on-demand.)
- * @param configuration The configuration
- */
- public FactoryData(final String pattern, final boolean append, final boolean bufferedIO,
- final TriggeringPolicy policy, final RolloverStrategy strategy, final String advertiseURI,
- final Layout<? extends Serializable> layout, final int bufferSize, final boolean immediateFlush,
- final boolean createOnDemand, final Configuration configuration) {
- super(configuration);
- this.pattern = pattern;
- this.append = append;
- this.bufferedIO = bufferedIO;
- this.bufferSize = bufferSize;
- this.policy = policy;
- this.strategy = strategy;
- this.advertiseURI = advertiseURI;
- this.layout = layout;
- this.immediateFlush = immediateFlush;
- this.createOnDemand = createOnDemand;
- }
-
- public TriggeringPolicy getTriggeringPolicy()
- {
- return this.policy;
- }
-
- public RolloverStrategy getRolloverStrategy()
- {
- return this.strategy;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append(super.toString());
- builder.append("[pattern=");
- builder.append(pattern);
- builder.append(", append=");
- builder.append(append);
- builder.append(", bufferedIO=");
- builder.append(bufferedIO);
- builder.append(", bufferSize=");
- builder.append(bufferSize);
- builder.append(", policy=");
- builder.append(policy);
- builder.append(", strategy=");
- builder.append(strategy);
- builder.append(", advertiseURI=");
- builder.append(advertiseURI);
- builder.append(", layout=");
- builder.append(layout);
- builder.append("]");
- return builder.toString();
- }
- }
-
- @Override
- public void updateData(final Object data)
- {
- final FactoryData factoryData = (FactoryData) data;
- setRolloverStrategy(factoryData.getRolloverStrategy());
- setTriggeringPolicy(factoryData.getTriggeringPolicy());
- }
-
- /**
- * Factory to create a RollingFileManager.
- */
- private static class RollingFileManagerFactory implements ManagerFactory<RollingFileManager, FactoryData> {
-
- /**
- * Creates a RollingFileManager.
- * @param name The name of the entity to manage.
- * @param data The data required to create the entity.
- * @return a RollingFileManager.
- */
- @Override
- public RollingFileManager createManager(final String name, final FactoryData data) {
- final File file = new File(name);
- final File parent = file.getParentFile();
- if (null != parent && !parent.exists()) {
- parent.mkdirs();
- }
- // LOG4J2-1140: check writeHeader before creating the file
- final boolean writeHeader = !data.append || !file.exists();
- try {
- final boolean created = data.createOnDemand ? false : file.createNewFile();
- LOGGER.trace("New file '{}' created = {}", name, created);
- } catch (final IOException ioe) {
- LOGGER.error("Unable to create file " + name, ioe);
- return null;
- }
- final long size = data.append ? file.length() : 0;
-
- try {
- final int actualSize = data.bufferedIO ? data.bufferSize : Constants.ENCODER_BYTE_BUFFER_SIZE;
- final ByteBuffer buffer = ByteBuffer.wrap(new byte[actualSize]);
- final OutputStream os = data.createOnDemand ? null : new FileOutputStream(name, data.append);
- final long time = data.createOnDemand? System.currentTimeMillis() : file.lastModified(); // LOG4J2-531 create file first so time has valid value
-
- return new RollingFileManager(data.getLoggerContext(), name, data.pattern, os,
- data.append, data.createOnDemand, size, time, data.policy, data.strategy, data.advertiseURI,
- data.layout, writeHeader, buffer);
- } catch (final IOException ex) {
- LOGGER.error("RollingFileManager (" + name + ") " + ex, ex);
- }
- return null;
- }
- }
-
-}
+/*
+ * 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.rolling;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.util.concurrent.Future;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.ConfigurationFactoryData;
+import org.apache.logging.log4j.core.appender.FileManager;
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+import org.apache.logging.log4j.core.appender.rolling.action.AbstractAction;
+import org.apache.logging.log4j.core.appender.rolling.action.Action;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.util.Constants;
+
+/**
+ * The Rolling File Manager.
+ */
+public class RollingFileManager extends FileManager {
+
+ private static RollingFileManagerFactory factory = new RollingFileManagerFactory();
+
+ protected long size;
+ private long initialTime;
+ private final PatternProcessor patternProcessor;
+ private final Semaphore semaphore = new Semaphore(1);
+ private volatile TriggeringPolicy triggeringPolicy;
+ private volatile RolloverStrategy rolloverStrategy;
+ private volatile boolean renameEmptyFiles = false;
+
+ private static final AtomicReferenceFieldUpdater<RollingFileManager, TriggeringPolicy> triggeringPolicyUpdater =
+ AtomicReferenceFieldUpdater.newUpdater(RollingFileManager.class, TriggeringPolicy.class, "triggeringPolicy");
+
+ private static final AtomicReferenceFieldUpdater<RollingFileManager, RolloverStrategy> rolloverStrategyUpdater =
+ AtomicReferenceFieldUpdater.newUpdater(RollingFileManager.class, RolloverStrategy.class, "rolloverStrategy");
+
+ @Deprecated
+ protected RollingFileManager(final String fileName, final String pattern, final OutputStream os,
+ final boolean append, final long size, final long time, final TriggeringPolicy triggeringPolicy,
+ final RolloverStrategy rolloverStrategy, final String advertiseURI,
+ final Layout<? extends Serializable> layout, final int bufferSize, final boolean writeHeader) {
+ this(fileName, pattern, os, append, size, time, triggeringPolicy, rolloverStrategy, advertiseURI, layout,
+ writeHeader, ByteBuffer.wrap(new byte[Constants.ENCODER_BYTE_BUFFER_SIZE]));
+ }
+
+ @Deprecated
+ protected RollingFileManager(final String fileName, final String pattern, final OutputStream os,
+ final boolean append, final long size, final long time, final TriggeringPolicy triggeringPolicy,
+ final RolloverStrategy rolloverStrategy, final String advertiseURI,
+ final Layout<? extends Serializable> layout, final boolean writeHeader, final ByteBuffer buffer) {
+ super(fileName, os, append, false, advertiseURI, layout, writeHeader, buffer);
+ this.size = size;
+ this.initialTime = time;
+ this.triggeringPolicy = triggeringPolicy;
+ this.rolloverStrategy = rolloverStrategy;
+ this.patternProcessor = new PatternProcessor(pattern);
+ this.patternProcessor.setPrevFileTime(time);
+ }
+
+ /**
+ * @since 2.7
+ */
+ protected RollingFileManager(final LoggerContext loggerContext, final String fileName, final String pattern, final OutputStream os,
+ final boolean append, final boolean createOnDemand, final long size, final long time,
+ final TriggeringPolicy triggeringPolicy, final RolloverStrategy rolloverStrategy,
+ final String advertiseURI, final Layout<? extends Serializable> layout, final boolean writeHeader, final ByteBuffer buffer) {
+ super(loggerContext, fileName, os, append, false, createOnDemand, advertiseURI, layout, writeHeader, buffer);
+ this.size = size;
+ this.initialTime = time;
+ this.triggeringPolicy = triggeringPolicy;
+ this.rolloverStrategy = rolloverStrategy;
+ this.patternProcessor = new PatternProcessor(pattern);
+ this.patternProcessor.setPrevFileTime(time);
+ }
+
+ public void initialize() {
+ triggeringPolicy.initialize(this);
+ }
+
+ /**
+ * Returns a RollingFileManager.
+ * @param fileName The file name.
+ * @param pattern The pattern for rolling file.
+ * @param append true if the file should be appended to.
+ * @param bufferedIO true if data should be buffered.
+ * @param policy The TriggeringPolicy.
+ * @param strategy The RolloverStrategy.
+ * @param advertiseURI the URI to use when advertising the file
+ * @param layout The Layout.
+ * @param bufferSize buffer size to use if bufferedIO is true
+ * @param immediateFlush flush on every write or not
+ * @param createOnDemand true if you want to lazy-create the file (a.k.a. on-demand.)
+ * @param configuration The configuration.
+ * @return A RollingFileManager.
+ */
+ public static RollingFileManager getFileManager(final String fileName, final String pattern, final boolean append,
+ final boolean bufferedIO, final TriggeringPolicy policy, final RolloverStrategy strategy,
+ final String advertiseURI, final Layout<? extends Serializable> layout, final int bufferSize,
+ final boolean immediateFlush, final boolean createOnDemand, final Configuration configuration) {
+
+ return (RollingFileManager) getManager(fileName, new FactoryData(pattern, append,
+ bufferedIO, policy, strategy, advertiseURI, layout, bufferSize, immediateFlush, createOnDemand, configuration), factory);
+ }
+
+ // override to make visible for unit tests
+ @Override
+ protected synchronized void write(final byte[] bytes, final int offset, final int length,
+ final boolean immediateFlush) {
+ super.write(bytes, offset, length, immediateFlush);
+ }
+
+ @Override
+ protected synchronized void writeToDestination(final byte[] bytes, final int offset, final int length) {
+ size += length;
+ super.writeToDestination(bytes, offset, length);
+ }
+
+ public boolean isRenameEmptyFiles() {
+ return renameEmptyFiles;
+ }
+
+ public void setRenameEmptyFiles(final boolean renameEmptyFiles) {
+ this.renameEmptyFiles = renameEmptyFiles;
+ }
+
+ /**
+ * Returns the current size of the file.
+ * @return The size of the file in bytes.
+ */
+ public long getFileSize() {
+ return size + byteBuffer.position();
+ }
+
+ /**
+ * Returns the time the file was created.
+ * @return The time the file was created.
+ */
+ public long getFileTime() {
+ return initialTime;
+ }
+
+ /**
+ * Determines if a rollover should occur.
+ * @param event The LogEvent.
+ */
+ public synchronized void checkRollover(final LogEvent event) {
+ if (triggeringPolicy.isTriggeringEvent(event)) {
+ rollover();
+ }
+ }
+
+ @Override
+ public boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
+ boolean stopped = triggeringPolicy.stop(timeout, timeUnit);
+ return stopped && super.releaseSub(timeout, timeUnit);
+ }
+
+ public synchronized void rollover() {
+ if (rollover(rolloverStrategy)) {
+ try {
+ size = 0;
+ initialTime = System.currentTimeMillis();
+ createFileAfterRollover();
+ } catch (final IOException e) {
+ logError("Failed to create file after rollover", e);
+ }
+ }
+ }
+
+ protected void createFileAfterRollover() throws IOException {
+ setOutputStream(new FileOutputStream(getFileName(), isAppend()));
+ }
+
+ /**
+ * Returns the pattern processor.
+ * @return The PatternProcessor.
+ */
+ public PatternProcessor getPatternProcessor() {
+ return patternProcessor;
+ }
+
+ public void setTriggeringPolicy(final TriggeringPolicy triggeringPolicy) {
+ triggeringPolicy.initialize(this);
+ triggeringPolicyUpdater.compareAndSet(this, this.triggeringPolicy, triggeringPolicy);
+ }
+
+ public void setRolloverStrategy(final RolloverStrategy rolloverStrategy) {
+ rolloverStrategyUpdater.compareAndSet(this, this.rolloverStrategy, rolloverStrategy);
+ }
+
+ /**
+ * Returns the triggering policy.
+ * @param <T> TriggeringPolicy type
+ * @return The TriggeringPolicy
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends TriggeringPolicy> T getTriggeringPolicy() {
+ // TODO We could parameterize this class with a TriggeringPolicy instead of type casting here.
+ return (T) this.triggeringPolicy;
+ }
+
+ /**
+ * Returns the rollover strategy.
+ * @return The RolloverStrategy
+ */
+ public RolloverStrategy getRolloverStrategy() {
+ return this.rolloverStrategy;
+ }
+
+ private boolean rollover(final RolloverStrategy strategy) {
+
+ try {
+ // Block until the asynchronous operation is completed.
+ semaphore.acquire();
+ } catch (final InterruptedException e) {
+ logError("Thread interrupted while attempting to check rollover", e);
+ return false;
+ }
+
+ boolean success = false;
+ Future<?> future = null;
+
+ try {
+ final RolloverDescription descriptor = strategy.rollover(this);
+ if (descriptor != null) {
+ writeFooter();
+ closeOutputStream();
+ if (descriptor.getSynchronous() != null) {
+ LOGGER.debug("RollingFileManager executing synchronous {}", descriptor.getSynchronous());
+ try {
+ success = descriptor.getSynchronous().execute();
+ } catch (final Exception ex) {
+ logError("Caught error in synchronous task", ex);
+ }
+ }
+
+ if (success && descriptor.getAsynchronous() != null) {
+ LOGGER.debug("RollingFileManager executing async {}", descriptor.getAsynchronous());
+ future = LoggerContext.getContext(false).submit(new AsyncAction(descriptor.getAsynchronous(), this));
+ }
+ return true;
+ }
+ return false;
+ } finally {
+ if (future == null || future.isDone() || future.isCancelled()) {
+ semaphore.release();
+ }
+ }
+
+ }
+
+ /**
+ * Performs actions asynchronously.
+ */
+ private static class AsyncAction extends AbstractAction {
+
+ private final Action action;
+ private final RollingFileManager manager;
+
+ /**
+ * Constructor.
+ * @param act The action to perform.
+ * @param manager The manager.
+ */
+ public AsyncAction(final Action act, final RollingFileManager manager) {
+ this.action = act;
+ this.manager = manager;
+ }
+
+ /**
+ * Executes an action.
+ *
+ * @return true if action was successful. A return value of false will cause
+ * the rollover to be aborted if possible.
+ * @throws java.io.IOException if IO error, a thrown exception will cause the rollover
+ * to be aborted if possible.
+ */
+ @Override
+ public boolean execute() throws IOException {
+ try {
+ return action.execute();
+ } finally {
+ manager.semaphore.release();
+ }
+ }
+
+ /**
+ * Cancels the action if not already initialized or waits till completion.
+ */
+ @Override
+ public void close() {
+ action.close();
+ }
+
+ /**
+ * Determines if action has been completed.
+ *
+ * @return true if action is complete.
+ */
+ @Override
+ public boolean isComplete() {
+ return action.isComplete();
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(super.toString());
+ builder.append("[action=");
+ builder.append(action);
+ builder.append(", manager=");
+ builder.append(manager);
+ builder.append(", isComplete()=");
+ builder.append(isComplete());
+ builder.append(", isInterrupted()=");
+ builder.append(isInterrupted());
+ builder.append("]");
+ return builder.toString();
+ }
+ }
+
+ /**
+ * Factory data.
+ */
+ private static class FactoryData extends ConfigurationFactoryData {
+ private final String pattern;
+ private final boolean append;
+ private final boolean bufferedIO;
+ private final int bufferSize;
+ private final boolean immediateFlush;
+ private final boolean createOnDemand;
+ private final TriggeringPolicy policy;
+ private final RolloverStrategy strategy;
+ private final String advertiseURI;
+ private final Layout<? extends Serializable> layout;
+
+ /**
+ * Creates the data for the factory.
+ * @param pattern The pattern.
+ * @param append The append flag.
+ * @param bufferedIO The bufferedIO flag.
+ * @param advertiseURI
+ * @param layout The Layout.
+ * @param bufferSize the buffer size
+ * @param immediateFlush flush on every write or not
+ * @param createOnDemand true if you want to lazy-create the file (a.k.a. on-demand.)
+ * @param configuration The configuration
+ */
+ public FactoryData(final String pattern, final boolean append, final boolean bufferedIO,
+ final TriggeringPolicy policy, final RolloverStrategy strategy, final String advertiseURI,
+ final Layout<? extends Serializable> layout, final int bufferSize, final boolean immediateFlush,
+ final boolean createOnDemand, final Configuration configuration) {
+ super(configuration);
+ this.pattern = pattern;
+ this.append = append;
+ this.bufferedIO = bufferedIO;
+ this.bufferSize = bufferSize;
+ this.policy = policy;
+ this.strategy = strategy;
+ this.advertiseURI = advertiseURI;
+ this.layout = layout;
+ this.immediateFlush = immediateFlush;
+ this.createOnDemand = createOnDemand;
+ }
+
+ public TriggeringPolicy getTriggeringPolicy()
+ {
+ return this.policy;
+ }
+
+ public RolloverStrategy getRolloverStrategy()
+ {
+ return this.strategy;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(super.toString());
+ builder.append("[pattern=");
+ builder.append(pattern);
+ builder.append(", append=");
+ builder.append(append);
+ builder.append(", bufferedIO=");
+ builder.append(bufferedIO);
+ builder.append(", bufferSize=");
+ builder.append(bufferSize);
+ builder.append(", policy=");
+ builder.append(policy);
+ builder.append(", strategy=");
+ builder.append(strategy);
+ builder.append(", advertiseURI=");
+ builder.append(advertiseURI);
+ builder.append(", layout=");
+ builder.append(layout);
+ builder.append("]");
+ return builder.toString();
+ }
+ }
+
+ @Override
+ public void updateData(final Object data)
+ {
+ final FactoryData factoryData = (FactoryData) data;
+ setRolloverStrategy(factoryData.getRolloverStrategy());
+ setTriggeringPolicy(factoryData.getTriggeringPolicy());
+ }
+
+ /**
+ * Factory to create a RollingFileManager.
+ */
+ private static class RollingFileManagerFactory implements ManagerFactory<RollingFileManager, FactoryData> {
+
+ /**
+ * Creates a RollingFileManager.
+ * @param name The name of the entity to manage.
+ * @param data The data required to create the entity.
+ * @return a RollingFileManager.
+ */
+ @Override
+ public RollingFileManager createManager(final String name, final FactoryData data) {
+ final File file = new File(name);
+ final File parent = file.getParentFile();
+ if (null != parent && !parent.exists()) {
+ parent.mkdirs();
+ }
+ // LOG4J2-1140: check writeHeader before creating the file
+ final boolean writeHeader = !data.append || !file.exists();
+ try {
+ final boolean created = data.createOnDemand ? false : file.createNewFile();
+ LOGGER.trace("New file '{}' created = {}", name, created);
+ } catch (final IOException ioe) {
+ LOGGER.error("Unable to create file " + name, ioe);
+ return null;
+ }
+ final long size = data.append ? file.length() : 0;
+
+ try {
+ final int actualSize = data.bufferedIO ? data.bufferSize : Constants.ENCODER_BYTE_BUFFER_SIZE;
+ final ByteBuffer buffer = ByteBuffer.wrap(new byte[actualSize]);
+ final OutputStream os = data.createOnDemand ? null : new FileOutputStream(name, data.append);
+ final long time = data.createOnDemand? System.currentTimeMillis() : file.lastModified(); // LOG4J2-531 create file first so time has valid value
+
+ return new RollingFileManager(data.getLoggerContext(), name, data.pattern, os,
+ data.append, data.createOnDemand, size, time, data.policy, data.strategy, data.advertiseURI,
+ data.layout, writeHeader, buffer);
+ } catch (final IOException ex) {
+ LOGGER.error("RollingFileManager (" + name + ") " + ex, ex);
+ }
+ return null;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/78fe32c0/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java
index a52921d..abeb5ee 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java
@@ -1,144 +1,144 @@
-/*
- * 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.net;
-
-import java.util.Properties;
-import java.util.concurrent.TimeUnit;
-
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-
-import org.apache.logging.log4j.core.appender.AbstractManager;
-import org.apache.logging.log4j.core.appender.ManagerFactory;
-import org.apache.logging.log4j.core.util.JndiCloser;
-
-/**
- * JNDI {@link javax.naming.Context} manager.
- *
- * @since 2.1
- */
-public class JndiManager extends AbstractManager {
-
- private static final JndiManagerFactory FACTORY = new JndiManagerFactory();
-
- private final Context context;
-
- private JndiManager(final String name, final Context context) {
- super(null, name);
- this.context = context;
- }
-
- /**
- * Gets the default JndiManager using the default {@link javax.naming.InitialContext}.
- *
- * @return the default JndiManager
- */
- public static JndiManager getDefaultManager() {
- return getManager(JndiManager.class.getName(), FACTORY, null);
- }
-
- /**
- * Gets a named JndiManager using the default {@link javax.naming.InitialContext}.
- * @param name the name of the JndiManager instance to create or use if available
- * @return a default JndiManager
- */
- public static JndiManager getDefaultManager(final String name) {
- return getManager(name, FACTORY, null);
- }
-
- /**
- * 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(final long timeout, final TimeUnit timeUnit) {
- JndiCloser.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(final String name, final Properties data) {
- try {
- return new JndiManager(name, new InitialContext(data));
- } catch (final NamingException e) {
- LOGGER.error("Error creating JNDI InitialContext.", e);
- return null;
- }
- }
- }
-}
+/*
+ * 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.net;
+
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.apache.logging.log4j.core.appender.AbstractManager;
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+import org.apache.logging.log4j.core.util.JndiCloser;
+
+/**
+ * JNDI {@link javax.naming.Context} manager.
+ *
+ * @since 2.1
+ */
+public class JndiManager extends AbstractManager {
+
+ private static final JndiManagerFactory FACTORY = new JndiManagerFactory();
+
+ private final Context context;
+
+ private JndiManager(final String name, final Context context) {
+ super(null, name);
+ this.context = context;
+ }
+
+ /**
+ * Gets the default JndiManager using the default {@link javax.naming.InitialContext}.
+ *
+ * @return the default JndiManager
+ */
+ public static JndiManager getDefaultManager() {
+ return getManager(JndiManager.class.getName(), FACTORY, null);
+ }
+
+ /**
+ * Gets a named JndiManager using the default {@link javax.naming.InitialContext}.
+ * @param name the name of the JndiManager instance to create or use if available
+ * @return a default JndiManager
+ */
+ public static JndiManager getDefaultManager(final String name) {
+ return getManager(name, FACTORY, null);
+ }
+
+ /**
+ * 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 boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
+ return JndiCloser.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(final String name, final 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/78fe32c0/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JmsServer.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JmsServer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JmsServer.java
index 15e0a3f..730e778 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JmsServer.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JmsServer.java
@@ -1,147 +1,148 @@
-/*
- * 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.net.server;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.charset.Charset;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-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.LoggingException;
-import org.apache.logging.log4j.core.AbstractLifeCycle;
-import org.apache.logging.log4j.core.LifeCycle;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.LogEventListener;
-import org.apache.logging.log4j.core.appender.mom.JmsManager;
-import org.apache.logging.log4j.core.net.JndiManager;
-
-/**
- * LogEventListener server that receives LogEvents over a JMS {@link javax.jms.Destination}.
- *
- * @since 2.1
- */
-public class JmsServer extends LogEventListener implements MessageListener, LifeCycle {
-
- private final AtomicReference<State> state = new AtomicReference<>(State.INITIALIZED);
- private final JmsManager jmsManager;
- private MessageConsumer messageConsumer;
-
- public JmsServer(final String connectionFactoryBindingName,
- final String destinationBindingName,
- final String username,
- final String password) {
- final String managerName = JmsServer.class.getName() + '@' + JmsServer.class.hashCode();
- final JndiManager jndiManager = JndiManager.getDefaultManager(managerName);
- jmsManager = JmsManager.getJmsManager(managerName, jndiManager, connectionFactoryBindingName,
- destinationBindingName, username, password);
- }
-
- @Override
- public State getState() {
- return state.get();
- }
-
- @Override
- public void onMessage(final Message message) {
- try {
- if (message instanceof ObjectMessage) {
- final Object body = ((ObjectMessage) message).getObject();
- if (body instanceof LogEvent) {
- log((LogEvent) body);
- } else {
- LOGGER.warn("Expected ObjectMessage to contain LogEvent. Got type {} instead.", body.getClass());
- }
- } else {
- LOGGER.warn("Received message of type {} and JMSType {} which cannot be handled.", message.getClass(),
- message.getJMSType());
- }
- } catch (final JMSException e) {
- LOGGER.catching(e);
- }
- }
-
- @Override
- public void initialize() {
- }
-
- @Override
- public void start() {
- if (state.compareAndSet(State.INITIALIZED, State.STARTING)) {
- try {
- messageConsumer = jmsManager.createMessageConsumer();
- messageConsumer.setMessageListener(this);
- } catch (final JMSException e) {
- throw new LoggingException(e);
- }
- }
- }
-
- @Override
- public void stop() {
- stop(AbstractLifeCycle.DEFAULT_STOP_TIMEOUT, AbstractLifeCycle.DEFAULT_STOP_TIMEUNIT);
- }
-
- @Override
- public boolean stop(final long timeout, final TimeUnit timeUnit) {
- try {
- messageConsumer.close();
- } catch (final JMSException e) {
- LOGGER.debug("Exception closing {}", messageConsumer, e);
- }
- jmsManager.stop(timeout, timeUnit);
- return true;
- }
-
- @Override
- public boolean isStarted() {
- return state.get() == State.STARTED;
- }
-
- @Override
- public boolean isStopped() {
- return state.get() == State.STOPPED;
- }
-
- /**
- * Starts and runs this server until the user types "exit" into standard input.
- *
- * @throws IOException
- * @since 2.6
- */
- public void run() throws IOException {
- this.start();
- System.out.println("Type \"exit\" to quit.");
- final BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in, Charset.defaultCharset()));
- 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.");
- this.stop();
- return;
- }
- }
- }
-
-}
+/*
+ * 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.net.server;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+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.LoggingException;
+import org.apache.logging.log4j.core.AbstractLifeCycle;
+import org.apache.logging.log4j.core.LifeCycle;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LogEventListener;
+import org.apache.logging.log4j.core.appender.mom.JmsManager;
+import org.apache.logging.log4j.core.net.JndiManager;
+
+/**
+ * LogEventListener server that receives LogEvents over a JMS {@link javax.jms.Destination}.
+ *
+ * @since 2.1
+ */
+public class JmsServer extends LogEventListener implements MessageListener, LifeCycle {
+
+ private final AtomicReference<State> state = new AtomicReference<>(State.INITIALIZED);
+ private final JmsManager jmsManager;
+ private MessageConsumer messageConsumer;
+
+ public JmsServer(final String connectionFactoryBindingName,
+ final String destinationBindingName,
+ final String username,
+ final String password) {
+ final String managerName = JmsServer.class.getName() + '@' + JmsServer.class.hashCode();
+ final JndiManager jndiManager = JndiManager.getDefaultManager(managerName);
+ jmsManager = JmsManager.getJmsManager(managerName, jndiManager, connectionFactoryBindingName,
+ destinationBindingName, username, password);
+ }
+
+ @Override
+ public State getState() {
+ return state.get();
+ }
+
+ @Override
+ public void onMessage(final Message message) {
+ try {
+ if (message instanceof ObjectMessage) {
+ final Object body = ((ObjectMessage) message).getObject();
+ if (body instanceof LogEvent) {
+ log((LogEvent) body);
+ } else {
+ LOGGER.warn("Expected ObjectMessage to contain LogEvent. Got type {} instead.", body.getClass());
+ }
+ } else {
+ LOGGER.warn("Received message of type {} and JMSType {} which cannot be handled.", message.getClass(),
+ message.getJMSType());
+ }
+ } catch (final JMSException e) {
+ LOGGER.catching(e);
+ }
+ }
+
+ @Override
+ public void initialize() {
+ }
+
+ @Override
+ public void start() {
+ if (state.compareAndSet(State.INITIALIZED, State.STARTING)) {
+ try {
+ messageConsumer = jmsManager.createMessageConsumer();
+ messageConsumer.setMessageListener(this);
+ } catch (final JMSException e) {
+ throw new LoggingException(e);
+ }
+ }
+ }
+
+ @Override
+ public void stop() {
+ stop(AbstractLifeCycle.DEFAULT_STOP_TIMEOUT, AbstractLifeCycle.DEFAULT_STOP_TIMEUNIT);
+ }
+
+ @Override
+ public boolean stop(final long timeout, final TimeUnit timeUnit) {
+ boolean stopped = true;
+ try {
+ messageConsumer.close();
+ } catch (final JMSException e) {
+ LOGGER.debug("Exception closing {}", messageConsumer, e);
+ stopped = false;
+ }
+ return stopped && jmsManager.stop(timeout, timeUnit);
+ }
+
+ @Override
+ public boolean isStarted() {
+ return state.get() == State.STARTED;
+ }
+
+ @Override
+ public boolean isStopped() {
+ return state.get() == State.STOPPED;
+ }
+
+ /**
+ * Starts and runs this server until the user types "exit" into standard input.
+ *
+ * @throws IOException
+ * @since 2.6
+ */
+ public void run() throws IOException {
+ this.start();
+ System.out.println("Type \"exit\" to quit.");
+ final BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in, Charset.defaultCharset()));
+ 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.");
+ this.stop();
+ return;
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/78fe32c0/log4j-core/src/main/java/org/apache/logging/log4j/core/util/JndiCloser.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/JndiCloser.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/JndiCloser.java
index 671c922..2114b40 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/JndiCloser.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/JndiCloser.java
@@ -1,58 +1,60 @@
-/*
- * 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.util;
-
-import javax.naming.Context;
-import javax.naming.NamingException;
-
-/**
- * Helper class for closing JNDI resources.
- *
- * This class is separate from {@link Closer} because JNDI is not in Android.
- */
-public final class JndiCloser {
-
- private JndiCloser() {
- }
-
- /**
- * Closes the specified {@code Context}.
- *
- * @param context the JNDI Context to close, may be {@code null}
- * @throws NamingException if a problem occurred closing the specified JNDI Context
- */
- public static void close(final Context context) throws NamingException {
- if (context != null) {
- context.close();
- }
- }
-
- /**
- * Closes the specified {@code Context}, ignoring any exceptions thrown by the close operation.
- *
- * @param context the JNDI Context to close, may be {@code null}
- */
- public static void closeSilently(final Context context) {
- try {
- close(context);
- } catch (final NamingException ignored) {
- // ignored
- }
- }
-
-}
+/*
+ * 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.util;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+/**
+ * Helper class for closing JNDI resources.
+ *
+ * This class is separate from {@link Closer} because JNDI is not in Android.
+ */
+public final class JndiCloser {
+
+ private JndiCloser() {
+ }
+
+ /**
+ * Closes the specified {@code Context}.
+ *
+ * @param context the JNDI Context to close, may be {@code null}
+ * @throws NamingException if a problem occurred closing the specified JNDI Context
+ */
+ public static void close(final Context context) throws NamingException {
+ if (context != null) {
+ context.close();
+ }
+ }
+
+ /**
+ * Closes the specified {@code Context}, ignoring any exceptions thrown by the close operation.
+ *
+ * @param context the JNDI Context to close, may be {@code null}
+ */
+ public static boolean closeSilently(final Context context) {
+ try {
+ close(context);
+ return true;
+ } catch (final NamingException ignored) {
+ // ignored
+ return false;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/78fe32c0/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
----------------------------------------------------------------------
diff --git a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
index 1df6bed..a29df92 100644
--- a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
+++ b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
@@ -109,10 +109,10 @@ public final class FlumeAppender extends AbstractAppender implements FlumeEventF
@Override
public boolean stop(final long timeout, final TimeUnit timeUnit) {
setStopping();
- super.stop(timeout, timeUnit, false);
- manager.stop(timeout, timeUnit);
+ boolean stopped = super.stop(timeout, timeUnit, false);
+ stopped &= manager.stop(timeout, timeUnit);
setStopped();
- return true;
+ return stopped;
}
/**