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.tools;
21  
22  
23  import java.io.File;
24  import java.io.FileWriter;
25  import java.io.IOException;
26  import java.io.PrintWriter;
27  import java.util.ArrayList;
28  import java.util.HashSet;
29  import java.util.List;
30  import java.util.Set;
31  
32  import javax.naming.NamingEnumeration;
33  import javax.naming.directory.Attribute;
34  import javax.naming.directory.Attributes;
35  
36  import jdbm.helper.MRU;
37  import jdbm.recman.BaseRecordManager;
38  import jdbm.recman.CacheRecordManager;
39  
40  import org.apache.commons.cli.CommandLine;
41  import org.apache.commons.cli.Option;
42  import org.apache.commons.cli.Options;
43  import org.apache.directory.server.constants.ServerDNConstants;
44  import org.apache.directory.server.core.DefaultDirectoryService;
45  import org.apache.directory.server.core.DirectoryService;
46  import org.apache.directory.server.core.cursor.Cursor;
47  import org.apache.directory.server.core.entry.ServerEntry;
48  import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmIndex;
49  import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmMasterTable;
50  import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
51  import org.apache.directory.server.core.schema.PartitionSchemaLoader;
52  import org.apache.directory.server.schema.SerializableComparator;
53  import org.apache.directory.server.schema.bootstrap.ApacheSchema;
54  import org.apache.directory.server.schema.bootstrap.ApachemetaSchema;
55  import org.apache.directory.server.schema.bootstrap.BootstrapSchemaLoader;
56  import org.apache.directory.server.schema.bootstrap.CoreSchema;
57  import org.apache.directory.server.schema.bootstrap.Schema;
58  import org.apache.directory.server.schema.bootstrap.SystemSchema;
59  import org.apache.directory.server.schema.bootstrap.partition.DbFileListing;
60  import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
61  import org.apache.directory.server.schema.registries.DefaultOidRegistry;
62  import org.apache.directory.server.schema.registries.DefaultRegistries;
63  import org.apache.directory.server.schema.registries.OidRegistry;
64  import org.apache.directory.server.schema.registries.Registries;
65  import org.apache.directory.server.xdbm.Index;
66  import org.apache.directory.server.xdbm.Tuple;
67  import org.apache.directory.shared.ldap.MultiException;
68  import org.apache.directory.shared.ldap.exception.LdapConfigurationException;
69  import org.apache.directory.shared.ldap.exception.LdapNamingException;
70  import org.apache.directory.shared.ldap.ldif.LdifUtils;
71  import org.apache.directory.shared.ldap.message.ResultCodeEnum;
72  import org.apache.directory.shared.ldap.schema.AttributeType;
73  import org.apache.directory.shared.ldap.schema.UsageEnum;
74  import org.apache.directory.shared.ldap.util.Base64;
75  
76  
77  /**
78   * Simple tool used to dump the contents of a jdbm based partition.
79   * 
80   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
81   * @version $Rev: 493916 $
82   */
83  public class DumpCommand extends ToolCommand
84  {
85      private Registries bootstrapRegistries = new DefaultRegistries( "bootstrap", new BootstrapSchemaLoader(),
86          new DefaultOidRegistry() );
87      private Set exclusions = new HashSet();
88      private boolean includeOperational = false;
89  
90  
91      public DumpCommand()
92      {
93          super( "dump" );
94      }
95  
96  
97      private Registries loadRegistries() throws Exception
98      {
99          // --------------------------------------------------------------------
100         // Load the bootstrap schemas to start up the schema partition
101         // --------------------------------------------------------------------
102 
103         // setup temporary loader and temp registry 
104         BootstrapSchemaLoader loader = new BootstrapSchemaLoader();
105         OidRegistry oidRegistry = new DefaultOidRegistry();
106         final Registries registries = new DefaultRegistries( "bootstrap", loader, oidRegistry );
107 
108         // load essential bootstrap schemas 
109         Set<Schema> bootstrapSchemas = new HashSet<Schema>();
110         bootstrapSchemas.add( new ApachemetaSchema() );
111         bootstrapSchemas.add( new ApacheSchema() );
112         bootstrapSchemas.add( new CoreSchema() );
113         bootstrapSchemas.add( new SystemSchema() );
114         loader.loadWithDependencies( bootstrapSchemas, registries );
115 
116         // run referential integrity tests
117         List<Throwable> errors = registries.checkRefInteg();
118 
119         if ( !errors.isEmpty() )
120         {
121             MultiException e = new MultiException();
122             for ( Throwable t : errors )
123             {
124                 e.addThrowable( t );
125             }
126             
127             throw e;
128         }
129 
130         SerializableComparator.setRegistry( registries.getComparatorRegistry() );
131 
132         // --------------------------------------------------------------------
133         // Initialize schema partition or bomb out if we cannot find it on disk
134         // --------------------------------------------------------------------
135 
136         // If not present then we need to abort 
137         File schemaDirectory = new File( getLayout().getPartitionsDirectory(), "schema" );
138         if ( !schemaDirectory.exists() )
139         {
140             throw new LdapConfigurationException( "The following schema directory from "
141                 + "the installation layout could not be found:\n\t" + schemaDirectory );
142         }
143 
144         JdbmPartition schemaPartition = new JdbmPartition();
145         schemaPartition.setId( "schema" );
146         schemaPartition.setCacheSize( 1000 );
147 
148         DbFileListing listing;
149         try
150         {
151             listing = new DbFileListing();
152         }
153         catch ( IOException e )
154         {
155             throw new LdapNamingException( "Got IOException while trying to read DBFileListing: " + e.getMessage(),
156                 ResultCodeEnum.OTHER );
157         }
158 
159         Set<Index<?,ServerEntry>> indexedAttributes = new HashSet<Index<?,ServerEntry>>();
160 
161         for ( String attributeId : listing.getIndexedAttributes() )
162         {
163             indexedAttributes.add( new JdbmIndex( attributeId ) );
164         }
165 
166         schemaPartition.setIndexedAttributes( indexedAttributes );
167         schemaPartition.setSuffix( ServerDNConstants.OU_SCHEMA_DN );
168 
169         DirectoryService directoryService = new DefaultDirectoryService();
170         schemaPartition.init( directoryService );
171 
172         // --------------------------------------------------------------------
173         // Initialize schema subsystem and reset registries
174         // --------------------------------------------------------------------
175 
176         PartitionSchemaLoader schemaLoader = new PartitionSchemaLoader( schemaPartition, registries );
177         Registries globalRegistries = new DefaultRegistries( "global", schemaLoader, oidRegistry );
178         schemaLoader.loadEnabled( globalRegistries );
179         SerializableComparator.setRegistry( globalRegistries.getComparatorRegistry() );
180         return globalRegistries;
181     }
182 
183 
184     public void execute( CommandLine cmdline ) throws Exception
185     {
186         getLayout().verifyInstallation();
187         bootstrapRegistries = loadRegistries();
188 
189         includeOperational = cmdline.hasOption( 'o' );
190         String[] partitions = cmdline.getOptionValues( 'p' );
191         String outputFile = cmdline.getOptionValue( 'f' );
192         PrintWriter out = null;
193 
194         String[] excludedAttributes = cmdline.getOptionValues( 'e' );
195         if ( excludedAttributes != null )
196         {
197             AttributeTypeRegistry registry = bootstrapRegistries.getAttributeTypeRegistry();
198             for ( int ii = 0; ii < excludedAttributes.length; ii++ )
199             {
200                 AttributeType type = registry.lookup( excludedAttributes[ii] );
201                 exclusions.add( type.getName() );
202             }
203         }
204 
205         if ( outputFile == null )
206         {
207             out = new PrintWriter( System.out );
208         }
209         else
210         {
211             out = new PrintWriter( new FileWriter( outputFile ) );
212         }
213 
214         for ( int ii = 0; ii < partitions.length; ii++ )
215         {
216             File partitionDirectory = new File( getLayout().getPartitionsDirectory(), partitions[ii] );
217             out.println( "\n\n" );
218             dump( partitionDirectory, out );
219         }
220     }
221 
222 
223     private void dump( File partitionDirectory, PrintWriter out ) throws Exception
224     {
225         if ( !partitionDirectory.exists() )
226         {
227             System.err.println( "Partition directory " + partitionDirectory + " does not exist!" );
228             System.exit( 1 );
229         }
230 
231         out.println( "# ========================================================================" );
232         out.println( "# ApacheDS Tools Version: " + getVersion() );
233         out.println( "# Partition Directory: " + partitionDirectory );
234         out.println( "# ========================================================================\n\n" );
235 
236         String path = partitionDirectory.getPath() + File.separator + "master";
237         BaseRecordManager base = new BaseRecordManager( path );
238         base.disableTransactions();
239         CacheRecordManager recMan = new CacheRecordManager( base, new MRU( 1000 ) );
240 
241         JdbmMasterTable<ServerEntry> master = new JdbmMasterTable<ServerEntry>( recMan, bootstrapRegistries );
242         AttributeType attributeType = bootstrapRegistries.getAttributeTypeRegistry().lookup( "apacheUpdn" );
243         JdbmIndex idIndex = new JdbmIndex();
244         idIndex.setAttributeId( attributeType.getName() );
245         idIndex.setWkDirPath( partitionDirectory );
246         idIndex.setCacheSize( 1000 );
247         idIndex.setNumDupLimit( 1000 );
248         idIndex.init( attributeType, partitionDirectory );
249 
250         out.println( "#---------------------" );
251         Cursor<Tuple<Long,ServerEntry>> list = master.cursor();
252         StringBuffer buf = new StringBuffer();
253         while ( list.next() )
254         {
255             Tuple<Long,ServerEntry> tuple = list.get();
256             Long id = tuple.getKey();
257             String dn = ( String ) idIndex.reverseLookup( id );
258             Attributes entry = ( Attributes ) tuple.getValue();
259 
260             filterAttributes( dn, entry );
261 
262             buf.append( "# Entry: " ).append( id ).append( "\n#---------------------\n\n" );
263             if ( !LdifUtils.isLDIFSafe( dn ) )
264             {
265                 // If the DN isn't LdifSafe, it needs to be Base64 encoded.
266 
267                 buf.append( "dn:: " ).append( new String( Base64.encode( dn.getBytes() ) ) );
268             }
269             else
270             {
271                 buf.append( "dn: " ).append( dn );
272             }
273             buf.append( "\n" ).append( LdifUtils.convertToLdif( entry ) );
274             if ( list.next() )
275             {
276                 buf.append( "\n\n#---------------------\n" );
277             }
278             out.print( buf.toString() );
279             out.flush();
280             buf.setLength( 0 );
281         }
282     }
283 
284 
285     private void filterAttributes( String dn, Attributes entry ) throws Exception
286     {
287         List toRemove = new ArrayList();
288         AttributeTypeRegistry registry = bootstrapRegistries.getAttributeTypeRegistry();
289         NamingEnumeration attrs = entry.getAll();
290         while ( attrs.hasMore() )
291         {
292             Attribute attr = ( Attribute ) attrs.next();
293             if ( !registry.hasAttributeType( attr.getID() ) )
294             {
295                 if ( !isQuietEnabled() )
296                 {
297                     System.out
298                         .println( "# Cannot properly filter unrecognized attribute " + attr.getID() + " in " + dn );
299                 }
300                 continue;
301             }
302 
303             AttributeType type = registry.lookup( attr.getID() );
304             boolean isOperational = type.getUsage() != UsageEnum.USER_APPLICATIONS;
305             if ( exclusions.contains( attr.getID() ) || ( isOperational && ( !includeOperational ) ) )
306             {
307                 toRemove.add( attr.getID() );
308             }
309         }
310         for ( int ii = 0; ii < toRemove.size(); ii++ )
311         {
312             String id = ( String ) toRemove.get( ii );
313             entry.remove( id );
314             if ( isDebugEnabled() )
315             {
316                 System.out.println( "# Excluding attribute " + id + " in " + dn );
317             }
318         }
319     }
320 
321 
322     public Options getOptions()
323     {
324         Options opts = new Options();
325         Option op = new Option( "f", "file", true, "file to output the dump to" );
326         op.setRequired( false );
327         opts.addOption( op );
328         op = new Option( "p", "partitions", true, "the partitions to dump" );
329         op.setRequired( true );
330         op.setValueSeparator( File.pathSeparatorChar );
331         opts.addOption( op );
332         op = new Option( "e", "excluded-attributes", true, "the attributes to exclude" );
333         op.setRequired( false );
334         op.setValueSeparator( File.pathSeparatorChar );
335         opts.addOption( op );
336         op = new Option( "o", "include-operational", false, "include operational attributes: defaults to false" );
337         op.setRequired( false );
338         opts.addOption( op );
339         op = new Option( "i", "install-path", true, "path to apacheds installation directory" );
340         op.setRequired( true );
341         opts.addOption( op );
342         return opts;
343     }
344 }