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