/* * eXist Open Source Native XML Database * Copyright (C) 2007-09 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id$ */ package org.exist.xquery.functions.util; import java.util.Arrays; import java.util.Comparator; import java.util.Date; import org.apache.log4j.Logger; import org.exist.dom.QName; import org.exist.memtree.DocumentImpl; import org.exist.memtree.MemTreeBuilder; import org.exist.xquery.BasicFunction; import org.exist.xquery.Cardinality; import org.exist.xquery.FunctionSignature; import org.exist.xquery.Module; import org.exist.xquery.XPathException; import org.exist.xquery.XQueryContext; import org.exist.xquery.value.*; import org.xml.sax.helpers.AttributesImpl; public class ExtractDocs extends BasicFunction { protected static final Logger logger = Logger.getLogger(ExtractDocs.class); public final static FunctionSignature signature = new FunctionSignature( new QName("extract-docs", UtilModule.NAMESPACE_URI, UtilModule.PREFIX), "Returns an XML document which describes the functions available in a given module. " + "The module is identified through its module namespace URI, which is passed as an argument. " + "The function returns a module documentation in XQDoc format.", new SequenceType[] { new FunctionParameterSequenceType("uri", Type.STRING, Cardinality.EXACTLY_ONE, "The namespace URI of the function module") }, new FunctionReturnSequenceType(Type.NODE, Cardinality.ZERO_OR_ONE, "the xqdocs for the function module")); private final String XQDOC_NS = "http://www.xqdoc.org/1.0"; public ExtractDocs(XQueryContext context) { super(context, signature); } public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException { String moduleURI = args[0].getStringValue(); Module module = context.getModule(moduleURI); if (module == null || !module.isInternalModule()) { return Sequence.EMPTY_SEQUENCE; } MemTreeBuilder builder = context.getDocumentBuilder(); int nodeNr = builder.startElement(XQDOC_NS, "xqdoc", "xqdoc", null); builder.startElement(XQDOC_NS, "control", "control", null); simpleElement(builder, "date", new DateTimeValue(new Date()).getStringValue()); simpleElement(builder, "version", "1.0"); builder.endElement(); module(module, builder); functions(module, builder); builder.endElement(); return builder.getDocument().getNode(nodeNr); } private void functions(Module module, MemTreeBuilder builder) { builder.startElement(XQDOC_NS, "functions", "functions", null); FunctionSignature[] functions = module.listFunctions(); Arrays.sort(functions, new FunctionSignatureComparator()); for (int i = 0; i < functions.length; i++) { FunctionSignature function = functions[i]; builder.startElement(XQDOC_NS, "function", "function", null); builder.startElement(XQDOC_NS, "comment", "comment", null); String functionDescription = function.getDescription(); simpleElement(builder, "description", functionDescription); int index = -1; if (function.getArgumentTypes() != null) { for (SequenceType parameter : function.getArgumentTypes()) { simpleElement(builder, "param", parameterText(parameter, ++index)); } } else { for (; index < function.getArgumentCount();) { simpleElement(builder, "param", parameterText(null, ++index)); } } if (function.isOverloaded()) { simpleElement(builder, "param", "overloaded"); } SequenceType returnValue = function.getReturnType(); if (returnValue instanceof FunctionReturnSequenceType) { simpleElement(builder, "return", ((FunctionReturnSequenceType) returnValue).getDescription()); } String deprecated = function.getDeprecated(); if (deprecated != null && deprecated.length() > 0) { simpleElement(builder, "deprecated", deprecated); } builder.endElement(); simpleElement(builder, "name", function.getName().getLocalName()); simpleElement(builder, "signature", function.toString()); builder.endElement(); } builder.endElement(); } private String parameterText(SequenceType parameter, int index) { char var = 'a'; StringBuilder buf = new StringBuilder("$"); if (parameter != null && parameter instanceof FunctionParameterSequenceType) { FunctionParameterSequenceType funcType = (FunctionParameterSequenceType)parameter; buf.append(funcType.getAttributeName()); buf.append(" "); buf.append(funcType.getDescription()); } else { buf.append((char)(var + index)); } return buf.toString(); } private void module(Module module, MemTreeBuilder builder) { AttributesImpl attribs = new AttributesImpl(); attribs.addAttribute("", "type", "type", "CDATA", "library"); builder.startElement(XQDOC_NS, "module", "module", attribs); simpleElement(builder, "uri", module.getNamespaceURI()); simpleElement(builder, "name", module.getDefaultPrefix()); builder.startElement(XQDOC_NS, "comment", "comment", null); simpleElement(builder, "description", module.getDescription()); try { simpleElement(builder, "since", module.getReleaseVersion()); } catch (AbstractMethodError e) { logger.error("Problem with function module for [" + module.getNamespaceURI() + "]", e); } catch (Exception e) { logger.error("Problem with function module for [" + module.getNamespaceURI() + "]", e); } builder.endElement(); builder.endElement(); } private void simpleElement(MemTreeBuilder builder, String tag, String value) { builder.startElement(XQDOC_NS, tag, tag, null); builder.characters(value == null ? "" : value); builder.endElement(); } } //////////////////////////////////////////////////FunctionSignatureComparator //To sort directories before funcSigs, then alphabetically. class FunctionSignatureComparator implements Comparator<FunctionSignature> { // Comparator interface requires defining compare method. public int compare(FunctionSignature funcSiga, FunctionSignature funcSigb) { //... Sort directories before funcSigs, // otherwise alphabetical ignoring case. return funcSiga.toString().compareToIgnoreCase(funcSigb.toString()); } }