Merge branch 'master' into LOG4J2-1851

# Conflicts:
#       src/changes/changes.xml


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/394c30f5
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/394c30f5
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/394c30f5

Branch: refs/heads/java9NoMultiRelease
Commit: 394c30f594c9eac570a43313bf44be4bc60cded9
Parents: 6fd6dfc 1475bd9
Author: Mikael StÃ¥ldal <[email protected]>
Authored: Mon Apr 10 10:59:27 2017 +0200
Committer: Mikael StÃ¥ldal <[email protected]>
Committed: Mon Apr 10 10:59:27 2017 +0200

----------------------------------------------------------------------
 BUILDING.md                                     |   2 +-
 README.md                                       |   2 +
 RELEASE-NOTES.md                                |  74 ++++++++++---------
 log4j-1.2-api/pom.xml                           |   2 +-
 log4j-api-scala_2.10/pom.xml                    |   2 +-
 log4j-api-scala_2.11/pom.xml                    |   2 +-
 log4j-api/pom.xml                               |   2 +-
 .../org/apache/logging/log4j/ThreadContext.java |   5 +-
 log4j-bom/pom.xml                               |   2 +-
 log4j-core-its/pom.xml                          |   2 +-
 log4j-core/pom.xml                              |   2 +-
 .../apache/logging/log4j/core/config/Order.java |   2 +-
 .../log4j/core/config/OrderComparator.java      |   2 +-
 .../builder/api/ConfigurationBuilder.java       |  15 ++++
 .../api/KeyValuePairComponentBuilder.java       |  25 +++++++
 .../builder/api/PropertyComponentBuilder.java   |  25 +++++++
 .../impl/DefaultConfigurationBuilder.java       |  11 +++
 .../DefaultKeyValuePairComponentBuilder.java    |  34 +++++++++
 .../impl/DefaultPropertyComponentBuilder.java   |  32 ++++++++
 .../core/util/FilteredObjectInputStream.java    |  67 +++++++++++++++++
 .../builder/ConfigurationAssemblerTest.java     |   6 +-
 .../builder/ConfigurationBuilderTest.java       |  16 ++++
 .../builder/CustomConfigurationFactory.java     |  11 +++
 log4j-distribution/pom.xml                      |   2 +-
 log4j-distribution/src/assembly/bin.xml         |   4 +-
 log4j-flume-ng/pom.xml                          |   2 +-
 log4j-iostreams/pom.xml                         |   2 +-
 log4j-jcl/pom.xml                               |   2 +-
 log4j-jmx-gui/pom.xml                           |   2 +-
 log4j-jul/pom.xml                               |   2 +-
 log4j-liquibase/pom.xml                         |   2 +-
 log4j-nosql/pom.xml                             |   2 +-
 log4j-osgi/pom.xml                              |   2 +-
 log4j-perf/pom.xml                              |   2 +-
 log4j-samples/configuration/pom.xml             |   2 +-
 log4j-samples/flume-common/pom.xml              |   2 +-
 log4j-samples/flume-embedded/pom.xml            |   2 +-
 log4j-samples/flume-remote/pom.xml              |   2 +-
 log4j-samples/loggerProperties/pom.xml          |   2 +-
 log4j-samples/pom.xml                           |   2 +-
 log4j-samples/scala-api/pom.xml                 |   2 +-
 .../log4j/server/AbstractSocketServer.java      |  13 ++++
 .../server/ObjectInputStreamLogEventBridge.java |  23 +++++-
 .../logging/log4j/server/TcpSocketServer.java   |  25 ++++++-
 .../logging/log4j/server/UdpSocketServer.java   |  18 ++++-
 log4j-slf4j-impl/pom.xml                        |   2 +-
 log4j-taglib/pom.xml                            |   2 +-
 log4j-to-slf4j/pom.xml                          |   2 +-
 log4j-web/pom.xml                               |   2 +-
 pom.xml                                         |  31 +++++---
 src/changes/changes.xml                         |  26 ++++++-
 src/site/markdown/maven-artifacts.md.vm         |   2 +-
 src/site/resources/images/logo.png              | Bin 40517 -> 40494 bytes
 .../logo/logo-electric-blue-2-2.8.2.png         | Bin 0 -> 40494 bytes
 .../logo/logo-electric-blue-2-2.8.2.xcf         | Bin 0 -> 67168 bytes
 .../resources/logo/logo-electric-blue-2.xcf     | Bin 0 -> 66097 bytes
 56 files changed, 437 insertions(+), 90 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/394c30f5/log4j-server/src/main/java/org/apache/logging/log4j/server/AbstractSocketServer.java
