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.varia;
19  
20  import org.apache.log4j.RollingFileAppender;
21  import org.apache.log4j.helpers.LogLog;
22  
23  import java.io.DataInputStream;
24  import java.io.DataOutputStream;
25  import java.net.ServerSocket;
26  import java.net.Socket;
27  
28  /***
29     This appender listens on a socket on the port specified by the
30     <b>Port</b> property for a "RollOver" message. When such a message
31     is received, the underlying log file is rolled over and an
32     acknowledgment message is sent back to the process initiating the
33     roll over.
34  
35     <p>This method of triggering roll over has the advantage of being
36     operating system independent, fast and reliable.
37  
38     <p>A simple application {@link Roller} is provided to initiate the
39     roll over.
40  
41     <p>Note that the initiator is not authenticated. Anyone can trigger
42     a rollover. In production environments, it is recommended that you
43     add some form of protection to prevent undesired rollovers.
44  
45  
46     @author Ceki G&uuml;lc&uuml;
47     @since version 0.9.0 */
48  public class ExternallyRolledFileAppender extends RollingFileAppender {
49  
50    /***
51       The string constant sent to initiate a roll over.   Current value of
52       this string constant is <b>RollOver</b>.
53    */
54    static final public String ROLL_OVER = "RollOver";
55  
56    /***
57       The string constant sent to acknowledge a roll over.   Current value of
58        this string constant is <b>OK</b>.
59    */
60    static final public String OK = "OK";
61  
62    int port = 0;
63    HUP hup;
64  
65    /***
66       The default constructor does nothing but calls its super-class
67       constructor.  */
68    public
69    ExternallyRolledFileAppender() {
70    }
71  
72    /***
73       The <b>Port</b> [roperty is used for setting the port for
74       listening to external roll over messages.
75    */
76    public
77    void setPort(int port) {
78      this.port = port;
79    }
80  
81    /***
82       Returns value of the <b>Port</b> option.
83     */
84    public
85    int getPort() {
86      return port;
87    }
88  
89    /***
90       Start listening on the port specified by a preceding call to
91       {@link #setPort}.  */
92    public
93    void activateOptions() {
94      super.activateOptions();
95      if(port != 0) {
96        if(hup != null) {
97  	hup.interrupt();
98        }
99        hup = new HUP(this, port);
100       hup.setDaemon(true);
101       hup.start();
102     }
103   }
104 }
105 
106 
107 class HUP extends Thread {
108 
109   int port;
110   ExternallyRolledFileAppender er;
111 
112   HUP(ExternallyRolledFileAppender er, int port) {
113     this.er = er;
114     this.port = port;
115   }
116 
117   public
118   void run() {
119     while(!isInterrupted()) {
120       try {
121 	ServerSocket serverSocket = new ServerSocket(port);
122 	while(true) {
123 	  Socket socket = serverSocket.accept();
124 	  LogLog.debug("Connected to client at " + socket.getInetAddress());
125 	  new Thread(new HUPNode(socket, er)).start();
126 	}
127       }
128       catch(Exception e) {
129 	e.printStackTrace();
130       }
131     }
132   }
133 }
134 
135 class HUPNode implements Runnable {
136 
137   Socket socket;
138   DataInputStream dis;
139   DataOutputStream dos;
140   ExternallyRolledFileAppender er;
141 
142   public
143   HUPNode(Socket socket, ExternallyRolledFileAppender er) {
144     this.socket = socket;
145     this.er = er;
146     try {
147       dis = new DataInputStream(socket.getInputStream());
148       dos = new DataOutputStream(socket.getOutputStream());
149     }
150     catch(Exception e) {
151       e.printStackTrace();
152     }
153   }
154 
155   public void run() {
156     try {
157       String line = dis.readUTF();
158       LogLog.debug("Got external roll over signal.");
159       if(ExternallyRolledFileAppender.ROLL_OVER.equals(line)) {
160 	synchronized(er) {
161 	  er.rollOver();
162 	}
163 	dos.writeUTF(ExternallyRolledFileAppender.OK);
164       }
165       else {
166 	dos.writeUTF("Expecting [RollOver] string.");
167       }
168       dos.close();
169     }
170     catch(Exception e) {
171       LogLog.error("Unexpected exception. Exiting HUPNode.", e);
172     }
173   }
174 }
175