001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.logging.log4j.core.net.server;
018
019import java.io.File;
020import java.io.FileInputStream;
021import java.io.FileNotFoundException;
022import java.io.IOException;
023import java.io.InputStream;
024import java.net.MalformedURLException;
025import java.net.URI;
026import java.net.URL;
027import java.util.Objects;
028
029import org.apache.logging.log4j.LogManager;
030import org.apache.logging.log4j.Logger;
031import org.apache.logging.log4j.core.LogEventListener;
032import org.apache.logging.log4j.core.config.Configuration;
033import org.apache.logging.log4j.core.config.ConfigurationSource;
034import org.apache.logging.log4j.core.config.xml.XmlConfiguration;
035import org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory;
036import org.apache.logging.log4j.core.util.Log4jThread;
037import org.apache.logging.log4j.util.Strings;
038
039/**
040 * Abstract socket server for TCP and UDP implementations.
041 * 
042 * @param <T> The kind of input stream read
043 * 
044 * TODO Make a LifeCycle
045 */
046public abstract class AbstractSocketServer<T extends InputStream> extends LogEventListener implements Runnable {
047
048    /**
049     * Factory that creates a Configuration for the server.
050     */
051    protected static class ServerConfigurationFactory extends XmlConfigurationFactory {
052
053        private final String path;
054
055        public ServerConfigurationFactory(final String path) {
056            this.path = path;
057        }
058
059        @Override
060        public Configuration getConfiguration(final String name, final URI configLocation) {
061            if (Strings.isNotEmpty(path)) {
062                File file = null;
063                ConfigurationSource source = null;
064                try {
065                    file = new File(path);
066                    final FileInputStream is = new FileInputStream(file);
067                    source = new ConfigurationSource(is, file);
068                } catch (final FileNotFoundException ex) {
069                    // Ignore this error
070                }
071                if (source == null) {
072                    try {
073                        final URL url = new URL(path);
074                        source = new ConfigurationSource(url.openStream(), url);
075                    } catch (final MalformedURLException mue) {
076                        // Ignore this error
077                    } catch (final IOException ioe) {
078                        // Ignore this error
079                    }
080                }
081
082                try {
083                    if (source != null) {
084                        return new XmlConfiguration(source);
085                    }
086                } catch (final Exception ex) {
087                    // Ignore this error.
088                }
089                System.err.println("Unable to process configuration at " + path + ", using default.");
090            }
091            return super.getConfiguration(name, configLocation);
092        }
093    }
094
095    protected static final int MAX_PORT = 65534;
096
097    private volatile boolean active = true;
098
099    protected final LogEventBridge<T> logEventInput;
100
101    protected final Logger logger;
102
103    /**
104     * Creates a new socket server.
105     * 
106     * @param port listen to this port
107     * @param logEventInput Use this input to read log events.
108     */
109    public AbstractSocketServer(final int port, final LogEventBridge<T> logEventInput) {
110        this.logger = LogManager.getLogger(this.getClass().getName() + '.' + port);
111        this.logEventInput = Objects.requireNonNull(logEventInput, "LogEventInput");
112    }
113
114    protected boolean isActive() {
115        return this.active;
116    }
117
118    protected void setActive(final boolean isActive) {
119        this.active = isActive;
120    }
121
122    /**
123     * Start this server in a new thread.
124     * 
125     * @return the new thread that running this server.
126     */
127    public Thread startNewThread() {
128        final Thread thread = new Log4jThread(this);
129        thread.start();
130        return thread;
131    }
132
133}