----------------------------------------------------------------------
diff --cc 
log4j-server/src/main/java/org/apache/logging/log4j/server/AbstractSocketServer.java
index a8f1140,0000000..aff7eb1
mode 100644,000000..100644
--- 
a/log4j-server/src/main/java/org/apache/logging/log4j/server/AbstractSocketServer.java
+++ 
b/log4j-server/src/main/java/org/apache/logging/log4j/server/AbstractSocketServer.java
@@@ -1,209 -1,0 +1,222 @@@
 +/*
 + * 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.server;
 +
 +import java.io.BufferedReader;
 +import java.io.File;
 +import java.io.FileInputStream;
 +import java.io.FileNotFoundException;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.InputStreamReader;
 +import java.net.InetAddress;
 +import java.net.URI;
 +import java.net.URL;
++import java.util.Collections;
++import java.util.List;
 +import java.util.Objects;
 +
 +import com.beust.jcommander.Parameter;
 +import com.beust.jcommander.validators.PositiveInteger;
 +import org.apache.logging.log4j.LogManager;
 +import org.apache.logging.log4j.Logger;
 +import org.apache.logging.log4j.core.LogEventListener;
 +import org.apache.logging.log4j.core.LoggerContext;
 +import org.apache.logging.log4j.core.config.Configuration;
 +import org.apache.logging.log4j.core.config.ConfigurationSource;
 +import org.apache.logging.log4j.core.config.xml.XmlConfiguration;
 +import org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory;
 +import org.apache.logging.log4j.core.util.BasicCommandLineArguments;
 +import org.apache.logging.log4j.core.util.InetAddressConverter;
 +import org.apache.logging.log4j.core.util.Log4jThread;
 +import org.apache.logging.log4j.util.Strings;
 +
 +/**
 + * Abstract socket server for TCP and UDP implementations.
 + *
 + * @param <T>
 + *            The kind of input stream read
 + *
 + *            TODO Make a LifeCycle
 + */
 +public abstract class AbstractSocketServer<T extends InputStream> extends 
