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