001    /*
002     *   Licensed to the Apache Software Foundation (ASF) under one
003     *   or more contributor license agreements.  See the NOTICE file
004     *   distributed with this work for additional information
005     *   regarding copyright ownership.  The ASF licenses this file
006     *   to you under the Apache License, Version 2.0 (the
007     *   "License"); you may not use this file except in compliance
008     *   with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *   Unless required by applicable law or agreed to in writing,
013     *   software distributed under the License is distributed on an
014     *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *   KIND, either express or implied.  See the License for the
016     *   specific language governing permissions and limitations
017     *   under the License.
018     *
019     */
020    
021    package org.apache.directory.server.config;
022    
023    
024    import java.io.File;
025    import java.io.FilenameFilter;
026    import java.util.ArrayList;
027    import java.util.HashMap;
028    import java.util.HashSet;
029    import java.util.Iterator;
030    import java.util.List;
031    import java.util.Map;
032    import java.util.Set;
033    import java.util.TreeSet;
034    
035    import javax.naming.directory.SearchControls;
036    
037    import org.apache.directory.server.core.DefaultDirectoryService;
038    import org.apache.directory.server.core.DirectoryService;
039    import org.apache.directory.server.core.changelog.ChangeLog;
040    import org.apache.directory.server.core.changelog.DefaultChangeLog;
041    import org.apache.directory.server.core.entry.ClonedServerEntry;
042    import org.apache.directory.server.core.interceptor.Interceptor;
043    import org.apache.directory.server.core.journal.DefaultJournal;
044    import org.apache.directory.server.core.journal.DefaultJournalStore;
045    import org.apache.directory.server.core.journal.Journal;
046    import org.apache.directory.server.core.journal.JournalStore;
047    import org.apache.directory.server.core.partition.Partition;
048    import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmIndex;
049    import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
050    import org.apache.directory.server.core.partition.ldif.LdifPartition;
051    import org.apache.directory.server.dhcp.service.DhcpService;
052    import org.apache.directory.server.dhcp.service.StoreBasedDhcpService;
053    import org.apache.directory.server.dhcp.store.DhcpStore;
054    import org.apache.directory.server.dhcp.store.SimpleDhcpStore;
055    import org.apache.directory.server.dns.DnsServer;
056    import org.apache.directory.server.i18n.I18n;
057    import org.apache.directory.server.integration.http.HttpServer;
058    import org.apache.directory.server.integration.http.WebApp;
059    import org.apache.directory.server.kerberos.kdc.KdcServer;
060    import org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType;
061    import org.apache.directory.server.ldap.LdapServer;
062    import org.apache.directory.server.ntp.NtpServer;
063    import org.apache.directory.server.protocol.shared.transport.TcpTransport;
064    import org.apache.directory.server.protocol.shared.transport.Transport;
065    import org.apache.directory.server.protocol.shared.transport.UdpTransport;
066    import org.apache.directory.server.xdbm.ForwardIndexEntry;
067    import org.apache.directory.server.xdbm.Index;
068    import org.apache.directory.server.xdbm.IndexCursor;
069    import org.apache.directory.server.xdbm.search.SearchEngine;
070    import org.apache.directory.shared.ldap.NotImplementedException;
071    import org.apache.directory.shared.ldap.entry.StringValue;
072    import org.apache.directory.shared.ldap.entry.Entry;
073    import org.apache.directory.shared.ldap.entry.EntryAttribute;
074    import org.apache.directory.shared.ldap.entry.ServerEntry;
075    import org.apache.directory.shared.ldap.entry.Value;
076    import org.apache.directory.shared.ldap.filter.EqualityNode;
077    import org.apache.directory.shared.ldap.filter.PresenceNode;
078    import org.apache.directory.shared.ldap.ldif.LdifEntry;
079    import org.apache.directory.shared.ldap.ldif.LdifReader;
080    import org.apache.directory.shared.ldap.message.AliasDerefMode;
081    import org.apache.directory.shared.ldap.name.DN;
082    import org.apache.directory.shared.ldap.schema.SchemaManager;
083    import org.slf4j.Logger;
084    import org.slf4j.LoggerFactory;
085    
086    
087    /**
088     * A class used for reading the configuration present in a Partition
089     * and instantiate the necessary objects like DirectoryService, Interceptors etc.
090     *
091     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
092     * @version $Rev$, $Date$
093     */
094    public class ConfigPartitionReader
095    {
096        private static final Logger LOG = LoggerFactory.getLogger( ConfigPartitionReader.class );
097    
098        /** the partition which holds the configuration data */
099        private LdifPartition configPartition;
100    
101        /** the search engine of the partition */
102        private SearchEngine<ServerEntry, Long> se;
103    
104        /** the schema manager set in the config partition */
105        private SchemaManager schemaManager;
106    
107        /** the parent directory of the config partition's working directory */
108        private File workDir;
109    
110        /** LDIF file filter */
111        private FilenameFilter ldifFilter = new FilenameFilter()
112        {
113            public boolean accept( File file, String name )
114            {
115                if ( file.isDirectory() )
116                {
117                    return true;
118                }
119    
120                return file.getName().toLowerCase().endsWith( ".ldif" );
121            }
122        };
123    
124    
125        /**
126         * 
127         * Creates a new instance of ConfigPartitionReader.
128         *
129         * @param configPartition the non null config partition
130         */
131        public ConfigPartitionReader( LdifPartition configPartition )
132        {
133            if ( configPartition == null )
134            {
135                throw new IllegalArgumentException( I18n.err( I18n.ERR_503 ) );
136            }
137    
138            if ( !configPartition.isInitialized() )
139            {
140                throw new IllegalStateException( I18n.err( I18n.ERR_504 ) );
141            }
142    
143            this.configPartition = configPartition;
144            se = configPartition.getSearchEngine();
145            this.schemaManager = configPartition.getSchemaManager();
146            workDir = configPartition.getPartitionDir().getParentFile();
147        }
148    
149    
150        /**
151         * reads the LDAP server configuration and instantiates without setting a DirectoryService 
152         *
153         * @return the LdapServer instance without a DirectoryService
154         * @throws Exception
155         */
156        public LdapServer getLdapServer() throws Exception
157        {
158            EqualityNode<String> filter = new EqualityNode<String>( "objectClass", new StringValue( "ads-ldapServer" ) );
159            SearchControls controls = new SearchControls();
160            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
161    
162            IndexCursor<Long, ServerEntry, Long> cursor = se.cursor( configPartition.getSuffixDn(),
163                AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls );
164    
165            if ( !cursor.next() )
166            {
167                LOG.warn( "No LDAP server was configured under the DN {}", configPartition.getSuffixDn() );
168                return null;
169            }
170    
171            ForwardIndexEntry<Long, ServerEntry, Long> forwardEntry = ( ForwardIndexEntry<Long, ServerEntry, Long> ) cursor
172                .get();
173            cursor.close();
174    
175            ClonedServerEntry ldapServerEntry = configPartition.lookup( forwardEntry.getId() );
176            LOG.debug( "LDAP Server Entry {}", ldapServerEntry );
177    
178            if ( !isEnabled( ldapServerEntry ) )
179            {
180                return null;
181            }
182    
183            LdapServer server = new LdapServer();
184            server.setServiceId( getString( "ads-serverId", ldapServerEntry ) );
185    
186            DN transportsDN = new DN( getString( "ads-transports", ldapServerEntry ) );
187            transportsDN.normalize( schemaManager.getNormalizerMapping() );
188            Transport[] transports = getTransports( transportsDN );
189            server.setTransports( transports );
190    
191            return server;
192        }
193    
194    
195        public KdcServer getKdcServer() throws Exception
196        {
197            EqualityNode<String> filter = new EqualityNode<String>( "objectClass", new StringValue(
198                "ads-kerberosServer" ) );
199            SearchControls controls = new SearchControls();
200            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
201    
202            IndexCursor<Long, ServerEntry, Long> cursor = se.cursor( configPartition.getSuffixDn(),
203                AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls );
204    
205            if ( !cursor.next() )
206            {
207                LOG.warn( "No kerberos server was configured under the DN {}", configPartition.getSuffixDn() );
208                return null;
209            }
210    
211            ForwardIndexEntry<Long, ServerEntry, Long> forwardEntry = ( ForwardIndexEntry<Long, ServerEntry, Long> ) cursor
212                .get();
213            cursor.close();
214    
215            ClonedServerEntry kdcEntry = configPartition.lookup( forwardEntry.getId() );
216            LOG.debug( "kerberos server entry {}", kdcEntry );
217    
218            if ( !isEnabled( kdcEntry ) )
219            {
220                return null;
221            }
222    
223            KdcServer kdcServer = new KdcServer();
224    
225            kdcServer.setServiceId( getString( "ads-serverId", kdcEntry ) );
226    
227            DN transportsDN = new DN( getString( "ads-transports", kdcEntry ) );
228            transportsDN.normalize( schemaManager.getNormalizerMapping() );
229            Transport[] transports = getTransports( transportsDN );
230            kdcServer.setTransports( transports );
231    
232            // MAY attributes
233            EntryAttribute clockSkewAttr = kdcEntry.get( "ads-krbAllowableClockSkew" );
234    
235            if ( clockSkewAttr != null )
236            {
237                kdcServer.setAllowableClockSkew( Long.parseLong( clockSkewAttr.getString() ) );
238            }
239    
240            EntryAttribute encryptionTypeAttr = kdcEntry.get( "ads-krbEncryptionTypes" );
241    
242            if ( encryptionTypeAttr != null )
243            {
244                EncryptionType[] encryptionTypes = new EncryptionType[encryptionTypeAttr.size()];
245                Iterator<Value<?>> itr = encryptionTypeAttr.getAll();
246                int count = 0;
247    
248                while ( itr.hasNext() )
249                {
250                    Value<?> val = itr.next();
251                    encryptionTypes[count++] = EncryptionType.getByName( val.getString() );
252                }
253    
254                kdcServer.setEncryptionTypes( encryptionTypes );
255            }
256    
257            EntryAttribute emptyAddrAttr = kdcEntry.get( "ads-krbEmptyAddressesAllowed" );
258    
259            if ( emptyAddrAttr != null )
260            {
261                kdcServer.setEmptyAddressesAllowed( Boolean.parseBoolean( emptyAddrAttr.getString() ) );
262            }
263    
264            EntryAttribute fwdAllowedAttr = kdcEntry.get( "ads-krbForwardableAllowed" );
265    
266            if ( fwdAllowedAttr != null )
267            {
268                kdcServer.setForwardableAllowed( Boolean.parseBoolean( fwdAllowedAttr.getString() ) );
269            }
270    
271            EntryAttribute paEncTmstpAttr = kdcEntry.get( "ads-krbPaEncTimestampRequired" );
272    
273            if ( paEncTmstpAttr != null )
274            {
275                kdcServer.setPaEncTimestampRequired( Boolean.parseBoolean( paEncTmstpAttr.getString() ) );
276            }
277    
278            EntryAttribute posdtAllowedAttr = kdcEntry.get( "ads-krbPostdatedAllowed" );
279    
280            if ( posdtAllowedAttr != null )
281            {
282                kdcServer.setPostdatedAllowed( Boolean.parseBoolean( posdtAllowedAttr.getString() ) );
283            }
284    
285            EntryAttribute prxyAllowedAttr = kdcEntry.get( "ads-krbProxiableAllowed" );
286    
287            if ( prxyAllowedAttr != null )
288            {
289                kdcServer.setProxiableAllowed( Boolean.parseBoolean( prxyAllowedAttr.getString() ) );
290            }
291    
292            EntryAttribute rnwAllowedAttr = kdcEntry.get( "ads-krbRenewableAllowed" );
293    
294            if ( rnwAllowedAttr != null )
295            {
296                kdcServer.setRenewableAllowed( Boolean.parseBoolean( rnwAllowedAttr.getString() ) );
297            }
298    
299            EntryAttribute kdcPrncplAttr = kdcEntry.get( "ads-krbKdcPrincipal" );
300    
301            if ( kdcPrncplAttr != null )
302            {
303                kdcServer.setKdcPrincipal( kdcPrncplAttr.getString() );
304            }
305    
306            EntryAttribute maxRnwLfTimeAttr = kdcEntry.get( "ads-krbMaximumRenewableLifetime" );
307    
308            if ( maxRnwLfTimeAttr != null )
309            {
310                kdcServer.setMaximumRenewableLifetime( Long.parseLong( maxRnwLfTimeAttr.getString() ) );
311            }
312    
313            EntryAttribute maxTcktLfTimeAttr = kdcEntry.get( "ads-krbMaximumTicketLifetime" );
314    
315            if ( maxTcktLfTimeAttr != null )
316            {
317                kdcServer.setMaximumTicketLifetime( Long.parseLong( maxTcktLfTimeAttr.getString() ) );
318            }
319    
320            EntryAttribute prmRealmAttr = kdcEntry.get( "ads-krbPrimaryRealm" );
321    
322            if ( prmRealmAttr != null )
323            {
324                kdcServer.setPrimaryRealm( prmRealmAttr.getString() );
325            }
326    
327            EntryAttribute bdyCkhsmVerifyAttr = kdcEntry.get( "ads-krbBodyChecksumVerified" );
328    
329            if ( bdyCkhsmVerifyAttr != null )
330            {
331                kdcServer.setBodyChecksumVerified( Boolean.parseBoolean( bdyCkhsmVerifyAttr.getString() ) );
332            }
333    
334            return kdcServer;
335        }
336    
337    
338        public DnsServer getDnsServer() throws Exception
339        {
340            EqualityNode<String> filter = new EqualityNode<String>( "objectClass", new StringValue( "ads-dnsServer" ) );
341            SearchControls controls = new SearchControls();
342            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
343    
344            IndexCursor<Long, ServerEntry, Long> cursor = se.cursor( configPartition.getSuffixDn(),
345                AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls );
346    
347            if ( !cursor.next() )
348            {
349                LOG.warn( "No DNS server was configured under the DN {}", configPartition.getSuffixDn() );
350                return null;
351            }
352    
353            ForwardIndexEntry<Long, ServerEntry, Long> forwardEntry = ( ForwardIndexEntry<Long, ServerEntry, Long> ) cursor
354                .get();
355            cursor.close();
356    
357            ClonedServerEntry dnsEntry = configPartition.lookup( forwardEntry.getId() );
358            LOG.debug( "DNS server entry {}", dnsEntry );
359    
360            if ( !isEnabled( dnsEntry ) )
361            {
362                return null;
363            }
364    
365            DnsServer dnsServer = new DnsServer();
366    
367            dnsServer.setServiceId( getString( "ads-serverId", dnsEntry ) );
368    
369            DN transportsDN = new DN( getString( "ads-transports", dnsEntry ) );
370            transportsDN.normalize( schemaManager.getNormalizerMapping() );
371            Transport[] transports = getTransports( transportsDN );
372            dnsServer.setTransports( transports );
373    
374            return dnsServer;
375        }
376    
377    
378        //TODO making this method invisible cause there is no DhcpServer exists as of now
379        private DhcpService getDhcpServer() throws Exception
380        {
381            EqualityNode<String> filter = new EqualityNode<String>( "objectClass", new StringValue( "ads-dhcpServer" ) );
382            SearchControls controls = new SearchControls();
383            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
384    
385            IndexCursor<Long, ServerEntry, Long> cursor = se.cursor( configPartition.getSuffixDn(),
386                AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls );
387    
388            if ( !cursor.next() )
389            {
390                LOG.warn( "No DHCP server was configured under the DN {}", configPartition.getSuffixDn() );
391                return null;
392            }
393    
394            ForwardIndexEntry<Long, ServerEntry, Long> forwardEntry = ( ForwardIndexEntry<Long, ServerEntry, Long> ) cursor
395                .get();
396            cursor.close();
397    
398            ClonedServerEntry dhcpEntry = configPartition.lookup( forwardEntry.getId() );
399            LOG.debug( "DHCP server entry {}", dhcpEntry );
400    
401            if ( !isEnabled( dhcpEntry ) )
402            {
403                return null;
404            }
405    
406            DhcpStore dhcpStore = new SimpleDhcpStore();
407            DhcpService dhcpService = new StoreBasedDhcpService( dhcpStore );
408    
409            return dhcpService;
410        }
411    
412    
413        public NtpServer getNtpServer() throws Exception
414        {
415            EqualityNode<String> filter = new EqualityNode<String>( "objectClass", new StringValue( "ads-ntpServer" ) );
416            SearchControls controls = new SearchControls();
417            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
418    
419            IndexCursor<Long, ServerEntry, Long> cursor = se.cursor( configPartition.getSuffixDn(),
420                AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls );
421    
422            if ( !cursor.next() )
423            {
424                LOG.warn( "No NTP server was configured under the DN {}", configPartition.getSuffixDn() );
425                return null;
426            }
427    
428            ForwardIndexEntry<Long, ServerEntry, Long> forwardEntry = ( ForwardIndexEntry<Long, ServerEntry, Long> ) cursor
429                .get();
430            cursor.close();
431    
432            ClonedServerEntry ntpEntry = configPartition.lookup( forwardEntry.getId() );
433            LOG.debug( "NTP server entry {}", ntpEntry );
434    
435            if ( !isEnabled( ntpEntry ) )
436            {
437                return null;
438            }
439    
440            NtpServer ntpServer = new NtpServer();
441    
442            ntpServer.setServiceId( getString( "ads-serverId", ntpEntry ) );
443    
444            DN transportsDN = new DN( getString( "ads-transports", ntpEntry ) );
445            transportsDN.normalize( schemaManager.getNormalizerMapping() );
446            Transport[] transports = getTransports( transportsDN );
447            ntpServer.setTransports( transports );
448    
449            return ntpServer;
450        }
451    
452    
453        public HttpServer getHttpServer() throws Exception
454        {
455            EqualityNode<String> filter = new EqualityNode<String>( "objectClass", new StringValue( "ads-httpServer" ) );
456            SearchControls controls = new SearchControls();
457            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
458    
459            IndexCursor<Long, ServerEntry, Long> cursor = se.cursor( configPartition.getSuffixDn(),
460                AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls );
461    
462            if ( !cursor.next() )
463            {
464                LOG.warn( "No HTTP server was configured under the DN {}", configPartition.getSuffixDn() );
465                return null;
466            }
467    
468            ForwardIndexEntry<Long, ServerEntry, Long> forwardEntry = ( ForwardIndexEntry<Long, ServerEntry, Long> ) cursor
469                .get();
470            cursor.close();
471    
472            ClonedServerEntry httpEntry = configPartition.lookup( forwardEntry.getId() );
473            LOG.debug( "HTTP server entry {}", httpEntry );
474    
475            if ( !isEnabled( httpEntry ) )
476            {
477                return null;
478            }
479    
480            HttpServer httpServer = new HttpServer();
481    
482            EntryAttribute portAttr = httpEntry.get( "ads-systemPort" );
483    
484            if ( portAttr != null )
485            {
486                httpServer.setPort( Integer.parseInt( portAttr.getString() ) );
487            }
488    
489            EntryAttribute confFileAttr = httpEntry.get( "ads-httpConfFile" );
490    
491            if ( confFileAttr != null )
492            {
493                httpServer.setConfFile( confFileAttr.getString() );
494            }
495    
496            EntryAttribute webAppsAttr = httpEntry.get( "ads-httpWebApps" );
497    
498            if ( webAppsAttr != null )
499            {
500                DN webAppsDN = new DN( webAppsAttr.getString() );
501                webAppsDN.normalize( schemaManager.getNormalizerMapping() );
502    
503                Set<WebApp> webApps = getWebApps( webAppsDN );
504                httpServer.setWebApps( webApps );
505            }
506    
507            return httpServer;
508        }
509    
510    
511        /**
512         * 
513         * instantiates a DirectoryService based on the configuration present in the partition 
514         *
515         * @throws Exception
516         */
517        public DirectoryService getDirectoryService() throws Exception
518        {
519    
520            PresenceNode filter = new PresenceNode( "ads-directoryServiceId" );
521            SearchControls controls = new SearchControls();
522            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
523    
524            IndexCursor<Long, ServerEntry, Long> cursor = se.cursor( configPartition.getSuffixDn(),
525                AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls );
526    
527            if ( !cursor.next() )
528            {
529                // the DirectoryService is mandatory so throwing exception
530                throw new Exception( "No directoryService instance was configured under the DN "
531                    + configPartition.getSuffixDn() );
532            }
533    
534            ForwardIndexEntry<Long, ServerEntry, Long> forwardEntry = ( ForwardIndexEntry<Long, ServerEntry, Long> ) cursor
535                .get();
536            cursor.close();
537    
538            ClonedServerEntry dsEntry = configPartition.lookup( forwardEntry.getId() );
539    
540            LOG.debug( "directory service entry {}", dsEntry );
541    
542            DirectoryService dirService = new DefaultDirectoryService();
543            // MUST attributes
544            dirService.setInstanceId( getString( "ads-directoryServiceId", dsEntry ) );
545            dirService.setReplicaId( getInt( "ads-dsReplicaId", dsEntry ) );
546    
547            DN interceptorsDN = new DN( dsEntry.get( "ads-dsInterceptors" ).getString() );
548            interceptorsDN.normalize( configPartition.getSchemaManager().getNormalizerMapping() );
549            List<Interceptor> interceptors = getInterceptors( interceptorsDN );
550            dirService.setInterceptors( interceptors );
551    
552            DN partitionsDN = new DN( dsEntry.get( "ads-dsPartitions" ).getString() );
553            partitionsDN.normalize( configPartition.getSchemaManager().getNormalizerMapping() );
554    
555            Map<String, Partition> partitions = getPartitions( partitionsDN );
556    
557            Partition systemPartition = partitions.remove( "system" );
558    
559            if ( systemPartition == null )
560            {
561                throw new Exception( I18n.err( I18n.ERR_505 ) );
562            }
563    
564            dirService.setSystemPartition( systemPartition );
565            dirService.setPartitions( new HashSet<Partition>( partitions.values() ) );
566    
567            // MAY attributes
568            EntryAttribute acEnabledAttr = dsEntry.get( "ads-dsAccessControlEnabled" );
569    
570            if ( acEnabledAttr != null )
571            {
572                dirService.setAccessControlEnabled( Boolean.parseBoolean( acEnabledAttr.getString() ) );
573            }
574    
575            EntryAttribute anonAccessAttr = dsEntry.get( "ads-dsAllowAnonymousAccess" );
576    
577            if ( anonAccessAttr != null )
578            {
579                dirService.setAllowAnonymousAccess( Boolean.parseBoolean( anonAccessAttr.getString() ) );
580            }
581    
582            EntryAttribute changeLogAttr = dsEntry.get( "ads-dsChangeLog" );
583    
584            if ( changeLogAttr != null )
585            {
586                DN clDN = new DN( changeLogAttr.getString() );
587                clDN.normalize( schemaManager.getNormalizerMapping() );
588                ChangeLog cl = getChangeLog( clDN );
589                dirService.setChangeLog( cl );
590            }
591    
592            EntryAttribute denormAttr = dsEntry.get( "ads-dsDenormalizeOpAttrsEnabled" );
593    
594            if ( denormAttr != null )
595            {
596                dirService.setDenormalizeOpAttrsEnabled( Boolean.parseBoolean( denormAttr.getString() ) );
597            }
598    
599            EntryAttribute journalAttr = dsEntry.get( "ads-dsJournal" );
600    
601            if ( journalAttr != null )
602            {
603                DN journalDN = new DN( journalAttr.getString() );
604                journalDN.normalize( schemaManager.getNormalizerMapping() );
605                dirService.setJournal( getJournal( journalDN ) );
606            }
607    
608            EntryAttribute maxPduAttr = dsEntry.get( "ads-dsMaxPDUSize" );
609    
610            if ( maxPduAttr != null )
611            {
612                dirService.setMaxPDUSize( Integer.parseInt( maxPduAttr.getString() ) );
613            }
614    
615            EntryAttribute passwordHidAttr = dsEntry.get( "ads-dsPasswordHidden" );
616    
617            if ( passwordHidAttr != null )
618            {
619                dirService.setPasswordHidden( Boolean.parseBoolean( passwordHidAttr.getString() ) );
620            }
621    
622            EntryAttribute replAttr = dsEntry.get( "ads-dsReplication" );
623    
624            if ( replAttr != null )
625            {
626                // configure replication
627            }
628    
629            EntryAttribute syncPeriodAttr = dsEntry.get( "ads-dsSyncPeriodMillis" );
630    
631            if ( syncPeriodAttr != null )
632            {
633                // FIXME the DirectoryService interface doesn't have this setter
634                //dirService.setSyncPeriodMillis( Long.parseLong( syncPeriodAttr.getString() ) );
635            }
636    
637            EntryAttribute testEntryAttr = dsEntry.get( "ads-dsTestEntries" );
638    
639            if ( testEntryAttr != null )
640            {
641                String entryFilePath = testEntryAttr.getString();
642                dirService.setTestEntries( getTestEntries( entryFilePath ) );
643            }
644    
645            if ( !isEnabled( dsEntry ) )
646            {
647                // will only be useful if we ever allow more than one DS to be configured and
648                // switch between them
649                // decide which one to use based on this flag
650            }
651    
652            return dirService;
653        }
654    
655    
656        /**
657         * reads the Interceptor configuration and instantiates them in the order specified
658         *
659         * @param interceptorsDN the DN under which interceptors are configured
660         * @return a list of instantiated Interceptor objects
661         * @throws Exception
662         */
663        private List<Interceptor> getInterceptors( DN interceptorsDN ) throws Exception
664        {
665            PresenceNode filter = new PresenceNode( "ads-interceptorId" );
666            SearchControls controls = new SearchControls();
667            controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
668            IndexCursor<Long, ServerEntry, Long> cursor = se.cursor( interceptorsDN, AliasDerefMode.NEVER_DEREF_ALIASES,
669                filter, controls );
670    
671            Set<InterceptorConfig> set = new TreeSet<InterceptorConfig>();
672    
673            while ( cursor.next() )
674            {
675                ForwardIndexEntry<Long, ServerEntry, Long> forwardEntry = ( ForwardIndexEntry<Long, ServerEntry, Long> ) cursor
676                    .get();
677                ServerEntry interceptorEntry = configPartition.lookup( forwardEntry.getId() );
678    
679                String id = getString( "ads-interceptorId", interceptorEntry );
680                String fqcn = getString( "ads-interceptorClassName", interceptorEntry );
681                int order = getInt( "ads-interceptorOrder", interceptorEntry );
682    
683                InterceptorConfig intConfig = new InterceptorConfig( id, fqcn, order );
684                set.add( intConfig );
685            }
686    
687            cursor.close();
688    
689            List<Interceptor> interceptors = new ArrayList<Interceptor>();
690    
691            for ( InterceptorConfig iconfig : set )
692            {
693                try
694                {
695                    LOG.debug( "loading the interceptor class {} and instantiating", iconfig.getFqcn() );
696                    Interceptor ic = ( Interceptor ) Class.forName( iconfig.getFqcn() ).newInstance();
697                    interceptors.add( ic );
698                }
699                catch ( Exception e )
700                {
701                    throw e;
702                }
703            }
704    
705            return interceptors;
706        }
707    
708    
709        private Map<String, Partition> getPartitions( DN partitionsDN ) throws Exception
710        {
711            PresenceNode filter = new PresenceNode( "ads-partitionId" );
712            SearchControls controls = new SearchControls();
713            controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
714            IndexCursor<Long, ServerEntry, Long> cursor = se.cursor( partitionsDN, AliasDerefMode.NEVER_DEREF_ALIASES,
715                filter, controls );
716    
717            Map<String, Partition> partitions = new HashMap<String, Partition>();
718    
719            while ( cursor.next() )
720            {
721                ForwardIndexEntry<Long, ServerEntry, Long> forwardEntry = ( ForwardIndexEntry<Long, ServerEntry, Long> ) cursor
722                    .get();
723                ServerEntry partitionEntry = configPartition.lookup( forwardEntry.getId() );
724    
725                if ( !isEnabled( partitionEntry ) )
726                {
727                    continue;
728                }
729                EntryAttribute ocAttr = partitionEntry.get( "objectClass" );
730    
731                if ( ocAttr.contains( "ads-jdbmPartition" ) )
732                {
733                    JdbmPartition partition = getJdbmPartition( partitionEntry );
734                    partitions.put( partition.getId(), partition );
735                }
736                else
737                {
738                    throw new NotImplementedException( I18n.err( I18n.ERR_506 ) );
739                }
740            }
741    
742            cursor.close();
743    
744            return partitions;
745        }
746    
747    
748        private JdbmPartition getJdbmPartition( ServerEntry partitionEntry ) throws Exception
749        {
750            JdbmPartition partition = new JdbmPartition();
751            partition.setSchemaManager( schemaManager );
752    
753            partition.setId( getString( "ads-partitionId", partitionEntry ) );
754            partition.setPartitionDir( new File( workDir, partition.getId() ) );
755    
756            partition.setSuffix( getString( "ads-partitionSuffix", partitionEntry ) );
757    
758            EntryAttribute cacheAttr = partitionEntry.get( "ads-partitionCacheSize" );
759    
760            if ( cacheAttr != null )
761            {
762                partition.setCacheSize( Integer.parseInt( cacheAttr.getString() ) );
763            }
764    
765            EntryAttribute optimizerAttr = partitionEntry.get( "ads-jdbmPartitionOptimizerEnabled" );
766    
767            if ( optimizerAttr != null )
768            {
769                partition.setOptimizerEnabled( Boolean.parseBoolean( optimizerAttr.getString() ) );
770            }
771    
772            EntryAttribute syncAttr = partitionEntry.get( "ads-partitionSyncOnWrite" );
773    
774            if ( syncAttr != null )
775            {
776                partition.setSyncOnWrite( Boolean.parseBoolean( syncAttr.getString() ) );
777            }
778    
779            String indexesDN = partitionEntry.get( "ads-partitionIndexedAttributes" ).getString();
780    
781            Set<Index<?, ServerEntry, Long>> indexedAttributes = getIndexes( new DN( indexesDN ) );
782            partition.setIndexedAttributes( indexedAttributes );
783    
784            return partition;
785        }
786    
787    
788        private Set<Index<?, ServerEntry, Long>> getIndexes( DN indexesDN ) throws Exception
789        {
790            PresenceNode filter = new PresenceNode( "ads-indexAttributeId" );
791            SearchControls controls = new SearchControls();
792            controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
793            IndexCursor<Long, ServerEntry, Long> cursor = se.cursor( indexesDN, AliasDerefMode.NEVER_DEREF_ALIASES, filter,
794                controls );
795    
796            Set<Index<?, ServerEntry, Long>> indexes = new HashSet<Index<?, ServerEntry, Long>>();
797    
798            while ( cursor.next() )
799            {
800                ForwardIndexEntry<Long, ServerEntry, Long> forwardEntry = ( ForwardIndexEntry<Long, ServerEntry, Long> ) cursor
801                    .get();
802                ServerEntry indexEntry = configPartition.lookup( forwardEntry.getId() );
803    
804                if ( !isEnabled( indexEntry ) )
805                {
806                    continue;
807                }
808    
809                EntryAttribute ocAttr = indexEntry.get( "objectClass" );
810    
811                if ( ocAttr.contains( "ads-jdbmIndex" ) )
812                {
813                    indexes.add( getJdbmIndex( indexEntry ) );
814                }
815                else
816                {
817                    throw new NotImplementedException( I18n.err( I18n.ERR_506 ) );
818                }
819            }
820    
821            return indexes;
822        }
823    
824    
825        private JdbmIndex<?, ServerEntry> getJdbmIndex( ServerEntry indexEntry ) throws Exception
826        {
827            JdbmIndex<String, ServerEntry> index = new JdbmIndex<String, ServerEntry>();
828            index.setAttributeId( getString( "ads-indexAttributeId", indexEntry ) );
829            EntryAttribute cacheAttr = indexEntry.get( "ads-indexCacheSize" );
830    
831            if ( cacheAttr != null )
832            {
833                index.setCacheSize( Integer.parseInt( cacheAttr.getString() ) );
834            }
835    
836            return index;
837        }
838    
839    
840        private Transport[] getTransports( DN transportsDN ) throws Exception
841        {
842            PresenceNode filter = new PresenceNode( "ads-transportId" );
843            SearchControls controls = new SearchControls();
844            controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
845            IndexCursor<Long, ServerEntry, Long> cursor = se.cursor( transportsDN, AliasDerefMode.NEVER_DEREF_ALIASES,
846                filter, controls );
847    
848            List<Transport> transports = new ArrayList<Transport>();
849    
850            while ( cursor.next() )
851            {
852                ForwardIndexEntry<Long, ServerEntry, Long> forwardEntry = ( ForwardIndexEntry<Long, ServerEntry, Long> ) cursor
853                    .get();
854                ServerEntry transportEntry = configPartition.lookup( forwardEntry.getId() );
855    
856                if ( !isEnabled( transportEntry ) )
857                {
858                    continue;
859                }
860    
861                transports.add( getTransport( transportEntry ) );
862            }
863    
864            return transports.toArray( new Transport[]
865                {} );
866        }
867    
868    
869        private Transport getTransport( Entry transportEntry ) throws Exception
870        {
871            Transport transport = null;
872    
873            EntryAttribute ocAttr = transportEntry.get( "objectClass" );
874    
875            if ( ocAttr.contains( "ads-tcpTransport" ) )
876            {
877                transport = new TcpTransport();
878            }
879            else if ( ocAttr.contains( "ads-udpTransport" ) )
880            {
881                transport = new UdpTransport();
882            }
883    
884            transport.setPort( getInt( "ads-systemPort", transportEntry ) );
885            EntryAttribute addressAttr = transportEntry.get( "ads-transportAddress" );
886    
887            if ( addressAttr != null )
888            {
889                transport.setAddress( addressAttr.getString() );
890            }
891            else
892            {
893                transport.setAddress( "0.0.0.0" );
894            }
895    
896            EntryAttribute backlogAttr = transportEntry.get( "ads-transportBacklog" );
897    
898            if ( backlogAttr != null )
899            {
900                transport.setBackLog( Integer.parseInt( backlogAttr.getString() ) );
901            }
902    
903            EntryAttribute sslAttr = transportEntry.get( "ads-transportEnableSSL" );
904    
905            if ( sslAttr != null )
906            {
907                transport.setEnableSSL( Boolean.parseBoolean( sslAttr.getString() ) );
908            }
909    
910            EntryAttribute nbThreadsAttr = transportEntry.get( "ads-transportNbThreads" );
911    
912            if ( nbThreadsAttr != null )
913            {
914                transport.setNbThreads( Integer.parseInt( nbThreadsAttr.getString() ) );
915            }
916    
917            return transport;
918        }
919    
920    
921        private ChangeLog getChangeLog( DN changelogDN ) throws Exception
922        {
923            long id = configPartition.getEntryId( changelogDN.getNormName() );
924            Entry clEntry = configPartition.lookup( id );
925    
926            ChangeLog cl = new DefaultChangeLog();
927            EntryAttribute clEnabledAttr = clEntry.get( "ads-changeLogEnabled" );
928    
929            if ( clEnabledAttr != null )
930            {
931                cl.setEnabled( Boolean.parseBoolean( clEnabledAttr.getString() ) );
932            }
933    
934            EntryAttribute clExpAttr = clEntry.get( "ads-changeLogExposed" );
935    
936            if ( clExpAttr != null )
937            {
938                cl.setExposed( Boolean.parseBoolean( clExpAttr.getString() ) );
939            }
940    
941            return cl;
942        }
943    
944    
945        private Journal getJournal( DN journalDN ) throws Exception
946        {
947            long id = configPartition.getEntryId( journalDN.getNormName() );
948            Entry jlEntry = configPartition.lookup( id );
949    
950            Journal journal = new DefaultJournal();
951            JournalStore store = new DefaultJournalStore();
952    
953            store.setFileName( getString( "ads-journalFileName", jlEntry ) );
954    
955            EntryAttribute jlWorkDirAttr = jlEntry.get( "ads-journalWorkingDir" );
956    
957            if ( jlWorkDirAttr != null )
958            {
959                store.setWorkingDirectory( jlWorkDirAttr.getString() );
960            }
961    
962            EntryAttribute jlRotAttr = jlEntry.get( "ads-journalRotation" );
963    
964            if ( jlRotAttr != null )
965            {
966                journal.setRotation( Integer.parseInt( jlRotAttr.getString() ) );
967            }
968    
969            EntryAttribute jlEnabledAttr = jlEntry.get( "ads-journalEnabled" );
970    
971            if ( jlEnabledAttr != null )
972            {
973                journal.setEnabled( Boolean.parseBoolean( jlEnabledAttr.getString() ) );
974            }
975    
976            journal.setJournalStore( store );
977            return journal;
978        }
979    
980    
981        private List<LdifEntry> getTestEntries( String entryFilePath ) throws Exception
982        {
983            List<LdifEntry> entries = new ArrayList<LdifEntry>();
984    
985            File file = new File( entryFilePath );
986    
987            if ( !file.exists() )
988            {
989                LOG.warn( "LDIF test entry file path doesn't exist {}", entryFilePath );
990            }
991            else
992            {
993                LOG.info( "parsing the LDIF file(s) present at the path {}", entryFilePath );
994                loadEntries( file, entries );
995            }
996    
997            return entries;
998        }
999    
1000    
1001        private void loadEntries( File ldifFile, List<LdifEntry> entries ) throws Exception
1002        {
1003            if ( ldifFile.isDirectory() )
1004            {
1005                File[] files = ldifFile.listFiles( ldifFilter );
1006    
1007                for ( File f : files )
1008                {
1009                    loadEntries( f, entries );
1010                }
1011            }
1012            else
1013            {
1014                LdifReader reader = new LdifReader();
1015                entries.addAll( reader.parseLdifFile( ldifFile.getAbsolutePath() ) );
1016                reader.close();
1017            }
1018        }
1019    
1020    
1021        private Set<WebApp> getWebApps( DN webAppsDN ) throws Exception
1022        {
1023            PresenceNode filter = new PresenceNode( "ads-httpWarFile" );
1024            SearchControls controls = new SearchControls();
1025            controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
1026            IndexCursor<Long, ServerEntry, Long> cursor = se.cursor( webAppsDN, AliasDerefMode.NEVER_DEREF_ALIASES, filter,
1027                controls );
1028    
1029            Set<WebApp> webApps = new HashSet<WebApp>();
1030    
1031            while ( cursor.next() )
1032            {
1033                ForwardIndexEntry<Long, ServerEntry, Long> forwardEntry = ( ForwardIndexEntry<Long, ServerEntry, Long> ) cursor
1034                    .get();
1035                ServerEntry webAppEntry = configPartition.lookup( forwardEntry.getId() );
1036    
1037                WebApp app = new WebApp();
1038                app.setWarFile( getString( "ads-httpWarFile", webAppEntry ) );
1039    
1040                EntryAttribute ctxPathAttr = webAppEntry.get( "ads-httpAppCtxPath" );
1041    
1042                if ( ctxPathAttr != null )
1043                {
1044                    app.setContextPath( ctxPathAttr.getString() );
1045                }
1046    
1047                webApps.add( app );
1048            }
1049    
1050            return webApps;
1051        }
1052    
1053        /**
1054         * internal class used for holding the Interceptor classname and order configuration
1055         */
1056        private class InterceptorConfig implements Comparable<InterceptorConfig>
1057        {
1058            private String id;
1059            private String fqcn;
1060            private int order;
1061    
1062    
1063            public InterceptorConfig( String id, String fqcn, int order )
1064            {
1065                if ( order < 1 )
1066                {
1067                    throw new IllegalArgumentException( I18n.err( I18n.ERR_507 ) );
1068                }
1069    
1070                this.id = id;
1071                this.fqcn = fqcn;
1072                this.order = order;
1073            }
1074    
1075    
1076            public int compareTo( InterceptorConfig o )
1077            {
1078                if ( order > o.order )
1079                {
1080                    return 1;
1081                }
1082                else if ( order < o.order )
1083                {
1084                    return -1;
1085                }
1086    
1087                return 0;
1088            }
1089    
1090    
1091            /**
1092             * @return the fqcn
1093             */
1094            public String getFqcn()
1095            {
1096                return fqcn;
1097            }
1098    
1099        }
1100    
1101    
1102        private String getString( String attrName, Entry entry ) throws Exception
1103        {
1104            return entry.get( attrName ).getString();
1105        }
1106    
1107    
1108        private int getInt( String attrName, Entry entry ) throws Exception
1109        {
1110            return Integer.parseInt( entry.get( attrName ).getString() );
1111        }
1112    
1113    
1114        private boolean isEnabled( Entry entry ) throws Exception
1115        {
1116            EntryAttribute enabledAttr = entry.get( "ads-enabled" );
1117            if ( enabledAttr != null )
1118            {
1119                return Boolean.parseBoolean( enabledAttr.getString() );
1120            }
1121            else
1122            {
1123                return true;
1124            }
1125        }
1126    }