Changeset 23913


Ignore:
Timestamp:
2011-04-16T20:16:19+12:00 (13 years ago)
Author:
ak19
Message:

Additional changes to succeed in more of the OAIServer validation tests: 1. Now passes POST requests introduced in OAI version 2.0. 2. Passes further error tests regarding handling of erroneous parameters for From and/or Until dates and ResumptionToken. More (major) changes yet to be made to pass the final official OAIServer validation test: to do with earliestDateStamp.

Location:
main/trunk/greenstone3/src/java/org/greenstone/gsdl3
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • main/trunk/greenstone3/src/java/org/greenstone/gsdl3/OAIServer.java

    r21802 r23913  
    2929import java.util.Enumeration;
    3030import java.util.HashSet;
     31import java.util.Iterator;
     32import java.util.Map;
     33import java.util.Map.Entry;
    3134import java.io.File;
    3235
     
    7881  protected String oai_stylesheet = "interfaces/oai/oai2.xsl";
    7982
     83    // there is no getQueryString() method in the HttpServletRequest returned from doPost,
     84    // since that is actually of type apache RequestFacade, and doesn't define such a method
     85    protected String queryString = null;
     86
    8087  static Logger logger = Logger.getLogger(org.greenstone.gsdl3.OAIServer.class.getName());
    8188 
     
    223230    String usageInfo = "";
    224231   
     232    String query = (queryString == null) ? request.getQueryString() : queryString;
     233
    225234    //logged info = general-info + session-info
    226235    usageInfo =
    227236      request.getContextPath()+" "+ //session id
    228237      request.getServletPath()+" "+ //serlvet
    229       "["+request.getQueryString()+"]" +" "+ //the query string
     238      "["+query+"]" +" "+ //the query string
    230239      "["+usageInfo.trim()+"]" +" "+ // params stored in a session
    231240      request.getRemoteAddr()+" "+   //remote address
     
    256265    return query.substring(verb_start_index, verb_end_index);
    257266  }
     267
    258268  public void doGet(HttpServletRequest request, HttpServletResponse response)
    259269    throws ServletException, IOException {
     
    276286    //For example, puka.cs.waikato.ac.nz vs www.greenstone.org
    277287    //String base_url = request.getRequestURL().toString();
    278     String query = request.getQueryString();
     288    // if called by doPost (if this was originally a POST request), var queryString would have been set
     289    String query = (queryString == null) ? request.getQueryString() : queryString;
    279290    String[] pairs = (query==null)? null : query.split("&");//split into key/value pairs
    280291    String verb = getVerb(query);
     
    377388    }
    378389  }
     390
     391  // For OAI version 2.0, validation tests indicated that POST needs to be supported. Some
     392  // modification was required in order to ensure that the request is passed intact to doGet()
    379393  public void doPost(HttpServletRequest request,
    380394    HttpServletResponse response)
    381395    throws ServletException, IOException {
     396
     397      // the post method returns a wrapper of type RequestFacade by apache and there
     398      // is no getQueryString() method defined for it. Therefore, need to work this out
     399      // manually before calling doGet(request, response) so that doGet can work as before.
     400     
     401      queryString = "";
     402      Iterator parameter_entries = request.getParameterMap().entrySet().iterator();
     403      while(parameter_entries.hasNext()) {   
     404      Map.Entry param_entry = (Map.Entry)parameter_entries.next();
     405      String[] paramVals = (String[]) param_entry.getValue();
     406      if(paramVals != null) {
     407          if(paramVals.length > 0) {
     408          logger.error("POST request received: " + param_entry.getKey() + " - " + paramVals[0]);
     409          queryString = queryString + "&" + param_entry.getKey() + "=" + paramVals[0];
     410          }
     411      }   
     412      }
     413      if(queryString.length() > 0) {
     414      queryString = queryString.substring(1);
     415      //queryString = java.net.URLEncoder.encode(queryString,"UTF-8");
     416      }
     417      if(queryString.equals("")) {
     418      queryString = null;
     419      }
    382420    doGet(request,response);   
    383421  }
  • main/trunk/greenstone3/src/java/org/greenstone/gsdl3/core/OAIReceptionist.java

    r23901 r23913  
    339339   
    340340    HashMap param_map = OAIXML.getParamMap(params);   
    341     if (!isValidParam(param_map, valid_strs) ||
    342         !param_map.containsKey(OAIXML.METADATA_PREFIX)) {
    343       logger.error("contains invalid params or no metadataPrefix");
    344       return getMessage(OAIXML.createErrorElement(OAIXML.BAD_ARGUMENT, ""));
     341    if (!isValidParam(param_map, valid_strs)) {
     342    logger.error("One of the params is invalid");
     343    return getMessage(OAIXML.createErrorElement(OAIXML.BAD_ARGUMENT, ""));
    345344    }
     345    // param keys are valid, but if there are any date params, check they're of the right format
     346    String from = (String)param_map.get(OAIXML.FROM);
     347    if(from != null) { 
     348    Date from_date = OAIXML.getDate(from);
     349    if(from_date == null) {
     350        logger.error("invalid date: " + from);
     351        return getMessage(OAIXML.createErrorElement(OAIXML.BAD_ARGUMENT, ""));
     352    }
     353    }
     354    String until = (String)param_map.get(OAIXML.UNTIL);
     355    if(until != null) {
     356    Date until_date = OAIXML.getDate(until);
     357    if(until_date == null) {
     358        logger.error("invalid date: " + until);
     359        return getMessage(OAIXML.createErrorElement(OAIXML.BAD_ARGUMENT, ""));
     360    }
     361    }   
     362    if(from != null && until != null) { // check they are of the same date-time format (granularity)
     363    if(from.length() != until.length()) {
     364        logger.error("The request has different granularities (date-time formats) for the From and Until date parameters.");
     365        return getMessage(OAIXML.createErrorElement(OAIXML.BAD_ARGUMENT, ""));
     366    }
     367    }
     368
    346369    //ask the message router for a list of oai collections
    347370    NodeList oai_coll = getOAICollectionList();
     
    350373      logger.info("returned oai collection list is empty");
    351374      return getMessage(OAIXML.createErrorElement(OAIXML.NO_RECORDS_MATCH, ""));
    352     }
    353     //Now that we got a prefix, check and see if it's supported by this repository
    354     String prefix_value = (String)param_map.get(OAIXML.METADATA_PREFIX);
    355     if (containsMetadataPrefix(prefix_value) == false) {
    356       logger.error("requested prefix is not found in OAIConfig.xml");
    357       return getMessage(OAIXML.createErrorElement(OAIXML.CANNOT_DISSEMINATE_FORMAT, ""));
    358375    }
    359376   
     
    390407    }
    391408   
     409    // Custom test that expects a metadataPrefix comes here at end so that the official params can
     410    // be tested first for errors and their error responses sent off. Required for OAI validation
     411    if (!param_map.containsKey(OAIXML.METADATA_PREFIX)) {
     412      logger.error("contains invalid params or no metadataPrefix");
     413      return getMessage(OAIXML.createErrorElement(OAIXML.BAD_ARGUMENT, ""));
     414    }   
     415   
     416    //Now that we got a prefix, check and see if it's supported by this repository
     417    String prefix_value = (String)param_map.get(OAIXML.METADATA_PREFIX);
     418    if (containsMetadataPrefix(prefix_value) == false) {
     419      logger.error("requested prefix is not found in OAIConfig.xml");
     420      return getMessage(OAIXML.createErrorElement(OAIXML.CANNOT_DISSEMINATE_FORMAT, ""));
     421    }
     422
    392423    //Now that all validation has been done, I hope, we can send request to the message router
    393424    Element result = null;
     
    519550   
    520551    HashMap param_map = OAIXML.getParamMap(params);   
    521     if (!isValidParam(param_map, valid_strs) ||
    522         !param_map.containsKey(OAIXML.METADATA_PREFIX)) {
    523       // it must have a metadataPrefix
    524       /** Here I disagree with the OAI specification: even if a resumptionToken is
    525        *  included in the request, the metadataPrefix is a must argument. Otherwise
    526        *  how would we know what metadataPrefix the harvester requested in his last request?
    527        */
    528       logger.error("no metadataPrefix");
    529       return getMessage(OAIXML.createErrorElement(OAIXML.BAD_ARGUMENT, ""));
    530     }
     552    if (!isValidParam(param_map, valid_strs)) {
     553    logger.error("One of the params is invalid");
     554    return getMessage(OAIXML.createErrorElement(OAIXML.BAD_ARGUMENT, ""));
     555    }
     556    // param keys are valid, but if there are any date params, check they're of the right format
     557    String from = (String)param_map.get(OAIXML.FROM);
     558    if(from != null) { 
     559    Date from_date = OAIXML.getDate(from);
     560    if(from_date == null) {
     561        logger.error("invalid date: " + from);
     562        return getMessage(OAIXML.createErrorElement(OAIXML.BAD_ARGUMENT, ""));
     563    }
     564    }
     565    String until = (String)param_map.get(OAIXML.UNTIL);
     566    Date until_date = null;
     567    if(until != null) {
     568    until_date = OAIXML.getDate(until);
     569    if(until_date == null) {
     570        logger.error("invalid date: " + until);
     571        return getMessage(OAIXML.createErrorElement(OAIXML.BAD_ARGUMENT, ""));
     572    }
     573    }
     574    if(from != null && until != null) { // check they are of the same date-time format (granularity)
     575    if(from.length() != until.length()) {
     576        logger.error("The request has different granularities (date-time formats) for the From and Until date parameters.");
     577        return getMessage(OAIXML.createErrorElement(OAIXML.BAD_ARGUMENT, ""));
     578    }
     579    }
    531580   
    532581    //ask the message router for a list of oai collections
     
    536585      logger.info("returned oai collection list is empty");
    537586      return getMessage(OAIXML.createErrorElement(OAIXML.NO_RECORDS_MATCH, ""));
    538     }
    539    
    540     //Now that we got a prefix, check and see if it's supported by this repository
    541     String prefix_value = (String)param_map.get(OAIXML.METADATA_PREFIX);
    542     if (containsMetadataPrefix(prefix_value) == false) {
    543       logger.error("requested prefix is not found in OAIConfig.xml");
    544       return getMessage(OAIXML.createErrorElement(OAIXML.CANNOT_DISSEMINATE_FORMAT, ""));
    545587    }
    546588   
     
    585627      }
    586628    }
     629
     630    // Moved the additional custom test that mandates the metadataPrefix here, since official
     631    // errors should be caught first, so that their error responses can be sent off first
     632    // such that GS2's oaiserver will validate properly.
     633    if (!param_map.containsKey(OAIXML.METADATA_PREFIX)) {
     634      // it must have a metadataPrefix
     635      /** Here I disagree with the OAI specification: even if a resumptionToken is
     636       *  included in the request, the metadataPrefix is a must argument. Otherwise
     637       *  how would we know what metadataPrefix the harvester requested in his last request?
     638       */
     639      logger.error("no metadataPrefix");
     640      return getMessage(OAIXML.createErrorElement(OAIXML.BAD_ARGUMENT, ""));
     641    }
     642       
     643    //Now that we got a prefix, check and see if it's supported by this repository
     644    String prefix_value = (String)param_map.get(OAIXML.METADATA_PREFIX);
     645    if (containsMetadataPrefix(prefix_value) == false) {
     646      logger.error("requested prefix is not found in OAIConfig.xml");
     647      return getMessage(OAIXML.createErrorElement(OAIXML.CANNOT_DISSEMINATE_FORMAT, ""));
     648    }
     649
    587650    //Now that all validation has been done, I hope, we can send request to the message router
    588651    Element result = null;
     
    790853        // get the names
    791854        strs = splitNames(identifier);
     855    if(strs == null || strs.length < 3) {
     856        logger.error("identifier is not in the form site:coll:id" + identifier);
     857        return getMessage(OAIXML.createErrorElement(OAIXML.ID_DOES_NOT_EXIST, ""));
     858    }
    792859        String name_of_site = strs[0];
    793860        String coll_name = strs[1];
     
    851918
    852919    //do the earliestDatestamp
    853     long lastmodified = System.currentTimeMillis();
    854920    //send request to mr to search through the earliest datestamp amongst all oai collections in the repository.
    855921    //ask the message router for a list of oai collections
    856922    NodeList oai_coll = getOAICollectionList();
    857     int oai_coll_size = oai_coll.getLength();
    858     if (oai_coll_size == 0) {
    859       logger.info("returned oai collection list is empty. Set repository earliestDatestamp to be 1970-01-01.");
    860       lastmodified = 0;
    861     }
    862     //the collection build time is determined by the last modified time of the buildConfig.xml file
    863     for(int i=0; i<oai_coll_size; i++) {
    864       long coll_build_time = Long.parseLong(((Element)oai_coll.item(i)).getAttribute(OAIXML.LASTMODIFIED));
    865       lastmodified = (lastmodified > coll_build_time)? coll_build_time : lastmodified;
    866     }
    867     String earliestDatestamp_str = OAIXML.getTime(lastmodified);
     923    long earliestDatestamp = getEarliestDateStamp(oai_coll);
     924    String earliestDatestamp_str = OAIXML.getTime(earliestDatestamp);
    868925    Element earliestDatestamp_elem = OAIXML.createElement(OAIXML.EARLIEST_DATESTAMP);
    869926    GSXML.setNodeText(earliestDatestamp_elem, earliestDatestamp_str);
     
    889946    String [] strs = new String[3];
    890947    int first_colon = identifier.indexOf(":");
     948    if(first_colon == -1) {
     949    return null;
     950    }
    891951    strs[0] = identifier.substring(0, first_colon);
    892952
     
    9711031    return converter.nodeToElement(result_node);
    9721032  }
     1033
     1034    // See OAIConfig.xml
     1035    // dynamically works out what the earliestDateStamp is, since it varies by collection
     1036    protected long getEarliestDateStamp(NodeList oai_coll) {
     1037    //do the earliestDatestamp
     1038    long lastmodified = System.currentTimeMillis();
     1039    int oai_coll_size = oai_coll.getLength();
     1040    if (oai_coll_size == 0) {
     1041        logger.info("returned oai collection list is empty. Setting repository earliestDatestamp to be 1970-01-01.");
     1042        lastmodified = 0;
     1043    }
     1044    //the collection build time is determined by the last modified time of the buildConfig.xml file
     1045    for(int i=0; i<oai_coll_size; i++) {
     1046        long coll_build_time = Long.parseLong(((Element)oai_coll.item(i)).getAttribute(OAIXML.LASTMODIFIED));
     1047        lastmodified = (lastmodified > coll_build_time)? coll_build_time : lastmodified;
     1048    }
     1049    return lastmodified;
     1050    }
    9731051}
  • main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/OAIXML.java

    r23862 r23913  
    161161    //stores the date format "yyyy-MM-ddTHH:mm:ssZ"
    162162    public static String granularity = "";
     163
     164    // http://www.openarchives.org/OAI/openarchivesprotocol.html#DatestampsRequests
     165    // specifies that all repositories must support YYYY-MM-DD (yyyy-MM-dd in Java)
     166    // this would be in addition to the other (optional) granularity of above that
     167    // a repository may additionally choose to support.
     168    public static final String default_granularity = "yyyy-MM-dd";
     169
    163170    //this value is overriden in getOAIConfigXML()
    164171    public static long token_expiration = 7200;
     
    312319      //initialize the granu_str which might be used by other methods (eg, getDate())
    313320      granularity = GSXML.getNodeText(granu_elem).trim();
     321
    314322      //change "yyyy-MM-ddTHH:mm:ssZ" to "yyyy-MM-dd'T'HH:mm:ss'Z'"
    315323      granularity = granularity.replaceAll("T", "'T'");
     
    462470        date = sdf.parse(pattern);
    463471      } catch(Exception e) {
    464         logger.error("invalid date format: " + pattern);
    465         return null;
     472      if(!default_granularity.equals(granularity)) { // try validating against default granularity
     473          try {
     474          date = null;
     475          sdf = null;
     476          sdf = new SimpleDateFormat(default_granularity);
     477          date = sdf.parse(pattern);
     478          } catch(Exception ex) {
     479          logger.error("invalid date format: " + pattern);
     480          return null;
     481          }
     482      } else {
     483          logger.error("invalid date format: " + pattern);
     484          return null;
     485      }
    466486      }
    467487      return date;
     
    481501        date = sdf.parse(pattern);
    482502      } catch(Exception e) {
    483         logger.error("invalid date format: " + pattern);
    484         return -1;
     503      if(!default_granularity.equals(granularity)) { // try validating against default granularity
     504          try {
     505          date = null;
     506          sdf = null;
     507          sdf = new SimpleDateFormat(default_granularity);
     508          date = sdf.parse(pattern);
     509          } catch(Exception ex) {
     510          logger.error("invalid date format: " + pattern);
     511          return -1;
     512          }
     513      } else {
     514          logger.error("invalid date format: " + pattern);
     515          return -1;
     516      }       
    485517      }
    486518      return date.getTime();
Note: See TracChangeset for help on using the changeset viewer.