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.configuration;
21  
22  
23  import org.apache.commons.lang.StringUtils;
24  import org.apache.directory.server.constants.ApacheSchemaConstants;
25  import org.apache.directory.server.constants.ServerDNConstants;
26  import org.apache.directory.server.core.DefaultDirectoryService;
27  import org.apache.directory.server.core.DirectoryService;
28  import org.apache.directory.server.core.entry.ClonedServerEntry;
29  import org.apache.directory.server.core.entry.ServerEntry;
30  import org.apache.directory.server.ldap.LdapService;
31  import org.apache.directory.server.protocol.shared.store.LdifFileLoader;
32  import org.apache.directory.server.protocol.shared.store.LdifLoadFilter;
33  import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
34  import org.apache.directory.shared.ldap.constants.SchemaConstants;
35  import org.apache.directory.shared.ldap.name.LdapDN;
36  import org.apache.directory.shared.ldap.util.StringTools;
37  import org.apache.mina.common.ByteBuffer;
38  import org.apache.mina.common.SimpleByteBufferAllocator;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  
43  import java.io.File;
44  import java.io.FileFilter;
45  import java.io.IOException;
46  import java.util.ArrayList;
47  import java.util.List;
48  
49  
50  /**
51   * Apache Directory Server top level.
52   *
53   * @org.apache.xbean.XBean
54   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
55   * @version $Rev$
56   */
57  public class ApacheDS
58  {
59      private static final Logger LOG = LoggerFactory.getLogger( ApacheDS.class.getName() );
60      
61      /** Default delay between two flushes to the backend */
62      private static final long DEFAULT_SYNC_PERIOD_MILLIS = 20000;
63  
64      /** Wainting period between two flushes to the backend */
65      private long synchPeriodMillis = DEFAULT_SYNC_PERIOD_MILLIS;
66  
67      /** Directory where are stored the LDIF files to be loaded at startup */
68      private File ldifDirectory;
69      
70      private final List<LdifLoadFilter> ldifFilters = new ArrayList<LdifLoadFilter>();
71  
72      /** The LDAP server protocol handler */
73      private final LdapService ldapService;
74      
75      /** The LDAPS server protocol handler */
76      private final LdapService ldapsService;
77      
78      /** The directory service */
79      private final DirectoryService directoryService;
80  
81  
82      /**
83       * Creates a new instance of the ApacheDS server
84       *  
85       * @param directoryService 
86       * @param ldapService
87       * @param ldapsService
88       */
89      public ApacheDS( DirectoryService directoryService, LdapService ldapService, LdapService ldapsService )
90      {
91          LOG.info( "Starting the Apache Directory Server" );
92  
93          if ( directoryService == null )
94          {
95              this.directoryService = new DefaultDirectoryService();
96          }
97          else
98          {        
99              this.directoryService = directoryService;
100         }
101         
102         this.ldapService = ldapService;
103         this.ldapsService = ldapsService;
104         ByteBuffer.setAllocator( new SimpleByteBufferAllocator() );
105         ByteBuffer.setUseDirectBuffers( false );
106     }
107 
108 
109     /**
110      * Start the server :
111      *  <li>initialize the DirectoryService</li>
112      *  <li>start the LDAP server</li>
113      *  <li>start the LDAPS server</li>
114      *  
115      * @throws NamingException If the server cannot be started
116      * @throws IOException If an IO error occured while reading some file
117      */
118     public void startup() throws Exception
119     {
120         LOG.debug( "Starting the server" );
121         
122         // Start the directory service if not started yet
123         if ( ! directoryService.isStarted() )
124         {
125             LOG.debug( "1. Starting the DirectoryService" );
126             directoryService.startup();
127         }
128 
129         // Load the LDIF files - if any - into the server
130         loadLdifs();
131 
132         // Start the LDAP server
133         if ( ldapService != null && ! ldapService.isStarted() )
134         {
135             LOG.debug( "3. Starting the LDAP server" );
136             ldapService.start();
137         }
138 
139         // Start the LDAPS  server
140         if ( ldapsService != null && ! ldapsService.isStarted() )
141         {
142             LOG.debug(  "4. Starting the LDAPS server" );
143             ldapsService.start();
144         }
145         
146         LOG.debug( "Server successfully started" );
147     }
148 
149 
150     public boolean isStarted()
151     {
152         if ( ldapService != null || ldapsService != null )
153         {
154              return ( ldapService != null && ldapService.isStarted() )
155                      || ( ldapsService != null && ldapsService.isStarted() );
156         }
157         
158         return directoryService.isStarted();
159     }
160     
161 
162     public void shutdown() throws Exception
163     {
164         if ( ldapService != null && ldapService.isStarted() )
165         {
166             ldapService.stop();
167         }
168 
169         if ( ldapsService != null && ldapsService.isStarted() )
170         {
171             ldapsService.stop();
172         }
173 
174         directoryService.shutdown();
175     }
176 
177 
178     public LdapService getLdapService()
179     {
180         return ldapService;
181     }
182 
183 
184     public LdapService getLdapsService()
185     {
186         return ldapsService;
187     }
188 
189 
190     public DirectoryService getDirectoryService()
191     {
192         return directoryService;
193     }
194 
195 
196     public long getSynchPeriodMillis()
197     {
198         return synchPeriodMillis;
199     }
200 
201 
202     public void setSynchPeriodMillis( long synchPeriodMillis )
203     {
204         LOG.info( "Set the synchPeriodMillis to {}", synchPeriodMillis );
205         this.synchPeriodMillis = synchPeriodMillis;
206     }
207 
208     
209     /**
210      * Get the directory where 
211      * @return
212      */
213     public File getLdifDirectory()
214     {
215         return ldifDirectory;
216     }
217 
218 
219     public void setAllowAnonymousAccess( boolean allowAnonymousAccess )
220     {
221         LOG.info( "Set the allowAnonymousAccess flag to {}", allowAnonymousAccess );
222         
223         directoryService.setAllowAnonymousAccess( allowAnonymousAccess );
224         
225         if ( ldapService != null )
226         {
227             ldapService.setAllowAnonymousAccess( allowAnonymousAccess );
228         }
229         
230         if ( ldapsService != null )
231         {
232             ldapsService.setAllowAnonymousAccess( allowAnonymousAccess );
233         }
234     }
235 
236 
237     public void setLdifDirectory( File ldifDirectory )
238     {
239         LOG.info( "The LDIF directory file is {}", ldifDirectory.getAbsolutePath() );
240         this.ldifDirectory = ldifDirectory;
241     }
242     
243     
244     // ----------------------------------------------------------------------
245     // From CoreContextFactory: presently in intermediate step but these
246     // methods will be moved to the appropriate protocol service eventually.
247     // This is here simply to start to remove the JNDI dependency then further
248     // refactoring will be needed to place these where they belong.
249     // ----------------------------------------------------------------------
250 
251 
252     /**
253      * Check that the entry where are stored the loaded Ldif files is created.
254      * 
255      * If not, create it.
256      * 
257      * The files are stored in ou=loadedLdifFiles,ou=configuration,ou=system
258      */
259     private void ensureLdifFileBase() throws Exception
260     {
261         LdapDN dn = new LdapDN( ServerDNConstants.LDIF_FILES_DN );
262         ServerEntry entry = null;
263         
264         try
265         {
266             entry = directoryService.getAdminSession().lookup( dn );
267         }
268         catch( Exception e )
269         {
270             LOG.error( "Failure while looking up " + ServerDNConstants.LDIF_FILES_DN, e );
271         }
272 
273         if ( entry == null )
274         {
275             entry = directoryService.newEntry( new LdapDN( ServerDNConstants.LDIF_FILES_DN ) );
276             entry.add( SchemaConstants.OU_AT, "loadedLdifFiles" );
277             entry.add( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, SchemaConstants.ORGANIZATIONAL_UNIT_OC );
278     
279             directoryService.getAdminSession().add( entry );
280         }
281     }
282 
283 
284     /**
285      * Create a string containing a hex dump of the loaded ldif file name.
286      * 
287      * It is associated with the attributeType wrt to the underlying system.
288      */
289     private LdapDN buildProtectedFileEntryDn( File ldif ) throws Exception
290     {
291         String fileSep = File.separatorChar == '\\' ? 
292                 ApacheSchemaConstants.WINDOWS_FILE_AT : 
293                 ApacheSchemaConstants.UNIX_FILE_AT;
294 
295         return  new LdapDN( fileSep + 
296                 "=" + 
297                 StringTools.dumpHexPairs( StringTools.getBytesUtf8( getCanonical( ldif ) ) ) + 
298                 "," + 
299                 ServerDNConstants.LDIF_FILES_DN ); 
300     }
301 
302     
303     private void addFileEntry( File ldif ) throws Exception
304     {
305         String rdnAttr = File.separatorChar == '\\' ? 
306             ApacheSchemaConstants.WINDOWS_FILE_AT : 
307             ApacheSchemaConstants.UNIX_FILE_AT;
308         String oc = File.separatorChar == '\\' ? ApacheSchemaConstants.WINDOWS_FILE_OC : ApacheSchemaConstants.UNIX_FILE_OC;
309 
310         ServerEntry entry = directoryService.newEntry( buildProtectedFileEntryDn( ldif ) );
311         entry.add( rdnAttr, getCanonical( ldif ) );
312         entry.add( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, oc );
313         directoryService.getAdminSession().add( entry );
314     }
315 
316 
317     private String getCanonical( File file )
318     {
319         String canonical;
320 
321         try
322         {
323             canonical = file.getCanonicalPath();
324         }
325         catch ( IOException e )
326         {
327             LOG.error( "could not get canonical path", e );
328             return null;
329         }
330 
331         return StringUtils.replace( canonical, "\\", "\\\\" );
332     }
333 
334 
335     /**
336      * Load a ldif into the directory.
337      *  
338      * @param root The context in which we will inject the entries
339      * @param ldifFile The ldif file to read
340      * @throws NamingException If something went wrong while loading the entries
341      */
342     private void loadLdif( File ldifFile ) throws Exception
343     {
344         ClonedServerEntry fileEntry = null;
345         try
346         {
347             fileEntry = directoryService.getAdminSession().lookup( buildProtectedFileEntryDn( ldifFile ) );
348         }
349         catch( Exception e )
350         {
351             // if does not exist
352         }
353         
354         if ( fileEntry != null )
355         {
356             String time = ((ClonedServerEntry)fileEntry).getOriginalEntry().get( SchemaConstants.CREATE_TIMESTAMP_AT ).getString();
357             LOG.info( "Load of LDIF file '" + getCanonical( ldifFile )
358                     + "' skipped.  It has already been loaded on " + time + "." );
359         }
360         else
361         {
362             LdifFileLoader loader = new LdifFileLoader( directoryService.getAdminSession(), ldifFile, ldifFilters );
363             int count = loader.execute();
364             LOG.info( "Loaded " + count + " entries from LDIF file '" + getCanonical( ldifFile ) + "'" );
365             addFileEntry( ldifFile );
366         }
367     }
368     
369     
370     /**
371      * Load the ldif files if there are some
372      */
373     public void loadLdifs() throws Exception
374     {
375         // LOG and bail if property not set
376         if ( ldifDirectory == null )
377         {
378             LOG.info( "LDIF load directory not specified.  No LDIF files will be loaded." );
379             return;
380         }
381 
382         // LOG and bail if LDIF directory does not exists
383         if ( ! ldifDirectory.exists() )
384         {
385             LOG.warn( "LDIF load directory '{}' does not exist.  No LDIF files will be loaded.",
386                 getCanonical( ldifDirectory ) );
387             return;
388         }
389 
390 
391         LdapDN dn = new LdapDN( ServerDNConstants.ADMIN_SYSTEM_DN );
392         
393         // Must normalize the dn or - IllegalStateException!
394         AttributeTypeRegistry reg = directoryService.getRegistries().getAttributeTypeRegistry();
395         dn.normalize( reg.getNormalizerMapping() );
396         
397         ensureLdifFileBase();
398 
399         // if ldif directory is a file try to load it
400         if ( ldifDirectory.isFile() )
401         {
402             if ( LOG.isInfoEnabled() )
403             {
404                 LOG.info( "LDIF load directory '{}' is a file. Will attempt to load as LDIF.",
405                     getCanonical( ldifDirectory ) );
406             }
407 
408             try
409             {
410                 loadLdif( ldifDirectory );
411             }
412             catch ( Exception ne )
413             {
414                 // If the file can't be read, log the error, and stop
415                 // loading LDIFs.
416                 LOG.error( "Cannot load the ldif file '{}', error : ",
417                     ldifDirectory.getAbsolutePath(), 
418                     ne.getMessage() );
419                 throw ne;
420             }
421         }
422         else
423         {
424             // get all the ldif files within the directory (should be sorted alphabetically)
425             File[] ldifFiles = ldifDirectory.listFiles( new FileFilter()
426             {
427                 public boolean accept( File pathname )
428                 {
429                     boolean isLdif = pathname.getName().toLowerCase().endsWith( ".ldif" );
430                     return pathname.isFile() && pathname.canRead() && isLdif;
431                 }
432             } );
433     
434             // LOG and bail if we could not find any LDIF files
435             if ( ( ldifFiles == null ) || ( ldifFiles.length == 0 ) )
436             {
437                 LOG.warn( "LDIF load directory '{}' does not contain any LDIF files. No LDIF files will be loaded.", 
438                     getCanonical( ldifDirectory ) );
439                 return;
440             }
441     
442             // load all the ldif files and load each one that is loaded
443             for ( File ldifFile : ldifFiles )
444             {
445                 try
446                 {
447                     LOG.info(  "Loading LDIF file '{}'", ldifFile.getName() );
448                     loadLdif( ldifFile );
449                 }
450                 catch ( Exception ne )
451                 {
452                     // If the file can't be read, log the error, and stop
453                     // loading LDIFs.
454                     LOG.error( "Cannot load the ldif file '{}', error : {}", 
455                         ldifFile.getAbsolutePath(), 
456                         ne.getMessage() );
457                     throw ne;
458                 }
459             }
460         }
461     }
462 }