001 /*
002 * Copyright 2009-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2009-2014 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk.persist;
022
023
024
025 import java.io.Serializable;
026
027 import com.unboundid.ldap.sdk.Entry;
028 import com.unboundid.ldap.sdk.EntrySource;
029 import com.unboundid.ldap.sdk.LDAPEntrySource;
030 import com.unboundid.ldap.sdk.LDAPException;
031 import com.unboundid.ldap.sdk.SearchResult;
032 import com.unboundid.util.ThreadSafety;
033 import com.unboundid.util.ThreadSafetyLevel;
034
035 import static com.unboundid.ldap.sdk.persist.PersistMessages.*;
036 import static com.unboundid.util.Debug.*;
037 import static com.unboundid.util.StaticUtils.*;
038
039
040
041 /**
042 * This class provides a mechanism for iterating through the objects returned
043 * by a search operation performed using one of the {@code search} methods in
044 * the {@link LDAPPersister} class. However, it has a couple of notable
045 * differences from a standard Java {@code Iterator} object:
046 * <UL>
047 * <LI>It does not have a {@code hasNext} method. Instead, the {@link #next}
048 * method will return {@code null} when there are no more objects in the
049 * set of results.</LI>
050 * <LI>The {@link #next} method may throw an exception if a problem occurs
051 * while trying to read an entry or decode it as an object of the
052 * appropriate type. This does not necessarily mean that the search is
053 * complete, and the {@link #next} method should be called again to see
054 * if there are any more objects to retrieve.</LI>
055 * <LI>If you wish to stop iterating through the results before all of them
056 * have been retrieved, then you must call the {@link #close} method
057 * </UL>
058 *
059 * @param <T> The type of object handled by this class.
060 */
061 @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
062 public final class PersistedObjects<T>
063 implements Serializable
064 {
065 /**
066 * The serial version UID for this serializable class.
067 */
068 private static final long serialVersionUID = 7430494946944736169L;
069
070
071
072 // The LDAP entry source that will be used to read matching entries.
073 private final EntrySource entrySource;
074
075 // The LDAP persister that will be used to decode the entries that are
076 // returned.
077 private final LDAPPersister<T> persister;
078
079
080
081 /**
082 * Creates a new {@code PersistedObjects} object that will read entries from
083 * the provided entry source.
084 *
085 * @param persister The persister that will be used to decode entries that
086 * are returned.
087 * @param entrySource The entry source that will be used to read entries
088 * returned from the search.
089 */
090 PersistedObjects(final LDAPPersister<T> persister,
091 final EntrySource entrySource)
092 {
093 this.persister = persister;
094 this.entrySource = entrySource;
095 }
096
097
098
099 /**
100 * Retrieves the next object returned from the search request. This method
101 * may block until the necessary information has been received from the
102 * server.
103 *
104 * @return The next object returned from the search request, or {@code null}
105 * if all objects have been read.
106 *
107 * @throws LDAPPersistException If a problem occurs while reading the next
108 * entry from the server, or when trying to
109 * decode that entry as an object.
110 */
111 public T next()
112 throws LDAPPersistException
113 {
114 final Entry entry;
115 try
116 {
117 entry = entrySource.nextEntry();
118 }
119 catch (Exception e)
120 {
121 debugException(e);
122
123 final Throwable cause = e.getCause();
124 if ((cause != null) && (cause instanceof LDAPException))
125 {
126 throw new LDAPPersistException((LDAPException) cause);
127 }
128 else
129 {
130 throw new LDAPPersistException(
131 ERR_OBJECT_SEARCH_RESULTS_ENTRY_SOURCE_EXCEPTION.get(
132 getExceptionMessage(e)), e);
133 }
134 }
135
136 if (entry == null)
137 {
138 return null;
139 }
140 else
141 {
142 return persister.decode(entry);
143 }
144 }
145
146
147
148 /**
149 * Indicates that you wish to stop iterating through search results and will
150 * not be retrieving any additional objects. This method MUST be called to
151 * avoid leaking resources if you stop iterating through results before the
152 * {@link #next} method returns {@code null} to indicate that there are no
153 * more objects to retrieve. This method MAY be called after the search has
154 * completed (including being called multiple times) with no adverse effects.
155 */
156 public void close()
157 {
158 entrySource.close();
159 }
160
161
162
163 /**
164 * Retrieves the search result for the search operation, if available. It
165 * will not be available until the search has completed (as indicated by a
166 * {@code null} return value from the {@link #next} method), and for some use
167 * cases it may never be available.
168 *
169 * @return The search result for the search operation, or {@code null} if it
170 * is not available (e.g., because the search has not yet completed).
171 */
172 public SearchResult getSearchResult()
173 {
174 if (entrySource instanceof LDAPEntrySource)
175 {
176 return ((LDAPEntrySource) entrySource).getSearchResult();
177 }
178 else
179 {
180 return null;
181 }
182 }
183 }