com.xpn.xwiki.plugin.query.QueryPlugin.java Source code

Java tutorial

Introduction

Here is the source code for com.xpn.xwiki.plugin.query.QueryPlugin.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This 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.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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 software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package com.xpn.xwiki.plugin.query;

import java.util.List;
import java.util.Set;

import javax.jcr.ValueFactory;
import javax.jcr.query.InvalidQueryException;
import javax.jcr.query.Query;

import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.core.query.QueryParser;
import org.apache.jackrabbit.core.query.QueryRootNode;
import org.apache.jackrabbit.value.ValueFactoryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.api.Api;
import com.xpn.xwiki.objects.classes.BaseClass;
import com.xpn.xwiki.plugin.XWikiDefaultPlugin;
import com.xpn.xwiki.plugin.XWikiPluginInterface;
import com.xpn.xwiki.store.XWikiStoreInterface;

/** Plugin for Query API */
public class QueryPlugin extends XWikiDefaultPlugin implements IQueryFactory {
    private static final Logger LOGGER = LoggerFactory.getLogger(QueryPlugin.class);

    XWikiContext context;

    public QueryPlugin(String name, String className, XWikiContext context) throws XWikiException {
        super(name, className, context);
        this.context = context;
    }

    @Override
    public String getName() {
        return "query";
    }

    @Override
    public Api getPluginApi(XWikiPluginInterface plugin, XWikiContext context) {
        return new QueryPluginApi((QueryPlugin) plugin, context);
    }

    /**
     * @deprecated This version si buggy since it use the initial context of the plugin and not the current context
     */
    @Deprecated
    public XWikiContext getContext() {
        return context;
    }

    /**
     * @deprecated This version si buggy since it use the initial context of the plugin and not the current context. For
     *             the store itself this is not major as it is a singleton
     */
    @Deprecated
    public XWikiStoreInterface getStore() {
        return getStore(this);
    }

    public XWikiStoreInterface getStore(IQueryFactory qf) {
        return qf.getContext().getWiki().getStore();
    }

    ValueFactory valueFactory = null;

    public ValueFactory getValueFactory() {
        if (valueFactory == null) {
            valueFactory = ValueFactoryImpl.getInstance();
        }
        return valueFactory;
    }

    /**
     * @deprecated This version si buggy since it use the initial context of the plugin and not the current context
     */
    @Deprecated
    boolean isHibernate() {
        return isHibernate(this);
    }

    boolean isHibernate(IQueryFactory qf) {
        return qf.getContext().getWiki().getHibernateStore() != null;
    }

    /**
     * @deprecated This version si buggy since it use the initial context of the plugin and not the current context
     */
    @Deprecated
    boolean isJcr() {
        return isJcr(this);
    }

    boolean isJcr(IQueryFactory qf) {
        return false;
    }

    /** Translate query string to query tree */
    protected QueryRootNode parse(String query, String language) throws InvalidQueryException {
        if (query == null)
            return null;
        final QueryRootNode qn = QueryParser.parse(query, language, XWikiNamespaceResolver.getInstance());
        return qn;
    }

    /**
     * create xpath query
     * 
     * @throws XWikiException
     * @deprecated This version si buggy since it use the initial context of the plugin and not the current context
     */
    @Deprecated
    public IQuery xpath(String q) throws XWikiException {
        return xpath(q, this);
    }

    public IQuery xpath(String q, IQueryFactory qf) throws XWikiException {
        if (LOGGER.isDebugEnabled())
            LOGGER.debug("create xpath query: " + q);
        if (isHibernate(qf))
            try {
                return new HibernateQuery(parse(q, Query.XPATH), qf);
            } catch (InvalidQueryException e) {
                throw new XWikiException(XWikiException.MODULE_XWIKI_PLUGINS, XWikiException.ERROR_XWIKI_UNKNOWN,
                        "Invalid xpath query: " + q, e);
            }
        return null;
    }

