View | Details | Raw Unified | Return to bug 40369
Collapse All | Expand All

(-)bin/jmeter.properties (+10 lines)
Lines 407-412 Link Here
407
#beanshell.server.port=9000
407
#beanshell.server.port=9000
408
# The telnet server will be started on the next port
408
# The telnet server will be started on the next port
409
409
410
#---------------------------------------------------------------------------
411
# LDAP Sampler configuration
412
#---------------------------------------------------------------------------
413
# Maximum number of search results returned by a search that will be sorted
414
# to guarantee a stable ordering (if more results then this limit are retruned
415
# then no sorting is done). Set to 0 to turn off all sorting, in which case
416
# "Equals" response assertions will be very likely to fail against search results.
417
#ldapsampler.max_sorted_results=2000
418
ldapsampler.max_sorted_results=0
419
410
#
420
#
411
# Define the server initialisation file
421
# Define the server initialisation file
412
beanshell.server.file=../extras/startup.bsh
422
beanshell.server.file=../extras/startup.bsh
(-)src/components/org/apache/jmeter/assertions/gui/AssertionGui.java (-6 / +23 lines)
Lines 81-86 Link Here
81
	private JRadioButton matchesBox;
81
	private JRadioButton matchesBox;
82
82
83
	/**
83
	/**
84
	 * Radio button indicating if the field equals the first pattern.
85
	 */
86
	private JRadioButton equalsBox;
87
88
    /**
84
	 * Checkbox indicating to test that the field does NOT contain/match the
89
	 * Checkbox indicating to test that the field does NOT contain/match the
85
	 * patterns.
90
	 * patterns.
86
	 */
91
	 */
Lines 142-152 Link Here
142
147
143
			if (containsBox.isSelected()) {
148
			if (containsBox.isSelected()) {
144
				ra.setToContainsType();
149
				ra.setToContainsType();
150
			} else if (matchesBox.isSelected()) {
151
				ra.setToMatchType();
145
			} else {
152
			} else {
146
				ra.setToMatchType();
153
                ra.setToEqualsType();
147
			}
154
            }
