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    }