Changeset 28851

Show
Ignore:
Timestamp:
27.02.2014 11:27:40 (6 years ago)
Author:
kjdon
Message:

tidied up OAIXML. Moved out any generic methods. Split off resumption token code to OAIResumptionToken.java, apart from the bit where we generate the XML for the OAI response. resumption token todo: still have to handle expiring old tokens.

Location:
main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util
Files:
1 added
1 modified

Legend:

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

    r28846 r28851  
    2828import java.text.DateFormat; 
    2929import java.text.SimpleDateFormat; 
    30 import org.apache.xerces.parsers.*; 
    31 import org.apache.xml.serialize.*; 
    32  
    33 // SAX 
    34 import org.xml.sax.XMLReader; 
    35 import org.xml.sax.SAXException; 
    36 import org.xml.sax.SAXParseException; 
    37 import org.xml.sax.helpers.DefaultHandler; 
    38 import org.xml.sax.InputSource; 
    39  
    40 // JAXP 
    41 import javax.xml.parsers.FactoryConfigurationError; 
    42 import javax.xml.parsers.ParserConfigurationException; 
    43 import javax.xml.parsers.SAXParser; 
    44 import javax.xml.parsers.SAXParserFactory; 
    4530 
    4631// import file Logger.java 
     
    6348  public static final String IDENTIFY = "Identify"; 
    6449 
    65   // other valid oai parameters 
    66   public static final String OAI_METADATAFORMAT = "OAIMetadataFormat"; 
    67   public static final String METADATA_NAMESPACE = "metadataNamespace"; 
    68   public static final String OAI_DC = "oai_dc"; 
    69   public static final String DC = "dc"; 
     50  // oai request parameters 
    7051  public static final String METADATA_PREFIX = "metadataPrefix"; 
    7152  public static final String FROM = "from"; 
     
    7354  public static final String SET = "set"; 
    7455  public static final String RESUMPTION_TOKEN = "resumptionToken"; 
    75   public static final String RESUMPTION_TOKEN_EXPIRATION = "resumptionTokenExpiration"; 
    7656  public static final String IDENTIFIER = "identifier"; 
    7757 
    78   public static final String USE_STYLESHEET = "useOAIStylesheet"; 
    79   public static final String STYLESHEET = "OAIStylesheet"; 
    80    
    81   // words used to compose oai responses and read in OAIConfig.xml 
    82   public static final String ADMIN_EMAIL = "adminEmail"; 
     58  // Error element and code att 
     59  public static final String ERROR = "error"; 
     60  public static final String CODE = "code"; 
     61   
     62  // OAI error codes 
    8363  public static final String BAD_ARGUMENT = "badArgument"; 
    8464  public static final String BAD_RESUMPTION_TOKEN = "badResumptionToken"; 
    8565  public static final String BAD_VERB = "badVerb"; 
     66  public static final String CANNOT_DISSEMINATE_FORMAT = "cannotDisseminateFormat"; 
     67  public static final String ID_DOES_NOT_EXIST = "idDoesNotExist"; 
     68  public static final String NO_METADATA_FORMATS = "noMetadataFormats"; 
     69  public static final String NO_RECORDS_MATCH = "noRecordsMatch"; 
     70  public static final String NO_SET_HIERARCHY = "noSetHierarchy"; 
     71   
     72 
     73  // words used to compose oai responses 
     74  // many of these used in OAIConfig too 
     75 
     76  // General 
     77  public static final String OAI_PMH = "OAI-PMH"; 
     78  public static final String RESPONSE_DATE = "responseDate"; 
     79  public static final String REQUEST = "request"; 
     80   
     81  // Identify data 
     82  public static final String ADMIN_EMAIL = "adminEmail"; 
    8683  public static final String BASE_URL = "baseURL"; 
    87   public static final String CANNOT_DISSEMINATE_FORMAT = "cannotDisseminateFormat"; 
    88   public static final String CODE = "code"; 
    89   public static final String COLLECTION = "collection"; 
    90   public static final String COLLECTION_LIST = "collectionList"; 
    91   public static final String COMPLETE_LIST_SIZE = "completeListSize"; 
    9284  public static final String COMPRESSION = "compression"; 
    93   public static final String CURSOR = "cursor"; 
    94   public static final String DATESTAMP = "datestamp"; 
    9585  public static final String DELETED_RECORD = "deletedRecord"; 
    9686  public static final String DESCRIPTION = "description"; 
    9787  public static final String EARLIEST_DATESTAMP = "earliestDatestamp"; 
    98   public static final String ERROR = "error"; 
     88  public static final String GRANULARITY = "granularity"; 
     89  public static final String PROTOCOL_VERSION = "protocolVersion"; 
     90  public static final String REPOSITORY_NAME = "repositoryName"; 
     91  public static final String OAI_IDENTIFIER = "oai-identifier"; 
     92  public static final String SCHEME = "scheme"; 
     93  public static final String REPOSITORY_IDENTIFIER = "repositoryIdentifier"; 
     94  public static final String DELIMITER = "delimiter"; 
     95  public static final String SAMPLE_IDENTIFIER = "sampleIdentifier"; 
     96 
     97  // metadata formats 
     98  public static final String METADATA_FORMAT = "metadataFormat"; 
     99  public static final String SCHEMA = "schema"; 
     100  public static final String METADATA_NAMESPACE = "metadataNamespace"; 
     101  public static final String OAI_DC = "oai_dc"; 
     102  public static final String DC = "dc"; 
     103 
     104  // record response data 
     105  // SET_SPEC 
     106  public static final String RECORD = "record"; 
     107  public static final String HEADER = "header"; 
     108  public static final String DATESTAMP = "datestamp"; 
     109  public static final String METADATA = "metadata"; 
     110 
     111  // list sets 
     112  // SET,  
     113  public static final String SET_NAME = "setName"; 
     114  public static final String SET_SPEC = "setSpec"; 
     115  public static final String SET_DESCRIPTION = "setDescription"; 
     116 
     117  // resumption token element 
     118  public static final String RESUMPTION_TOKEN_ELEM = "resumptionToken"; 
    99119  public static final String EXPIRATION_DATE = "expirationDate"; 
    100   public static final String GRANULARITY = "granularity"; 
    101   public static final String GS3OAI = "GS3OAI"; 
    102   public static final String GS_OAI_RESOURCE_URL = "gs.OAIResourceURL"; 
    103   public static final String HAS_OAI = "hasOAI"; 
    104   public static final String HEADER = "header"; 
    105   public static final String ILLEGAL_OAI_VERB = "Illegal OAI verb"; 
    106   public static final String INDEX_STEM = "indexStem"; 
    107   public static final String INFO_METADATA = "Metadata"; // this has capital M 
    108   public static final String LASTMODIFIED = "lastmodified"; 
     120  public static final String COMPLETE_LIST_SIZE = "completeListSize"; 
     121  public static final String CURSOR = "cursor"; 
     122   
     123  // extra elements/attributes from OAIConfig 
     124  public static final String OAI_INFO = "oaiInfo"; 
     125  public static final String USE_STYLESHEET = "useOAIStylesheet"; 
     126  public static final String STYLESHEET = "OAIStylesheet"; 
     127  public static final String RESUME_AFTER = "resumeAfter"; 
     128  public static final String RESUMPTION_TOKEN_EXPIRATION = "resumptionTokenExpiration"; 
     129  public static final String OAI_SUPER_SET = "oaiSuperSet"; 
    109130  public static final String MAPPING = "mapping"; 
    110131  public static final String MAPPING_LIST = "mappingList"; 
    111   public static final String MESSAGE = "message"; 
    112   public static final String METADATA = "metadata"; 
    113   public static final String METADATA_FORMAT = "metadataFormat"; 
    114   public static final String NAME = "name"; 
    115   public static final String NO_RECORDS_MATCH = "noRecordsMatch"; 
    116   public static final String OAI = "OAI"; 
    117   public static final String OAI_DASH_PMH = "OAI-PMH"; 
    118   public static final String OAI_LASTMODIFIED = "oailastmodified"; 
    119   public static final String OAIPMH = "OAIPMH"; 
    120   public static final String OAI_RESUMPTION_TOKENS = "OAIResumptionTokens"; 
    121   public static final String OAI_INFO = "oaiInfo"; 
    122   public static final String OAI_SERVICE = "oaiService"; 
    123   public static final String OAI_SET_LIST = "oaiSetList"; 
    124   public static final String OAI_SERVICE_UNAVAILABLE = "OAI service unavailable"; 
    125   public static final String OID = "OID"; 
    126   public static final String PARAM = "param"; 
    127   public static final String PARAM_LIST = "paramList"; 
    128   public static final String PROTOCOL_VERSION = "protocolVersion"; 
    129   public static final String RECORD = "record"; 
    130   public static final String REQUEST = "request"; 
    131   public static final String REPOSITORY_NAME = "repositoryName"; 
    132   public static final String REPOSITORY_ID = "repositoryId"; 
    133   public static final String RESPONSE = "response"; 
    134   public static final String RESPONSE_DATE = "responseDate"; 
    135   public static final String RESUME_AFTER = "resumeAfter"; 
    136   public static final String SCHEMA = "schema"; 
    137   public static final String SERVICE = "service"; 
    138   public static final String SERVICE_UNAVAILABLE = "service unavailable"; 
    139   public static final String SET_SPEC = "setSpec"; 
    140   public static final String SET_NAME = "setName"; 
    141   public static final String SET_DESCRIPTION = "setDescription"; 
    142   public static final String SITE = "site"; 
    143   public static final String TO = "to"; 
    144   public static final String TYPE = "type"; 
    145   public static final String VALUE = "value"; 
    146      
    147   //Two error and exception conditions for the verb 'ListMetadataFormats' 
    148   public static final String ID_DOES_NOT_EXIST = "idDoesNotExist"; 
    149   public static final String NO_METADATA_FORMATS = "noMetadataFormats"; 
    150      
    151   // The node id in the collection database, which contains all the OIDs in the database 
    152   public static final String BROWSELIST = "browselist"; 
    153          
     132 
     133  // code constants 
     134   public static final String GS_OAI_RESOURCE_URL = "gs.OAIResourceURL"; 
     135   public static final String ILLEGAL_OAI_VERB = "Illegal OAI verb"; 
     136   public static final String LASTMODIFIED = "lastmodified"; 
     137  // // The node id in the collection database, which contains all the OIDs in the database 
     138   public static final String BROWSELIST = "browselist"; 
     139   public static final String OAI_LASTMODIFIED = "oailastmodified"; 
     140   public static final String OAIPMH = "OAIPMH"; 
     141   public static final String OAI_SET_LIST = "oaiSetList"; 
     142   public static final String OAI_SERVICE_UNAVAILABLE = "OAI service unavailable"; 
     143   public static final String OID = "OID"; 
     144     
    154145  //system-dependent file separator, maybe '/' or '\' 
    155146  public static final String FILE_SEPARATOR = File.separator; 
     
    158149  /*************************above are final values****************************/ 
    159150     
    160   public static Element resumption_token_elem = null; 
    161   //used when saving the token file 
    162   public static File resumption_token_file = null; 
    163   //public static ArrayList token_list = new ArrayList(); 
    164151     
    165152  //initialized in getOAIConfigXML() 
     
    175162  public static final String default_granularity = "yyyy-MM-dd"; 
    176163 
    177   //this value is overriden in getOAIConfigXML() 
    178164  public static long token_expiration = 7200; 
    179      
    180165  /** which version of oai that this oaiserver supports; default is 2.0  
    181166   *  initialized in getOAIConfigXML() 
     
    184169  public static String baseURL = ""; 
    185170     
    186   /**response owner document */ 
    187   public static Document response_doc = new XMLConverter().newDOM();  
    188      
     171  /** Converter for parsing files and creating Elements */ 
     172  public static XMLConverter converter = new XMLConverter(); 
     173   
    189174  public static String[] special_char = {"/", "?", "#", "=", "&", ":", ";", " ", "%", "+"}; 
    190175  public static String[] escape_sequence = {"%2F", "%3F", "%23", "%3D", "%26", "%3A", "%3B", "%20", "%25", "%2B"}; 
    191   //    /** key=special character; value=escaped sequence */ 
    192   //    public static HashMap encode_map = new HashMap(); 
    193   //    /** key=escaped sequence; value=special character */ 
    194   //    public static HashMap decode_map = new HashMap(); 
    195  
    196   public static void init() { 
    197     resumption_token_elem = getOAIResumptionTokenXML(); 
    198   } 
     176 
    199177  public static String getOAIVersion() { 
    200178    return oai_version; 
     
    205183  } 
    206184     
    207   public static Element createElement(String tag_name) { 
    208     return response_doc.createElement(tag_name); 
    209   } 
    210   /**Compose a response element used when OAIPMH service sending responses thru  
    211    * ServiceCluster and MessageRouter, as they automatically wrap a message element 
    212    * on this response element 
    213    */ 
    214   public static Element getResponse(Element core_msg) { 
    215     Element res = createElement(RESPONSE); 
    216     res.appendChild(response_doc.importNode(core_msg, true)); 
    217     return res; 
    218   } 
    219   /** Read in OAIResumptionToken.xml (residing web/WEB-INF/classes/) */  
    220   public static Element getOAIResumptionTokenXML() {      
    221        
    222     // The system environment variable $GSDL3HOME(ends ../web) does not contain the file separator  
    223     resumption_token_file = new File(GlobalProperties.getGSDL3Home() + FILE_SEPARATOR + 
    224                      "WEB-INF" + FILE_SEPARATOR + "classes" +FILE_SEPARATOR + "OAIResumptionToken.xml"); 
    225     if (resumption_token_file.exists()) { 
    226       Document token_doc = parseXMLFile(resumption_token_file); 
    227       if (token_doc != null) { 
    228     resumption_token_elem = token_doc.getDocumentElement(); 
    229       } else { 
    230     logger.error("Fail to parse resumption token file OAIReceptionToken.xml."); 
    231     return null; 
    232       } 
    233       //remove all expired tokens 
    234       clearExpiredTokens(); 
    235       return resumption_token_elem;   
    236     } 
    237     //if resumption_token_file does not exist         
    238     logger.info("resumption token file: "+ resumption_token_file.getPath()+" not found! create an empty one."); 
    239     resumption_token_elem = createElement(OAI_RESUMPTION_TOKENS); 
    240     saveOAIResumptionTokenXML(resumption_token_elem); 
    241     return resumption_token_elem; 
    242   } 
    243   public static void saveOAIResumptionTokenXML(Element token_elem) {      
    244     if(writeXMLFile(resumption_token_file, token_elem.getOwnerDocument()) == false) { 
    245       logger.error("Fail to save the resumption token file"); 
    246     } 
    247   } 
    248   public static void clearExpiredTokens() { 
    249     boolean token_deleted = false; 
    250     NodeList tokens = GSXML.getChildrenByTagName(resumption_token_elem, RESUMPTION_TOKEN); 
    251     for (int i=0; i<tokens.getLength(); i++) { 
    252       Element token_elem = (Element)tokens.item(i); 
    253       String expire_str = token_elem.getAttribute(EXPIRATION_DATE); 
    254       long datestamp = getTime(expire_str); // expire_str is in milliseconds 
    255       if(datestamp < System.currentTimeMillis()) { 
    256     resumption_token_elem.removeChild(token_elem); 
    257     token_elem = null; 
    258     token_deleted = true; 
    259       } 
    260     }  
    261        
    262     if(token_deleted) { 
    263       saveOAIResumptionTokenXML(resumption_token_elem); 
    264     } 
    265   } 
    266   public static boolean containsToken(String token) { 
    267     NodeList tokens = GSXML.getChildrenByTagName(resumption_token_elem, OAIXML.RESUMPTION_TOKEN); 
    268     for (int i=0; i<tokens.getLength(); i++) { 
    269       if(token.equals(GSXML.getNodeText((Element)tokens.item(i)).trim() )) 
    270     return true; 
    271     } 
    272     return false; 
    273   } 
    274   public static void addToken(Element token) { 
    275     Document doc = resumption_token_elem.getOwnerDocument(); 
    276     resumption_token_elem.appendChild(duplicateElement(doc, token, true)); 
    277     saveOAIResumptionTokenXML(resumption_token_elem); 
    278   } 
    279   public static void addToken(String token) { 
    280     Element te = resumption_token_elem.getOwnerDocument().createElement(OAIXML.RESUMPTION_TOKEN); 
    281     //add expiration att 
    282     resumption_token_elem.appendChild(te); 
    283     saveOAIResumptionTokenXML(resumption_token_elem); 
    284   } 
    285   public static boolean removeToken(String token) { 
    286     NodeList tokens = GSXML.getChildrenByTagName(resumption_token_elem, OAIXML.RESUMPTION_TOKEN); 
    287     int num_tokens = tokens.getLength(); 
    288     for (int i=0; i<num_tokens; i++) { 
    289       Element e = (Element)(tokens.item(i)); 
    290       if(token.equals(GSXML.getNodeText(e))) { 
    291     resumption_token_elem.removeChild(e); 
    292     saveOAIResumptionTokenXML(resumption_token_elem); 
    293     return true; 
    294       } 
    295     } 
    296     return false;       
    297   } 
    298185  /** Read in OAIConfig.xml (residing web/WEB-INF/classes/) and use it to configure the receptionist etc. 
    299186   *  the oai_version and baseURL variables are also set in here.  
    300187   *  The init() method is also called in here. */  
    301188  public static Element getOAIConfigXML() { 
    302     init(); 
    303189      
    304     // The system environment variable $GSDL3HOME(ends ../web) does not contain the file separator  
    305     File oai_config_file = new File(GlobalProperties.getGSDL3Home() + FILE_SEPARATOR + 
    306                     "WEB-INF" + FILE_SEPARATOR + "classes" +FILE_SEPARATOR + "OAIConfig.xml"); 
    307     if (!oai_config_file.exists()) { 
    308       logger.error(" oai config file: "+oai_config_file.getPath()+" not found!"); 
    309       return null; 
    310     } 
    311     Document oai_config_doc = parseXMLFile(oai_config_file); 
     190    File oai_config_file = null; 
     191 
     192    try { 
     193      URL oai_config_url = Class.forName("org.greenstone.gsdl3.OAIServer").getClassLoader().getResource("OAIConfig.xml"); 
     194      if (oai_config_url == null) { 
     195    logger.error("couldn't find OAIConfig.xml via class loader"); 
     196    return null; 
     197      } 
     198      oai_config_file = new File(oai_config_url.toURI()); 
     199      if (!oai_config_file.exists()) { 
     200        logger.error(" oai config file: "+oai_config_file.getPath()+" not found!"); 
     201        return null; 
     202      } 
     203    } catch(Exception e) { 
     204      logger.error("couldn't find OAIConfig.xml "+e.getMessage()); 
     205      return null; 
     206    } 
     207 
     208    Document oai_config_doc = converter.getDOM(oai_config_file, "utf-8"); 
    312209    if (oai_config_doc != null) { 
    313210      oai_config_elem = oai_config_doc.getDocumentElement(); 
    314211    } else { 
    315       logger.error("Fail to parse oai config file OAIConfig.xml."); 
     212      logger.error("Failed to parse oai config file OAIConfig.xml."); 
    316213      return null; 
    317214    } 
     
    383280   *   
    384281   */ 
    385   public static  Element createBasicResponse(String verb, String[] pairs) { 
    386  
    387     Element response = createResponseHeader(verb); 
     282  public static  Element createBasicResponse(Document doc, String verb, String[] pairs) { 
     283 
     284    Element response = createResponseHeader(doc, verb); 
    388285       
    389286    //set the responseDate and request elements accordingly 
     
    414311  /** @param error_code the value of the code attribute 
    415312   *  @param error_text the node text of the error element 
    416    *  @return an oai error element  
    417    *  Used by receptionist 
    418    */ 
    419   public static Element createErrorElement(String error_code, String error_text) { 
    420     Element error = createElement(ERROR); 
     313   *  @return an oai error <message><response><error> 
     314   */ 
     315  public static Element createErrorMessage(String error_code, String error_text) { 
     316    Document doc = converter.newDOM(); 
     317    Element message = doc.createElement(GSXML.MESSAGE_ELEM); 
     318    Element resp = doc.createElement(GSXML.RESPONSE_ELEM); 
     319    message.appendChild(resp); 
     320    Element error = createErrorElement(doc, error_code, error_text); 
     321    resp.appendChild(error); 
     322    return message; 
     323  } 
     324     
     325  /** @param error_code the value of the code attribute 
     326   *  @param error_text the node text of the error element 
     327   *  @return an oai error <response><error> 
     328   */ 
     329  public static Element createErrorResponse(String error_code, String error_text) { 
     330    Document doc = converter.newDOM(); 
     331    Element resp = doc.createElement(GSXML.RESPONSE_ELEM); 
     332    Element error = createErrorElement(doc, error_code, error_text); 
     333    resp.appendChild(error); 
     334    return resp; 
     335  } 
     336     
     337  /** @param error_code the value of the code attribute 
     338   *  @param error_text the node text of the error element 
     339   *  @return an oai error <error> 
     340   */ 
     341  public static Element createErrorElement(Document doc, String error_code, String error_text) { 
     342    Element error = doc.createElement(ERROR); 
    421343    error.setAttribute(CODE, error_code); 
    422344    GSXML.setNodeText(error, error_text); 
     
    434356      } 
    435357    } 
    436     //escaped_str = escaped_str.replaceAll("%3A", ":"); 
    437358    return escaped_str;         
    438359  } 
     
    447368      } 
    448369    } 
    449     //original_str = original_str.replaceAll(":", "%3A"); 
    450370    return original_str;   
    451371  } 
     
    541461    return sdf.format(date); 
    542462  }     
    543   public static Element createResponseHeader(String verb) { 
    544     String tag_name = (oai_version.equals(OAI_VERSION2))? OAI_DASH_PMH : verb; 
     463  public static Element createResponseHeader(Document response_doc, String verb) { 
     464    String tag_name = (oai_version.equals(OAI_VERSION2))? OAI_PMH : verb; 
    545465    Element oai = response_doc.createElement(tag_name); 
    546466    Element resp_date = response_doc.createElement(RESPONSE_DATE); 
     
    560480    return oai; 
    561481  } 
    562   public static Element getMetadataPrefixElement(String tag_name, String version) { 
     482  public static Element getMetadataPrefixElement(Document doc, String tag_name, String version) { 
    563483    //examples of tag_name: dc, oai_dc:dc, etc. 
    564     Element oai = response_doc.createElement(tag_name); 
     484    Element oai = doc.createElement(tag_name); 
    565485    if (version.equals(OAI_VERSION2)) { 
    566486      oai.setAttribute("xmlns:oai_dc", "http://www.openarchives.org/OAI/2.0/oai_dc/"); 
     
    569489      oai.setAttribute("xsi:schemaLocation", "http://www.openarchives.org/OAI/2.0/oai_dc/ \n http://www.openarchives.org/OAI/2.0/oai_dc.xsd"); 
    570490    } else { 
    571       oai.setAttribute("xmlns", "ttp://www.openarchives.com/OAI/1.1/"); 
     491      oai.setAttribute("xmlns", "http://www.openarchives.com/OAI/1.1/"); 
    572492      oai.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); 
    573493      oai.setAttribute("xsi:schemaLocation", "http://www.openarchives.org/OAI/1.1/" + tag_name + ".xsd");         
     
    590510  } 
    591511     
    592   /** Duplicates an element */ 
    593   public static Element duplicateElement (Document owner, Element element, boolean with_attributes) { 
    594     return duplicateElementNS (owner, element, null, with_attributes); 
    595   } 
    596      
    597   /** Duplicates an element */ 
    598   public static Element duplicateElementNS (Document owner, 
    599                         Element element, 
    600                         String namespace_uri, 
    601                         boolean with_attributes) { 
    602     Element duplicate; 
    603     if (namespace_uri == null) { 
    604       duplicate = owner.createElement (element.getTagName ()); 
    605     } else { 
    606       duplicate = owner.createElementNS (namespace_uri, element.getTagName ()); 
    607     } 
    608     // Copy element attributes 
    609     if (with_attributes) { 
    610       NamedNodeMap attributes = element.getAttributes (); 
    611       for (int i = 0; i < attributes.getLength (); i++) { 
    612     Node attribute = attributes.item (i); 
    613     duplicate.setAttribute (attribute.getNodeName (), attribute.getNodeValue ()); 
    614       } 
    615     } 
    616          
    617     // Copy element children 
    618     NodeList children = element.getChildNodes (); 
    619     for (int i = 0; i < children.getLength (); i++) { 
    620       Node child = children.item (i); 
    621       duplicate.appendChild (owner.importNode (child, true)); 
    622     } 
    623          
    624     return duplicate; 
    625   } 
    626  
    627   public static void copyElement(Element to, Element from, String elem_name) { 
    628        
    629     Document to_doc = to.getOwnerDocument(); 
    630     Node child = from.getFirstChild(); 
    631     while (child != null) { 
    632       if (child.getNodeName().equals(elem_name)) { 
    633     to.appendChild(to_doc.importNode(child, true)); 
    634     return; 
    635       } 
    636       child = child.getNextSibling(); 
    637     } 
    638   } 
    639  
    640   public static HashMap<String, String> getParamMap(NodeList params) { 
    641     HashMap<String, String> map = new HashMap<String, String>(); 
    642     for(int i=0; i<params.getLength(); i++) { 
    643       Element param = (Element)params.item(i); 
    644       String param_name = param.getAttribute(OAIXML.NAME); 
    645       String param_value = param.getAttribute(OAIXML.VALUE); 
    646       map.put(param_name, param_value); 
    647     } 
    648     return map; 
    649   } 
    650  
    651  
    652   /** Parse an XML document from a given file */ 
    653   static public Document parseXMLFile (File xml_file) { 
    654     // No file? No point trying! 
    655     if (xml_file.exists () == false) { 
    656       return null; 
    657     } 
    658     Document doc = null; 
    659     try { 
    660       doc = parseXML (new FileInputStream (xml_file)); 
    661     } 
    662     catch (Exception exception) { 
    663       logger.error(exception.toString()); 
    664       return null; 
    665     } 
    666     return doc; 
    667   } 
    668      
    669      
    670   /** Parse an XML document from a given input stream */ 
    671   static public Document parseXML (InputStream xml_input_stream) { 
    672     Document document = null; 
    673          
    674     try { 
    675       InputStreamReader isr = new InputStreamReader (xml_input_stream, "UTF-8"); 
    676       Reader xml_reader = new BufferedReader (isr); 
    677       document = parseXML (xml_reader); 
    678       isr.close (); 
    679       xml_input_stream.close (); 
    680     } 
    681     catch (Exception exception) { 
    682       logger.error(exception.toString()); 
    683     } 
    684          
    685     return document; 
    686   } 
    687  
    688   /** Parse an XML document from a given reader */ 
    689   static public Document parseXML (Reader xml_reader) { 
    690     Document document = null; 
    691          
    692     try { 
    693       InputSource isc       = new InputSource (xml_reader); 
    694       DOMParser parser      = new DOMParser (); 
    695       parser.setFeature ("http://xml.org/sax/features/validation", false); 
    696       parser.setFeature ("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); 
    697       // May or may not be ignored, the documentation for Xerces is contradictory. If it works then parsing -should- be faster. 
    698       parser.setFeature ("http://apache.org/xml/features/dom/defer-node-expansion", true); 
    699       parser.setFeature ("http://apache.org/xml/features/dom/include-ignorable-whitespace", false); 
    700       parser.parse (isc); 
    701       document = parser.getDocument (); 
    702     } 
    703     catch (SAXException exception) { 
    704       System.err.println ("SAX exception: " + exception.getMessage ()); 
    705       logger.error(exception.toString()); 
    706     } 
    707     catch (Exception exception) { 
    708       logger.error(exception.toString()); 
    709     } 
    710          
    711     return document; 
    712   } 
    713   /** Write an XML document to a given file */ 
    714   static public boolean writeXMLFile (File xml_file, Document document) { 
    715     try { 
    716       OutputStream os = new FileOutputStream (xml_file); 
    717       // Create an output format for our document. 
    718       OutputFormat f = new OutputFormat (document); 
    719       f.setEncoding ("UTF-8"); 
    720       f.setIndenting (true); 
    721       f.setLineWidth (0); // Why isn't this working! 
    722       f.setPreserveSpace (false); 
    723       // Create the necessary writer stream for serialization. 
    724       OutputStreamWriter osw = new OutputStreamWriter (os, "UTF-8"); 
    725       Writer w               = new BufferedWriter (osw); 
    726       // Generate a new serializer from the above. 
    727       XMLSerializer s        = new XMLSerializer (w, f); 
    728       s.asDOMSerializer (); 
    729       // Finally serialize the document to file. 
    730       s.serialize (document); 
    731       // And close. 
    732       os.close (); 
    733       return true; 
    734     } 
    735     catch (Exception exception) { 
    736       logger.error(exception.toString()); 
    737       return false; 
    738     } 
    739   } 
    740      
    741  
    742   public static Element createOAIIdentifierXML(String repository_id, String sample_collection, String sample_doc_id) { 
     512  public static Element createOAIIdentifierXML(Document doc, String repository_id, String sample_collection, String sample_doc_id) { 
    743513    String xml = "<oai-identifier xmlns=\"http://www.openarchives.org/OAI/2.0/oai-identifier\"\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n xsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/oai-identifier\n http://www.openarchives.org/OAI/2.0/oai-identifier.xsd\">\n <scheme>oai</scheme>\n<repositoryIdentifier>" + repository_id + "</repositoryIdentifier>\n<delimiter>:</delimiter>\n<sampleIdentifier>oai:"+repository_id+":"+sample_collection+":"+sample_doc_id+"</sampleIdentifier>\n</oai-identifier>"; 
    744514 
    745     Document xml_doc = new XMLConverter().getDOM(xml); 
    746     return (Element)response_doc.importNode(xml_doc.getDocumentElement(), true); 
    747      
    748  
    749   } 
    750  
    751   public static Element createGSDLElement() { 
     515    Document xml_doc = converter.getDOM(xml); 
     516    return (Element)doc.importNode(xml_doc.getDocumentElement(), true); 
     517     
     518 
     519  } 
     520 
     521  public static Element createGSDLElement(Document doc) { 
    752522    String xml = "<gsdl xmlns=\"http://www.greenstone.org/namespace/gsdl_oaiinfo/1.0/gsdl_oaiinfo\"\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n xsi:schemaLocation=\"http://www.greenstone.org/namespace/gsdl_oaiinfo/1.0/gsdl_oaiinfo\n   http://www.greenstone.org/namespace/gsdl_oaiinfo/1.0/gsdl_oaiinfo.xsd\"></gsdl>"; 
    753     Document xml_doc = new XMLConverter().getDOM(xml); 
    754     return (Element)response_doc.importNode(xml_doc.getDocumentElement(), true); 
    755      
    756  
    757   } 
     523    Document xml_doc = converter.getDOM(xml); 
     524    return (Element)doc.importNode(xml_doc.getDocumentElement(), true); 
     525     
     526 
     527  } 
     528 
     529  public static Element createSet(Document doc, String spec, String name, String description) { 
     530 
     531    Element set_elem = doc.createElement(SET); 
     532    Element set_spec = doc.createElement(SET_SPEC); 
     533    GSXML.setNodeText(set_spec, spec); 
     534    set_elem.appendChild(set_spec); 
     535    Element set_name = doc.createElement(SET_NAME); 
     536    GSXML.setNodeText(set_name, name); 
     537    set_elem.appendChild(set_name); 
     538    if (description != null) { 
     539      Element set_description = doc.createElement(SET_DESCRIPTION); 
     540      GSXML.setNodeText(set_description, description); 
     541      set_elem.appendChild(set_description); 
     542    } 
     543    return set_elem; 
     544     
     545  } 
     546 
     547  /** returns the resumptionToken element to go into an OAI response */ 
     548  public static Element createResumptionTokenElement(Document doc, String token_name, int total_size, int cursor, long expiration_time) { 
     549    Element token = doc.createElement(OAIXML.RESUMPTION_TOKEN); 
     550    if (total_size != -1) { 
     551      token.setAttribute(OAIXML.COMPLETE_LIST_SIZE, "" + total_size); 
     552    } 
     553    if (cursor != -1) { 
     554      token.setAttribute(OAIXML.CURSOR, "" + cursor); 
     555    } 
     556    if(expiration_time !=-1) { 
     557      token.setAttribute(OAIXML.EXPIRATION_DATE, getTime(expiration_time)); 
     558    } 
     559    
     560    if (token != null) { 
     561      GSXML.setNodeText(token, token_name); 
     562    } 
     563    return token; 
     564  } 
     565   
    758566} 
    759567