1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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ülcü
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
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
164
165 LoggerRepository configureHierarchy(InetAddress inetAddress) {
166 cat.info("Locating configuration file for "+inetAddress);
167
168
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 }