148
155
149
			if (notBox.isSelected()) {
156
            if (notBox.isSelected()) {
150
				ra.setToNotType();
157
				ra.setToNotType();
151
			} else {
158
			} else {
152
				ra.unsetNotType();
159
				ra.unsetNotType();
Lines 170-179 Link Here
170
		if (model.isContainsType()) {
177
		if (model.isContainsType()) {
171
			containsBox.setSelected(true);
178
			containsBox.setSelected(true);
172
			matchesBox.setSelected(false);
179
			matchesBox.setSelected(false);
180
            equalsBox.setSelected(false);
181
        } else if (model.isMatchType()) {
182
			containsBox.setSelected(false);
183
			matchesBox.setSelected(true);
184
            equalsBox.setSelected(false);
173
		} else {
185
		} else {
174
			containsBox.setSelected(false);
186
			containsBox.setSelected(false);
175
			matchesBox.setSelected(true);
187
			matchesBox.setSelected(false);
176
		}
188
            equalsBox.setSelected(true);
189
        }
177
190
178
		if (model.isNotType()) {
191
		if (model.isNotType()) {
179
			notBox.setSelected(true);
192
			notBox.setSelected(true);
Lines 279-285 Link Here
279
		group.add(matchesBox);
292
		group.add(matchesBox);
280
		panel.add(matchesBox);
293
		panel.add(matchesBox);
281
294
282
		notBox = new JCheckBox(JMeterUtils.getResString("assertion_not"));
295
		equalsBox = new JRadioButton(JMeterUtils.getResString("assertion_equals"));
296
		group.add(equalsBox);
297
		panel.add(equalsBox);
298
299
        notBox = new JCheckBox(JMeterUtils.getResString("assertion_not"));
283
		panel.add(notBox);
300
		panel.add(notBox);
284
301
285
		return panel;
302
		return panel;
(-)src/components/org/apache/jmeter/assertions/ResponseAssertion.java (-58 / +201 lines)
Lines 72-78 Link Here
72
72
73
	private final static int NOT = 1 << 2;
73
	private final static int NOT = 1 << 2;
74
74
75
	private static ThreadLocal matcher = new ThreadLocal() {
75
	private final static int EQUALS = 1 << 3;
76
77
    private static ThreadLocal matcher = new ThreadLocal() {
76
		protected Object initialValue() {
78
		protected Object initialValue() {
77
			return new Perl5Matcher();
79
			return new Perl5Matcher();
78
		}
80
		}
Lines 217-222 Link Here
217
		return (CollectionProperty) getProperty(TEST_STRINGS);
219
		return (CollectionProperty) getProperty(TEST_STRINGS);
218
	}
220
	}
219
221
222
	public boolean isEqualsType() {
223
		return (getTestType() & EQUALS) > 0;
224
	}
225
220
	public boolean isContainsType() {
226
	public boolean isContainsType() {
221
		return (getTestType() & CONTAINS) > 0;
227
		return (getTestType() & CONTAINS) > 0;
222
	}
228
	}
Lines 230-243 Link Here
230
	}
236
	}
231
237
232
	public void setToContainsType() {
238
	public void setToContainsType() {
233
		setTestType((getTestType() | CONTAINS) & (~MATCH));
239
		setTestType((getTestType() | CONTAINS) & ~ (MATCH | EQUALS));
234
	}
240
	}
235
241
236
	public void setToMatchType() {
242
	public void setToMatchType() {
237
		setTestType((getTestType() | MATCH) & (~CONTAINS));
243
		setTestType((getTestType() | MATCH) & ~(CONTAINS | EQUALS));
238
	}
244
	}
239
245
240
	public void setToNotType() {
246
	public void setToEqualsType() {
247
		setTestType((getTestType() | EQUALS) & ~(MATCH | CONTAINS));
248
	}
249
250
    public void setToNotType() {
241
		setTestType((getTestType() | NOT));
251
		setTestType((getTestType() | NOT));
242
	}
252
	}
243
253
Lines 294-326 Link Here
294
		result.setError(false);
304
		result.setError(false);
295
305
296
		boolean contains = isContainsType(); // do it once outside loop
306
		boolean contains = isContainsType(); // do it once outside loop
297
		boolean debugEnabled = log.isDebugEnabled();
307
        boolean equals = isEqualsType();
308
        boolean debugEnabled = log.isDebugEnabled();
298
		if (debugEnabled){
309
		if (debugEnabled){
299
			log.debug("Type:" + (contains?"Contains":"Match") + (not? "(not)": ""));
310
			log.debug("Type:" + (contains?"Contains":"Match") + (not? "(not)": ""));
300
		}
311
		}
301
		
312
302
		try {
313
        try {
303
			// Get the Matcher for this thread
314
			// Get the Matcher for this thread
304
			Perl5Matcher localMatcher = (Perl5Matcher) matcher.get();
315
			Perl5Matcher localMatcher = (Perl5Matcher) matcher.get();
305
			PropertyIterator iter = getTestStrings().iterator();
316
			PropertyIterator iter = getTestStrings().iterator();
306
			while (iter.hasNext()) {
317
			while (iter.hasNext()) {
307
				String stringPattern = iter.next().getStringValue();
318
				String stringPattern = iter.next().getStringValue();
308
				Pattern pattern = patternCache.getPattern(stringPattern, Perl5Compiler.READ_ONLY_MASK);
319
                boolean found;
309
				boolean found;
320
310
				if (contains) {
321
                if (equals) {
311
					found = localMatcher.contains(toCheck, pattern);
322
                    found = toCheck.equals(stringPattern);
312
				} else {
323
                } else {
313
					found = localMatcher.matches(toCheck, pattern);
324
                    Pattern pattern = patternCache.getPattern(stringPattern, Perl5Compiler.READ_ONLY_MASK);
314
				}
325
                    if (contains) {
315
				pass = not ? !found : found;
326
                        found = localMatcher.contains(toCheck, pattern);
327
                    } else {
328
                        found = localMatcher.matches(toCheck, pattern);
329
                    }
330
                }
331
                pass = not ? !found : found;
316
				if (!pass) {
332
				if (!pass) {
317
					if (debugEnabled){log.debug("Failed: "+pattern);}
333
                    String      failText = getFailText(stringPattern);
318
					result.setFailure(true);
334
319
					result.setFailureMessage(getFailText(stringPattern));
335
                    if (equals) {
336
                        failText += equalsComparisonText(toCheck, stringPattern);
337
                    }
338
                    log.info(failText);
339
                    result.setFailure(true);
340
					result.setFailureMessage(failText);
320
					break;
341
					break;
321
				}
342
				}
322
				if (debugEnabled){log.debug("Passed: "+pattern);}
343
				if (debugEnabled){log.debug("Passed: (" + getName() + ") /" + stringPattern);}
323
			}
344
                if (equals)
345
                    break;
346
            }
324
		} catch (MalformedCachePatternException e) {
347
		} catch (MalformedCachePatternException e) {
325
			result.setError(true);
348
			result.setError(true);
326
			result.setFailure(false);
349
			result.setFailure(false);
Lines 329-371 Link Here
329
		return result;
352
		return result;
330
	}
353
	}
331
354
332
	/**
355
    /**
333
	 * Generate the failure reason from the TestType
356
     *   Returns some helpful logging text to determine where equality between two strings
334
	 * 
357
     * is broken, with one pointer working from the front of the strings and another working
335
	 * @param stringPattern
358
     * backwards from the end.
336
	 * @return the message for the assertion report 
359
     *
337
	 */
360
     * @param received      String received from sampler.
338
	// TODO strings should be resources
361
     * @param comparison    String specified for "equals" response assertion.
339
	private String getFailText(String stringPattern) {
362
     * @return  Two lines of text separated by newlines, and then forward and backward pointers
340
		String text;
363
     *      denoting first position of difference.
341
		String what;
364
     */
342
		if (ResponseAssertion.RESPONSE_DATA.equals(getTestField())) {
365
    private static String equalsComparisonText(final String received, final String comparison)
343
			what = "text";
366
    {
344
		} else if (ResponseAssertion.RESPONSE_CODE.equals(getTestField())) {
367
        final StringBuffer      text;
345
			what = "code";
368
        int                     firstDiff;
346
		} else if (ResponseAssertion.RESPONSE_MESSAGE.equals(getTestField())) {
369
        int                     lastRecDiff = -1;
347
			what = "message";
370
        int                     lastCompDiff = -1;
348
		} else // Assume it is the URL
371
        final int               recLength = received.length();
349
		{
372
        final int               compLength = comparison.length();
350
			what = "URL";
373
        final int               minLength = Math.min(recLength, compLength);
351
		}
374
        final String            startingEqSeq;
352
		switch (getTestType()) {
375
        String                  recDeltaSeq = "";
353
		case CONTAINS:
376
        String                  compDeltaSeq = "";
354
			text = " expected to contain ";
377
        String                  endingEqSeq = "";
355
			break;
378
        final boolean           completeStrings;
356
		case NOT | CONTAINS:
357
			text = " expected not to contain ";
358
			break;
359
		case MATCH:
360
			text = " expected to match ";
361
			break;
362
		case NOT | MATCH:
363
			text = " expected not to match ";
364
			break;
365
		default:// should never happen...
366
			text = " expected something using ";
367
		}
368
379
369
		return "Test failed, " + what + text + "/" + stringPattern + "/";
380
        text = new StringBuffer(Math.max(recLength, compLength) * 2);
370
	}
381
        for (firstDiff = 0; firstDiff < minLength; firstDiff++)
382
            if (received.charAt(firstDiff) != comparison.charAt(firstDiff))
383
                break;
384
        if (firstDiff == 0)
385
            startingEqSeq = "";
386
        else
387
            startingEqSeq = received.substring(0, firstDiff);
388
        completeStrings = (firstDiff == minLength);
389
        if (!completeStrings)
390
        {
391
            final StringBuffer      pad;
392
393
            lastRecDiff = recLength - 1;
394
            lastCompDiff = compLength - 1;
395
396
            while (received.charAt(lastRecDiff) == comparison.charAt(lastCompDiff))
397
            {
398
                lastRecDiff--;
399
                lastCompDiff--;
400
            }
401
            endingEqSeq = received.substring(lastRecDiff + 1, recLength);
402
            if (endingEqSeq.length() == 0)
403
            {
404
                recDeltaSeq = received.substring(firstDiff, recLength);
405
                compDeltaSeq = comparison.substring(firstDiff, compLength);
406
            }
407
            else
408
            {
409
                pad = new StringBuffer(Math.abs(lastRecDiff - lastCompDiff));
410
                for (int i = 0; i < pad.capacity(); i++)
411
                    pad.append(' ');
412
                if (lastRecDiff > lastCompDiff)
413
                {
414
                    recDeltaSeq = received.substring(firstDiff, lastRecDiff + 1);
415
                    compDeltaSeq = pad.toString();
416
                }
417
                else
418
                {
419
                    recDeltaSeq = pad.toString();
420
                    compDeltaSeq = comparison.substring(firstDiff, lastCompDiff + 1);
421
                }
422
            }
423
        }
424
425
        text.append("\nreceived  : ");
426
        if (completeStrings)
427
            text.append(received);
428
        else
429
        {
430
            text.append(startingEqSeq);
431
            text.append(recDeltaSeq);
432
            text.append(endingEqSeq);
433
        }
434
        text.append("\ncomparison: ");
435
        if (completeStrings)
436
            text.append(comparison);
437
        else
438
        {
439
            text.append(startingEqSeq);
440
            text.append(compDeltaSeq);
441
            text.append(endingEqSeq);
442
        }
443
        text.append('\n');
444
        for (int i = 0; i < firstDiff + "comparison: ".length(); i++)
445
            text.append(' ');
446
        text.append("^\n");
447
        return text.toString();
448
    }
449
//
450
//    public static void main(String[] args)
451
//    {
452
//        String[][]  tests = new String[][] {
453
//            new String[] { "aaa", "zzz" },
454
//            new String[] { "aaa", "aaazzz" },
455
//            new String[] { "aaaz", "aaazzz" },
456
//            new String[] { "aaazzz", "aaaz" },
457
//            new String[] { "aaazzz", "aaabcdezzz" },
458
//        };
459
//
460
//        for (int i = 0; i < tests.length; i++)
461
//        {
462
//            String[] test = tests[i];
463
//
464
//            System.out.println();
465
//            System.out.println(equalsComparisonText(test[0], test[1]));
466
//        }
467
//    }
468
469
    /**
470
     * Generate the failure reason from the TestType
471
     *
472
     * @param stringPattern
473
     * @return the message for the assertion report
474
     */
475
    // TODO strings should be resources
476
    private String getFailText(String stringPattern) {
477
        String text;
478
        String what;
479
        if (ResponseAssertion.RESPONSE_DATA.equals(getTestField())) {
480
            what = "text";
481
        } else if (ResponseAssertion.RESPONSE_CODE.equals(getTestField())) {
482
            what = "code";
483
        } else if (ResponseAssertion.RESPONSE_MESSAGE.equals(getTestField())) {
484
            what = "message";
485
        } else // Assume it is the URL
486
        {
487
            what = "URL";
488
        }
489
        switch (getTestType()) {
490
        case CONTAINS:
491
            text = " expected to contain ";
492
            break;
493
        case NOT | CONTAINS:
494
            text = " expected not to contain ";
495
            break;
496
        case MATCH:
497
            text = " expected to match ";
498
            break;
499
        case NOT | MATCH:
500
            text = " expected not to match ";
501
            break;
502
        case EQUALS:
503
            text = " expected to equal ";
504
            break;
505
        case NOT | EQUALS:
506
            text = " expected not to equal ";
507
            break;
508
        default:// should never happen...
509
            text = " expected something using ";
510
        }
511
512
        return "Test failed, (" + getName() + "): " + what + text + "/" + stringPattern + "/";
513
    }
371
}
514
}
(-)src/core/org/apache/jmeter/resources/messages.properties (+1 lines)
Lines 46-51 Link Here
46
assertion_code_resp=Response Code
46
assertion_code_resp=Response Code
47
assertion_contains=Contains
47
assertion_contains=Contains
48
assertion_matches=Matches
48
assertion_matches=Matches
49
assertion_equals=Equals
49
assertion_message_resp=Response Message
50
assertion_message_resp=Response Message
50
assertion_not=Not
51
assertion_not=Not
51
assertion_pattern_match_rules=Pattern Matching Rules
52
assertion_pattern_match_rules=Pattern Matching Rules
(-)src/core/org/apache/jmeter/util/JMeterVersion.java (-1 / +1 lines)
Lines 41-47 Link Here
41
	 * JMeterUtils This ensures that JMeterUtils always gets the correct
