001/* 002 * Copyright 2009-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-2017 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 */ 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.ThreadSafety; 034import com.unboundid.util.ThreadSafetyLevel; 035 036import static com.unboundid.ldap.sdk.persist.PersistMessages.*; 037import static com.unboundid.util.Debug.*; 038import static com.unboundid.util.StaticUtils.*; 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 (Exception e) 121 { 122 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 getExceptionMessage(e)), e); 134 } 135 } 136 137 if (entry == null) 138 { 139 return null; 140 } 141 else 142 { 143 return persister.decode(entry); 144 } 145 } 146 147 148 149 /** 150 * Indicates that you wish to stop iterating through search results and will 151 * not be retrieving any additional objects. This method MUST be called to 152 * avoid leaking resources if you stop iterating through results before the 153 * {@link #next} method returns {@code null} to indicate that there are no 154 * more objects to retrieve. This method MAY be called after the search has 155 * completed (including being called multiple times) with no adverse effects. 156 */ 157 public void close() 158 { 159 entrySource.close(); 160 } 161 162 163 164 /** 165 * Retrieves the search result for the search operation, if available. It 166 * will not be available until the search has completed (as indicated by a 167 * {@code null} return value from the {@link #next} method), and for some use 168 * cases it may never be available. 169 * 170 * @return The search result for the search operation, or {@code null} if it 171 * is not available (e.g., because the search has not yet completed). 172 */ 173 public SearchResult getSearchResult() 174 { 175 if (entrySource instanceof LDAPEntrySource) 176 { 177 return ((LDAPEntrySource) entrySource).getSearchResult(); 178 } 179 else 180 { 181 return null; 182 } 183 } 184}