1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.tools;
21
22
23 import java.util.Hashtable;
24
25 import javax.naming.CommunicationException;
26 import javax.naming.ldap.InitialLdapContext;
27 import javax.naming.ldap.LdapContext;
28
29 import org.apache.commons.cli.CommandLine;
30 import org.apache.commons.cli.Option;
31 import org.apache.commons.cli.Options;
32 import org.apache.directory.daemon.AvailablePortFinder;
33 import org.apache.directory.shared.ldap.message.extended.GracefulShutdownRequest;
34
35
36
37
38
39
40
41
42
43
44
45 public class GracefulShutdownCommand extends ToolCommand
46 {
47 public static final String PORT_RANGE = "(" + AvailablePortFinder.MIN_PORT_NUMBER + ", "
48 + AvailablePortFinder.MAX_PORT_NUMBER + ")";
49
50 private static final int DELAY_MAX = 86400;
51
52 private static final int TIME_OFFLINE_MAX = 720;
53
54 private int port = 10389;
55 private String host = "localhost";
56 private String password = "secret";
57 private int delay;
58 private int timeOffline;
59
60
61 protected GracefulShutdownCommand()
62 {
63 super( "graceful" );
64 }
65
66 private boolean isWaiting;
67 private boolean isSuccess = false;
68 private Thread executeThread = null;
69
70
71 public void execute( CommandLine cmd ) throws Exception
72 {
73 executeThread = Thread.currentThread();
74 processOptions( cmd );
75
76 if ( isDebugEnabled() )
77 {
78 System.out.println( "Parameters for GracefulShutdown extended request:" );
79 System.out.println( "port = " + port );
80 System.out.println( "host = " + host );
81 System.out.println( "password = " + password );
82 System.out.println( "delay = " + delay );
83 System.out.println( "timeOffline = " + timeOffline );
84 }
85
86 Hashtable env = new Hashtable();
87 env.put( "java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory" );
88 env.put( "java.naming.provider.url", "ldap://" + host + ":" + port );
89 env.put( "java.naming.security.principal", "uid=admin,ou=system" );
90 env.put( "java.naming.security.credentials", password );
91 env.put( "java.naming.security.authentication", "simple" );
92
93 LdapContext ctx = new InitialLdapContext( env, null );
94 if ( !isQuietEnabled() )
95 {
96 System.out.println( "Connection to the server established.\n"
97 + "Sending extended request and blocking for shutdown:" );
98 isWaiting = true;
99 Thread t = new Thread( new Ticker() );
100 t.start();
101 }
102 try
103 {
104 ctx.extendedOperation( new GracefulShutdownRequest( 0, timeOffline, delay ) );
105 isSuccess = true;
106 }
107 catch ( Throwable t )
108 {
109
110
111
112
113
114 try
115 {
116 new InitialLdapContext( env, null );
117 isSuccess = false;
118 System.err.print( "shutdown request failed with error: " + t.getMessage() );
119 }
120 catch ( CommunicationException e )
121 {
122 isSuccess = true;
123 }
124 }
125 isWaiting = false;
126 ctx.close();
127 }
128
129 class Ticker implements Runnable
130 {
131 public void run()
132 {
133 if ( !isQuietEnabled() )
134 System.out.print( "[waiting for shutdown] " );
135 while ( isWaiting )
136 {
137 try
138 {
139 Thread.sleep( 1000 );
140 }
141 catch ( InterruptedException e )
142 {
143
144 e.printStackTrace();
145 }
146 if ( !isQuietEnabled() )
147 System.out.print( "." );
148 }
149 if ( isSuccess )
150 {
151 if ( !isQuietEnabled() )
152 System.out.println( "\n[shutdown complete]" );
153 try
154 {
155 executeThread.join( 1000 );
156 }
157 catch ( InterruptedException e )
158 {
159 e.printStackTrace();
160 }
161 System.exit( 0 );
162 }
163 else
164 {
165 if ( !isQuietEnabled() )
166 System.out.println( "\n[shutdown failed]" );
167 try
168 {
169 executeThread.join( 1000 );
170 }
171 catch ( InterruptedException e )
172 {
173 e.printStackTrace();
174 }
175 System.exit( 1 );
176 }
177 }
178 }
179
180
181 private void processOptions( CommandLine cmd )
182 {
183 if ( isDebugEnabled() )
184 {
185 System.out.println( "Processing options for graceful shutdown ..." );
186 }
187
188
189
190
191
192 if ( cmd.hasOption( 'p' ) )
193 {
194 String val = cmd.getOptionValue( 'p' );
195 try
196 {
197 port = Integer.parseInt( val );
198 }
199 catch ( NumberFormatException e )
200 {
201 System.err.println( "port value of '" + val + "' is not a number" );
202 System.exit( 1 );
203 }
204
205 if ( port > AvailablePortFinder.MAX_PORT_NUMBER )
206 {
207 System.err.println( "port value of '" + val + "' is larger than max port number: "
208 + AvailablePortFinder.MAX_PORT_NUMBER );
209 System.exit( 1 );
210 }
211 else if ( port < AvailablePortFinder.MIN_PORT_NUMBER )
212 {
213 System.err.println( "port value of '" + val + "' is smaller than the minimum port number: "
214 + AvailablePortFinder.MIN_PORT_NUMBER );
215 System.exit( 1 );
216 }
217
218 if ( isDebugEnabled() )
219 {
220 System.out.println( "port overriden by -p option: " + port );
221 }
222 }
223 else if ( getApacheDS() != null )
224 {
225 port = getApacheDS().getLdapService().getIpPort();
226
227 if ( isDebugEnabled() )
228 {
229 System.out.println( "port overriden by server.xml configuration: " + port );
230 }
231 }
232 else if ( isDebugEnabled() )
233 {
234 System.out.println( "port set to default: " + port );
235 }
236
237
238
239
240
241 if ( cmd.hasOption( 'h' ) )
242 {
243 host = cmd.getOptionValue( 'h' );
244
245 if ( isDebugEnabled() )
246 {
247 System.out.println( "host overriden by -h option: " + host );
248 }
249 }
250 else if ( isDebugEnabled() )
251 {
252 System.out.println( "host set to default: " + host );
253 }
254
255
256
257
258
259 if ( cmd.hasOption( 'w' ) )
260 {
261 password = cmd.getOptionValue( 'w' );
262
263 if ( isDebugEnabled() )
264 {
265 System.out.println( "password overriden by -w option: " + password );
266 }
267 }
268 else if ( isDebugEnabled() )
269 {
270 System.out.println( "password set to default: " + password );
271 }
272
273
274
275
276
277 if ( cmd.hasOption( 'e' ) )
278 {
279 String val = cmd.getOptionValue( 'e' );
280 try
281 {
282 delay = Integer.parseInt( val );
283 }
284 catch ( NumberFormatException e )
285 {
286 System.err.println( "delay value of '" + val + "' is not a number" );
287 System.exit( 1 );
288 }
289
290 if ( delay > DELAY_MAX )
291 {
292 System.err.println( "delay value of '" + val + "' is larger than max delay (seconds) allowed: "
293 + DELAY_MAX );
294 System.exit( 1 );
295 }
296 else if ( delay < 0 )
297 {
298 System.err.println( "delay value of '" + val + "' is less than zero and makes no sense" );
299 System.exit( 1 );
300 }
301
302 if ( isDebugEnabled() )
303 {
304 System.out.println( "delay seconds overriden by -e option: " + delay );
305 }
306 }
307 else if ( isDebugEnabled() )
308 {
309 System.out.println( "Using default delay value of " + delay );
310 }
311
312
313
314
315
316 if ( cmd.hasOption( 't' ) )
317 {
318 String val = cmd.getOptionValue( 't' );
319 try
320 {
321 timeOffline = Integer.parseInt( val );
322 }
323 catch ( NumberFormatException e )
324 {
325 System.err.println( "timeOffline value of '" + val + "' is not a number" );
326 System.exit( 1 );
327 }
328
329 if ( timeOffline > TIME_OFFLINE_MAX )
330 {
331 System.err.println( "timeOffline value of '" + val
332 + "' is larger than max timeOffline (minutes) allowed: " + TIME_OFFLINE_MAX );
333 System.exit( 1 );
334 }
335 else if ( timeOffline < 0 )
336 {
337 System.err.println( "timeOffline value of '" + val + "' is less than zero and makes no sense" );
338 System.exit( 1 );
339 }
340
341 if ( isDebugEnabled() )
342 {
343 System.out.println( "timeOffline seconds overriden by -t option: " + timeOffline );
344 }
345 }
346 else if ( isDebugEnabled() )
347 {
348 System.out.println( "Using default timeOffline value of " + delay );
349 }
350 }
351
352
353 public Options getOptions()
354 {
355 Options opts = new Options();
356 Option op = new Option( "h", "host", true, "server host: defaults to localhost" );
357 op.setRequired( false );
358 opts.addOption( op );
359 op = new Option( "p", "port", true, "server port: defaults to 10389 or server.xml specified port" );
360 op.setRequired( false );
361 opts.addOption( op );
362 op = new Option( "e", "delay", true, "delay (seconds) before shutdown: defaults to 0" );
363 op.setRequired( false );
364 opts.addOption( op );
365 op = new Option( "w", "password", true, "the apacheds administrator's password: defaults to secret" );
366 op.setRequired( false );
367 opts.addOption( op );
368 op = new Option( "t", "time-offline", true, "server offline time (minutes): defaults to 0 (indefinate)" );
369 op.setRequired( false );
370 opts.addOption( op );
371 op = new Option( "i", "install-path", true, "path to apacheds installation directory" );
372 op.setRequired( false );
373 opts.addOption( op );
374 return opts;
375 }
376 }