/*
* 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);
}