0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: *
0017: */
0018:
0019: package org.apache.jmeter.protocol.ldap.sampler;
0020:
0021: import java.io.UnsupportedEncodingException;
0022: import java.util.ArrayList;
0023: import java.util.Collections;
0024: import java.util.Comparator;
0025: import java.util.Hashtable;
0026: import java.util.Iterator;
0027: import java.util.Map;
0028:
0029: import javax.naming.NamingEnumeration;
0030: import javax.naming.NamingException;
0031: import javax.naming.directory.Attribute;
0032: import javax.naming.directory.Attributes;
0033: import javax.naming.directory.BasicAttribute;
0034: import javax.naming.directory.BasicAttributes;
0035: import javax.naming.directory.DirContext;
0036: import javax.naming.directory.InitialDirContext;
0037: import javax.naming.directory.ModificationItem;
0038: import javax.naming.directory.SearchResult;
0039:
0040: import org.apache.commons.lang.StringEscapeUtils;
0041: import org.apache.jmeter.config.Argument;
0042: import org.apache.jmeter.config.Arguments;
0043: import org.apache.jmeter.engine.event.LoopIterationEvent;
0044: import org.apache.jmeter.protocol.ldap.config.gui.LDAPArgument;
0045: import org.apache.jmeter.protocol.ldap.config.gui.LDAPArguments;
0046: import org.apache.jmeter.samplers.AbstractSampler;
0047: import org.apache.jmeter.samplers.Entry;
0048: import org.apache.jmeter.samplers.SampleResult;
0049: import org.apache.jmeter.testelement.TestListener;
0050: import org.apache.jmeter.testelement.property.PropertyIterator;
0051: import org.apache.jmeter.testelement.property.StringProperty;
0052: import org.apache.jmeter.testelement.property.TestElementProperty;
0053: import org.apache.jmeter.util.JMeterUtils;
0054: import org.apache.jorphan.logging.LoggingManager;
0055: import org.apache.jorphan.util.XMLBuffer;
0056: import org.apache.log.Logger;
0057:
0058: /*******************************************************************************
0059: * Ldap Sampler class is main class for the LDAP test. This will control all the
0060: * test available in the LDAP Test.
0061: ******************************************************************************/
0062:
0063: public class LDAPExtSampler extends AbstractSampler implements
0064: TestListener {
0065:
0066: private static final Logger log = LoggingManager
0067: .getLoggerForClass();
0068:
0069: /*
0070: * The following strings are used in the test plan, and the values must not be changed
0071: * if test plans are to be upwardly compatible.
0072: */
0073: public final static String SERVERNAME = "servername"; // $NON-NLS-1$
0074:
0075: public final static String PORT = "port"; // $NON-NLS-1$
0076:
0077: public final static String SECURE = "secure"; // $NON-NLS-1$
0078:
0079: public final static String ROOTDN = "rootdn"; // $NON-NLS-1$
0080:
0081: public final static String TEST = "test"; // $NON-NLS-1$
0082:
0083: // These are values for the TEST attribute above
0084: public final static String ADD = "add"; // $NON-NLS-1$
0085:
0086: public final static String MODIFY = "modify"; // $NON-NLS-1$
0087:
0088: public final static String BIND = "bind"; // $NON-NLS-1$
0089:
0090: public final static String UNBIND = "unbind"; // $NON-NLS-1$
0091:
0092: public final static String DELETE = "delete"; // $NON-NLS-1$
0093:
0094: public final static String SEARCH = "search"; // $NON-NLS-1$
0095: // end of TEST values
0096:
0097: public final static String SEARCHBASE = "search"; // $NON-NLS-1$
0098:
0099: public final static String SEARCHFILTER = "searchfilter"; // $NON-NLS-1$
0100:
0101: public final static String ARGUMENTS = "arguments"; // $NON-NLS-1$
0102:
0103: public final static String LDAPARGUMENTS = "ldaparguments"; // $NON-NLS-1$
0104:
0105: public final static String BASE_ENTRY_DN = "base_entry_dn"; // $NON-NLS-1$
0106:
0107: public final static String SCOPE = "scope"; // $NON-NLS-1$
0108:
0109: public final static String COUNTLIM = "countlimit"; // $NON-NLS-1$
0110:
0111: public final static String TIMELIM = "timelimit"; // $NON-NLS-1$
0112:
0113: public final static String ATTRIBS = "attributes"; // $NON-NLS-1$
0114:
0115: public final static String RETOBJ = "return_object"; // $NON-NLS-1$
0116:
0117: public final static String DEREF = "deref_aliases"; // $NON-NLS-1$
0118:
0119: public final static String USERDN = "user_dn"; // $NON-NLS-1$
0120:
0121: public final static String USERPW = "user_pw"; // $NON-NLS-1$
0122:
0123: public final static String SBIND = "sbind"; // $NON-NLS-1$
0124:
0125: public final static String COMPARE = "compare"; // $NON-NLS-1$
0126:
0127: public final static String CONNTO = "connection_timeout"; // $NON-NLS-1$
0128:
0129: public final static String COMPAREDN = "comparedn"; // $NON-NLS-1$
0130:
0131: public final static String COMPAREFILT = "comparefilt"; // $NON-NLS-1$
0132:
0133: public final static String PARSEFLAG = "parseflag"; // $NON-NLS-1$
0134:
0135: public final static String RENAME = "rename"; // $NON-NLS-1$
0136:
0137: public final static String MODDDN = "modddn"; // $NON-NLS-1$
0138:
0139: public final static String NEWDN = "newdn"; // $NON-NLS-1$
0140:
0141: private static final String SEMI_COLON = ";"; // $NON-NLS-1$
0142:
0143: private static Hashtable ldapConnections = new Hashtable();
0144:
0145: private static Hashtable ldapContexts = new Hashtable();
0146:
0147: private static final int MAX_SORTED_RESULTS = JMeterUtils
0148: .getPropDefault("ldapsampler.max_sorted_results", 1000); // $NON-NLS-1$
0149:
0150: /***************************************************************************
0151: * !ToDo (Constructor description)
0152: **************************************************************************/
0153: public LDAPExtSampler() {
0154: }
0155:
0156: public void setConnTimeOut(String connto) {
0157: setProperty(new StringProperty(CONNTO, connto));
0158: }
0159:
0160: public String getConnTimeOut() {
0161: return getPropertyAsString(CONNTO);
0162: }
0163:
0164: public void setSecure(String sec) {
0165: setProperty(new StringProperty(SECURE, sec));
0166: }
0167:
0168: public boolean isSecure() {
0169: return getPropertyAsBoolean(SECURE);
0170: }
0171:
0172: public boolean isParseFlag() {
0173: return getPropertyAsBoolean(PARSEFLAG);
0174: }
0175:
0176: public void setParseFlag(String parseFlag) {
0177: setProperty(new StringProperty(PARSEFLAG, parseFlag));
0178: }
0179:
0180: /***************************************************************************
0181: * Gets the username attribute of the LDAP object
0182: *
0183: * @return The username
0184: **************************************************************************/
0185:
0186: public String getUserDN() {
0187: return getPropertyAsString(USERDN);
0188: }
0189:
0190: /***************************************************************************
0191: * Sets the username attribute of the LDAP object
0192: *
0193: **************************************************************************/
0194:
0195: public void setUserDN(String newUserDN) {
0196: setProperty(new StringProperty(USERDN, newUserDN));
0197: }
0198:
0199: /***************************************************************************
0200: * Gets the password attribute of the LDAP object
0201: *
0202: * @return The password
0203: **************************************************************************/
0204:
0205: public String getUserPw() {
0206: return getPropertyAsString(USERPW);
0207: }
0208:
0209: /***************************************************************************
0210: * Sets the password attribute of the LDAP object
0211: *
0212: **************************************************************************/
0213:
0214: public void setUserPw(String newUserPw) {
0215: setProperty(new StringProperty(USERPW, newUserPw));
0216: }
0217:
0218: /***************************************************************************
0219: * Sets the Servername attribute of the ServerConfig object
0220: *
0221: * @param servername
0222: * The new servername value
0223: **************************************************************************/
0224: public void setServername(String servername) {
0225: setProperty(new StringProperty(SERVERNAME, servername));
0226: }
0227:
0228: /***************************************************************************
0229: * Sets the Port attribute of the ServerConfig object
0230: *
0231: * @param port
0232: * The new Port value
0233: **************************************************************************/
0234: public void setPort(String port) {
0235: setProperty(new StringProperty(PORT, port));
0236: }
0237:
0238: /***************************************************************************
0239: * Gets the servername attribute of the LDAPSampler object
0240: *
0241: * @return The Servername value
0242: **************************************************************************/
0243:
0244: public String getServername() {
0245: return getPropertyAsString(SERVERNAME);
0246: }
0247:
0248: /***************************************************************************
0249: * Gets the Port attribute of the LDAPSampler object
0250: *
0251: * @return The Port value
0252: **************************************************************************/
0253:
0254: public String getPort() {
0255: return getPropertyAsString(PORT);
0256: }
0257:
0258: /***************************************************************************
0259: * Sets the Rootdn attribute of the LDAPSampler object
0260: *
0261: * @param newRootdn
0262: * The new rootdn value
0263: **************************************************************************/
0264: public void setRootdn(String newRootdn) {
0265: this .setProperty(ROOTDN, newRootdn);
0266: }
0267:
0268: /***************************************************************************
0269: * Gets the Rootdn attribute of the LDAPSampler object
0270: *
0271: * @return The Rootdn value
0272: **************************************************************************/
0273: public String getRootdn() {
0274: return getPropertyAsString(ROOTDN);
0275: }
0276:
0277: /***************************************************************************
0278: * Gets the search scope attribute of the LDAPSampler object
0279: *
0280: * @return The scope value
0281: **************************************************************************/
0282: public String getScope() {
0283: return getPropertyAsString(SCOPE);
0284: }
0285:
0286: public int getScopeAsInt() {
0287: return getPropertyAsInt(SCOPE);
0288: }
0289:
0290: /***************************************************************************
0291: * Sets the search scope attribute of the LDAPSampler object
0292: *
0293: * @param newScope
0294: * The new scope value
0295: **************************************************************************/
0296: public void setScope(String newScope) {
0297: this .setProperty(SCOPE, newScope);
0298: }
0299:
0300: /***************************************************************************
0301: * Gets the size limit attribute of the LDAPSampler object
0302: *
0303: * @return The size limit
0304: **************************************************************************/
0305: public String getCountlim() {
0306: return getPropertyAsString(COUNTLIM);
0307: }
0308:
0309: public long getCountlimAsLong() {
0310: return getPropertyAsLong(COUNTLIM);
0311: }
0312:
0313: /***************************************************************************
0314: * Sets the size limit attribute of the LDAPSampler object
0315: *
0316: * @param newClim
0317: * The new size limit value
0318: **************************************************************************/
0319: public void setCountlim(String newClim) {
0320: this .setProperty(COUNTLIM, newClim);
0321: }
0322:
0323: /***************************************************************************
0324: * Gets the time limit attribute of the LDAPSampler object
0325: *
0326: * @return The time limit
0327: **************************************************************************/
0328: public String getTimelim() {
0329: return getPropertyAsString(TIMELIM);
0330: }
0331:
0332: public int getTimelimAsInt() {
0333: return getPropertyAsInt(TIMELIM);
0334: }
0335:
0336: /***************************************************************************
0337: * Sets the time limit attribute of the LDAPSampler object
0338: *
0339: * @param newTlim
0340: * The new time limit value
0341: **************************************************************************/
0342: public void setTimelim(String newTlim) {
0343: this .setProperty(TIMELIM, newTlim);
0344: }
0345:
0346: /***************************************************************************
0347: * Gets the return objects attribute of the LDAPSampler object
0348: *
0349: * @return if the object(s) are to be returned
0350: **************************************************************************/
0351: public boolean isRetobj() {
0352: return getPropertyAsBoolean(RETOBJ);
0353: }
0354:
0355: /***************************************************************************
0356: * Sets the return objects attribute of the LDAPSampler object
0357: *
0358: **************************************************************************/
0359: public void setRetobj(String newRobj) {
0360: this .setProperty(RETOBJ, newRobj);
0361: }
0362:
0363: /***************************************************************************
0364: * Gets the deref attribute of the LDAPSampler object
0365: *
0366: * @return if dereferencing is required
0367: **************************************************************************/
0368: public boolean isDeref() {
0369: return getPropertyAsBoolean(DEREF);
0370: }
0371:
0372: /***************************************************************************
0373: * Sets the deref attribute of the LDAPSampler object
0374: *
0375: * @param newDref
0376: * The new deref value
0377: **************************************************************************/
0378: public void setDeref(String newDref) {
0379: this .setProperty(DEREF, newDref);
0380: }
0381:
0382: /***************************************************************************
0383: * Sets the Test attribute of the LdapConfig object
0384: *
0385: * @param newTest
0386: * The new test value(Add,Modify,Delete and search)
0387: **************************************************************************/
0388: public void setTest(String newTest) {
0389: this .setProperty(TEST, newTest);
0390: }
0391:
0392: /***************************************************************************
0393: * Gets the test attribute of the LDAPSampler object
0394: *
0395: * @return The test value (Add,Modify,Delete and search)
0396: **************************************************************************/
0397: public String getTest() {
0398: return getPropertyAsString(TEST);
0399: }
0400:
0401: /***************************************************************************
0402: * Sets the attributes of the LdapConfig object
0403: *
0404: * @param newAttrs
0405: * The new attributes value
0406: **************************************************************************/
0407: public void setAttrs(String newAttrs) {
0408: this .setProperty(ATTRIBS, newAttrs);
0409: }
0410:
0411: /***************************************************************************
0412: * Gets the attributes of the LDAPSampler object
0413: *
0414: * @return The attributes
0415: **************************************************************************/
0416: public String getAttrs() {
0417: return getPropertyAsString(ATTRIBS);
0418: }
0419:
0420: /***************************************************************************
0421: * Sets the Base Entry DN attribute of the LDAPSampler object
0422: *
0423: * @param newbaseentry
0424: * The new Base entry DN value
0425: **************************************************************************/
0426: public void setBaseEntryDN(String newbaseentry) {
0427: setProperty(new StringProperty(BASE_ENTRY_DN, newbaseentry));
0428: }
0429:
0430: /***************************************************************************
0431: * Gets the BaseEntryDN attribute of the LDAPSampler object
0432: *
0433: * @return The Base entry DN value
0434: **************************************************************************/
0435: public String getBaseEntryDN() {
0436: return getPropertyAsString(BASE_ENTRY_DN);
0437: }
0438:
0439: /***************************************************************************
0440: * Sets the Arguments attribute of the LdapConfig object This will collect
0441: * values from the table for user defined test case
0442: *
0443: * @param value
0444: * The arguments
0445: **************************************************************************/
0446: public void setArguments(Arguments value) {
0447: setProperty(new TestElementProperty(ARGUMENTS, value));
0448: }
0449:
0450: /***************************************************************************
0451: * Gets the Arguments attribute of the LdapConfig object
0452: *
0453: * @return The arguments user defined test case
0454: **************************************************************************/
0455: public Arguments getArguments() {
0456: return (Arguments) getProperty(ARGUMENTS).getObjectValue();
0457: }
0458:
0459: /***************************************************************************
0460: * Sets the Arguments attribute of the LdapConfig object This will collect
0461: * values from the table for user defined test case
0462: *
0463: * @param value
0464: * The arguments
0465: **************************************************************************/
0466: public void setLDAPArguments(LDAPArguments value) {
0467: setProperty(new TestElementProperty(LDAPARGUMENTS, value));
0468: }
0469:
0470: /***************************************************************************
0471: * Gets the LDAPArguments attribute of the LdapConfig object
0472: *
0473: * @return The LDAParguments user defined modify test case
0474: **************************************************************************/
0475: public LDAPArguments getLDAPArguments() {
0476: return (LDAPArguments) getProperty(LDAPARGUMENTS)
0477: .getObjectValue();
0478: }
0479:
0480: /***************************************************************************
0481: * Collect all the values from the table (Arguments), using this create the
0482: * Attributes, this will create the Attributes for the User
0483: * defined TestCase for Add Test
0484: *
0485: * @return The Attributes
0486: **************************************************************************/
0487: private Attributes getUserAttributes() {
0488: Attributes attrs = new BasicAttributes(true);
0489: Attribute attr;
0490: PropertyIterator iter = getArguments().iterator();
0491:
0492: while (iter.hasNext()) {
0493: Argument item = (Argument) iter.next().getObjectValue();
0494: attr = attrs.get(item.getName());
0495: if (attr == null) {
0496: attr = getBasicAttribute(item.getName(), item
0497: .getValue());
0498: } else {
0499: attr.add(item.getValue());
0500: }
0501: attrs.put(attr);
0502: }
0503: return attrs;
0504: }
0505:
0506: /***************************************************************************
0507: * Collect all the value from the table (Arguments), using this create the
0508: * basicAttributes This will create the Basic Attributes for the User
0509: * defined TestCase for Modify test
0510: *
0511: * @return The BasicAttributes
0512: **************************************************************************/
0513: private ModificationItem[] getUserModAttributes() {
0514: ModificationItem[] mods = new ModificationItem[getLDAPArguments()
0515: .getArguments().size()];
0516: BasicAttribute attr;
0517: PropertyIterator iter = getLDAPArguments().iterator();
0518: int count = 0;
0519: while (iter.hasNext()) {
0520: LDAPArgument item = (LDAPArgument) iter.next()
0521: .getObjectValue();
0522: if ((item.getValue()).length() == 0) {
0523: attr = new BasicAttribute(item.getName());
0524: } else {
0525: attr = getBasicAttribute(item.getName(), item
0526: .getValue());
0527: }
0528:
0529: final String opcode = item.getOpcode();
0530: if ("add".equals(opcode)) { // $NON-NLS-1$
0531: mods[count++] = new ModificationItem(
0532: DirContext.ADD_ATTRIBUTE, attr);
0533: } else if ("delete".equals(opcode) // $NON-NLS-1$
0534: || "remove".equals(opcode)) { // $NON-NLS-1$
0535: mods[count++] = new ModificationItem(
0536: DirContext.REMOVE_ATTRIBUTE, attr);
0537: } else if ("replace".equals(opcode)) { // $NON-NLS-1$
0538: mods[count++] = new ModificationItem(
0539: DirContext.REPLACE_ATTRIBUTE, attr);
0540: } else {
0541: log.warn("Invalid opCode: " + opcode);
0542: }
0543: }
0544: return mods;
0545: }
0546:
0547: /***************************************************************************
0548: * Collect all the value from the table (Arguments), using this create the
0549: * Attributes This will create the Basic Attributes for the User defined
0550: * TestCase for search test
0551: *
0552: * @return The BasicAttributes
0553: **************************************************************************/
0554: private String[] getRequestAttributes(String reqAttr) {
0555: int index;
0556: String[] mods;
0557: int count = 0;
0558: if (reqAttr.length() == 0) {
0559: return null;
0560: }
0561: if (!reqAttr.endsWith(SEMI_COLON)) {
0562: reqAttr = reqAttr + SEMI_COLON;
0563: }
0564: String attr = reqAttr;
0565:
0566: while (attr.length() > 0) {
0567: index = attr.indexOf(SEMI_COLON);
0568: count += 1;
0569: attr = attr.substring(index + 1);
0570: }
0571: if (count > 0) {
0572: mods = new String[count];
0573: attr = reqAttr;
0574: count = 0;
0575: while (attr.length() > 0) {
0576: index = attr.indexOf(SEMI_COLON);
0577: mods[count] = attr.substring(0, index);
0578: count += 1;
0579: attr = attr.substring(index + 1);
0580: }
0581: } else {
0582: mods = null;
0583: }
0584: return mods;
0585: }
0586:
0587: /***************************************************************************
0588: * This will create the Basic Attribute for the give name value pair
0589: *
0590: * @return The BasicAttribute
0591: **************************************************************************/
0592: private BasicAttribute getBasicAttribute(String name, String value) {
0593: BasicAttribute attr = new BasicAttribute(name, value);
0594: return attr;
0595: }
0596:
0597: /**
0598: * Returns a formatted string label describing this sampler Example output:
0599: *
0600: * @return a formatted string label describing this sampler
0601: */
0602: public String getLabel() {
0603: return ("ldap://" + this .getServername() //$NON-NLS-1$
0604: + ":" + getPort() //$NON-NLS-1$
0605: + "/" + this .getRootdn()); //$NON-NLS-1$
0606: }
0607:
0608: /***************************************************************************
0609: * This will do the add test for the User defined TestCase
0610: *
0611: **************************************************************************/
0612: private void addTest(LdapExtClient ldap, DirContext dirContext,
0613: SampleResult res) throws NamingException {
0614: try {
0615: res.sampleStart();
0616: ldap.createTest(dirContext, getUserAttributes(),
0617: getBaseEntryDN());
0618: } finally {
0619: res.sampleEnd();
0620: }
0621: }
0622:
0623: /***************************************************************************
0624: * This will do the delete test for the User defined TestCase
0625: *
0626: **************************************************************************/
0627: private void deleteTest(LdapExtClient ldap, DirContext dirContext,
0628: SampleResult res) throws NamingException {
0629: try {
0630: res.sampleStart();
0631: ldap.deleteTest(dirContext, getPropertyAsString(DELETE));
0632: } finally {
0633: res.sampleEnd();
0634: }
0635: }
0636:
0637: /***************************************************************************
0638: * This will do the modify test for the User defined TestCase
0639: *
0640: **************************************************************************/
0641: private void modifyTest(LdapExtClient ldap, DirContext dirContext,
0642: SampleResult res) throws NamingException {
0643: try {
0644: res.sampleStart();
0645: ldap.modifyTest(dirContext, getUserModAttributes(),
0646: getBaseEntryDN());
0647: } finally {
0648: res.sampleEnd();
0649: }
0650: }
0651:
0652: /***************************************************************************
0653: * This will do the bind for the User defined Thread, this bind is used for
0654: * the whole context
0655: *
0656: **************************************************************************/
0657: private void bindOp(LdapExtClient ldap, DirContext dirContext,
0658: SampleResult res) throws NamingException {
0659: DirContext ctx = (DirContext) ldapContexts
0660: .remove(getThreadName());
0661: if (ctx != null) {
0662: log.warn("Closing previous context for thread: "
0663: + getThreadName());
0664: ctx.close();
0665: }
0666: try {
0667: res.sampleStart();
0668: ctx = ldap.connect(getServername(), getPort(), getRootdn(),
0669: getUserDN(), getUserPw(), getConnTimeOut(),
0670: isSecure());
0671: } finally {
0672: res.sampleEnd();
0673: }
0674: ldapContexts.put(getThreadName(), ctx);
0675: }
0676:
0677: /***************************************************************************
0678: * This will do the bind and unbind for the User defined TestCase
0679: *
0680: **************************************************************************/
0681: private void singleBindOp(SampleResult res) throws NamingException {
0682: LdapExtClient ldap_temp;
0683: ldap_temp = new LdapExtClient();
0684: try {
0685: res.sampleStart();
0686: DirContext ctx = ldap_temp.connect(getServername(),
0687: getPort(), getRootdn(), getUserDN(), getUserPw(),
0688: getConnTimeOut(), isSecure());
0689: ldap_temp.disconnect(ctx);
0690: } finally {
0691: res.sampleEnd();
0692: }
0693: }
0694:
0695: /***************************************************************************
0696: * This will do a moddn Opp for the User new DN defined
0697: *
0698: **************************************************************************/
0699: private void renameTest(LdapExtClient ldap, DirContext dirContext,
0700: SampleResult res) throws NamingException {
0701: try {
0702: res.sampleStart();
0703: ldap.moddnOp(dirContext, getPropertyAsString(MODDDN),
0704: getPropertyAsString(NEWDN));
0705: } finally {
0706: res.sampleEnd();
0707: }
0708: }
0709:
0710: /***************************************************************************
0711: * This will do the unbind for the User defined TestCase as well as inbuilt
0712: * test case
0713: *
0714: **************************************************************************/
0715: private void unbindOp(LdapExtClient ldap, DirContext dirContext,
0716: SampleResult res) {
0717: try {
0718: res.sampleStart();
0719: ldap.disconnect(dirContext);
0720: } finally {
0721: res.sampleEnd();
0722: }
0723: ldapConnections.remove(getThreadName());
0724: ldapContexts.remove(getThreadName());
0725: log.info("context and LdapExtClients removed");
0726: }
0727:
0728: /***************************************************************************
0729: * !ToDo (Method description)
0730: *
0731: * @param e
0732: * !ToDo (Parameter description)
0733: * @return !ToDo (Return description)
0734: **************************************************************************/
0735: public SampleResult sample(Entry e) {
0736: XMLBuffer xmlBuffer = new XMLBuffer();
0737: xmlBuffer.openTag("ldapanswer"); // $NON-NLS-1$
0738: SampleResult res = new SampleResult();
0739: res.setResponseData("successfull".getBytes());
0740: res.setResponseMessage("Success"); // $NON-NLS-1$
0741: res.setResponseCode("0"); // $NON-NLS-1$
0742: boolean isSuccessful = true;
0743: res.setSampleLabel(getName());
0744: LdapExtClient temp_client = (LdapExtClient) ldapConnections
0745: .get(getThreadName());
0746: DirContext dirContext = (DirContext) ldapContexts
0747: .get(getThreadName());
0748: if (temp_client == null) {
0749: temp_client = new LdapExtClient();
0750: try {
0751: dirContext = new InitialDirContext();
0752: } catch (NamingException err) {
0753: log.error("Ldap client context creation - ", err);
0754: }
0755: ldapConnections.put(getThreadName(), temp_client);
0756: }
0757:
0758: try {
0759: xmlBuffer.openTag("operation"); // $NON-NLS-1$
0760: final String testType = getTest();
0761: xmlBuffer.tag("opertype", testType); // $NON-NLS-1$
0762: log.debug("performing test: " + testType);
0763: if (testType.equals(UNBIND)) {
0764: res.setSamplerData("Unbind");
0765: xmlBuffer.tag("baseobj", getRootdn()); // $NON-NLS-1$
0766: xmlBuffer.tag("binddn", getUserDN()); // $NON-NLS-1$
0767: unbindOp(temp_client, dirContext, res);
0768: } else if (testType.equals(BIND)) {
0769: res.setSamplerData("Bind as " + getUserDN());
0770: xmlBuffer.tag("baseobj", getRootdn()); // $NON-NLS-1$
0771: xmlBuffer.tag("binddn", getUserDN()); // $NON-NLS-1$
0772: xmlBuffer.tag("connectionTO", getConnTimeOut()); // $NON-NLS-1$
0773: bindOp(temp_client, dirContext, res);
0774: } else if (testType.equals(SBIND)) {
0775: res.setSamplerData("SingleBind as " + getUserDN());
0776: xmlBuffer.tag("baseobj", getRootdn()); // $NON-NLS-1$
0777: xmlBuffer.tag("binddn", getUserDN()); // $NON-NLS-1$
0778: xmlBuffer.tag("connectionTO", getConnTimeOut()); // $NON-NLS-1$
0779: singleBindOp(res);
0780: } else if (testType.equals(COMPARE)) {
0781: res.setSamplerData("Compare "
0782: + getPropertyAsString(COMPAREFILT) + " "
0783: + getPropertyAsString(COMPAREDN));
0784: xmlBuffer.tag("comparedn",
0785: getPropertyAsString(COMPAREDN)); // $NON-NLS-1$
0786: xmlBuffer.tag("comparefilter",
0787: getPropertyAsString(COMPAREFILT)); // $NON-NLS-1$
0788: NamingEnumeration cmp;
0789: try {
0790: res.sampleStart();
0791: cmp = temp_client.compare(dirContext,
0792: getPropertyAsString(COMPAREFILT),
0793: getPropertyAsString(COMPAREDN));
0794: } finally {
0795: res.sampleEnd();
0796: }
0797: if (cmp.hasMore()) {
0798: } else {
0799: res.setResponseCode("5"); // $NON-NLS-1$
0800: res.setResponseMessage("compareFalse");
0801: isSuccessful = false;
0802: }
0803: } else if (testType.equals(ADD)) {
0804: res.setSamplerData("Add object " + getBaseEntryDN());
0805: xmlBuffer.tag("attributes", getArguments().toString()); // $NON-NLS-1$
0806: xmlBuffer.tag("dn", getBaseEntryDN()); // $NON-NLS-1$
0807: addTest(temp_client, dirContext, res);
0808: } else if (testType.equals(DELETE)) {
0809: res.setSamplerData("Delete object " + getBaseEntryDN());
0810: xmlBuffer.tag("dn", getBaseEntryDN()); // $NON-NLS-1$
0811: deleteTest(temp_client, dirContext, res);
0812: } else if (testType.equals(MODIFY)) {
0813: res.setSamplerData("Modify object " + getBaseEntryDN());
0814: xmlBuffer.tag("dn", getBaseEntryDN()); // $NON-NLS-1$
0815: xmlBuffer.tag("attributes", getLDAPArguments()
0816: .toString()); // $NON-NLS-1$
0817: modifyTest(temp_client, dirContext, res);
0818: } else if (testType.equals(RENAME)) {
0819: res.setSamplerData("ModDN object "
0820: + getPropertyAsString(MODDDN) + " to "
0821: + getPropertyAsString(NEWDN));
0822: xmlBuffer.tag("dn", getPropertyAsString(MODDDN)); // $NON-NLS-1$
0823: xmlBuffer.tag("newdn", getPropertyAsString(NEWDN)); // $NON-NLS-1$
0824: renameTest(temp_client, dirContext, res);
0825: } else if (testType.equals(SEARCH)) {
0826: final String scopeStr = getScope();
0827: final int scope = getScopeAsInt();
0828: final String searchFilter = getPropertyAsString(SEARCHFILTER);
0829: final String searchBase = getPropertyAsString(SEARCHBASE);
0830: final String timeLimit = getTimelim();
0831: final String countLimit = getCountlim();
0832:
0833: res
0834: .setSamplerData("Search with filter "
0835: + searchFilter);
0836: xmlBuffer.tag("searchfilter", searchFilter); // $NON-NLS-1$
0837: xmlBuffer.tag("baseobj", getRootdn()); // $NON-NLS-1$
0838: xmlBuffer.tag("searchbase", searchBase);// $NON-NLS-1$
0839: xmlBuffer.tag("scope", scopeStr); // $NON-NLS-1$
0840: xmlBuffer.tag("countlimit", countLimit); // $NON-NLS-1$
0841: xmlBuffer.tag("timelimit", timeLimit); // $NON-NLS-1$
0842:
0843: NamingEnumeration srch;
0844: try {
0845: res.sampleStart();
0846: srch = temp_client.searchTest(dirContext,
0847: searchBase, searchFilter, scope,
0848: getCountlimAsLong(), getTimelimAsInt(),
0849: getRequestAttributes(getAttrs()),
0850: isRetobj(), isDeref());
0851: } finally {
0852: res.sampleEnd();
0853: }
0854:
0855: if (isParseFlag()) {
0856: try {
0857: xmlBuffer.openTag("searchresults"); // $NON-NLS-1$
0858: writeSearchResults(xmlBuffer, srch);
0859: } finally {
0860: xmlBuffer.closeTag("searchresults"); // $NON-NLS-1$
0861: }
0862: }
0863: }
0864:
0865: } catch (NamingException ex) {
0866: //log.warn("DEBUG",ex);
0867: // e.g. javax.naming.SizeLimitExceededException: [LDAP: error code 4 - Sizelimit Exceeded]; remaining name ''
0868: // 123456789012345678901
0869: // TODO: tidy this up
0870: String returnData = ex.toString();
0871: final int indexOfLDAPErrCode = returnData
0872: .indexOf("LDAP: error code");
0873: if (indexOfLDAPErrCode >= 0) {
0874: res.setResponseMessage(returnData.substring(
0875: indexOfLDAPErrCode + 21, returnData
0876: .indexOf("]"))); // $NON-NLS-1$
0877: res.setResponseCode(returnData.substring(
0878: indexOfLDAPErrCode + 17,
0879: indexOfLDAPErrCode + 19));
0880: } else {
0881: res.setResponseMessage(returnData);
0882: res.setResponseCode("800"); // $NON-NLS-1$
0883: }
0884: isSuccessful = false;
0885: } finally {
0886: xmlBuffer.closeTag("operation"); // $NON-NLS-1$
0887: xmlBuffer.tag("responsecode", res.getResponseCode()); // $NON-NLS-1$
0888: xmlBuffer.tag("responsemessage", res.getResponseMessage()); // $NON-NLS-1$
0889: res.setResponseData(xmlBuffer.toString().getBytes());
0890: res.setDataType(SampleResult.TEXT);
0891: res.setSuccessful(isSuccessful);
0892: }
0893: return res;
0894: }
0895:
0896: /*
0897: * Write out search results in a stable order (including order of all subelements which might
0898: * be reordered like attributes and their values) so that simple textual comparison can be done,
0899: * unless the number of results exceeds {@link #MAX_SORTED_RESULTS} in which case just stream
0900: * the results out without sorting.
0901: */
0902: private void writeSearchResults(final XMLBuffer xmlb,
0903: final NamingEnumeration srch) throws NamingException {
0904:
0905: final ArrayList sortedResults = new ArrayList(
0906: MAX_SORTED_RESULTS);
0907: final String searchBase = getPropertyAsString(SEARCHBASE);
0908: final String rootDn = getRootdn();
0909:
0910: // read all sortedResults into memory so we can guarantee ordering
0911: try {
0912: while (srch.hasMore()
0913: && (sortedResults.size() < MAX_SORTED_RESULTS)) {
0914: final SearchResult sr = (SearchResult) srch.next();
0915:
0916: // must be done prior to sorting
0917: normaliseSearchDN(sr, searchBase, rootDn);
0918: sortedResults.add(sr);
0919: }
0920: } finally { // show what we did manage to retrieve
0921:
0922: sortResults(sortedResults);
0923:
0924: for (Iterator it = sortedResults.iterator(); it.hasNext();) {
0925: final SearchResult sr = (SearchResult) it.next();
0926: writeSearchResult(sr, xmlb);
0927: }
0928: }
0929:
0930: while (srch.hasMore()) { // If there's anything left ...
0931: final SearchResult sr = (SearchResult) srch.next();
0932:
0933: normaliseSearchDN(sr, searchBase, rootDn);
0934: writeSearchResult(sr, xmlb);
0935: }
0936: }
0937:
0938: private void writeSearchResult(final SearchResult sr,
0939: final XMLBuffer xmlb) throws NamingException {
0940: final Attributes attrs = sr.getAttributes();
0941: final int size = attrs.size();
0942: final ArrayList sortedAttrs = new ArrayList(size);
0943:
0944: xmlb.openTag("searchresult"); // $NON-NLS-1$
0945: xmlb.tag("dn", sr.getName()); // $NON-NLS-1$
0946: xmlb.tag("returnedattr", Integer.toString(size)); // $NON-NLS-1$
0947: xmlb.openTag("attributes"); // $NON-NLS-1$
0948:
0949: try {
0950: for (NamingEnumeration en = attrs.getAll(); en.hasMore();) {
0951: final Attribute attr = (Attribute) en.next();
0952:
0953: sortedAttrs.add(attr);
0954: }
0955: sortAttributes(sortedAttrs);
0956: for (Iterator ait = sortedAttrs.iterator(); ait.hasNext();) {
0957: final Attribute attr = (Attribute) ait.next();
0958:
0959: StringBuffer sb = new StringBuffer();
0960: if (attr.size() == 1)
0961: sb.append(getWriteValue(attr.get()));
0962: else {
0963: final ArrayList sortedVals = new ArrayList(attr
0964: .size());
0965: boolean first = true;
0966:
0967: for (NamingEnumeration ven = attr.getAll(); ven
0968: .hasMore();) {
0969: final Object value = getWriteValue(ven.next());
0970: sortedVals.add(value.toString());
0971: }
0972:
0973: Collections.sort(sortedVals);
0974:
0975: for (Iterator vit = sortedVals.iterator(); vit
0976: .hasNext();) {
0977: final String value = (String) vit.next();
0978: if (first) {
0979: first = false;
0980: } else {
0981: sb.append(", "); // $NON-NLS-1$
0982: }
0983: sb.append(value);
0984: }
0985: }
0986: xmlb.tag(attr.getID(), sb);
0987: }
0988: } finally {
0989: xmlb.closeTag("attributes"); // $NON-NLS-1$
0990: xmlb.closeTag("searchresult"); // $NON-NLS-1$
0991: }
0992: }
0993:
0994: private void sortAttributes(final ArrayList sortedAttrs) {
0995: Collections.sort(sortedAttrs, new Comparator() {
0996: public int compare(Object o1, Object o2) {
0997: String nm1 = ((Attribute) o1).getID();
0998: String nm2 = ((Attribute) o2).getID();
0999:
1000: return nm1.compareTo(nm2);
1001: }
1002: });
1003: }
1004:
1005: private void sortResults(final ArrayList sortedResults) {
1006: Collections.sort(sortedResults, new Comparator() {
1007: private int compareToReverse(final String s1,
1008: final String s2) {
1009: int len1 = s1.length();
1010: int len2 = s2.length();
1011: int s1i = len1 - 1;
1012: int s2i = len2 - 1;
1013:
1014: for (; (s1i >= 0) && (s2i >= 0); s1i--, s2i--) {
1015: char c1 = s1.charAt(s1i);
1016: char c2 = s2.charAt(s2i);
1017:
1018: if (c1 != c2)
1019: return c1 - c2;
1020: }
1021: return len1 - len2;
1022: }
1023:
1024: public int compare(Object o1, Object o2) {
1025: String nm1 = ((SearchResult) o1).getName();
1026: String nm2 = ((SearchResult) o2).getName();
1027:
1028: if (nm1 == null)
1029: nm1 = "";
1030: if (nm2 == null)
1031: nm2 = "";
1032: return compareToReverse(nm1, nm2);
1033: }
1034: });
1035: }
1036:
1037: private String normaliseSearchDN(final SearchResult sr,
1038: final String searchBase, final String rootDn) {
1039: String srName = sr.getName();
1040:
1041: if (!srName.endsWith(searchBase)) {
1042: if (srName.length() > 0)
1043: srName = srName + ',';
1044: srName = srName + searchBase;
1045: }
1046: if ((rootDn.length() > 0) && !srName.endsWith(rootDn)) {
1047: if (srName.length() > 0)
1048: srName = srName + ',';
1049: srName = srName + rootDn;
1050: }
1051: sr.setName(srName);
1052: return srName;
1053: }
1054:
1055: private String getWriteValue(final Object value) {
1056: if (value instanceof String)
1057: // assume it's senstive data
1058: return StringEscapeUtils.escapeXml((String) value);
1059: else if (value instanceof byte[])
1060: try {
1061: return StringEscapeUtils.escapeXml(new String(
1062: (byte[]) value, "UTF-8"));
1063: } catch (UnsupportedEncodingException e) {
1064: log
1065: .error(
1066: "this can't happen: UTF-8 character encoding not supported",
1067: e);
1068: }
1069: return StringEscapeUtils.escapeXml(value.toString());
1070: }
1071:
1072: public void testStarted() {
1073: testStarted(""); // $NON-NLS-1$
1074: }
1075:
1076: public void testEnded() {
1077: testEnded(""); // $NON-NLS-1$
1078: }
1079:
1080: public void testStarted(String host) {
1081: // ignored
1082: }
1083:
1084: // Ensure any remaining contexts are closed
1085: public void testEnded(String host) {
1086: Iterator it = ldapContexts.entrySet().iterator();
1087: while (it.hasNext()) {
1088: Map.Entry entry = (Map.Entry) it.next();
1089: String key = (String) entry.getKey();
1090: DirContext dc = (DirContext) entry.getValue();
1091: try {
1092: log.warn("Tidying old Context for thread: " + key);
1093: dc.close();
1094: } catch (NamingException ignored) {
1095: // ignored
1096: }
1097: it.remove();// Make sure the entry is not left around for the next run
1098: }
1099:
1100: }
1101:
1102: public void testIterationStart(LoopIterationEvent event) {
1103: // ignored
1104: }
1105: }
|