    /**
     * create JCRSQL query unsupported for now
     * 
     * @throws XWikiException
     * @deprecated This version si buggy since it use the initial context of the plugin and not the current context
     */
    @Deprecated
    public IQuery ql(String q) throws XWikiException {
        return ql(q, this);
    }

    public IQuery ql(String q, IQueryFactory qf) throws XWikiException {
        if (LOGGER.isDebugEnabled())
            LOGGER.debug("create JCRSQL query: " + q);
        if (isHibernate(qf))
            try {
                return new HibernateQuery(parse(q, Query.SQL), qf);
            } catch (InvalidQueryException e) {
                throw new XWikiException(XWikiException.MODULE_XWIKI_PLUGINS, XWikiException.ERROR_XWIKI_UNKNOWN,
                        "Invalid jcrsql query: " + q);
            }
        return null;
    }

    /**
     * create query for docs
     * 
     * @param web, docname - document.space & .name. it may consist xpath []-selection. if any - *
     * @param prop - return property, start with @, if null - return document
     * @param order - properties for sort, separated by ','; order: ascending/descending after prop. name, or +/-
     *            before. if null - not sort
     * @throws XWikiException
     * @deprecated This version si buggy since it use the initial context of the plugin and not the current context
     */
    @Deprecated
    public IQuery getDocs(String docname, String prop, String order) throws XWikiException {
        return getDocs(docname, prop, order, this);
    }

    public IQuery getDocs(String docname, String prop, String order, IQueryFactory qf) throws XWikiException {
        // if (prop==null) prop = "@fullName";
        return xpath("/" + getXPathName(docname) + getPropertyXPath(prop) + getOrderXPath(order), qf);
    }

    /**
     * create query for child documents
     * 
     * @param web,docname must be without templates & [] select
     * @throws XWikiException
     * @see getDocs
     * @deprecated This version si buggy since it use the initial context of the plugin and not the current context
     */
    @Deprecated
    public IQuery getChildDocs(String docname, String prop, String order) throws XWikiException {
        return getChildDocs(docname, prop, order, this);
    }

    public IQuery getChildDocs(String docname, String prop, String order, IQueryFactory qf) throws XWikiException {
        return xpath(
                "/*/*[@parent='" + getXWikiName(docname) + "']" + getPropertyXPath(prop) + getOrderXPath(order),
                qf);
    }

    /**
     * create query for attachments
     * 
     * @param attachname - name of attachment, may be *, *[]
     * @throws XWikiException
     * @see getDocs
     * @deprecated This version si buggy since it use the initial context of the plugin and not the current context
     */
    @Deprecated
    public IQuery getAttachment(String docname, String attachname, String order) throws XWikiException {
        return getAttachment(docname, attachname, order, this);
    }

    public IQuery getAttachment(String docname, String attachname, String order, IQueryFactory qf)
            throws XWikiException {
        return xpath("/" + getXPathName(docname) + "/attach/" + attachname + getOrderXPath(order), qf);
    }

    /**
     * create query for objects
     * 
     * @param oweb, oclass - object web & class. if any - *
     * @param prop. for flex-attributes use f:flexname
     * @throws XWikiException
     * @see getDocs
     * @deprecated This version si buggy since it use the initial context of the plugin and not the current context
     */
    @Deprecated
    public IQuery getObjects(String docname, String oclass, String prop, String order) throws XWikiException {
        return getObjects(docname, oclass, prop, order, this);
    }

    public IQuery getObjects(String docname, String oclass, String prop, String order, IQueryFactory qf)
            throws XWikiException {
        return xpath("/" + getXPathName(docname) + "/obj/" + getXPathName(oclass) + getPropertyXPath(prop)
                + getOrderXPath(order), qf);
    }

    protected String getXWikiName(String name) {
        int is = name.indexOf('['), ip = name.indexOf('/');
        if (is < 0 || ip < is)
            return name.replaceAll("/", ".");
        return name;
    }

    protected String getXPathName(String name) {
        int is = name.indexOf('['), ip = name.indexOf('.');
        if (ip > 0 && (is < 0 || ip < is)) {
            StringBuffer sb = new StringBuffer(name);
            sb.setCharAt(ip, '/');
            return sb.toString();
        } else
            return name;
    }

