VersantQueryImp.java :  » Testing » PolePosition-0.20 » com » versant » core » jdo » Java Open Source

Java Open Source » Testing » PolePosition 0.20 
PolePosition 0.20 » com » versant » core » jdo » VersantQueryImp.java

/*
 * Copyright (c) 1998 - 2005 Versant Corporation
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Versant Corporation - initial API and implementation
 */
package com.versant.core.jdo;

import com.versant.core.common.NewObjectOID;
import com.versant.core.metadata.ClassMetaData;
import com.versant.core.metadata.FetchGroup;
import com.versant.core.server.CompiledQuery;
import com.versant.core.util.BeanUtils;

import javax.jdo.Extent;
import javax.jdo.PersistenceManager;
import javax.jdo.spi.PersistenceCapable;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.*;

import com.versant.core.common.BindingSupportImpl;

/**
 * This is the implementation of a Query.
 */
public final class VersantQueryImp implements VersantQuery, Externalizable {

    private final QueryDetails queryDetails = new QueryDetails();
    private QueryResult resultList;
    private PMProxy pmProxy;
    private CompiledQuery compiledQuery;

    /**
     * For Serialization.
     */
    public VersantQueryImp() {
    }

    /**
     * Create a new JDOQL query for pmProxy. The ignoreCache setting is taken
     * from the curremt setting of pmProxy.
     */
    public VersantQueryImp(PMProxy pmProxy) {
        this(pmProxy, QueryDetails.LANGUAGE_JDOQL);
    }

    /**
     * Create a new query for pmProxy. The ignoreCache setting is taken
     * from the curremt setting of pmProxy.
     *
     * @param language Query language
     * @see QueryDetails#LANGUAGE_JDOQL
     * @see QueryDetails#LANGUAGE_SQL
     */
    public VersantQueryImp(PMProxy pmProxy, int language) {
        this.pmProxy = pmProxy;
        queryDetails.setLanguage(language);
        setIgnoreCache(pmProxy.getIgnoreCache());
    }

    /**
     * Create a new query for pmProxy using all the settings of other.
     */
    public VersantQueryImp(PMProxy pmProxy, VersantQueryImp other) {
        this(pmProxy, other.queryDetails);
    }

    /**
     * Create a new query for pmProxy using all the settings of params.
     * This is used to create Query's from named queries in the meta data.
     */
    public VersantQueryImp(PMProxy pmProxy, QueryDetails params) {
        this.pmProxy = pmProxy;
        queryDetails.fillFrom(params);
        if (params.isUseIgnoreCacheFromPM()) {
            setIgnoreCache(pmProxy.getIgnoreCache());
        }
    }

    /**
     * This is a util method that invalidates the preCompiled query because of
     * change made by the client.
     */
    private void changed() {
        compiledQuery = null;
    }

    public void setBounded(boolean value) {
        queryDetails.setBounded(value);
    }

    public boolean isBounded() {
        return queryDetails.isBounded();
    }

    public void setClass(Class cls) {
        changed();
        queryDetails.setCandidateClass(cls);
    }

    public void setCandidates(Extent pcs) {
        changed();
        queryDetails.setExtent(pcs);
    }

    public void setCandidates(Collection pcs) {
        changed();
        queryDetails.setCol(pcs);
    }

    public void setFilter(String filter) {
        changed();
        queryDetails.setFilter(filter);
    }

    public String getFilter() {
        return queryDetails.getFilter();
    }

    public void declareImports(String imports) {
        changed();
        queryDetails.setImports(imports);
    }

    public void declareParameters(String params) {
        changed();
        queryDetails.declareParameters(params);
    }

    public void declareVariables(String variables) {
        changed();
        queryDetails.setVariables(variables);
    }

    public void setOrdering(String ordering) {
        changed();
        queryDetails.setOrdering(ordering);
    }

    public void setIgnoreCache(boolean ignoreCache) {
        changed();
        queryDetails.setIgnoreCache(ignoreCache);
    }

