View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements. See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache license, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License. You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the license for the specific language governing permissions and
    15   * limitations under the license.
    16   */
    17  package org.apache.logging.log4j.core.net;
    18
    19  import java.io.IOException;
    20  import java.io.OutputStream;
    21  import java.net.DatagramPacket;
    22  import java.net.DatagramSocket;
    23  import java.net.InetAddress;
    24  import java.net.SocketException;
    25  import java.net.UnknownHostException;
    26
    27  import org.apache.logging.log4j.Logger;
    28  import org.apache.logging.log4j.core.appender.AppenderLoggingException;
    29  import org.apache.logging.log4j.status.StatusLogger;
    30
    31  /**
    32   * OutputStream for UDP connections.
    33   */
    34  public class DatagramOutputStream extends OutputStream {
    35
    36      /**
    37       * Allow subclasses access to the status logger without creating another instance.
    38       */
    39      protected static final Logger LOGGER = StatusLogger.getLogger();
    40
    41      private static final int SHIFT_1 = 8;
    42      private static final int SHIFT_2 = 16;
    43      private static final int SHIFT_3 = 24;
    44
    45      private DatagramSocket ds;
    46      private final InetAddress address;
    47      private final int port;
    48
    49      private byte[] data;
    50
    51      private final byte[] header;
    52      private final byte[] footer;
    53
    54      /**
    55       * The Constructor.
    56       * @param host The host to connect to.
    57       * @param port The port on the host.
    58       */
    59      public DatagramOutputStream(final String host, final int port, final byte[] header, final byte[] footer) {
    60          this.port = port;
    61          this.header = header;
    62          this.footer = footer;
    63          try {
    64              address = InetAddress.getByName(host);
    65          } catch (final UnknownHostException ex) {
    66              final String msg = "Could not find host " + host;
    67              LOGGER.error(msg, ex);
    68              throw new AppenderLoggingException(msg, ex);
    69          }
    70
    71          try {
    72              ds = new DatagramSocket();
    73          } catch (final SocketException ex) {
    74              final String msg = "Could not instantiate DatagramSocket to " + host;
    75              LOGGER.error(msg, ex);
    76              throw new AppenderLoggingException(msg, ex);
    77          }
    78      }
    79
    80      @Override
    81      public synchronized void write(final byte[] bytes, final int offset, final int length) throws IOException {
    82          copy(bytes, offset, length);
    83      }
    84
    85      @Override
    86      public synchronized void write(final int i) throws IOException {
    87          copy(new byte[] {(byte) (i >>> SHIFT_3), (byte) (i >>> SHIFT_2), (byte) (i >>> SHIFT_1), (byte) i}, 0, 4);
    88      }
    89
    90      @Override
    91      public synchronized void write(final byte[] bytes) throws IOException {
    92          copy(bytes, 0, bytes.length);
    93      }
    94
    95      @Override
    96      public synchronized void flush() throws IOException {
    97          try {
    98              if (this.data != null && this.ds != null && this.address != null) {
    99                  if (footer != null) {
    100                     copy(footer, 0, footer.length);
    101                 }
    102                 final DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
    103                 ds.send(packet);
    104             }
    105         } finally {
    106             data = null;
    107             if (header != null) {
    108                 copy(header, 0, header.length);
    109             }
    110         }
    111     }
    112
    113     @Override
    114     public synchronized void close() throws IOException {
    115         if (ds != null) {
    116             if (data != null) {
    117                 flush();
    118             }
    119             ds.close();
    120             ds = null;
    121         }
    122     }
    123
    124     private void copy(final byte[] bytes, final int offset, final int length) {
    125         final int index = data == null ? 0 : data.length;
    126         final byte[] copy = new byte[length + index];
    127         if (data != null) {
    128             System.arraycopy(data, 0, copy, 0, data.length);
    129         }
    130         System.arraycopy(bytes, offset, copy, index, length);
    131         data = copy;
    132     }
    133 }