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 */ 021package com.unboundid.ldap.sdk.persist; 022 023 024 025import java.io.Serializable; 026 027import com.unboundid.ldap.sdk.Entry; 028import com.unboundid.ldap.sdk.EntrySource; 029import com.unboundid.ldap.sdk.LDAPEntrySource; 030import com.unboundid.ldap.sdk.LDAPException; 031import com.unboundid.ldap.sdk.SearchResult; 032import com.unboundid.util.ThreadSafety; 033import com.unboundid.util.ThreadSafetyLevel; 034 035import static com.unboundid.ldap.sdk.persist.PersistMessages.*; 036import static com.unboundid.util.Debug.*; 037import 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) 062public 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}