0001: package org.sakaibrary.xserver;
0002:
0003: //Util imports
0004: import java.util.ArrayList;
0005:
0006: //I/O imports
0007: import java.io.ByteArrayInputStream;
0008: import java.io.ByteArrayOutputStream;
0009: import java.io.IOException;
0010: import java.io.InputStream;
0011:
0012: //URL/Network Connectivity imports
0013: import java.net.MalformedURLException;
0014: import java.net.URL;
0015: import java.net.HttpURLConnection;
0016:
0017: //SAX XML parsing imports
0018: import org.sakaibrary.osid.repository.xserver.SearchStatusProperties;
0019: import org.sakaibrary.xserver.session.MetasearchSession;
0020: import org.sakaibrary.xserver.session.MetasearchSessionManager;
0021: import org.xml.sax.*;
0022: import org.xml.sax.helpers.DefaultHandler;
0023: import javax.xml.parsers.SAXParserFactory;
0024: import javax.xml.parsers.SAXParser;
0025: import javax.xml.parsers.ParserConfigurationException;
0026:
0027: public class XServer extends DefaultHandler {
0028:
0029: // debugging
0030: boolean printXML = false;
0031:
0032: /* constants */
0033: private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory
0034: .getLog("org.sakaibrary.xserver.XServer");
0035: private static final String XSLT_FILE = "/xsl/xserver2sakaibrary.xsl";
0036:
0037: /* fields coming from searchProperties */
0038: private String guid; // required
0039: private String username; // required
0040: private String password; // required
0041: private String xserverBaseUrl; // required
0042: private ArrayList searchSourceIds; // required
0043: private String sortBy;
0044: private Integer pageSize;
0045: private Integer startRecord;
0046:
0047: /* session variables */
0048: private MetasearchSessionManager msm;
0049: private String sessionId;
0050: private String foundGroupNumber;
0051: private String mergedGroupNumber;
0052: private String setNumber;
0053:
0054: /* other member variables */
0055: // findResultSets keeps track of all result sets found
0056: private ArrayList findResultSets;
0057:
0058: // check authorization from X-server
0059: private String auth;
0060:
0061: // SAXParser variables
0062: private SAXParser saxParser;
0063:
0064: // text buffer to hold SAXParser character data
0065: private StringBuffer textBuffer;
0066:
0067: // create parser flags
0068: private boolean parsingMergeSort = false;
0069:
0070: // merge control flag
0071: private boolean singleSearchSource;
0072:
0073: //--------------
0074: // Constructor -
0075: //--------------
0076: /**
0077: * Creates a new XServer object ready to communicate with the
0078: * MetaLib X-server. Reads searchProperties, sets up SAX Parser, and
0079: * sets up session management for this object.
0080: */
0081: public XServer(String guid) throws XServerException {
0082: this .guid = guid;
0083:
0084: // setup the SAX parser
0085: SAXParserFactory factory;
0086: factory = SAXParserFactory.newInstance();
0087: factory.setNamespaceAware(true);
0088: try {
0089: saxParser = factory.newSAXParser();
0090: } catch (SAXException sxe) {
0091: // Error generated by this application
0092: // (or a parser-initialization error)
0093: Exception x = sxe;
0094:
0095: if (sxe.getException() != null) {
0096: x = sxe.getException();
0097: }
0098:
0099: LOG.warn(
0100: "XServer() SAX exception in trying to get a new SAXParser "
0101: + "from SAXParserFactory: "
0102: + sxe.getMessage(), x);
0103: throw new RuntimeException("XServer() SAX exception: "
0104: + sxe.getMessage(), x);
0105: } catch (ParserConfigurationException pce) {
0106: // Parser with specified options can't be built
0107: LOG
0108: .warn("XServer() SAX parser cannot be built with specified options");
0109: throw new RuntimeException(
0110: "XServer() SAX parser cannot be built with "
0111: + "specified options: " + pce.getMessage(),
0112: pce);
0113: }
0114:
0115: // load session state
0116: msm = MetasearchSessionManager.getInstance();
0117: MetasearchSession metasearchSession = msm
0118: .getMetasearchSession(guid);
0119:
0120: if (metasearchSession == null) {
0121: // bad state management
0122: throw new RuntimeException(
0123: "XServer() - ehcache MetasearchSession is "
0124: + "NULL :: guid is " + guid);
0125: }
0126:
0127: // get X-Server base URL
0128: xserverBaseUrl = metasearchSession.getBaseUrl();
0129:
0130: if (!metasearchSession.isLoggedIn()) {
0131: // need to login
0132: username = metasearchSession.getUsername();
0133: password = metasearchSession.getPassword();
0134:
0135: if (!loginURL(username, password)) {
0136: // authorization failed
0137: throw new XServerException("XServer.loginURL()",
0138: "authorization failed.");
0139: }
0140:
0141: // login success
0142: metasearchSession.setLoggedIn(true);
0143: metasearchSession.setSessionId(sessionId);
0144: }
0145:
0146: // get search properties
0147: org.osid.shared.Properties searchProperties = metasearchSession
0148: .getSearchProperties();
0149:
0150: try {
0151: searchSourceIds = (ArrayList) searchProperties
0152: .getProperty("searchSourceIds"); // empty TODO
0153: sortBy = (String) searchProperties.getProperty("sortBy");
0154: pageSize = (Integer) searchProperties
0155: .getProperty("pageSize");
0156: startRecord = (Integer) searchProperties
0157: .getProperty("startRecord");
0158: } catch (org.osid.shared.SharedException se) {
0159: LOG.warn(
0160: "XServer() failed to get search properties - will assign "
0161: + "defaults", se);
0162: }
0163:
0164: // assign defaults if necessary
0165: // TODO assign the updated values to the session... searchProperties is read-only, need to add additional fields to MetasearchSession.
0166: if (sortBy == null) {
0167: sortBy = "rank";
0168: }
0169:
0170: if (pageSize == null) {
0171: pageSize = new Integer(10);
0172: }
0173:
0174: if (startRecord == null) {
0175: startRecord = new Integer(1);
0176: }
0177:
0178: // check args
0179: if (startRecord.intValue() <= 0) {
0180: LOG
0181: .warn("XServer() - startRecord must be set to 1 or higher.");
0182: startRecord = null;
0183: startRecord = new Integer(1);
0184: }
0185:
0186: // add/update this MetasearchSession in the cache
0187: msm.putMetasearchSession(guid, metasearchSession);
0188: }
0189:
0190: //------------------------------------
0191: // METALIB X-SERVICE IMPLEMENTATIONS -
0192: //------------------------------------
0193:
0194: /**
0195: * Logs a user into the X-server using URL Syntax for communications.
0196: * Uses the login X-service.
0197: *
0198: * @param username String representing user username
0199: * @param password String representing user password
0200: *
0201: * @return boolean true if authorization succeeds, false otherwise.
0202: *
0203: * @throws XServerException if login fails due to X-server error
0204: */
0205: private boolean loginURL(String username, String password)
0206: throws XServerException {
0207: // build URL query string
0208: StringBuffer query = new StringBuffer(xserverBaseUrl);
0209: query.append("?op=login_request&user_name=" + username
0210: + "&user_password=" + password);
0211:
0212: // connect to URL and get response
0213: java.io.ByteArrayOutputStream xml = doURLConnection(query
0214: .toString());
0215:
0216: if (printXML) {
0217: // print xml
0218: LOG.debug(xml.toString());
0219: }
0220:
0221: // run SAX Parser
0222: try {
0223: saxParseXML(new java.io.ByteArrayInputStream(xml
0224: .toByteArray()));
0225: } catch (SAXException sxe) {
0226: // Error generated by this application
0227: // (or a parser-initialization error)
0228: Exception x = sxe;
0229:
0230: if (sxe.getException() != null) {
0231: x = sxe.getException();
0232: }
0233:
0234: LOG
0235: .warn("loginURL() SAX exception: "
0236: + sxe.getMessage(), x);
0237: } catch (IOException ioe) {
0238: // I/O error
0239: LOG.warn("loginURL() IO exception", ioe);
0240: }
0241:
0242: // return whether or not the login was successful
0243: return (loginSuccessful());
0244: }
0245:
0246: /**
0247: * Finds records within the given sources using the given find command
0248: * query. Uses the find X-service.
0249: *
0250: * @param findCommand String representing find_request_command. See
0251: * <a href="http://searchtools.lib.umich.edu/X/?op=explain&func=find">
0252: * find</a> explanation from MetaLib X-Server to see how
0253: * find_request_command should be built.
0254: *
0255: * @param waitFlag String representing the wait_flag. A "Y" indicates
0256: * the X-server will not produce a response until the find command has
0257: * completed. Full information about the group and each search set will
0258: * be returned.
0259: * <br></br>
0260: * A "N" indicates the X-server will immediately respond with the group
0261: * number while the find continues to run in the background. The user
0262: * can then use the findGroupInfo method to poll for results.
0263: *
0264: * @throws XServerException if find fails due to X-server error
0265: */
0266: private void findURL(String findCommand, String waitFlag)
0267: throws XServerException {
0268: // build a query string containing all sources that need to be searched
0269: StringBuffer findBaseString = new StringBuffer();
0270: for (int i = 0; i < searchSourceIds.size(); i++) {
0271: findBaseString.append("&find_base_001="
0272: + (String) searchSourceIds.get(i));
0273: }
0274:
0275: // build URL query string
0276: StringBuffer query = new StringBuffer(xserverBaseUrl);
0277: query.append("?op=find_request" + "&wait_flag=" + waitFlag
0278: + "&find_request_command=" + findCommand
0279: + findBaseString.toString() + "&session_id="
0280: + sessionId);
0281:
0282: // connect to URL and get response
0283: java.io.ByteArrayOutputStream xml = doURLConnection(query
0284: .toString());
0285:
0286: if (printXML) {
0287: // print xml
0288: LOG.debug(xml.toString());
0289: }
0290:
0291: // run SAX Parser
0292: try {
0293: saxParseXML(new java.io.ByteArrayInputStream(xml
0294: .toByteArray()));
0295: } catch (SAXException sxe) {
0296: // Error generated by this application
0297: // (or a parser-initialization error)
0298: Exception x = sxe;
0299:
0300: if (sxe.getException() != null) {
0301: x = sxe.getException();
0302: }
0303:
0304: LOG.warn("findURL() SAX exception: " + sxe.getMessage(), x);
0305: } catch (IOException ioe) {
0306: // I/O error
0307: LOG.warn("findURL() IO exception", ioe);
0308: }
0309: }
0310:
0311: /**
0312: * Gets information on a result set group which has already been created
0313: * using the find command in asynchronous mode (waitFlag set to "N")
0314: *
0315: * @throws XServerException if find_group_info fails due to X-Server error
0316: */
0317: private void findGroupInfoURL() throws XServerException {
0318: findResultSets = new java.util.ArrayList();
0319:
0320: StringBuffer query = new StringBuffer(xserverBaseUrl);
0321: query.append("?op=find_group_info_request" + "&group_number="
0322: + foundGroupNumber + "&session_id=" + sessionId);
0323:
0324: // connect to URL and get response
0325: java.io.ByteArrayOutputStream xml = doURLConnection(query
0326: .toString());
0327:
0328: if (printXML) {
0329: // print xml
0330: LOG.debug(xml.toString());
0331: }
0332:
0333: // run SAX Parser
0334: try {
0335: saxParseXML(new java.io.ByteArrayInputStream(xml
0336: .toByteArray()));
0337: } catch (SAXException sxe) {
0338: // Error generated by this application
0339: // (or a parser-initialization error)
0340: Exception x = sxe;
0341:
0342: if (sxe.getException() != null) {
0343: x = sxe.getException();
0344: }
0345:
0346: LOG.warn("findGroupInfoURL() SAX exception: "
0347: + sxe.getMessage(), x);
0348: } catch (IOException ioe) {
0349: // I/O error
0350: LOG.warn("findGroupInfoURL() IO exception", ioe);
0351: }
0352: }
0353:
0354: /**
0355: * Finds records within the given sources using the given find command
0356: * query. Uses the find X-service.
0357: *
0358: * @param action valid values: merge, merge_more, remerge, sort_only
0359: * @param primarySortKey valid values: rank, title, author, year, database
0360: *
0361: * @throws XServerException if mergeSort fails due to X-server error
0362: */
0363: private void mergeSortURL(String action, String primarySortKey)
0364: throws XServerException {
0365:
0366: if (primarySortKey == null) {
0367: // default to rank
0368: primarySortKey = "rank";
0369: }
0370:
0371: // build URL query string
0372: StringBuffer query = new StringBuffer(xserverBaseUrl);
0373: query.append("?op=merge_sort_request" + "&group_number="
0374: + foundGroupNumber + "&action=" + action
0375: + "&primary_sort_key=" + primarySortKey
0376: + "&session_id=" + sessionId);
0377:
0378: // connect to URL and get response
0379: java.io.ByteArrayOutputStream xml = doURLConnection(query
0380: .toString());
0381:
0382: if (printXML) {
0383: // print xml
0384: LOG.debug(xml.toString());
0385: }
0386:
0387: // run SAX Parser
0388: try {
0389: saxParseXML(new java.io.ByteArrayInputStream(xml
0390: .toByteArray()));
0391: } catch (SAXException sxe) {
0392: // Error generated by this application
0393: // (or a parser-initialization error)
0394: Exception x = sxe;
0395:
0396: if (sxe.getException() != null) {
0397: x = sxe.getException();
0398: }
0399:
0400: LOG.warn("mergeSortURL() SAX exception: "
0401: + sxe.getMessage(), x);
0402: } catch (IOException ioe) {
0403: // I/O error
0404: LOG.warn("mergeSortURL() IO exception", ioe);
0405: }
0406: }
0407:
0408: /**
0409: * Presents records found in the given set. Displays records in full MARC
0410: * format.
0411: *
0412: * @param setNumber identifier for a set to obtain records from
0413: * @param setEntry how many/which records to present
0414: * @throws XServerException
0415: */
0416: private ByteArrayOutputStream presentURL(String setNumber,
0417: String setEntry) throws XServerException {
0418:
0419: // build URL query string
0420: StringBuffer query = new StringBuffer(xserverBaseUrl);
0421: query.append("?op=present_request" + "&set_number=" + setNumber
0422: + "&set_entry=" + setEntry + "&format=marc"
0423: + "&view=full" +
0424:
0425: // "&view=customize" +
0426: // "&field=VOL%23%23" +
0427: // "&field=YR%23%23%23" +
0428: // "&field=ISSUE" +
0429: // "&field=PAGES" +
0430: // "&field=ISSU%23" +
0431: // "&field=PAGE%23" +
0432: // "&field=DATE%23" +
0433: // "&field=JT%23%23%23" +
0434: // "&field=DOI%23%23" +
0435: // "&field=245%23%23" + // title
0436: // "&field=520%23%23" + // abstract
0437: // "&field=100%23%23" + // author
0438: // "&field=700%23%23" + // secondary authors
0439: // "&field=022%23%23" + // issn
0440:
0441: "&session_id=" + sessionId);
0442:
0443: // connect to URL and get response
0444: ByteArrayOutputStream xml = doURLConnection(query.toString());
0445:
0446: if (printXML) {
0447: // print xml
0448: LOG.debug(xml.toString());
0449: }
0450:
0451: return xml;
0452: }
0453:
0454: /**
0455: * Returns a metasearchStatus Type Properties object describing this search's
0456: * status.
0457: *
0458: * @return metasearchStatus org.osid.shared.Properties
0459: */
0460: public org.osid.shared.Properties getSearchStatusProperties() {
0461: MetasearchSession metasearchSession = msm
0462: .getMetasearchSession(guid);
0463: return new SearchStatusProperties(metasearchSession
0464: .getSearchStatusProperties());
0465: }
0466:
0467: /**
0468: * Runs a blocking search of the X-Server and returns the response xml.
0469: *
0470: * @param numAssets number of records presented from the X-Server. Must be 0
0471: * or greater.
0472: * @return ByteArrayInputStream encapsulating response xml from the X-Server
0473: * @throws XServerException in case of X-Server error
0474: */
0475: public ByteArrayInputStream getRecordsXML(int numAssets)
0476: throws XServerException,
0477: org.osid.repository.RepositoryException {
0478: // check args
0479: if (numAssets < 0) {
0480: LOG.warn("getRecordsXML() - numAssets below zero.");
0481: numAssets = 0;
0482: }
0483:
0484: // check session state
0485: if (!checkSessionState()) {
0486: // throw invalid session exception (TODO use of RepositoryException = bad)
0487: throw new org.osid.repository.RepositoryException(
0488: org.sakaibrary.osid.repository.xserver.MetasearchException.SESSION_TIMED_OUT);
0489: }
0490:
0491: /* figure out whether to merge or not */
0492: MetasearchSession metasearchSession = msm
0493: .getMetasearchSession(guid);
0494: setNumber = metasearchSession.getRecordsSetNumber();
0495:
0496: if (setNumber == null) {
0497: // null setNumber indicates multiple search sources, do a merge
0498: LOG
0499: .debug("getRecordsXML() - doing merge, set number is null");
0500: mergeSortURL("merge", sortBy);
0501:
0502: // we'll be getting a new setNumber for the merged set, store it
0503: metasearchSession.setRecordsSetNumber(setNumber);
0504: metasearchSession.setMergedGroupNumber(mergedGroupNumber);
0505:
0506: // add/update this MetasearchSession in the cache
0507: msm.putMetasearchSession(guid, metasearchSession);
0508: } else {
0509: if (!singleSearchSource) {
0510: // do a merge_more if we're working with multiple search sources
0511: LOG
0512: .debug("getRecordsXML() - doing merge_more, set number "
0513: + "is " + setNumber);
0514: mergeSortURL("merge_more", sortBy);
0515: }
0516: }
0517:
0518: // determine which records to pull from the X-Server
0519: java.text.DecimalFormat df = new java.text.DecimalFormat(
0520: "000000000");
0521: String setEntryStart;
0522: String setEntryEnd;
0523: int setEntryStartValue;
0524:
0525: // starting record
0526: if (numAssets == 0) {
0527: // just beginning a search
0528: setEntryStart = df.format(startRecord.intValue());
0529: setEntryStartValue = startRecord.intValue();
0530: } else {
0531: // already conducted a search, continue from where we left off
0532: setEntryStart = df.format(numAssets + 1);
0533: setEntryStartValue = numAssets + 1;
0534: }
0535:
0536: // ending record
0537: Integer numRecords = (singleSearchSource) ? metasearchSession
0538: .getNumRecordsFetched() : metasearchSession
0539: .getNumRecordsMerged();
0540:
0541: if (numAssets == numRecords.intValue()) {
0542: // we've already returned all the records that the X-Server has.
0543: // need to wait longer
0544: // TODO - dangerous to throw a RepositoryException here...
0545: throw new org.osid.repository.RepositoryException(
0546: org.sakaibrary.osid.repository.xserver.MetasearchException.ASSET_NOT_FETCHED);
0547: }
0548:
0549: int setEntryEndValue = numRecords.intValue();
0550: if (numRecords.intValue() >= pageSize.intValue()
0551: + setEntryStartValue - 1) {
0552: setEntryEndValue = pageSize.intValue() + setEntryStartValue
0553: - 1;
0554: if (numRecords.intValue() >= pageSize.intValue() * 2
0555: + setEntryStartValue - 1) {
0556: // watch out if the user sets pageSize very large...
0557: setEntryEndValue = pageSize.intValue() * 2
0558: + setEntryStartValue - 1;
0559: }
0560: }
0561:
0562: setEntryEnd = df.format(setEntryEndValue);
0563: LOG.debug("getRecordsXML() - presenting records: "
0564: + setEntryStart + "-" + setEntryEnd);
0565:
0566: // run the present X-Service
0567: ByteArrayOutputStream cleanXml = presentURL(setNumber,
0568: setEntryStart + "-" + setEntryEnd);
0569:
0570: // transform the cleaned up xml
0571: XMLTransform xmlTransform = new XMLTransform(XSLT_FILE,
0572: cleanXml);
0573: ByteArrayOutputStream transformedXml = xmlTransform.transform();
0574:
0575: // return transformed xml bytes
0576: return new ByteArrayInputStream(transformedXml.toByteArray());
0577: }
0578:
0579: public void initAsynchSearch(String criteria,
0580: java.util.ArrayList sourceIds) throws XServerException {
0581: this .searchSourceIds = sourceIds;
0582:
0583: LOG.debug("initAsynchSearch() - searchSourceIds: "
0584: + searchSourceIds.size());
0585: if (searchSourceIds.size() == 1) {
0586: // only one search source - do not need to merge
0587: singleSearchSource = true;
0588: } else {
0589: singleSearchSource = false;
0590: }
0591:
0592: LOG.debug("initAsynchSearch() - find_command: " + criteria);
0593: // run the find X-Service in non-blocking mode
0594: findURL(criteria, "N");
0595:
0596: // add/update this MetasearchSession in the cache
0597: MetasearchSession metasearchSession = msm
0598: .getMetasearchSession(guid);
0599: metasearchSession.setFoundGroupNumber(foundGroupNumber);
0600: metasearchSession.setSingleSearchSource(singleSearchSource);
0601: msm.putMetasearchSession(guid, metasearchSession);
0602: }
0603:
0604: public void updateSearchStatusProperties() throws XServerException,
0605: org.osid.repository.RepositoryException {
0606: // check session state
0607: if (!checkSessionState()) {
0608: // throw invalid session exception (TODO use of RepositoryException = bad)
0609: throw new org.osid.repository.RepositoryException(
0610: org.sakaibrary.osid.repository.xserver.MetasearchException.SESSION_TIMED_OUT);
0611: }
0612:
0613: // run the find_group_info X-Service
0614: findGroupInfoURL();
0615:
0616: // setup search status properties
0617: MetasearchSession metasearchSession = msm
0618: .getMetasearchSession(guid);
0619: java.util.Properties searchStatusProperties = metasearchSession
0620: .getSearchStatusProperties();
0621:
0622: // set up other variables to determine search status properties
0623: java.util.ArrayList databaseNames = new java.util.ArrayList();
0624: java.util.HashMap databaseMap;
0625: String status = null;
0626: String statusMessage = null;
0627: int numRecordsFound = 0;
0628: int numRecordsFetched = 0;
0629: int numRecordsMerged = 0;
0630: int delayHint = 2500; // 2.5 seconds
0631: boolean ready = false;
0632: boolean fetching = false;
0633: boolean searching = false;
0634: boolean timeout = false;
0635: boolean error = false;
0636:
0637: // collect findGroupInfoURL results
0638: for (int i = 0; i < findResultSets.size(); i++) {
0639: FindResultSetBean frsb = (FindResultSetBean) findResultSets
0640: .get(i);
0641:
0642: // separate MERGESET info
0643: if (frsb.getBaseName().equals("MERGESET")) {
0644: setNumber = frsb.getSetNumber();
0645: if (frsb.getStatus().equals("DONE")) {
0646: status = "ready";
0647: statusMessage = "X-Server is ready to return records.";
0648: numRecordsMerged = Integer.parseInt(frsb
0649: .getNumDocs());
0650: } else if (frsb.getStatus().equals("FORK")
0651: || frsb.getStatus().equals("FIND")) {
0652: status = "searching";
0653: statusMessage = "X-Server is currently searching. Please wait.";
0654: } else if (frsb.getStatus().equals("FETCH")) {
0655: status = "fetching";
0656: statusMessage = "X-Server is currently fetching records. Please wait.";
0657: } else if (frsb.getStatus().equals("STOP")) {
0658: status = "timeout";
0659: statusMessage = "X-Server session has timed out. Please start a new session.";
0660: } else if (frsb.getStatus().equals("ERROR")) {
0661: status = "error";
0662: statusMessage = "An X-Server error has occurred ("
0663: + frsb.getFindErrorText()
0664: + "). Please try again.";
0665: }
0666: } else {
0667: setNumber = (singleSearchSource) ? frsb.getSetNumber()
0668: : null;
0669:
0670: // create a new Map entry for this database
0671: databaseMap = new java.util.HashMap();
0672: databaseMap.put("databaseName", frsb.getFullName());
0673:
0674: if (frsb.getStatus().equals("FORK")
0675: || frsb.getStatus().equals("FIND")) {
0676: searching = true;
0677: databaseMap.put("status", "searching");
0678: databaseMap.put("statusMessage",
0679: "Currently searching. Please wait.");
0680: } else if (frsb.getStatus().equals("FETCH")) {
0681: fetching = true;
0682: databaseMap.put("status", "fetching");
0683: databaseMap.put("statusMessage",
0684: "Currently fetching records. Please wait.");
0685: databaseMap.put("numRecordsFound", new Integer(frsb
0686: .getNumDocs()));
0687: numRecordsFound += Integer.parseInt(frsb
0688: .getNumDocs());
0689: } else if (frsb.getStatus().equals("DONE1")) {
0690: ready = true;
0691: databaseMap.put("status", "ready");
0692: databaseMap.put("statusMessage",
0693: "Fetched 10 records.");
0694: databaseMap.put("numRecordsFound", new Integer(frsb
0695: .getNumDocs()));
0696: databaseMap.put("numRecordsFetched",
0697: new Integer(10));
0698: numRecordsFound += Integer.parseInt(frsb
0699: .getNumDocs());
0700: numRecordsFetched += 10;
0701: } else if (frsb.getStatus().equals("DONE2")) {
0702: ready = true;
0703: databaseMap.put("status", "ready");
0704: databaseMap.put("statusMessage",
0705: "Fetched 20 records.");
0706: databaseMap.put("numRecordsFound", new Integer(frsb
0707: .getNumDocs()));
0708: databaseMap.put("numRecordsFetched",
0709: new Integer(20));
0710: numRecordsFound += Integer.parseInt(frsb
0711: .getNumDocs());
0712: numRecordsFetched += 20;
0713: } else if (frsb.getStatus().equals("DONE3")) {
0714: ready = true;
0715: databaseMap.put("status", "ready");
0716: databaseMap.put("statusMessage",
0717: "Fetched 30 records.");
0718: databaseMap.put("numRecordsFound", new Integer(frsb
0719: .getNumDocs()));
0720: databaseMap.put("numRecordsFetched",
0721: new Integer(30));
0722: numRecordsFound += Integer.parseInt(frsb
0723: .getNumDocs());
0724: numRecordsFetched += 30;
0725: } else if (frsb.getStatus().equals("DONE")) {
0726: if (Integer.parseInt(frsb.getNumDocs()) > 0) {
0727: // have results
0728: ready = true;
0729: databaseMap.put("status", "ready");
0730: databaseMap.put("statusMessage",
0731: "Fetched ALL records.");
0732: databaseMap.put("numRecordsFound", new Integer(
0733: frsb.getNumDocs()));
0734: databaseMap.put("numRecordsFetched",
0735: new Integer(frsb.getNumDocs()));
0736: numRecordsFound += Integer.parseInt(frsb
0737: .getNumDocs());
0738: numRecordsFetched += Integer.parseInt(frsb
0739: .getNumDocs());
0740: } else {
0741: // no results
0742: databaseMap.put("status", "empty");
0743: databaseMap.put("statusMessage",
0744: "No records found.");
0745: databaseMap.put("numRecordsFound", new Integer(
0746: frsb.getNumDocs()));
0747: databaseMap.put("numRecordsFetched",
0748: new Integer(0));
0749: }
0750: } else if (frsb.getStatus().equals("STOP")) {
0751: timeout = true;
0752: databaseMap.put("status", "timeout");
0753: databaseMap
0754: .put("statusMessage",
0755: "X-Server session has timed out. Please start a new session.");
0756: numRecordsFound += Integer.parseInt(frsb
0757: .getNumDocs());
0758: } else if (frsb.getStatus().equals("ERROR")) {
0759: error = true;
0760: databaseMap.put("status", "error");
0761: databaseMap.put("statusMessage",
0762: "An X-Server error has occurred ("
0763: + frsb.getFindErrorText()
0764: + "). Please try again.");
0765: statusMessage = "An X-Server error has occurred ("
0766: + frsb.getFindErrorText()
0767: + "). Please try again.";
0768: numRecordsFound += Integer.parseInt(frsb
0769: .getNumDocs());
0770: }
0771:
0772: // add this Map to the Properties object
0773: searchStatusProperties.put(frsb.getFullName(),
0774: databaseMap);
0775:
0776: // add the database name to databaseNames array
0777: databaseNames.add(frsb.getFullName());
0778: }
0779: }
0780:
0781: // determine status of search set
0782: if (status == null) {
0783: // a merge has not been done
0784: if (ready) {
0785: searchStatusProperties.put("status", "ready");
0786: searchStatusProperties.put("statusMessage",
0787: "X-Server is ready to return records.");
0788: } else if (fetching) {
0789: searchStatusProperties.put("status", "fetching");
0790: searchStatusProperties.put("statusMessage",
0791: "Currently searching. Please wait.");
0792: } else if (searching) {
0793: searchStatusProperties.put("status", "searching");
0794: searchStatusProperties.put("statusMessage",
0795: "Currently fetching records. Please wait.");
0796: } else if (timeout) {
0797: searchStatusProperties.put("status", "timeout");
0798: searchStatusProperties
0799: .put("statusMessage",
0800: "X-Server session has timed out. Please start a new session.");
0801: } else if (error) {
0802: searchStatusProperties.put("status", "error");
0803: searchStatusProperties.put("statusMessage",
0804: statusMessage);
0805: } else if (!ready) {
0806: // absolutely no records found
0807: searchStatusProperties.put("status", "empty");
0808: searchStatusProperties.put("statusMessage",
0809: "No records found for your query.");
0810: }
0811: } else {
0812: // a merge has been done
0813: searchStatusProperties.put("status", status);
0814: searchStatusProperties.put("statusMessage", statusMessage);
0815: }
0816:
0817: // update properties
0818: searchStatusProperties.put("delayHint", new Integer(delayHint));
0819: searchStatusProperties.put("databaseNames", databaseNames);
0820: searchStatusProperties.put("numRecordsFound", new Integer(
0821: numRecordsFound));
0822: searchStatusProperties.put("numRecordsFetched", new Integer(
0823: numRecordsFetched));
0824: searchStatusProperties.put("numRecordsMerged", new Integer(
0825: numRecordsMerged));
0826:
0827: // add/update this MetasearchSession in the cache
0828: metasearchSession
0829: .setSearchStatusProperties(searchStatusProperties);
0830: metasearchSession.setRecordsSetNumber(setNumber);
0831: metasearchSession.setNumRecordsFound(new Integer(
0832: numRecordsFound));
0833: metasearchSession.setNumRecordsFetched(new Integer(
0834: numRecordsFetched));
0835: metasearchSession.setNumRecordsMerged(new Integer(
0836: numRecordsMerged));
0837: msm.putMetasearchSession(guid, metasearchSession);
0838: }
0839:
0840: //-----------------------------
0841: // PUBLIC DATA ACCESS METHODS |
0842: //-----------------------------
0843:
0844: /**
0845: * Returns the list of find result sets found during this session. This
0846: * method should be called only after calling the findURL method.
0847: *
0848: * @return array of FindResultSetBeans encapsulating a list of result sets
0849: * provided by the find X-service data
0850: */
0851: public ArrayList getFindResultSets() {
0852: return findResultSets;
0853: }
0854:
0855: //----------------------------------
0856: // DEFAULT HANDLER IMPLEMENTATIONS -
0857: //----------------------------------
0858:
0859: /**
0860: * Receive notification of the beginning of an element.
0861: *
0862: * @see DefaultHandler
0863: */
0864: public void startElement(String namespaceURI, String sName,
0865: String qName, Attributes attrs) throws SAXException {
0866: // set flags to avoid overwriting duplicate tag data
0867: if (qName.equals("merge_sort_response")) {
0868: parsingMergeSort = true;
0869: }
0870: }
0871:
0872: /**
0873: * Receive notification of the end of an element.
0874: *
0875: * @see DefaultHandler
0876: */
0877: public void endElement(String namespaceURI, String sName,
0878: String qName) throws SAXException {
0879: // extract data
0880: extractDataFromText(qName);
0881:
0882: // clear flags
0883: if (qName.equals("merge_sort_response")) {
0884: parsingMergeSort = false;
0885: }
0886: }
0887:
0888: /**
0889: * Receive notification of character data inside an element.
0890: *
0891: * @see DefaultHandler
0892: */
0893: public void characters(char[] buf, int offset, int len)
0894: throws SAXException {
0895: // store character data
0896: String text = new String(buf, offset, len);
0897:
0898: if (textBuffer == null) {
0899: textBuffer = new StringBuffer(text);
0900: } else {
0901: textBuffer.append(text);
0902: }
0903: }
0904:
0905: //-------------------------
0906: // PRIVATE HELPER METHODS -
0907: //-------------------------
0908:
0909: private void extractDataFromText(String element) {
0910: if (textBuffer == null) {
0911: return;
0912: }
0913:
0914: String text = textBuffer.toString().trim();
0915: if (text.equals("")) {
0916: return;
0917: }
0918:
0919: /* login */
0920: else if (element.equals("session_id")) {
0921: sessionId = text;
0922: } else if (element.equals("auth")) {
0923: auth = text;
0924: }
0925:
0926: /* find */
0927: else if (element.equals("group_number")) {
0928: // merge_sort will also return a group_number
0929: if (parsingMergeSort) {
0930: mergedGroupNumber = text;
0931: } else {
0932: foundGroupNumber = text;
0933: }
0934: }
0935:
0936: /* find_group_info */
0937: else if (element.equals("base")) {
0938: // add FindResultSetBean to FindResultSet array, findResultSets
0939: findResultSets.add(new FindResultSetBean(text));
0940: }
0941:
0942: else if (element.equals("full_name")) {
0943: // result set's resource full name
0944: ((FindResultSetBean) findResultSets.get(findResultSets
0945: .size() - 1)).setFullName(text);
0946: }
0947:
0948: else if (element.equals("base_001")) {
0949: // result set resource id
0950: ((FindResultSetBean) findResultSets.get(findResultSets
0951: .size() - 1)).setSourceId(text);
0952: }
0953:
0954: else if (element.equals("set_number")) {
0955: // result set's set number
0956: ((FindResultSetBean) findResultSets.get(findResultSets
0957: .size() - 1)).setSetNumber(text);
0958: }
0959:
0960: else if (element.equals("find_status")) {
0961: // result set's status
0962: ((FindResultSetBean) findResultSets.get(findResultSets
0963: .size() - 1)).setStatus(text);
0964: }
0965:
0966: else if (element.equals("find_error_text")) {
0967: // if status is ERROR, extract error text
0968: ((FindResultSetBean) findResultSets.get(findResultSets
0969: .size() - 1)).setFindErrorText(text);
0970: }
0971:
0972: else if (element.equals("no_of_documents")) {
0973: if (!parsingMergeSort) {
0974: // number of documents in result set
0975: ((FindResultSetBean) findResultSets.get(findResultSets
0976: .size() - 1)).setNumDocs(text);
0977: } else {
0978: MetasearchSession ms = msm.getMetasearchSession(guid);
0979: ms.setNumRecordsMerged(new Integer(text));
0980: msm.putMetasearchSession(guid, ms);
0981: }
0982: }
0983:
0984: /* merge_sort */
0985: else if (element.equals("new_set_number")) {
0986: setNumber = text;
0987: }
0988:
0989: textBuffer = null;
0990: }
0991:
0992: /**
0993: * Check for invalid session state
0994: */
0995: private boolean checkSessionState() {
0996: // a search (find X-Service) should have been conducted
0997: MetasearchSession metasearchSession = msm
0998: .getMetasearchSession(guid);
0999: if (metasearchSession == null
1000: || !metasearchSession.isLoggedIn()
1001: || metasearchSession.getSessionId() == null
1002: || metasearchSession.getFoundGroupNumber() == null
1003: || metasearchSession.getSearchProperties() == null) {
1004: if (metasearchSession == null) {
1005: LOG
1006: .error("checkSessionState() - session state out of sync:"
1007: + "\n guid: "
1008: + guid
1009: + "\n MetasearchSession: null");
1010: } else {
1011: LOG
1012: .error("checkSessionState() - session state out of sync:"
1013: + "\n guid: "
1014: + guid
1015: + "\n MetasearchSession: "
1016: + metasearchSession
1017: + "\n logged in: "
1018: + metasearchSession.isLoggedIn()
1019: + "\n sessionId: "
1020: + metasearchSession.getSessionId()
1021: + "\n foundGroupNumber: "
1022: + metasearchSession
1023: .getFoundGroupNumber()
1024: + "\n searchProperties: "
1025: + metasearchSession
1026: .getSearchProperties());
1027: }
1028: return false;
1029: } else {
1030: this .sessionId = metasearchSession.getSessionId();
1031: this .foundGroupNumber = metasearchSession
1032: .getFoundGroupNumber();
1033: this .singleSearchSource = metasearchSession
1034: .isSingleSearchSource();
1035: return true;
1036: }
1037: }
1038:
1039: /**
1040: * Setup a URL Connection, get an InputStream for parsing
1041: *
1042: * @param urlQuery String with URL Query for X-server
1043: */
1044: private ByteArrayOutputStream doURLConnection(String urlQuery)
1045: throws XServerException {
1046: ByteArrayOutputStream xml = null;
1047:
1048: try {
1049: // define URL
1050: URL url = new URL(urlQuery);
1051:
1052: // open a connection to X-server
1053: HttpURLConnection urlConn = (HttpURLConnection) url
1054: .openConnection();
1055:
1056: XMLCleanup xmlCleanup = new XMLCleanup();
1057: xml = xmlCleanup.cleanup(urlConn.getInputStream());
1058:
1059: // disconnect
1060: urlConn.disconnect();
1061: } catch (MalformedURLException mue) {
1062: LOG.warn("doURLConnection() - malformed URL: "
1063: + mue.getMessage());
1064: } catch (IOException ioe) {
1065: LOG.warn("doURLConnection() - IO exception: "
1066: + ioe.getMessage());
1067: } catch (XServerException xse) {
1068: // update searchStatusProperties
1069: MetasearchSession metasearchSession = msm
1070: .getMetasearchSession(guid);
1071: java.util.Properties searchStatusProperties = metasearchSession
1072: .getSearchStatusProperties();
1073: searchStatusProperties.put("status", "error");
1074: searchStatusProperties.put("statusMessage", xse
1075: .getErrorText());
1076: metasearchSession
1077: .setSearchStatusProperties(searchStatusProperties);
1078: msm.putMetasearchSession(guid, metasearchSession);
1079:
1080: // re-throw the exception now that status has been updated
1081: throw xse;
1082: }
1083:
1084: return xml;
1085: }
1086:
1087: /**
1088: * Initiate the SAX Parser with the given InputStream.
1089: *
1090: * @param is InputStream to parse
1091: *
1092: * @throws IOException
1093: * @throws SAXException
1094: */
1095: private void saxParseXML(InputStream is) throws IOException,
1096: SAXException {
1097: // run the SAX Parser
1098: saxParser.parse(is, this );
1099: is.close();
1100: }
1101:
1102: /**
1103: * Validate login X-service
1104: *
1105: * @return true if succesful, false otherwise
1106: */
1107: private boolean loginSuccessful() {
1108: if (auth != null && auth.equals("N")) {
1109: return false;
1110: }
1111: return true;
1112: }
1113: }
|