Renamed ApacheDSStartStopBean to ApacheDSContainer and implemented LifeCycle interface.

This commit is contained in:
Luke Taylor 2007-10-03 18:09:53 +00:00
parent 3f2b9cd6fb
commit 650a5467e8
2 changed files with 109 additions and 55 deletions

View File

@ -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;
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);
}
// We need this for shutdown
instanceId = configuration.getInstanceId();
startDirectoryService();
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());
try {
new InitialDirContext(env);
} catch (NamingException e) {
logger.error("Failed to start directory service", e);
return;
}
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
}
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 + "'");
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);
}
public void destroy() throws Exception {
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");
ShutdownConfiguration shutdown = new ShutdownConfiguration(instanceId);
ShutdownConfiguration shutdown = new ShutdownConfiguration(configuration.getInstanceId());
env.putAll(shutdown.toJndiEnvironment());
logger.info("Shutting down directory server with Id '" + instanceId + "'");
new InitialContext(env);
logger.info("Shutting down directory server with Id '" + configuration.getInstanceId() + "'");
try {
new InitialContext(env);
} catch (NamingException e) {
logger.error("Failed to shutdown directory server", e);
return;
}
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;
}
}

View File

@ -34,7 +34,7 @@ public class LdapBeanDefinitionParser extends AbstractBeanDefinitionParser {
/** Defines the Url of the ldap server to use. If not specified, an embedded apache DS instance will be created */
private static final String URL_ATTRIBUTE = "url";
private static final String AUTH_TYPE_ATTRIBUTE = "auth";
// TODO: Setting login/passwords for non embedded server.
// TODO: Setting login/passwords for non embedded server.
private static final String PRINCIPAL_ATTRIBUTE = "managerDn";
private static final String PASSWORD_ATTRIBUTE = "managerPassword";
@ -113,7 +113,7 @@ public class LdapBeanDefinitionParser extends AbstractBeanDefinitionParser {
*
* @return the BeanDefinition for the ContextSource for the embedded server.
*
* @see ApacheDSStartStopBean
* @see ApacheDSContainer
*/
private RootBeanDefinition createEmbeddedServer(Element element, ParserContext parserContext) {
MutableServerStartupConfiguration configuration = new MutableServerStartupConfiguration();
@ -158,7 +158,7 @@ public class LdapBeanDefinitionParser extends AbstractBeanDefinitionParser {
initialDirContextFactory.getPropertyValues().addPropertyValue("managerDn", "uid=admin,ou=system");
initialDirContextFactory.getPropertyValues().addPropertyValue("managerPassword", "secret");
RootBeanDefinition apacheDSStartStop = new RootBeanDefinition(ApacheDSStartStopBean.class);
RootBeanDefinition apacheDSStartStop = new RootBeanDefinition(ApacheDSContainer.class);
apacheDSStartStop.getConstructorArgumentValues().addGenericArgumentValue(configuration);
apacheDSStartStop.getConstructorArgumentValues().addGenericArgumentValue(initialDirContextFactory);