package edu.indiana.lib.osid.base.repository.http;
import edu.indiana.lib.twinpeaks.net.*;
import edu.indiana.lib.twinpeaks.search.*;
import edu.indiana.lib.twinpeaks.util.*;
import java.io.*;
import java.net.*;
import java.lang.*;
import java.util.*;
/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/citations/trunk/citations-osid/web2bridge/src/java/edu/indiana/lib/osid/base/repository/http/AssetIterator.java $
* $Id: AssetIterator.java 105079 2012-02-24 23:08:11Z ottenhoff@longsight.com $
**********************************************************************************
*
* Copyright (c) 2003, 2004, 2005, 2007, 2008 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
/**
* @author Massachusetts Institute of Techbology, Sakai Software Development Team
* @version
*/
public class AssetIterator extends edu.indiana.lib.osid.base.repository.AssetIterator
{
private static org.apache.commons.logging.Log _log = edu.indiana.lib.twinpeaks.util.LogUtils.getLog(AssetIterator.class);
private org.osid.shared.Properties searchProperties;
private org.osid.shared.Id repositoryId;
/*
* HTTP transaction information
*/
private QueryBase queryBase;
private SearchResultBase searchResult;
private SessionContext sessionContext;
private String database;
/*
* Asset vector (a queue) and various details
*/
private AssetIterator assetIterator;
private Vector assetVector;
private int index;
private int populated;
private int startRecord;
private int pageSize;
/**
* Unused constructor
*/
protected AssetIterator(Vector vector)
{
}
/**
* Constructor
*
* @param database The database (or target) for this search
* @queryBase Query handler (QueryBase implementation)
* @searchResult Search result handler (SearchResultBase implementation)
* @param searchProperties Property list (search characteristics, provided by our caller)
* @param repositoryId Unique Repository ID
* @param sessionContext Context data for the current user/caller
*/
protected AssetIterator(String database,
QueryBase queryBase,
SearchResultBase searchResult,
org.osid.shared.Properties searchProperties,
org.osid.shared.Id repositoryId,
SessionContext sessionContext)
throws org.osid.repository.RepositoryException
{
try
{
this.database = database;
this.queryBase = queryBase;
this.searchResult = searchResult;
this.repositoryId = repositoryId;
this.sessionContext = sessionContext;
this.assetIterator = null;
initialize(searchProperties);
}
catch (Throwable throwable)
{
_log.error("AssetIterator() " + throwable);
throw new org.osid.repository.RepositoryException(org.osid.shared.SharedException.OPERATION_FAILED);
}
}
/**
* Initialize
* @param searchProperties Property list (search characteristics, provided by our caller)
*/
protected void initialize(org.osid.shared.Properties searchProperties) throws org.osid.shared.SharedException
{
try
{
this.assetVector = new Vector();
this.index = 0;
this.populated = 0;
/*
* Save starting record number, page size, properties pointer
*/
startRecord = getIntegerProperty(searchProperties, "startRecord").intValue();
pageSize = getIntegerProperty(searchProperties, "pageSize").intValue();
this.searchProperties = searchProperties;
_log.debug("AssetIterator max = " + getMaximumRecords() + ", page = " + pageSize + ", start = " + startRecord);
}
catch (Throwable throwable)
{
_log.error("initialize() " + throwable);
throw new org.osid.repository.RepositoryException(org.osid.shared.SharedException.OPERATION_FAILED);
}
}
/**
* Is another Asset available? If so, set the search status as "complete".
* @return true if an Asset is available, false if not
*/
public boolean hasNextAsset()
throws org.osid.repository.RepositoryException
{
try
{
boolean moreRecords;
_log.debug("hasNextAsset: index=" + index
+ ", maximum records=" + getMaximumRecords()
+ ", async init=" + StatusUtils.doingAsyncInit(sessionContext));
/*
* During asynchronous initialization, we assume there are more assets
*/
if (StatusUtils.doingAsyncInit(sessionContext))
{
return true;
}
/*
* Normal use, are there any more assets?
*/
moreRecords = (index < getMaximumRecords());
_log.debug("AssetIterator.hasNext() = " + moreRecords);
if (!moreRecords)
{
StatusUtils.setAllComplete(sessionContext);
}
return moreRecords;
}
catch (Throwable throwable)
{
_log.error("hasNextAsset() " + throwable);
throw new org.osid.repository.RepositoryException(org.osid.shared.SharedException.OPERATION_FAILED);
}
}
/**
* Fetch the next available search result (from the "Asset queue")
* @return The next search result (as an Asset)
*/
public org.osid.repository.Asset nextAsset()
throws org.osid.repository.RepositoryException
{
org.osid.repository.Asset asset;
/*
* End-of-file?
*/
if (!StatusUtils.doingAsyncInit(sessionContext))
{
if (index >= getMaximumRecords())
{
StatusUtils.setAllComplete(sessionContext);
throw new org.osid.repository.RepositoryException(org.osid.shared.SharedException.NO_MORE_ITERATOR_ELEMENTS);
}
}
/*
* Additional assets should be available from the server
*/
_log.debug("nextAsset: index=" + index
+ ", populated=" + populated
+ ", async init=" + StatusUtils.doingAsyncInit(sessionContext));
if ((index >= populated) || (populated == 0))
{
if (!StatusUtils.doingAsyncInit(sessionContext))
{ /*
* The cache is depleted - we need to fetch more assets
*/
if (sessionContext.getInt("active") == 0)
{ /*
* Every search has been marked "complete" (unexepected).
*/
throw new org.osid.repository.RepositoryException(org.osid.shared.SharedException.NO_MORE_ITERATOR_ELEMENTS);
}
}
/*
* Populate the Asset queue with new results
*/
try
{
populateAssetQueue();
}
catch (SessionTimeoutException sessionTimeoutException)
{
_log.error("nextAsset() session timeout: " + sessionTimeoutException);
throw new MetasearchException(MetasearchException.SESSION_TIMED_OUT);
}
catch (SearchException searchException)
{ /*
* No assets ready?
*/
if (searchException.getMessage().equals(SearchException.ASSET_NOT_READY))
{
throw new MetasearchException(MetasearchException.ASSET_NOT_FETCHED);
}
/*
* Unexpected error
*/
_log.error("nextAsset() search exception: " + searchException);
throw new MetasearchException(MetasearchException.METASEARCH_ERROR);
}
catch (Throwable throwable)
{
_log.error("nextAsset() general: ", throwable);
throw new org.osid.repository.RepositoryException(org.osid.OsidException.OPERATION_FAILED);
}
}
/*
* Finally, return the next Asset from the queue
*/
asset = getAsset();
_log.debug("AssetIterator.nextAsset() returns asset at index " + index + ", vector size = " + assetVectorSize());
return asset;
}
/*
* Helpers
*/
private int getMaximumRecords()
{
return sessionContext.getInt("maxRecords");
}
/**
* Fetch an Integer property value
* @param searchProperties Property list (search characteristics, provided by our caller)
* @name Property name to lookup
* @return Property value (cast as an Integer)
*/
private Integer getIntegerProperty(org.osid.shared.Properties searchProperties,
String name)
throws org.osid.shared.SharedException
{
return (Integer) searchProperties.getProperty(name);
}
/*
* Asset queue
*/
/**
* Get the next asset from the queue, increment the index
* @return The next available asset (the asset is removed from the queue)
*/
private synchronized org.osid.repository.Asset getAsset()
{
org.osid.repository.Asset asset = (org.osid.repository.Asset) assetVector.elementAt(0);
assetVector.removeElementAt(0);
index++;
return asset;
}
/**
* Add an Asset to the end of the queue
* @param asset Asset to add
* @return the logical "size" of the queue
*/
private synchronized int addAsset(org.osid.repository.Asset asset)
{
assetVector.addElement(asset);
return ++populated;
}
/**
* Get the size of the "physical" queue (the size() of the vector)
* @return Queue size (count of queued Asset elements)
*/
private synchronized int assetVectorSize()
{
return assetVector.size();
}
/*
* Populate the Asset queue
*/
private void populateAssetQueue()
throws org.osid.repository.RepositoryException, org.osid.shared.SharedException
{
HashMap parameterMap;
int assetsAdded;
/*
* Search properties
*/
parameterMap = new HashMap();
parameterMap.put("searchString", "");
parameterMap.put("database", database);
parameterMap.put("guid", searchProperties.getProperty("guid"));
parameterMap.put("url", searchProperties.getProperty("baseUrl"));
parameterMap.put("sortBy", searchProperties.getProperty("sortBy"));
parameterMap.put("maxRecords", getIntegerProperty(searchProperties, "maxRecords"));
/*
* Search type (internal use only)
*/
parameterMap.put("action", "requestResults");
/*
* Starting record, page size
*/
sessionContext.putInt("startRecord", startRecord);
sessionContext.putInt("pageSize", pageSize);
/*
* Send the "more results" request, parse the server response
*/
queryBase.parseRequest(parameterMap);
queryBase.doQuery();
searchResult.initialize(queryBase);
searchResult.doParse();
/*
* Save the assets (matching records) returned frm the server
*
* These have been stored in an intermediate list of MatchItem objects,
* largely as "PartPairs", a part id/part content pair.
*/
assetsAdded = 0;
for (Iterator iterator = searchResult.iterator(); iterator.hasNext(); )
{
org.osid.repository.Asset asset;
org.osid.repository.Record record;
org.osid.repository.Part part;
MatchItem item;
Iterator partPairIterator;
item = (MatchItem) iterator.next();
/*
* Create a new Asset (what "content"?)
*/
asset = new Asset(item.getDisplayName(), item.getDescription(),
getId(), repositoryId);
asset.updateContent("");
/*
* and Record
*/
record = asset.createRecord(RecordStructure.getInstance().getId());
/*
* Populate the Record with all available Parts
*/
partPairIterator = item.partPairIterator();
while (partPairIterator.hasNext())
{
MatchItem.PartPair partPair = (MatchItem.PartPair) partPairIterator.next();
record.createPart(partPair.getId(), partPair.getValue());
}
/*
* Save this asset
*/
addAsset(asset);
assetsAdded++;
// _log.debug("populate() Added " + asset
// + ", vector size = " + assetVectorSize()
// + ", populated = " + populated);
if (populated >= getMaximumRecords())
{
break;
}
}
/*
* Update the starting record number
*/
startRecord += assetsAdded; // WAS: Math.min(pageSize, assetsAdded);
sessionContext.putInt("startRecord", startRecord);
sessionContext.putInt("pageSize", pageSize);
}
private int idCount = 1;
private synchronized String getId()
{
return String.valueOf(idCount++);
}
}