    private VersantPersistenceManagerImp getRealPM() {
        if (pmProxy == null) {
            throw BindingSupportImpl.getInstance().invalidOperation(
                    "Query is not associated with a PersistenceManager");
        }
        return pmProxy.getRealPM();
    }

    public void setFetchGroup(String fgName) {
        if (fgName == null) {
            queryDetails.setFetchGroupIndex(0);
            changed();
            return;
        } else {
            if (queryDetails.getCandidateClass() == null) {
                throw BindingSupportImpl.getInstance().invalidOperation(
                        "Please first supply a candidate class");
            }
            FetchGroup fg = getRealPM().modelMetaData.getClassMetaData(
                    queryDetails.getCandidateClass()).getFetchGroup(fgName);
            if (fg == null) {
                throw BindingSupportImpl.getInstance().invalidOperation("No fetchGroup with name "
                        + fgName
                        + " for class "
                        + queryDetails.getCandidateClass().getName());
            }

            queryDetails.setFetchGroupIndex(fg.index);
            changed();
        }
    }

    public String getFetchGroup() {
        int i = queryDetails.getFetchGroupIndex();
        if (i == 0) return null;
        ClassMetaData cmd = getRealPM().modelMetaData.getClassMetaData(
                queryDetails.getCandidateClass());
        return cmd.fetchGroups[i].name;
    }

    public void setMaxRows(int amount) {
        changed();
        this.queryDetails.setMaxResultCount(amount);
    }

    public int getMaxRows() {
        return queryDetails.getMaxResultCount();
    }

    public void setFetchSize(int value) {
        changed();
        this.queryDetails.setResultBatchSize(value);
    }

    public int getFetchSize() {
        return queryDetails.getResultBatchSize();
    }

    public void setRandomAccess(boolean on) {
        changed();
        queryDetails.setRandomAccess(on);
    }

    public boolean isRandomAccess() {
        return queryDetails.isRandomAccess();
    }

    public void setCountStarOnSize(boolean on) {
        changed();
        queryDetails.setCountOnSize(on);
    }

    public boolean isCountStarOnSize() {
        return queryDetails.isCountOnSize();
    }

    public boolean getIgnoreCache() {
        return queryDetails.isIgnoreCache();
    }

    public void setEvictionClasses(Class[] classes, boolean includeSubclasses) {
        setEvictionClasses(getRealPM().modelMetaData.convertToClassIndexes(
                classes,
                includeSubclasses));
    }

    public void setEvictionClasses(int[] classIndexes) {
        changed();
        queryDetails.setExtraEvictClasses(classIndexes);
    }

    public Class[] getEvictionClasses() {
        int[] a = queryDetails.getExtraEvictClasses();
        return a == null ? null : getRealPM().modelMetaData.convertFromClassIndexes(
                a);
    }

    public void setResult(String result) {
        changed();
        queryDetails.setResult(result);
    }

    public void setGrouping(String grouping) {
        changed();
        queryDetails.setGrouping(grouping);
    }

    /**
     * Specify that there is a single result of the query.
     */
    public void setUnique(boolean unique) {
        changed();
        queryDetails.setUnique(unique);
    }

    public void compile() {
        if (compiledQuery == null) {
            queryDetails.updateCounts();
            compiledQuery = pmProxy.getRealPM().getStorageManager().compileQuery(
                    queryDetails);
        }
    }


    private


  void checkParamCount(int n) {
        int tc = queryDetails.getTotalParamCount();
        if (tc >= 0 && n != tc) {
            throw BindingSupportImpl.getInstance().runtime(
                    "Expected " +
                    queryDetails.getTotalParamCount() + " parameters, have " + n);
        }
    }

    public Object execute() {
        checkParamCount(0);
        queryDetails.updateCounts();
        return executeWithArrayImp(null);
    }

