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-2016 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 */
038public class LDAPEntryReader extends BackgroundTask<CustomSearchResult>
039{
040  private final String dn;
041  private final InitialLdapContext ctx;
042  private final Set<EntryReadListener> listeners = new HashSet<>();
043  private boolean isOver;
044  private boolean notifyListeners;
045
046  /**
047   * Constructor of the entry reader.
048   * @param dn the DN of the entry.
049   * @param ctx the connection to the server.
050   */
051  public LDAPEntryReader(String dn, InitialLdapContext ctx)
052  {
053    this.dn = dn;
054    this.ctx = ctx;
055    this.notifyListeners = true;
056  }
057
058  @Override
059  public CustomSearchResult processBackgroundTask() throws Throwable
060  {
061    isOver = false;
062    NamingEnumeration<SearchResult> en = null;
063    try
064    {
065      SearchControls controls = new SearchControls();
066
067      String[] attrs = {"*", "+"};
068      controls.setReturningAttributes(attrs);
069      controls.setSearchScope(SearchControls.OBJECT_SCOPE);
070      final String filter = "(|(objectclass=*)(objectclass=ldapsubentry))";
071
072      en = ctx.search(Utilities.getJNDIName(dn), filter, controls);
073
074      SearchResult sr = null;
075      while (en.hasMore())
076      {
077        sr = en.next();
078      }
079
080      return new CustomSearchResult(sr, dn);
081    }
082    finally
083    {
084      if (isInterrupted())
085      {
086        isOver = true;
087      }
088      if (en != null)
089      {
090        en.close();
091      }
092    }
093  }
094
095  @Override
096  public void backgroundTaskCompleted(CustomSearchResult sr,
097      Throwable throwable)
098  {
099    if (!isInterrupted() && isNotifyListeners())
100    {
101      if (throwable == null)
102      {
103        notifyListeners(sr);
104      }
105      else
106      {
107        notifyListeners(throwable);
108      }
109    }
110    isOver = true;
111  }
112
113  /**
114   * Returns whether this entry reader will notify the listeners once it is
115   * over.
116   * @return whether this entry reader will notify the listeners once it is
117   * over.
118   */
119  public boolean isNotifyListeners()
120  {
121    return notifyListeners;
122  }
123
124  /**
125   * Sets whether this entry reader will notify the listeners once it is
126   * over.
127   * @param notifyListeners whether this entry reader will notify the listeners
128   * once it is over.
129   */
130  public void setNotifyListeners(boolean notifyListeners)
131  {
132    this.notifyListeners = notifyListeners;
133  }
134
135  /**
136   * Returns <CODE>true</CODE> if the read process is over and
137   * <CODE>false</CODE> otherwise.
138   * @return <CODE>true</CODE> if the read process is over and
139   * <CODE>false</CODE> otherwise.
140   */
141  public boolean isOver()
142  {
143    return isOver;
144  }
145
146  /**
147   * Notifies listeners that a new entry was read.
148   * @param sr the new entry in form of CustomSearchResult.
149   */
150  private void notifyListeners(CustomSearchResult sr)
151  {
152    EntryReadEvent ev = new EntryReadEvent(this, sr);
153    for (EntryReadListener listener : listeners)
154    {
155      listener.entryRead(ev);
156    }
157  }
158
159  /**
160   * Notifies the listeners that an error occurred reading an entry.
161   * @param t the error that occurred reading an entry.
162   */
163  private void notifyListeners(Throwable t)
164  {
165    EntryReadErrorEvent ev = new EntryReadErrorEvent(this, dn, t);
166    for (EntryReadListener listener : listeners)
167    {
168      listener.entryReadError(ev);
169    }
170  }
171
172  /**
173   * Adds an EntryReadListener.
174   * @param listener the listener.
175   */
176  public void addEntryReadListener(EntryReadListener listener)
177  {
178    listeners.add(listener);
179  }
180
181  /**
182   * Removes an EntryReadListener.
183   * @param listener the listener.
184   */
185  public void removeEntryReadListener(EntryReadListener listener)
186  {
187    listeners.remove(listener);
188  }
189}