001    /*
002     * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org
003     * Copyright (C) 2011 NightLabs Consulting GmbH
004     *
005     * This program is free software: you can redistribute it and/or modify
006     * it under the terms of the GNU Affero General Public License as
007     * published by the Free Software Foundation, either version 3 of the
008     * License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU Affero General Public License for more details.
014     *
015     * You should have received a copy of the GNU Affero General Public License
016     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017     */
018    package org.cumulus4j.store.query;
019    
020    import java.util.ArrayList;
021    import java.util.Collection;
022    import java.util.Collections;
023    import java.util.List;
024    import java.util.Map;
025    import java.util.Set;
026    
027    import javax.jdo.PersistenceManager;
028    
029    import org.cumulus4j.store.Cumulus4jStoreManager;
030    import org.cumulus4j.store.PersistenceManagerConnection;
031    import org.cumulus4j.store.model.ClassMeta;
032    import org.datanucleus.query.evaluator.JDOQLEvaluator;
033    import org.datanucleus.query.evaluator.JavaQueryEvaluator;
034    import org.datanucleus.store.ExecutionContext;
035    import org.datanucleus.store.StoreManager;
036    import org.datanucleus.store.connection.ManagedConnection;
037    import org.datanucleus.store.query.AbstractJDOQLQuery;
038    import org.datanucleus.util.NucleusLogger;
039    
040    /**
041     * JDOQL query implementation. Delegates to the query-language-agnostic {@link QueryEvaluator} via
042     * its thin wrapper sub-class {@link JDOQueryEvaluator}.
043     *
044     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
045     */
046    public class JDOQLQuery extends AbstractJDOQLQuery
047    {
048            private static final long serialVersionUID = 1L;
049    
050    // BEGIN DataNucleus 3.0.0-m6 and 3.0.0-release
051    //      public JDOQLQuery(ExecutionContext ec, AbstractJDOQLQuery q) {
052    //              super(ec, q);
053    //      }
054    //
055    //      public JDOQLQuery(ExecutionContext ec, String query) {
056    //              super(ec, query);
057    //      }
058    //
059    //      public JDOQLQuery(ExecutionContext ec) {
060    //              super(ec);
061    //      }
062    // END DataNucleus 3.0.0-m6 and 3.0.0-release
063    
064    // BEGIN DataNucleus 3.0.1 and newer
065            public JDOQLQuery(StoreManager storeMgr, ExecutionContext ec, AbstractJDOQLQuery q) {
066                    super(storeMgr, ec, q);
067            }
068    
069            public JDOQLQuery(StoreManager storeMgr, ExecutionContext ec, String query) {
070                    super(storeMgr, ec, query);
071            }
072    
073            public JDOQLQuery(StoreManager storeMgr, ExecutionContext ec) {
074                    super(storeMgr, ec);
075            }
076    // END DataNucleus 3.0.1 and newer
077    
078            @Override
079            protected Object performExecute(@SuppressWarnings("rawtypes") Map parameters)
080            {
081                    ManagedConnection mconn = ec.getStoreManager().getConnection(ec);
082                    try {
083                            PersistenceManagerConnection pmConn = (PersistenceManagerConnection)mconn.getConnection();
084                            PersistenceManager pmData = pmConn.getDataPM();
085    
086                            boolean inMemory = evaluateInMemory();
087                            boolean inMemory_applyFilter = true;
088                            List<Object> candidates = null;
089                            if (this.candidateCollection != null) {
090                                    if (candidateCollection.isEmpty())
091                                    {
092                                            return Collections.EMPTY_LIST;
093                                    }
094    
095                                    @SuppressWarnings("unchecked")
096                                    Collection<? extends Object> c = this.candidateCollection;
097                                    candidates = new ArrayList<Object>(c);
098                            }
099                            else {
100                                    if (candidateExtent != null) {
101                                            this.setCandidateClass(candidateExtent.getCandidateClass());
102                                            this.setSubclasses(candidateExtent.hasSubclasses());
103                                    }
104    
105                                    if (inMemory) {
106                                            // Retrieve all candidates and perform all evaluation in-memory
107                                            Set<ClassMeta> classMetas = QueryHelper.getCandidateClassMetas((Cumulus4jStoreManager) ec.getStoreManager(),
108                                                            ec, candidateClass, subclasses);
109                                            candidates = QueryHelper.getAllPersistentObjectsForCandidateClasses(pmData, ec, classMetas);
110                                    }
111                                    else {
112                                            try
113                                            {
114                                                    // Apply filter in datastore
115                                                    @SuppressWarnings("unchecked")
116                                                    Map<String, Object> parameterValues = parameters;
117                                                    JDOQueryEvaluator queryEvaluator = new JDOQueryEvaluator(this, compilation, parameterValues, clr, pmConn);
118                                                    candidates = queryEvaluator.execute();
119                                                    if (queryEvaluator.isComplete()) {
120                                                            inMemory_applyFilter = false;
121                                                    }
122                                                    else {
123                                                            NucleusLogger.QUERY.debug("Query evaluation of filter in datastore was incomplete so doing further work in-memory");
124                                                    }
125                                            }
126                                            catch (UnsupportedOperationException uoe) {
127                                                    // Some part of the filter is not yet supported, so fallback to in-memory evaluation
128                                                    // Retrieve all candidates and perform all evaluation in-memory
129                                                    NucleusLogger.QUERY.info("Query filter is not totally evaluatable in-datastore using Cumulus4j currently, so evaluating in-memory : "+uoe.getMessage());
130                                                    Set<ClassMeta> classMetas = QueryHelper.getCandidateClassMetas((Cumulus4jStoreManager) ec.getStoreManager(),
131                                                                    ec, candidateClass, subclasses);
132                                                    candidates = QueryHelper.getAllPersistentObjectsForCandidateClasses(pmData, ec, classMetas);
133                                            }
134                                    }
135                            }
136    
137                            // Evaluate any remaining query components in-memory
138                            JavaQueryEvaluator evaluator = new JDOQLEvaluator(this, candidates, compilation, parameters, ec.getClassLoaderResolver());
139                            return evaluator.execute(inMemory_applyFilter, true, true, true, true);
140                    } finally {
141                            mconn.release();
142                    }
143            }
144    
145    }