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