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
    18  package org.apache.log4j.net;
    19
    20  import org.apache.log4j.plugins.Pauseable;
    21  import org.apache.log4j.plugins.Plugin;
    22  import org.apache.log4j.plugins.Receiver;
    23  import org.apache.log4j.spi.LoggerRepository;
    24  import org.apache.log4j.spi.LoggingEvent;
    25
    26  import java.net.ServerSocket;
    27  import java.net.Socket;
    28  import java.util.List;
    29  import java.util.Vector;
    30
    31
    32  /**
    33   * XMLSocketReceiver receives a remote logging event via XML on a configured
    34   * socket and "posts" it to a LoggerRepository as if the event were
    35   * generated locally. This class is designed to receive events from
    36   * the XMLSocketAppender class (or classes that send compatible events).
    37   * <p>
    38   * This receiver supports log files created using log4j's XMLLayout, as well as java.util.logging
    39   * XMLFormatter (via the org.apache.log4j.spi.Decoder interface).
    40   * <p>
    41   * By default, log4j's XMLLayout is supported (no need to specify a decoder in that case).
    42   * <p>
    43   * To configure this receiver to support java.util.logging's XMLFormatter, specify a 'decoder' param
    44   * of org.apache.log4j.xml.UtilLoggingXMLDecoder.
    45   * <p>
    46   * Once the event has been "posted", it will be handled by the
    47   * appenders currently configured in the LoggerRespository.
    48   *
    49   * @author Mark Womack
    50   * @author Scott Deboy &lt;sdeboy@apache.org&gt;
    51   */
    52  public class XMLSocketReceiver extends Receiver implements Runnable, PortBased, Pauseable {
    53      private boolean paused;
    54      //default to log4j xml decoder
    55      protected String decoder = "org.apache.log4j.xml.XMLDecoder";
    56      private ServerSocket serverSocket;
    57      private List<Socket> socketList = new Vector<>();
    58      private Thread rThread;
    59      public static final int DEFAULT_PORT = 4448;
    60      protected int port = DEFAULT_PORT;
    61      private boolean advertiseViaMulticastDNS;
    62      private ZeroConfSupport zeroConf;
    63
    64      /**
    65       * The MulticastDNS zone advertised by an XMLSocketReceiver
    66       */
    67      public static final String ZONE = "_log4j_xml_tcpaccept_receiver.local.";
    68
    69      /*
    70       * Log4j doesn't provide an XMLSocketAppender, but the MulticastDNS zone that should be advertised by one is:
    71       * _log4j_xml_tcpconnect_appender.local.
    72       */
    73
    74      public XMLSocketReceiver() {
    75      }
    76
    77      public XMLSocketReceiver(int _port) {
    78          port = _port;
    79      }
    80
    81      public XMLSocketReceiver(int _port, LoggerRepository _repository) {
    82          port = _port;
    83          repository = _repository;
    84      }
    85
    86      /**
    87       * Get the port to receive logging events on.
    88       */
    89      public int getPort() {
    90          return port;
    91      }
    92
    93      /**
    94       * Set the port to receive logging events on.
    95       */
    96      public void setPort(int _port) {
    97          port = _port;
    98      }
    99
    100     public String getDecoder() {
    101         return decoder;
    102     }
    103
    104     /**
    105      * Specify the class name implementing org.apache.log4j.spi.Decoder that can process the file.
    106      */
    107     public void setDecoder(String _decoder) {
    108         decoder = _decoder;
    109     }
    110
    111     public boolean isPaused() {
    112         return paused;
    113     }
    114
    115     public void setPaused(boolean b) {
    116         paused = b;
    117     }
    118
    119     /**
    120      * Returns true if the receiver is the same class and they are
    121      * configured for the same properties, and super class also considers
    122      * them to be equivalent. This is used by PluginRegistry when determining
    123      * if the a similarly configured receiver is being started.
    124      *
    125      * @param testPlugin The plugin to test equivalency against.
    126      * @return boolean True if the testPlugin is equivalent to this plugin.
    127      */
    128     public boolean isEquivalent(Plugin testPlugin) {
    129         if ((testPlugin != null) && testPlugin instanceof XMLSocketReceiver) {
    130             XMLSocketReceiver sReceiver = (XMLSocketReceiver) testPlugin;
    131
    132             return (port == sReceiver.getPort() && super.isEquivalent(testPlugin));
    133         }
    134
    135         return false;
    136     }
    137
    138     public int hashCode() {
    139
    140         int result = 37 * (repository != null ? repository.hashCode() : 0);
    141         result = result * 37 + port;
    142         return (result * 37 + (getName() != null ? getName().hashCode() : 0));
    143     }
    144
    145     /**
    146      * Sets the flag to indicate if receiver is active or not.
    147      *
    148      * @param b new value
    149      */
    150     protected synchronized void setActive(final boolean b) {
    151         active = b;
    152     }
    153
    154     /**
    155      * Starts the XMLSocketReceiver with the current options.
    156      */
    157     public void activateOptions() {
    158         if (!isActive()) {
    159             rThread = new Thread(this);
    160             rThread.setDaemon(true);
    161             rThread.start();
    162
    163             if (advertiseViaMulticastDNS) {
    164                 zeroConf = new ZeroConfSupport(ZONE, port, getName());
    165                 zeroConf.advertise();
    166             }
    167
    168             active = true;
    169         }
    170     }
    171
    172     public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
    173         this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
    174     }
    175
    176     public boolean isAdvertiseViaMulticastDNS() {
    177         return advertiseViaMulticastDNS;
    178     }
    179
    180     /**
    181      * Called when the receiver should be stopped. Closes the
    182      * server socket and all of the open sockets.
    183      */
    184     public synchronized void shutdown() {
    185         // mark this as no longer running
    186         active = false;
    187
    188         if (rThread != null) {
    189             rThread.interrupt();
    190             rThread = null;
    191         }
    192         doShutdown();
    193     }
    194
    195     /**
    196      * Does the actual shutting down by closing the server socket
    197      * and any connected sockets that have been created.
    198      */
    199     private synchronized void doShutdown() {
    200         active = false;
    201
    202         getLogger().debug("{} doShutdown called", getName());
    203
    204         // close the server socket
    205         closeServerSocket();
    206
    207         // close all of the accepted sockets
    208         closeAllAcceptedSockets();
    209
    210         if (advertiseViaMulticastDNS) {
    211             zeroConf.unadvertise();
    212         }
    213     }
    214
    215     /**
    216      * Closes the server socket, if created.
    217      */
    218     private void closeServerSocket() {
    219         getLogger().debug("{} closing server socket", getName());
    220
    221         try {
    222             if (serverSocket != null) {
    223                 serverSocket.close();
    224             }
    225         } catch (Exception e) {
    226             // ignore for now
    227         }
    228
    229         serverSocket = null;
    230     }
    231
    232     /**
    233      * Closes all the connected sockets in the List.
    234      */
    235     private synchronized void closeAllAcceptedSockets() {
    236         for (Object aSocketList : socketList) {
    237             try {
    238                 ((Socket) aSocketList).close();
    239             } catch (Exception e) {
    240                 // ignore for now
    241             }
    242         }
    243
    244         // clear member variables
    245         socketList.clear();
    246     }
    247
    248     /**
    249      * Loop, accepting new socket connections.
    250      */
    251     public void run() {
    252         /**
    253          * Ensure we start fresh.
    254          */
    255         getLogger().debug("performing socket cleanup prior to entering loop for {}", name);
    256         closeServerSocket();
    257         closeAllAcceptedSockets();
    258         getLogger().debug("socket cleanup complete for {}", name);
    259         active = true;
    260
    261         // start the server socket
    262         try {
    263             serverSocket = new ServerSocket(port);
    264         } catch (Exception e) {
    265             getLogger().error(
    266                 "error starting XMLSocketReceiver (" + this.getName()
    267                     + "), receiver did not start", e);
    268             active = false;
    269             doShutdown();
    270
    271             return;
    272         }
    273
    274         Socket socket = null;
    275
    276         try {
    277             getLogger().debug("in run-about to enter while isactiveloop");
    278
    279             active = true;
    280
    281             while (!rThread.isInterrupted()) {
    282                 // if we have a socket, start watching it
    283                 if (socket != null) {
    284                     getLogger().debug("socket not null - creating and starting socketnode");
    285                     socketList.add(socket);
    286
    287                     XMLSocketNode node = new XMLSocketNode(decoder, socket, this);
    288                     node.setLoggerRepository(this.repository);
    289                     new Thread(node).start();
    290                 }
    291
    292                 getLogger().debug("waiting to accept socket");
    293
    294                 // wait for a socket to open, then loop to start it
    295                 socket = serverSocket.accept();
    296                 getLogger().debug("accepted socket");
    297             }
    298
    299             // socket not watched because we a no longer running
    300             // so close it now.
    301             if (socket != null) {
    302                 socket.close();
    303             }
    304         } catch (Exception e) {
    305             getLogger().warn(
    306                 "socket server disconnected, stopping");
    307         }
    308     }
    309
    310     /* (non-Javadoc)
    311      * @see org.apache.log4j.plugins.Receiver#doPost(org.apache.log4j.spi.LoggingEvent)
    312      */
    313     public void doPost(LoggingEvent event) {
    314         if (!isPaused()) {
    315             super.doPost(event);
    316         }
    317     }
    318
    319
    320 }