@ -5,8 +5,10 @@ import org.springframework.beans.factory.DisposableBean;
@@ -5,8 +5,10 @@ import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.BeansException ;
import org.springframework.context.ApplicationContextAware ;
import org.springframework.context.ApplicationContext ;
import org.springframework.context.Lifecycle ;
import org.springframework.core.io.Resource ;
import org.springframework.ldap.core.ContextSource ;
import org.springframework.util.Assert ;
import org.apache.commons.logging.Log ;
import org.apache.commons.logging.LogFactory ;
import org.apache.directory.server.configuration.MutableServerStartupConfiguration ;
@ -22,54 +24,132 @@ import javax.naming.directory.DirContext;
@@ -22,54 +24,132 @@ import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext ;
import java.util.Properties ;
import java.io.File ;
import java.io.IOException ;
/ * *
* Starts and stops the embedded apacheDS server defined by the supplied configuration .
* Used by { @link LdapBeanDefinitionParser } . An instance will be stored in the context for
* each embedded server instance and its InitializingBean and DisposableBean implementations
* used to start and stop the server , respectively .
* Provides lifecycle services for the embedded apacheDS server defined by the supplied configuration .
* Used by { @link LdapBeanDefinitionParser } . An instance will be stored in the application context for
* each embedded server instance . It will start the server when the context is initialized and shut it down when
* it is closed . It is intended for temporary embedded use and will not retain changes across start / stop boundaries . The
* working directory is deleted on shutdown .
*
* < p >
* If used repeatedly in a single JVM process with the same configuration ( for example , when
* repeatedly loading an application context during testing ) , it ' s important that the
* application context is closed to allow the bean to be disposed of and the server shutdown
* prior to attempting to start it again .
* < / p >
*
*
*
* @author Luke Taylor
* @version $Id$
* /
class ApacheDSStartStopBean implements InitializingBean , DisposableBean , ApplicationContextAware {
class ApacheDSContainer implements InitializingBean , DisposableBean , Lifecycle , ApplicationContextAware {
private Log logger = LogFactory . getLog ( getClass ( ) ) ;
private MutableServerStartupConfiguration configuration ;
private ApplicationContext ctxt ;
private File workingDir ;
/** The instance Id of the Apache DS DirectoryServer instance */
private String instanceId ;
private ContextSource contextSource ;
private boolean running ;
public ApacheDSStartStopBean ( MutableServerStartupConfiguration configuration , ContextSource contextSource ) {
public ApacheDSContainer ( MutableServerStartupConfiguration configuration , ContextSource contextSource ) {
this . configuration = configuration ;
this . contextSource = contextSource ;
}
public void afterPropertiesSet ( ) throws Exception {
if ( workingDir ! = null ) {
return ;
}
String apacheWorkDir = System . getProperty ( "apacheDSWorkDir" ) ;
if ( apacheWorkDir = = null ) {
apacheWorkDir = System . getProperty ( "java.io.tmpdir" ) + File . separator + "apacheds-spring-security" ;
}
workingDir = new File ( apacheWorkDir ) ;
setWorkingDirectory ( new File ( apacheWorkDir ) ) ;
start ( ) ;
}
public void destroy ( ) throws Exception {
stop ( ) ;
}
public void setApplicationContext ( ApplicationContext applicationContext ) throws BeansException {
ctxt = applicationContext ;
}
private static boolean deleteDir ( File dir ) {
if ( dir . isDirectory ( ) ) {
String [ ] children = dir . list ( ) ;
for ( int i = 0 ; i < children . length ; i + + ) {
boolean success = deleteDir ( new File ( dir , children [ i ] ) ) ;
if ( ! success ) {
return false ;
}
}
}
return dir . delete ( ) ;
}
public void setWorkingDirectory ( File workingDir ) {
Assert . notNull ( workingDir ) ;
if ( workingDir . exists ( ) ) {
throw new IllegalArgumentException ( "The specified working directory '" + workingDir . getAbsolutePath ( ) +
"' already exists. Another directory service instance may be using it or it may be from a " +
" previous unclean shutdown. Please confirm and delete it or configure a different " +
"working directory" ) ;
}
this . workingDir = workingDir ;
configuration . setWorkingDirectory ( workingDir ) ;
}
public void start ( ) {
if ( isRunning ( ) ) {
return ;
}
DirectoryService ds = DirectoryService . getInstance ( configuration . getInstanceId ( ) ) ;
if ( ds . isStarted ( ) ) {
throw new IllegalStateException ( "A DirectoryService with Id '" + configuration . getInstanceId ( ) + "' is already running." ) ;
}
logger . info ( "Starting directory server with Id '" + configuration . getInstanceId ( ) + "'" ) ;
Properties env = new Properties ( ) ;
env . setProperty ( Context . INITIAL_CONTEXT_FACTORY , ServerContextFactory . class . getName ( ) ) ;
env . setProperty ( Context . SECURITY_AUTHENTICATION , "simple" ) ;
env . setProperty ( Context . SECURITY_PRINCIPAL , "uid=admin,ou=system" ) ;
env . setProperty ( Context . SECURITY_CREDENTIALS , "secret" ) ;
env . putAll ( configuration . toJndiEnvironment ( ) ) ;
// We need this for shutdown
instanceId = configuration . getInstanceId ( ) ;
try {
new InitialDirContext ( env ) ;
} catch ( NamingException e ) {
logger . error ( "Failed to start directory service" , e ) ;
return ;
}
startDirectoryService ( ) ;
running = true ;
try {
importLdifs ( ) ;
} catch ( Exception e ) {
logger . error ( "Failed to import LDIF file(s)" , e ) ;
}
}
private void importLdifs ( ) throws IOException , NamingException {
// Import any ldif files
Resource [ ] ldifs = ctxt . getResources ( "classpath:*.ldif" ) ;
@ -90,60 +170,34 @@ class ApacheDSStartStopBean implements InitializingBean, DisposableBean, Applica
@@ -90,60 +170,34 @@ class ApacheDSStartStopBean implements InitializingBean, DisposableBean, Applica
}
private void startDirectoryService ( ) throws NamingException {
DirectoryService ds = DirectoryService . getInstance ( instanceId ) ;
if ( ds . isStarted ( ) ) {
throw new IllegalStateException ( "A DirectoryService with Id '" + instanceId + "' is already running." ) ;
}
logger . info ( "Starting directory server with Id '" + instanceId + "'" ) ;
public void stop ( ) {
Properties env = new Properties ( ) ;
env . setProperty ( Context . INITIAL_CONTEXT_FACTORY , ServerContextFactory . class . getName ( ) ) ;
env . setProperty ( Context . SECURITY_AUTHENTICATION , "simple" ) ;
env . setProperty ( Context . SECURITY_PRINCIPAL , "uid=admin,ou=system" ) ;
env . setProperty ( Context . SECURITY_CREDENTIALS , "secret" ) ;
env . putAll ( configuration . toJndiEnvironment ( ) ) ;
new InitialDirContext ( env ) ;
}
ShutdownConfiguration shutdown = new ShutdownConfiguration ( configuration . getInstanceId ( ) ) ;
env . putAll ( shutdown . toJndiEnvironment ( ) ) ;
public void destroy ( ) throws Exception {
Properties env = new Properties ( ) ;
env . setProperty ( Context . INITIAL_CONTEXT_FACTORY , ServerContextFactory . class . getName ( ) ) ;
env . setProperty ( Context . SECURITY_AUTHENTICATION , "simple" ) ;
env . setProperty ( Context . SECURITY_PRINCIPAL , "uid=admin,ou=system" ) ;
env . setProperty ( Context . SECURITY_CREDENTIALS , "secret" ) ;
logger . info ( "Shutting down directory server with Id '" + configuration . getInstanceId ( ) + "'" ) ;
ShutdownConfiguration shutdown = new ShutdownConfiguration ( instanceId ) ;
env . putAll ( shutdown . toJndiEnvironment ( ) ) ;
try {
new InitialContext ( env ) ;
} catch ( NamingException e ) {
logger . error ( "Failed to shutdown directory server" , e ) ;
return ;
}
logger . info ( "Shutting down directory server with Id '" + instanceId + "'" ) ;
new InitialContext ( env ) ;
running = false ;
if ( workingDir . exists ( ) ) {
logger . info ( "Deleting working directory " + workingDir . getAbsolutePath ( ) ) ;
deleteDir ( workingDir ) ;
}
}
public void setApplicationContext ( ApplicationContext applicationContext ) throws BeansException {
ctxt = applicationContext ;
}
public static boolean deleteDir ( File dir ) {
if ( dir . isDirectory ( ) ) {
String [ ] children = dir . list ( ) ;
for ( int i = 0 ; i < children . length ; i + + ) {
boolean success = deleteDir ( new File ( dir , children [ i ] ) ) ;
if ( ! success ) {
return false ;
}
}
}
return dir . delete ( ) ;
public boolean isRunning ( ) {
return running ;
}
}