41
	 * JMeterUtils This ensures that JMeterUtils always gets the correct
42
	 * version, even if it is not re-compiled during the build.
42
	 * version, even if it is not re-compiled during the build.
43
	 */
43
	 */
44
	private static final String VERSION = "2.1.2";
44
	private static final String VERSION = "2.1.2.20060830";
45
45
46
	static final String COPYRIGHT = "Copyright (c) 1998-2006 The Apache Software Foundation";
46
	static final String COPYRIGHT = "Copyright (c) 1998-2006 The Apache Software Foundation";
47
47
(-)src/protocol/ldap/org/apache/jmeter/protocol/ldap/sampler/LDAPExtSampler.java (-41 / +167 lines)
Lines 17-25 Link Here
17
17
18
package org.apache.jmeter.protocol.ldap.sampler;
18
package org.apache.jmeter.protocol.ldap.sampler;
19
19
20
import java.util.Hashtable;
20
import java.util.*;
21
import java.util.Iterator;
22
import java.util.Map;
23
21
24
import javax.naming.NamingEnumeration;
22
import javax.naming.NamingEnumeration;
25
import javax.naming.NamingException;
23
import javax.naming.NamingException;
Lines 44-49 Link Here
44
import org.apache.jmeter.testelement.property.PropertyIterator;
42
import org.apache.jmeter.testelement.property.PropertyIterator;
45
import org.apache.jmeter.testelement.property.StringProperty;
43
import org.apache.jmeter.testelement.property.StringProperty;
46
import org.apache.jmeter.testelement.property.TestElementProperty;
44
import org.apache.jmeter.testelement.property.TestElementProperty;
45
import org.apache.jmeter.util.JMeterUtils;
47
import org.apache.jorphan.logging.LoggingManager;
46
import org.apache.jorphan.logging.LoggingManager;
48
import org.apache.log.Logger;
47
import org.apache.log.Logger;
49
48
Lines 56-61 Link Here
56
55
57
    private static final Logger log = LoggingManager.getLoggerForClass();
