/* * Sun Public License * * The contents of this file are subject to the Sun Public License Version * 1.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is available at http://www.sun.com/ * * The Original Code is the SLAMD Distributed Load Generation Engine. * The Initial Developer of the Original Code is Neil A. Wilson. * Portions created by Neil A. Wilson are Copyright (C) 2004-2010. * Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): Neil A. Wilson */ package com.slamd.dslogplay; import java.util.ArrayList; import java.util.StringTokenizer; import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.ResultCode; import com.unboundid.ldap.sdk.SearchScope; /** * This class defines an LDAP search operation parsed from an access log and * implements the necessary logic to parse the log file line and to replay the * operation against a Directory Server. * * * @author Neil A. Wilson */ public class SearchOperation extends LogOperation { // The scope to use for the search request. private final SearchScope scope; // The base DN for the search request. private final String baseDN; // The filter for the search request. private final String filter; // The set of attributes to return for the search request. private final String[] attributes; /** * Creates a new search operation with the provided information. * * @param baseDN The base DN to use for the search request. * @param scope The scope to use for the search request. * @param filter The filter to use for the search request. * @param attributes The set of attributes to include in matching entries. */ public SearchOperation(String baseDN, SearchScope scope, String filter, String[] attributes) { this.baseDN = baseDN; this.scope = scope; this.filter = filter; this.attributes = attributes; } /** * Parses the provided line as appropriate for this type of operation and * constructs a new log operation based on the information it contains. * * @param jobThread The job thread with which this parser is associated. * @param line The line to be parsed and converted to a log operation. * * @return The log operation created from the provided log line, or * <CODE>null</CODE> if a problem prevented the line from being * parsed properly. */ public static LogOperation parseLogLine(LogPlaybackJobClass jobThread, String line) { try { int basePos = line.indexOf("SRCH base=\""); if (basePos < 0) { return null; } int scopePos = line.indexOf("\" scope=", basePos+11); if (scopePos < 0) { return null; } String baseDN = line.substring(basePos+11, scopePos); char scopeChar = line.charAt(scopePos+8); SearchScope scope; switch (scopeChar) { case '0': scope = SearchScope.BASE; break; case '1': scope = SearchScope.ONE; break; case '2': scope = SearchScope.SUB; break; default: scope = SearchScope.BASE; break; } int filterPos = line.indexOf(scopeChar + " filter=\"", scopePos+8); if (filterPos < 0) { return null; } String filter = null; String[] attrs = null; int attrsPos = line.indexOf("\" attrs=", filterPos+10); if (attrsPos < 0) { int filterClosePos = line.indexOf('"', filterPos+10); if (filterClosePos < 0) { return null; } else { filter = line.substring(filterPos+10, filterClosePos); } } else { filter = line.substring(filterPos+10, attrsPos); char attrsChar = line.charAt(attrsPos+8); if (attrsChar == '\"') { int attrsClosePos = line.indexOf('"', attrsPos+9); if (attrsClosePos > 0) { String attrsStr = line.substring(attrsPos+9, attrsClosePos); ArrayList<String> attrList = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(attrsStr, " "); while (tokenizer.hasMoreTokens()) { attrList.add(tokenizer.nextToken()); } attrs = new String[attrList.size()]; attrList.toArray(attrs); } } } return new SearchOperation(baseDN, scope, filter, attrs); } catch (Exception e) { jobThread.writeVerbose("Unable to parse search line \"" + line + "\": " + e); return null; } } /** * Replays this operation against the directory server using the information * contained in the provided job thread. * * @param jobThread The job thread to use when replaying this operation. */ @Override() public void replayOperation(LogPlaybackJobClass jobThread) { String resultCode = DEFAULT_RESULT_CODE; try { jobThread.totalTimer.startTimer(); jobThread.searchTimer.startTimer(); jobThread.opConnection.search(baseDN, scope, filter, attributes); } catch (LDAPException le) { ResultCode rc = le.getResultCode(); resultCode = rc.intValue() + " (" + rc.getName() + ')'; } catch (Exception e) { resultCode = ResultCode.OTHER_INT_VALUE + " (" + e + ')'; } finally { jobThread.totalTimer.stopTimer(); jobThread.searchTimer.stopTimer(); jobThread.totalReplayed.increment(); jobThread.searchesReplayed.increment(); jobThread.opRatios.increment("Search"); jobThread.resultCodes.increment(resultCode); } } /** * Retrieves a string representation of this log operation. * * @return A string representation of this log operation. */ @Override() public String toString() { StringBuilder buffer = new StringBuilder(); buffer.append("SRCH base=\""); buffer.append(baseDN); buffer.append("\" scope="); buffer.append(scope); buffer.append(" filter=\""); buffer.append(filter); buffer.append("\" attrs="); if ((attributes == null) || (attributes.length == 0)) { buffer.append("ALL"); } else { buffer.append('"'); buffer.append(attributes[0]); for (int i=1; i < attributes.length; i++) { buffer.append(' '); buffer.append(attributes[i]); } buffer.append('"'); } return buffer.toString(); } }