    public Object execute(Object p1) {
        checkParamCount(1);
        queryDetails.updateCounts();
        if (queryDetails.hasJdoGenieOptions()) {
            processJdoGenieOptions(p1);
            return executeWithArrayImp(null);
        } else {
            return executeWithArrayImp(new Object[]{p1});
        }
    }

    public Object execute(Object p1, Object p2) {
        checkParamCount(2);
        queryDetails.updateCounts();
        switch (queryDetails.getOptionsParamIndex()) {
            case 0:
                processJdoGenieOptions(p1);
                return executeWithArrayImp(new Object[]{p2});
            case 1:
                processJdoGenieOptions(p2);
                return executeWithArrayImp(new Object[]{p1});
        }
        return executeWithArrayImp(new Object[]{p1, p2});
    }

    public Object execute(Object p1, Object p2, Object p3) {
        checkParamCount(3);
        queryDetails.updateCounts();
        switch (queryDetails.getOptionsParamIndex()) {
            case 0:
                processJdoGenieOptions(p1);
                return executeWithArrayImp(new Object[]{p2, p3});
            case 1:
                processJdoGenieOptions(p2);
                return executeWithArrayImp(new Object[]{p1, p3});
            case 2:
                processJdoGenieOptions(p2);
                return executeWithArrayImp(new Object[]{p1, p2});
        }
        return executeWithArrayImp(new Object[]{p1, p2, p3});
    }

    public final Object executeWithArray(Object[] parameters) {
        queryDetails.updateCounts();
        int n = parameters == null ? 0 : parameters.length;
        checkParamCount(n);
        int oi = queryDetails.getOptionsParamIndex();
        if (oi >= 0) {
            processJdoGenieOptions(parameters[oi]);
            if (n == 1) {
                return executeWithArrayImp(null);
            }
            Object[] a = new Object[n - 1];
            if (oi > 0) System.arraycopy(parameters, 0, a, 0, oi);
            if (oi < n) System.arraycopy(parameters, oi + 1, a, oi, n - oi - 1);
            return executeWithArrayImp(a);
        } else {
            return executeWithArrayImp(copyParams(parameters));
        }
    }

    /**
     * Get the query plan for this query. This will include the SQL and
     * possibly also a query plan for the SQL from the database itself.
     */
    public VersantQueryPlan getPlan(Object[] parameters) {
        queryDetails.updateCounts();
        if (queryDetails.getCol() != null) {
            throw BindingSupportImpl.getInstance().invalidOperation(
                    "getPlan is not supported for queries executed against a collection");
        }
        int n = parameters == null ? 0 : parameters.length;
        checkParamCount(n);
        int oi = queryDetails.getOptionsParamIndex();
        if (oi >= 0) {
            processJdoGenieOptions(parameters[oi]);
            if (n == 1) {
                return getPlanImp(null);
            }
            Object[] a = new Object[n - 1];
            if (oi > 0) System.arraycopy(parameters, 0, a, 0, oi);
            if (oi < n) System.arraycopy(parameters, oi, a, oi - 1, n - oi - 1);
            return getPlanImp(a);
        } else {
            return getPlanImp(parameters);
        }
    }

    public Object executeWithMap(Map parameters) {
        queryDetails.updateCounts();
        int tp = queryDetails.getTotalParamCount();
        if (parameters.size() != tp) {
            throw BindingSupportImpl.getInstance().runtime(
                    "The number of entries in the map (" + parameters.size() + ") " +
                    "differs from the number of declared parameters (" + tp + ")");
        }
        if (tp == 0) return executeWithArrayImp(null);

        // extract the normal parameters from the map in declaration order
        Object[] pa;
        int np = queryDetails.getParamCount();
        if (np > 0) {
            pa = new Object[np];
            String[] names = queryDetails.getParamNames();
            for (int i = 0; i < np; i++) {
                String name = names[i];
                if (!parameters.containsKey(name)) {
                    throw BindingSupportImpl.getInstance().runtime(
                            "Parameter '" + name + "' not found in map");
                }
                pa[i] = parameters.get(name);
            }
        } else {
            pa = null;
        }

        // process the jdoGenieOptions parameter if required
        if (queryDetails.hasJdoGenieOptions()) {
            Object o = parameters.get(VERSANT_OPTIONS);
            if (o == null) o = parameters.get(JDO_GENIE_OPTIONS);
            processJdoGenieOptions(o);
        }

        // exec
        return executeWithArrayImp(pa);
    }