56
    private static final Logger log = LoggingManager.getLoggerForClass();
58
57
58
    /** Signature start of response data generated by this sample. */
59
    public static final String LDAPANSWER = "<ldapanswer>";
60
59
	public final static String SERVERNAME = "servername"; // $NON-NLS-1$
61
	public final static String SERVERNAME = "servername"; // $NON-NLS-1$
60
62
61
	public final static String PORT = "port"; // $NON-NLS-1$
63
	public final static String PORT = "port"; // $NON-NLS-1$
Lines 125-139 Link Here
125
    // TODO replace these with ThreadLocal
127
    // TODO replace these with ThreadLocal
126
	private static Hashtable ldapConnections = new Hashtable();
128
	private static Hashtable ldapConnections = new Hashtable();
127
129
128
	private static Hashtable ldapContexts = new Hashtable();
130
	private static Hashtable    ldapContexts = new Hashtable();
131
    protected static final int MAX_SORTED_RESULTS = JMeterUtils.getPropDefault("ldapsampler.max_sorted_results", 1000);
129
132
130
	/***************************************************************************
131
	 * !ToDo (Constructor description)
132
	 **************************************************************************/
133
	public LDAPExtSampler() {
134
	}
135
133
136
	/***************************************************************************
134
    /***************************************************************************
135
     * !ToDo (Constructor description)
136
     **************************************************************************/
