001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2008-2010 Sun Microsystems, Inc.
015 * Portions Copyright 2015 ForgeRock AS.
016 */
017
018package org.opends.guitools.controlpanel.util;
019
020import java.util.HashSet;
021import java.util.Set;
022
023import javax.naming.NamingEnumeration;
024import javax.naming.directory.SearchControls;
025import javax.naming.directory.SearchResult;
026import javax.naming.ldap.InitialLdapContext;
027
028import org.opends.guitools.controlpanel.datamodel.CustomSearchResult;
029import org.opends.guitools.controlpanel.event.EntryReadErrorEvent;
030import org.opends.guitools.controlpanel.event.EntryReadEvent;
031import org.opends.guitools.controlpanel.event.EntryReadListener;
032
033/**
034 * A class that reads an entry on the background.  This is used in the LDAP
035 * entries browser.  When the entry is read it notifies to the EntryReadListener
036 * objects that have been registered.
037 *
038 */
039public class LDAPEntryReader extends BackgroundTask<CustomSearchResult>
040{
041  private final String dn;
042  private final InitialLdapContext ctx;
043  private final Set<EntryReadListener> listeners = new HashSet<>();
044  private boolean isOver;
045  private boolean notifyListeners;
046
047  /**
048   * Constructor of the entry reader.
049   * @param dn the DN of the entry.
050   * @param ctx the connection to the server.
051   */
052  public LDAPEntryReader(String dn, InitialLdapContext ctx)
053  {
054    this.dn = dn;
055    this.ctx = ctx;
056    this.notifyListeners = true;
057  }
058
059  /** {@inheritDoc} */
060  @Override
061  public CustomSearchResult processBackgroundTask() throws Throwable
062  {
063    isOver = false;
064    NamingEnumeration<SearchResult> en = null;
065    try
066    {
067      SearchControls controls = new SearchControls();
068
069      String[] attrs = {"*", "+"};
070      controls.setReturningAttributes(attrs);
071      controls.setSearchScope(SearchControls.OBJECT_SCOPE);
072      final String filter = "(|(objectclass=*)(objectclass=ldapsubentry))";
073
074      en = ctx.search(Utilities.getJNDIName(dn), filter, controls);
075
076      SearchResult sr = null;
077      while (en.hasMore())
078      {
079        sr = en.next();
080      }
081
082      return new CustomSearchResult(sr, dn);
083    }
084    finally
085    {
086      if (isInterrupted())
087      {
088        isOver = true;
089      }
090      if (en != null)
091      {
092        en.close();
093      }
094    }
095  }
096
097  /** {@inheritDoc} */
098  @Override
099  public void backgroundTaskCompleted(CustomSearchResult sr,
100      Throwable throwable)
101  {
102    if (!isInterrupted() && isNotifyListeners())
103    {
104      if (throwable == null)
105      {
106        notifyListeners(sr);
107      }
108      else
109      {
110        notifyListeners(throwable);
111      }
112    }
113    isOver = true;
114  }
115
116  /**
117   * Returns whether this entry reader will notify the listeners once it is
118   * over.
119   * @return whether this entry reader will notify the listeners once it is
120   * over.
121   */
122  public boolean isNotifyListeners()
123  {
124    return notifyListeners;
125  }
126
127  /**
128   * Sets whether this entry reader will notify the listeners once it is
129   * over.
130   * @param notifyListeners whether this entry reader will notify the listeners
131   * once it is over.
132   */
133  public void setNotifyListeners(boolean notifyListeners)
134  {
135    this.notifyListeners = notifyListeners;
136  }
137
138  /**
139   * Returns <CODE>true</CODE> if the read process is over and
140   * <CODE>false</CODE> otherwise.
141   * @return <CODE>true</CODE> if the read process is over and
142   * <CODE>false</CODE> otherwise.
143   */
144  public boolean isOver()
145  {
146    return isOver;
147  }
148
149  /**
150   * Notifies listeners that a new entry was read.
151   * @param sr the new entry in form of CustomSearchResult.
152   */
153  private void notifyListeners(CustomSearchResult sr)
154  {
155    EntryReadEvent ev = new EntryReadEvent(this, sr);
156    for (EntryReadListener listener : listeners)
157    {
158      listener.entryRead(ev);
159    }
160  }
161
162  /**
163   * Notifies the listeners that an error occurred reading an entry.
164   * @param t the error that occurred reading an entry.
165   */
166  private void notifyListeners(Throwable t)
167  {
168    EntryReadErrorEvent ev = new EntryReadErrorEvent(this, dn, t);
169    for (EntryReadListener listener : listeners)
170    {
171      listener.entryReadError(ev);
172    }
173  }
174
175  /**
176   * Adds an EntryReadListener.
177   * @param listener the listener.
178   */
179  public void addEntryReadListener(EntryReadListener listener)
180  {
181    listeners.add(listener);
182  }
183
184  /**
185   * Removes an EntryReadListener.
186   * @param listener the listener.
187   */
188  public void removeEntryReadListener(EntryReadListener listener)
189  {
190    listeners.remove(listener);
191  }
192}