View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.tools;
21  
22  
23  import java.util.Hashtable;
24  
25  import javax.naming.directory.SearchControls;
26  import javax.naming.event.EventContext;
27  import javax.naming.event.NamingExceptionEvent;
28  import javax.naming.ldap.InitialLdapContext;
29  import javax.naming.ldap.LdapContext;
30  import javax.naming.ldap.UnsolicitedNotification;
31  import javax.naming.ldap.UnsolicitedNotificationEvent;
32  import javax.naming.ldap.UnsolicitedNotificationListener;
33  
34  import org.apache.commons.cli.CommandLine;
35  import org.apache.commons.cli.Option;
36  import org.apache.commons.cli.Options;
37  import org.apache.directory.daemon.AvailablePortFinder;
38  import org.apache.directory.shared.asn1.codec.DecoderException;
39  import org.apache.directory.shared.ldap.message.extended.GracefulDisconnect;
40  import org.apache.directory.shared.ldap.message.extended.NoticeOfDisconnect;
41  
42  
43  /**
44   * Responds to unsolicited notifications by launching an external process.  Also 
45   * reconnects to the server an launches another process to notify that the server
46   * is back up.
47   * 
48   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
49   * @version $Rev: 434420 $
50   */
51  public class DisconnectNotificationCommand extends ToolCommand implements UnsolicitedNotificationListener
52  {
53      UnsolicitedNotification notification;
54      boolean canceled = false;
55      private String host = "localhost";
56      private int port = 10389;
57      private String bindDn = "uid=admin,ou=system";
58      private String password = "secret";
59  
60  
61      //    private String shutdownCommand = "echo"; 
62      //    private String[] shutdownCommandArgs = new String[] { 
63      //        "server $HOST:$PORT will shutdown for $OFFLINE minutes in $DELAY seconds" };
64  
65      protected DisconnectNotificationCommand()
66      {
67          super( "notifications" );
68      }
69  
70  
71      public void notificationReceived( UnsolicitedNotificationEvent evt )
72      {
73          notification = evt.getNotification();
74  
75          if ( notification.getID().equals( NoticeOfDisconnect.EXTENSION_OID ) )
76          {
77              System.out.println( "\nRecieved NoticeOfDisconnect: " + NoticeOfDisconnect.EXTENSION_OID );
78              System.out.println( "Expect to loose this connection without further information." );
79              canceled = true;
80          }
81          else if ( notification.getID().equals( GracefulDisconnect.EXTENSION_OID ) )
82          {
83              System.out.println( "Recieved GracefulDisconnect: " + GracefulDisconnect.EXTENSION_OID );
84              GracefulDisconnect gd = null;
85  
86              try
87              {
88                  gd = new GracefulDisconnect( notification.getEncodedValue() );
89              }
90              catch ( DecoderException de )
91              {
92                  // TODO Auto-generated catch block
93                  de.printStackTrace();
94              }
95  
96              System.out.println( "LDAP server will shutdown in " + gd.getDelay() + " seconds." );
97              System.out.println( "LDAP server will be back online in " + gd.getTimeOffline() + " minutes." );
98  
99              if ( gd.getDelay() > 0 )
100             {
101                 Thread t = new Thread( new Counter( gd.getDelay() ) );
102                 t.start();
103             }
104         }
105         else
106         {
107             System.out.println( "Unknown event recieved with OID: " + evt.getNotification().getID() );
108         }
109     }
110 
111 
112     public void namingExceptionThrown( NamingExceptionEvent evt )
113     {
114         canceled = true;
115         System.out.println( "Got an excption event: " + evt.getException().getMessage() );
116         System.out.println( "Process shutting down abruptly." );
117         System.exit( 1 );
118     }
119 
120     class Counter implements Runnable
121     {
122         int delay;
123 
124 
125         Counter( int delay )
126         {
127             this.delay = delay;
128         }
129 
130 
131         public void run()
132         {
133             System.out.println( "Starting countdown until server shutdown:" );
134             System.out.print( "[" );
135             long delayMillis = delay * 1000 - 1000; // 1000 is for setup costs
136             long startTime = System.currentTimeMillis();
137             while ( System.currentTimeMillis() - startTime < delayMillis && !canceled )
138             {
139                 try
140                 {
141                     Thread.sleep( 1000 );
142                 }
143                 catch ( InterruptedException e )
144                 {
145                 }
146                 System.out.print( "." );
147             }
148 
149             if ( canceled )
150             {
151                 System.out.println( " -- countdown canceled -- " );
152             }
153             else
154             {
155                 System.out.println( "]" );
156                 System.out.println( "Client shutting down gracefully." );
157                 System.exit( 0 );
158             }
159         }
160     }
161 
162 
163     public void execute( CommandLine cmd ) throws Exception
164     {
165         processOptions( cmd );
166 
167         Hashtable env = new Hashtable();
168         env.put( "java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory" );
169         env.put( "java.naming.provider.url", "ldap://" + host + ":" + port );
170         env.put( "java.naming.security.principal", bindDn );
171         env.put( "java.naming.security.credentials", password );
172         env.put( "java.naming.security.authentication", "simple" );
173 
174         LdapContext ctx = new InitialLdapContext( env, null );
175         ctx = ctx.newInstance( null );
176         UnsolicitedNotificationListener listener = new DisconnectNotificationCommand();
177         ( ( EventContext ) ctx ).addNamingListener( "", SearchControls.SUBTREE_SCOPE, listener );
178 
179         System.out.println( "Listening for notifications." );
180         System.out.println( "Press any key to terminate." );
181         System.in.read();
182         ctx.close();
183         System.out.println( "Process terminated!!!" );
184     }
185 
186 
187     private void processOptions( CommandLine cmd )
188     {
189         if ( isDebugEnabled() )
190         {
191             System.out.println( "Processing options for disconnect notifications ..." );
192         }
193 
194         // -------------------------------------------------------------------
195         // figure out and error check the port value
196         // -------------------------------------------------------------------
197 
198         if ( cmd.hasOption( 'p' ) ) // - user provided port w/ -p takes precedence
199         {
200             String val = cmd.getOptionValue( 'p' );
201             try
202             {
203                 port = Integer.parseInt( val );
204             }
205             catch ( NumberFormatException e )
206             {
207                 System.err.println( "port value of '" + val + "' is not a number" );
208                 System.exit( 1 );
209             }
210 
211             if ( port > AvailablePortFinder.MAX_PORT_NUMBER )
212             {
213                 System.err.println( "port value of '" + val + "' is larger than max port number: "
214                     + AvailablePortFinder.MAX_PORT_NUMBER );
215                 System.exit( 1 );
216             }
217             else if ( port < AvailablePortFinder.MIN_PORT_NUMBER )
218             {
219                 System.err.println( "port value of '" + val + "' is smaller than the minimum port number: "
220                     + AvailablePortFinder.MIN_PORT_NUMBER );
221                 System.exit( 1 );
222             }
223 
224             if ( isDebugEnabled() )
225             {
226                 System.out.println( "port overriden by -p option: " + port );
227             }
228         }
229         else if ( getApacheDS() != null )
230         {
231             port = getApacheDS().getLdapService().getIpPort();
232 
233             if ( isDebugEnabled() )
234             {
235                 System.out.println( "port overriden by server.xml configuration: " + port );
236             }
237         }
238         else if ( isDebugEnabled() )
239         {
240             System.out.println( "port set to default: " + port );
241         }
242 
243         // -------------------------------------------------------------------
244         // figure out the host value
245         // -------------------------------------------------------------------
246 
247         if ( cmd.hasOption( 'h' ) )
248         {
249             host = cmd.getOptionValue( 'h' );
250 
251             if ( isDebugEnabled() )
252             {
253                 System.out.println( "host overriden by -h option: " + host );
254             }
255         }
256         else if ( isDebugEnabled() )
257         {
258             System.out.println( "host set to default: " + host );
259         }
260 
261         // -------------------------------------------------------------------
262         // figure out the password value
263         // -------------------------------------------------------------------
264 
265         if ( cmd.hasOption( 'w' ) )
266         {
267             password = cmd.getOptionValue( 'w' );
268 
269             if ( isDebugEnabled() )
270             {
271                 System.out.println( "password overriden by -w option: " + password );
272             }
273         }
274         else if ( isDebugEnabled() )
275         {
276             System.out.println( "password set to default: " + password );
277         }
278 
279         // -------------------------------------------------------------------
280         // figure out the binddn value
281         // -------------------------------------------------------------------
282 
283         if ( cmd.hasOption( 'u' ) )
284         {
285             bindDn = cmd.getOptionValue( 'u' );
286 
287             if ( isDebugEnabled() )
288             {
289                 System.out.println( "binddn overriden by -u option: " + bindDn );
290             }
291         }
292         else if ( isDebugEnabled() )
293         {
294             System.out.println( "binddn set to default: " + bindDn );
295         }
296     }
297 
298 
299     public Options getOptions()
300     {
301         Options opts = new Options();
302         Option op = new Option( "h", "host", true, "server host: defaults to localhost" );
303         op.setRequired( false );
304         opts.addOption( op );
305         op = new Option( "p", "port", true, "server port: defaults to 10389 or server.xml specified port" );
306         op.setRequired( false );
307         opts.addOption( op );
308         op = new Option( "w", "password", true, "the apacheds administrator's password: defaults to secret" );
309         op.setRequired( false );
310         opts.addOption( op );
311         op = new Option( "u", "binddn", true, "an apacheds user's dn: defaults to " + bindDn );
312         op.setRequired( false );
313         opts.addOption( op );
314         op = new Option( "i", "install-path", true, "path to apacheds installation directory" );
315         op.setRequired( false );
316         opts.addOption( op );
317         return opts;
318     }
319 }