137
    public LDAPExtSampler() {
138
    }
139
140
    /***************************************************************************
137
	 * Gets the username attribute of the LDAP object
141
	 * Gets the username attribute of the LDAP object
138
	 * 
142
	 * 
139
	 * @return The username
143
	 * @return The username
Lines 681-687 Link Here
681
	 * @return !ToDo (Return description)
685
	 * @return !ToDo (Return description)
682
	 **************************************************************************/
686
	 **************************************************************************/
683
	public SampleResult sample(Entry e) {
687
	public SampleResult sample(Entry e) {
684
		String responseData = "<ldapanswer>";
688
		String responseData = LDAPANSWER;
685
		SampleResult res = new SampleResult();
689
		SampleResult res = new SampleResult();
686
		res.setResponseData("successfull".getBytes());
690
		res.setResponseData("successfull".getBytes());
687
		res.setResponseMessage("Success");
691
		res.setResponseMessage("Success");
Lines 761-799 Link Here
761
				responseData = responseData + "<newdn>" + getPropertyAsString(NEWDN) + "</newdn></operation>";
765
				responseData = responseData + "<newdn>" + getPropertyAsString(NEWDN) + "</newdn></operation>";
762
				renameTest(temp_client, dirContext, res);
766
				renameTest(temp_client, dirContext, res);
763
			} else if (getPropertyAsString(TEST).equals(SEARCHBASE)) {
767
			} else if (getPropertyAsString(TEST).equals(SEARCHBASE)) {
764
				res.setSamplerData("Search with filter " + getPropertyAsString(SEARCHFILTER));
768
                final StringBuffer      sb = new StringBuffer(2 * 1024);
765
				responseData = responseData + "<operation><opertype>search</opertype>";
769
766
				responseData = responseData + "<searchfilter>" + getPropertyAsString(SEARCHFILTER) + "</searchfilter>";
770
                res.setSamplerData("Search with filter " + getPropertyAsString(SEARCHFILTER));
767
				responseData = responseData + "<searchbase>" + getPropertyAsString(SEARCHBASE) + ","
771
                sb.append(responseData);
768
						+ getPropertyAsString(ROOTDN) + "</searchbase>";
772
                writeSearchResponseHeader(sb);
769
				responseData = responseData + "<scope>" + getPropertyAsString(SCOPE) + "</scope>";
770
				responseData = responseData + "<countlimit>" + getPropertyAsString(COUNTLIM) + "</countlimit>";
771
				responseData = responseData + "<timelimit>" + getPropertyAsString(TIMELIM) + "</timelimit>";
772
				responseData = responseData + "</operation><searchresult>";
773
                res.sampleStart();
773
                res.sampleStart();
774
                NamingEnumeration srch = temp_client.searchTest(dirContext, getPropertyAsString(SEARCHBASE), getPropertyAsString(SEARCHFILTER),
774
                NamingEnumeration srch = temp_client.searchTest(dirContext, getPropertyAsString(SEARCHBASE), getPropertyAsString(SEARCHFILTER),
775
                        getPropertyAsInt(SCOPE), getPropertyAsLong(COUNTLIM), getPropertyAsInt(TIMELIM),
775
                        getPropertyAsInt(SCOPE), getPropertyAsLong(COUNTLIM), getPropertyAsInt(TIMELIM),
776
                        getRequestAttributes(getPropertyAsString(ATTRIBS)), getPropertyAsBoolean(RETOBJ),
776
                        getRequestAttributes(getPropertyAsString(ATTRIBS)), getPropertyAsBoolean(RETOBJ),
777
                        getPropertyAsBoolean(DEREF));
777
                        getPropertyAsBoolean(DEREF));
778
                res.sampleEnd();
778
                res.sampleEnd();
779
				while (srch.hasMore()) {
779
                writeSearchResults(sb, srch);
780
                    SearchResult sr = (SearchResult) srch.next();
780
                responseData = sb.toString();
781
					responseData = responseData + "<dn>" + sr.getName() + "," + getPropertyAsString(SEARCHBASE) + ","
781
            }
782
							+ getRootdn() + "</dn>";
783
					responseData = responseData + "<returnedattr>" + sr.getAttributes().size() + "</returnedattr>";
784
                    NamingEnumeration attrlist = sr.getAttributes().getIDs();
785
					while (attrlist.hasMore()) {
786
						String iets = (String) attrlist.next();
787
						responseData = responseData + "<attribute><attributename>" + iets
788
								+ "</attributename>";
789
						responseData = responseData
790
								+ "<attributevalue>"
791
								+ sr.getAttributes().get(iets).toString().substring(
792
										iets.length() + 2) + "</attributevalue></attribute>";
793
					}
794
				}
795
				responseData = responseData + "</searchresult></operation>";
796
			}
