opends/src/guitools/org/opends/guitools/controlpanel/browser/BrowserController.java
@@ -89,20 +89,20 @@ /** * The mask used to display the number of ACIs or not. */ public final static int DISPLAY_ACI_COUNT = 0x01; private static final int DISPLAY_ACI_COUNT = 0x01; /** * The list of attributes that are used to sort the entries (if the sorting * option is used). */ public static final String[] SORT_ATTRIBUTES = {"cn", "givenname", "o", "ou", "sn", "uid"}; private static final String[] SORT_ATTRIBUTES = { "cn", "givenname", "o", "ou", "sn", "uid" }; /** * This is a key value. It is used to specify that the attribute that should * be used to display the entry is the RDN attribute. */ public static final String RDN_ATTRIBUTE = "rdn attribute"; private static final String RDN_ATTRIBUTE = "rdn attribute"; /** * The filter used to retrieve all the entries. @@ -110,12 +110,12 @@ public static final String ALL_OBJECTS_FILTER = "(|(objectClass=*)(objectClass=ldapsubentry))"; private JTree tree; private DefaultTreeModel treeModel; private RootNode rootNode; private final JTree tree; private final DefaultTreeModel treeModel; private final RootNode rootNode; private int displayFlags; private String displayAttribute; private boolean showAttributeName; private final boolean showAttributeName; private InitialLdapContext ctxConfiguration; private InitialLdapContext ctxUserData; private boolean followReferrals; @@ -127,12 +127,12 @@ private NumSubordinateHacker numSubordinateHacker; private int queueTotalSize; private int maxChildren = 0; private Collection<BrowserEventListener> listeners = private final Collection<BrowserEventListener> listeners = new ArrayList<BrowserEventListener>(); private LDAPConnectionPool connectionPool; private IconPool iconPool; private final LDAPConnectionPool connectionPool; private final IconPool iconPool; private NodeSearcherQueue refreshQueue; private final NodeSearcherQueue refreshQueue; private String filter; @@ -159,6 +159,7 @@ tree.addTreeExpansionListener(this); tree.setCellRenderer(new BrowserCellRenderer()); displayFlags = DISPLAY_ACI_COUNT; showAttributeName = false; displayAttribute = RDN_ATTRIBUTE; followReferrals = false; sorted = false; @@ -260,17 +261,16 @@ } /** * Tells wether the given suffix is in the tree or not. * Tells whether the given suffix is in the tree or not. * @param suffixDn the DN of the suffix to be analyzed. * @return <CODE>true</CODE> if the provided String is the DN of a suffix * and <CODE>false</CODE> otherwise. * @throws IllegalArgumentException if a node with the given dn exists but * is not a suffix node. */ public boolean hasSuffix(String suffixDn) throws IllegalArgumentException public boolean hasSuffix(String suffixDn) throws IllegalArgumentException { return (findSuffixNode(suffixDn, rootNode) != null); return findSuffixNode(suffixDn, rootNode) != null; } /** @@ -328,28 +328,6 @@ return new TreePath(treeModel.getPathToRoot(newNode)); } /** * Remove the suffix from this controller. * The controller updates the JTree and returns the TreePath * of the parent node. * @param suffixDn the DN of the suffix to be removed. * @return the TreePath of the parent node of the removed node. */ public TreePath removeSuffix(String suffixDn) { TreePath result = null; BasicNode node = findSuffixNode(suffixDn, rootNode); TreeNode parentNode = node.getParent(); /* If the parent is null... the node is no longer in the tree */ if (parentNode != null) { removeOneNode(node); result = new TreePath(treeModel.getPathToRoot(parentNode)); } return result; } /** * Remove all the suffixes. * The controller removes all the nodes from the JTree except the root. @@ -403,18 +381,6 @@ } /** * Says wether to show the attribute name or not. * This routine collapses the JTree and invokes startRefresh(). * @param showAttributeName whether to show the attribute name or not. */ public void showAttributeName(boolean showAttributeName) { this.showAttributeName = showAttributeName; stopRefresh(); removeAllChildNodes(rootNode, true /* Keep suffixes */); startRefresh(null); } /** * Says wether we are showing the attribute name or not. * @return <CODE>true</CODE> if we are showing the attribute name and * <CODE>false</CODE> otherwise. @@ -586,16 +552,6 @@ listeners.add(l); } /** * Remove a BrowserEventListener from this controller. * @param l the listener to be removed. */ public void removeBrowserEventListener(BrowserEventListener l) { listeners.remove(l); } /** * Notify this controller that an entry has been added. * The controller adds a new node in the JTree and starts refreshing this new @@ -635,19 +591,18 @@ * @return the tree path associated with the parent of the deleted node. */ public TreePath notifyEntryDeleted(BrowserNodeInfo nodeInfo) { TreePath result = null; BasicNode node = nodeInfo.getNode(); if (node == rootNode) { throw new IllegalArgumentException("Root node cannot be removed"); } TreeNode parentNode = node.getParent(); /* If the parent is null... the node is no longer in the tree */ final TreeNode parentNode = node.getParent(); if (parentNode != null) { removeOneNode(node); result = new TreePath(treeModel.getPathToRoot(parentNode)); return new TreePath(treeModel.getPathToRoot(parentNode)); } return result; return null; } @@ -663,50 +618,10 @@ } /** * Notify this controller that a child entry has changed. * The controller has to refresh the corresponding node and (if necessary) * itself. * @param nodeInfo the parent of the node that changed. * @param dn the DN of the entry that changed. */ public void notifyChildEntryChanged(BrowserNodeInfo nodeInfo, String dn) { BasicNode node = nodeInfo.getNode(); startRefreshNode(node, null, true); } /** * Notify this controller that a child entry has been added. * The controller has to refresh the corresponding node and (if necessary) * itself. * @param nodeInfo the parent of the node that was added. * @param dn the DN of the entry that was added. */ public void notifyChildEntryAdded(BrowserNodeInfo nodeInfo, String dn) { BasicNode node = nodeInfo.getNode(); startRefreshNode(node, null, true); } /** * Notify this controller that a child entry has been deleted. * The controller has to refresh the corresponding node and (if necessary) * itself. * @param nodeInfo the parent of the node that was deleted. * @param dn the DN of the entry that was deleted. */ public void notifyChildEntryDeleted(BrowserNodeInfo nodeInfo, String dn) { BasicNode node = nodeInfo.getNode(); if (node.getParent() != null) { startRefreshNode((BasicNode) node.getParent(), null, true); } else { startRefreshNode(node, null, true); } } /** * Notify this controller that authentication data have changed in the * connection pool. */ @Override public void notifyAuthDataChanged() { notifyAuthDataChanged(null); } @@ -718,7 +633,7 @@ * url. * @param url the URL of the connection that changed. */ public void notifyAuthDataChanged(LDAPURL url) { private void notifyAuthDataChanged(LDAPURL url) { // TODO: temporary implementation // we should refresh only nodes : // - whose URL matches 'url' @@ -730,7 +645,7 @@ /** * Start a refresh from the specified node. * If some refresh are on-going on descendent nodes, they are stopped. * If some refresh are on-going on descendant nodes, they are stopped. * If nodeInfo is null, refresh is started from the root. * @param nodeInfo the node to be refreshed. */ @@ -746,35 +661,15 @@ startRefreshNode(node, null, true); } /** * Equivalent to startRefresh(null). */ public void startRefresh() { startRefresh(null); } /** * Stop the current refreshing. * Nodes being expanded are collapsed. */ public void stopRefresh() { private void stopRefresh() { stopRefreshNode(rootNode); // TODO: refresh must be stopped in a clean state. } /** * Shutdown the controller : all the backgroup threads are stopped. * After this call, the controller is no longer usable. */ public void shutDown() { tree.removeTreeExpansionListener(this); refreshQueue.shutdown(); connectionPool.flush(); } /** * Start refreshing the whole tree from the specified node. * We queue a refresh which: @@ -784,7 +679,7 @@ * @param localEntry the local entry corresponding to the node. * @param recursive whether the refresh must be executed recursively or not. */ void startRefreshNode(BasicNode node, SearchResult localEntry, private void startRefreshNode(BasicNode node, SearchResult localEntry, boolean recursive) { if (node == rootNode) { // For the root node, readBaseEntry is meaningless. @@ -803,7 +698,7 @@ // The task does not *see* suffixes. // So we need to propagate the refresh on // the sub-suffixes if any. if (recursive && (node instanceof SuffixNode)) { if (recursive && node instanceof SuffixNode) { Enumeration<?> e = node.children(); while (e.hasMoreElements()) { BasicNode child = (BasicNode)e.nextElement(); @@ -824,7 +719,7 @@ * root node. * @param node the node where the refresh must stop. */ void stopRefreshNode(BasicNode node) { private void stopRefreshNode(BasicNode node) { if (node == rootNode) { refreshQueue.cancelAll(); } @@ -844,11 +739,11 @@ * Call startRefreshNode() on each referral node accessible from parentNode. * @param parentNode the parent node. */ void startRefreshReferralNodes(BasicNode parentNode) { private void startRefreshReferralNodes(BasicNode parentNode) { Enumeration<?> e = parentNode.children(); while (e.hasMoreElements()) { BasicNode child = (BasicNode)e.nextElement(); if ((child.getReferral() != null) || (child.getRemoteUrl() != null)) { if (child.getReferral() != null || child.getRemoteUrl() != null) { startRefreshNode(child, null, true); } else { @@ -866,10 +761,10 @@ * @param parentNode the parent node. * @param keepSuffixes whether the suffixes should be kept or not. */ void removeAllChildNodes(BasicNode parentNode, boolean keepSuffixes) { private void removeAllChildNodes(BasicNode parentNode, boolean keepSuffixes) { for (int i = parentNode.getChildCount() - 1; i >= 0; i--) { BasicNode child = (BasicNode)parentNode.getChildAt(i); if ((child instanceof SuffixNode) && keepSuffixes) { if (child instanceof SuffixNode && keepSuffixes) { removeAllChildNodes(child, true); child.setRefreshNeededOnExpansion(true); } @@ -885,6 +780,7 @@ * if it needs it (to search the children for instance). * @param event the tree expansion event. */ @Override public void treeExpanded(TreeExpansionEvent event) { if (!automaticallyExpandedNode) { @@ -904,6 +800,7 @@ * tasks on it are canceled. * @param event the tree collapse event. */ @Override public void treeCollapsed(TreeExpansionEvent event) { Object node = event.getPath().getLastPathComponent(); if (!(node instanceof RootNode)) { @@ -1054,32 +951,19 @@ * @throws NamingException if there is an error retrieving the connection. * @return the LDAP connection to reading the base entry of a node. */ InitialLdapContext findConnectionForLocalEntry(BasicNode node, boolean isConfigurationNode) throws NamingException { InitialLdapContext result; private InitialLdapContext findConnectionForLocalEntry(BasicNode node, boolean isConfigurationNode) throws NamingException { if (node == rootNode) { result = ctxConfiguration; return ctxConfiguration; } else { BasicNode parent = (BasicNode)node.getParent(); if ((parent != null) && (parent != rootNode)) { result = findConnectionForDisplayedEntry(parent, isConfigurationNode); } else { if (isConfigurationNode) { result = ctxConfiguration; } else { result = ctxUserData; } } final BasicNode parent = (BasicNode) node.getParent(); if (parent != null && parent != rootNode) { return findConnectionForDisplayedEntry(parent, isConfigurationNode); } return result; return isConfigurationNode ? ctxConfiguration : ctxUserData; } /** @@ -1090,7 +974,6 @@ */ public boolean isConfigurationNode(BasicNode node) { boolean isConfigurationNode = false; if (node instanceof SuffixNode) { String dn = node.getDN(); @@ -1103,12 +986,12 @@ Utilities.areDnsEqual(dn, ConfigConstants.DN_BACKUP_ROOT) || Utilities.areDnsEqual(dn, ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT)) { isConfigurationNode = true; return true; } } else if (node instanceof RootNode) { isConfigurationNode = true; return true; } else { @@ -1116,7 +999,7 @@ return isConfigurationNode(parentNode); } return isConfigurationNode; return false; } /** @@ -1140,18 +1023,13 @@ * @return the LDAP connection to search the displayed entry. * @throws NamingException if there is an error retrieving the connection. */ InitialLdapContext findConnectionForDisplayedEntry(BasicNode node, boolean isConfigurationNode) throws NamingException { InitialLdapContext result; if (followReferrals && (node.getRemoteUrl() != null)) private InitialLdapContext findConnectionForDisplayedEntry(BasicNode node, boolean isConfigurationNode) throws NamingException { if (followReferrals && node.getRemoteUrl() != null) { result = connectionPool.getConnection(node.getRemoteUrl()); return connectionPool.getConnection(node.getRemoteUrl()); } else { result = findConnectionForLocalEntry(node, isConfigurationNode); } return result; return findConnectionForLocalEntry(node, isConfigurationNode); } @@ -1162,8 +1040,7 @@ * @param ctx the connection to be released. */ void releaseLDAPConnection(InitialLdapContext ctx) { if ((ctx != this.ctxConfiguration) && (ctx != this.ctxUserData)) if (ctx != this.ctxConfiguration && ctx != this.ctxUserData) { // Thus it comes from the connection pool connectionPool.releaseConnection(ctx); @@ -1177,20 +1054,16 @@ * @return the local entry URL for a given node. */ LDAPURL findUrlForLocalEntry(BasicNode node) { LDAPURL result; if (node == rootNode) { result = LDAPConnectionPool.makeLDAPUrl(ctxConfiguration, ""); return LDAPConnectionPool.makeLDAPUrl(ctxConfiguration, ""); } else { BasicNode parent = (BasicNode)node.getParent(); if (parent != null) { LDAPURL parentUrl = findUrlForDisplayedEntry(parent); result = LDAPConnectionPool.makeLDAPUrl(parentUrl, node.getDN()); } else { result = LDAPConnectionPool.makeLDAPUrl(ctxConfiguration, node.getDN()); } final BasicNode parent = (BasicNode) node.getParent(); if (parent != null) { final LDAPURL parentUrl = findUrlForDisplayedEntry(parent); return LDAPConnectionPool.makeLDAPUrl(parentUrl, node.getDN()); } return result; return LDAPConnectionPool.makeLDAPUrl(ctxConfiguration, node.getDN()); } @@ -1199,15 +1072,12 @@ * @param node the node. * @return the displayed entry URL for a given node. */ LDAPURL findUrlForDisplayedEntry(BasicNode node) { LDAPURL result; if (followReferrals && (node.getRemoteUrl() != null)) { result = node.getRemoteUrl(); private LDAPURL findUrlForDisplayedEntry(BasicNode node) { if (followReferrals && node.getRemoteUrl() != null) { return node.getRemoteUrl(); } else { result = findUrlForLocalEntry(node); } return result; return findUrlForLocalEntry(node); } @@ -1221,15 +1091,10 @@ * @return the DN to use for searching children of a given node. */ String findBaseDNForChildEntries(BasicNode node) { String result; if (followReferrals && (node.getRemoteUrl() != null)) { result = node.getRemoteUrl().getRawBaseDN(); if (followReferrals && node.getRemoteUrl() != null) { return node.getRemoteUrl().getRawBaseDN(); } else { result = node.getDN(); } return result; return node.getDN(); } @@ -1240,24 +1105,20 @@ * @return <CODE>true</CODE> if the node displays a remote entry and * <CODE>false</CODE> otherwise. */ boolean isDisplayedEntryRemote(BasicNode node) { boolean result = false; private boolean isDisplayedEntryRemote(BasicNode node) { if (followReferrals) { if (node == rootNode) { result = false; return false; } else if (node.getRemoteUrl() != null) { result = true; if (node.getRemoteUrl() != null) { return true; } else { BasicNode parent = (BasicNode)node.getParent(); if (parent != null) { result = isDisplayedEntryRemote(parent); } final BasicNode parent = (BasicNode)node.getParent(); if (parent != null) { return isDisplayedEntryRemote(parent); } } return result; return false; } @@ -1275,30 +1136,11 @@ if ((displayFlags & DISPLAY_ACI_COUNT) != 0) { v.add("aci"); } if (!displayAttribute.equals(RDN_ATTRIBUTE)) { if (!RDN_ATTRIBUTE.equals(displayAttribute)) { v.add(displayAttribute); } String[] result = new String[v.size()]; v.toArray(result); return result; } /** * Returns the list of attributes for the green search. * @return the list of attributes for the green search. */ String[] getAttrsForGreenSearch() { if (!displayAttribute.equals(RDN_ATTRIBUTE)) { return new String[] { "aci", displayAttribute}; } else { return new String[] { "aci" }; } return v.toArray(new String[v.size()]); } /** @@ -1306,7 +1148,7 @@ * @return the list of attributes for the black search. */ String[] getAttrsForBlackSearch() { if (!displayAttribute.equals(RDN_ATTRIBUTE)) { if (!RDN_ATTRIBUTE.equals(displayAttribute)) { return new String[] { "objectClass", "numsubordinates", @@ -1339,7 +1181,7 @@ * Returns the request controls to search user data. * @return the request controls to search user data. */ Control[] getRequestControls() private Control[] getRequestControls() { Control ctls[]; if (followReferrals) @@ -1378,7 +1220,7 @@ * Returns the request controls to search configuration data. * @return the request controls to search configuration data. */ Control[] getConfigurationRequestControls() private Control[] getConfigurationRequestControls() { return getRequestControls(); } @@ -1430,8 +1272,8 @@ // tree. // Except when it's due a to referral resolution: we keep the node // in order the user can fix the referral. if (isNameNotFoundException(task.getException()) && (oldState != NodeRefresher.State.SOLVING_REFERRAL)) { if (isNameNotFoundException(task.getException()) && oldState != NodeRefresher.State.SOLVING_REFERRAL) { removeOneNode(node); } else { @@ -1460,8 +1302,8 @@ nodeChanged = updateNodeRendering(node, task.getDisplayedEntry()); } } else if ((newState == NodeRefresher.State.CANCELLED) && (newState == NodeRefresher.State.INTERRUPTED)) { else if (newState == NodeRefresher.State.CANCELLED && newState == NodeRefresher.State.INTERRUPTED) { // Let's collapse task.getNode() tree.collapsePath(new TreePath(treeModel.getPathToRoot(node))); @@ -1470,8 +1312,8 @@ } else { if ((oldState != NodeRefresher.State.SEARCHING_CHILDREN) && (newState == NodeRefresher.State.SEARCHING_CHILDREN)) { if (oldState != NodeRefresher.State.SEARCHING_CHILDREN && newState == NodeRefresher.State.SEARCHING_CHILDREN) { // The children search is going to start if (canDoDifferentialUpdate(task)) { Enumeration<?> e = node.children(); @@ -1538,11 +1380,9 @@ } } if (newState == NodeRefresher.State.FINISHED) { if (node.getError() != null) { node.setError(null); nodeChanged = updateNodeRendering(node, task.getDisplayedEntry()); } if (newState == NodeRefresher.State.FINISHED && node.getError() != null) { node.setError(null); nodeChanged = updateNodeRendering(node, task.getDisplayedEntry()); } } @@ -1551,10 +1391,9 @@ treeModel.nodeChanged(task.getNode()); } if (node.isLeaf() && (node.getChildCount() >= 1)) { if (node.isLeaf() && node.getChildCount() >= 1) { throw new RuntimeException("Inconsistent node: " + node.getDN()); } } @@ -1570,8 +1409,8 @@ final NodeRefresher.State oldState, final NodeRefresher.State newState) throws InterruptedException { Runnable r = new Runnable() { @Override public void run() { try { refreshTaskDidProgress(task, oldState, newState); @@ -1635,13 +1474,13 @@ child = new BasicNode(entry.getName()); parent.insert(child, index); updateNodeRendering(child, entry); insertIndex.add(new Integer(index)); insertIndex.add(Integer.valueOf(index)); // System.out.println("Inserted " + child.getDN() + " at " + index); } else { // Else we update the existing one child = (BasicNode)parent.getChildAt(index); if (updateNodeRendering(child, entry)) { changedIndex.add(new Integer(index)); changedIndex.add(Integer.valueOf(index)); } // The node is no longer obsolete child.setObsolete(false); @@ -1649,24 +1488,13 @@ // NUMSUBORDINATE HACK // Let's see if child has subordinates or not. // Thanks to slapd, we cannot always trust the // numSubOrdinates attribute. If the child entry's DN // is found in the hacker's list, then we ignore // Thanks to slapd, we cannot always trust the numSubOrdinates attribute. // If the child entry's DN is found in the hacker's list, then we ignore // the numSubordinate attribute... :(( boolean hasNoSubOrdinates; if (!child.hasSubOrdinates() && dontTrust) { LDAPURL childUrl = findUrlForDisplayedEntry(child); if (numSubordinateHacker.contains(childUrl)) { // The numSubOrdinates we have is unreliable. // child may potentially have subordinates. hasNoSubOrdinates = false; // System.out.println("numSubordinates of " + childUrl + // " is not reliable"); } else { // We can trust this 0 value hasNoSubOrdinates = true; } hasNoSubOrdinates = !numSubordinateHacker.contains(childUrl); } else { hasNoSubOrdinates = !child.hasSubOrdinates(); @@ -1675,7 +1503,7 @@ // Propagate the refresh // Note: logically we should unconditionaly call: // Note: logically we should unconditionally call: // startRefreshNode(child, false, true); // // However doing that saturates refreshQueue @@ -1691,9 +1519,9 @@ // node had children (in the tree). In this case // we force the refresh. See bug 5015115 // if (!hasNoSubOrdinates || (child.getReferral() != null) || (child.getChildCount() > 0)) { if (!hasNoSubOrdinates || child.getReferral() != null || child.getChildCount() > 0) { startRefreshNode(child, entry, true); } } @@ -1711,16 +1539,14 @@ /** * Tells wheter a differential update can be made in the provided task. * Tells whether a differential update can be made in the provided task. * @param task the task. * @return <CODE>true</CODE> if a differential update can be made and * <CODE>false</CODE> otherwise. */ private boolean canDoDifferentialUpdate(NodeRefresher task) { return ( (task.getNode().getChildCount() >= 1) && (task.getNode().getNumSubOrdinates() <= 100) ); return task.getNode().getChildCount() >= 1 && task.getNode().getNumSubOrdinates() <= 100; } @@ -1736,82 +1562,25 @@ if (entry != null) { // Get the numsubordinates node.setNumSubOrdinates(getNumSubOrdinates(entry)); if (node.getNumSubOrdinates() > 0) { node.setHasSubOrdinates(true); } else { // Calculate based also in the hasSubordinates attribute node.setHasSubOrdinates(getHasSubOrdinates(entry)); } node.setHasSubOrdinates( node.getNumSubOrdinates() > 0 || getHasSubOrdinates(entry)); node.setReferral(getReferral(entry)); Set<String> ocValues = ConnectionUtils.getValues(entry, "objectClass"); if (ocValues != null) { String[] array = new String[ocValues.size()]; ocValues.toArray(array); node.setObjectClassValues(array); node.setObjectClassValues(ocValues.toArray(new String[ocValues.size()])); } } // Get the aci count int aciCount; if (((displayFlags & DISPLAY_ACI_COUNT) != 0) && (entry != null)) { Set<String> aciValues = ConnectionUtils.getValues(entry, "aci"); if (aciValues != null) { aciCount = aciValues.size(); } else { aciCount = 0; } } else { aciCount = 0; } // Select the icon according the objectClass,... int modifiers = 0; if (node.isLeaf() && !node.hasSubOrdinates()) { modifiers |= IconPool.MODIFIER_LEAF; } if (node.getReferral() != null) { modifiers |= IconPool.MODIFIER_REFERRAL; } if (node.getError() != null) { if (node.getError().getException() != null) { LOG.log(Level.SEVERE, "node has error: "+node.getError().getException(), node.getError().getException()); } modifiers |= IconPool.MODIFIER_ERROR; } SortedSet<String> objectClasses = new TreeSet<String>(); if (entry != null) { Set<String> ocs = ConnectionUtils.getValues(entry, "objectClass"); if (ocs != null) { objectClasses.addAll(ocs); } } Icon newIcon; if (node instanceof SuffixNode) { newIcon = iconPool.getSuffixIcon(); } else { newIcon = iconPool.getIcon(objectClasses, modifiers); } int aciCount = getAciCount(entry); Icon newIcon = getNewIcon(node, entry); // Construct the icon text according the dn, the aci count... StringBuilder sb2 = new StringBuilder(); if (aciCount >= 1) { sb2.append(String.valueOf(aciCount)); if (aciCount == 1) { sb2.append(" aci"); } else { sb2.append(" acis"); sb2.append(aciCount); sb2.append(" aci"); if (aciCount != 1) { sb2.append("s"); } } @@ -1822,8 +1591,7 @@ } } else { boolean useRdn = true; if (!displayAttribute.equals(RDN_ATTRIBUTE) && (entry != null)) { if (!RDN_ATTRIBUTE.equals(displayAttribute) && entry != null) { String value = ConnectionUtils.getFirstValue(entry,displayAttribute); if (value != null) { if (showAttributeName) { @@ -1833,9 +1601,10 @@ useRdn = false; } } if (useRdn) { String rdn; if (followReferrals && (node.getRemoteUrl() != null)) { if (followReferrals && node.getRemoteUrl() != null) { if (showAttributeName) { rdn = node.getRemoteRDNWithAttributeName(); } else { @@ -1866,21 +1635,66 @@ } // Determine if the rendering needs to be updated boolean changed = ( (node.getIcon() != newIcon) || (node.getDisplayName() != newDisplayName) || (node.getFontStyle() != newStyle) ); boolean changed = node.getIcon() != newIcon || node.getDisplayName() != newDisplayName || node.getFontStyle() != newStyle; if (changed) { node.setIcon(newIcon); node.setDisplayName(newDisplayName); node.setFontStyle(newStyle); } return changed; } private int getAciCount(SearchResult entry) throws NamingException { if ((displayFlags & DISPLAY_ACI_COUNT) != 0 && entry != null) { Set<String> aciValues = ConnectionUtils.getValues(entry, "aci"); if (aciValues != null) { return aciValues.size(); } } return 0; } private Icon getNewIcon(BasicNode node, SearchResult entry) throws NamingException { // Select the icon according the objectClass,... int modifiers = 0; if (node.isLeaf() && !node.hasSubOrdinates()) { modifiers |= IconPool.MODIFIER_LEAF; } if (node.getReferral() != null) { modifiers |= IconPool.MODIFIER_REFERRAL; } if (node.getError() != null) { final Exception ex = node.getError().getException(); if (ex != null) { LOG.log(Level.SEVERE, "node has error: " + ex, ex); } modifiers |= IconPool.MODIFIER_ERROR; } SortedSet<String> objectClasses = new TreeSet<String>(); if (entry != null) { Set<String> ocs = ConnectionUtils.getValues(entry, "objectClass"); if (ocs != null) { objectClasses.addAll(ocs); } } if (node instanceof SuffixNode) { return iconPool.getSuffixIcon(); } return iconPool.getIcon(objectClasses, modifiers); } /** * Find a child node matching a given DN. @@ -1895,14 +1709,13 @@ public int findChildNode(BasicNode parent, String childDn) { int childCount = parent.getChildCount(); int i = 0; while ((i < childCount) && !childDn.equals(((BasicNode)parent.getChildAt(i)).getDN())) { while (i < childCount && !childDn.equals(((BasicNode)parent.getChildAt(i)).getDN())) { i++; } if (i >= childCount) { // Not found i = -(childCount + 1); } return i; } @@ -1936,10 +1749,10 @@ newSize = newSize - 1; } if (newSize != queueTotalSize) { if ((queueTotalSize == 0) && (newSize >= 1)) { if (queueTotalSize == 0 && newSize >= 1) { fireEvent(BrowserEvent.Type.UPDATE_START); } else if ((queueTotalSize >= 1) && (newSize == 0)) { else if (queueTotalSize >= 1 && newSize == 0) { fireEvent(BrowserEvent.Type.UPDATE_END); } queueTotalSize = newSize; @@ -1985,46 +1798,44 @@ * @throws IllegalArgumentException if a node with the given dn exists but * is not a suffix node. */ SuffixNode findSuffixNode(String suffixDn, SuffixNode suffixNode) throws IllegalArgumentException private SuffixNode findSuffixNode(String suffixDn, SuffixNode suffixNode) throws IllegalArgumentException { SuffixNode result; if (Utilities.areDnsEqual(suffixNode.getDN(), suffixDn)) { result = suffixNode; } else { int childCount = suffixNode.getChildCount(); if (childCount == 0) { result = null; } else { BasicNode child; int i = 0; boolean found = false; do { child = (BasicNode)suffixNode.getChildAt(i) ; if (Utilities.areDnsEqual(child.getDN(), suffixDn)) { found = true; } i++; } while ((i < childCount) && !found); if (!found) { result = null; } else if (child instanceof SuffixNode) { result = (SuffixNode)child; } else { // A node matches suffixDn however it's not a suffix node. // There's a bug in the caller. throw new IllegalArgumentException(suffixDn +" is not a suffix node"); } } return suffixNode; } return result; int childCount = suffixNode.getChildCount(); if (childCount == 0) { return null; } BasicNode child; int i = 0; boolean found = false; do { child = (BasicNode) suffixNode.getChildAt(i); if (Utilities.areDnsEqual(child.getDN(), suffixDn)) { found = true; } i++; } while (i < childCount && !found); if (!found) { return null; } if (child instanceof SuffixNode) { return (SuffixNode) child; } // A node matches suffixDn however it's not a suffix node. // There's a bug in the caller. throw new IllegalArgumentException(suffixDn + " is not a suffix node"); } @@ -2036,15 +1847,7 @@ * NameNotFoundException. */ private boolean isNameNotFoundException(Object x) { boolean result; if ((x != null) && (x instanceof NameNotFoundException)) { result = true; } else { result = false; } return result; return x instanceof NameNotFoundException; } @@ -2054,28 +1857,12 @@ * If numsubordinates is not present, returns 0. * @param entry the entry to analyze. * @throws NamingException if an error occurs. * @return the value of the numsubordinate attribute. 0 if the attribute * @return the value of the numsubordinates attribute. 0 if the attribute * could not be found. */ public static int getNumSubOrdinates(SearchResult entry) throws NamingException private static int getNumSubOrdinates(SearchResult entry) throws NamingException { int result; String v = ConnectionUtils.getFirstValue(entry, "numsubordinates"); if (v == null) { result = 0; } else { try { result = Integer.parseInt(v); } catch(NumberFormatException x) { result = 0; } } return result; return toInt(ConnectionUtils.getFirstValue(entry, "numsubordinates")); } /** @@ -2090,49 +1877,46 @@ public static boolean getHasSubOrdinates(SearchResult entry) throws NamingException { boolean result; String v = ConnectionUtils.getFirstValue(entry, "hassubordinates"); if (v == null) { result = getNumSubOrdinates(entry) > 0; if (v != null) { return "true".equalsIgnoreCase(v); } else { result = "true".equalsIgnoreCase(v); } return result; return getNumSubOrdinates(entry) > 0; } /** * Get the value of the numsubordinates attribute. * If numsubordinates is not present, returns 0. * @param entry the entry to analyze. * @return the value of the numsubordinate attribute. 0 if the attribute * @return the value of the numsubordinates attribute. 0 if the attribute * could not be found. */ public static int getNumSubOrdinates(CustomSearchResult entry) private static int getNumSubOrdinates(CustomSearchResult entry) { int result; List<Object> vs = entry.getAttributeValues("numsubordinates"); String v = null; if (vs != null && !vs.isEmpty()) { v = vs.get(0).toString(); } if (v == null) { result = 0; } else { try { result = Integer.parseInt(v); } catch(NumberFormatException x) { result = 0; } } return toInt(v); } return result; private static int toInt(String v) { if (v == null) { return 0; } try { return Integer.parseInt(v); } catch (NumberFormatException x) { return 0; } } /** @@ -2145,22 +1929,17 @@ */ public static boolean getHasSubOrdinates(CustomSearchResult entry) { boolean result; List<Object> vs = entry.getAttributeValues("hassubordinates"); String v = null; if (vs != null && !vs.isEmpty()) { v = vs.get(0).toString(); } if (v == null) { result = getNumSubOrdinates(entry) > 0; if (v != null) { return "true".equalsIgnoreCase(v); } else { result = "true".equalsIgnoreCase(v); } return result; return getNumSubOrdinates(entry) > 0; } @@ -2180,7 +1959,7 @@ { for (String value : values) { boolean isReferral = value.equalsIgnoreCase("referral"); boolean isReferral = "referral".equalsIgnoreCase(value); if (isReferral) { Set<String> refValues = ConnectionUtils.getValues(entry, "ref"); @@ -2231,7 +2010,7 @@ * @param v the Collection of Integer objects. * @return an array of int from a Collection of Integer objects. */ static int[] intArrayFromCollection(Collection<Integer> v) { private static int[] intArrayFromCollection(Collection<Integer> v) { int[] result = new int[v.size()]; int i = 0; for (Integer value : v) @@ -2242,29 +2021,6 @@ return result; } /** * Returns an array of SearchResult from a Collection of SearchResult objects. * @param v the Collection of SearchResult objects. * @return an array of SearchResult from a Collection of SearchResult objects. */ static SearchResult[] entryArrayFromCollection(Collection<SearchResult> v) { SearchResult[] result = new SearchResult[v.size()]; v.toArray(result); return result; } /** * Returns an array of BasicNode from a Collection of BasicNode objects. * @param v the Collection of BasicNode objects. * @return an array of BasicNode from a Collection of BasicNode objects. */ static BasicNode[] nodeArrayFromCollection(Collection<BasicNode> v) { BasicNode[] result = new BasicNode[v.size()]; v.toArray(result); return result; } /** * For debugging purpose: allows to switch easily @@ -2273,8 +2029,7 @@ * @param r the runnable to be invoked. * @throws InterruptedException if there is an error invoking SwingUtilities. */ static void swingInvoke(Runnable r) throws InterruptedException { private static void swingInvoke(Runnable r) throws InterruptedException { try { SwingUtilities.invokeAndWait(r); } @@ -2289,23 +2044,23 @@ /** * The default implementaion of the BrowserNodeInfo interface. * The default implementation of the BrowserNodeInfo interface. */ class BrowserNodeInfoImpl implements BrowserNodeInfo private class BrowserNodeInfoImpl implements BrowserNodeInfo { BasicNode node; LDAPURL url; boolean isRemote; boolean isSuffix; boolean isRootNode; String[] referral; int numSubOrdinates; boolean hasSubOrdinates; int errorType; Exception errorException; Object errorArg; String[] objectClassValues; String toString; private BasicNode node; private LDAPURL url; private boolean isRemote; private boolean isSuffix; private boolean isRootNode; private String[] referral; private int numSubOrdinates; private boolean hasSubOrdinates; private int errorType; private Exception errorException; private Object errorArg; private String[] objectClassValues; private String toString; /** * The constructor of this object. @@ -2353,6 +2108,7 @@ * Returns the node associated with this object. * @return the node associated with this object. */ @Override public BasicNode getNode() { return node; } @@ -2361,6 +2117,7 @@ * Returns the LDAP URL associated with this object. * @return the LDAP URL associated with this object. */ @Override public LDAPURL getURL() { return url; } @@ -2370,6 +2127,7 @@ * @return <CODE>true</CODE> if this is a root node and <CODE>false</CODE> * otherwise. */ @Override public boolean isRootNode() { return isRootNode; } @@ -2379,6 +2137,7 @@ * @return <CODE>true</CODE> if this is a suffix node and <CODE>false</CODE> * otherwise. */ @Override public boolean isSuffix() { return isSuffix; } @@ -2388,6 +2147,7 @@ * @return <CODE>true</CODE> if this is a remote node and <CODE>false</CODE> * otherwise. */ @Override public boolean isRemote() { return isRemote; } @@ -2396,6 +2156,7 @@ * Returns the list of referral associated with this node. * @return the list of referral associated with this node. */ @Override public String[] getReferral() { return referral; } @@ -2406,6 +2167,7 @@ * @return the number of subordinates of the entry associated with this * node. */ @Override public int getNumSubOrdinates() { return numSubOrdinates; } @@ -2415,6 +2177,7 @@ * @return {@code true} if the entry has subordinates and {@code false} * otherwise. */ @Override public boolean hasSubOrdinates() { return hasSubOrdinates; } @@ -2425,6 +2188,7 @@ * @return the error type associated we got when refreshing the node. * <CODE>null</CODE> if no error was found. */ @Override public int getErrorType() { return errorType; } @@ -2435,6 +2199,7 @@ * @return the exception associated we got when refreshing the node. * <CODE>null</CODE> if no exception was found. */ @Override public Exception getErrorException() { return errorException; } @@ -2445,6 +2210,7 @@ * @return the error argument associated we got when refreshing the node. * <CODE>null</CODE> if no error argument was found. */ @Override public Object getErrorArg() { return errorArg; } @@ -2453,6 +2219,7 @@ * Return the tree path associated with the node in the tree. * @return the tree path associated with the node in the tree. */ @Override public TreePath getTreePath() { return new TreePath(treeModel.getPathToRoot(node)); } @@ -2461,6 +2228,7 @@ * Returns the object class values of the entry associated with the node. * @return the object class values of the entry associated with the node. */ @Override public String[] getObjectClassValues() { return objectClassValues; } @@ -2469,6 +2237,7 @@ * Returns a String representation of the object. * @return a String representation of the object. */ @Override public String toString() { return toString; } @@ -2479,12 +2248,12 @@ * @return <CODE>true</CODE> if the node info represents the same node as * this and <CODE>false</CODE> otherwise. */ @Override public boolean representsSameNode(BrowserNodeInfo node) { boolean representsSameNode = false; if (node != null) { representsSameNode = node.getNode() == node; return node.getNode() == node; } return representsSameNode; return false; } } opends/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; } } opends/src/guitools/org/opends/guitools/controlpanel/browser/LDAPConnectionPool.java
@@ -22,12 +22,11 @@ * * * Copyright 2008-2010 Sun Microsystems, Inc. * Portions Copyright 2014 ForgeRock AS */ package org.opends.guitools.controlpanel.browser; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import javax.naming.NamingException; @@ -42,6 +41,8 @@ import org.opends.server.types.LDAPURL; import org.opends.server.types.SearchScope; import static org.opends.admin.ads.util.ConnectionUtils.*; /** * An LDAPConnectionPool is a pool of LDAPConnection. * <BR><BR> @@ -71,11 +72,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; @@ -89,28 +91,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; } /** @@ -119,12 +113,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; @@ -141,11 +130,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); @@ -164,17 +149,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(). @@ -287,35 +261,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 @@ -331,14 +287,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; @@ -371,15 +324,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"); @@ -395,7 +343,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); @@ -403,45 +351,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. @@ -490,8 +399,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); } /** @@ -505,24 +413,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); } /** @@ -579,26 +481,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 @@ -643,20 +535,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; } opends/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; @@ -51,7 +51,7 @@ */ class PersistentServerState { private final DN baseDn; private final DN baseDN; private final int serverId; private final ServerState state; @@ -64,13 +64,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(); @@ -108,7 +108,7 @@ { if (!state.isSaved()) { state.setSaved(updateStateEntry() == ResultCode.SUCCESS); state.setSaved(updateStateEntry()); } } @@ -158,18 +158,16 @@ * 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, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, filter, attributes); if (((search.getResultCode() != ResultCode.SUCCESS)) && ((search.getResultCode() != ResultCode.NO_SUCH_OBJECT))) baseDN, SearchScope.BASE_OBJECT, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, filter, Collections.singleton(REPLICATION_STATE)); final ResultCode resultCode = search.getResultCode(); if (resultCode != ResultCode.SUCCESS && resultCode != ResultCode.NO_SUCH_OBJECT) { logError(ERR_ERROR_SEARCHING_RUV.get( search.getResultCode().getResultCodeName(), search.toString(), search.getErrorMessage(), baseDn.toString())); resultCode.getResultCodeName(), search.toString(), search.getErrorMessage(), baseDN.toString())); return null; } return getFirstResult(search); @@ -193,15 +191,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.decode("cn=config"), SearchScope.SUBORDINATE_SUBTREE, DereferencePolicy.NEVER_DEREF_ALIASES, 1, 0, false, filter, attributes); 1, 0, false, filter, Collections.singleton(REPLICATION_STATE)); return getFirstResult(op); } catch (DirectoryException e) @@ -234,12 +230,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 (AttributeValue value : attr) for (AttributeValue value : attrs.get(0)) { update(new CSN(value.toString())); } @@ -250,12 +244,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, @@ -263,11 +257,10 @@ SearchResultEntry configEntry = searchConfigEntry(); if (configEntry != null) { DN configDN = configEntry.getDN(); result = runUpdateStateEntry(configDN); result = runUpdateStateEntry(configEntry.getDN()); } } return result; return result == ResultCode.SUCCESS; } /** @@ -283,14 +276,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); @@ -301,7 +292,7 @@ op.getResultCode().getResultCodeName().toString(), op.toString(), op.getErrorMessage().toString(), baseDn.toString())); baseDN.toString())); } return op.getResultCode(); } @@ -356,7 +347,7 @@ InternalSearchOperation op; try { op = LDAPReplicationDomain.searchForChangedEntries(baseDn, op = LDAPReplicationDomain.searchForChangedEntries(baseDN, serverStateMaxCSN, null); } catch (Exception e) @@ -368,7 +359,7 @@ { // An error happened trying to search for the updates // Log an error logError(ERR_CANNOT_RECOVER_CHANGES.get(baseDn.toNormalizedString())); logError(ERR_CANNOT_RECOVER_CHANGES.get(baseDN.toNormalizedString())); return; } @@ -394,7 +385,7 @@ { // Update the serverState with the new maxCSN present in the database update(dbMaxCSN); logError(NOTE_SERVER_STATE_RECOVERY.get(baseDn.toNormalizedString(), logError(NOTE_SERVER_STATE_RECOVERY.get(baseDN.toNormalizedString(), dbMaxCSN.toString())); } } @@ -411,4 +402,14 @@ { return state.getCSN(serverId); } /** {@inheritDoc} */ @Override public String toString() { return getClass().getSimpleName() + " baseDN=" + baseDN + " serverId=" + serverId + " " + REPLICATION_STATE + "=" + state; } } opends/src/server/org/opends/server/replication/server/MessageHandler.java
@@ -295,31 +295,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) { TRACER.debugCaught(DebugLogLevel.ERROR, 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 @@ -333,8 +313,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(); @@ -356,7 +336,7 @@ { // get the next change from the lateQueue UpdateMsg msg; synchronized (msgQueue) synchronized (msgQueue) // TODO JNR why synchronize(msgQueue) here? { msg = lateQueue.removeFirst(); } @@ -409,6 +389,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) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } finally { close(cursor); } } private boolean isLateQueueBelowThreshold() { return lateQueue.count() < 100 && lateQueue.bytesCount() < 50000; @@ -428,16 +429,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 { opends/src/server/org/opends/server/replication/server/MsgQueue.java
@@ -22,14 +22,12 @@ * * * Copyright 2006-2010 Sun Microsystems, Inc. * Portions copyright 2012-2013 ForgeRock AS. * Portions copyright 2012-2014 ForgeRock AS. */ package org.opends.server.replication.server; import java.util.NavigableMap; import java.util.TreeMap; import org.opends.messages.Message; import org.opends.server.replication.common.CSN; import org.opends.server.replication.protocol.UpdateMsg; @@ -39,10 +37,18 @@ /** * 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 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. */ @@ -110,7 +116,7 @@ { synchronized (lock) { UpdateMsg msgSameCSN = map.put(update.getCSN(), update); final UpdateMsg msgSameCSN = map.put(update.getCSN(), update); if (msgSameCSN != null) { try @@ -121,14 +127,13 @@ { // Adding 2 msgs with the same CSN is ok only when // the 2 msgs are the same bytesCount += (update.size() - msgSameCSN.size()); Message errMsg = ERR_RSQUEUE_DIFFERENT_MSGS_WITH_SAME_CN.get( bytesCount += update.size() - msgSameCSN.size(); logError(ERR_RSQUEUE_DIFFERENT_MSGS_WITH_SAME_CN.get( msgSameCSN.getCSN().toString(), msgSameCSN.toString(), update.toString()); logError(errMsg); msgSameCSN.toString(), update.toString())); } } catch(Exception e) catch (Exception e) {} } else @@ -148,14 +153,15 @@ { 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 Message msg = ERR_BYTE_COUNT.get(Integer.toString(bytesCount)); logError(msg); logError(ERR_BYTE_COUNT.get(Integer.toString(bytesCount))); bytesCount = 0; } return update; @@ -197,18 +203,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(); } } opends/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} */ opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java
@@ -22,33 +22,33 @@ * * * Copyright 2006-2008 Sun Microsystems, Inc. * Portions copyright 2013 ForgeRock AS. * Portions copyright 2013-2014 ForgeRock AS. */ package org.opends.server.monitors; import java.util.ArrayList; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.annotations.AfterClass; import java.util.Iterator; import java.util.Set; 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.*; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.opends.server.protocols.internal.InternalClientConnection.*; import static org.opends.server.types.SearchFilter.*; import static org.opends.server.types.SearchScope.*; 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 { @@ -56,20 +56,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); @@ -77,19 +72,13 @@ /** * 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.decode("cn=monitor"), SearchScope.WHOLE_SUBTREE, SearchFilter.createFilterFromString("(objectClass=*)")); assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS); InternalSearchOperation op = getRootConnection().processSearch( "cn=monitor", WHOLE_SUBTREE, "(objectClass=*)"); assertEquals(op.getResultCode(), ResultCode.SUCCESS); } @@ -102,18 +91,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,52 +108,36 @@ * 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.decode("cn="+monitorName+",cn=monitor"); InternalClientConnection conn = InternalClientConnection.getRootConnection(); InternalSearchOperation searchOperation = conn.processSearch(monitorDN, SearchScope.BASE_OBJECT, SearchFilter.createFilterFromString("(objectClass=*)")); assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS); final String monitorDN = "cn="+monitorName+",cn=monitor"; InternalSearchOperation op = getRootConnection().processSearch( monitorDN, BASE_OBJECT, "(objectClass=*)"); assertEquals(op.getResultCode(), ResultCode.SUCCESS); } /** * 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.decode("cn=monitor"), SearchScope.WHOLE_SUBTREE, SearchFilter.createFilterFromString("(objectClass=*)")); final InternalClientConnection conn = getRootConnection(); InternalSearchOperation searchOperation = conn.processSearch( "cn=monitor", WHOLE_SUBTREE, "(objectClass=*)"); assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS); for (SearchResultEntry sre : searchOperation.getSearchEntries()) { SearchFilter filter = SearchFilter.createFilterFromString("(objectClass=*)"); searchOperation = conn.processSearch(sre.getDN(), SearchScope.BASE_OBJECT, filter); assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS); final InternalSearchOperation op = conn.processSearch( sre.getDN(), BASE_OBJECT, createFilterFromString("(objectClass=*)")); assertEquals(op.getResultCode(), ResultCode.SUCCESS); } } } opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ExternalChangeLogTest.java
@@ -28,7 +28,6 @@ import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; import java.net.Socket; import java.util.*; @@ -159,17 +158,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); @@ -190,29 +179,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 { @@ -226,27 +192,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 { @@ -279,10 +224,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. @@ -296,27 +239,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 @@ -410,7 +346,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); } @@ -470,11 +408,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 { @@ -558,7 +500,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"); @@ -569,12 +511,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); } /** @@ -666,11 +607,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; @@ -880,7 +826,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); } @@ -925,9 +871,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; @@ -992,9 +939,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; @@ -1131,7 +1079,7 @@ baseUUID, entry.getObjectClassAttribute(), entry.getAttributes(), new ArrayList<Attribute>()); Collections.<Attribute> emptyList()); server01.publish(addMsg); debugInfo(tn, " publishes " + addMsg.getCSN()); @@ -1248,31 +1196,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; } @@ -1432,7 +1376,7 @@ // Creates cookie control String cookie = ""; List<Control> controls = createControls(cookie); List<Control> controls = createCookieControl(cookie); if (compatMode) { cookie = null; @@ -1574,7 +1518,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; @@ -1653,11 +1597,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; @@ -1723,7 +1668,7 @@ // Creates cookie control String cookie = ""; List<Control> controls = createControls(cookie); List<Control> controls = createCookieControl(cookie); if (compatMode) { cookie = null; @@ -2162,9 +2107,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; @@ -2291,7 +2237,7 @@ baseUUID, entry.getObjectClassAttribute(), entry.getAttributes(), new ArrayList<Attribute>()); Collections.<Attribute> emptyList()); server01.publish(addMsg); debugInfo(tn, " publishes " + addMsg.getCSN()); @@ -2603,9 +2549,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"); @@ -2622,9 +2572,7 @@ 0, // Time limit false, // Types only "(objectclass=*)", attributes, NO_CONTROL, null); attributes); waitOpResult(searchOp, ResultCode.SUCCESS); final List<SearchResultEntry> entries = searchOp.getSearchEntries(); @@ -2720,9 +2668,7 @@ 0, // Time limit false, // Types only "(objectclass=*)", attributes, NO_CONTROL, null); attributes); waitOpResult(searchOp, ResultCode.SUCCESS); return searchOp; } @@ -2773,11 +2719,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"; @@ -2952,9 +2899,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, @@ -2969,8 +2914,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