/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at * * http://www.dspace.org/license/ */ package org.dspace.app.webui.jsptag; import java.io.File; import java.io.FilenameFilter; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.TagSupport; import org.apache.log4j.Logger; import org.dspace.app.webui.util.XMLUtil; import org.dspace.core.ConfigurationManager; import org.w3c.dom.Document; /** * A Tag to load and display controlled vocabularies * * @author Miguel Ferreira * @version $Revision$ * */ public class ControlledVocabularyTag extends TagSupport { // path to the jsp that outputs the results of this tag private static final String CONTROLLEDVOCABULARY_JSPTAG = "/controlledvocabulary/controlledvocabularyTag.jsp"; // the log private static Logger log = Logger.getLogger(ControlledVocabularyTag.class); // a tag attribute that contains the words used to trim the vocabulary tree private String filter; // a tag attribute that activates multiple selection of vocabulary terms private boolean allowMultipleSelection; // a tag attribute that specifies the vocabulary to be displayed private String vocabulary; // an hashtable containing all the loaded vocabularies public Map<String, Document> controlledVocabularies; /** * Process tag */ public int doStartTag() throws JspException { HttpServletRequest request = (HttpServletRequest) pageContext .getRequest(); String vocabulariesPath = ConfigurationManager .getProperty("dspace.dir") + "/config/controlled-vocabularies/"; String addonBaseDirectory = pageContext.getServletContext() .getRealPath("") + "/controlledvocabulary/"; String vocabularyPrunningXSLT = addonBaseDirectory + "vocabularyprune.xsl"; String controlledVocabulary2HtmlXSLT = addonBaseDirectory + "vocabulary2html.xsl"; // Load vocabularies on startup controlledVocabularies = (Map<String, Document>) pageContext.getServletContext().getAttribute("controlledvocabulary.controlledVocabularies"); if (controlledVocabularies == null) { controlledVocabularies = loadControlledVocabularies(vocabulariesPath); pageContext.getServletContext().setAttribute("controlledvocabulary.controlledVocabularies", controlledVocabularies); } try { Map<String, Document> prunnedVocabularies = needsFiltering() ? filterVocabularies(controlledVocabularies, vocabularyPrunningXSLT) : controlledVocabularies; String html = ""; if (vocabulary != null && !vocabulary.equals("")) { html = renderVocabularyAsHTML(prunnedVocabularies.get(vocabulary + ".xml"), controlledVocabulary2HtmlXSLT, isAllowMultipleSelection(), request.getContextPath()); } else { html = renderVocabulariesAsHTML(prunnedVocabularies, controlledVocabulary2HtmlXSLT, isAllowMultipleSelection(), request.getContextPath()); } request.getSession().setAttribute( "controlledvocabulary.vocabularyHTML", html); pageContext.include(CONTROLLEDVOCABULARY_JSPTAG); } catch (Exception e) { log.warn("Exception", e); } return SKIP_BODY; } /** * End processing tag */ public int doEndTag() { return EVAL_PAGE; } /** * Do we gave a filter to apply to the controlled vocabularies? * * @return true if a filter was provided. */ private boolean needsFiltering() { return getFilter() != null && getFilter().length() > 0; } /** * Converts a XML Vocabulary to a HTML tree * * @param vocabularies * A hashtable with all the XML taxonomies/vocabularies loaded as * values * @param xslt * the filename of the stylesheet to apply the XML taxonomies * @param allowMultipleSelection * include checkboxes next to the taxonomy terms * @param contextPath * The context path * @return the HTML that represents the vocabularies */ private String renderVocabulariesAsHTML(Map<String, Document> vocabularies, String xslt, boolean allowMultipleSelection, String contextPath) { StringBuilder result = new StringBuilder(); Iterator<Document> iter = vocabularies.values().iterator(); while (iter.hasNext()) { Document controlledVocabularyXML = iter.next(); result.append(renderVocabularyAsHTML(controlledVocabularyXML, xslt, allowMultipleSelection, contextPath)); } return result.toString(); } /** * Applies a filter to the vocabularies, i.e. it prunes the trees by * removing all the branches that do not contain the words in the filter. * * @param vocabularies * A hashtable with all the XML taxonomies/vocabularies loaded as * values * @param vocabularyPrunningXSLT * the filename of the stylesheet that trimms the taxonomies * @return An hashtable with all the filtered vocabularies */ private Map<String, Document> filterVocabularies(Map<String, Document> vocabularies, String vocabularyPrunningXSLT) { Map<String, Document> prunnedVocabularies = new HashMap<String, Document>(); for (Map.Entry<String, Document> entry : vocabularies.entrySet()) { prunnedVocabularies.put(entry.getKey(), filterVocabulary(entry.getValue(), vocabularyPrunningXSLT, getFilter())); } return prunnedVocabularies; } /** * Renders a taxonomy as HTML by applying a stylesheet. * * @param vocabulary * The XML document representing a taxonomy * @param controlledVocabulary2HtmlXSLT * The filename of the stylesheet that converts the taxonomy to * HTML * @param allowMultipleSelection * include checkboxes next to the taxonomy terms * @param contextPath * The context path * @return the provided taxonomy as HTML. */ public String renderVocabularyAsHTML(Document vocabulary, String controlledVocabulary2HtmlXSLT, boolean allowMultipleSelection, String contextPath) { if (vocabulary == null) { return ""; } String result = ""; try { Map<String, String> parameters = new HashMap<String, String>(); parameters.put("allowMultipleSelection", allowMultipleSelection ? "yes" : "no"); parameters.put("contextPath", contextPath); result = XMLUtil.transformDocumentAsString(vocabulary, parameters, controlledVocabulary2HtmlXSLT); } catch (Exception e) { log.error("Error rendering HTML", e); } return result; } /** * Applies a filter to the provided vocabulary, i.e. it prunes the tree by * removing all the branches that do not contain the words in the filter. * * @param vocabulary * The vocabulary to be trimmed * @param vocabularyPrunningXSLT * The filename of the stylesheet that trims the vocabulary * @param filter * The filter to be applied * @return The trimmed vocabulary. */ public Document filterVocabulary(Document vocabulary, String vocabularyPrunningXSLT, String filter) { if (vocabulary == null) { return null; } try { Map<String, String> parameters = new HashMap<String, String>(); parameters.put("filter", filter); return XMLUtil.transformDocument(vocabulary, parameters, vocabularyPrunningXSLT); } catch (Exception e) { log.error("Error filtering vocabulary", e); return null; } } /** * Loads into memory all the vocabularies found in the given directory. All * files with .xml extension are considered to be controlled vocabularies. * * @param directory * where the files are positioned * @return an hashtable with the filenames of the vocabularies as keys and * the XML documents representing the vocabularies as values. */ private static Map<String, Document> loadControlledVocabularies(String directory) { Map<String, Document> controlledVocabularies = new HashMap<String, Document>(); File dir = new File(directory); FilenameFilter filter = new FilenameFilter() { public boolean accept(File dir, String name) { return name.endsWith(".xml"); } }; String[] children = dir.list(filter); if (children != null && children.length > 0) { for (int i = 0; i < children.length; i++) { String filename = children[i]; try { Document controlledVocabulary = XMLUtil.loadXML(directory + filename); controlledVocabularies.put(filename, controlledVocabulary); log.warn("Loaded vocabulary: " + filename); } catch (Exception e) { log.warn("Failed to load vocabulary from " + filename, e); } } } else { log.warn("Could not find any vocabularies..."); } return controlledVocabularies; } /** * Gets the filter provided as parameter to the tag * * @return the filter */ public String getFilter() { return filter; } /** * Sets the filter * * @param filter * the filter */ public void setFilter(String filter) { this.filter = filter; } /** * Returns the value of the multiple selection parameter * * @return true if the multiple selection was selected */ public boolean isAllowMultipleSelection() { return allowMultipleSelection; } /** * Defines if we want to be able to select multiple terms of the taxonomy * * @param allowMultipleSelection * true if we want to be able to select more than on term */ public void setAllowMultipleSelection(boolean allowMultipleSelection) { this.allowMultipleSelection = allowMultipleSelection; } /** * Gets the name of the vocabulary to be displayed * * @return the name of the vocabulary */ public String getVocabulary() { return vocabulary; } /** * Sets the name of the vocabulary to be displayed. If no name is provided, * all vocabularies loaded will be rendered to the output * * @param vocabulary * the name of the vocabulary to be selected */ public void setVocabulary(String vocabulary) { this.vocabulary = vocabulary; } }