| | |
| | | */ |
| | | package org.opends.guitools.controlpanel.browser; |
| | | |
| | | import static org.opends.messages.AdminToolMessages.*; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Set; |
| | | |
| | |
| | | import org.opends.server.types.OpenDsException; |
| | | import org.opends.server.types.RDN; |
| | | |
| | | import static org.opends.messages.AdminToolMessages.*; |
| | | |
| | | /** |
| | | * The class that is in charge of doing the LDAP searches required to update a |
| | | * node: search the local entry, detect if it has children, retrieve the |
| | | * attributes required to render the node, etc. |
| | | */ |
| | | public class NodeRefresher extends AbstractNodeTask { |
| | | |
| | | /** |
| | | * The enumeration containing all the states the refresher can have. |
| | | * |
| | | */ |
| | | /** The enumeration containing all the states the refresher can have. */ |
| | | public enum State |
| | | { |
| | | /** |
| | | * The refresher is queued, but not started. |
| | | */ |
| | | /** The refresher is queued, but not started. */ |
| | | QUEUED, |
| | | /** |
| | | * The refresher is reading the local entry. |
| | | */ |
| | | /** The refresher is reading the local entry. */ |
| | | READING_LOCAL_ENTRY, |
| | | /** |
| | | * The refresher is solving a referral. |
| | | */ |
| | | /** The refresher is solving a referral. */ |
| | | SOLVING_REFERRAL, |
| | | /** |
| | | * The refresher is detecting whether the entry has children or not. |
| | | */ |
| | | /** The refresher is detecting whether the entry has children or not. */ |
| | | DETECTING_CHILDREN, |
| | | /** |
| | | * The refresher is searching for the children of the entry. |
| | | */ |
| | | /** The refresher is searching for the children of the entry. */ |
| | | SEARCHING_CHILDREN, |
| | | /** |
| | | * The refresher is finished. |
| | | */ |
| | | /** The refresher is finished. */ |
| | | FINISHED, |
| | | /** |
| | | * The refresher is cancelled. |
| | | */ |
| | | /** The refresher is cancelled. */ |
| | | CANCELLED, |
| | | /** |
| | | * The refresher has been interrupted. |
| | | */ |
| | | /** The refresher has been interrupted. */ |
| | | INTERRUPTED, |
| | | /** |
| | | * The refresher has failed. |
| | | */ |
| | | /** The refresher has failed. */ |
| | | FAILED |
| | | } |
| | | |
| | |
| | | SearchResult remoteEntry; |
| | | LDAPURL remoteUrl; |
| | | boolean isLeafNode; |
| | | ArrayList<SearchResult> childEntries = new ArrayList<SearchResult>(); |
| | | boolean differential; |
| | | final ArrayList<SearchResult> childEntries = new ArrayList<>(); |
| | | final boolean differential; |
| | | Exception exception; |
| | | Object exceptionArg; |
| | | |
| | | |
| | | /** |
| | | * The constructor of the refresher object. |
| | | * @param node the node on the tree to be updated. |
| | | * @param ctlr the BrowserController. |
| | | * @param localEntry the local entry corresponding to the node. |
| | | * @param recursive whether this task is recursive or not (children must be |
| | | * searched). |
| | | * @param recursive whether this task is recursive or not (children must be searched). |
| | | */ |
| | | public NodeRefresher(BasicNode node, BrowserController ctlr, |
| | | SearchResult localEntry, boolean recursive) { |
| | | NodeRefresher(BasicNode node, BrowserController ctlr, SearchResult localEntry, boolean recursive) { |
| | | super(node); |
| | | controller = ctlr; |
| | | state = State.QUEUED; |
| | | this.recursive = recursive; |
| | | |
| | | this.localEntry = localEntry; |
| | | differential = false; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the local entry the refresher is handling. |
| | | * @return the local entry the refresher is handling. |
| | |
| | | return localEntry; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the remote entry for the node. It will be <CODE>null</CODE> if |
| | | * the entry is not a referral. |
| | |
| | | return remoteUrl; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Tells whether the node is a leaf or not. |
| | | * @return <CODE>true</CODE> if the node is a leaf and <CODE>false</CODE> |
| | |
| | | return isLeafNode; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the child entries of the node. |
| | | * @return the child entries of the node. |
| | |
| | | return exception; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the argument of the exception that occurred during the processing. |
| | | * It returns <CODE>null</CODE> if no exception occurred or if the exception |
| | |
| | | return exceptionArg; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the displayed entry in the browser. This depends on the |
| | | * visualization options in the BrowserController. |
| | |
| | | */ |
| | | public SearchResult getDisplayedEntry() { |
| | | SearchResult result; |
| | | if (controller.getFollowReferrals() && (remoteEntry != null)) { |
| | | if (controller.getFollowReferrals() && remoteEntry != null) |
| | | { |
| | | result = remoteEntry; |
| | | } |
| | | else { |
| | |
| | | */ |
| | | public LDAPURL getDisplayedUrl() { |
| | | LDAPURL result; |
| | | if (controller.getFollowReferrals() && (remoteUrl != null)) { |
| | | if (controller.getFollowReferrals() && remoteUrl != null) |
| | | { |
| | | result = remoteUrl; |
| | | } |
| | | else { |
| | |
| | | * otherwise. |
| | | */ |
| | | public boolean isInFinalState() { |
| | | return ( |
| | | (state == State.FINISHED) || |
| | | (state == State.CANCELLED) || |
| | | (state == State.FAILED) || |
| | | (state == State.INTERRUPTED) |
| | | ); |
| | | return state == State.FINISHED || state == State.CANCELLED || state == State.FAILED || state == State.INTERRUPTED; |
| | | } |
| | | |
| | | /** |
| | | * The method that actually does the refresh. |
| | | */ |
| | | /** The method that actually does the refresh. */ |
| | | @Override |
| | | public void run() { |
| | | final BasicNode node = getNode(); |
| | |
| | | if (controller.nodeIsExpanded(node) && recursive) { |
| | | changeStateTo(State.SEARCHING_CHILDREN); |
| | | runSearchChildren(); |
| | | /* If the node is not expanded, we have to refresh its children |
| | | when we expand it */ |
| | | /* If the node is not expanded, we have to refresh its children when we expand it */ |
| | | } else if (recursive && (!node.isLeaf() || !isLeafNode)) { |
| | | node.setRefreshNeededOnExpansion(true); |
| | | checkExpand = true; |
| | |
| | | { |
| | | boolean result=false; |
| | | if (controller.getFilter()!=null) |
| | | { |
| | | result = |
| | | !controller.getFilter().equals(BrowserController.ALL_OBJECTS_FILTER); |
| | | !BrowserController.ALL_OBJECTS_FILTER.equals(controller.getFilter()); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Read the local entry associated to the current node. |
| | | */ |
| | | /** Read the local entry associated to the current node. */ |
| | | private void runReadLocalEntry() throws SearchAbandonException { |
| | | BasicNode node = getNode(); |
| | | InitialLdapContext ctx = null; |
| | |
| | | { |
| | | localEntry = s.next(); |
| | | localEntry.setName(node.getDN()); |
| | | |
| | | } |
| | | } |
| | | finally |
| | |
| | | s.close(); |
| | | } |
| | | if (localEntry == null) { |
| | | /* Not enough rights to read the entry or the entry simply does not |
| | | exist */ |
| | | /* Not enough rights to read the entry or the entry simply does not exist */ |
| | | throw new NameNotFoundException("Can't find entry: "+node.getDN()); |
| | | } |
| | | throwAbandonIfNeeded(null); |
| | |
| | | throws SearchAbandonException, NamingException { |
| | | int hopCount = 0; |
| | | String[] referral = getNode().getReferral(); |
| | | while ((referral != null) && (hopCount < 10)) { |
| | | while (referral != null && hopCount < 10) |
| | | { |
| | | readRemoteEntry(referral); |
| | | referral = BrowserController.getReferral(remoteEntry); |
| | | hopCount++; |
| | | } |
| | | if (referral != null) { // -> hopCount has reached the max |
| | | if (referral != null) |
| | | { |
| | | throwAbandonIfNeeded(new ReferralLimitExceededException( |
| | | AdminToolMessages.ERR_REFERRAL_LIMIT_EXCEEDED.get(hopCount))); |
| | | } |
| | |
| | | Object lastExceptionArg = null; |
| | | |
| | | int i = 0; |
| | | while ((i < referral.length) && (entry == null)) { |
| | | while (i < referral.length && entry == null) |
| | | { |
| | | InitialLdapContext ctx = null; |
| | | try { |
| | | url = LDAPURL.decode(referral[i], false); |
| | |
| | | } |
| | | ctx = connectionPool.getConnection(url); |
| | | remoteDn = url.getRawBaseDN(); |
| | | if ((remoteDn == null) || |
| | | remoteDn.equals("")) { |
| | | if (remoteDn == null || "".equals(remoteDn)) |
| | | { |
| | | /* The referral has not a target DN specified: we |
| | | have to use the DN of the entry that contains the |
| | | referral... */ |
| | |
| | | } else { |
| | | remoteDn = localEntry.getName(); |
| | | } |
| | | /* We have to recreate the url including the target DN |
| | | we are using */ |
| | | /* We have to recreate the url including the target DN we are using */ |
| | | url = new LDAPURL(url.getScheme(), url.getHost(), url.getPort(), |
| | | remoteDn, url.getAttributes(), url.getScope(), url.getRawFilter(), |
| | | url.getExtensions()); |
| | |
| | | catch (InterruptedNamingException x) { |
| | | throwAbandonIfNeeded(x); |
| | | } |
| | | catch (NamingException x) { |
| | | catch (NamingException | DirectoryException x) { |
| | | lastException = x; |
| | | lastExceptionArg = referral[i]; |
| | | } |
| | | catch (DirectoryException de) { |
| | | lastException = de; |
| | | lastExceptionArg = referral[i]; |
| | | } |
| | | finally { |
| | | if (ctx != null) { |
| | | connectionPool.releaseConnection(ctx); |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Detects whether the entry has children by performing a search using the |
| | | * entry as base DN. |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * NUMSUBORDINATE HACK |
| | | * numsubordinates is not usable if the displayed entry |
| | |
| | | private boolean isNumSubOrdinatesUsable() throws NamingException { |
| | | SearchResult entry = getDisplayedEntry(); |
| | | boolean hasSubOrdinates = BrowserController.getHasSubOrdinates(entry); |
| | | if (!hasSubOrdinates) { // We must check |
| | | if (!hasSubOrdinates) |
| | | { |
| | | LDAPURL url = getDisplayedUrl(); |
| | | return !controller.getNumSubordinateHacker().contains(url); |
| | | } |
| | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Searches for the children. |
| | | * @throws SearchAbandonException if an error occurs. |
| | |
| | | return sr; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Utilities |
| | | */ |
| | | |
| | | /** Utilities. */ |
| | | |
| | | /** |
| | | * Change the state of the task and inform the BrowserController. |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Transform an exception into a TaskAbandonException. |
| | | * If no exception is passed, the routine checks if the task has |
| | |
| | | private void throwAbandonIfNeeded(Exception x) throws SearchAbandonException { |
| | | SearchAbandonException tax = null; |
| | | if (x != null) { |
| | | if ((x instanceof InterruptedException) || |
| | | (x instanceof InterruptedNamingException)) { |
| | | if (x instanceof InterruptedException || x instanceof InterruptedNamingException) |
| | | { |
| | | tax = new SearchAbandonException(State.INTERRUPTED, x, null); |
| | | } |
| | | else { |
| | |
| | | */ |
| | | private String unquoteRelativeName(String name) |
| | | { |
| | | if ((name.length() > 0) && (name.charAt(0) == '"')) |
| | | if (name.length() > 0 && name.charAt(0) == '"') |
| | | { |
| | | if (name.charAt(name.length() - 1) == '"') |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * DEBUG : Dump the state of the task. |
| | | */ |
| | | /** DEBUG : Dump the state of the task. */ |
| | | void dump() { |
| | | System.out.println("============="); |
| | | System.out.println(" node: " + getNode().getDN()); |
| | |
| | | System.out.println("============="); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Checks that the entry's objectClass contains 'referral' and that the |
| | | * attribute 'ref' is present. |
| | |
| | | if (ocValues != null) { |
| | | for (String value : ocValues) |
| | | { |
| | | boolean isReferral = value.equalsIgnoreCase("referral"); |
| | | boolean isReferral = "referral".equalsIgnoreCase(value); |
| | | |
| | | if (isReferral) { |
| | | result = (ConnectionUtils.getFirstValue(entry, "ref") != null); |
| | | result = ConnectionUtils.getFirstValue(entry, "ref") != null; |
| | | break; |
| | | } |
| | | } |
| | |
| | | controller.getConfigurationConnection()); |
| | | int adminPort = |
| | | ConnectionUtils.getPort(controller.getConfigurationConnection()); |
| | | checkSucceeded = (port != adminPort) || |
| | | checkSucceeded = port != adminPort || |
| | | !adminHost.equalsIgnoreCase(host); |
| | | |
| | | if (checkSucceeded) |
| | |
| | | controller.getUserDataConnection()); |
| | | int portUserData = |
| | | ConnectionUtils.getPort(controller.getUserDataConnection()); |
| | | checkSucceeded = (port != portUserData) || |
| | | checkSucceeded = port != portUserData || |
| | | !hostUserData.equalsIgnoreCase(host); |
| | | } |
| | | } |