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.HashSet;
024 import java.util.List;
025 import java.util.Set;
026
027 import javax.jdo.PersistenceManager;
028
029 import org.cumulus4j.store.Cumulus4jStoreManager;
030 import org.cumulus4j.store.model.ClassMeta;
031 import org.cumulus4j.store.model.DataEntry;
032 import org.datanucleus.ClassLoaderResolver;
033 import org.datanucleus.identity.IdentityUtils;
034 import org.datanucleus.store.ExecutionContext;
035
036 /**
037 * Helper methods for querying.
038 */
039 public class QueryHelper {
040
041 /**
042 * Access the data entry ids for a candidate.
043 * @param pmData PersistenceManager for the backend data
044 * @param ec ExecutionContext
045 * @param candidateCls Candidate class
046 * @param subclasses Whether to include subclasses
047 * @return The data entry ids
048 */
049 public static Set<Long> getAllDataEntryIdsForCandidate(PersistenceManager pmData, ExecutionContext ec, Class candidateCls, boolean subclasses) {
050 javax.jdo.Query q = pmData.newQuery(DataEntry.class);
051 q.setResult("this.dataEntryID");
052
053 Object queryParam;
054 Set<ClassMeta> classMetas = QueryHelper.getCandidateClassMetas((Cumulus4jStoreManager) ec.getStoreManager(),
055 ec, candidateCls, subclasses);
056 if (classMetas.size() == 1) {
057 q.setFilter("this.classMeta == :classMeta");
058 queryParam = classMetas.iterator().next();
059 }
060 else {
061 q.setFilter(":classMetas.contains(this.classMeta)");
062 queryParam = classMetas;
063 }
064
065 @SuppressWarnings("unchecked")
066 Collection<Object[]> c = (Collection<Object[]>) q.execute(queryParam);
067 Set<Long> resultList = new HashSet<Long>(c.size());
068 for (Object[] oa : c) {
069 resultList.add((Long)oa[0]);
070 }
071 q.closeAll();
072 return resultList;
073 }
074
075 /**
076 * Convenience method to return the persistent objects for the classes with the provided ClassMetas.
077 * @param pmData PersistenceManager for the backend data
078 * @param ec ExecutionContext
079 * @param candidateClassMetas The class metas defining the required classes
080 * @return The persistent objects
081 */
082 public static List<Object> getAllPersistentObjectsForCandidateClasses(PersistenceManager pmData, ExecutionContext ec,
083 Set<ClassMeta> candidateClassMetas)
084 {
085 javax.jdo.Query q = pmData.newQuery(DataEntry.class);
086 q.setResult("this.classMeta, this.objectID");
087
088 Object queryParam;
089 if (candidateClassMetas.size() == 1) {
090 q.setFilter("this.classMeta == :classMeta");
091 queryParam = candidateClassMetas.iterator().next();
092 }
093 else {
094 q.setFilter(":classMetas.contains(this.classMeta)");
095 queryParam = candidateClassMetas;
096 }
097
098 @SuppressWarnings("unchecked")
099 Collection<Object[]> c = (Collection<Object[]>) q.execute(queryParam);
100 List<Object> resultList = new ArrayList<Object>(c.size());
101 for (Object[] oa : c) {
102 ClassMeta classMeta = (ClassMeta) oa[0];
103 String objectIDString = (String) oa[1];
104 Object obj = IdentityUtils.getObjectFromIdString(objectIDString, classMeta.getDataNucleusClassMetaData(ec), ec, true);
105 resultList.add(obj);
106 }
107 q.closeAll();
108 return resultList;
109 }
110
111 /**
112 * Convenience method to return the ClassMeta objects for the specified class (and subclasses if required).
113 * @param storeMgr Cumulus4J StoreManager
114 * @param ec ExecutionContext
115 * @param candidateClass The class required
116 * @param withSubclasses Whether to return subclasses too
117 * @return The ClassMeta objects
118 */
119 public static Set<ClassMeta> getCandidateClassMetas(Cumulus4jStoreManager storeMgr, ExecutionContext ec,
120 Class<?> candidateClass, boolean withSubclasses)
121 {
122 Set<? extends Class<?>> candidateClasses;
123 if (withSubclasses) {
124 ClassLoaderResolver clr = ec.getClassLoaderResolver();
125 HashSet<String> classNames = storeMgr.getSubClassesForClass(candidateClass.getName(), true, clr);
126 Set<Class<?>> classes = new HashSet<Class<?>>(classNames.size() + 1);
127 classes.add(candidateClass);
128 for (String className : classNames) {
129 Class<?> clazz = clr.classForName(className);
130 classes.add(clazz);
131 }
132 candidateClasses = classes;
133 }
134 else
135 candidateClasses = Collections.singleton(candidateClass);
136
137 Set<ClassMeta> candidateClassMetas = new HashSet<ClassMeta>(candidateClasses.size());
138 for (Class<?> c : candidateClasses) {
139 ClassMeta cm = storeMgr.getClassMeta(ec, c);
140 candidateClassMetas.add(cm);
141 }
142
143 return candidateClassMetas;
144 }
145 }