1 /*******************************************************************************
2 
3     Set of files which are reopened upon calling the reopenAll() method. The
4     extension cooperates with the SignalExt, allowing the registered set of
5     files to be reopened when a specific signal is received by the application.
6     The constructor provides a convenient means to configure this behaviour.
7 
8     Copyright:
9         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
10         All rights reserved.
11 
12     License:
13         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
14         Alternatively, this file may be distributed under the terms of the Tango
15         3-Clause BSD License (see LICENSE_BSD.txt for details).
16 
17 *******************************************************************************/
18 
19 module ocean.util.app.ext.ReopenableFilesExt;
20 
21 
22 
23 
24 import ocean.meta.types.Qualifiers;
25 
26 import ocean.core.Verify;
27 
28 import ocean.util.app.model.IApplication;
29 import ocean.util.app.model.IApplicationExtension;
30 
31 import ocean.util.app.ext.SignalExt;
32 import ocean.util.app.ext.UnixSocketExt;
33 
34 import ocean.util.app.ext.model.ISignalExtExtension;
35 
36 import core.sys.posix.signal : SIGHUP;
37 
38 import ocean.io.device.File;
39 
40 
41 public class ReopenableFilesExt : IApplicationExtension, ISignalExtExtension
42 {
43     import ocean.application.components.OpenFiles;
44 
45     /// TODO
46     private OpenFiles files;
47 
48 
49     /***************************************************************************
50 
51         The code of the signal to trigger reopening the files, when used with
52         the SignalExt. See onSignal().
53 
54     ***************************************************************************/
55 
56     private int reopen_signal;
57 
58 
59     /***************************************************************************
60 
61         Constructor.
62 
63         Optionally registers this extension with the signal extension and
64         activates the handling of the specified signal, which will cause the
65         registered files to be reopened. For this to happen, a non-null
66         `signal_ext` and a non-zero `reopen_signal` must be supplied.
67 
68         Params:
69             signal_ext = SignalExt instance to register with (defaults to null)
70             reopen_signal = signal to trigger reopening of registered files
71                 (defaults to SIGHUP, and considered only if non-zero and
72                 `signal_ext` is non-null)
73 
74     ***************************************************************************/
75 
76     public this ( SignalExt signal_ext = null, int reopen_signal = SIGHUP )
77     {
78         this.files = new OpenFiles;
79 
80         if (signal_ext && reopen_signal)
81         {
82             this.setupSignalHandler(signal_ext, reopen_signal);
83         }
84     }
85 
86 
87     /***************************************************************************
88 
89         Registers this extension with the signal extension and activates the
90         handling of the specified signal, which will cause the registered files
91         to be reopened.
92 
93         Params:
94             signal_ext = SignalExt instance
95             reopen_signal = signal to trigger reopening of registered files
96 
97     ***************************************************************************/
98 
99     public void setupSignalHandler ( SignalExt signal_ext,
100             int reopen_signal = SIGHUP )
101     {
102         verify(signal_ext !is null);
103         verify(this.reopen_signal == this.reopen_signal.init,
104             "Either pass SignalExt to constructor or to setupSignalHandler, " ~
105             "not to both.");
106 
107         this.reopen_signal = reopen_signal;
108         signal_ext.register(this.reopen_signal);
109         signal_ext.registerExtension(this);
110     }
111 
112 
113     /***************************************************************************
114 
115         Registers this extension with the unix socket extension and activates the
116         handling of the specified unix socket command, which will cause reopening
117         files specified as arguments to the command.
118 
119         Params:
120             unix_socket_ext = UnixSocketExt instance to register with
121             reopen_command = command to trigger reopening of the registered
122                 file (passed as arguments to the command).
123 
124     ***************************************************************************/
125 
126     public void setupUnixSocketHandler ( UnixSocketExt unix_socket_ext,
127             istring reopen_command = "reopen_files" )
128     {
129         verify(unix_socket_ext !is null);
130 
131         unix_socket_ext.addHandler(reopen_command,
132             &this.socketReloadCommand);
133     }
134 
135 
136     /***************************************************************************
137 
138         Registers the specified file, to be reopened when reopenAll() is called.
139 
140         Params:
141             file = file to add to the set of reopenable files
142 
143     ***************************************************************************/
144 
145     public void register ( File file )
146     {
147         this.files.register(file);
148     }
149 
150 
151     /***************************************************************************
152 
153         Reopens all registered files.
154 
155     ***************************************************************************/
156 
157     public void reopenAll ( )
158     {
159         this.files.reopenAll();
160     }
161 
162 
163     /***************************************************************************
164 
165         Reopens all registered files with the given path
166 
167         Params:
168             file_path = path of the file to open
169 
170         Returns:
171             true if the file was registered and reopen, false otherwise.
172 
173     ***************************************************************************/
174 
175     public bool reopenFile ( cstring file_path )
176     {
177         return this.files.reopenFile(file_path);
178     }
179 
180     /***************************************************************************
181 
182         Signal handler. Called by SignalExt when a signal occurs. Reopens all
183         log files.
184 
185         Params:
186             signal = signal which fired
187 
188     ***************************************************************************/
189 
190     public void onSignal ( int signal )
191     {
192         if ( signal == this.reopen_signal )
193         {
194             this.reopenAll();
195         }
196     }
197 
198     /****************************************************************************
199 
200         Reopen command to trigger from the Unix Domain socket. It reads
201         the file names to reload and reloads the appropriate files.
202 
203         Params:
204             args = list of arguments received from the socket - should contain
205                    names of the files to rotate.
206             send_response = delegate to send the response to the client
207 
208     *****************************************************************************/
209 
210     private void socketReloadCommand ( cstring[] args,
211             scope void delegate ( cstring response ) send_response )
212     {
213         if (args.length == 0)
214         {
215             send_response("ERROR: missing name of the file to rotate.\n");
216             return;
217         }
218 
219         foreach (filename; args)
220         {
221             if (!this.reopenFile(filename))
222             {
223                 send_response("ERROR: Could not rotate the file '");
224                 send_response(filename);
225                 send_response("'\n");
226                 return;
227             }
228         }
229 
230         send_response("ACK\n");
231     }
232 
233     /***************************************************************************
234 
235         Required by ISignalExtExtension.
236 
237         Returns:
238             a number to provide ordering to extensions
239 
240     ***************************************************************************/
241 
242     override public int order ( )
243     {
244         return -1;
245     }
246 
247 
248     /***************************************************************************
249 
250         Unused IApplicationExtension method.
251 
252         We just need to provide an "empty" implementation to satisfy the
253         interface.
254 
255     ***************************************************************************/
256 
257     override public void preRun ( IApplication app, istring[] args )
258     {
259         // Unused
260     }
261 
262 
263     /// ditto
264     override public void postRun ( IApplication app, istring[] args, int status )
265     {
266         // Unused
267     }
268 
269 
270     /// ditto
271     override public void atExit ( IApplication app, istring[] args, int status,
272             ExitException exception )
273     {
274         // Unused
275     }
276 
277 
278     /// ditto
279     override public ExitException onExitException ( IApplication app, istring[] args,
280             ExitException exception )
281     {
282         // Unused
283         return exception;
284     }
285 }