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.FileWriter;
24  import java.io.PrintWriter;
25  import java.util.Hashtable;
26  
27  import javax.naming.NameAlreadyBoundException;
28  import javax.naming.NamingException;
29  import javax.naming.directory.Attribute;
30  import javax.naming.directory.Attributes;
31  import javax.naming.directory.BasicAttributes;
32  import javax.naming.ldap.InitialLdapContext;
33  import javax.naming.ldap.LdapContext;
34  
35  import org.apache.commons.cli.CommandLine;
36  import org.apache.commons.cli.Option;
37  import org.apache.commons.cli.Options;
38  import org.apache.commons.lang.RandomStringUtils;
39  import org.apache.directory.daemon.AvailablePortFinder;
40  
41  
42  /**
43   * A capacity testing tool.  This command will generate bogus user
44   * entries and add them under a base DN.  It will output a table 
45   * of values mapping the capacity of the partition to the time it
46   * took to add an entry to it.
47   * 
48   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
49   * @version $Rev$
50   */
51  public class CapacityTestCommand extends ToolCommand
52  {
53      public static final String PORT_RANGE = "(" + AvailablePortFinder.MIN_PORT_NUMBER + ", "
54          + AvailablePortFinder.MAX_PORT_NUMBER + ")";
55  
56      private int port = 10389;
57      private String host = "localhost";
58      private String password = "secret";
59      private String baseDn = "ou=users,dc=example,dc=com";
60  
61  
62      public CapacityTestCommand()
63      {
64          super( "capacity" );
65      }
66  
67  
68      public void execute( CommandLine cmdline ) throws Exception
69      {
70          processOptions( cmdline );
71          getLayout().verifyInstallation();
72          String outputFile = cmdline.getOptionValue( 'f' );
73          PrintWriter out = null;
74  
75          if ( outputFile == null )
76          {
77              out = new PrintWriter( System.out );
78          }
79          else
80          {
81              out = new PrintWriter( new FileWriter( outputFile ) );
82          }
83  
84          if ( isDebugEnabled() )
85          {
86              out.println( "Parameters for capacity extended request:" );
87              out.println( "port = " + port );
88              out.println( "host = " + host );
89              out.println( "password = " + password );
90          }
91  
92          Hashtable env = new Hashtable();
93          env.put( "java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory" );
94          env.put( "java.naming.provider.url", "ldap://" + host + ":" + port );
95          env.put( "java.naming.security.principal", "uid=admin,ou=system" );
96          env.put( "java.naming.security.credentials", password );
97          env.put( "java.naming.security.authentication", "simple" );
98  
99          LdapContext ctx = new InitialLdapContext( env, null );
100 
101         // create the base dn if it does not exist
102         createBase( ctx );
103 
104         StringBuffer dnBuf = new StringBuffer();
105         StringBuffer outBuf = new StringBuffer();
106         int counter = 0;
107         if ( cmdline.hasOption( "s" ) )
108         {
109             counter = Integer.parseInt( cmdline.getOptionValue( 's' ) ) - 1;
110         }
111         int end = Integer.MAX_VALUE;
112         if ( cmdline.hasOption( "e" ) )
113         {
114             end = Integer.parseInt( cmdline.getOptionValue( 'e' ) );
115         }
116 
117         while ( counter < end )
118         {
119             counter++;
120             Attributes attrs = generateLdif( counter );
121             dnBuf.setLength( 0 );
122             dnBuf.append( "uid=user." ).append( counter ).append( "," ).append( baseDn );
123 
124             long startTime = System.currentTimeMillis();
125             ctx.createSubcontext( dnBuf.toString(), attrs );
126 
127             outBuf.setLength( 0 );
128             outBuf.append( counter ).append( " " ).append( System.currentTimeMillis() - startTime );
129             out.println( outBuf.toString() );
130             out.flush();
131         }
132     }
133 
134 
135     private boolean createBase( LdapContext ctx ) throws NamingException
136     {
137         Attributes attrs = new BasicAttributes( "objectClass", "organizationalUnit", true );
138         attrs.put( "ou", "users" );
139 
140         try
141         {
142             ctx.createSubcontext( "ou=users,dc=example,dc=com", attrs );
143             return true;
144         }
145         catch ( NameAlreadyBoundException e )
146         {
147             return false;
148         }
149     }
150 
151 
152     private Attributes generateLdif( int counter )
153     {
154         Attributes attrs = new BasicAttributes( "objectClass", "top", true );
155         Attribute oc = attrs.get( "objectClass" );
156         oc.add( "person" );
157         oc.add( "organizationalPerson" );
158         oc.add( "inetOrgPerson" );
159 
160         attrs.put( "givenName", RandomStringUtils.randomAlphabetic( 6 ) );
161         attrs.put( "sn", RandomStringUtils.randomAlphabetic( 9 ) );
162         attrs.put( "cn", RandomStringUtils.randomAlphabetic( 15 ) );
163         attrs.put( "initials", RandomStringUtils.randomAlphabetic( 2 ) );
164         attrs.put( "mail", RandomStringUtils.randomAlphabetic( 15 ) );
165         attrs.put( "userPassword", "password" );
166         attrs.put( "telephoneNumber", RandomStringUtils.randomNumeric( 10 ) );
167         attrs.put( "homePhone", RandomStringUtils.randomNumeric( 10 ) );
168         attrs.put( "pager", RandomStringUtils.randomNumeric( 10 ) );
169         attrs.put( "mobile", RandomStringUtils.randomNumeric( 10 ) );
170         attrs.put( "employeeNumber", String.valueOf( counter ) );
171         attrs.put( "street", RandomStringUtils.randomAlphabetic( 20 ) );
172         attrs.put( "l", RandomStringUtils.randomAlphabetic( 10 ) );
173         attrs.put( "st", RandomStringUtils.randomAlphabetic( 2 ) );
174         attrs.put( "postalCode", RandomStringUtils.randomAlphabetic( 5 ) );
175         attrs.put( "postalAddress", RandomStringUtils.randomAlphabetic( 20 ) );
176         attrs.put( "description", RandomStringUtils.randomAlphabetic( 20 ) );
177         return attrs;
178     }
179 
180 
181     private void processOptions( CommandLine cmd )
182     {
183         if ( isDebugEnabled() )
184         {
185             System.out.println( "Processing options for capacity test ..." );
186         }
187 
188         // -------------------------------------------------------------------
189         // figure out and error check the port value
190         // -------------------------------------------------------------------
191 
192         if ( cmd.hasOption( 'p' ) ) // - user provided port w/ -p takes precedence
193         {
194             String val = cmd.getOptionValue( 'p' );
195             try
196             {
197                 port = Integer.parseInt( val );
198             }
199             catch ( NumberFormatException e )
200             {
201                 System.err.println( "port value of '" + val + "' is not a number" );
202                 System.exit( 1 );
203             }
204 
205             if ( port > AvailablePortFinder.MAX_PORT_NUMBER )
206             {
207                 System.err.println( "port value of '" + val + "' is larger than max port number: "
208                     + AvailablePortFinder.MAX_PORT_NUMBER );
209                 System.exit( 1 );
210             }
211             else if ( port < AvailablePortFinder.MIN_PORT_NUMBER )
212             {
213                 System.err.println( "port value of '" + val + "' is smaller than the minimum port number: "
214                     + AvailablePortFinder.MIN_PORT_NUMBER );
215                 System.exit( 1 );
216             }
217 
218             if ( isDebugEnabled() )
219             {
220                 System.out.println( "port overriden by -p option: " + port );
221             }
222         }
223         else if ( getApacheDS() != null )
224         {
225             port = getApacheDS().getLdapService().getIpPort();
226 
227             if ( isDebugEnabled() )
228             {
229                 System.out.println( "port overriden by server.xml configuration: " + port );
230             }
231         }
232         else if ( isDebugEnabled() )
233         {
234             System.out.println( "port set to default: " + port );
235         }
236 
237         // -------------------------------------------------------------------
238         // figure out the host value
239         // -------------------------------------------------------------------
240 
241         if ( cmd.hasOption( 'h' ) )
242         {
243             host = cmd.getOptionValue( 'h' );
244 
245             if ( isDebugEnabled() )
246             {
247                 System.out.println( "host overriden by -h option: " + host );
248             }
249         }
250         else if ( isDebugEnabled() )
251         {
252             System.out.println( "host set to default: " + host );
253         }
254 
255         // -------------------------------------------------------------------
256         // figure out the password value
257         // -------------------------------------------------------------------
258 
259         if ( cmd.hasOption( 'w' ) )
260         {
261             password = cmd.getOptionValue( 'w' );
262 
263             if ( isDebugEnabled() )
264             {
265                 System.out.println( "password overriden by -w option: " + password );
266             }
267         }
268         else if ( isDebugEnabled() )
269         {
270             System.out.println( "password set to default: " + password );
271         }
272     }
273 
274 
275     public Options getOptions()
276     {
277         Options opts = new Options();
278         Option op = new Option( "f", "file", true, "file to output the stats to" );
279         op.setRequired( false );
280         opts.addOption( op );
281         op = new Option( "i", "install-path", true, "path to apacheds installation directory" );
282         op.setRequired( true );
283         opts.addOption( op );
284         op = new Option( "h", "host", true, "server host: defaults to localhost" );
285         op.setRequired( false );
286         opts.addOption( op );
287         op = new Option( "p", "port", true, "server port: defaults to 10389 or server.xml specified port" );
288         op.setRequired( false );
289         opts.addOption( op );
290         op = new Option( "w", "password", true, "the apacheds administrator's password: defaults to secret" );
291         op.setRequired( false );
292         opts.addOption( op );
293 
294         op = new Option( "s", "start", true, "start on id: number to start on (user.start)" );
295         op.setRequired( false );
296         opts.addOption( op );
297 
298         op = new Option( "e", "end", true, "end on id: number to end on (user.end)" );
299         op.setRequired( false );
300         opts.addOption( op );
301 
302         return opts;
303     }
304 }