Ignore:
Timestamp:
2014-04-10T14:39:33+12:00 (10 years ago)
Author:
kjdon
Message:

Lots of changes. Mainly to do with removing this.doc from everywhere. Document is not thread safe. Now we tend to create a new Document everytime we are starting a new page/message etc. in service this.desc_doc is available as teh document to create service info stuff. But it should only be used for this and not for other messages. newDOM is now static for XMLConverter. method param changes for some GSXML methods.

File:
1 edited

Legend:

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

    r26311 r28966  
    8787    extends ServiceRack implements OID.OIDTranslatable
    8888{
     89
     90    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.FedoraServiceProxy.class.getName());
     91    protected MacroResolver macro_resolver = null;
     92
     93
     94    /** The handle to the fedora connection */
     95    private DigitalLibraryServicesAPIA fedoraServicesAPIA;
     96
     97    private String prevLanguage = "";
     98
     99    public void cleanUp() {
     100    super.cleanUp();
     101    }
     102   
     103    /** sets the message router */
     104    public void setMessageRouter(MessageRouter m) {
     105       this.router = m;
     106       setLibraryName(m.getLibraryName());
     107    }
     108
     109    /** the no-args constructor */
     110    public FedoraServiceProxy() {
     111    super();
     112
     113    this.macro_resolver = new BasicTextMacroResolver();
     114    }
     115   
     116
     117    /* configure the service module
     118     *
     119     * @param info the XML node <serviceRack name="XXX"/> with name equal
     120     * to the class name (of the subclass)
     121     *
     122     * must configure short_service_info_ and service_info_map_
     123     * @return true if configured ok
     124     * must be implemented in subclasses
     125     */
     126    /*public boolean configure(Element info) {
     127    return configure(info, null);
     128    }*/
     129   
     130    public boolean configure(Element info, Element extra_info) {
     131    // set up the class loader
     132       
     133    if (!super.configure(info, extra_info)){
     134        return false;
     135    }
     136
     137    // Try to instantiate a Fedora dl handle
     138    try {
     139        // Fedora connection settings defaults.
     140        // Read host and port from global.properties, since by default, we expect the Greenstone server to be used
     141        Properties globalProperties = new Properties();
     142        globalProperties.load(Class.forName("org.greenstone.util.GlobalProperties").getClassLoader().getResourceAsStream("global.properties"));
     143        String host = globalProperties.getProperty("tomcat.server", "localhost");
     144        String port = globalProperties.getProperty("tomcat.port", "8383");
     145        String protocol = "http";
     146        String username = "fedoraIntCallUser"; //"fedoraAdmin"
     147        String password = "changeme"; //"<user password>"
     148
     149        // See if buildConfig.xml overrides any of the defaults
     150        // info is the <serviceRack> Element from buildConfig.xml (extra_info are the Elements of collectionConfig.xml)
     151
     152        NodeList nodes = info.getElementsByTagName("fedoraConnection");
     153        if(nodes != null && nodes.getLength() > 0) {
     154
     155        Element fedoraElement = (Element)nodes.item(0);
     156        if(fedoraElement.hasAttribute("protocol")) {
     157            protocol = fedoraElement.getAttribute("protocol");
     158        }       
     159        if(fedoraElement.hasAttribute("host")) {
     160            host = fedoraElement.getAttribute("host");
     161        }
     162        if(fedoraElement.hasAttribute("port")) {
     163            port = fedoraElement.getAttribute("port");
     164        }
     165        if(fedoraElement.hasAttribute("username")) {
     166            username = fedoraElement.getAttribute("username");
     167        }
     168        if(fedoraElement.hasAttribute("password")) {
     169            password = fedoraElement.getAttribute("password");
     170        }       
     171        }   
     172
     173        fedoraServicesAPIA = new FedoraServicesAPIA(protocol, host, Integer.parseInt(port), username, password);
     174
     175    } catch(org.greenstone.fedora.services.FedoraGS3Exception.CancelledException e) {
     176        // The user pressed cancel in the fedora services instantiation dialog
     177        return false;
     178    } catch(Exception e) {
     179        logger.error("Error instantiating the interface to the Fedora Repository:\n", e); // second parameter prints e's stacktrace
     180        return false;
     181    }
     182
     183   
     184    // Need to put the available services into short_service_info
     185    // This is used by DefaultReceptionist.process() has an exception. But DefaultReceptionist.addExtraInfo()
     186    // isn't helpful, and the problem actually already occurs in
     187    // Receptionist.process() -> PageAction.process() -> MessageRouter.process()
     188    // -> Collection/ServiceCluster.process() -> ServiceCluster.configureServiceRackList()
     189    // -> ServiceRack.process() -> ServiceRack.processDescribe() -> ServiceRack.getServiceList().
     190    // ServiceRack.getServiceList() requires this ServiceRack's services to be filled into the
     191    // short_service_info Element which needs to be done in this FedoraServiceProxy.configure().
     192   
     193    // get the display and format elements from the coll config file for
     194    // the classifiers
     195    AbstractBrowse.extractExtraClassifierInfo(info, extra_info);
     196
     197    // Copied from IViaProxy.java:
     198    String collection = fedoraServicesAPIA.describeCollection(this.cluster_name);
     199
     200    Element collNode = getResponseAsDOM(collection);
     201    Element serviceList = (Element)collNode.getElementsByTagName(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER).item(0);
     202
     203//this.short_service_info.appendChild(short_service_info.getOwnerDocument().importNode(serviceList, true));
     204    // we want the individual service Elements, not the serviceList Element which will wrap it later
     205    NodeList services = collNode.getElementsByTagName(GSXML.SERVICE_ELEM);
     206    for(int i = 0; i < services.getLength(); i++) {
     207        Node service = services.item(i);
     208        this.short_service_info.appendChild(short_service_info.getOwnerDocument().importNode(service, true));
     209    }
     210
     211    // add some format info to service map if there is any
     212    String path = GSPath.appendLink(GSXML.SEARCH_ELEM, GSXML.FORMAT_ELEM);
     213    Element search_format = (Element) GSXML.getNodeByPath(extra_info, path);
     214    if (search_format != null) {
     215        this.format_info_map.put("TextQuery", this.desc_doc.importNode(search_format, true));
     216        this.format_info_map.put("FieldQuery", this.desc_doc.importNode(search_format, true));
     217    }
     218   
     219    // look for document display format
     220    path = GSPath.appendLink(GSXML.DISPLAY_ELEM, GSXML.FORMAT_ELEM);
     221    Element display_format = (Element)GSXML.getNodeByPath(extra_info, path);
     222    if (display_format != null) {
     223        this.format_info_map.put("DocumentContentRetrieve", this.desc_doc.importNode(display_format, true));
     224        // should we make a copy?
     225    }
     226
     227    // the format info
     228    Element cb_format_info = this.desc_doc.createElement(GSXML.FORMAT_ELEM);
     229    boolean format_found = false;
     230
     231    // look for classifier <browse><format>
     232    path = GSPath.appendLink(GSXML.BROWSE_ELEM, GSXML.FORMAT_ELEM);
     233    Element browse_format = (Element)GSXML.getNodeByPath(extra_info, path);
     234    if (browse_format != null) {
     235        cb_format_info.appendChild(GSXML.duplicateWithNewName(this.desc_doc, browse_format, GSXML.DEFAULT_ELEM, true));
     236        format_found = true;
     237    }
     238   
     239    // add in to the description a simplified list of classifiers
     240    Element browse = (Element)GSXML.getChildByTagName(extra_info, "browse"); // the <browse>
     241    NodeList classifiers = browse.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
     242    for(int i=0; i<classifiers.getLength(); i++) {
     243        Element cl = (Element)classifiers.item(i);
     244        Element new_cl = (Element)this.desc_doc.importNode(cl, false); // just import this node, not the children
     245       
     246        // get the format info out, and put inside a classifier element
     247        Element format_cl = (Element)new_cl.cloneNode(false);
     248        Element format = (Element)GSXML.getChildByTagName(cl, GSXML.FORMAT_ELEM);
     249        if (format != null) {
     250       
     251        //copy all the children
     252        NodeList elems = format.getChildNodes();
     253        for (int j=0; j<elems.getLength();j++) {
     254            format_cl.appendChild(this.desc_doc.importNode(elems.item(j), true));
     255        }
     256        cb_format_info.appendChild(format_cl);
     257        format_found = true;
     258        }
     259               
     260    }
     261       
     262    if (format_found) {
     263        this.format_info_map.put("ClassifierBrowse", cb_format_info);
     264    }
     265   
     266
     267    // set up the macro resolver
     268    macro_resolver.setSiteDetails(this.site_http_address, this.cluster_name, this.getLibraryName());
     269    Element replacement_elem = (Element)GSXML.getChildByTagName(extra_info, "replaceList");
     270    if (replacement_elem != null) {
     271        macro_resolver.addMacros(replacement_elem);
     272    }
     273    // look for any refs to global replace lists
     274    NodeList replace_refs_elems = extra_info.getElementsByTagName("replaceListRef");
     275    for (int i=0; i<replace_refs_elems.getLength(); i++) {
     276        String id = ((Element)replace_refs_elems.item(i)).getAttribute("id");
     277        if (!id.equals("")) {
     278        Element replace_list = GSXML.getNamedElement(this.router.config_info, "replaceList", "id", id);
     279        if (replace_list != null) {
     280            macro_resolver.addMacros(replace_list);
     281        }
     282        }
     283    }
     284
     285    // configured ok
     286    return true;
     287    }
     288
     289 
     290    /* "DocumentContentRetrieve", "DocumentMetadataRetrieve", "DocumentStructureRetrieve",
     291      "TextQuery", "FieldQuery", "ClassifierBrowse", "ClassifierBrowseMetadataRetrieve" */
     292
     293    protected Element processDocumentContentRetrieve(Element request) {
     294    String[] docIDs = parse(request, GSXML.DOC_NODE_ELEM, GSXML.NODE_ID_ATT);
     295    String[] relLinks = parse(request, GSXML.DOC_NODE_ELEM, "externalURL");
     296   
     297    //logger.error("### request:");
     298    //logger.error(GSXML.elementToString(request, true));
     299
     300    if(docIDs == null) {
     301        logger.error("DocumentContentRetrieve request specified no doc nodes.\n");
     302        return XMLConverter.newDOM().createElement(GSXML.RESPONSE_ELEM); // empty response
     303    } else {
     304        for(int i = 0; i < docIDs.length; i++) {
     305        //logger.error("BEFORE: docIDs[" + i + "]: " + docIDs[i]);
     306        if(relLinks[i] != null && docIDs[i].startsWith("http://")) { // need to do a look up
     307            docIDs[i] = translateExternalId(docIDs[i]);
     308        } else {
     309            docIDs[i] = translateId(docIDs[i]);         
     310        }
     311        //logger.error("AFTER: docIDs[" + i + "]: " + docIDs[i]);
     312        }
     313    }
     314   
     315    String lang = request.getAttribute(GSXML.LANG_ATT);
     316    if(!lang.equals(prevLanguage)) {
     317        prevLanguage = lang;
     318        fedoraServicesAPIA.setLanguage(lang);
     319    }
     320   
     321    // first param (the collection) is not used by Fedora   
     322    Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentContent(this.cluster_name, docIDs));
     323
     324   
     325    // resolve any collection specific macros
     326    NodeList nodeContents = response.getElementsByTagName(GSXML.NODE_CONTENT_ELEM);
     327    for(int i = 0; i < nodeContents.getLength(); i++) {
     328        Element nodeContent = (Element)nodeContents.item(i);
     329        /*if(nodeContent != null) {
     330        nodeContent = (Element)nodeContent.getFirstChild(); // textNode
     331        }*/
     332        //logger.error("GIRAFFE 1. content retrieve response - nodeContent: " + GSXML.nodeToFormattedString(nodeContent));
     333        String docContent = nodeContent.getFirstChild().getNodeValue(); // getTextNode and get its contents.
     334        //logger.error("GIRAFFE 2. content retrieve response - docContent: " + docContent);
     335       
     336        if(docContent != null) {
     337        // get document text and resolve and macros. Rel and external links have _httpextlink_ set by HTMLPlugin
     338        docContent = macro_resolver.resolve(docContent, lang, MacroResolver.SCOPE_TEXT, ""); // doc_id
     339        nodeContent.getFirstChild().setNodeValue(docContent);
     340        //logger.error("GIRAFFE 3. content retrieve response. Updated docContent: " + docContent);
     341        }
     342    }
     343
     344    return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
     345    }
     346
     347    protected Element processDocumentStructureRetrieve(Element request) {
     348    String[] docIDs = parse(request, GSXML.DOC_NODE_ELEM, GSXML.NODE_ID_ATT);
     349    String[] relLinks = parse(request, GSXML.DOC_NODE_ELEM, "externalURL");
     350
     351    if(docIDs == null) {
     352        logger.error("DocumentStructureRetrieve request specified no doc nodes.\n");
     353        return XMLConverter.newDOM().createElement(GSXML.RESPONSE_ELEM); // empty response
     354    } else {
     355        for(int i = 0; i < docIDs.length; i++) {
     356        //logger.error("BEFORE: docIDs[" + i + "]: " + docIDs[i]);
     357        if(relLinks[i] != null && docIDs[i].startsWith("http://")) { // need to do a look up
     358            docIDs[i] = translateExternalId(docIDs[i]);
     359        } else {
     360            docIDs[i] = translateId(docIDs[i]);
     361        }
     362        }
     363    }
     364
     365    NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
     366    String structure="";
     367    String info="";
     368    for(int i = 0; i < params.getLength(); i++) {
     369        Element param = (Element)params.item(i);
     370        if(param.getAttribute("name").equals("structure")) {
     371        structure = structure + param.getAttribute("value") + "|";
     372        } else if(param.getAttribute("name").equals("info")) {
     373        info = info + param.getAttribute("value") + "|";
     374        }
     375    }   
     376   
     377    String lang = request.getAttribute(GSXML.LANG_ATT);
     378    if(!lang.equals(prevLanguage)) {
     379        prevLanguage = lang;
     380        fedoraServicesAPIA.setLanguage(lang);
     381    }
     382    Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentStructure(
     383        this.cluster_name, docIDs, new String[]{structure}, new String[]{info}));
     384    return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
     385    }
     386
     387    protected Element processDocumentMetadataRetrieve(Element request) {
     388    String[] docIDs = parse(request, GSXML.DOC_NODE_ELEM, GSXML.NODE_ID_ATT);
     389    String[] relLinks = parse(request, GSXML.DOC_NODE_ELEM, "externalURL");
     390
     391    if(docIDs == null) {
     392        logger.error("DocumentMetadataRetrieve request specified no doc nodes.\n");
     393        return XMLConverter.newDOM().createElement(GSXML.RESPONSE_ELEM); // empty response
     394    } else {
     395        for(int i = 0; i < docIDs.length; i++) {
     396        //logger.error("**** relLinks[i]: " + relLinks[i]);
     397        //logger.error("**** docIDs[i]: " + docIDs[i]);
     398        if(relLinks[i] != null && docIDs[i].startsWith("http://")) { // need to do a look up
     399            docIDs[i] = translateExternalId(docIDs[i]);
     400        } else {
     401            docIDs[i] = translateId(docIDs[i]);
     402        }
     403        //logger.error("AFTER: docIDs[" + i + "]: " + docIDs[i]);
     404        }
     405    }
     406   
     407    NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
     408    String[] metafields = {};
     409    if(params.getLength() > 0) {
     410        metafields = new String[params.getLength()];
     411        for(int i = 0; i < metafields.length; i++) {
     412        Element param = (Element)params.item(i);
     413        //if(param.hasAttribute(GSXML.NAME_ATT) && param.getAttribute(GSXML.NAME_ATT).equals("metadata") && param.hasAttribute(GSXML.VALUE_ATT)) {
     414        if(param.hasAttribute(GSXML.VALUE_ATT)){
     415            metafields[i] = param.getAttribute(GSXML.VALUE_ATT);
     416        } else {
     417            metafields[i] = "";
     418        }
     419        }
     420    }
     421
     422    String lang = request.getAttribute(GSXML.LANG_ATT);
     423    if(!lang.equals(prevLanguage)) {
     424        prevLanguage = lang;
     425        fedoraServicesAPIA.setLanguage(lang);
     426    }
     427    Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentMetadata(
     428                        this.cluster_name, docIDs, metafields));
     429    return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
     430    }
     431
     432    protected Element processClassifierBrowseMetadataRetrieve(Element request) {   
     433    String[] classIDs = parse(request, GSXML.CLASS_NODE_ELEM, GSXML.NODE_ID_ATT);
     434    //String[] relLinks = parse(request, GSXML.CLASS_NODE_ELEM, "externalURL");
     435
     436    if(classIDs == null) {
     437        logger.error("ClassifierBrowseMetadataRetrieve request specified no classifier nodes.\n");
     438        return XMLConverter.newDOM().createElement(GSXML.RESPONSE_ELEM); // empty response
     439    } else {
     440        for(int i = 0; i < classIDs.length; i++) {
     441        classIDs[i] = translateId(classIDs[i]);
     442        }
     443    }
     444   
     445    NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
     446    String[] metafields = {};
     447    if(params.getLength() > 0) {
     448        metafields = new String[params.getLength()];
     449        for(int i = 0; i < metafields.length; i++) {
     450        Element param = (Element)params.item(i);
     451        if(param.hasAttribute(GSXML.VALUE_ATT)){
     452            metafields[i] = param.getAttribute(GSXML.VALUE_ATT);
     453        } else {
     454            metafields[i] = "";
     455        }
     456        }
     457    }
     458   
     459    String lang = request.getAttribute(GSXML.LANG_ATT);
     460    if(!lang.equals(prevLanguage)) {
     461        prevLanguage = lang;
     462        fedoraServicesAPIA.setLanguage(lang);
     463    }
     464    Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveBrowseMetadata(
     465           this.cluster_name, "ClassifierBrowseMetadataRetrieve", classIDs, metafields));
     466    //logger.error("**** Response from retrieveBrowseMeta: " + GSXML.elementToString(response, true));
     467    return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
     468    }
     469
     470    protected Element processClassifierBrowse(Element request) {
     471    String collection = this.cluster_name;
     472    String lang = request.getAttribute(GSXML.LANG_ATT);
     473    if(!lang.equals(prevLanguage)) {
     474        prevLanguage = lang;
     475        fedoraServicesAPIA.setLanguage(lang);
     476    }
     477
     478    NodeList classNodes = request.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
     479    if(classNodes == null || classNodes.getLength() <= 0) {
     480        logger.error("ClassifierBrowse request specified no classifier IDs.\n");
     481        return XMLConverter.newDOM().createElement(GSXML.RESPONSE_ELEM); // empty response
     482    }
     483    String classifierIDs[] = new String[classNodes.getLength()];
     484    for(int i = 0; i < classifierIDs.length; i++) {
     485        Element e = (Element)classNodes.item(i);
     486        classifierIDs[i] = e.getAttribute(GSXML.NODE_ID_ATT);
     487        classifierIDs[i] = translateId(classifierIDs[i]);   
     488    }
     489   
     490    NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
     491    String structure="";
     492    String info="";
     493    for(int i = 0; i < params.getLength(); i++) {
     494        Element param = (Element)params.item(i);
     495        if(param.getAttribute("name").equals("structure")) {
     496        structure = structure + param.getAttribute("value") + "|";
     497        } else if(param.getAttribute("name").equals("info")) {
     498        info = info + param.getAttribute("value") + "|";
     499        }
     500    }
     501    ///structure = structure + "siblings"; //test for getting with classifier browse structure: siblings
     502   
     503    Element response
     504        = getResponseAsDOM(fedoraServicesAPIA.retrieveBrowseStructure(collection, "ClassifierBrowse", classifierIDs,
     505                                      new String[] {structure}, new String[] {info}));
     506    //logger.error("**** FedoraServiceProxy - Response from retrieveBrowseStructure: " + GSXML.elementToString(response, true));   
     507   
     508    return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
     509    }
     510
     511    protected Element processTextQuery(Element request) {
     512    return processQuery(request, "TextQuery");
     513    }
     514
     515    protected Element processFieldQuery(Element request) {
     516    return processQuery(request, "FieldQuery");
     517    }
     518
     519    protected Element processQuery(Element request, String querytype) {
     520    String collection = this.cluster_name;
     521
     522    String lang = request.getAttribute(GSXML.LANG_ATT);
     523    if(!lang.equals(prevLanguage)) {
     524        prevLanguage = lang;
     525        fedoraServicesAPIA.setLanguage(lang);
     526    }
     527
     528    NodeList paramNodes = request.getElementsByTagName(GSXML.PARAM_ELEM);
     529    if(paramNodes.getLength() > 0) {
     530        HashMap<String, String> params = new HashMap<String, String>(paramNodes.getLength());
     531        for(int i = 0; i < paramNodes.getLength(); i++) {
     532        Element param = (Element)paramNodes.item(i);
     533        params.put(param.getAttribute(GSXML.NAME_ATT), param.getAttribute(GSXML.VALUE_ATT));
     534        }
     535
     536        Element response = getResponseAsDOM(fedoraServicesAPIA.query(collection, querytype, params));
     537        return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
     538    } else {
     539        logger.error("TextQuery request specified no parameters.\n");
     540        return XMLConverter.newDOM().createElement(GSXML.RESPONSE_ELEM); // empty response
     541    }
     542    }
     543
     544    // get the requested nodeIDs out of a request message
     545    protected String[] parse(Element request, String nodeType, String attribute) { 
     546    String[] nodevalues = null;
     547    int count = 0;
     548
     549    Element docList = (Element) GSXML.getChildByTagName(request, nodeType+GSXML.LIST_MODIFIER);
     550    if (docList != null) {     
     551        NodeList docNodes = docList.getElementsByTagName(nodeType);
     552        if(docNodes.getLength() > 0) {
     553        nodevalues = new String[docNodes.getLength()];
     554        for(int i = 0; i < nodevalues.length; i++) {
     555            Element e = (Element)docNodes.item(i);
     556            String id = e.getAttribute(attribute);
     557            // Not sure why there are at times requests for hashXXX.dir, which is not a fedora PID
     558            // To skip these: if not requesting an externalURL and if requesting a docNode,
     559            // then the ID has to contain the : character special to fedora PIDs
     560            if(attribute == "externalURL" || (nodeType != GSXML.DOC_NODE_ELEM || id.contains(":"))) {
     561            nodevalues[count++] = id;
     562            }
     563        }
     564        }
     565    }
     566
     567    if(count == 0) {
     568        return null;
     569    }
     570
     571    String[] tmp = new String[count];
     572    for(int i = 0; i < count; i++) {
     573        tmp[i] = nodevalues[i];
     574    }
     575    nodevalues = null;
     576    nodevalues = tmp;
     577
     578    return nodevalues;
     579    }
     580
     581
     582    /** if id ends in .fc, .pc etc, then translate it to the correct id
     583     * For now (for testing things work) the default implementation is to just remove the suffix */
     584    protected String translateId(String id) {
     585    if (OID.needsTranslating(id)) {
     586        return OID.translateOID(this, id); //return translateOID(id);
     587    }
     588    return id;
     589    }
     590   
     591    /** if an id is not a greenstone id (an external id) then translate
     592     * it to a greenstone one
     593     * default implementation: return the id. Custom implementation:
     594     * the id is a url that maps to a fedorapid whose dc.title contains the required HASHID */
     595    protected String translateExternalId(String id) {
     596    //logger.error("*** to translate an external ID: " + id); /////return id;
     597    return this.externalId2OID(id);
     598    }
     599
     600    /** converts an external id to greenstone OID. External ID is a URL link
     601     * that, if relative, maps to a fedorapid that has an entry in fedora.
     602     * The dc:title meta for that fedorapid will contain the required OID. */
     603    public String externalId2OID(String extid) {
     604    if(extid.endsWith(".rt") && (extid.indexOf('.') != extid.lastIndexOf('.'))) {
     605           // .rt is not file extension, but Greenstone request for root of document
     606           // not relevant for external ID
     607           extid = extid.substring(0, extid.length()-3);
     608    }
     609
     610       // the following method is unique to FedoraServicesAPIA
     611    String response = ((FedoraServicesAPIA)fedoraServicesAPIA).getDocIDforURL(extid, this.cluster_name);
     612    if(response.indexOf(GSXML.ERROR_ELEM) != -1) {
     613        logger.error("**** The following error occurred when trying to find externalID for ID " + extid);
     614        logger.error(response);
     615        return extid;
     616    }
     617    if(response.equals("")) {
     618        return extid;
     619    } else {
     620        return response;
     621    }
     622    }
     623
     624
     625  /** translates relative oids into proper oids:
     626   * .pr (parent), .rt (root) .fc (first child), .lc (last child),
     627   * .ns (next sibling), .ps (previous sibling)
     628   * .np (next page), .pp (previous page) : links sections in the order that you'd read the document
     629   * a suffix is expected to be present so test before using
     630   */
     631    public String processOID(String doc_id, String top, String suff, int sibling_num) {
     632
     633    // send off request to get sibling etc. information from Fedora
     634    Element response = null;
     635    String[] children = null;
     636    if(doc_id.startsWith("CL")) { // classifiernode
     637    response = getResponseAsDOM(fedoraServicesAPIA.retrieveBrowseStructure(this.cluster_name, "ClassifierBrowse", new String[]{doc_id},
     638                                           new String[]{"children"}, new String[]{"siblingPosition"}));
     639    NodeList nl = response.getElementsByTagName(GSXML.NODE_STRUCTURE_ELEM);
     640    if(nl.getLength() > 0) {
     641        Element nodeStructure = (Element)nl.item(0);
     642
     643        if(nodeStructure != null) {
     644        Element root = (Element) GSXML.getChildByTagName(nodeStructure, GSXML.CLASS_NODE_ELEM);
     645        if(root != null) { // get children
     646            NodeList classNodes = root.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
     647            if(classNodes != null) {
     648            children = new String[classNodes.getLength()];
     649            for(int i = 0; i < children.length; i++) {
     650                Element child = (Element)classNodes.item(i);
     651                children[i] = child.getAttribute(GSXML.NODE_ID_ATT);
     652            }
     653            }
     654        }
     655        }
     656    }
     657    } else { // documentnode
     658    response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentStructure(this.cluster_name, new String[]{doc_id},
     659                                         new String[]{"children"}, new String[]{"siblingPosition"}));
     660    String path = GSPath.createPath(new String[]{GSXML.RESPONSE_ELEM, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER,
     661                          GSXML.DOC_NODE_ELEM, GSXML.NODE_STRUCTURE_ELEM, GSXML.DOC_NODE_ELEM});   
     662    Element parentDocNode = (Element) GSXML.getNodeByPath(response, path);
     663
     664    if (parentDocNode == null) {
     665        return top;
     666    } // else
     667    NodeList docNodes = parentDocNode.getElementsByTagName(GSXML.DOC_NODE_ELEM); // only children should remain, since that's what we requested
     668    if(docNodes.getLength() > 0) {
     669        children = new String[docNodes.getLength()];
     670       
     671        for(int i = 0; i < children.length; i++) {
     672        Element e = (Element)docNodes.item(i);
     673        children[i] = e.getAttribute(GSXML.NODE_ID_ATT);
     674        }
     675    } else { // return root node
     676        children = new String[]{doc_id};
     677    }
     678    }
     679   
     680    if (suff.equals("fc")) {
     681      return children[0];
     682    } else if (suff.equals("lc")) {
     683      return children[children.length-1];
     684    } else {
     685      if (suff.equals("ss")) {
     686    return children[sibling_num-1];
     687      }
     688      // find the position that we are at.
     689      int i=0;
     690      while(i<children.length) {
     691    if (children[i].equals(top)) {
     692      break;
     693    }
     694    i++;
     695      }
     696       
     697      if (suff.equals("ns")) {
     698    if (i==children.length-1) {
     699      return children[i];
     700    }
     701    return children[i+1];
     702      } else if (suff.equals("ps")) {
     703    if (i==0) {
     704      return children[i];
     705    }
     706    return children[i-1];
     707      }
     708    }
     709
     710    return top;
     711  }
     712
     713
     714    protected Element getResponseAsDOM(String response) {
     715    if(response == null) { // will not be the case, because an empty 
     716        return null;    // response message will be sent instead
     717    }
     718
     719    Element message = null;     
     720    try{
     721        // turn the String xml response into a DOM tree:   
     722        DocumentBuilder builder
     723        = DocumentBuilderFactory.newInstance().newDocumentBuilder();
     724        Document doc
     725        = builder.parse(new InputSource(new StringReader(response)));
     726        message = doc.getDocumentElement();
     727    } catch(Exception e){
     728        if(response == null) {
     729        response = "";
     730        }
     731        logger.error("An error occurred while trying to parse the response: ");
     732        logger.error(response);
     733        logger.error(e.getMessage());
     734    }
     735   
     736    // Error elements in message will be processed outside of here, just return the message
     737    return message;
     738    }
     739
     740    /* //process method for stylesheet requests   
     741    protected Element processFormat(Element request) {} */
     742   
     743    /* returns the service list for the subclass */
     744    /* protected Element getServiceList(String lang) {
     745    // for now, it is static and has no language stuff
     746    return (Element) this.short_service_info.cloneNode(true);
     747    }*/
     748
     749    /** returns a specific service description */
     750  protected Element getServiceDescription(Document doc, String service, String lang, String subset) {
     751    if(!lang.equals(prevLanguage)) {
     752        prevLanguage = lang;
     753        fedoraServicesAPIA.setLanguage(lang);
     754    }
     755    String serviceResponse = fedoraServicesAPIA.describeService(service);
     756    Element response = getResponseAsDOM(serviceResponse);
     757
     758    // should be no chance of an npe, since FedoraGS3 lists the services, so will have descriptions for each
     759    Element e = (Element)response.getElementsByTagName(GSXML.SERVICE_ELEM).item(0);
     760    e = (Element)doc.importNode(e, true);
     761    return e;
     762    }
     763
     764    /** overloaded version for no args case */
     765    protected String getTextString(String key, String lang) {
     766    return getTextString(key, lang, null, null);
     767    }
     768
     769    protected String getTextString(String key, String lang, String dictionary) {
     770    return getTextString(key, lang, dictionary, null);
     771    }
     772    protected String getTextString(String key, String lang, String [] args) {
     773    return getTextString(key, lang, null, args);
     774    }
     775   
     776    /** getTextString - retrieves a language specific text string for the given
     777key and locale, from the specified resource_bundle (dictionary)
     778    */
     779    protected String getTextString(String key, String lang, String dictionary, String[] args) {
     780
     781    // we want to use the collection class loader in case there are coll specific files
     782    if (dictionary != null) {
     783        // just try the one specified dictionary
     784        Dictionary dict = new Dictionary(dictionary, lang, this.class_loader);
     785        String result = dict.get(key, args);
     786        if (result == null) { // not found
     787        return "_"+key+"_";
     788        }
     789        return result;
     790    }
     791
     792    // now we try class names for dictionary names
     793    String class_name = this.getClass().getName();
     794    class_name = class_name.substring(class_name.lastIndexOf('.')+1);
     795    Dictionary dict = new Dictionary(class_name, lang, this.class_loader);
     796    String result = dict.get(key, args);
     797    if (result != null) {
     798        return result;
     799    }
     800
     801    // we have to try super classes
     802    Class c = this.getClass().getSuperclass();
     803    while (result == null && c != null) {
     804        class_name = c.getName();
     805        class_name = class_name.substring(class_name.lastIndexOf('.')+1);
     806        if (class_name.equals("ServiceRack")) {
     807        // this is as far as we go
     808        break;
     809        }
     810        dict = new Dictionary(class_name, lang, this.class_loader);
     811        result = dict.get(key, args);
     812        c = c.getSuperclass();
     813    }
     814    if (result == null) {
     815        return "_"+key+"_";
     816    }
     817    return result;
     818   
     819    }
     820
     821    protected String getMetadataNameText(String key, String lang) {
     822
     823    String properties_name = "metadata_names";
     824    Dictionary dict = new Dictionary(properties_name, lang);
     825   
     826    String result = dict.get(key);
     827    if (result == null) { // not found
     828        return null;
     829    }
     830    return result;
     831    }
     832
    89833    public static class BasicTextMacroResolver extends MacroResolver { 
    90834    private static final Pattern p_back_slash = Pattern.compile("\\\"");// create a pattern "\\\"", but it matches both " and \"
     
    137881    }
    138882
    139     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.FedoraServiceProxy.class.getName());
    140     protected MacroResolver macro_resolver = null;
    141 
    142 
    143     /** The handle to the fedora connection */
    144     private DigitalLibraryServicesAPIA fedoraServicesAPIA;
    145 
    146     private String prevLanguage = "";
    147 
    148     public void cleanUp() {
    149     super.cleanUp();
    150     }
    151    
    152     /** sets the message router */
    153     public void setMessageRouter(MessageRouter m) {
    154        this.router = m;
    155        setLibraryName(m.getLibraryName());
    156     }
    157 
    158     /** the no-args constructor */
    159     public FedoraServiceProxy() {
    160     super();
    161 
    162     this.converter = new XMLConverter();
    163     this.doc = this.converter.newDOM();
    164     this.short_service_info = this.doc.createElement(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
    165     this.macro_resolver = new BasicTextMacroResolver();
    166     }
    167    
    168 
    169     /* configure the service module
    170      *
    171      * @param info the XML node <serviceRack name="XXX"/> with name equal
    172      * to the class name (of the subclass)
    173      *
    174      * must configure short_service_info_ and service_info_map_
    175      * @return true if configured ok
    176      * must be implemented in subclasses
    177      */
    178     /*public boolean configure(Element info) {
    179     return configure(info, null);
    180     }*/
    181    
    182     public boolean configure(Element info, Element extra_info) {
    183     // set up the class loader
    184        
    185     if (!super.configure(info, extra_info)){
    186         return false;
    187     }
    188 
    189     // Try to instantiate a Fedora dl handle
    190     try {
    191         // Fedora connection settings defaults.
    192         // Read host and port from global.properties, since by default, we expect the Greenstone server to be used
    193         Properties globalProperties = new Properties();
    194         globalProperties.load(Class.forName("org.greenstone.util.GlobalProperties").getClassLoader().getResourceAsStream("global.properties"));
    195         String host = globalProperties.getProperty("tomcat.server", "localhost");
    196         String port = globalProperties.getProperty("tomcat.port", "8383");
    197         String protocol = "http";
    198         String username = "fedoraIntCallUser"; //"fedoraAdmin"
    199         String password = "changeme"; //"<user password>"
    200 
    201         // See if buildConfig.xml overrides any of the defaults
    202         // info is the <serviceRack> Element from buildConfig.xml (extra_info are the Elements of collectionConfig.xml)
    203 
    204         NodeList nodes = info.getElementsByTagName("fedoraConnection");
    205         if(nodes != null && nodes.getLength() > 0) {
    206 
    207         Element fedoraElement = (Element)nodes.item(0);
    208         if(fedoraElement.hasAttribute("protocol")) {
    209             protocol = fedoraElement.getAttribute("protocol");
    210         }       
    211         if(fedoraElement.hasAttribute("host")) {
    212             host = fedoraElement.getAttribute("host");
    213         }
    214         if(fedoraElement.hasAttribute("port")) {
    215             port = fedoraElement.getAttribute("port");
    216         }
    217         if(fedoraElement.hasAttribute("username")) {
    218             username = fedoraElement.getAttribute("username");
    219         }
    220         if(fedoraElement.hasAttribute("password")) {
    221             password = fedoraElement.getAttribute("password");
    222         }       
    223         }   
    224 
    225         fedoraServicesAPIA = new FedoraServicesAPIA(protocol, host, Integer.parseInt(port), username, password);
    226 
    227     } catch(org.greenstone.fedora.services.FedoraGS3Exception.CancelledException e) {
    228         // The user pressed cancel in the fedora services instantiation dialog
    229         return false;
    230     } catch(Exception e) {
    231         logger.error("Error instantiating the interface to the Fedora Repository:\n", e); // second parameter prints e's stacktrace
    232         return false;
    233     }
    234 
    235    
    236     // Need to put the available services into short_service_info
    237     // This is used by DefaultReceptionist.process() has an exception. But DefaultReceptionist.addExtraInfo()
    238     // isn't helpful, and the problem actually already occurs in
    239     // Receptionist.process() -> PageAction.process() -> MessageRouter.process()
    240     // -> Collection/ServiceCluster.process() -> ServiceCluster.configureServiceRackList()
    241     // -> ServiceRack.process() -> ServiceRack.processDescribe() -> ServiceRack.getServiceList().
    242     // ServiceRack.getServiceList() requires this ServiceRack's services to be filled into the
    243     // short_service_info Element which needs to be done in this FedoraServiceProxy.configure().
    244    
    245     // get the display and format elements from the coll config file for
    246     // the classifiers
    247     AbstractBrowse.extractExtraClassifierInfo(info, extra_info);
    248 
    249     // Copied from IViaProxy.java:
    250     String collection = fedoraServicesAPIA.describeCollection(this.cluster_name);
    251 
    252     Element collNode = getResponseAsDOM(collection);
    253     Element serviceList = (Element)collNode.getElementsByTagName(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER).item(0);
    254 
    255 //this.short_service_info.appendChild(short_service_info.getOwnerDocument().importNode(serviceList, true));
    256     // we want the individual service Elements, not the serviceList Element which will wrap it later
    257     NodeList services = collNode.getElementsByTagName(GSXML.SERVICE_ELEM);
    258     for(int i = 0; i < services.getLength(); i++) {
    259         Node service = services.item(i);
    260         this.short_service_info.appendChild(short_service_info.getOwnerDocument().importNode(service, true));
    261     }
    262 
    263     // add some format info to service map if there is any
    264     String path = GSPath.appendLink(GSXML.SEARCH_ELEM, GSXML.FORMAT_ELEM);
    265     Element search_format = (Element) GSXML.getNodeByPath(extra_info, path);
    266     if (search_format != null) {
    267         this.format_info_map.put("TextQuery", this.doc.importNode(search_format, true));
    268         this.format_info_map.put("FieldQuery", this.doc.importNode(search_format, true));
    269     }
    270    
    271     // look for document display format
    272     path = GSPath.appendLink(GSXML.DISPLAY_ELEM, GSXML.FORMAT_ELEM);
    273     Element display_format = (Element)GSXML.getNodeByPath(extra_info, path);
    274     if (display_format != null) {
    275         this.format_info_map.put("DocumentContentRetrieve", this.doc.importNode(display_format, true));
    276         // should we make a copy?
    277     }
    278 
    279     // the format info
    280     Element cb_format_info = this.doc.createElement(GSXML.FORMAT_ELEM);
    281     boolean format_found = false;
    282 
    283     // look for classifier <browse><format>
    284     path = GSPath.appendLink(GSXML.BROWSE_ELEM, GSXML.FORMAT_ELEM);
    285     Element browse_format = (Element)GSXML.getNodeByPath(extra_info, path);
    286     if (browse_format != null) {
    287         cb_format_info.appendChild(GSXML.duplicateWithNewName(this.doc, browse_format, GSXML.DEFAULT_ELEM, true));
    288         format_found = true;
    289     }
    290    
    291     // add in to the description a simplified list of classifiers
    292     Element browse = (Element)GSXML.getChildByTagName(extra_info, "browse"); // the <browse>
    293     NodeList classifiers = browse.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
    294     for(int i=0; i<classifiers.getLength(); i++) {
    295         Element cl = (Element)classifiers.item(i);
    296         Element new_cl = (Element)this.doc.importNode(cl, false); // just import this node, not the children
    297        
    298         // get the format info out, and put inside a classifier element
    299         Element format_cl = (Element)new_cl.cloneNode(false);
    300         Element format = (Element)GSXML.getChildByTagName(cl, GSXML.FORMAT_ELEM);
    301         if (format != null) {
    302        
    303         //copy all the children
    304         NodeList elems = format.getChildNodes();
    305         for (int j=0; j<elems.getLength();j++) {
    306             format_cl.appendChild(this.doc.importNode(elems.item(j), true));
    307         }
    308         cb_format_info.appendChild(format_cl);
    309         format_found = true;
    310         }
    311                
    312     }
    313        
    314     if (format_found) {
    315         this.format_info_map.put("ClassifierBrowse", cb_format_info);
    316     }
    317    
    318 
    319     // set up the macro resolver
    320     macro_resolver.setSiteDetails(this.site_http_address, this.cluster_name, this.getLibraryName());
    321     Element replacement_elem = (Element)GSXML.getChildByTagName(extra_info, "replaceList");
    322     if (replacement_elem != null) {
    323         macro_resolver.addMacros(replacement_elem);
    324     }
    325     // look for any refs to global replace lists
    326     NodeList replace_refs_elems = extra_info.getElementsByTagName("replaceListRef");
    327     for (int i=0; i<replace_refs_elems.getLength(); i++) {
    328         String id = ((Element)replace_refs_elems.item(i)).getAttribute("id");
    329         if (!id.equals("")) {
    330         Element replace_list = GSXML.getNamedElement(this.router.config_info, "replaceList", "id", id);
    331         if (replace_list != null) {
    332             macro_resolver.addMacros(replace_list);
    333         }
    334         }
    335     }
    336 
    337     // configured ok
    338     return true;
    339     }
    340 
    341  
    342     /* "DocumentContentRetrieve", "DocumentMetadataRetrieve", "DocumentStructureRetrieve",
    343       "TextQuery", "FieldQuery", "ClassifierBrowse", "ClassifierBrowseMetadataRetrieve" */
    344 
    345     protected Element processDocumentContentRetrieve(Element request) {
    346     String[] docIDs = parse(request, GSXML.DOC_NODE_ELEM, GSXML.NODE_ID_ATT);
    347     String[] relLinks = parse(request, GSXML.DOC_NODE_ELEM, "externalURL");
    348    
    349     //logger.error("### request:");
    350     //logger.error(GSXML.elementToString(request, true));
    351 
    352     if(docIDs == null) {
    353         logger.error("DocumentContentRetrieve request specified no doc nodes.\n");
    354         return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
    355     } else {
    356         for(int i = 0; i < docIDs.length; i++) {
    357         //logger.error("BEFORE: docIDs[" + i + "]: " + docIDs[i]);
    358         if(relLinks[i] != null && docIDs[i].startsWith("http://")) { // need to do a look up
    359             docIDs[i] = translateExternalId(docIDs[i]);
    360         } else {
    361             docIDs[i] = translateId(docIDs[i]);         
    362         }
    363         //logger.error("AFTER: docIDs[" + i + "]: " + docIDs[i]);
    364         }
    365     }
    366    
    367     String lang = request.getAttribute(GSXML.LANG_ATT);
    368     if(!lang.equals(prevLanguage)) {
    369         prevLanguage = lang;
    370         fedoraServicesAPIA.setLanguage(lang);
    371     }
    372    
    373     // first param (the collection) is not used by Fedora   
    374     Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentContent(this.cluster_name, docIDs));
    375 
    376    
    377     // resolve any collection specific macros
    378     NodeList nodeContents = response.getElementsByTagName(GSXML.NODE_CONTENT_ELEM);
    379     for(int i = 0; i < nodeContents.getLength(); i++) {
    380         Element nodeContent = (Element)nodeContents.item(i);
    381         /*if(nodeContent != null) {
    382         nodeContent = (Element)nodeContent.getFirstChild(); // textNode
    383         }*/
    384         //logger.error("GIRAFFE 1. content retrieve response - nodeContent: " + GSXML.nodeToFormattedString(nodeContent));
    385         String docContent = nodeContent.getFirstChild().getNodeValue(); // getTextNode and get its contents.
    386         //logger.error("GIRAFFE 2. content retrieve response - docContent: " + docContent);
    387        
    388         if(docContent != null) {
    389         // get document text and resolve and macros. Rel and external links have _httpextlink_ set by HTMLPlugin
    390         docContent = macro_resolver.resolve(docContent, lang, MacroResolver.SCOPE_TEXT, ""); // doc_id
    391         nodeContent.getFirstChild().setNodeValue(docContent);
    392         //logger.error("GIRAFFE 3. content retrieve response. Updated docContent: " + docContent);
    393         }
    394     }
    395 
    396     return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
    397     }
    398 
    399     protected Element processDocumentStructureRetrieve(Element request) {
    400     String[] docIDs = parse(request, GSXML.DOC_NODE_ELEM, GSXML.NODE_ID_ATT);
    401     String[] relLinks = parse(request, GSXML.DOC_NODE_ELEM, "externalURL");
    402 
    403     if(docIDs == null) {
    404         logger.error("DocumentStructureRetrieve request specified no doc nodes.\n");
    405         return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
    406     } else {
    407         for(int i = 0; i < docIDs.length; i++) {
    408         //logger.error("BEFORE: docIDs[" + i + "]: " + docIDs[i]);
    409         if(relLinks[i] != null && docIDs[i].startsWith("http://")) { // need to do a look up
    410             docIDs[i] = translateExternalId(docIDs[i]);
    411         } else {
    412             docIDs[i] = translateId(docIDs[i]);
    413         }
    414         }
    415     }
    416 
    417     NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
    418     String structure="";
    419     String info="";
    420     for(int i = 0; i < params.getLength(); i++) {
    421         Element param = (Element)params.item(i);
    422         if(param.getAttribute("name").equals("structure")) {
    423         structure = structure + param.getAttribute("value") + "|";
    424         } else if(param.getAttribute("name").equals("info")) {
    425         info = info + param.getAttribute("value") + "|";
    426         }
    427     }   
    428    
    429     String lang = request.getAttribute(GSXML.LANG_ATT);
    430     if(!lang.equals(prevLanguage)) {
    431         prevLanguage = lang;
    432         fedoraServicesAPIA.setLanguage(lang);
    433     }
    434     Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentStructure(
    435         this.cluster_name, docIDs, new String[]{structure}, new String[]{info}));
    436     return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
    437     }
    438 
    439     protected Element processDocumentMetadataRetrieve(Element request) {
    440     String[] docIDs = parse(request, GSXML.DOC_NODE_ELEM, GSXML.NODE_ID_ATT);
    441     String[] relLinks = parse(request, GSXML.DOC_NODE_ELEM, "externalURL");
    442 
    443     if(docIDs == null) {
    444         logger.error("DocumentMetadataRetrieve request specified no doc nodes.\n");
    445         return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
    446     } else {
    447         for(int i = 0; i < docIDs.length; i++) {
    448         //logger.error("**** relLinks[i]: " + relLinks[i]);
    449         //logger.error("**** docIDs[i]: " + docIDs[i]);
    450         if(relLinks[i] != null && docIDs[i].startsWith("http://")) { // need to do a look up
    451             docIDs[i] = translateExternalId(docIDs[i]);
    452         } else {
    453             docIDs[i] = translateId(docIDs[i]);
    454         }
    455         //logger.error("AFTER: docIDs[" + i + "]: " + docIDs[i]);
    456         }
    457     }
    458    
    459     NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
    460     String[] metafields = {};
    461     if(params.getLength() > 0) {
    462         metafields = new String[params.getLength()];
    463         for(int i = 0; i < metafields.length; i++) {
    464         Element param = (Element)params.item(i);
    465         //if(param.hasAttribute(GSXML.NAME_ATT) && param.getAttribute(GSXML.NAME_ATT).equals("metadata") && param.hasAttribute(GSXML.VALUE_ATT)) {
    466         if(param.hasAttribute(GSXML.VALUE_ATT)){
    467             metafields[i] = param.getAttribute(GSXML.VALUE_ATT);
    468         } else {
    469             metafields[i] = "";
    470         }
    471         }
    472     }
    473 
    474     String lang = request.getAttribute(GSXML.LANG_ATT);
    475     if(!lang.equals(prevLanguage)) {
    476         prevLanguage = lang;
    477         fedoraServicesAPIA.setLanguage(lang);
    478     }
    479     Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentMetadata(
    480                         this.cluster_name, docIDs, metafields));
    481     return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
    482     }
    483 
    484     protected Element processClassifierBrowseMetadataRetrieve(Element request) {   
    485     String[] classIDs = parse(request, GSXML.CLASS_NODE_ELEM, GSXML.NODE_ID_ATT);
    486     //String[] relLinks = parse(request, GSXML.CLASS_NODE_ELEM, "externalURL");
    487 
    488     if(classIDs == null) {
    489         logger.error("ClassifierBrowseMetadataRetrieve request specified no classifier nodes.\n");
    490         return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
    491     } else {
    492         for(int i = 0; i < classIDs.length; i++) {
    493         classIDs[i] = translateId(classIDs[i]);
    494         }
    495     }
    496    
    497     NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
    498     String[] metafields = {};
    499     if(params.getLength() > 0) {
    500         metafields = new String[params.getLength()];
    501         for(int i = 0; i < metafields.length; i++) {
    502         Element param = (Element)params.item(i);
    503         if(param.hasAttribute(GSXML.VALUE_ATT)){
    504             metafields[i] = param.getAttribute(GSXML.VALUE_ATT);
    505         } else {
    506             metafields[i] = "";
    507         }
    508         }
    509     }
    510    
    511     String lang = request.getAttribute(GSXML.LANG_ATT);
    512     if(!lang.equals(prevLanguage)) {
    513         prevLanguage = lang;
    514         fedoraServicesAPIA.setLanguage(lang);
    515     }
    516     Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveBrowseMetadata(
    517            this.cluster_name, "ClassifierBrowseMetadataRetrieve", classIDs, metafields));
    518     //logger.error("**** Response from retrieveBrowseMeta: " + GSXML.elementToString(response, true));
    519     return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
    520     }
    521 
    522     protected Element processClassifierBrowse(Element request) {
    523     String collection = this.cluster_name;
    524     String lang = request.getAttribute(GSXML.LANG_ATT);
    525     if(!lang.equals(prevLanguage)) {
    526         prevLanguage = lang;
    527         fedoraServicesAPIA.setLanguage(lang);
    528     }
    529 
    530     NodeList classNodes = request.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
    531     if(classNodes == null || classNodes.getLength() <= 0) {
    532         logger.error("ClassifierBrowse request specified no classifier IDs.\n");
    533         return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
    534     }
    535     String classifierIDs[] = new String[classNodes.getLength()];
    536     for(int i = 0; i < classifierIDs.length; i++) {
    537         Element e = (Element)classNodes.item(i);
    538         classifierIDs[i] = e.getAttribute(GSXML.NODE_ID_ATT);
    539         classifierIDs[i] = translateId(classifierIDs[i]);   
    540     }
    541    
    542     NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
    543     String structure="";
    544     String info="";
    545     for(int i = 0; i < params.getLength(); i++) {
    546         Element param = (Element)params.item(i);
    547         if(param.getAttribute("name").equals("structure")) {
    548         structure = structure + param.getAttribute("value") + "|";
    549         } else if(param.getAttribute("name").equals("info")) {
    550         info = info + param.getAttribute("value") + "|";
    551         }
    552     }
    553     ///structure = structure + "siblings"; //test for getting with classifier browse structure: siblings
    554    
    555     Element response
    556         = getResponseAsDOM(fedoraServicesAPIA.retrieveBrowseStructure(collection, "ClassifierBrowse", classifierIDs,
    557                                       new String[] {structure}, new String[] {info}));
    558     //logger.error("**** FedoraServiceProxy - Response from retrieveBrowseStructure: " + GSXML.elementToString(response, true));   
    559    
    560     return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
    561     }
    562 
    563     protected Element processTextQuery(Element request) {
    564     return processQuery(request, "TextQuery");
    565     }
    566 
    567     protected Element processFieldQuery(Element request) {
    568     return processQuery(request, "FieldQuery");
    569     }
    570 
    571     protected Element processQuery(Element request, String querytype) {
    572     String collection = this.cluster_name;
    573 
    574     String lang = request.getAttribute(GSXML.LANG_ATT);
    575     if(!lang.equals(prevLanguage)) {
    576         prevLanguage = lang;
    577         fedoraServicesAPIA.setLanguage(lang);
    578     }
    579 
    580     NodeList paramNodes = request.getElementsByTagName(GSXML.PARAM_ELEM);
    581     if(paramNodes.getLength() > 0) {
    582         HashMap<String, String> params = new HashMap<String, String>(paramNodes.getLength());
    583         for(int i = 0; i < paramNodes.getLength(); i++) {
    584         Element param = (Element)paramNodes.item(i);
    585         params.put(param.getAttribute(GSXML.NAME_ATT), param.getAttribute(GSXML.VALUE_ATT));
    586         }
    587 
    588         Element response = getResponseAsDOM(fedoraServicesAPIA.query(collection, querytype, params));
    589         return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
    590     } else {
    591         logger.error("TextQuery request specified no parameters.\n");
    592         return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
    593     }
    594     }
    595 
    596     // get the requested nodeIDs out of a request message
    597     protected String[] parse(Element request, String nodeType, String attribute) { 
    598     String[] nodevalues = null;
    599     int count = 0;
    600 
    601     Element docList = (Element) GSXML.getChildByTagName(request, nodeType+GSXML.LIST_MODIFIER);
    602     if (docList != null) {     
    603         NodeList docNodes = docList.getElementsByTagName(nodeType);
    604         if(docNodes.getLength() > 0) {
    605         nodevalues = new String[docNodes.getLength()];
    606         for(int i = 0; i < nodevalues.length; i++) {
    607             Element e = (Element)docNodes.item(i);
    608             String id = e.getAttribute(attribute);
    609             // Not sure why there are at times requests for hashXXX.dir, which is not a fedora PID
    610             // To skip these: if not requesting an externalURL and if requesting a docNode,
    611             // then the ID has to contain the : character special to fedora PIDs
    612             if(attribute == "externalURL" || (nodeType != GSXML.DOC_NODE_ELEM || id.contains(":"))) {
    613             nodevalues[count++] = id;
    614             }
    615         }
    616         }
    617     }
    618 
    619     if(count == 0) {
    620         return null;
    621     }
    622 
    623     String[] tmp = new String[count];
    624     for(int i = 0; i < count; i++) {
    625         tmp[i] = nodevalues[i];
    626     }
    627     nodevalues = null;
    628     nodevalues = tmp;
    629 
    630     return nodevalues;
    631     }
    632 
    633 
    634     /** if id ends in .fc, .pc etc, then translate it to the correct id
    635      * For now (for testing things work) the default implementation is to just remove the suffix */
    636     protected String translateId(String id) {
    637     if (OID.needsTranslating(id)) {
    638         return OID.translateOID(this, id); //return translateOID(id);
    639     }
    640     return id;
    641     }
    642    
    643     /** if an id is not a greenstone id (an external id) then translate
    644      * it to a greenstone one
    645      * default implementation: return the id. Custom implementation:
    646      * the id is a url that maps to a fedorapid whose dc.title contains the required HASHID */
    647     protected String translateExternalId(String id) {
    648     //logger.error("*** to translate an external ID: " + id); /////return id;
    649     return this.externalId2OID(id);
    650     }
    651 
    652     /** converts an external id to greenstone OID. External ID is a URL link
    653      * that, if relative, maps to a fedorapid that has an entry in fedora.
    654      * The dc:title meta for that fedorapid will contain the required OID. */
    655     public String externalId2OID(String extid) {
    656     if(extid.endsWith(".rt") && (extid.indexOf('.') != extid.lastIndexOf('.'))) {
    657            // .rt is not file extension, but Greenstone request for root of document
    658            // not relevant for external ID
    659            extid = extid.substring(0, extid.length()-3);
    660     }
    661 
    662        // the following method is unique to FedoraServicesAPIA
    663     String response = ((FedoraServicesAPIA)fedoraServicesAPIA).getDocIDforURL(extid, this.cluster_name);
    664     if(response.indexOf(GSXML.ERROR_ELEM) != -1) {
    665         logger.error("**** The following error occurred when trying to find externalID for ID " + extid);
    666         logger.error(response);
    667         return extid;
    668     }
    669     if(response.equals("")) {
    670         return extid;
    671     } else {
    672         return response;
    673     }
    674     }
    675 
    676 
    677   /** translates relative oids into proper oids:
    678    * .pr (parent), .rt (root) .fc (first child), .lc (last child),
    679    * .ns (next sibling), .ps (previous sibling)
    680    * .np (next page), .pp (previous page) : links sections in the order that you'd read the document
    681    * a suffix is expected to be present so test before using
    682    */
    683     public String processOID(String doc_id, String top, String suff, int sibling_num) {
    684 
    685     // send off request to get sibling etc. information from Fedora
    686     Element response = null;
    687     String[] children = null;
    688     if(doc_id.startsWith("CL")) { // classifiernode
    689     response = getResponseAsDOM(fedoraServicesAPIA.retrieveBrowseStructure(this.cluster_name, "ClassifierBrowse", new String[]{doc_id},
    690                                            new String[]{"children"}, new String[]{"siblingPosition"}));
    691     NodeList nl = response.getElementsByTagName(GSXML.NODE_STRUCTURE_ELEM);
    692     if(nl.getLength() > 0) {
    693         Element nodeStructure = (Element)nl.item(0);
    694 
    695         if(nodeStructure != null) {
    696         Element root = (Element) GSXML.getChildByTagName(nodeStructure, GSXML.CLASS_NODE_ELEM);
    697         if(root != null) { // get children
    698             NodeList classNodes = root.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
    699             if(classNodes != null) {
    700             children = new String[classNodes.getLength()];
    701             for(int i = 0; i < children.length; i++) {
    702                 Element child = (Element)classNodes.item(i);
    703                 children[i] = child.getAttribute(GSXML.NODE_ID_ATT);
    704             }
    705             }
    706         }
    707         }
    708     }
    709     } else { // documentnode
    710     response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentStructure(this.cluster_name, new String[]{doc_id},
    711                                          new String[]{"children"}, new String[]{"siblingPosition"}));
    712     String path = GSPath.createPath(new String[]{GSXML.RESPONSE_ELEM, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER,
    713                           GSXML.DOC_NODE_ELEM, GSXML.NODE_STRUCTURE_ELEM, GSXML.DOC_NODE_ELEM});   
    714     Element parentDocNode = (Element) GSXML.getNodeByPath(response, path);
    715 
    716     if (parentDocNode == null) {
    717         return top;
    718     } // else
    719     NodeList docNodes = parentDocNode.getElementsByTagName(GSXML.DOC_NODE_ELEM); // only children should remain, since that's what we requested
    720     if(docNodes.getLength() > 0) {
    721         children = new String[docNodes.getLength()];
    722        
    723         for(int i = 0; i < children.length; i++) {
    724         Element e = (Element)docNodes.item(i);
    725         children[i] = e.getAttribute(GSXML.NODE_ID_ATT);
    726         }
    727     } else { // return root node
    728         children = new String[]{doc_id};
    729     }
    730     }
    731    
    732     if (suff.equals("fc")) {
    733       return children[0];
    734     } else if (suff.equals("lc")) {
    735       return children[children.length-1];
    736     } else {
    737       if (suff.equals("ss")) {
    738     return children[sibling_num-1];
    739       }
    740       // find the position that we are at.
    741       int i=0;
    742       while(i<children.length) {
    743     if (children[i].equals(top)) {
    744       break;
    745     }
    746     i++;
    747       }
    748        
    749       if (suff.equals("ns")) {
    750     if (i==children.length-1) {
    751       return children[i];
    752     }
    753     return children[i+1];
    754       } else if (suff.equals("ps")) {
    755     if (i==0) {
    756       return children[i];
    757     }
    758     return children[i-1];
    759       }
    760     }
    761 
    762     return top;
    763   }
    764 
    765 
    766     protected Element getResponseAsDOM(String response) {
    767     if(response == null) { // will not be the case, because an empty 
    768         return null;    // response message will be sent instead
    769     }
    770 
    771     Element message = null;     
    772     try{
    773         // turn the String xml response into a DOM tree:   
    774         DocumentBuilder builder
    775         = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    776         Document doc
    777         = builder.parse(new InputSource(new StringReader(response)));
    778         message = doc.getDocumentElement();
    779     } catch(Exception e){
    780         if(response == null) {
    781         response = "";
    782         }
    783         logger.error("An error occurred while trying to parse the response: ");
    784         logger.error(response);
    785         logger.error(e.getMessage());
    786     }
    787    
    788     // Error elements in message will be processed outside of here, just return the message
    789     return message;
    790     }
    791 
    792     /* //process method for stylesheet requests   
    793     protected Element processFormat(Element request) {} */
    794    
    795     /* returns the service list for the subclass */
    796     /* protected Element getServiceList(String lang) {
    797     // for now, it is static and has no language stuff
    798     return (Element) this.short_service_info.cloneNode(true);
    799     }*/
    800 
    801     /** returns a specific service description */
    802     protected Element getServiceDescription(String service, String lang, String subset) {
    803     if(!lang.equals(prevLanguage)) {
    804         prevLanguage = lang;
    805         fedoraServicesAPIA.setLanguage(lang);
    806     }
    807     String serviceResponse = fedoraServicesAPIA.describeService(service);
    808     Element response = getResponseAsDOM(serviceResponse);
    809 
    810     // should be no chance of an npe, since FedoraGS3 lists the services, so will have descriptions for each
    811     Element e = (Element)response.getElementsByTagName(GSXML.SERVICE_ELEM).item(0);
    812     e = (Element)this.doc.importNode(e, true);
    813     return e;
    814     }
    815 
    816     /** overloaded version for no args case */
    817     protected String getTextString(String key, String lang) {
    818     return getTextString(key, lang, null, null);
    819     }
    820 
    821     protected String getTextString(String key, String lang, String dictionary) {
    822     return getTextString(key, lang, dictionary, null);
    823     }
    824     protected String getTextString(String key, String lang, String [] args) {
    825     return getTextString(key, lang, null, args);
    826     }
    827    
    828     /** getTextString - retrieves a language specific text string for the given
    829 key and locale, from the specified resource_bundle (dictionary)
    830     */
    831     protected String getTextString(String key, String lang, String dictionary, String[] args) {
    832 
    833     // we want to use the collection class loader in case there are coll specific files
    834     if (dictionary != null) {
    835         // just try the one specified dictionary
    836         Dictionary dict = new Dictionary(dictionary, lang, this.class_loader);
    837         String result = dict.get(key, args);
    838         if (result == null) { // not found
    839         return "_"+key+"_";
    840         }
    841         return result;
    842     }
    843 
    844     // now we try class names for dictionary names
    845     String class_name = this.getClass().getName();
    846     class_name = class_name.substring(class_name.lastIndexOf('.')+1);
    847     Dictionary dict = new Dictionary(class_name, lang, this.class_loader);
    848     String result = dict.get(key, args);
    849     if (result != null) {
    850         return result;
    851     }
    852 
    853     // we have to try super classes
    854     Class c = this.getClass().getSuperclass();
    855     while (result == null && c != null) {
    856         class_name = c.getName();
    857         class_name = class_name.substring(class_name.lastIndexOf('.')+1);
    858         if (class_name.equals("ServiceRack")) {
    859         // this is as far as we go
    860         break;
    861         }
    862         dict = new Dictionary(class_name, lang, this.class_loader);
    863         result = dict.get(key, args);
    864         c = c.getSuperclass();
    865     }
    866     if (result == null) {
    867         return "_"+key+"_";
    868     }
    869     return result;
    870    
    871     }
    872 
    873     protected String getMetadataNameText(String key, String lang) {
    874 
    875     String properties_name = "metadata_names";
    876     Dictionary dict = new Dictionary(properties_name, lang);
    877    
    878     String result = dict.get(key);
    879     if (result == null) { // not found
    880         return null;
    881     }
    882     return result;
    883     }
     883
    884884}
    885885
Note: See TracChangeset for help on using the changeset viewer.