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.io.BufferedInputStream;
21 import java.io.IOException;
22 import java.io.ObjectInputStream;
23 import java.net.Socket;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.Iterator;
27 import java.util.List;
28
29 import org.apache.log4j.Logger;
30 import org.apache.log4j.helpers.Constants;
31 import org.apache.log4j.plugins.Pauseable;
32 import org.apache.log4j.plugins.Receiver;
33 import org.apache.log4j.spi.ComponentBase;
34 import org.apache.log4j.spi.LoggerRepository;
35 import org.apache.log4j.spi.LoggingEvent;
36
37
38
39
40 /***
41 Read {@link LoggingEvent} objects sent from a remote client using
42 Sockets (TCP). These logging events are logged according to local
43 policy, as if they were generated locally.
44
45 <p>For example, the socket node might decide to log events to a
46 local file and also resent them to a second socket node.
47
48 Implementation lifted from org.apache.log4j.net.SocketNode
49 in log4j 1.3 and renamed to prevent collision with
50 log4j 1.2 implementation.
51
52 @author Ceki Gülcü
53 @author Paul Smith (psmith@apache.org)
54
55
56 */
57 public class SocketNode13 extends ComponentBase implements Runnable, Pauseable {
58
59 /***
60 * Paused state.
61 */
62 private boolean paused;
63 /***
64 * Socket.
65 */
66 private Socket socket;
67 /***
68 * Receiver.
69 */
70 private Receiver receiver;
71 /***
72 * List of listeners.
73 */
74 private List listenerList = Collections.synchronizedList(new ArrayList());
75
76
77
78 /***
79 Constructor for socket and logger repository.
80 @param s socket
81 @param hierarchy logger repository
82 */
83 public SocketNode13(final Socket s,
84 final LoggerRepository hierarchy) {
85 super();
86 this.socket = s;
87 this.repository = hierarchy;
88 }
89
90 /***
91 Constructor for socket and receiver.
92 @param s socket
93 @param r receiver
94 */
95 public SocketNode13(final Socket s, final Receiver r) {
96 super();
97 this.socket = s;
98 this.receiver = r;
99 }
100
101 /***
102 * Set the event listener on this node.
103 *
104 * @deprecated Now supports mutliple listeners, this method
105 * simply invokes the removeSocketNodeEventListener() to remove
106 * the listener, and then readds it.
107 * @param l listener
108 */
109 public void setListener(final SocketNodeEventListener l) {
110 removeSocketNodeEventListener(l);
111 addSocketNodeEventListener(l);
112 }
113
114 /***
115 * Adds the listener to the list of listeners to be notified of the
116 * respective event.
117 * @param listener the listener to add to the list
118 */
119 public void addSocketNodeEventListener(
120 final SocketNodeEventListener listener) {
121 listenerList.add(listener);
122 }
123
124 /***
125 * Removes the registered Listener from this instances list of
126 * listeners. If the listener has not been registered, then invoking
127 * this method has no effect.
128 *
129 * @param listener the SocketNodeEventListener to remove
130 */
131 public void removeSocketNodeEventListener(
132 final SocketNodeEventListener listener) {
133 listenerList.remove(listener);
134 }
135
136
137 /***
138 * Deserialize events from socket until interrupted.
139 */
140 public void run() {
141 LoggingEvent event;
142 Logger remoteLogger;
143 Exception listenerException = null;
144 ObjectInputStream ois = null;
145
146 try {
147 ois =
148 new ObjectInputStream(
149 new BufferedInputStream(socket.getInputStream()));
150 } catch (Exception e) {
151 ois = null;
152 listenerException = e;
153 getLogger().error("Exception opening ObjectInputStream to " + socket, e);
154 }
155
156 if (ois != null) {
157
158 String hostName = socket.getInetAddress().getHostName();
159 String remoteInfo = hostName + ":" + socket.getPort();
160
161 /***
162 * notify the listener that the socket has been
163 * opened and this SocketNode is ready and waiting
164 */
165 fireSocketOpened(remoteInfo);
166
167 try {
168 while (true) {
169
170 event = (LoggingEvent) ois.readObject();
171 event.setProperty(Constants.HOSTNAME_KEY, hostName);
172
173 event.setProperty("log4j.remoteSourceInfo", remoteInfo);
174
175
176 if (!isPaused()) {
177 if ((receiver != null)) {
178 receiver.doPost(event);
179
180
181 } else {
182
183
184 remoteLogger = repository.getLogger(event.getLoggerName());
185
186
187
188 if (event
189 .getLevel()
190 .isGreaterOrEqual(remoteLogger.getEffectiveLevel())) {
191
192 remoteLogger.callAppenders(event);
193 }
194 }
195 } else {
196
197 }
198 }
199 } catch (java.io.EOFException e) {
200 getLogger().info("Caught java.io.EOFException closing connection.");
201 listenerException = e;
202 } catch (java.net.SocketException e) {
203 getLogger().info("Caught java.net.SocketException closing connection.");
204 listenerException = e;
205 } catch (IOException e) {
206 getLogger().info("Caught java.io.IOException: " + e);
207 getLogger().info("Closing connection.");
208 listenerException = e;
209 } catch (Exception e) {
210 getLogger().error("Unexpected exception. Closing connection.", e);
211 listenerException = e;
212 }
213 }
214
215
216 try {
217 if (ois != null) {
218 ois.close();
219 }
220 } catch (Exception e) {
221
222 }
223
224
225 if (listenerList.size() > 0) {
226 fireSocketClosedEvent(listenerException);
227 }
228 }
229
230 /***
231 * Notifies all registered listeners regarding the closing of the Socket.
232 * @param listenerException listener exception
233 */
234 private void fireSocketClosedEvent(final Exception listenerException) {
235 synchronized (listenerList) {
236 for (Iterator iter = listenerList.iterator(); iter.hasNext();) {
237 SocketNodeEventListener snel =
238 (SocketNodeEventListener) iter.next();
239 if (snel != null) {
240 snel.socketClosedEvent(listenerException);
241 }
242 }
243 }
244 }
245
246 /***
247 * Notifies all registered listeners regarding the opening of a Socket.
248 * @param remoteInfo remote info
249 */
250 private void fireSocketOpened(final String remoteInfo) {
251 synchronized (listenerList) {
252 for (Iterator iter = listenerList.iterator(); iter.hasNext();) {
253 SocketNodeEventListener snel =
254 (SocketNodeEventListener) iter.next();
255 if (snel != null) {
256 snel.socketOpened(remoteInfo);
257 }
258 }
259 }
260 }
261
262 /***
263 * Sets if node is paused.
264 * @param b new value
265 */
266 public void setPaused(final boolean b) {
267 this.paused = b;
268 }
269
270 /***
271 * Get if node is paused.
272 * @return true if pause.
273 */
274 public boolean isPaused() {
275 return this.paused;
276 }
277 }