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;
018
019import java.io.OutputStream;
020import java.io.Serializable;
021import java.net.InetAddress;
022import java.net.UnknownHostException;
023import java.util.HashMap;
024import java.util.Map;
025
026import org.apache.logging.log4j.core.Layout;
027import org.apache.logging.log4j.core.appender.ManagerFactory;
028import org.apache.logging.log4j.util.Strings;
029
030/**
031 * Socket Manager for UDP connections.
032 */
033public class DatagramSocketManager extends AbstractSocketManager {
034
035    private static final DatagramSocketManagerFactory FACTORY = new DatagramSocketManagerFactory();
036
037    /**
038     * The Constructor.
039     * @param name The unique name of the connection.
040     * @param os The OutputStream.
041     * @param inetAddress
042     * @param host The host to connect to.
043     * @param port The port on the host.
044     * @param layout The layout
045     * @param bufferSize The buffer size
046     */
047    protected DatagramSocketManager(final String name, final OutputStream os, final InetAddress inetAddress, final String host,
048                final int port, final Layout<? extends Serializable> layout, final int bufferSize) {
049        super(name, os, inetAddress, host, port, layout, true, bufferSize);
050    }
051
052    /**
053     * Obtain a SocketManager.
054     * @param host The host to connect to.
055     * @param port The port on the host.
056     * @param layout The layout.
057     * @param bufferSize The buffer size.
058     * @return A DatagramSocketManager.
059     */
060    public static DatagramSocketManager getSocketManager(final String host, final int port,
061            final Layout<? extends Serializable> layout, final int bufferSize) {
062        if (Strings.isEmpty(host)) {
063            throw new IllegalArgumentException("A host name is required");
064        }
065        if (port <= 0) {
066            throw new IllegalArgumentException("A port value is required");
067        }
068        return (DatagramSocketManager) getManager("UDP:" + host + ':' + port,
069                new FactoryData(host, port, layout, bufferSize), FACTORY);
070    }
071
072    /**
073     * Gets this DatagramSocketManager's content format. Specified by:
074     * <ul>
075     * <li>Key: "protocol" Value: "udp"</li>
076     * <li>Key: "direction" Value: "out"</li>
077     * </ul>
078     *
079     * @return Map of content format keys supporting DatagramSocketManager
080     */
081    @Override
082    public Map<String, String> getContentFormat() {
083        final Map<String, String> result = new HashMap<>(super.getContentFormat());
084        result.put("protocol", "udp");
085        result.put("direction", "out");
086        return result;
087    }
088
089    /**
090     * Data for the factory.
091     */
092    private static class FactoryData {
093        private final String host;
094        private final int port;
095        private final Layout<? extends Serializable> layout;
096        private final int bufferSize;
097
098        public FactoryData(final String host, final int port, final Layout<? extends Serializable> layout, final int bufferSize) {
099            this.host = host;
100            this.port = port;
101            this.layout = layout;
102            this.bufferSize = bufferSize;
103        }
104    }
105
106    /**
107     * Factory to create the DatagramSocketManager.
108     */
109    private static class DatagramSocketManagerFactory implements ManagerFactory<DatagramSocketManager, FactoryData> {
110
111        @Override
112        public DatagramSocketManager createManager(final String name, final FactoryData data) {
113            InetAddress inetAddress;
114            try {
115                inetAddress = InetAddress.getByName(data.host);
116            } catch (final UnknownHostException ex) {
117                LOGGER.error("Could not find address of " + data.host, ex);
118                return null;
119            }
120            final OutputStream os = new DatagramOutputStream(data.host, data.port, data.layout.getHeader(),
121                    data.layout.getFooter());
122            return new DatagramSocketManager(name, os, inetAddress, data.host, data.port, data.layout, data.bufferSize);
123        }
124    }
125}