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.Socket;
    21  import java.net.ServerSocket;
    22  import java.net.InetAddress;
    23  import java.io.File;
    24  import java.util.Hashtable;
    25
    26  import org.apache.log4j.*;
    27  import org.apache.log4j.spi.*;
    28
    29
    30  /***
    31     A {@link SocketNode} based server that uses a different hierarchy
    32     for each client.
    33
    34     <pre>
    35       <b>Usage:</b> java org.apache.log4j.net.SocketServer port configFile configDir
    36
    37       where <b>port</b> is a part number where the server listens,
    38             <b>configFile</b> is a configuration file fed to the {@link PropertyConfigurator} and
    39             <b>configDir</b> is a path to a directory containing configuration files, possibly one for each client host.
    40       </pre>
    41
    42       <p>The <code>configFile</code> is used to configure the log4j
    43       default hierarchy that the <code>SocketServer</code> will use to
    44       report on its actions.
    45
    46       <p>When a new connection is opened from a previously unknown
    47       host, say <code>foo.bar.net</code>, then the
    48       <code>SocketServer</code> will search for a configuration file
    49       called <code>foo.bar.net.lcf</code> under the directory
    50       <code>configDir</code> that was passed as the third argument. If
    51       the file can be found, then a new hierarchy is instantiated and
    52       configured using the configuration file
    53       <code>foo.bar.net.lcf</code>. If and when the host
    54       <code>foo.bar.net</code> opens another connection to the server,
    55       then the previously configured hierarchy is used.
    56
    57       <p>In case there is no file called <code>foo.bar.net.lcf</code>
    58       under the directory <code>configDir</code>, then the
    59       <em>generic</em> hierarchy is used. The generic hierarchy is
    60       configured using a configuration file called
    61       <code>generic.lcf</code> under the <code>configDir</code>
    62       directory. If no such file exists, then the generic hierarchy will be
    63       identical to the log4j default hierarchy.
    64
    65       <p>Having different client hosts log using different hierarchies
    66       ensures the total independence of the clients with respect to
    67       their logging settings.
    68
    69       <p>Currently, the hierarchy that will be used for a given request
    70       depends on the IP address of the client host. For example, two
    71       separate applicatons running on the same host and logging to the
    72       same server will share the same hierarchy. This is perfectly safe
    73       except that it might not provide the right amount of independence
    74       between applications. The <code>SocketServer</code> is intended
    75       as an example to be enhanced in order to implement more elaborate
    76       policies.
    77
    78
    79      @author  Ceki G&uuml;lc&uuml;
    80
    81      @since 1.0 */
    82
    83  public class SocketServer  {
    84
    85    static String GENERIC = "generic";
    86    static String CONFIG_FILE_EXT = ".lcf";
    87
    88    static Logger cat = Logger.getLogger(SocketServer.class);
    89    static SocketServer server;
    90    static int port;
    91
    92    // key=inetAddress, value=hierarchy
    93    Hashtable hierarchyMap;
    94    LoggerRepository genericHierarchy;
    95    File dir;
    96
    97    public
    98    static
    99    void main(String argv[]) {
    100     if(argv.length == 3)
    101       init(argv[0], argv[1], argv[2]);
    102     else
    103       usage("Wrong number of arguments.");
    104
    105     try {
    106       cat.info("Listening on port " + port);
    107       ServerSocket serverSocket = new ServerSocket(port);
    108       while(true) {
    109 	cat.info("Waiting to accept a new client.");
    110 	Socket socket = serverSocket.accept();
    111 	InetAddress inetAddress =  socket.getInetAddress();
    112 	cat.info("Connected to client at " + inetAddress);
    113
    114 	LoggerRepository h = (LoggerRepository) server.hierarchyMap.get(inetAddress);
    115 	if(h == null) {
    116 	  h = server.configureHierarchy(inetAddress);
    117 	}
    118
    119 	cat.info("Starting new socket node.");
    120 	new Thread(new SocketNode(socket, h)).start();
    121       }
    122     }
    123     catch(Exception e) {
    124       e.printStackTrace();
    125     }
    126   }
    127
    128
    129   static
    130   void  usage(String msg) {
    131     System.err.println(msg);
    132     System.err.println(
    133       "Usage: java " +SocketServer.class.getName() + " port configFile directory");
    134     System.exit(1);
    135   }
    136
    137   static
    138   void init(String portStr, String configFile, String dirStr) {
    139     try {
    140       port = Integer.parseInt(portStr);
    141     }
    142     catch(java.lang.NumberFormatException e) {
    143       e.printStackTrace();
    144       usage("Could not interpret port number ["+ portStr +"].");
    145     }
    146
    147     PropertyConfigurator.configure(configFile);
    148
    149     File dir = new File(dirStr);
    150     if(!dir.isDirectory()) {
    151       usage("["+dirStr+"] is not a directory.");
    152     }
    153     server = new SocketServer(dir);
    154   }
    155
    156
    157   public
    158   SocketServer(File directory) {
    159     this.dir = directory;
    160     hierarchyMap = new Hashtable(11);
    161   }
    162
    163   // This method assumes that there is no hiearchy for inetAddress
    164   // yet. It will configure one and return it.
    165   LoggerRepository configureHierarchy(InetAddress inetAddress) {
    166     cat.info("Locating configuration file for "+inetAddress);
    167     // We assume that the toSting method of InetAddress returns is in
    168     // the format hostname/d1.d2.d3.d4 e.g. torino/192.168.1.1
    169     String s = inetAddress.toString();
    170     int i = s.indexOf("/");
    171     if(i == -1) {
    172       cat.warn("Could not parse the inetAddress ["+inetAddress+
    173 	       "]. Using default hierarchy.");
    174       return genericHierarchy();
    175     } else {
    176       String key = s.substring(0, i);
    177
    178       File configFile = new File(dir, key+CONFIG_FILE_EXT);
    179       if(configFile.exists()) {
    180 	Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG));
    181 	hierarchyMap.put(inetAddress, h);
    182
    183 	new PropertyConfigurator().doConfigure(configFile.getAbsolutePath(), h);
    184
    185 	return h;
    186       } else {
    187 	cat.warn("Could not find config file ["+configFile+"].");
    188 	return genericHierarchy();
    189       }
    190     }
    191   }
    192
    193   LoggerRepository  genericHierarchy() {
    194     if(genericHierarchy == null) {
    195       File f = new File(dir, GENERIC+CONFIG_FILE_EXT);
    196       if(f.exists()) {
    197 	genericHierarchy = new Hierarchy(new RootLogger(Level.DEBUG));
    198 	new PropertyConfigurator().doConfigure(f.getAbsolutePath(), genericHierarchy);
    199       } else {
    200 	cat.warn("Could not find config file ["+f+
    201 		 "]. Will use the default hierarchy.");
    202 	genericHierarchy = LogManager.getLoggerRepository();
    203       }
    204     }
    205     return genericHierarchy;
    206   }
    207 }