797
782
798
		} catch (NamingException ex) {
783
		} catch (NamingException ex) {
799
			String returnData = ex.toString();
784
			String returnData = ex.toString();
Lines 818-827 Link Here
818
		return res;
803
		return res;
819
	}
804
	}
820
805
821
	public void testStarted() {
806
    public void writeSearchResponseHeader(final StringBuffer sb)
822
		testStarted("");
807
    {
823
	}
808
        sb.append("<operation><opertype>search</opertype>");
809
        sb.append("<searchfilter>").append(getPropertyAsString(SEARCHFILTER)).append("</searchfilter>");
810
        sb.append("<searchbase>").append(getPropertyAsString(SEARCHBASE)).append(",")
811
                .append(getPropertyAsString(ROOTDN)).append("</searchbase>");
812
        sb.append("<scope>").append(getPropertyAsString(SCOPE)).append("</scope>");
813
        sb.append("<countlimit>").append(getPropertyAsString(COUNTLIM)).append("</countlimit>");
814
        sb.append("<timelimit>").append(getPropertyAsString(TIMELIM)).append("</timelimit>");
815
        sb.append("</operation>");
816
    }
824
817
818
    /**
819
     *   Write out search results in a stable order (including order of all subelements which might
820
     * be reordered like attributes and their values) so that simple textual comparison can be done,
821
     * unless the number of results exceeds {@link #MAX_SORTED_RESULTS} in which case just stream
822
     * the results out without sorting.
823
     */