    private void processJdoGenieOptions(Object o) {
        // restore default values first
        setFetchGroup(null);
        setRandomAccess(false);

        // now set properties
        if (o == null) return;
        if (!(o instanceof String)) {
            throw BindingSupportImpl.getInstance().runtime("Invalid " +
                    VERSANT_OPTIONS + ": Expected String value: " +
                    o.getClass());
        }
        String props = (String)o;
        if (props.length() == 0) return;
        try {
            BeanUtils.parseProperties(props, this);
        } catch (Exception e) {
            throw BindingSupportImpl.getInstance().runtime(
                    "Invalid " + VERSANT_OPTIONS + ": " + e.getMessage(), e);
        }
    }

    /**
     * The parameters array must NOT contain the jdoGenieOptions.
     */
    private final Object executeWithArrayImp(Object[] parameters) {
        final PMProxy pmProxy = this.pmProxy;
        pmProxy.getRealPM().convertPcParamsToOID(parameters);
        if (!pmProxy.isActive() && !pmProxy.getRealPM().isNontransactionalRead()) {
            throw BindingSupportImpl.getInstance().invalidOperation(
                    "Must set nonTransactionalRead to true");
        }

        //Check if this should be a multi-part query
        Class cls = queryDetails.getCandidateClass();
        Class[] candidates = null;
        if (cls != null) {
            candidates = pmProxy.getRealPM().modelMetaData.getQueryCandidatesFor(cls);
            if (candidates == null) {
                throw BindingSupportImpl.getInstance().unsupported("Queries for class '"
                        + queryDetails.getCandidateClass() + "' is not supported");
            }
        }

        if (candidates != null && candidates.length > 1) {
            //create subQueries for all the candidates and compile it
            queryDetails.updateCounts();
            Set qResults = new HashSet();
            for (int i = 0; i < candidates.length; i++) {
                Class candidate = candidates[i];

                QueryDetails qd = new QueryDetails(queryDetails);
                qd.setCandidateClass(candidate);

                CompiledQuery cq = this.pmProxy.getRealPM().getStorageManager().compileQuery(qd);
                QueryResult qr = getQueryResult(parameters, qd, cq, this.pmProxy);

                qResults.add(qr);
            }
            return new MultiPartQueryResult(qResults);
        } else {
            compile();

            //is this a unique query
            if (compiledQuery.isUnique()) {
                //must do immediately
                return QueryResultBase.resolveRow(pmProxy.getAllQueryResults(
                        compiledQuery,
                        parameters).getUnique(),
                        pmProxy);
            } else {
                return getQueryResult(parameters, queryDetails, compiledQuery, this.pmProxy);
            }
        }
    }

    private static Object[] copyParams(Object[] parameters) {
        Object[] params = null;
        if (parameters != null) {
            params = new Object[parameters.length];
            for (int i = 0; i < params.length; i++) {
                params[i] = parameters[i];
            }
        }
        return params;
    }

    private QueryResult getQueryResult(Object[] params,
            QueryDetails queryDetails, CompiledQuery compiledQuery, PMProxy pmProxy) {
        QueryResult res = null;
        boolean collectionQuery = queryDetails.getCol() != null;
        boolean containsNewOID = containsNewOID(params);

        if (collectionQuery) {
            // query agains a collection in memory
            res = new MemoryQueryResult(pmProxy,
                    queryDetails, createSMList(queryDetails.getCol(), pmProxy), params);
        } else if (containsNewOID && queryDetails.isIgnoreCache()) {
            // query agains a collection in memory with some new instances
            res = new MemoryQueryResult();
        } else if (queryDetails.isRandomAccess()) {
            // random access query against database
            res = new RandomAccessQueryResult(pmProxy,
                    compiledQuery, params);
        } else {
            // normal query against database
            res = new ForwardQueryResult(pmProxy, queryDetails,
                    compiledQuery, params);
        }
        if (pmProxy.getMultithreaded()) {
            res = new SynchronizedQueryResult(pmProxy, res);
        }

        addResults(res);
        return res;
    }

