Package org.exist.xquery.functions.inspect

Source Code of org.exist.xquery.functions.inspect.InspectFunction

package org.exist.xquery.functions.inspect;

import org.exist.dom.QName;
import org.exist.memtree.MemTreeBuilder;
import org.exist.xquery.functions.util.UtilModule;
import org.exist.xquery.xqdoc.XQDocHelper;
import org.exist.xquery.*;
import org.exist.xquery.value.*;
import org.xml.sax.helpers.AttributesImpl;

import java.util.Map;
import java.util.Set;

public class InspectFunction extends BasicFunction {

    public final static FunctionSignature SIGNATURE_DEPRECATED =
        new FunctionSignature(
            new QName("inspect-function", UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
            "Returns an XML fragment describing the function referenced by the passed function item.",
            new SequenceType[] {
                new FunctionParameterSequenceType("function", Type.FUNCTION_REFERENCE, Cardinality.EXACTLY_ONE, "The function item to inspect"),
            },
            new FunctionReturnSequenceType(Type.NODE, Cardinality.EXACTLY_ONE, "the signature of the function"));

    public final static FunctionSignature SIGNATURE =
        new FunctionSignature(
            new QName("inspect-function", InspectionModule.NAMESPACE_URI, InspectionModule.PREFIX),
            "Returns an XML fragment describing the function referenced by the passed function item.",
            new SequenceType[] {
                    new FunctionParameterSequenceType("function", Type.FUNCTION_REFERENCE, Cardinality.EXACTLY_ONE, "The function item to inspect"),
            },
            new FunctionReturnSequenceType(Type.NODE, Cardinality.EXACTLY_ONE, "the signature of the function"));

    protected final static QName ARGUMENT_QNAME = new QName("argument");
    protected final static QName DEPRECATED_QNAME = new QName("deprecated");
    protected final static QName DESCRIPTION_QNAME = new QName("description");
    protected final static QName RETURN_QNAME = new QName("returns");
    protected final static QName FUNCTION_QNAME = new QName("function");
    protected final static QName ANNOTATION_QNAME = new QName("annotation");
    protected final static QName ANNOTATION_VALUE_QNAME = new QName("value");
    protected static final QName VERSION_QNAME = new QName("version");
    protected static final QName AUTHOR_QNAME = new QName("author");
    protected static final QName CALLS_QNAME = new QName("calls");

    public InspectFunction(XQueryContext context, FunctionSignature signature) {
        super(context, signature);
    }

    @Override
    public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
        final FunctionReference ref = (FunctionReference) args[0].itemAt(0);
        final FunctionSignature sig = ref.getSignature();
        final MemTreeBuilder builder = context.getDocumentBuilder();
        final int nodeNr = generateDocs(sig, null, builder);
        return builder.getDocument().getNode(nodeNr);
    }

    /**
     * Generate an XML fragment containing information about the function identified by its signature.
     *
     * @param sig the signature of the function to describe
     * @param func the function implementation. If provided, the method will also inspect the function body
     *             and list all functions called from the current function.
     * @param builder builder used to create the XML
     * @return nodeNr of the generated element
     * @throws XPathException
     */
    public static int generateDocs(FunctionSignature sig, UserDefinedFunction func, MemTreeBuilder builder) throws XPathException {
        XQDocHelper.parse(sig);

        final AttributesImpl attribs = new AttributesImpl();
        attribs.addAttribute("", "name", "name", "CDATA", sig.getName().toString());
        attribs.addAttribute("", "module", "module", "CDATA", sig.getName().getNamespaceURI());
        final int nodeNr = builder.startElement(FUNCTION_QNAME, attribs);
        writeParameters(sig, builder);
        final SequenceType returnType = sig.getReturnType();
        if (returnType != null) {
            attribs.clear();
            attribs.addAttribute("", "type", "type", "CDATA", Type.getTypeName(returnType.getPrimaryType()));
            attribs.addAttribute("", "cardinality", "cardinality", "CDATA", Cardinality.getDescription(returnType.getCardinality()));
            builder.startElement(RETURN_QNAME, attribs);
            if (returnType instanceof FunctionReturnSequenceType) {
                final FunctionReturnSequenceType type = (FunctionReturnSequenceType) returnType;
                builder.characters(type.getDescription());
            }
            builder.endElement();
        }
        writeAnnotations(sig, builder);
        if (sig.getDescription() != null) {
            builder.startElement(DESCRIPTION_QNAME, null);
            builder.characters(sig.getDescription());
            builder.endElement();
        }
        final Map<String, String> metadata = sig.getMetadata();
        if (metadata != null) {
            for (final Map.Entry<String, String> meta : metadata.entrySet()) {
                builder.startElement(new QName(meta.getKey()), null);
                builder.characters(meta.getValue());
                builder.endElement();
            }
        }
        if (sig.isDeprecated()) {
            builder.startElement(DEPRECATED_QNAME, null);
            builder.characters(sig.getDeprecated());
            builder.endElement();
        }
        if (func != null) {
            generateDependencies(func, builder);
        }
        builder.endElement();
        return nodeNr;
    }

