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 }