    /**
     * Add a set of results to this query.
     */
    private void addResults(QueryResult q) {
        synchronized (pmProxy) {
            if (resultList == null) {
                resultList = q;
            } else {
                q.setNext(resultList);
                resultList.setPrev(q);
                resultList = q;
            }
        }
    }

    /**
     * Remove a set of results from this query.
     */
    private void removeResults(QueryResult q) {
        synchronized (pmProxy) {
            if (resultList == q) {  // at tail of list
                resultList = q.getNext();
                if (resultList != null) resultList.setPrev(null);
                q.setNext(null);
            } else {
                q.getPrev().setNext(q.getNext());
                if (q.getNext() != null) q.getNext().setPrev(q.getPrev());
                q.setNext(null);
                q.setPrev(null);
            }
        }
    }

    /**
     * TODO must check not to try and do convertPcParams twice
     * <p/>
     * The parameters array must NOT contain the jdoGenieOptions.
     */
    private VersantQueryPlan getPlanImp(Object[] parameters) {
        VersantPersistenceManagerImp realPM = pmProxy.getRealPM();
        realPM.convertPcParamsToOID(parameters);
        compile();
        return realPM.getStorageManager().getQueryPlan(queryDetails,
                compiledQuery, parameters);
    }

    private static List createSMList(Collection col, PMProxy pmProxy) {
        List tmpList = new ArrayList();
        for (Iterator iterator = col.iterator(); iterator.hasNext();) {
            PersistenceCapable persistenceCapable = (PersistenceCapable)iterator.next();
            tmpList.add(pmProxy.getInternalSM(persistenceCapable));
        }
        return tmpList;
    }

    private static boolean containsNewOID(Object[] params) {
        if (params != null) {
            for (int i = 0; i < params.length; i++) {
                Object param = params[i];
                if (param instanceof NewObjectOID) {
                    return true;
                }
            }
        }
        return false;
    }

    public PersistenceManager getPersistenceManager() {
        return pmProxy;
    }

    public void close(Object queryResult) {
        QueryResult qr = (QueryResult)queryResult;
        qr.close();
        removeResults(qr);
    }

    public void closeAll() {
        synchronized (pmProxy) {
            if (resultList == null) return;
            resultList.close();
            for (QueryResult i = resultList.getNext(); i != null; i = i.getNext()) {
                i.close();
                i.getPrev().setNext(null);
                i.setPrev(null);
            }
            resultList = null;
        }
    }

    public void writeExternal(ObjectOutput out) throws IOException {
        queryDetails.writeExternal(out);
    }

    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        QueryDetails qp = new QueryDetails();
        qp.readExternal(in);
        this.queryDetails.fillFrom(qp);
    }

    public void initialiseFrom(VersantQueryImp clientQuery) {
        this.queryDetails.fillFrom(clientQuery.queryDetails);
        this.queryDetails.clearExtentAndCol();
    }

    public void setCacheable(boolean on) {
        changed();
        queryDetails.setCacheable(on);
    }

    public String getImports() {
        return queryDetails.getImports();
    }

    public String getParameters() {
        return queryDetails.getParameters();
    }

    public String getVariables() {
        return queryDetails.getVariables();
    }

    public String getOrdering() {
        return queryDetails.getOrdering();
    }

    public String getGrouping() {
        return queryDetails.getGrouping();
    }

    public String getResult() {
        return queryDetails.getResult();
    }

    public boolean isUnique() {
        return queryDetails.getUnique() == QueryDetails.TRUE;
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.