    protected String getOrderXPath(String order) {
        if ("".equals(n2e(order)))
            return "";
        final String[] props = StringUtils.split(order, ',');
        StringBuffer res = new StringBuffer();
        res.append(" order by ");
        String comma = "";
        for (int i = 0; i < props.length; i++) {
            res.append(comma);
            String prop = props[i].trim();
            char c = prop.charAt(0);
            boolean descending = (c == '-');
            if (c == '-' || c == '+')
                prop = prop.substring(1);
            if (prop.indexOf("@") < 0)
                res.append("@");
            res.append(prop);
            if (descending)
                res.append(" descending");
            comma = ",";
        }
        return res.toString();
    }

    protected String getPropertyXPath(String prop) {
        if ("".equals(n2e(prop)))
            return "";
        prop = prop.trim();
        if (prop.charAt(0) == '(')
            return "/" + prop;

        final StringBuffer sb = new StringBuffer();
        final String[] props = StringUtils.split(prop, " ,");
        sb.append("/");
        if (props.length > 1)
            sb.append("(");
        String comma = "";
        for (int i = 0; i < props.length; i++) {
            final String p = props[i];
            sb.append(comma);
            if (p.indexOf("@") < 0)
                sb.append("@");
            sb.append(p);
            comma = ",";
        }
        if (props.length > 1)
            sb.append(")");

        return sb.toString();
    }

    private String n2e(String s) {
        return s == null ? "" : s;
    }

    public String makeQuery(XWikiQuery query) throws XWikiException {
        StringBuffer xwqlfrom = new StringBuffer();
        StringBuffer xwqlwhere = new StringBuffer();
        StringBuffer xwqlorder = new StringBuffer();

        Set classes = query.getClasses();
        if (classes.size() > 1)
            throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
                    XWikiException.ERROR_XWIKI_STORE_SEARCH_NOTIMPL,
                    "Search with more than one class is not implemented");
        if (classes.size() == 0)
            return "";

        String className = (String) classes.toArray()[0];
        BaseClass bclass = context.getWiki().getClass(className, context);
        xwqlfrom.append("doc.object(" + className + ") as obj");
        String where = bclass.makeQuery(query);
        if (!where.equals("")) {
            xwqlwhere.append(where);
        }

        List oProps = query.getOrderProperties();
        if ((oProps != null) && (oProps.size() > 0)) {
            for (int i = 0; i < oProps.size(); i++) {
                OrderClause clause = (OrderClause) oProps.get(i);
                String propPath = clause.getProperty();
                int i1 = propPath.indexOf("_");
                if (i1 != -1) {
                    String propClassName = propPath.substring(0, i1);
                    if (propClassName.equals(className)) {
                        String propName = propPath.substring(i1 + 1);
                        if (xwqlorder.length() != 0) {
                            xwqlorder.append(",");
                        }
                        xwqlorder.append("obj." + propName);
                        if (clause.getOrder() == OrderClause.DESC)
                            xwqlorder.append(" desc");
                    }
                }
            }
        }

        String xwql = "from " + xwqlfrom.toString();
        if (xwqlwhere.length() != 0)
            xwql += " where " + xwqlwhere.toString();
        if (xwqlorder.length() != 0) {
            xwql += " order by " + xwqlorder.toString();
        }

        return xwql;
    }

    /*
     * @deprecated This version si buggy since it use the initial context of the plugin and not the current context
     */
    @Deprecated
    public List search(XWikiQuery query) throws XWikiException {
        return search(query, this);
    }

    public List search(XWikiQuery query, IQueryFactory qf) throws XWikiException {
        List doclist = xpath(makeQuery(query), qf).list();
        return doclist;
        /*
         * if (doclist==null) return null; List list = new ArrayList(); for (int i=0;i<doclist.size();i++) {
         * list.add(((XWikiDocument)doclist.get(i)).getFullName()); } return list;
         */
    }
}