blob: 662ff48506c0bf1cb03937fff39f2be187318cec [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.server.tools.commands.disconnectnotificationcmd;
import org.apache.directory.server.configuration.ApacheDS;
import org.apache.directory.server.constants.ServerDNConstants;
import org.apache.directory.server.tools.ToolCommandListener;
import org.apache.directory.server.tools.execution.BaseToolCommandExecutor;
import org.apache.directory.server.tools.util.ListenerParameter;
import org.apache.directory.server.tools.util.Parameter;
import org.apache.directory.shared.asn1.codec.DecoderException;
import org.apache.directory.shared.ldap.constants.JndiPropertyConstants;
import org.apache.directory.shared.ldap.message.extended.GracefulDisconnect;
import org.apache.directory.shared.ldap.message.extended.NoticeOfDisconnect;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import javax.naming.directory.SearchControls;
import javax.naming.event.EventContext;
import javax.naming.event.NamingExceptionEvent;
import javax.naming.ldap.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
/**
* This is the Executor Class of the Disconnect Notification Command.
*
* The command can be called using the 'execute' method.
*/
public class DisconnectNotificationCommandExecutor extends BaseToolCommandExecutor implements
UnsolicitedNotificationListener
{
// Additional Parameter
public static final String BINDDN_PARAMETER = "bindDN";
private String bindDN;
public static final String DEFAULT_BINDDN = ServerDNConstants.ADMIN_SYSTEM_DN;
UnsolicitedNotification notification;
boolean canceled;
public DisconnectNotificationCommandExecutor()
{
super( "notifications" );
}
/**
* Executes the command.
* <p>
* Use the following Parameters and ListenerParameters to call the command.
* <p>
* Parameters : <ul>
* <li>"HOST_PARAMETER" with a value of type 'String', representing server host</li>
* <li>"PORT_PARAMETER" with a value of type 'Integer', representing server port</li>
* <li>"BINDDN_PARAMETER" with a value of type 'String', representing an apacheds user's dn</li>
* <li>"PASSWORD_PARAMETER" with a value of type 'String', representing user password</li>
* <li>"DEBUG_PARAMETER" with a value of type 'Boolean', true to enable debug</li>
* <li>"QUIET_PARAMETER" with a value of type 'Boolean', true to enable quiet</li>
* <li>"VERBOSE_PARAMETER" with a value of type 'Boolean', true to enable verbose</li>
* <li>"INSTALLPATH_PARAMETER" with a value of type 'String', representing the path to installation
* directory</li>
* <li>"CONFIGURATION_PARAMETER" with a value of type "Boolean"</li>
* </ul>
* <br />
* ListenersParameters : <ul>
* <li>"OUTPUTLISTENER_PARAMETER", a listener that will receive all output messages. It returns
* messages as a String.</li>
* <li>"ERRORLISTENER_PARAMETER", a listener that will receive all error messages. It returns messages
* as a String.</li>
* <li>"EXCEPTIONLISTENER_PARAMETER", a listener that will receive all exception(s) raised. It returns
* Exceptions.</li>
* </ul>
* <b>Note:</b> "HOST_PARAMETER", "PORT_PARAMETER", "BINDDN_PARAMETER" and "PASSWORD_PARAMETER" are required.
*/
public void execute( Parameter[] params, ListenerParameter[] listeners )
{
processParameters( params );
processListeners( listeners );
try
{
execute();
}
catch ( Exception e )
{
notifyExceptionListener( e );
}
}
private void execute() throws Exception
{
Hashtable<String, Object> env = new Hashtable<String, Object>();
env.put( JndiPropertyConstants.JNDI_FACTORY_INITIAL, "com.sun.jndi.ldap.LdapCtxFactory" );
env.put( JndiPropertyConstants.JNDI_PROVIDER_URL, "ldap://" + host + ":" + port );
env.put( "java.naming.security.principal", bindDN );
env.put( JndiPropertyConstants.JNDI_SECURITY_CREDENTIALS, password );
env.put( JndiPropertyConstants.JNDI_SECURITY_AUTHENTICATION, "simple" );
LdapContext ctx = new InitialLdapContext( env, null );
ctx = ctx.newInstance( null );
UnsolicitedNotificationListener listener = new DisconnectNotificationCommandExecutor();
( ( EventContext ) ctx ).addNamingListener( "", SearchControls.SUBTREE_SCOPE, listener );
notifyOutputListener( "Listening for notifications." );
notifyOutputListener( "Press any key to terminate." );
//noinspection ResultOfMethodCallIgnored
System.in.read();
ctx.close();
notifyOutputListener( "Process terminated!!!" );
}
private void processParameters( Parameter[] params )
{
Map<String, Object> parameters = new HashMap<String, Object>();
for ( Parameter parameter : params )
{
parameters.put( parameter.getName(), parameter.getValue() );
}
// Quiet param
Boolean quietParam = ( Boolean ) parameters.get( QUIET_PARAMETER );
if ( quietParam != null )
{
setQuietEnabled( quietParam );
}
// Debug param
Boolean debugParam = ( Boolean ) parameters.get( DEBUG_PARAMETER );
if ( debugParam != null )
{
setDebugEnabled( debugParam );
}
// Verbose param
Boolean verboseParam = ( Boolean ) parameters.get( VERBOSE_PARAMETER );
if ( verboseParam != null )
{
setVerboseEnabled( verboseParam );
}
// Install-path param
String installPathParam = ( String ) parameters.get( INSTALLPATH_PARAMETER );
if ( installPathParam != null )
{
try
{
setLayout( installPathParam );
if ( !isQuietEnabled() )
{
notifyOutputListener( "loading settings from: " + getLayout().getConfigurationFile() );
}
URL configUrl = getLayout().getConfigurationFile().toURI().toURL();
ApplicationContext factory = new FileSystemXmlApplicationContext( configUrl.toString() );
setApacheDS( ( ApacheDS ) factory.getBean( "apacheDS" ) );
}
catch ( MalformedURLException e )
{
notifyErrorListener( e.getMessage() );
notifyExceptionListener( e );
}
}
// Host param
String hostParam = ( String ) parameters.get( HOST_PARAMETER );
if ( hostParam != null )
{
host = hostParam;
}
else
{
host = DEFAULT_HOST;
if ( isDebugEnabled() )
{
notifyOutputListener( "host set to default: " + host );
}
}
// Port param
Integer portParam = ( Integer ) parameters.get( PORT_PARAMETER );
if ( portParam != null )
{
port = portParam;
}
else if ( getApacheDS() != null )
{
port = getApacheDS().getLdapServer().getIpPort();
if ( isDebugEnabled() )
{
notifyOutputListener( "port overriden by server.xml configuration: " + port );
}
}
else
{
port = DEFAULT_PORT;
if ( isDebugEnabled() )
{
notifyOutputListener( "port set to default: " + port );
}
}
// Password param
String passwordParam = ( String ) parameters.get( PASSWORD_PARAMETER );
if ( passwordParam != null )
{
password = passwordParam;
}
else
{
password = DEFAULT_PASSWORD;
if ( isDebugEnabled() )
{
notifyOutputListener( "password set to default: " + password );
}
}
// BindDn param
String bindDNParam = ( String ) parameters.get( BINDDN_PARAMETER );
if ( bindDNParam != null )
{
bindDN = bindDNParam;
}
else
{
bindDN = DEFAULT_BINDDN;
if ( isDebugEnabled() )
{
notifyOutputListener( "binddn set to default: " + bindDN );
}
}
}
private void processListeners( ListenerParameter[] listeners )
{
Map<String, ToolCommandListener> parameters = new HashMap<String, ToolCommandListener>();
for ( ListenerParameter parameter:listeners )
{
parameters.put( parameter.getName(), parameter.getListener() );
}
// OutputListener param
ToolCommandListener outputListener = parameters.get( OUTPUTLISTENER_PARAMETER );
if ( outputListener != null )
{
this.outputListener = outputListener;
}
// ErrorListener param
ToolCommandListener errorListener = parameters.get( ERRORLISTENER_PARAMETER );
if ( errorListener != null )
{
this.errorListener = errorListener;
}
// ExceptionListener param
ToolCommandListener exceptionListener = parameters.get( EXCEPTIONLISTENER_PARAMETER );
if ( exceptionListener != null )
{
this.exceptionListener = exceptionListener;
}
}
public void notificationReceived( UnsolicitedNotificationEvent evt )
{
notification = evt.getNotification();
if ( notification.getID().equals( NoticeOfDisconnect.EXTENSION_OID ) )
{
notifyOutputListener( "\nRecieved NoticeOfDisconnect: " + NoticeOfDisconnect.EXTENSION_OID );
notifyOutputListener( "Expect to loose this connection without further information." );
canceled = true;
}
else if ( notification.getID().equals( GracefulDisconnect.EXTENSION_OID ) )
{
notifyOutputListener( "Recieved GracefulDisconnect: " + GracefulDisconnect.EXTENSION_OID );
GracefulDisconnect gd = null;
try
{
gd = new GracefulDisconnect( notification.getEncodedValue() );
}
catch ( DecoderException de )
{
// TODO Auto-generated catch block
de.printStackTrace();
}
assert gd != null;
notifyOutputListener( "LDAP server will shutdown in " + gd.getDelay() + " seconds." );
notifyOutputListener( "LDAP server will be back online in " + gd.getTimeOffline() + " minutes." );
if ( gd.getDelay() > 0 )
{
Thread t = new Thread( new Counter( gd.getDelay() ) );
t.start();
}
}
else
{
notifyOutputListener( "Unknown event recieved with OID: " + evt.getNotification().getID() );
}
}
public void namingExceptionThrown( NamingExceptionEvent evt )
{
canceled = true;
notifyOutputListener( "Got an excption event: " + evt.getException().getMessage() );
notifyOutputListener( "Process shutting down abruptly." );
notifyExceptionListener( evt );
}
class Counter implements Runnable
{
int delay;
Counter( int delay )
{
this.delay = delay;
}
public void run()
{
notifyOutputListener( "Starting countdown until server shutdown:" );
notifyOutputListener( "[" );
long delayMillis = delay * 1000 - 1000; // 1000 is for setup costs
long startTime = System.currentTimeMillis();
while ( System.currentTimeMillis() - startTime < delayMillis && !canceled )
{
try
{
Thread.sleep( 1000 );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
notifyOutputListener( "." );
}
if ( canceled )
{
notifyOutputListener( " -- countdown canceled -- " );
}
else
{
notifyOutputListener( "]" );
notifyOutputListener( "Client shutting down gracefully." );
}
}
}
}