824
    public void writeSearchResults(final StringBuffer sb, final NamingEnumeration srch)
825
            throws NamingException
826
    {
827
        final ArrayList         sortedResults = new ArrayList(MAX_SORTED_RESULTS);
828
        boolean                 abandonedSort;
829
830
        sb.append("<searchresults>");
831
        // read all sortedResults into memory so we can guarantee ordering
832
        while (srch.hasMore() && (sortedResults.size() < MAX_SORTED_RESULTS)) {
833
            final SearchResult    sr = (SearchResult) srch.next();
834
835
            sortedResults.add(sr);
836
        }
837
838
        abandonedSort = (sortedResults.size() > MAX_SORTED_RESULTS);
839
        if (!abandonedSort)
840
        {
841
            Collections.sort(sortedResults, new Comparator()
842
            {
843
                public int compare(Object o1, Object o2)
844
                {
845
                    String      nm1 = ((SearchResult) o1).getName();
846
                    String      nm2 = ((SearchResult) o2).getName();
847
848
                    if (nm1 == null)
849
                        nm1 = "";
850
                    if (nm2 == null)
851
                        nm2 = "";
852
                    return nm1.compareTo(nm2);
853
                }
854
            });
855
        }
856
857
        for (Iterator it = sortedResults.iterator(); it.hasNext();)
858
        {
859
            final SearchResult  sr = (SearchResult) it.next();
860
            writeSearchResult(sr, sb);
861
        }
862
863
        if (abandonedSort)
864
        {
865
                // if abonded sort because there were too many items, then read the
866
                //  rest of the results now...
867
            while (srch.hasMore()) {
868
                final SearchResult    sr = (SearchResult) srch.next();
869
870
                writeSearchResult(sr, sb);
871
            }
872
        }
873
        sb.append("</searchresults>");
874
    }
