/* * AbstractBrowse.java * Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.greenstone.gsdl3.service; // Greenstone classes import org.greenstone.gsdl3.util.GSXML; import org.greenstone.gsdl3.util.GSPath; import org.greenstone.gsdl3.util.MacroResolver; import org.greenstone.gsdl3.util.OID; // XML classes import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; // General Java classes import java.util.ArrayList; import org.apache.log4j.*; /** Partially implements a generic classifier service * * @author Katherine Don */ public abstract class AbstractBrowse extends ServiceRack { static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractBrowse.class.getName()); // the browsing services private static final String CLASSIFIER_SERVICE = "ClassifierBrowse"; private static final String CLASSIFIER_METADATA_SERVICE = "ClassifierBrowseMetadataRetrieve"; // do we want to keep info request? protected static final String STRUCT_PARAM = "structure"; protected static final String INFO_PARAM = "info"; protected static final String STRUCT_ANCESTORS = "ancestors"; protected static final String STRUCT_PARENT = "parent"; protected static final String STRUCT_SIBS = "siblings"; protected static final String STRUCT_CHILDREN = "children"; protected static final String STRUCT_DESCENDS = "descendants"; protected static final String STRUCT_ENTIRE = "entire"; protected static final String INFO_NUM_SIBS = "numSiblings"; protected static final String INFO_NUM_CHILDREN = "numChildren"; protected static final String INFO_SIB_POS = "siblingPosition"; protected Element config_info = null; // the xml from the config file protected MacroResolver macro_resolver = null; protected String default_document_type = null; /** constructor */ protected AbstractBrowse() { } /** configure this service */ public boolean configure(Element info, Element extra_info) { if (!super.configure(info, extra_info)){ return false; } logger.info("Configuring AbstractBrowse..."); this.config_info = info; if (macro_resolver != null) { macro_resolver.setSiteDetails(this.site_http_address, this.cluster_name, this.library_name); // set up the macro resolver Element replacement_elem = (Element)GSXML.getChildByTagName(extra_info, "replaceList"); if (replacement_elem != null) { macro_resolver.addMacros(replacement_elem); } } // check that there are classifiers specified Element class_list = (Element)GSXML.getChildByTagName(info, GSXML.CLASSIFIER_ELEM+GSXML.LIST_MODIFIER); if (class_list == null) { // no classifiers specified return false; } // get the display and format elements from the coll config file for // the classifiers extractExtraClassifierInfo(info, extra_info); // short_service_info_ - the browse one Element cb_service = this.doc.createElement(GSXML.SERVICE_ELEM); cb_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_BROWSE); cb_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_SERVICE); this.short_service_info.appendChild(cb_service); // metadata retrieval for the browsing Element cbmr_service = this.doc.createElement(GSXML.SERVICE_ELEM); cbmr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE); cbmr_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_METADATA_SERVICE); this.short_service_info.appendChild(cbmr_service); // the format info Element cb_format_info = this.doc.createElement(GSXML.FORMAT_ELEM); boolean format_found = false; // try the default format first Element def_format = (Element) GSXML.getChildByTagName(info, GSXML.FORMAT_ELEM); if (def_format != null) { cb_format_info.appendChild(GSXML.duplicateWithNewName(this.doc, def_format, GSXML.DEFAULT_ELEM, true)); format_found = true; } // add in to the description a simplified list of classifiers NodeList classifiers = class_list.getElementsByTagName(GSXML.CLASSIFIER_ELEM); for(int i=0; i0 && position <= cls.getLength()) { node_extra = (Element) cls.item((position -1)); } if (node_extra == null) { logger.error("GS2REtrieve: haven't found extra info for classifier named "+name); continue; } // get the display elements if any - displayName NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM); if (display_names !=null) { Element display = owner.createElement(GSXML.DISPLAY_ELEM); for (int j=0; j */ protected Element createDocNode(String node_id) { Element node = this.doc.createElement(GSXML.DOC_NODE_ELEM); node.setAttribute(GSXML.NODE_ID_ATT, node_id); String doc_type = null; if (default_document_type != null) { doc_type = default_document_type; } else { doc_type = getDocType(node_id); } node.setAttribute(GSXML.DOC_TYPE_ATT, doc_type); String node_type = getNodeType(node_id, doc_type); node.setAttribute(GSXML.NODE_TYPE_ATT, node_type); return node; } /** returns the node type of the specified node. should be one of GSXML.NODE_TYPE_LEAF, GSXML.NODE_TYPE_INTERNAL, GSXML.NODE_TYPE_ROOT */ protected String getNodeType(String node_id, String doc_type) { if (doc_type.equals(GSXML.DOC_TYPE_SIMPLE)) { return GSXML.NODE_TYPE_LEAF; } if (getParentId(node_id)==null) { return GSXML.NODE_TYPE_ROOT; } if (doc_type.equals(GSXML.DOC_TYPE_PAGED)) { return GSXML.NODE_TYPE_LEAF; } if (getChildrenIds(node_id)==null) { return GSXML.NODE_TYPE_LEAF; } return GSXML.NODE_TYPE_INTERNAL; } /** adds all the children of doc_id the the doc element, * and if recursive=true, adds all their children as well*/ protected void addDescendants(Element node, String node_id, boolean recursive) { ArrayList child_ids = getChildrenIds(node_id); if (child_ids==null) return; for (int i=0; i< child_ids.size(); i++) { String child_id = (String)child_ids.get(i); Element child_elem; if (isDocumentId(child_id)) { child_elem = createDocNode(child_id); } else { child_elem = createClassifierNode(child_id); } node.appendChild(child_elem); if (recursive) { addDescendants(child_elem, child_id, recursive); } } } /** adds all the siblings of current_id to the parent element. returns the new current element*/ protected Element addSiblings(Element parent_node, String parent_id, String current_id) { Element current_node = GSXML.getFirstElementChild(parent_node);//(Element)parent_node.getFirstChild(); if (current_node == null) { // create a sensible error message logger.error(" there should be a first child."); return null; } // remove the current child,- will add it in later in its correct place parent_node.removeChild(current_node); // add in all the siblings, addDescendants(parent_node, parent_id, false); // find the node that is now the current node // this assumes that the new node that was created is the same as // the old one that was removed - we may want to replace the new one // with the old one. Element new_current = GSXML.getNamedElement(parent_node, current_node.getNodeName(), GSXML.NODE_ID_ATT, current_id); return new_current; } /** returns true if oid ends in .fc (firstchild), .lc (lastchild), .pr (parent), .ns (next sibling), .ps (prev sibling), .rt (root) .ss (specified sibling), false otherwise */ protected boolean idNeedsTranslating(String node_id) { return OID.needsTranslating(node_id); } /** returns the list of sibling ids, including the specified node_id */ protected ArrayList getSiblingIds(String node_id) { String parent_id = getParentId(node_id); if (parent_id == null) { return null; } return getChildrenIds(parent_id); } /** if id ends in .fc, .pc etc, then translate it to the correct id */ abstract protected String translateId(String node_id); /** returns the document type of the doc that the specified node belongs to. should be one of GSXML.DOC_TYPE_SIMPLE, GSXML.DOC_TYPE_PAGED, GSXML.DOC_TYPE_HIERARCHY */ abstract protected String getDocType(String node_id); /** returns the id of the root node of the document containing node node_id. . may be the same as node_id */ abstract protected String getRootId(String node_id); /** returns a list of the child ids in order, null if no children */ abstract protected ArrayList getChildrenIds(String node_id); /** returns the node id of the parent node, null if no parent */ abstract protected String getParentId(String node_id); /** returns true if the id refers to a document (rather than * a classifier node) */ abstract protected boolean isDocumentId(String node_id); /** get the metadata for the classifier node node_id * returns a metadataList element: * value * if all_metadata is true, returns all available metadata, otherwise just * returns requested metadata */ abstract protected Element getMetadataList(String node_id, boolean all_metadata, ArrayList metadata_names); /** get the particular metadata (identified by the metadata name) for the classifier node node_id * */ abstract protected String getMetadata(String node_id, String metadata_name); /** returns the structural information asked for. * info_type may be one of * INFO_NUM_SIBS, INFO_NUM_CHILDREN, INFO_SIB_POS */ abstract protected String getStructureInfo(String node_id, String info_type); }