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.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  // Contributors:  Moses Hohman <mmhohman@rainbow.uchicago.edu>
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&uuml;lc&uuml;
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           // read an event from the wire
170           event = (LoggingEvent) ois.readObject();
171           event.setProperty(Constants.HOSTNAME_KEY, hostName);
172           // store the known remote info in an event property
173           event.setProperty("log4j.remoteSourceInfo", remoteInfo);
174 
175           // if configured with a receiver, tell it to post the event
176           if (!isPaused()) {
177             if ((receiver != null)) {
178               receiver.doPost(event);
179 
180               // else post it via the hierarchy
181             } else {
182               // get a logger from the hierarchy. The name of the logger
183               // is taken to be the name contained in the event.
184               remoteLogger = repository.getLogger(event.getLoggerName());
185 
186               //event.logger = remoteLogger;
187               // apply the logger-level filter
188               if (event
189                 .getLevel()
190                 .isGreaterOrEqual(remoteLogger.getEffectiveLevel())) {
191                 // finally log the event as if was generated locally
192                 remoteLogger.callAppenders(event);
193               }
194             }
195           } else {
196             //we simply discard this event.
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     // close the socket
216     try {
217       if (ois != null) {
218         ois.close();
219       }
220     } catch (Exception e) {
221       //getLogger().info("Could not close connection.", e);
222     }
223 
224     // send event to listener, if configured
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 }