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 // http://sourceforge.net/tracker/?func=detail&aid=3514690&group_id=517465&atid=2102911
101 // Must NOT call this.setCandidateClass(...), because 1st it's already assigned and 2nd it clears the compilation.
102 // Marco :-)
103 // if (candidateExtent != null) {
104 // this.setCandidateClass(candidateExtent.getCandidateClass());
105 // this.setSubclasses(candidateExtent.hasSubclasses());
106 // }
107
108 if (inMemory) {
109 // Retrieve all candidates and perform all evaluation in-memory
110 Set<ClassMeta> classMetas = QueryHelper.getCandidateClassMetas((Cumulus4jStoreManager) ec.getStoreManager(),
111 ec, candidateClass, subclasses);
112 candidates = QueryHelper.getAllPersistentObjectsForCandidateClasses(pmData, ec, classMetas);
113 }
114 else {
115 try
116 {
117 // Apply filter in datastore
118 @SuppressWarnings("unchecked")
119 Map<String, Object> parameterValues = parameters;
120 JDOQueryEvaluator queryEvaluator = new JDOQueryEvaluator(this, compilation, parameterValues, clr, pmConn);
121 candidates = queryEvaluator.execute();
122 if (queryEvaluator.isComplete()) {
123 inMemory_applyFilter = false;
124 }
125 else {
126 NucleusLogger.QUERY.debug("Query evaluation of filter in datastore was incomplete so doing further work in-memory");
127 }
128 }
129 catch (UnsupportedOperationException uoe) {
130 // Some part of the filter is not yet supported, so fallback to in-memory evaluation
131 // Retrieve all candidates and perform all evaluation in-memory
132 NucleusLogger.QUERY.info("Query filter is not totally evaluatable in-datastore using Cumulus4j currently, so evaluating in-memory : "+uoe.getMessage());
133 Set<ClassMeta> classMetas = QueryHelper.getCandidateClassMetas((Cumulus4jStoreManager) ec.getStoreManager(),
134 ec, candidateClass, subclasses);
135 candidates = QueryHelper.getAllPersistentObjectsForCandidateClasses(pmData, ec, classMetas);
136 }
137 }
138 }
139
140 // Evaluate any remaining query components in-memory
141 JavaQueryEvaluator evaluator = new JDOQLEvaluator(this, candidates, compilation, parameters, ec.getClassLoaderResolver());
142 return evaluator.execute(inMemory_applyFilter, true, true, true, true);
143 } finally {
144 mconn.release();
145 }
146 }
147
148 }