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    package org.apache.directory.server.tools;
021    
022    
023    import java.io.FileWriter;
024    import java.io.PrintWriter;
025    import java.util.Hashtable;
026    
027    import javax.naming.NameAlreadyBoundException;
028    import javax.naming.NamingException;
029    import javax.naming.directory.Attribute;
030    import javax.naming.directory.Attributes;
031    import javax.naming.directory.BasicAttributes;
032    import javax.naming.ldap.InitialLdapContext;
033    import javax.naming.ldap.LdapContext;
034    
035    import org.apache.commons.cli.CommandLine;
036    import org.apache.commons.cli.Option;
037    import org.apache.commons.cli.Options;
038    import org.apache.commons.lang.RandomStringUtils;
039    import org.apache.directory.daemon.AvailablePortFinder;
040    import org.apache.directory.server.i18n.I18n;
041    
042    
043    /**
044     * A capacity testing tool.  This command will generate bogus user
045     * entries and add them under a base DN.  It will output a table 
046     * of values mapping the capacity of the partition to the time it
047     * took to add an entry to it.
048     * 
049     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
050     * @version $Rev$
051     */
052    public class CapacityTestCommand extends ToolCommand
053    {
054        public static final String PORT_RANGE = "(" + AvailablePortFinder.MIN_PORT_NUMBER + ", "
055            + AvailablePortFinder.MAX_PORT_NUMBER + ")";
056    
057        private int port = 10389;
058        private String host = "localhost";
059        private String password = "secret";
060        private String baseDn = "ou=users,dc=example,dc=com";
061    
062    
063        public CapacityTestCommand()
064        {
065            super( "capacity" );
066        }
067    
068    
069        public void execute( CommandLine cmdline ) throws Exception
070        {
071            processOptions( cmdline );
072            getLayout().verifyInstallation();
073            String outputFile = cmdline.getOptionValue( 'f' );
074            PrintWriter out = null;
075    
076            if ( outputFile == null )
077            {
078                out = new PrintWriter( System.out );
079            }
080            else
081            {
082                out = new PrintWriter( new FileWriter( outputFile ) );
083            }
084    
085            if ( isDebugEnabled() )
086            {
087                out.println( "Parameters for capacity extended request:" );
088                out.println( "port = " + port );
089                out.println( "host = " + host );
090                out.println( "password = " + password );
091            }
092    
093            Hashtable env = new Hashtable();
094            env.put( "java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory" );
095            env.put( "java.naming.provider.url", "ldap://" + host + ":" + port );
096            env.put( "java.naming.security.principal", "uid=admin,ou=system" );
097            env.put( "java.naming.security.credentials", password );
098            env.put( "java.naming.security.authentication", "simple" );
099    
100            LdapContext ctx = new InitialLdapContext( env, null );
101    
102            // create the base dn if it does not exist
103            createBase( ctx );
104    
105            StringBuffer dnBuf = new StringBuffer();
106            StringBuffer outBuf = new StringBuffer();
107            int counter = 0;
108            if ( cmdline.hasOption( "s" ) )
109            {
110                counter = Integer.parseInt( cmdline.getOptionValue( 's' ) ) - 1;
111            }
112            int end = Integer.MAX_VALUE;
113            if ( cmdline.hasOption( "e" ) )
114            {
115                end = Integer.parseInt( cmdline.getOptionValue( 'e' ) );
116            }
117    
118            while ( counter < end )
119            {
120                counter++;
121                Attributes attrs = generateLdif( counter );
122                dnBuf.setLength( 0 );
123                dnBuf.append( "uid=user." ).append( counter ).append( "," ).append( baseDn );
124    
125                long startTime = System.currentTimeMillis();
126                ctx.createSubcontext( dnBuf.toString(), attrs );
127    
128                outBuf.setLength( 0 );
129                outBuf.append( counter ).append( " " ).append( System.currentTimeMillis() - startTime );
130                out.println( outBuf.toString() );
131                out.flush();
132            }
133        }
134    
135    
136        private boolean createBase( LdapContext ctx ) throws NamingException
137        {
138            Attributes attrs = new BasicAttributes( "objectClass", "organizationalUnit", true );
139            attrs.put( "ou", "users" );
140    
141            try
142            {
143                ctx.createSubcontext( "ou=users,dc=example,dc=com", attrs );
144                return true;
145            }
146            catch ( NameAlreadyBoundException e )
147            {
148                return false;
149            }
150        }
151    
152    
153        private Attributes generateLdif( int counter )
154        {
155            Attributes attrs = new BasicAttributes( "objectClass", "top", true );
156            Attribute oc = attrs.get( "objectClass" );
157            oc.add( "person" );
158            oc.add( "organizationalPerson" );
159            oc.add( "inetOrgPerson" );
160    
161            attrs.put( "givenName", RandomStringUtils.randomAlphabetic( 6 ) );
162            attrs.put( "sn", RandomStringUtils.randomAlphabetic( 9 ) );
163            attrs.put( "cn", RandomStringUtils.randomAlphabetic( 15 ) );
164            attrs.put( "initials", RandomStringUtils.randomAlphabetic( 2 ) );
165            attrs.put( "mail", RandomStringUtils.randomAlphabetic( 15 ) );
166            attrs.put( "userPassword", "password" );
167            attrs.put( "telephoneNumber", RandomStringUtils.randomNumeric( 10 ) );
168            attrs.put( "homePhone", RandomStringUtils.randomNumeric( 10 ) );
169            attrs.put( "pager", RandomStringUtils.randomNumeric( 10 ) );
170            attrs.put( "mobile", RandomStringUtils.randomNumeric( 10 ) );
171            attrs.put( "employeeNumber", String.valueOf( counter ) );
172            attrs.put( "street", RandomStringUtils.randomAlphabetic( 20 ) );
173            attrs.put( "l", RandomStringUtils.randomAlphabetic( 10 ) );
174            attrs.put( "st", RandomStringUtils.randomAlphabetic( 2 ) );
175            attrs.put( "postalCode", RandomStringUtils.randomAlphabetic( 5 ) );
176            attrs.put( "postalAddress", RandomStringUtils.randomAlphabetic( 20 ) );
177            attrs.put( "description", RandomStringUtils.randomAlphabetic( 20 ) );
178            return attrs;
179        }
180    
181    
182        private void processOptions( CommandLine cmd )
183        {
184            if ( isDebugEnabled() )
185            {
186                System.out.println( "Processing options for capacity test ..." );
187            }
188    
189            // -------------------------------------------------------------------
190            // figure out and error check the port value
191            // -------------------------------------------------------------------
192    
193            if ( cmd.hasOption( 'p' ) ) // - user provided port w/ -p takes precedence
194            {
195                String val = cmd.getOptionValue( 'p' );
196                try
197                {
198                    port = Integer.parseInt( val );
199                }
200                catch ( NumberFormatException e )
201                {
202                    System.err.println( I18n.err( I18n.ERR_193, val ) );
203                    System.exit( 1 );
204                }
205    
206                if ( port > AvailablePortFinder.MAX_PORT_NUMBER )
207                {
208                    System.err.println( I18n.err( I18n.ERR_194, val, AvailablePortFinder.MAX_PORT_NUMBER ) );
209                    System.exit( 1 );
210                }
211                else if ( port < AvailablePortFinder.MIN_PORT_NUMBER )
212                {
213                    System.err.println( I18n.err( I18n.ERR_195, val, AvailablePortFinder.MIN_PORT_NUMBER ) );
214                    System.exit( 1 );
215                }
216    
217                if ( isDebugEnabled() )
218                {
219                    System.out.println( "port overriden by -p option: " + port );
220                }
221            }
222            else if ( getApacheDS() != null )
223            {
224                port = getApacheDS().getLdapServer().getPort();
225    
226                if ( isDebugEnabled() )
227                {
228                    System.out.println( "port overriden by server.xml configuration: " + port );
229                }
230            }
231            else if ( isDebugEnabled() )
232            {
233                System.out.println( "port set to default: " + port );
234            }
235    
236            // -------------------------------------------------------------------
237            // figure out the host value
238            // -------------------------------------------------------------------
239    
240            if ( cmd.hasOption( 'h' ) )
241            {
242                host = cmd.getOptionValue( 'h' );
243    
244                if ( isDebugEnabled() )
245                {
246                    System.out.println( "host overriden by -h option: " + host );
247                }
248            }
249            else if ( isDebugEnabled() )
250            {
251                System.out.println( "host set to default: " + host );
252            }
253    
254            // -------------------------------------------------------------------
255            // figure out the password value
256            // -------------------------------------------------------------------
257    
258            if ( cmd.hasOption( 'w' ) )
259            {
260                password = cmd.getOptionValue( 'w' );
261    
262                if ( isDebugEnabled() )
263                {
264                    System.out.println( "password overriden by -w option: " + password );
265                }
266            }
267            else if ( isDebugEnabled() )
268            {
269                System.out.println( "password set to default: " + password );
270            }
271        }
272    
273    
274        public Options getOptions()
275        {
276            Options opts = new Options();
277            Option op = new Option( "f", "file", true, "file to output the stats to" );
278            op.setRequired( false );
279            opts.addOption( op );
280            op = new Option( "i", "install-path", true, "path to apacheds installation directory" );
281            op.setRequired( true );
282            opts.addOption( op );
283            op = new Option( "h", "host", true, "server host: defaults to localhost" );
284            op.setRequired( false );
285            opts.addOption( op );
286            op = new Option( "p", "port", true, "server port: defaults to 10389 or server.xml specified port" );
287            op.setRequired( false );
288            opts.addOption( op );
289            op = new Option( "w", "password", true, "the apacheds administrator's password: defaults to secret" );
290            op.setRequired( false );
291            opts.addOption( op );
292    
293            op = new Option( "s", "start", true, "start on id: number to start on (user.start)" );
294            op.setRequired( false );
295            opts.addOption( op );
296    
297            op = new Option( "e", "end", true, "end on id: number to end on (user.end)" );
298            op.setRequired( false );
299            opts.addOption( op );
300    
301            return opts;
302        }
303    }