Changeset 23913

Show
Ignore:
Timestamp:
16.04.2011 20:16:19 (9 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 modified

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();