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