001: package edu.indiana.lib.osid.base.repository.http;
002:
003: import edu.indiana.lib.twinpeaks.net.*;
004: import edu.indiana.lib.twinpeaks.search.*;
005: import edu.indiana.lib.twinpeaks.util.*;
006:
007: import java.io.*;
008: import java.net.*;
009: import java.lang.*;
010: import java.util.*;
011:
012: /**********************************************************************************
013: * $URL: https://source.sakaiproject.org/svn/citations/tags/sakai_2-4-1/citations-osid/web2bridge/src/java/edu/indiana/lib/osid/base/repository/http/AssetIterator.java $
014: * $Id: AssetIterator.java 22624 2007-03-14 20:17:21Z jimeng@umich.edu $
015: **********************************************************************************
016: *
017: * Copyright (c) 2003, 2004, 2005 The Regents of the University of Michigan, Trustees of Indiana University,
018: * Board of Trustees of the Leland Stanford, Jr., University, and The MIT Corporation
019: *
020: * Licensed under the Educational Community License Version 1.0 (the "License");
021: * By obtaining, using and/or copying this Original Work, you agree that you have read,
022: * understand, and will comply with the terms and conditions of the Educational Community License.
023: * You may obtain a copy of the License at:
024: *
025: * http://cvs.sakaiproject.org/licenses/license_1_0.html
026: *
027: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
028: * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
029: * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
030: * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
031: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
032: *
033: **********************************************************************************/
034: /**
035: * @author Massachusetts Institute of Techbology, Sakai Software Development Team
036: * @version
037: */
038: public class AssetIterator extends
039: edu.indiana.lib.osid.base.repository.AssetIterator {
040: private static org.apache.commons.logging.Log _log = edu.indiana.lib.twinpeaks.util.LogUtils
041: .getLog(AssetIterator.class);
042:
043: private org.osid.shared.Properties searchProperties;
044: private org.osid.shared.Id repositoryId;
045: /*
046: * HTTP transaction information
047: */
048: private QueryBase queryBase;
049: private SearchResultBase searchResult;
050: private SessionContext sessionContext;
051: private String database;
052: /*
053: * Asset vector (a queue) and various details
054: */
055: private AssetIterator assetIterator;
056:
057: private Vector assetVector;
058: private int index;
059: private int populated;
060: private int startRecord;
061: private int pageSize;
062: private int maximumRecords;
063:
064: /**
065: * Unused constructor
066: */
067: protected AssetIterator(Vector vector) {
068: }
069:
070: /**
071: * Constructor
072: *
073: * @param database The database (or target) for this search
074: * @queryBase Query handler (QueryBase implementation)
075: * @searchResult Search result handler (SearchResultBase implementation)
076: * @param searchProperties Property list (search characteristics, provided by our caller)
077: * @param repositoryId Unique Repository ID
078: * @param sessionContext Context data for the current user/caller
079: */
080: protected AssetIterator(String database, QueryBase queryBase,
081: SearchResultBase searchResult,
082: org.osid.shared.Properties searchProperties,
083: org.osid.shared.Id repositoryId,
084: SessionContext sessionContext)
085: throws org.osid.repository.RepositoryException {
086: try {
087: this .database = database;
088: this .queryBase = queryBase;
089: this .searchResult = searchResult;
090: this .repositoryId = repositoryId;
091: this .sessionContext = sessionContext;
092:
093: this .assetIterator = null;
094:
095: initialize(searchProperties);
096: } catch (Throwable throwable) {
097: _log.error(throwable.getMessage());
098: throw new org.osid.repository.RepositoryException(
099: org.osid.shared.SharedException.OPERATION_FAILED);
100: }
101: }
102:
103: /**
104: * Initialize
105: * @param searchProperties Property list (search characteristics, provided by our caller)
106: */
107: protected void initialize(
108: org.osid.shared.Properties searchProperties)
109: throws org.osid.shared.SharedException {
110: try {
111: Integer max = getIntegerProperty(searchProperties,
112: "maxRecords");
113: int m1 = sessionContext.getInt("maxRecords");
114: int m2;
115:
116: /*
117: * Determine maximum number of search result records to request
118: */
119: m2 = (max == null) ? m1 : max.intValue();
120:
121: this .maximumRecords = Math.min(m1, m2);
122: this .assetVector = new Vector(maximumRecords);
123: this .index = 0;
124: this .populated = 0;
125: /*
126: * Save starting record number, page size, properties pointer
127: */
128: startRecord = getIntegerProperty(searchProperties,
129: "startRecord").intValue();
130: pageSize = getIntegerProperty(searchProperties, "pageSize")
131: .intValue();
132:
133: this .searchProperties = searchProperties;
134:
135: _log.debug("AssetIterator max = " + maximumRecords
136: + ", page = " + pageSize + ", start = "
137: + startRecord);
138: } catch (Throwable throwable) {
139: _log.error(throwable.getMessage());
140: throw new org.osid.repository.RepositoryException(
141: org.osid.shared.SharedException.OPERATION_FAILED);
142: }
143:
144: }
145:
146: /**
147: * Is another Asset available? If so, set the search status as "complete".
148: * @return true if an Asset is available, false if not
149: */
150: public boolean hasNextAsset()
151: throws org.osid.repository.RepositoryException {
152: try {
153: boolean moreRecords = (index < maximumRecords);
154:
155: _log.debug("AssetIterator.hasNext() = " + moreRecords);
156: if (!moreRecords) {
157: StatusUtils.setAllComplete(sessionContext);
158: }
159: return moreRecords;
160: } catch (Throwable throwable) {
161: _log.error(throwable.getMessage());
162: throw new org.osid.repository.RepositoryException(
163: org.osid.shared.SharedException.OPERATION_FAILED);
164: }
165: }
166:
167: /**
168: * Fetch the next available search result (from the "Asset queue")
169: * @return The next search result (as an Asset)
170: */
171: public org.osid.repository.Asset nextAsset()
172: throws org.osid.repository.RepositoryException {
173: org.osid.repository.Asset asset;
174:
175: /*
176: * End-of-file?
177: */
178: if (index >= maximumRecords) {
179: StatusUtils.setAllComplete(sessionContext);
180: throw new org.osid.repository.RepositoryException(
181: org.osid.shared.SharedException.NO_MORE_ITERATOR_ELEMENTS);
182: }
183: /*
184: * Additional assets should be available from the server
185: */
186: if ((index >= populated) || (populated == 0)) {
187: /*
188: * The cache is depleted, request more assets
189: */
190: if (sessionContext.getInt("active") == 0) {
191: /*
192: * End-of-file? Every search has been marked "complete" (unxepected).
193: */
194: throw new org.osid.repository.RepositoryException(
195: org.osid.shared.SharedException.NO_MORE_ITERATOR_ELEMENTS);
196: }
197: /*
198: * Populate the Asset queue with new results
199: */
200: try {
201: populateAssetQueue();
202: } catch (SessionTimeoutException sessionTimeoutException) {
203: _log.error(sessionTimeoutException.getMessage());
204: throw new MetasearchException(
205: MetasearchException.SESSION_TIMED_OUT);
206: } catch (SearchException searchException) {
207: _log.error(searchException.getMessage());
208: throw new MetasearchException(
209: MetasearchException.METASEARCH_ERROR);
210: } catch (Throwable throwable) {
211: _log.error(throwable.getMessage());
212: throw new org.osid.repository.RepositoryException(
213: org.osid.OsidException.OPERATION_FAILED);
214: }
215: }
216: /*
217: * Finally, return the next Asset from the queue
218: */
219: asset = getAsset();
220: _log.debug("AssetIterator.nextAsset() returns asset = " + asset
221: + ", index = " + index + ", vector size = "
222: + assetVectorSize());
223: return asset;
224: }
225:
226: /*
227: * Helpers
228: */
229:
230: /**
231: * Fetch an Integer property value
232: * @param searchProperties Property list (search characteristics, provided by our caller)
233: * @name Property name to lookup
234: * @return Property value (cast as an Integer)
235: */
236: private Integer getIntegerProperty(
237: org.osid.shared.Properties searchProperties, String name)
238: throws org.osid.shared.SharedException {
239: return (Integer) searchProperties.getProperty(name);
240: }
241:
242: /*
243: * Asset queue
244: */
245:
246: /**
247: * Get the next asset from the queue, increment the index
248: * @return The next available asset (the asset is removed from the queue)
249: */
250: private synchronized org.osid.repository.Asset getAsset() {
251: org.osid.repository.Asset asset = (org.osid.repository.Asset) assetVector
252: .elementAt(0);
253:
254: assetVector.removeElementAt(0);
255: index++;
256:
257: return asset;
258: }
259:
260: /**
261: * Add an Asset to the end of the queue
262: * @param asset Asset to add
263: * @return the logical "size" of the queue
264: */
265: private synchronized int addAsset(org.osid.repository.Asset asset) {
266: assetVector.addElement(asset);
267: return ++populated;
268: }
269:
270: /**
271: * Get the size of the "physical" queue (the size() of the vector)
272: * @return Queue size (count of queued Asset elements)
273: */
274: private synchronized int assetVectorSize() {
275: return assetVector.size();
276: }
277:
278: /*
279: * Populate the Asset queue
280: */
281: private void populateAssetQueue()
282: throws org.osid.repository.RepositoryException,
283: org.osid.shared.SharedException
284:
285: {
286: HashMap parameterMap;
287: int assetsAdded;
288:
289: /*
290: * Search properties
291: */
292: parameterMap = new HashMap();
293: parameterMap.put("searchString", "");
294: parameterMap.put("database", database);
295:
296: parameterMap.put("guid", searchProperties.getProperty("guid"));
297: parameterMap
298: .put("url", searchProperties.getProperty("baseUrl"));
299:
300: parameterMap.put("sortBy", searchProperties
301: .getProperty("sortBy"));
302: parameterMap.put("maxRecords", getIntegerProperty(
303: searchProperties, "maxRecords"));
304: /*
305: * Search type (internal use only)
306: */
307: parameterMap.put("action", "requestResults");
308: /*
309: * Starting record, page size
310: */
311: sessionContext.putInt("startRecord", startRecord);
312: sessionContext.putInt("pageSize", pageSize);
313: /*
314: * Send the "more results" request, parse the server response
315: */
316: queryBase.parseRequest(parameterMap);
317: queryBase.doQuery();
318:
319: searchResult.initialize(queryBase);
320: searchResult.doParse();
321: /*
322: * Save the assets (matching records) returned frm the server
323: *
324: * These have been stored in an intermediate list of MatchItem objects,
325: * largely as "PartPairs", a part id/part content pair.
326: */
327: assetsAdded = 0;
328: for (Iterator iterator = searchResult.iterator(); iterator
329: .hasNext();) {
330: org.osid.repository.Asset asset;
331: org.osid.repository.Record record;
332: org.osid.repository.Part part;
333:
334: MatchItem item;
335: Iterator partPairIterator;
336:
337: item = (MatchItem) iterator.next();
338: /*
339: * Create a new Asset (what "content"?)
340: */
341: asset = new Asset(item.getDisplayName(), item
342: .getDescription(), getId(), repositoryId);
343: asset.updateContent("");
344: /*
345: * and Record
346: */
347: record = asset.createRecord(RecordStructure.getInstance()
348: .getId());
349: /*
350: * Populate the Record with all available Parts
351: */
352: partPairIterator = item.partPairIterator();
353: while (partPairIterator.hasNext()) {
354: MatchItem.PartPair partPair = (MatchItem.PartPair) partPairIterator
355: .next();
356: record
357: .createPart(partPair.getId(), partPair
358: .getValue());
359: }
360: /*
361: * Save this asset
362: */
363: addAsset(asset);
364: assetsAdded++;
365:
366: _log.debug("populate() Added " + asset + ", vector size = "
367: + assetVectorSize() + ", populated = " + populated);
368:
369: if (populated >= maximumRecords) {
370: break;
371: }
372: }
373: /*
374: * Update the starting record number
375: */
376: startRecord += Math.min(pageSize, assetsAdded);
377: sessionContext.putInt("startRecord", startRecord);
378: sessionContext.putInt("pageSize", pageSize);
379:
380: for (int i = 0; i < assetVectorSize(); i++) {
381: Asset asset = (Asset) assetVector.elementAt(i);
382: }
383: }
384:
385: private int idCount = 1;
386:
387: private synchronized String getId() {
388: return String.valueOf(idCount++);
389: }
390: }
|