875
876
    private void writeSearchResult(final SearchResult sr, final StringBuffer responseData)
877
            throws NamingException
878
    {
879
        final String        srName = sr.getName();
880
        final Attributes    attrs = sr.getAttributes();
881
        final ArrayList     sortedAttrs;
882
883
        responseData.append("<searchresult>");
884
        responseData.append("<dn>");
885
        if (srName.length() > 0)
886
            responseData.append(srName).append(",");
887
        responseData.append(getPropertyAsString(SEARCHBASE));
888
        if (getRootdn().length() > 0)
889
            responseData.append(",").append(getRootdn());
890
        responseData.append("</dn>");
891
        responseData.append("<returnedattr>").append(attrs.size()).append("</returnedattr>");
892
        sortedAttrs = new ArrayList(attrs.size());
893
        for (NamingEnumeration en = attrs.getAll(); en.hasMore(); )
894
        {
895
            final Attribute     attr = (Attribute) en.next();
896
897
            sortedAttrs.add(attr);
898
        }
899
        Collections.sort(sortedAttrs, new Comparator()
900
        {
901
            public int compare(Object o1, Object o2)
902
            {
903
                String      nm1 = ((Attribute) o1).getID();
904
                String      nm2 = ((Attribute) o2).getID();
905
906
                return nm1.compareTo(nm2);
907
            }
908
        });
909
        for (Iterator ait = sortedAttrs.iterator(); ait.hasNext();)
910
        {
911
            final Attribute     attr = (Attribute) ait.next();
912
913
            responseData.append("<attribute><attributename>").append(attr.getID()).append("</attributename>");
914
            responseData.append("<attributevalue>");
915
            if (attr.size() == 1)
916
                responseData.append(attr.get());
917
            else
918
            {
919
                final ArrayList     sortedVals = new ArrayList(attr.size());
920
                boolean             first = true;
921
922
                for (NamingEnumeration ven = attr.getAll(); ven.hasMore(); )
923
                {
924
                    final Object    value = ven.next();
925
926
                    sortedVals.add(value.toString());
927
                }
928
929
                Collections.sort(sortedVals);
930
                
931
                for (Iterator vit = sortedVals.iterator(); vit.hasNext();)
932
                {
933
                    final String    value = (String) vit.next();
934
935
                    if (first)
936
                        first = false;
937
                    else
938
                        responseData.append(", ");
939
                    responseData.append(value);
940
                }
941
            }
942
            responseData.append("</attributevalue></attribute>");
943
        }
944
        responseData.append("</searchresult>");
945
    }
946
947
    public void testStarted() {
948
        testStarted("");
949
    }
950
825
	public void testEnded() {
951
	public void testEnded() {
826
		testEnded("");
952
		testEnded("");
827
	}
953
	}

Return to bug 40369