opendj3-server-dev/src/guitools/org/opends/guitools/controlpanel/browser/IconPool.java
@@ -22,20 +22,10 @@ * * * Copyright 2008-2010 Sun Microsystems, Inc. * Portions Copyright 2013 ForgeRock AS. * Portions Copyright 2013-2014 ForgeRock AS. */ package org.opends.guitools.controlpanel.browser; import static org.opends.messages.AdminToolMessages.*; import java.awt.Canvas; import java.awt.Image; import java.awt.MediaTracker; import java.awt.image.ColorModel; import java.awt.image.ImageObserver; import java.awt.image.MemoryImageSource; import java.awt.image.PixelGrabber; import java.util.HashMap; import java.util.Set; import java.util.SortedSet; @@ -46,6 +36,8 @@ import org.opends.quicksetup.ui.UIFactory; import org.opends.server.util.ServerConstants; import static org.opends.messages.AdminToolMessages.*; /** * This class is used as a cache containing the icons that are used by the * BrowserController to update the nodes. It keeps some icons associated with @@ -66,10 +58,11 @@ */ public static final int MODIFIER_ERROR = 0x04; private HashMap<String, ImageIcon> iconTable = private final HashMap<String, ImageIcon> iconTable = new HashMap<String, ImageIcon>(); private HashMap<String, String> pathTable = new HashMap<String, String>(); private HashMap<String, String> descriptionTable = private final HashMap<String, String> pathTable = new HashMap<String, String>(); private final HashMap<String, String> descriptionTable = new HashMap<String, String>(); private ImageIcon defaultLeafIcon; private ImageIcon suffixIcon; @@ -117,12 +110,9 @@ "passwordpolicy", INFO_PASSWORD_POLICY_ICON_DESCRIPTION.get().toString() }; private String GENERIC_OBJECT_DESCRIPTION = "Generic entry"; private final String GENERIC_OBJECT_DESCRIPTION = "Generic entry"; /** * The default constructor. * */ /** The default constructor. */ public IconPool() { // Recopy ICON_PATH in pathTable for fast access for (int i = 0; i < ICON_PATH.length; i = i+2) { @@ -144,15 +134,12 @@ * modifiers. */ public ImageIcon getIcon(SortedSet<String> objectClasses, int modifiers) { ImageIcon result; String key = makeKey(objectClasses, modifiers); result = iconTable.get(key); ImageIcon result = iconTable.get(key); if (result == null) { result = makeIcon(objectClasses, modifiers); iconTable.put(key, result); } return result; } @@ -270,7 +257,7 @@ ImageIcon result; // Find the icon associated to the object class if ((objectClasses == null) || (objectClasses.size() == 0)) { if (objectClasses == null || objectClasses.size() == 0) { result = getDefaultContainerIcon(); } else { @@ -328,87 +315,8 @@ if(ocValues != null) { result.append(Utilities.getStringFromCollection(ocValues, "")); } result.append(String.valueOf(modifiers)); result.append(modifiers); return result.toString(); } /** * Returns a RemoteImage corresponding to the superposition of the icon * Image and the mask Image. * * @param icon the RemoteImage that we want to bar. * @param mask the ImageIcond to be used as mask. * @return a RemoteImage corresponding to the superposition of the icon * Image and the mask Image. */ public static ImageIcon maskedIcon(ImageIcon icon, ImageIcon mask) { ImageIcon fReturn; int TRANSPARENT = 16711165; // The value of a transparent pixel int h = icon.getIconHeight(); int w = icon.getIconWidth(); if (mask.getImageLoadStatus() != MediaTracker.COMPLETE) { return null; } Image maskImage = mask.getImage(); Image scaledMaskImage = maskImage.getScaledInstance(w, h , Image.SCALE_SMOOTH); ImageIcon scaledMask = new ImageIcon(scaledMaskImage); if (scaledMask.getImageLoadStatus() != MediaTracker.COMPLETE) { return null; } int[] iconPixels = new int[w * h]; try { PixelGrabber pg = new PixelGrabber(icon.getImage(), 0, 0, w, h, iconPixels, 0, w); pg.grabPixels(); if ((pg.status() & ImageObserver.ABORT) !=0) { return null; } } catch (Exception e) { e.printStackTrace(); return null; } int[] filterPixels = new int[w * h]; try { PixelGrabber pgf = new PixelGrabber(scaledMask.getImage(), 0, 0, w, h, filterPixels, 0, w); pgf.grabPixels(); if ((pgf.status() & ImageObserver.ABORT) !=0) { fReturn = null; return fReturn; } } catch (Exception e) { e.printStackTrace(); fReturn = null; return fReturn; } int[] newPixels = new int[w * h]; for( int i = 0; i < h; i++) for (int j = 0; j < w; j++) if (filterPixels[j + i*w] != TRANSPARENT) { newPixels[j + i*w] = filterPixels[j + i*w]; } else { newPixels[j + i*w] = iconPixels[j + i*w]; } Canvas component = new Canvas(); Image newImage = component.getToolkit().createImage( new MemoryImageSource( w, h, ColorModel.getRGBdefault(), newPixels, 0, w)); fReturn = new ImageIcon(newImage, icon.getDescription()); return fReturn; } } opendj3-server-dev/src/guitools/org/opends/guitools/controlpanel/browser/LDAPConnectionPool.java
@@ -27,7 +27,6 @@ package org.opends.guitools.controlpanel.browser; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import javax.naming.NamingException; @@ -44,6 +43,8 @@ import com.forgerock.opendj.cli.CliConstants; import static org.opends.admin.ads.util.ConnectionUtils.*; /** * An LDAPConnectionPool is a pool of LDAPConnection. * <BR><BR> @@ -73,11 +74,12 @@ */ public class LDAPConnectionPool { HashMap<String, AuthRecord> authTable = new HashMap<String, AuthRecord>(); HashMap<String, ConnectionRecord> connectionTable = private final HashMap<String, AuthRecord> authTable = new HashMap<String, AuthRecord>(); private final HashMap<String, ConnectionRecord> connectionTable = new HashMap<String, ConnectionRecord>(); ArrayList<ReferralAuthenticationListener> listeners; private ArrayList<ReferralAuthenticationListener> listeners; private Control[] requestControls = new Control[] {}; private ApplicationTrustManager trustManager; @@ -91,28 +93,20 @@ * connection pool, <CODE>false</CODE> otherwise. */ public boolean isConnectionRegistered(InitialLdapContext ctx) { boolean isConnectionRegistered = false; for (String key : connectionTable.keySet()) { ConnectionRecord cr = connectionTable.get(key); if (cr.ctx != null) { isConnectionRegistered = ConnectionUtils.getHostName(cr.ctx).equals( ConnectionUtils.getHostName(ctx)) && (ConnectionUtils.getPort(cr.ctx) == ConnectionUtils.getPort(ctx)) && ConnectionUtils.getBindDN(cr.ctx).equals( ConnectionUtils.getBindDN(ctx)) && ConnectionUtils.getBindPassword(cr.ctx).equals( ConnectionUtils.getBindPassword(ctx)) && (ConnectionUtils.isSSL(cr.ctx) == ConnectionUtils.isSSL(ctx)) && (ConnectionUtils.isStartTLS(cr.ctx) == ConnectionUtils.isStartTLS(ctx)); } if (isConnectionRegistered) { break; if (cr.ctx != null && getHostName(cr.ctx).equals(getHostName(ctx)) && getPort(cr.ctx) == getPort(ctx) && getBindDN(cr.ctx).equals(getBindDN(ctx)) && getBindPassword(cr.ctx).equals(getBindPassword(ctx)) && isSSL(cr.ctx) == isSSL(ctx) && isStartTLS(cr.ctx) == isStartTLS(ctx)) { return true; } } return isConnectionRegistered; return false; } /** @@ -121,12 +115,7 @@ */ public void registerConnection(InitialLdapContext ctx) { registerAuth(ctx); LDAPURL url = makeLDAPUrl( ConnectionUtils.getHostName(ctx), ConnectionUtils.getPort(ctx), "", ConnectionUtils.isSSL(ctx) ); LDAPURL url = makeLDAPUrl(ctx); String key = makeKeyFromLDAPUrl(url); ConnectionRecord cr = new ConnectionRecord(); cr.ctx = ctx; @@ -143,11 +132,7 @@ public void unregisterConnection(InitialLdapContext ctx) throws NamingException { LDAPURL url = makeLDAPUrl( ConnectionUtils.getHostName(ctx), ConnectionUtils.getPort(ctx), "", ConnectionUtils.isSSL(ctx)); LDAPURL url = makeLDAPUrl(ctx); unRegisterAuth(url); String key = makeKeyFromLDAPUrl(url); connectionTable.remove(key); @@ -166,17 +151,6 @@ } /** * Removes a referral authentication listener. * @param listener the referral authentication listener. */ public void removeReferralAuthenticationListener( ReferralAuthenticationListener listener) { if (listeners != null) { listeners.remove(listener); } } /** * Returns an LDAPConnection for accessing the specified url. * If no connection are available for the protocol/host/port * of the URL, getConnection() makes a new one and call connect(). @@ -289,35 +263,17 @@ if (targetRecord == null) { // ldc is not in _connectionTable -> bug throw new IllegalArgumentException("Invalid LDAP connection"); } else { synchronized(targetRecord) { targetRecord.counter--; if ((targetRecord.counter == 0) && targetRecord.disconnectAfterUse) { disconnectAndRemove(targetRecord); } } } } /** * Disconnect the connections which are not being used. * Connections being used will be disconnected as soon * as they are released. */ public synchronized void flush() { for (ConnectionRecord cr : connectionTable.values()) synchronized (targetRecord) { if (cr.counter <= 0) { disconnectAndRemove(cr); } else { cr.disconnectAfterUse = true; targetRecord.counter--; if (targetRecord.counter == 0 && targetRecord.disconnectAfterUse) { disconnectAndRemove(targetRecord); } } } /** * Register authentication data. * If authentication data are already available for the protocol/host/port @@ -333,14 +289,11 @@ * provided authentication (for testing purposes). * @throws NamingException if an error occurs connecting. */ public void registerAuth(LDAPURL ldapUrl, String dn, String pw, boolean connect) throws NamingException { private void registerAuth(LDAPURL ldapUrl, String dn, String pw, boolean connect) throws NamingException { String key = makeKeyFromLDAPUrl(ldapUrl); AuthRecord ar; ar = new AuthRecord(); ar.ldapUrl = ldapUrl; final AuthRecord ar = new AuthRecord(); ar.dn = dn; ar.password = pw; @@ -373,15 +326,10 @@ * @param ctx the connection that we retrieve the authentication information * from. */ public void registerAuth(InitialLdapContext ctx) { LDAPURL url = makeLDAPUrl( ConnectionUtils.getHostName(ctx), ConnectionUtils.getPort(ctx), "", ConnectionUtils.isSSL(ctx)); private void registerAuth(InitialLdapContext ctx) { LDAPURL url = makeLDAPUrl(ctx); try { registerAuth(url, ConnectionUtils.getBindDN(ctx), ConnectionUtils.getBindPassword(ctx), false); registerAuth(url, getBindDN(ctx), getBindPassword(ctx), false); } catch (NamingException x) { throw new RuntimeException("Bug"); @@ -397,7 +345,7 @@ * unregistered. * @throws NamingException if the unbind fails. */ public void unRegisterAuth(LDAPURL ldapUrl) throws NamingException { private void unRegisterAuth(LDAPURL ldapUrl) throws NamingException { String key = makeKeyFromLDAPUrl(ldapUrl); authTable.remove(key); @@ -405,45 +353,6 @@ } /** * Get authentication DN registered for this url. * @param ldapUrl the LDAP URL for which we want to get authentication DN. * @return the bind DN of the authentication. */ public synchronized String getAuthDN(LDAPURL ldapUrl) { String result; String key = makeKeyFromLDAPUrl(ldapUrl); AuthRecord ar = authTable.get(key); if (ar == null) { result = null; } else { result = ar.dn; } return result; } /** * Get authentication password registered for this url. * @param ldapUrl the LDAP URL for which we want to get authentication * password. * @return the password of the authentication. */ public synchronized String getAuthPassword(LDAPURL ldapUrl) { String result; String key = makeKeyFromLDAPUrl(ldapUrl); AuthRecord ar = authTable.get(key); if (ar == null) { result = null; } else { result = ar.password; } return result; } /** * Disconnect the connection associated to a record * and remove the record from connectionTable. * @param cr the ConnectionRecord to remove. @@ -492,8 +401,7 @@ */ private static String makeKeyFromRecord(ConnectionRecord rec) { String protocol = ConnectionUtils.isSSL(rec.ctx) ? "LDAPS" : "LDAP"; return protocol + ":" + ConnectionUtils.getHostName(rec.ctx) + ":" + ConnectionUtils.getPort(rec.ctx); return protocol + ":" + getHostName(rec.ctx) + ":" + getPort(rec.ctx); } /** @@ -507,24 +415,18 @@ private InitialLdapContext createLDAPConnection(LDAPURL ldapUrl, AuthRecord ar) throws NamingException { InitialLdapContext ctx; // Take the base DN out of the URL and only keep the protocol, host and port ldapUrl = new LDAPURL(ldapUrl.getScheme(), ldapUrl.getHost(), ldapUrl.getPort(), (DN)null, null, null, null, null); if (isSecureLDAPUrl(ldapUrl)) { ctx = ConnectionUtils.createLdapsContext(ldapUrl.toString(), ar.dn, return ConnectionUtils.createLdapsContext(ldapUrl.toString(), ar.dn, ar.password, getConnectTimeout(), null, getTrustManager() , getKeyManager()); getTrustManager(), getKeyManager()); } else { ctx = ConnectionUtils.createLdapContext(ldapUrl.toString(), ar.dn, ar.password, getConnectTimeout(), null); } return ctx; return ConnectionUtils.createLdapContext(ldapUrl.toString(), ar.dn, ar.password, getConnectTimeout(), null); } /** @@ -581,26 +483,16 @@ * @return <CODE>true</CODE> if the LDAP URL is secure and <CODE>false</CODE> * otherwise. */ public static boolean isSecureLDAPUrl(LDAPURL url) { private static boolean isSecureLDAPUrl(LDAPURL url) { return !LDAPURL.DEFAULT_SCHEME.equalsIgnoreCase(url.getScheme()); } /** * Make an url from the specified arguments. * @param host the host. * @param port the port. * @param dn the dn. * @param secure whether it is a secure URL or not. * @return an LDAP URL from the specified arguments. */ public static LDAPURL makeLDAPUrl(String host, int port, String dn, boolean secure) { private LDAPURL makeLDAPUrl(InitialLdapContext ctx) { return new LDAPURL( secure ? "ldaps" : LDAPURL.DEFAULT_SCHEME, host, port, dn, isSSL(ctx) ? "ldaps" : LDAPURL.DEFAULT_SCHEME, getHostName(ctx), getPort(ctx), "", null, // no attributes SearchScope.BASE_OBJECT, null, // No filter @@ -645,20 +537,12 @@ null); // No extensions } /** * Returns a collection of AuthRecord. * @return a collection of AuthRecord. */ Collection<?> getRegisteredAuthentication() { return authTable.values(); } } /** * A structure representing authentication data. */ class AuthRecord { LDAPURL ldapUrl; String dn; String password; } opendj3-server-dev/src/server/org/opends/server/replication/plugin/PersistentServerState.java
@@ -27,7 +27,7 @@ package org.opends.server.replication.plugin; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -57,7 +57,7 @@ private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); private final DN baseDn; private final DN baseDN; private final int serverId; private final ServerState state; @@ -70,13 +70,13 @@ * Create a new PersistentServerState based on an already existing * ServerState. * * @param baseDn The baseDN for which the ServerState is created. * @param baseDN The baseDN for which the ServerState is created. * @param serverId The serverId. * @param state The serverState. */ PersistentServerState(DN baseDn, int serverId, ServerState state) PersistentServerState(DN baseDN, int serverId, ServerState state) { this.baseDn = baseDn; this.baseDN = baseDN; this.serverId = serverId; this.state = state; loadState(); @@ -114,7 +114,7 @@ { if (!state.isSaved()) { state.setSaved(updateStateEntry() == ResultCode.SUCCESS); state.setSaved(updateStateEntry()); } } @@ -164,16 +164,15 @@ * Search the database entry that is used to periodically * save the ServerState */ LinkedHashSet<String> attributes = new LinkedHashSet<String>(1); attributes.add(REPLICATION_STATE); final InternalSearchOperation search = getRootConnection().processSearch( baseDn, SearchScope.BASE_OBJECT, DereferenceAliasesPolicy.NEVER, 0, 0, false, filter, attributes); if (((search.getResultCode() != ResultCode.SUCCESS)) && ((search.getResultCode() != ResultCode.NO_SUCH_OBJECT))) baseDN, SearchScope.BASE_OBJECT, DereferenceAliasesPolicy.NEVER, 0, 0, false, filter, Collections.singleton(REPLICATION_STATE)); final ResultCode resultCode = search.getResultCode(); if (resultCode != ResultCode.SUCCESS && resultCode != ResultCode.NO_SUCH_OBJECT) { logger.error(ERR_ERROR_SEARCHING_RUV, search.getResultCode().getName(), search, search.getErrorMessage(), baseDn); search.getErrorMessage(), baseDN); return null; } return getFirstResult(search); @@ -197,15 +196,13 @@ { SearchFilter filter = SearchFilter.createFilterFromString( "(&(objectclass=ds-cfg-replication-domain)" + "(ds-cfg-base-dn=" + baseDn + "))"); + "(ds-cfg-base-dn=" + baseDN + "))"); LinkedHashSet<String> attributes = new LinkedHashSet<String>(1); attributes.add(REPLICATION_STATE); final InternalSearchOperation op = getRootConnection().processSearch( DN.valueOf("cn=config"), SearchScope.SUBORDINATES, DereferenceAliasesPolicy.NEVER, 1, 0, false, filter, attributes); 1, 0, false, filter, Collections.singleton(REPLICATION_STATE)); return getFirstResult(op); } catch (DirectoryException e) @@ -238,12 +235,10 @@ { AttributeType synchronizationStateType = DirectoryServer.getAttributeType(REPLICATION_STATE); List<Attribute> attrs = resultEntry.getAttribute(synchronizationStateType); List<Attribute> attrs = resultEntry.getAttribute(synchronizationStateType); if (attrs != null) { Attribute attr = attrs.get(0); for (ByteString value : attr) for (ByteString value : attrs.get(0)) { update(new CSN(value.toString())); } @@ -254,12 +249,12 @@ * Save the current values of this PersistentState object * in the appropriate entry of the database. * * @return a ResultCode indicating if the method was successful. * @return a boolean indicating if the method was successful. */ private ResultCode updateStateEntry() private boolean updateStateEntry() { // Generate a modify operation on the Server State baseDN Entry. ResultCode result = runUpdateStateEntry(baseDn); ResultCode result = runUpdateStateEntry(baseDN); if (result == ResultCode.NO_SUCH_OBJECT) { // The base entry does not exist yet in the database or has been deleted, @@ -267,11 +262,10 @@ SearchResultEntry configEntry = searchConfigEntry(); if (configEntry != null) { DN configDN = configEntry.getName(); result = runUpdateStateEntry(configDN); result = runUpdateStateEntry(configEntry.getName()); } } return result; return result == ResultCode.SUCCESS; } /** @@ -287,14 +281,12 @@ ArrayList<ByteString> values = state.toASN1ArrayList(); LDAPAttribute attr = new LDAPAttribute(REPLICATION_STATE, values); LDAPModification mod = new LDAPModification(ModificationType.REPLACE, attr); ArrayList<RawModification> mods = new ArrayList<RawModification>(1); mods.add(mod); RawModification mod = new LDAPModification(ModificationType.REPLACE, attr); ModifyOperationBasis op = new ModifyOperationBasis(getRootConnection(), nextOperationID(), nextMessageID(), null, ByteString.valueOf(serverStateEntryDN.toString()), mods); Collections.singletonList(mod)); op.setInternalOperation(true); op.setSynchronizationOperation(true); op.setDontSynchronize(true); @@ -302,7 +294,7 @@ if (op.getResultCode() != ResultCode.SUCCESS) { logger.error(DEBUG_ERROR_UPDATING_RUV, op.getResultCode().getName(), op, op.getErrorMessage(), baseDn); op.getResultCode().getName(), op, op.getErrorMessage(), baseDN); } return op.getResultCode(); } @@ -357,7 +349,7 @@ InternalSearchOperation op; try { op = LDAPReplicationDomain.searchForChangedEntries(baseDn, op = LDAPReplicationDomain.searchForChangedEntries(baseDN, serverStateMaxCSN, null); } catch (Exception e) @@ -369,7 +361,7 @@ { // An error happened trying to search for the updates // Log an error logger.error(ERR_CANNOT_RECOVER_CHANGES, baseDn.toNormalizedString()); logger.error(ERR_CANNOT_RECOVER_CHANGES, baseDN.toNormalizedString()); return; } @@ -394,7 +386,7 @@ { // Update the serverState with the new maxCsn present in the database update(dbMaxCSN); logger.info(NOTE_SERVER_STATE_RECOVERY, baseDn.toNormalizedString(), dbMaxCSN); logger.info(NOTE_SERVER_STATE_RECOVERY, baseDN.toNormalizedString(), dbMaxCSN); } } } @@ -410,4 +402,14 @@ { return state.getCSN(serverId); } /** {@inheritDoc} */ @Override public String toString() { return getClass().getSimpleName() + " baseDN=" + baseDN + " serverId=" + serverId + " " + REPLICATION_STATE + "=" + state; } } opendj3-server-dev/src/server/org/opends/server/replication/server/MessageHandler.java
@@ -292,31 +292,11 @@ * restart as usual * load this change on the delayList */ DBCursor<UpdateMsg> cursor = null; try { // fill the lateQueue cursor = replicationServerDomain.getCursorFrom(serverState); while (cursor.next() && isLateQueueBelowThreshold()) { lateQueue.add(cursor.getRecord()); } } catch (ChangelogException e) { logger.traceException(e); } finally { close(cursor); } /* * If the late queue is empty then we could not find any messages in * the replication log so the remote server is not late anymore. */ fillLateQueue(); if (lateQueue.isEmpty()) { // we could not find any messages in the changelog // so the remote server is not late anymore. synchronized (msgQueue) { // Ensure we are below threshold so this server will follow the @@ -330,8 +310,8 @@ else { /* * if the first change in the lateQueue is also on the regular * queue, we can resume the processing from the regular queue * if the first change in the lateQueue is also on the regular queue, * we can resume the processing from the regular queue * -> set following to true and empty the lateQueue. */ UpdateMsg msg = lateQueue.first(); @@ -353,7 +333,7 @@ { // get the next change from the lateQueue UpdateMsg msg; synchronized (msgQueue) synchronized (msgQueue) // TODO JNR why synchronize(msgQueue) here? { msg = lateQueue.removeFirst(); } @@ -406,6 +386,27 @@ return null; } private void fillLateQueue() { DBCursor<UpdateMsg> cursor = null; try { cursor = replicationServerDomain.getCursorFrom(serverState); while (cursor.next() && isLateQueueBelowThreshold()) { lateQueue.add(cursor.getRecord()); } } catch (ChangelogException e) { logger.traceException(e); } finally { close(cursor); } } private boolean isLateQueueBelowThreshold() { return lateQueue.count() < 100 && lateQueue.bytesCount() < 50000; @@ -425,16 +426,14 @@ { if (!msgQueue.isEmpty()) { UpdateMsg msg = msgQueue.first(); result = msg.getCSN(); result = msgQueue.first().getCSN(); } } else { if (!lateQueue.isEmpty()) { UpdateMsg msg = lateQueue.first(); result = msg.getCSN(); result = lateQueue.first().getCSN(); } else { opendj3-server-dev/src/server/org/opends/server/replication/server/MsgQueue.java
@@ -26,7 +26,6 @@ */ package org.opends.server.replication.server; import java.util.NavigableMap; import org.forgerock.i18n.slf4j.LocalizedLogger; import java.util.TreeMap; @@ -38,13 +37,21 @@ /** * This class is used to build ordered lists of UpdateMsg. * The order is defined by the order of the CSN of the UpdateMsg. * @ThreadSafe */ public class MsgQueue { private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); private NavigableMap<CSN, UpdateMsg> map = new TreeMap<CSN, UpdateMsg>(); private TreeMap<CSN, UpdateMsg> map = new TreeMap<CSN, UpdateMsg>(); /** * FIXME JNR to be investigated: * I strongly suspect that we could replace this field * by using the synchronized keyword on each method. * However, MessageHandler is weirdly synchronizing on msgQueue field * even though it is touching the lateQueue field (?!?). */ private final Object lock = new Object(); /** The total number of bytes for all the message in the queue. */ @@ -112,7 +119,7 @@ { synchronized (lock) { UpdateMsg msgSameCSN = map.put(update.getCSN(), update); final UpdateMsg msgSameCSN = map.put(update.getCSN(), update); if (msgSameCSN != null) { try @@ -123,11 +130,11 @@ { // Adding 2 msgs with the same CSN is ok only when // the 2 msgs are the same bytesCount += (update.size() - msgSameCSN.size()); bytesCount += update.size() - msgSameCSN.size(); logger.error(ERR_RSQUEUE_DIFFERENT_MSGS_WITH_SAME_CN, msgSameCSN.getCSN(), msgSameCSN, update); } } catch(Exception e) catch (Exception e) { logger.traceException(e); } @@ -149,10 +156,12 @@ { synchronized (lock) { UpdateMsg update = map.get(map.firstKey()); // FIXME JNR replace next 2 lines with just that one: // final UpdateMsg update = map.pollFirstEntry().getValue(); final UpdateMsg update = map.get(map.firstKey()); map.remove(update.getCSN()); bytesCount -= update.size(); if ((map.size() == 0) && (bytesCount != 0)) if (map.isEmpty() && bytesCount != 0) { // should never happen logger.error(ERR_BYTE_COUNT, bytesCount); @@ -197,18 +206,33 @@ * message. If the passed in message is not contained in the current queue, * then all messages will be removed from it. * * @param msg * @param finalMsg * the final message to reach when consuming messages from this queue */ public void consumeUpTo(UpdateMsg msg) public void consumeUpTo(UpdateMsg finalMsg) { UpdateMsg msg1; // FIXME this code could be more efficient if the msgQueue could call the // following code (to be tested): // if (!map.containsKey(finalMsg.getCSN())) { // map.clear(); // } else { // map.headMap(finalMsg.getCSN(), true).clear(); // } final CSN finalCSN = finalMsg.getCSN(); UpdateMsg msg; do { // FIXME this code could be more efficient if the msgQueue could call the // following code (to be tested): // map.headMap(msg.getCSN(), true).clear() msg1 = removeFirst(); } while (!msg.getCSN().equals(msg1.getCSN())); msg = removeFirst(); } while (!finalCSN.equals(msg.getCSN())); } /** {@inheritDoc} */ @Override public String toString() { return getClass().getSimpleName() + " bytesCount=" + bytesCount + " queue=" + map.values(); } } opendj3-server-dev/src/server/org/opends/server/replication/server/changelog/je/JEReplicaDBCursor.java
@@ -30,7 +30,7 @@ import org.opends.server.replication.protocol.UpdateMsg; import org.opends.server.replication.server.changelog.api.ChangelogException; import org.opends.server.replication.server.changelog.api.DBCursor; import org.opends.server.replication.server.changelog.je.ReplicationDB.*; import org.opends.server.replication.server.changelog.je.ReplicationDB.ReplServerDBCursor; /** * Berkeley DB JE implementation of {@link DBCursor}. @@ -89,11 +89,7 @@ final ReplServerDBCursor localCursor = cursor; currentChange = localCursor != null ? localCursor.next() : null; if (currentChange != null) { lastNonNullCurrentCSN = currentChange.getCSN(); } else if (currentChange == null) { synchronized (this) { @@ -105,13 +101,14 @@ // and fixing such issue with unit tests. cursor = db.openReadCursor(lastNonNullCurrentCSN); currentChange = cursor.next(); if (currentChange != null) { lastNonNullCurrentCSN = currentChange.getCSN(); } } } return currentChange != null; if (currentChange != null) { lastNonNullCurrentCSN = currentChange.getCSN(); return true; } return false; } /** {@inheritDoc} */ opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java
@@ -26,28 +26,30 @@ */ package org.opends.server.monitors; import java.util.ArrayList; import java.util.Iterator; import java.util.Set; import org.forgerock.opendj.ldap.SearchScope; import org.opends.server.types.DN; import org.forgerock.opendj.ldap.ResultCode; import org.opends.server.types.SearchFilter; import org.opends.server.TestCaseUtils; import org.opends.server.core.DirectoryServer; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.types.SearchResultEntry; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.opends.server.TestCaseUtils; import org.opends.server.core.DirectoryServer; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchOperation; import static org.forgerock.opendj.ldap.SearchScope.*; import static org.opends.server.protocols.internal.InternalClientConnection.*; import static org.opends.server.types.SearchFilter.*; import static org.testng.Assert.*; /** * Interacts with the Directory Server monitor providers by retrieving the * monitor entries with internal searches. */ @SuppressWarnings("javadoc") public class InternalSearchMonitorTestCase extends MonitorTestCase { @@ -55,20 +57,15 @@ /** * Ensures that the Directory Server is started. * * @throws Exception If an unexpected problem occurs. */ @BeforeClass() public void startServer() throws Exception @BeforeClass public void startServer() throws Exception { TestCaseUtils.startServer(); DirectoryServer.registerMonitorProvider(testMonitorProvider); } @AfterClass() @AfterClass public void deregisterTestMonitor() { DirectoryServer.deregisterMonitorProvider(testMonitorProvider); @@ -76,20 +73,14 @@ /** * Uses an internal subtree search to retrieve the monitor entries. * * @throws Exception If an unexpected problem occurs. */ @Test public void testWithSubtreeMonitorSearch() throws Exception public void testWithSubtreeMonitorSearch() throws Exception { InternalClientConnection conn = InternalClientConnection.getRootConnection(); InternalSearchOperation searchOperation = conn.processSearch(DN.valueOf("cn=monitor"), SearchScope.WHOLE_SUBTREE, SearchFilter.createFilterFromString("(objectClass=*)")); assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS, "Failed to search cn=monitor subtree. Got error message: " + searchOperation.getErrorMessage()); InternalSearchOperation op = getRootConnection().processSearch( "cn=monitor", WHOLE_SUBTREE, "(objectClass=*)"); assertEquals(op.getResultCode(), ResultCode.SUCCESS, "Failed to search cn=monitor subtree. Got error message: " + op.getErrorMessage()); } @@ -102,18 +93,14 @@ @DataProvider(name = "monitorNames") public Object[][] getMonitorNames() { ArrayList<String> monitorNames = new ArrayList<String>(); for (String name : DirectoryServer.getMonitorProviders().keySet()) { monitorNames.add(name); } Set<String> monitorNames = DirectoryServer.getMonitorProviders().keySet(); Iterator<String> it = monitorNames.iterator(); Object[][] nameArray = new Object[monitorNames.size()][1]; for (int i=0; i < nameArray.length; i++) { nameArray[i] = new Object[] { monitorNames.get(i) }; nameArray[i] = new Object[] { it.next() }; } return nameArray; } @@ -123,55 +110,39 @@ * Uses a set of internal base-level searches to retrieve the monitor entries. * * @param monitorName The name of the monitor entry to retrieve. * * @throws Exception If an unexpected problem occurs. */ @Test(dataProvider = "monitorNames") public void testWithBaseObjectMonitorSearch(String monitorName) throws Exception public void testWithBaseObjectMonitorSearch(String monitorName) throws Exception { // could be more than one level DN monitorDN = DN.valueOf("cn="+monitorName+",cn=monitor"); InternalClientConnection conn = InternalClientConnection.getRootConnection(); InternalSearchOperation searchOperation = conn.processSearch(monitorDN, SearchScope.BASE_OBJECT, SearchFilter.createFilterFromString("(objectClass=*)")); assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS, "Failed to read " + monitorDN + " entry. Got error message: " + searchOperation.getErrorMessage()); final String monitorDN = "cn="+monitorName+",cn=monitor"; InternalSearchOperation op = getRootConnection().processSearch( monitorDN, BASE_OBJECT, "(objectClass=*)"); assertEquals(op.getResultCode(), ResultCode.SUCCESS, "Failed to read " + monitorDN + " entry. Got error message: " + op.getErrorMessage()); } /** * Uses an internal subtree search to retrieve the monitor entries, then * verifies that the resulting entry DNs can be used to get the same * entries with a base object search. * * @throws Exception If an unexpected problem occurs. */ @Test public void testWithSubtreeAndBaseMonitorSearch() throws Exception public void testWithSubtreeAndBaseMonitorSearch() throws Exception { InternalClientConnection conn = InternalClientConnection.getRootConnection(); InternalSearchOperation searchOperation = conn.processSearch(DN.valueOf("cn=monitor"), SearchScope.WHOLE_SUBTREE, SearchFilter.createFilterFromString("(objectClass=*)")); assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS, "Failed to search cn=monitor subtree. Got error message: " + searchOperation.getErrorMessage()); final InternalClientConnection conn = getRootConnection(); InternalSearchOperation op = conn.processSearch( "cn=monitor", WHOLE_SUBTREE, "(objectClass=*)"); assertEquals(op.getResultCode(), ResultCode.SUCCESS, "Failed to search cn=monitor subtree. Got error message: " + op.getErrorMessage()); for (SearchResultEntry sre : searchOperation.getSearchEntries()) for (SearchResultEntry sre : op.getSearchEntries()) { SearchFilter filter = SearchFilter.createFilterFromString("(objectClass=*)"); InternalSearchOperation readOperation = conn.processSearch(sre.getName(), SearchScope.BASE_OBJECT, filter); assertEquals(readOperation.getResultCode(), ResultCode.SUCCESS, "Failed to read " + sre.getName() + " entry. Got error message: " + readOperation.getErrorMessage()); final InternalSearchOperation readOp = conn.processSearch( sre.getName(), BASE_OBJECT, createFilterFromString("(objectClass=*)")); assertEquals(readOp.getResultCode(), ResultCode.SUCCESS, "Failed to read " + sre.getName() + " entry. Got error message: " + readOp.getErrorMessage()); } } } opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ExternalChangeLogTest.java
@@ -28,17 +28,13 @@ import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; import java.net.Socket; import java.util.*; import org.assertj.core.api.Assertions; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.DereferenceAliasesPolicy; import org.forgerock.opendj.ldap.ModificationType; import org.forgerock.opendj.ldap.SearchScope; import org.forgerock.opendj.ldap.*; import org.opends.server.TestCaseUtils; import org.opends.server.admin.std.server.ExternalChangelogDomainCfg; import org.opends.server.api.Backend; @@ -67,7 +63,12 @@ import org.opends.server.tools.LDAPSearch; import org.opends.server.tools.LDAPWriter; import org.opends.server.types.*; import org.forgerock.opendj.ldap.ResultCode; import org.opends.server.types.Attribute; import org.opends.server.types.Attributes; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.Modification; import org.opends.server.types.RDN; import org.opends.server.util.LDIFWriter; import org.opends.server.util.TimeThread; import org.opends.server.workflowelement.externalchangelog.ECLSearchOperation; @@ -79,11 +80,11 @@ import org.testng.annotations.Test; import static org.assertj.core.api.Assertions.*; import static org.forgerock.opendj.ldap.ResultCode.*; import static org.opends.messages.ReplicationMessages.*; import static org.opends.server.TestCaseUtils.*; import static org.opends.server.controls.PersistentSearchChangeType.*; import static org.opends.server.replication.protocol.OperationContext.*; import static org.forgerock.opendj.ldap.ResultCode.*; import static org.opends.server.util.StaticUtils.*; import static org.testng.Assert.*; @@ -163,17 +164,7 @@ debugInfo("configure", "ReplicationServer created"+replicationServer); } /** * Launcher. */ @Test(enabled=true) public void PreTest() throws Exception { // No RSDomain created yet => RS only case => ECL is not a supported ECLIsNotASupportedSuffix(); } @Test(enabled=true, dependsOnMethods = { "PreTest"}) @Test(enabled = true, dependsOnMethods = { "TestECLIsNotASupportedSuffix" }) public void PrimaryTest() throws Exception { replicationServer.getChangelogDB().setPurgeDelay(0); @@ -194,27 +185,6 @@ ECLCompatTestLimits(1,4,true); } @Test(enabled=false, dependsOnMethods = { "PrimaryTest"}) public void TestWithTwoDomains() throws Exception { replicationServer.getChangelogDB().setPurgeDelay(0); // Test with a mix of domains, a mix of DSes ECLTwoDomains(); } @Test(enabled=false, dependsOnMethods = { "PrimaryTest"}) public void TestAfterChangelogTrim() throws Exception { // Test ECL after changelog trimming ECLAfterChangelogTrim(); } @Test(enabled=true, dependsOnMethods = { "PrimaryTest"}) public void TestAfterDomainIsRemoved() throws Exception { ECLAfterDomainIsRemoved(); } @Test(enabled=true, dependsOnMethods = { "PrimaryTest"}) public void TestWithAndWithoutControl() throws Exception { @@ -228,27 +198,6 @@ ECLCompatWriteReadAllOps(5); } @Test(enabled = true, dependsOnMethods = { "TestWithAndWithoutControl" }) public void TestWithIncludeAttributes() throws Exception { ECLIncludeAttributes(); } @Test(enabled=true, dependsOnMethods = { "PrimaryTest"}) public void TestChangeTimeHeartBeat() throws Exception { ChangeTimeHeartbeatTest(); } @Test(enabled=true, dependsOnMethods = { "PrimaryTest"}) public void TestOperationalAttributesNotVisibleOutsideRootDSE() throws Exception { // Test that ECL Operational, virtual attributes are not visible // outside rootDSE. Next test will test access in RootDSE. // This one checks in data. ECLOperationalAttributesFailTest(); } @Test(enabled=false, dependsOnMethods = { "PrimaryTest"}) public void PrimaryFullTest() throws Exception { @@ -281,10 +230,8 @@ // Test all types of ops. ECLAllOps(); // Do not clean the db for the next test // Test that ECL Operational, virtual attributes are not visible // outside rootDSE. Next test will test access in RootDSE. // This one checks in data. ECLOperationalAttributesFailTest(); // Test after this one will test access in RootDSE. This one checks in data. TestECLOperationalAttributesNotVisibleOutsideRootDSE(); // First and last should be ok whenever a request has been done or not // in compat mode. @@ -298,27 +245,20 @@ ECLRemoteNonEmpty(); } /** Persistent search with changesOnly request */ @Test(enabled=false, groups="slow", dependsOnMethods = { "PrimaryTest"}) public void FullTestPersistentSearchWithChangesOnlyRequest() throws Exception { // Persistent search with changesOnly request ECLPsearch(true, false); } /** Persistent search with init values request */ @Test(enabled=false, groups="slow", dependsOnMethods = { "PrimaryTest"}) public void FullTestPersistentSearchWithInitValuesRequest() throws Exception { // Persistent search with init values request ECLPsearch(false, false); } @Test(enabled=false, groups="slow", dependsOnMethods = { "PrimaryTest"}) public void FullTestSimultaneousPersistentSearches() throws Exception { // Simultaneous psearches ECLSimultaneousPsearches(); } // TODO:ECL Test SEARCH abandon and check everything shutdown and cleaned // TODO:ECL Test PSEARCH abandon and check everything shutdown and cleaned // TODO:ECL Test invalid DN in cookie returns UNWILLING + message @@ -412,7 +352,9 @@ assertEquals(ico.getErrorMessage().toMessage(), NOTE_SEARCH_CHANGELOG_INSUFFICIENT_PRIVILEGES.get()); } private void ECLIsNotASupportedSuffix() throws Exception /** No RSDomain created yet => RS only case => ECL is not a supported. */ @Test(enabled = true) public void TestECLIsNotASupportedSuffix() throws Exception { ECLCompatTestLimits(0,0, false); } @@ -472,11 +414,15 @@ } /** * Objectives * - Test that everything is ok with changes on 2 suffixes * Procedure * - From 1 remote ECL session, * - Test simple update to be received from 2 suffixes * Objectives: * <ul> * <li>Test that everything is ok with changes on 2 suffixes</li> * </ul> * Procedure: * <ul> * <li>From 1 remote ECL session,</li> * <li>Test simple update to be received from 2 suffixes</li> * </ul> */ private void ECLRemoteNonEmpty() throws Exception { @@ -560,7 +506,7 @@ debugInfo(tn, "Starting test\n\n"); // root entry returned searchOnChangelog("(objectclass=*)", Collections.<String> emptySet(), createControls(""), searchOnChangelog("(objectclass=*)", Collections.<String> emptySet(), createCookieControl(""), 1, ResultCode.SUCCESS, tn); debugInfo(tn, "Ending test successfully"); @@ -571,12 +517,11 @@ * @param cookie The provided cookie. * @return The built list of controls. */ private List<Control> createControls(String cookie) throws DirectoryException private List<Control> createCookieControl(String cookie) throws DirectoryException { final MultiDomainServerState state = new MultiDomainServerState(cookie); final List<Control> controls = new ArrayList<Control>(1); controls.add(new ExternalChangelogRequestControl(true, state)); return controls; final Control cookieControl = new ExternalChangelogRequestControl(true, state); return newList(cookieControl); } /** @@ -668,11 +613,16 @@ } /** * From embedded ECL Search ECL with 4 messages on 2 suffixes from 2 brokers * From embedded ECL Search ECL with 4 messages on 2 suffixes from 2 brokers. * Test with a mix of domains, a mix of DSes. */ private void ECLTwoDomains() throws Exception @Test(enabled=false, dependsOnMethods = { "PrimaryTest"}) public void TestECLWithTwoDomains() throws Exception { String tn = "ECLTwoDomains"; replicationServer.getChangelogDB().setPurgeDelay(0); String tn = "TestECLWithTwoDomains"; debugInfo(tn, "Starting test"); ReplicationBroker s1test = null; @@ -882,7 +832,7 @@ throws Exception { debugInfo(testName, "Search with cookie=[" + cookie + "] filter=[" + filterString + "]"); return searchOnChangelog(filterString, ALL_ATTRIBUTES, createControls(cookie), return searchOnChangelog(filterString, ALL_ATTRIBUTES, createCookieControl(cookie), expectedNbEntries, expectedResultCode, testName); } @@ -927,9 +877,10 @@ } /** Test ECL content after replication changelogDB trimming */ private void ECLAfterChangelogTrim() throws Exception @Test(enabled=false, dependsOnMethods = { "PrimaryTest"}) public void testECLAfterChangelogTrim() throws Exception { String testName = "ECLAfterChangelogTrim"; String testName = "testECLAfterChangelogTrim"; debugInfo(testName, "Starting test"); ReplicationBroker server01 = null; @@ -994,9 +945,10 @@ } /** Test ECL content after a domain has been removed. */ private void ECLAfterDomainIsRemoved() throws Exception @Test(enabled=true, dependsOnMethods = { "PrimaryTest"}) public void testECLAfterDomainIsRemoved() throws Exception { String testName = "ECLAfterDomainIsRemoved"; String testName = "testECLAfterDomainIsRemoved"; debugInfo(testName, "Starting test"); ReplicationBroker server01 = null; @@ -1133,7 +1085,7 @@ baseUUID, entry.getObjectClassAttribute(), entry.getAttributes(), new ArrayList<Attribute>()); Collections.<Attribute> emptyList()); server01.publish(addMsg); debugInfo(tn, " publishes " + addMsg.getCSN()); @@ -1250,31 +1202,27 @@ assertThat(actualDN).isEqualToIgnoringCase(expectedDN); } private List<String> getControls(String resultString) private List<String> getControls(String resultString) throws Exception { StringReader r=new StringReader(resultString); BufferedReader br=new BufferedReader(r); List<String> ctrlList = new ArrayList<String>(); try { while(true) { String s = br.readLine(); if(s == null) { break; } if(!s.startsWith("#")) { continue; } String[] a=s.split(": "); if(a.length != 2) { break; } ctrlList.add(a[1]); final BufferedReader br = new BufferedReader(new StringReader(resultString)); final List<String> ctrlList = new ArrayList<String>(); while (true) { final String s = br.readLine(); if (s == null) { break; } } catch (IOException e) { assertEquals(0, 1, e.getMessage()); if (!s.startsWith("#")) { continue; } final String[] a = s.split(": "); if (a.length != 2) { break; } ctrlList.add(a[1]); } return ctrlList; } @@ -1433,7 +1381,7 @@ // Creates cookie control String cookie = ""; List<Control> controls = createControls(cookie); List<Control> controls = createCookieControl(cookie); if (compatMode) { cookie = null; @@ -1575,7 +1523,7 @@ createSearchRequest("(targetDN=*directpsearch*,o=test)", null); debugInfo(tn, "ACI test : sending search"); message = new LDAPMessage(2, searchRequest, createControls("")); message = new LDAPMessage(2, searchRequest, createCookieControl("")); w.writeMessage(message); searchesDone=0; @@ -1654,11 +1602,12 @@ } /** * Test parallel simultaneous psearch with different filters. * Test parallel simultaneous persistent search with different filters. */ private void ECLSimultaneousPsearches() throws Exception @Test(enabled = false, groups = "slow", dependsOnMethods = { "PrimaryTest" }) public void FullTestSimultaneousPersistentSearches() throws Exception { String tn = "ECLSimultaneousPsearches"; String tn = "FullTestSimultaneousPersistentSearches"; debugInfo(tn, "Starting test \n\n"); Socket s1 = null, s2 = null, s3 = null; ReplicationBroker server01 = null; @@ -1724,7 +1673,7 @@ // Creates cookie control String cookie = ""; List<Control> controls = createControls(cookie); List<Control> controls = createCookieControl(cookie); if (compatMode) { cookie = null; @@ -2163,9 +2112,10 @@ /** * FIXME this test actually tests nothing: there are no asserts. */ private void ChangeTimeHeartbeatTest() throws Exception @Test(enabled = true, dependsOnMethods = { "PrimaryTest" }) public void testChangeTimeHeartbeat() throws Exception { String tn = "ChangeTimeHeartbeatTest"; String tn = "testChangeTimeHeartbeat"; debugInfo(tn, "Starting test"); ReplicationBroker s1test = null; ReplicationBroker s2test = null; @@ -2292,7 +2242,7 @@ baseUUID, entry.getObjectClassAttribute(), entry.getAttributes(), new ArrayList<Attribute>()); Collections.<Attribute> emptyList()); server01.publish(addMsg); debugInfo(tn, " publishes " + addMsg.getCSN()); @@ -2604,9 +2554,13 @@ debugInfo(tn, "Ending test with success"); } private void ECLOperationalAttributesFailTest() throws Exception /** * Test that ECL Operational, virtual attributes are not visible outside rootDSE. */ @Test(enabled = true, dependsOnMethods = { "PrimaryTest" }) public void TestECLOperationalAttributesNotVisibleOutsideRootDSE() throws Exception { String tn = "ECLOperationalAttributesFailTest"; String tn = "TestECLOperationalAttributesNotVisibleOutsideRootDSE"; // The goal is to verify that the Changelog attributes are not // available in other entries. We u debugInfo(tn, "Starting test \n\n"); @@ -2623,9 +2577,7 @@ 0, // Time limit false, // Types only "(objectclass=*)", attributes, NO_CONTROL, null); attributes); waitOpResult(searchOp, ResultCode.SUCCESS); final List<SearchResultEntry> entries = searchOp.getSearchEntries(); @@ -2721,9 +2673,7 @@ 0, // Time limit false, // Types only "(objectclass=*)", attributes, NO_CONTROL, null); attributes); waitOpResult(searchOp, ResultCode.SUCCESS); return searchOp; } @@ -2774,11 +2724,12 @@ } /** * Test ECl entry attributes, and there configuration. * Test ECl entry attributes, and their configuration. */ private void ECLIncludeAttributes() throws Exception @Test(enabled = true, dependsOnMethods = { "TestWithAndWithoutControl" }) public void TestECLWithIncludeAttributes() throws Exception { String tn = "ECLIncludeAttributes"; String tn = "TestECLWithIncludeAttributes"; debugInfo(tn, "Starting test\n\n"); final String backendId3 = "test3"; @@ -2953,9 +2904,7 @@ private List<Modification> createMods(String attributeName, String valueString) { Attribute attr = Attributes.create(attributeName, valueString); List<Modification> mods = new ArrayList<Modification>(); mods.add(new Modification(ModificationType.REPLACE, attr)); return mods; return newList(new Modification(ModificationType.REPLACE, attr)); } private Entry parseIncludedAttributes(SearchResultEntry resultEntry, @@ -2970,8 +2919,7 @@ return TestCaseUtils.makeEntry(ldif); } private void waitOpResult(Operation operation, ResultCode expectedResult) throws Exception private void waitOpResult(Operation operation, ResultCode expectedResult) throws Exception { int i = 0; while (operation.getResultCode() == ResultCode.UNDEFINED