LogEventListener implements Runnable {
 +
 +    protected static class CommandLineArguments extends 
BasicCommandLineArguments {
 +
 +        @Parameter(names = { "--config", "-c" }, description = "Log4j 
configuration file location (path or URL).")
 +        private String configLocation;
 +
 +        @Parameter(names = { "--interactive",
 +                "-i" }, description = "Accepts commands on standard input 
(\"exit\" is the only command).")
 +        private boolean interactive;
 +
 +        @Parameter(names = { "--port",
 +                "-p" }, validateWith = PositiveInteger.class, description = 
"Server socket port.")
 +        private int port;
 +
 +        @Parameter(names = { "--localbindaddress",
 +                "-a" }, converter = InetAddressConverter.class, description = 
"Server socket local bind address.")
 +        private InetAddress localBindAddress;
 +
++        @Parameter(names = {"--classes", "-C"}, description = "Additional 
classes to allow deserialization")
++        private List<String> allowedClasses;
++
 +        String getConfigLocation() {
 +            return configLocation;
 +        }
 +
 +        int getPort() {
 +            return port;
 +        }
 +
 +        protected boolean isInteractive() {
 +            return interactive;
 +        }
 +
 +        void setConfigLocation(final String configLocation) {
 +            this.configLocation = configLocation;
 +        }
 +
 +        void setInteractive(final boolean interactive) {
 +            this.interactive = interactive;
 +        }
 +
 +        void setPort(final int port) {
 +            this.port = port;
 +        }
 +
 +        InetAddress getLocalBindAddress() {
 +            return localBindAddress;
 +        }
 +
 +        void setLocalBindAddress(final InetAddress localBindAddress) {
 +            this.localBindAddress = localBindAddress;
 +        }
++
++        List<String> getAllowedClasses() {
++            return allowedClasses == null ? Collections.<String>emptyList() : 
allowedClasses;
++        }
++
++        void setAllowedClasses(final List<String> allowedClasses) {
++            this.allowedClasses = allowedClasses;
++        }
 +    }
 +
 +    /**
 +     * Factory that creates a Configuration for the server.
 +     */
 +    protected static class ServerConfigurationFactory extends 
XmlConfigurationFactory {
 +
 +        private final String path;
 +
 +        public ServerConfigurationFactory(final String path) {
 +            this.path = path;
 +        }
 +
 +        @Override
 +        public Configuration getConfiguration(final LoggerContext 
loggerContext, final String name,
 +                final URI configLocation) {
 +            if (Strings.isNotEmpty(path)) {
 +                File file = null;
 +                ConfigurationSource source = null;
 +                try {
 +                    file = new File(path);
 +                    final FileInputStream is = new FileInputStream(file);
 +                    source = new ConfigurationSource(is, file);
 +                } catch (final FileNotFoundException ignored) {
 +                    // Ignore this error
 +                }
 +                if (source == null) {
 +                    try {
 +                        final URL url = new URL(path);
 +                        source = new ConfigurationSource(url.openStream(), 
url);
 +                    } catch (final IOException ignored) {
 +                        // Ignore this error
 +                    }
 +                }
 +
 +                try {
 +                    if (source != null) {
 +                        return new XmlConfiguration(loggerContext, source);
 +                    }
 +                } catch (final Exception ignored) {
 +                    // Ignore this error.
 +                }
 +                System.err.println("Unable to process configuration at " + 
path + ", using default.");
 +            }
 +            return super.getConfiguration(loggerContext, name, 
configLocation);
 +        }
 +    }
 +
 +    protected static final int MAX_PORT = 65534;
 +
 +    private volatile boolean active = true;
 +
 +    protected final LogEventBridge<T> logEventInput;
 +
 +    protected final Logger logger;
 +
 +    /**
 +     * Creates a new socket server.
 +     *
 +     * @param port
 +     *            listen to this port
 +     * @param logEventInput
 +     *            Use this input to read log events.
 +     */
 +    public AbstractSocketServer(final int port, final LogEventBridge<T> 
logEventInput) {
 +        this.logger = LogManager.getLogger(this.getClass().getName() + '.' + 
port);
 +        this.logEventInput = Objects.requireNonNull(logEventInput, 
"LogEventInput");
 +    }
 +
 +    protected boolean isActive() {
 +        return this.active;
 +    }
 +
 +    protected void setActive(final boolean isActive) {
 +        this.active = isActive;
 +    }
 +
 +    /**
 +     * Start this server in a new thread.
 +     *
 +     * @return the new thread that running this server.
 +     */
 +    public Thread startNewThread() {
 +        final Thread thread = new Log4jThread(this);
 +        thread.start();
 +        return thread;
 +    }
 +
 +    public abstract void shutdown() throws Exception;
 +
 +    public void awaitTermination(final Thread serverThread) throws Exception {
 +        final BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
 +        while (true) {
 +            final String line = reader.readLine();
 +            if (line == null
 +                || line.equalsIgnoreCase("quit")
 +                || line.equalsIgnoreCase("stop")
 +                || line.equalsIgnoreCase("exit")) {
 +                this.shutdown();
 +                serverThread.join();
 +                break;
 +            }
 +        }
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/394c30f5/log4j-server/src/main/java/org/apache/logging/log4j/server/ObjectInputStreamLogEventBridge.java
----------------------------------------------------------------------
diff --cc 
log4j-server/src/main/java/org/apache/logging/log4j/server/ObjectInputStreamLogEventBridge.java
index 9f22b22,0000000..ddd2e26
mode 100644,000000..100644
--- 
a/log4j-server/src/main/java/org/apache/logging/log4j/server/ObjectInputStreamLogEventBridge.java
+++ 
b/log4j-server/src/main/java/org/apache/logging/log4j/server/ObjectInputStreamLogEventBridge.java
@@@ -1,45 -1,0 +1,64 @@@
 +/*
 + * 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.server;
 +
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.ObjectInputStream;
++import java.util.Collections;
++import java.util.List;
 +
 +import org.apache.logging.log4j.core.LogEvent;
 +import org.apache.logging.log4j.core.LogEventListener;
++import org.apache.logging.log4j.core.util.FilteredObjectInputStream;
 +
 +/**
 + * Reads and logs serialized {@link LogEvent} objects from an {@link 
ObjectInputStream}.
 + */
 +public class ObjectInputStreamLogEventBridge extends 
AbstractLogEventBridge<ObjectInputStream> {
 +
++    private final List<String> allowedClasses;
++
++    public ObjectInputStreamLogEventBridge() {
++        this(Collections.<String>emptyList());
++    }
++
++    /**
++     * Constructs an ObjectInputStreamLogEventBridge with additional allowed 
classes to deserialize.
++     *
++     * @param allowedClasses class names to also allow for deserialization
++     * @since 2.8.2
++     */
++    public ObjectInputStreamLogEventBridge(final List<String> allowedClasses) 
{
++        this.allowedClasses = allowedClasses;
++    }
++
 +    @Override
 +    public void logEvents(final ObjectInputStream inputStream, final 
LogEventListener logEventListener)
-             throws IOException {
++        throws IOException {
 +        try {
 +            logEventListener.log((LogEvent) inputStream.readObject());
 +        } catch (final ClassNotFoundException e) {
 +            throw new IOException(e);
 +        }
 +    }
 +
 +    @Override
 +    public ObjectInputStream wrapStream(final InputStream inputStream) throws 
IOException {
-         return new ObjectInputStream(inputStream);
++        return new FilteredObjectInputStream(inputStream, allowedClasses);
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/394c30f5/log4j-server/src/main/java/org/apache/logging/log4j/server/TcpSocketServer.java
----------------------------------------------------------------------
diff --cc 
log4j-server/src/main/java/org/apache/logging/log4j/server/TcpSocketServer.java
index 7856969,0000000..9a5521c
mode 100644,000000..100644
--- 
a/log4j-server/src/main/java/org/apache/logging/log4j/server/TcpSocketServer.java
+++ 
b/log4j-server/src/main/java/org/apache/logging/log4j/server/TcpSocketServer.java
@@@ -1,314 -1,0 +1,333 @@@
 +/*
 + * 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.server;
 +
 +import java.io.EOFException;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.ObjectInputStream;
 +import java.io.OptionalDataException;
 +import java.net.InetAddress;
 +import java.net.ServerSocket;
 +import java.net.Socket;
++import java.util.Collections;
++import java.util.List;
 +import java.util.Map;
 +import java.util.concurrent.ConcurrentHashMap;
 +import java.util.concurrent.ConcurrentMap;
 +
 +import com.beust.jcommander.Parameter;
 +import com.beust.jcommander.validators.PositiveInteger;
 +import org.apache.logging.log4j.core.config.ConfigurationFactory;
 +import org.apache.logging.log4j.core.util.BasicCommandLineArguments;
 +import org.apache.logging.log4j.core.util.Closer;
 +import org.apache.logging.log4j.core.util.Log4jThread;
 +import org.apache.logging.log4j.message.EntryMessage;
 +
 +/**
 + * Listens for Log4j events on a TCP server socket and passes them on to 
Log4j.
 + * 
 + * @param <T>
 + *        The kind of input stream read
 + * @see #main(String[])
 + */
 +public class TcpSocketServer<T extends InputStream> extends 
AbstractSocketServer<T> {
 +
 +    protected static class CommandLineArguments extends 
AbstractSocketServer.CommandLineArguments {
 +        
 +        @Parameter(names = { "--backlog",
 +                "-b" }, validateWith = PositiveInteger.class, description = 
"Server socket backlog.")
 +        // Same default as ServerSocket
 +        private int backlog = 50;
 +
 +        int getBacklog() {
 +            return backlog;
 +        }
 +
 +        void setBacklog(final int backlog) {
 +            this.backlog = backlog;
 +        }        
 +
 +    }
 +
 +    /**
 +     * Thread that processes the events.
 +     */
 +    private class SocketHandler extends Log4jThread {
 +
 +        private final T inputStream;
 +
 +        private volatile boolean shutdown = false;
 +
 +        public SocketHandler(final Socket socket) throws IOException {
 +            this.inputStream = 
logEventInput.wrapStream(socket.getInputStream());
 +        }
 +
 +        @Override
 +        public void run() {
 +            final EntryMessage entry = logger.traceEntry();
 +            boolean closed = false;
 +            try {
 +                try {
 +                    while (!shutdown) {
 +                        logEventInput.logEvents(inputStream, 
TcpSocketServer.this);
 +                    }
 +                } catch (final EOFException e) {
 +                    closed = true;
 +                } catch (final OptionalDataException e) {
 +                    logger.error("OptionalDataException eof=" + e.eof + " 
length=" + e.length, e);
 +                } catch (final IOException e) {
 +                    logger.error("IOException encountered while reading from 
socket", e);
 +                }
 +                if (!closed) {
 +                    Closer.closeSilently(inputStream);
 +                }
 +            } finally {
 +                handlers.remove(Long.valueOf(getId()));
 +            }
 +            logger.traceExit(entry);
 +        }
 +
 +        public void shutdown() {
 +            this.shutdown = true;
 +            interrupt();
 +        }
 +    }
 +
 +    /**
 +     * Creates a socket server that reads JSON log events.
 +     * 
 +     * @param port
 +     *        the port to listen
 +     * @return a new a socket server
 +     * @throws IOException
 +     *         if an I/O error occurs when opening the socket.
 +     */
 +    public static TcpSocketServer<InputStream> createJsonSocketServer(final 
int port) throws IOException {
 +        LOGGER.entry("createJsonSocketServer", port);
 +        final TcpSocketServer<InputStream> socketServer = new 
TcpSocketServer<>(port, new JsonInputStreamLogEventBridge());
 +        return LOGGER.exit(socketServer);
 +    }
 +
 +    /**
 +     * Creates a socket server that reads serialized log events.
 +     * 
 +     * @param port
 +     *        the port to listen
 +     * @return a new a socket server
 +     * @throws IOException
 +     *         if an I/O error occurs when opening the socket.
 +     */
 +    public static TcpSocketServer<ObjectInputStream> 
createSerializedSocketServer(final int port) throws IOException {
 +        LOGGER.entry(port);
 +        final TcpSocketServer<ObjectInputStream> socketServer = new 
TcpSocketServer<>(port, new ObjectInputStreamLogEventBridge());
 +        return LOGGER.exit(socketServer);
 +    }
 +
 +    /**
 +     * Creates a socket server that reads serialized log events.
 +     * 
 +     * @param port the port to listen
 +     * @param localBindAddress The server socket's local bin address
 +     * @return a new a socket server
 +     * @throws IOException
 +     *         if an I/O error occurs when opening the socket.
 +     * @since 2.7
 +     */
 +    public static TcpSocketServer<ObjectInputStream> 
createSerializedSocketServer(final int port, final int backlog,
 +            final InetAddress localBindAddress) throws IOException {
++        return createSerializedSocketServer(port, backlog, localBindAddress, 
Collections.<String>emptyList());
++    }
++
++    /**
++     * Creates a socket server that reads serialized log events.
++     *
++     * @param port the port to listen
++     * @param localBindAddress The server socket's local bin address
++     * @param allowedClasses additional class names to allow for 
deserialization
++     * @return a new a socket server
++     * @throws IOException
++     *         if an I/O error occurs when opening the socket.
++     * @since 2.8.2
++     */
++    public static TcpSocketServer<ObjectInputStream> 
createSerializedSocketServer(
++        final int port, final int backlog, final InetAddress 
localBindAddress, final List<String> allowedClasses
++    ) throws IOException {
 +        LOGGER.entry(port);
 +        final TcpSocketServer<ObjectInputStream> socketServer = new 
TcpSocketServer<>(port, backlog, localBindAddress,
-                 new ObjectInputStreamLogEventBridge());
++                new ObjectInputStreamLogEventBridge(allowedClasses));
 +        return LOGGER.exit(socketServer);
 +    }
 +
 +    /**
 +     * Creates a socket server that reads XML log events.
 +     * 
 +     * @param port
 +     *        the port to listen
 +     * @return a new a socket server
 +     * @throws IOException
 +     *         if an I/O error occurs when opening the socket.
 +     */
 +    public static TcpSocketServer<InputStream> createXmlSocketServer(final 
int port) throws IOException {
 +        LOGGER.entry(port);
 +        final TcpSocketServer<InputStream> socketServer = new 
TcpSocketServer<>(port, new XmlInputStreamLogEventBridge());
 +        return LOGGER.exit(socketServer);
 +    }
 +
 +    /**
 +     * Main startup for the server. Run with "--help" for to print command 
line help on the console.
 +     * 
 +     * @param args
 +     *        The command line arguments.
 +     * @throws Exception
 +     *         if an error occurs.
 +     */
 +    public static void main(final String[] args) throws Exception {
 +        final CommandLineArguments cla = 
BasicCommandLineArguments.parseCommandLine(args, TcpSocketServer.class, new 
CommandLineArguments());
 +        if (cla.isHelp()) {
 +            return;
 +        }
 +        if (cla.getConfigLocation() != null) {
 +            ConfigurationFactory.setConfigurationFactory(new 
ServerConfigurationFactory(cla.getConfigLocation()));
 +        }
-         final TcpSocketServer<ObjectInputStream> socketServer = 
TcpSocketServer
-                 .createSerializedSocketServer(cla.getPort(), 
cla.getBacklog(), cla.getLocalBindAddress());
++        final TcpSocketServer<ObjectInputStream> socketServer = 
TcpSocketServer.createSerializedSocketServer(
++            cla.getPort(), cla.getBacklog(), cla.getLocalBindAddress(), 
cla.getAllowedClasses());
 +        final Thread serverThread = socketServer.startNewThread();
 +        if (cla.isInteractive()) {
 +            socketServer.awaitTermination(serverThread);
 +        }
 +    }
 +
 +    private final ConcurrentMap<Long, SocketHandler> handlers = new 
ConcurrentHashMap<>();
 +
 +    private final ServerSocket serverSocket;
 +
 +    /**
 +     * Constructor.
 +     * 
 +     * @param port
 +     *        The server socket port.
 +     * @param backlog
 +     *        The server socket backlog.
 +     * @param localBindAddress TODO
 +     * @param logEventInput
 +     *        the log even input
 +     * @throws IOException
 +     *         if an I/O error occurs when opening the socket.
 +     * @since 2.7
 +     */
 +    @SuppressWarnings("resource")
 +    public TcpSocketServer(final int port, final int backlog, final 
InetAddress localBindAddress, final LogEventBridge<T> logEventInput) throws 
IOException {
 +        this(port, logEventInput, new ServerSocket(port, backlog, 
localBindAddress));
 +    }
 +
 +    /**
 +     * Constructor.
 +     * 
 +     * @param port
 +     *        to listen.
 +     * @param logEventInput
 +     *        the log even input
 +     * @throws IOException
 +     *         if an I/O error occurs when opening the socket.
 +     */
 +    public TcpSocketServer(final int port, final LogEventBridge<T> 
logEventInput) throws IOException {
 +        this(port, logEventInput, extracted(port));
 +    }
 +
 +    private static ServerSocket extracted(final int port) throws IOException {
 +        return new ServerSocket(port);
 +    }
 +
 +    /**
 +     * Constructor.
 +     * 
 +     * @param port
 +     *        to listen.
 +     * @param logEventInput
 +     *        the log even input
 +     * @param serverSocket
 +     *        the socket server
 +     * @throws IOException
 +     *         if an I/O error occurs when opening the socket.
 +     */
 +    public TcpSocketServer(final int port, final LogEventBridge<T> 
logEventInput, final ServerSocket serverSocket)
 +            throws IOException {
 +        super(port, logEventInput);
 +        this.serverSocket = serverSocket;
 +    }
 +
 +    /**
 +     * Accept incoming events and processes them.
 +     */
 +    @Override
 +    public void run() {
 +        final EntryMessage entry = logger.traceEntry();
 +        while (isActive()) {
 +            if (serverSocket.isClosed()) {
 +                return;
 +            }
 +            try {
 +                // Accept incoming connections.
 +                logger.debug("Listening for a connection {}...", 
serverSocket);
 +                final Socket clientSocket = serverSocket.accept();
 +                logger.debug("Acepted connection on {}...", serverSocket);
 +                logger.debug("Socket accepted: {}", clientSocket);
 +                clientSocket.setSoLinger(true, 0);
 +
 +                // accept() will block until a client connects to the server.
 +                // If execution reaches this point, then it means that a 
client
 +                // socket has been accepted.
 +
 +                final SocketHandler handler = new SocketHandler(clientSocket);
 +                handlers.put(Long.valueOf(handler.getId()), handler);
 +                handler.start();
 +            } catch (final IOException e) {
 +                if (serverSocket.isClosed()) {
 +                    // OK we're done.
 +                    logger.traceExit(entry);
 +                    return;
 +                }
 +                logger.error("Exception encountered on accept. Ignoring. 
Stack trace :", e);
 +            }
 +        }
 +        for (final Map.Entry<Long, SocketHandler> handlerEntry : 
handlers.entrySet()) {
 +            final SocketHandler handler = handlerEntry.getValue();
 +            handler.shutdown();
 +            try {
 +                handler.join();
 +            } catch (final InterruptedException ignored) {
 +                // Ignore the exception
 +            }
 +        }
 +        logger.traceExit(entry);
 +    }
 +
 +    /**
 +     * Shutdown the server.
 +     * 
 +     * @throws IOException if the server socket could not be closed
 +     */
 +    @Override
 +    public void shutdown() throws IOException {
 +        final EntryMessage entry = logger.traceEntry();
 +        setActive(false);
 +        Thread.currentThread().interrupt();
 +        serverSocket.close();
 +        logger.traceExit(entry);
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/394c30f5/log4j-server/src/main/java/org/apache/logging/log4j/server/UdpSocketServer.java
----------------------------------------------------------------------
diff --cc 
log4j-server/src/main/java/org/apache/logging/log4j/server/UdpSocketServer.java
index a2bac17,0000000..12a8450
mode 100644,000000..100644
--- 
a/log4j-server/src/main/java/org/apache/logging/log4j/server/UdpSocketServer.java
+++ 
b/log4j-server/src/main/java/org/apache/logging/log4j/server/UdpSocketServer.java
@@@ -1,169 -1,0 +1,185 @@@
 +/*
 + * 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.server;
 +
 +import java.io.ByteArrayInputStream;
 +import java.io.EOFException;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.ObjectInputStream;
 +import java.io.OptionalDataException;
 +import java.net.DatagramPacket;
 +import java.net.DatagramSocket;
++import java.util.List;
 +
 +import org.apache.logging.log4j.core.config.ConfigurationFactory;
 +import org.apache.logging.log4j.core.util.BasicCommandLineArguments;
 +
 +/**
 + * Listens for Log4j events on a datagram socket and passes them on to Log4j. 
 + * 
 + * @param <T>
 + *            The kind of input stream read
 + * @see #main(String[])
 + */
 +public class UdpSocketServer<T extends InputStream> extends 
AbstractSocketServer<T> {
 +
 +    /**
 +     * Creates a socket server that reads JSON log events.
 +     * 
 +     * @param port
 +     *            the port to listen
 +     * @return a new a socket server
 +     * @throws IOException
 +     *             if an I/O error occurs when opening the socket.
 +     */
 +    public static UdpSocketServer<InputStream> createJsonSocketServer(final 
int port) throws IOException {
 +        return new UdpSocketServer<>(port, new 
JsonInputStreamLogEventBridge());
 +    }
 +
 +    /**
 +     * Creates a socket server that reads serialized log events.
 +     * 
 +     * @param port
 +     *            the port to listen
 +     * @return a new a socket server
 +     * @throws IOException
 +     *             if an I/O error occurs when opening the socket.
 +     */
 +    public static UdpSocketServer<ObjectInputStream> 
createSerializedSocketServer(final int port) throws IOException {
 +        return new UdpSocketServer<>(port, new 
ObjectInputStreamLogEventBridge());
 +    }
 +
 +    /**
++     * Creates a socket server that reads serialized log events.
++     *
++     * @param port the port to listen
++     * @param allowedClasses additional classes to allow for deserialization
++     * @return a new a socket server
++     * @throws IOException if an I/O error occurs when opening the socket.
++     * @since 2.8.2
++     */
++    public static UdpSocketServer<ObjectInputStream> 
createSerializedSocketServer(final int port,
++                                                                              
    final List<String> allowedClasses)
++        throws IOException {
++        return new UdpSocketServer<>(port, new 
ObjectInputStreamLogEventBridge(allowedClasses));
++    }
++
++    /**
 +     * Creates a socket server that reads XML log events.
 +     * 
 +     * @param port
 +     *            the port to listen
 +     * @return a new a socket server
 +     * @throws IOException
 +     *             if an I/O error occurs when opening the socket.
 +     */
 +    public static UdpSocketServer<InputStream> createXmlSocketServer(final 
int port) throws IOException {
 +        return new UdpSocketServer<>(port, new 
XmlInputStreamLogEventBridge());
 +    }
 +
 +    /**
 +     * Main startup for the server. Run with "--help" for to print command 
line help on the console.
 +     * 
 +     * @param args
 +     *            The command line arguments.
 +     * @throws Exception
 +     *             if an error occurs.
 +     */
 +    public static void main(final String[] args) throws Exception {
 +        final CommandLineArguments cla = 
BasicCommandLineArguments.parseCommandLine(args, UdpSocketServer.class, new 
CommandLineArguments());
 +        if (cla.isHelp()) {
 +            return;
 +        }
 +        if (cla.getConfigLocation() != null) {
 +            ConfigurationFactory.setConfigurationFactory(new 
ServerConfigurationFactory(cla.getConfigLocation()));
 +        }
 +        final UdpSocketServer<ObjectInputStream> socketServer = 
UdpSocketServer
-                 .createSerializedSocketServer(cla.getPort());
++                .createSerializedSocketServer(cla.getPort(), 
cla.getAllowedClasses());
 +        final Thread serverThread = socketServer.startNewThread();
 +        if (cla.isInteractive()) {
 +            socketServer.awaitTermination(serverThread);
 +        }
 +    }
 +
 +    private final DatagramSocket datagramSocket;
 +
 +    // max size so we only have to deal with one packet
 +    private final int maxBufferSize = 1024 * 65 + 1024;
 +
 +    /**
 +     * Constructor.
 +     * 
 +     * @param port
 +     *            to listen on.
 +     * @param logEventInput
 +     * @throws IOException
 +     *             If an error occurs.
 +     */
 +    public UdpSocketServer(final int port, final LogEventBridge<T> 
logEventInput) throws IOException {
 +        super(port, logEventInput);
 +        this.datagramSocket = new DatagramSocket(port);
 +    }
 +
 +    /**
 +     * Accept incoming events and processes them.
 +     */
 +    @Override
 +    public void run() {
 +        while (isActive()) {
 +            if (datagramSocket.isClosed()) {
 +                // OK we're done.
 +                return;
 +            }
 +            try {
 +                final byte[] buf = new byte[maxBufferSize];
 +                final DatagramPacket packet = new DatagramPacket(buf, 
buf.length);
 +                datagramSocket.receive(packet);
 +                final ByteArrayInputStream bais = new 
ByteArrayInputStream(packet.getData(), packet.getOffset(), packet.getLength());
 +                logEventInput.logEvents(logEventInput.wrapStream(bais), this);
 +            } catch (final OptionalDataException e) {
 +                if (datagramSocket.isClosed()) {
 +                    // OK we're done.
 +                    return;
 +                }
 +                logger.error("OptionalDataException eof=" + e.eof + " 
length=" + e.length, e);
 +            } catch (final EOFException e) {
 +                if (datagramSocket.isClosed()) {
 +                    // OK we're done.
 +                    return;
 +                }
 +                logger.info("EOF encountered");
 +            } catch (final IOException e) {
 +                if (datagramSocket.isClosed()) {
 +                    // OK we're done.
 +                    return;
 +                }
 +                logger.error("Exception encountered on accept. Ignoring. 
Stack Trace :", e);
 +            }
 +        }
 +    }
 +
 +    /**
 +     * Shutdown the server.
 +     */
 +    @Override
 +    public void shutdown() {
 +        this.setActive(false);
 +        Thread.currentThread().interrupt();
 +        datagramSocket.close();
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/394c30f5/pom.xml
----------------------------------------------------------------------

Reply via email to