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.util.Strings;
037
038/**
039 * Abstract socket server for TCP and UDP implementations.
040 * 
041 * @param <T> The kind of input stream read
042 * 
043 * TODO Make a LifeCycle
044 */
045public abstract class AbstractSocketServer<T extends InputStream> extends LogEventListener implements Runnable {
046
047    /**
048     * Factory that creates a Configuration for the server.
049     */
050    protected static class ServerConfigurationFactory extends XmlConfigurationFactory {
051
052        private final String path;
053
054        public ServerConfigurationFactory(final String path) {
055            this.path = path;
056        }
057
058        @Override
059        public Configuration getConfiguration(final String name, final URI configLocation) {
060            if (Strings.isNotEmpty(path)) {
061                File file = null;
062                ConfigurationSource source = null;
063                try {
064                    file = new File(path);
065                    final FileInputStream is = new FileInputStream(file);
066                    source = new ConfigurationSource(is, file);
067                } catch (final FileNotFoundException ex) {
068                    // Ignore this error
069                }
070                if (source == null) {
071                    try {
072                        final URL url = new URL(path);
073                        source = new ConfigurationSource(url.openStream(), url);
074                    } catch (final MalformedURLException mue) {
075                        // Ignore this error
076                    } catch (final IOException ioe) {
077                        // Ignore this error
078                    }
079                }
080
081                try {
082                    if (source != null) {
083                        return new XmlConfiguration(source);
084                    }
085                } catch (final Exception ex) {
086                    // Ignore this error.
087                }
088                System.err.println("Unable to process configuration at " + path + ", using default.");
089            }
090            return super.getConfiguration(name, configLocation);
091        }
092    }
093
094    protected static final int MAX_PORT = 65534;
095
096    private volatile boolean active = true;
097
098    protected final LogEventBridge<T> logEventInput;
099
100    protected final Logger logger;
101
102    /**
103     * Creates a new socket server.
104     * 
105     * @param port listen to this port
106     * @param logEventInput Use this input to read log events.
107     */
108    public AbstractSocketServer(final int port, final LogEventBridge<T> logEventInput) {
109        this.logger = LogManager.getLogger(this.getClass().getName() + '.' + port);
110        this.logEventInput = Objects.requireNonNull(logEventInput, "LogEventInput");
111    }
112
113    protected boolean isActive() {
114        return this.active;
115    }
116
117    protected void setActive(final boolean isActive) {
118        this.active = isActive;
119    }
120
121    /**
122     * Start this server in a new thread.
123     * 
124     * @return the new thread that running this server.
125     */
126    public Thread startNewThread() {
127        final Thread thread = new Thread(this);
128        thread.start();
129        return thread;
130    }
131
132}