    private static void writeParameters(FunctionSignature sig, MemTreeBuilder builder) {
        final SequenceType[] arguments = sig.getArgumentTypes();
        if (arguments != null) {
            final AttributesImpl attribs = new AttributesImpl();
            for (final SequenceType type: arguments) {
                attribs.clear();
                attribs.addAttribute("", "type", "type", "CDATA", Type.getTypeName(type.getPrimaryType()));
                attribs.addAttribute("", "cardinality", "cardinality", "CDATA", Cardinality.getDescription(type.getCardinality()));
                if (type instanceof FunctionParameterSequenceType)
                    {attribs.addAttribute("", "var", "var", "CDATA", ((FunctionParameterSequenceType)type).getAttributeName());}
                builder.startElement(ARGUMENT_QNAME, attribs);
                if (type instanceof FunctionParameterSequenceType) {
                    builder.characters(((FunctionParameterSequenceType)type).getDescription());
                }
                builder.endElement();
            }
        }
    }

    private static void writeAnnotations(FunctionSignature signature, MemTreeBuilder builder) throws XPathException {
        final AttributesImpl attribs = new AttributesImpl();
        final Annotation[] annots = signature.getAnnotations();
        if (annots != null) {
            for (final Annotation annot : annots) {
                attribs.clear();
                attribs.addAttribute(null, "name", "name", "CDATA", annot.getName().toString());
                attribs.addAttribute(null, "namespace", "namespace", "CDATA", annot.getName().getNamespaceURI());
                builder.startElement(ANNOTATION_QNAME, attribs);
                final LiteralValue[] value = annot.getValue();
                if (value != null) {
                    for (final LiteralValue literal : value) {
                        builder.startElement(ANNOTATION_VALUE_QNAME, null);
                        builder.characters(literal.getValue().getStringValue());
                        builder.endElement();
                    }
                }
                builder.endElement();
            }
        }
    }

    /**
     * Inspect the provided function implementation and return an XML fragment listing all
     * functions called from the function.
     *
     * @param function
     * @param builder
     */
    public static void generateDependencies(UserDefinedFunction function, MemTreeBuilder builder) {
        FunctionCallVisitor visitor = new FunctionCallVisitor();
        function.getFunctionBody().accept(visitor);
        Set<FunctionSignature> signatures = visitor.getFunctionCalls();
        if (signatures.size() == 0) {
            return;
        }
        builder.startElement(CALLS_QNAME, null);
        final AttributesImpl attribs = new AttributesImpl();
        for (FunctionSignature signature : signatures) {
            attribs.clear();
            attribs.addAttribute(null, "name", "name", "CDATA", signature.getName().toString());
            attribs.addAttribute("", "module", "module", "CDATA", signature.getName().getNamespaceURI());
            attribs.addAttribute("", "arity", "arity", "CDATA", Integer.toString(signature.getArgumentCount()));

            builder.startElement(FUNCTION_QNAME, attribs);
            builder.endElement();
        }
        builder.endElement();
    }
}
TOP

Related Classes of org.exist.xquery.functions.inspect.InspectFunction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.