blob: 170511e67a894078ce00523aac8d8cce56288596 [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.configuration;
import org.apache.commons.lang.StringUtils;
import org.apache.directory.server.constants.ApacheSchemaConstants;
import org.apache.directory.server.constants.ServerDNConstants;
import org.apache.directory.server.core.DefaultDirectoryService;
import org.apache.directory.server.core.DirectoryService;
import org.apache.directory.server.core.authn.LdapPrincipal;
import org.apache.directory.server.ldap.LdapServer;
import org.apache.directory.server.protocol.shared.store.LdifFileLoader;
import org.apache.directory.server.protocol.shared.store.LdifLoadFilter;
import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
import org.apache.directory.shared.ldap.constants.SchemaConstants;
import org.apache.directory.shared.ldap.message.AttributesImpl;
import org.apache.directory.shared.ldap.name.LdapDN;
import org.apache.directory.shared.ldap.util.StringTools;
import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.SimpleByteBufferAllocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Apache Directory Server top level.
*
* @org.apache.xbean.XBean
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$
*/
public class ApacheDS
{
private static final Logger LOG = LoggerFactory.getLogger( ApacheDS.class.getName() );
/** Default delay between two flushes to the backend */
private static final long DEFAULT_SYNC_PERIOD_MILLIS = 20000;
/** Wainting period between two flushes to the backend */
private long synchPeriodMillis = DEFAULT_SYNC_PERIOD_MILLIS;
/** Directory where are stored the LDIF files to be loaded at startup */
private File ldifDirectory;
private final List<LdifLoadFilter> ldifFilters = new ArrayList<LdifLoadFilter>();
/** The LDAP server protocol handler */
private final LdapServer ldapServer;
/** The LDAPS server protocol handler */
private final LdapServer ldapsServer;
/** The directory service */
private final DirectoryService directoryService;
/**
* Creates a new instance of the ApacheDS server
*
* @param directoryService
* @param ldapServer
* @param ldapsServer
*/
public ApacheDS( DirectoryService directoryService, LdapServer ldapServer, LdapServer ldapsServer )
{
LOG.info( "Starting the Apache Directory Server" );
if ( directoryService == null )
{
this.directoryService = new DefaultDirectoryService();
}
else
{
this.directoryService = directoryService;
}
this.ldapServer = ldapServer;
this.ldapsServer = ldapsServer;
ByteBuffer.setAllocator( new SimpleByteBufferAllocator() );
ByteBuffer.setUseDirectBuffers( false );
}
/**
* Start the server :
* <li>initialize the DirectoryService</li>
* <li>start the LDAP server</li>
* <li>start the LDAPS server</li>
*
* @throws NamingException If the server cannot be started
* @throws IOException If an IO error occured while reading some file
*/
public void startup() throws NamingException, IOException
{
LOG.debug( "Starting the server" );
// Start the directory service if not started yet
if ( ! directoryService.isStarted() )
{
LOG.debug( "1. Starting the DirectoryService" );
directoryService.startup();
}
// Load the LDIF files - if any - into the server
loadLdifs();
// Start the LDAP server
if ( ldapServer != null && ! ldapServer.isStarted() )
{
LOG.debug( "3. Starting the LDAP server" );
ldapServer.start();
}
// Start the LDAPS server
if ( ldapsServer != null && ! ldapsServer.isStarted() )
{
LOG.debug( "4. Starting the LDAPS server" );
ldapsServer.start();
}
LOG.debug( "Server successfully started" );
}
public boolean isStarted()
{
if ( ldapServer != null || ldapsServer != null )
{
return ( ldapServer != null && ldapServer.isStarted() )
|| ( ldapsServer != null && ldapsServer.isStarted() );
}
return directoryService.isStarted();
}
public void shutdown() throws NamingException
{
if ( ldapServer != null && ldapServer.isStarted() )
{
ldapServer.stop();
}
if ( ldapsServer != null && ldapsServer.isStarted() )
{
ldapsServer.stop();
}
directoryService.shutdown();
}
public LdapServer getLdapServer()
{
return ldapServer;
}
public LdapServer getLdapsServer()
{
return ldapsServer;
}
public DirectoryService getDirectoryService()
{
return directoryService;
}
public long getSynchPeriodMillis()
{
return synchPeriodMillis;
}
public void setSynchPeriodMillis( long synchPeriodMillis )
{
LOG.info( "Set the synchPeriodMillis to {}", synchPeriodMillis );
this.synchPeriodMillis = synchPeriodMillis;
}
/**
* Get the directory where
* @return
*/
public File getLdifDirectory()
{
return ldifDirectory;
}
public void setAllowAnonymousAccess( boolean allowAnonymousAccess )
{
LOG.info( "Set the allowAnonymousAccess flag to {}", allowAnonymousAccess );
directoryService.setAllowAnonymousAccess( allowAnonymousAccess );
if ( ldapServer != null )
{
ldapServer.setAllowAnonymousAccess( allowAnonymousAccess );
}
if ( ldapsServer != null )
{
ldapsServer.setAllowAnonymousAccess( allowAnonymousAccess );
}
}
public void setLdifDirectory( File ldifDirectory )
{
LOG.info( "The LDIF directory file is {}", ldifDirectory.getAbsolutePath() );
this.ldifDirectory = ldifDirectory;
}
// ----------------------------------------------------------------------
// From CoreContextFactory: presently in intermediate step but these
// methods will be moved to the appropriate protocol service eventually.
// This is here simply to start to remove the JNDI dependency then further
// refactoring will be needed to place these where they belong.
// ----------------------------------------------------------------------
/**
* Check that the entry where are stored the loaded Ldif files is created.
*
* If not, create it.
*
* The files are stored in ou=loadedLdifFiles,ou=configuration,ou=system
*/
private void ensureLdifFileBase( DirContext root )
{
Attributes entry = new AttributesImpl( SchemaConstants.OU_AT, "loadedLdifFiles", true );
entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC );
entry.get( SchemaConstants.OBJECT_CLASS_AT ).add( SchemaConstants.ORGANIZATIONAL_UNIT_OC );
try
{
root.createSubcontext( ServerDNConstants.LDIF_FILES_DN, entry );
LOG.info( "Creating " + ServerDNConstants.LDIF_FILES_DN );
}
catch ( NamingException e )
{
LOG.info( ServerDNConstants.LDIF_FILES_DN + " exists" );
}
}
/**
* Create a string containing a hex dump of the loaded ldif file name.
*
* It is associated with the attributeType wrt to the underlying system.
*/
private String buildProtectedFileEntry( File ldif )
{
String fileSep = File.separatorChar == '\\' ?
ApacheSchemaConstants.WINDOWS_FILE_AT :
ApacheSchemaConstants.UNIX_FILE_AT;
return fileSep +
"=" +
StringTools.dumpHexPairs( StringTools.getBytesUtf8( getCanonical( ldif ) ) ) +
"," +
ServerDNConstants.LDIF_FILES_DN;
}
private void addFileEntry( DirContext root, File ldif ) throws NamingException
{
String rdnAttr = File.separatorChar == '\\' ?
ApacheSchemaConstants.WINDOWS_FILE_AT :
ApacheSchemaConstants.UNIX_FILE_AT;
String oc = File.separatorChar == '\\' ? ApacheSchemaConstants.WINDOWS_FILE_OC : ApacheSchemaConstants.UNIX_FILE_OC;
Attributes entry = new AttributesImpl( rdnAttr, getCanonical( ldif ), true );
entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC );
entry.get( SchemaConstants.OBJECT_CLASS_AT ).add( oc );
root.createSubcontext( buildProtectedFileEntry( ldif ), entry );
}
/**
*
* @param root
* @param ldif
* @return
*/
private Attributes getLdifFileEntry( DirContext root, File ldif )
{
try
{
return root.getAttributes( buildProtectedFileEntry( ldif ), new String[]
{ SchemaConstants.CREATE_TIMESTAMP_AT } );
}
catch ( NamingException e )
{
return null;
}
}
private String getCanonical( File file )
{
String canonical;
try
{
canonical = file.getCanonicalPath();
}
catch ( IOException e )
{
LOG.error( "could not get canonical path", e );
return null;
}
return StringUtils.replace( canonical, "\\", "\\\\" );
}
/**
* Load a ldif into the directory.
*
* @param root The context in which we will inject the entries
* @param ldifFile The ldif file to read
* @throws NamingException If something went wrong while loading the entries
*/
private void loadLdif( DirContext root, File ldifFile ) throws NamingException
{
Attributes fileEntry = getLdifFileEntry( root, ldifFile );
if ( fileEntry != null )
{
String time = ( String ) fileEntry.get( SchemaConstants.CREATE_TIMESTAMP_AT ).get();
LOG.info( "Load of LDIF file '" + getCanonical( ldifFile )
+ "' skipped. It has already been loaded on " + time + "." );
}
else
{
LdifFileLoader loader = new LdifFileLoader( root, ldifFile, ldifFilters );
int count = loader.execute();
LOG.info( "Loaded " + count + " entries from LDIF file '" + getCanonical( ldifFile ) + "'" );
addFileEntry( root, ldifFile );
}
}
/**
* Load the ldif files if there are some
*/
public void loadLdifs() throws NamingException
{
// LOG and bail if property not set
if ( ldifDirectory == null )
{
LOG.info( "LDIF load directory not specified. No LDIF files will be loaded." );
return;
}
// LOG and bail if LDIF directory does not exists
if ( ! ldifDirectory.exists() )
{
LOG.warn( "LDIF load directory '{}' does not exist. No LDIF files will be loaded.",
getCanonical( ldifDirectory ) );
return;
}
LdapDN dn = new LdapDN( ServerDNConstants.ADMIN_SYSTEM_DN );
// Must normalize the dn or - IllegalStateException!
AttributeTypeRegistry reg = directoryService.getRegistries().getAttributeTypeRegistry();
dn.normalize( reg.getNormalizerMapping() );
LdapPrincipal admin = new LdapPrincipal( dn, AuthenticationLevel.STRONG );
DirContext root = directoryService.getJndiContext( admin );
ensureLdifFileBase( root );
// if ldif directory is a file try to load it
if ( ldifDirectory.isFile() )
{
if ( LOG.isInfoEnabled() )
{
LOG.info( "LDIF load directory '{}' is a file. Will attempt to load as LDIF.",
getCanonical( ldifDirectory ) );
}
try
{
loadLdif( root, ldifDirectory );
}
catch ( NamingException ne )
{
// If the file can't be read, log the error, and stop
// loading LDIFs.
LOG.error( "Cannot load the ldif file '{}', error : ",
ldifDirectory.getAbsolutePath(),
ne.getMessage() );
throw ne;
}
}
else
{
// get all the ldif files within the directory (should be sorted alphabetically)
File[] ldifFiles = ldifDirectory.listFiles( new FileFilter()
{
public boolean accept( File pathname )
{
boolean isLdif = pathname.getName().toLowerCase().endsWith( ".ldif" );
return pathname.isFile() && pathname.canRead() && isLdif;
}
} );
// LOG and bail if we could not find any LDIF files
if ( ( ldifFiles == null ) || ( ldifFiles.length == 0 ) )
{
LOG.warn( "LDIF load directory '{}' does not contain any LDIF files. No LDIF files will be loaded.",
getCanonical( ldifDirectory ) );
return;
}
// load all the ldif files and load each one that is loaded
for ( File ldifFile : ldifFiles )
{
try
{
LOG.info( "Loading LDIF file '{}'", ldifFile.getName() );
loadLdif( root, ldifFile );
}
catch ( NamingException ne )
{
// If the file can't be read, log the error, and stop
// loading LDIFs.
LOG.error( "Cannot load the ldif file '{}', error : {}",
ldifFile.getAbsolutePath(),
ne.getMessage() );
throw ne;
}
}
}
}
}