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.crypto.CryptoContext;
032 import org.cumulus4j.store.model.ClassMeta;
033 import org.datanucleus.ExecutionContext;
034 import org.datanucleus.query.evaluator.JDOQLEvaluator;
035 import org.datanucleus.query.evaluator.JavaQueryEvaluator;
036 import org.datanucleus.store.StoreManager;
037 import org.datanucleus.store.connection.ManagedConnection;
038 import org.datanucleus.store.query.AbstractJDOQLQuery;
039 import org.datanucleus.util.NucleusLogger;
040
041 /**
042 * JDOQL query implementation. Delegates to the query-language-agnostic {@link QueryEvaluator} via
043 * its thin wrapper sub-class {@link JDOQueryEvaluator}.
044 *
045 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
046 */
047 public class JDOQLQuery extends AbstractJDOQLQuery
048 {
049 private static final long serialVersionUID = 1L;
050
051 // BEGIN DataNucleus 3.0.0-m6 and 3.0.0-release
052 // public JDOQLQuery(ExecutionContext ec, AbstractJDOQLQuery q) {
053 // super(ec, q);
054 // }
055 //
056 // public JDOQLQuery(ExecutionContext ec, String query) {
057 // super(ec, query);
058 // }
059 //
060 // public JDOQLQuery(ExecutionContext ec) {
061 // super(ec);
062 // }
063 // END DataNucleus 3.0.0-m6 and 3.0.0-release
064
065 // BEGIN DataNucleus 3.0.1 and newer
066 public JDOQLQuery(StoreManager storeMgr, ExecutionContext ec, AbstractJDOQLQuery q) {
067 super(storeMgr, ec, q);
068 }
069
070 public JDOQLQuery(StoreManager storeMgr, ExecutionContext ec, String query) {
071 super(storeMgr, ec, query);
072 }
073
074 public JDOQLQuery(StoreManager storeMgr, ExecutionContext ec) {
075 super(storeMgr, ec);
076 }
077 // END DataNucleus 3.0.1 and newer
078
079 @Override
080 protected Object performExecute(@SuppressWarnings("rawtypes") Map parameters)
081 {
082 ManagedConnection mconn = ec.getStoreManager().getConnection(ec);
083 try {
084 PersistenceManagerConnection pmConn = (PersistenceManagerConnection)mconn.getConnection();
085 PersistenceManager pmData = pmConn.getDataPM();
086
087 Cumulus4jStoreManager storeManager = (Cumulus4jStoreManager) ec.getStoreManager();
088 CryptoContext cryptoContext = new CryptoContext(storeManager.getEncryptionCoordinateSetManager(), storeManager.getKeyStoreRefManager(), ec, pmConn);
089 storeManager.getDatastoreVersionManager().applyOnce(cryptoContext);
090
091 boolean inMemory = evaluateInMemory();
092 boolean inMemory_applyFilter = true;
093 List<Object> candidates = null;
094 if (this.candidateCollection != null) {
095 if (candidateCollection.isEmpty())
096 {
097 return Collections.EMPTY_LIST;
098 }
099
100 @SuppressWarnings("unchecked")
101 Collection<? extends Object> c = this.candidateCollection;
102 candidates = new ArrayList<Object>(c);
103 }
104 else {
105 // http://sourceforge.net/tracker/?func=detail&aid=3514690&group_id=517465&atid=2102911
106 // Must NOT call this.setCandidateClass(...), because 1st it's already assigned and 2nd it clears the compilation.
107 // Marco :-)
108 // if (candidateExtent != null) {
109 // this.setCandidateClass(candidateExtent.getCandidateClass());
110 // this.setSubclasses(candidateExtent.hasSubclasses());
111 // }
112
113 if (inMemory) {
114 // Retrieve all candidates and perform all evaluation in-memory
115 Set<ClassMeta> classMetas = QueryHelper.getCandidateClassMetas(storeManager,
116 ec, candidateClass, subclasses);
117 candidates = QueryHelper.getAllPersistentObjectsForCandidateClasses(cryptoContext, pmData, classMetas);
118 }
119 else {
120 try
121 {
122 // Apply filter in datastore
123 @SuppressWarnings("unchecked")
124 Map<String, Object> parameterValues = parameters;
125 JDOQueryEvaluator queryEvaluator = new JDOQueryEvaluator(this, compilation, parameterValues, clr, pmConn, cryptoContext);
126 candidates = queryEvaluator.execute();
127 if (queryEvaluator.isComplete()) {
128 inMemory_applyFilter = false;
129 }
130 else {
131 NucleusLogger.QUERY.debug("Query evaluation of filter in datastore was incomplete so doing further work in-memory");
132 }
133 }
134 catch (UnsupportedOperationException uoe) {
135 // Some part of the filter is not yet supported, so fallback to in-memory evaluation
136 // Retrieve all candidates and perform all evaluation in-memory
137 NucleusLogger.QUERY.info("Query filter is not totally evaluatable in-datastore using Cumulus4j currently, so evaluating in-memory : "+uoe.getMessage());
138 Set<ClassMeta> classMetas = QueryHelper.getCandidateClassMetas(storeManager,
139 ec, candidateClass, subclasses);
140 candidates = QueryHelper.getAllPersistentObjectsForCandidateClasses(cryptoContext, pmData, classMetas);
141 }
142 }
143 }
144
145 // Evaluate any remaining query components in-memory
146 JavaQueryEvaluator evaluator = new JDOQLEvaluator(this, candidates, compilation, parameters, ec.getClassLoaderResolver());
147 return evaluator.execute(inMemory_applyFilter, true, true, true, true);
148 } finally {
149 mconn.release();
150 }
151 }
152
153 }