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.method; 019 020 import java.util.Collection; 021 import java.util.HashMap; 022 import java.util.HashSet; 023 import java.util.Map; 024 import java.util.Set; 025 026 import javax.jdo.Query; 027 028 import org.cumulus4j.store.crypto.CryptoContext; 029 import org.cumulus4j.store.model.ClassMeta; 030 import org.cumulus4j.store.model.FieldMeta; 031 import org.cumulus4j.store.model.IndexEntry; 032 import org.cumulus4j.store.model.IndexEntryFactory; 033 import org.cumulus4j.store.model.IndexValue; 034 import org.cumulus4j.store.query.QueryEvaluator; 035 import org.cumulus4j.store.query.eval.InvokeExpressionEvaluator; 036 import org.cumulus4j.store.query.eval.PrimaryExpressionResolver; 037 import org.cumulus4j.store.query.eval.ResultDescriptor; 038 import org.datanucleus.query.expression.Expression; 039 import org.datanucleus.query.expression.PrimaryExpression; 040 041 /** 042 * Evaluator for "Collection.isEmpty()". 043 */ 044 public class CollectionIsEmptyEvaluator extends AbstractMethodEvaluator { 045 046 /* (non-Javadoc) 047 * @see org.cumulus4j.store.query.method.MethodEvaluator#evaluate(org.cumulus4j.store.query.QueryEvaluator, org.cumulus4j.store.query.eval.InvokeExpressionEvaluator, org.datanucleus.query.expression.Expression, org.cumulus4j.store.query.eval.ResultDescriptor) 048 */ 049 @Override 050 public Set<Long> evaluate(QueryEvaluator queryEval, 051 InvokeExpressionEvaluator invokeExprEval, Expression invokedExpr, 052 ResultDescriptor resultDesc) { 053 if (invokeExprEval.getExpression().getArguments().size() != 0) 054 throw new IllegalStateException("isEmpty(...) expects no argument, but there are " + 055 invokeExprEval.getExpression().getArguments().size()); 056 057 if (invokedExpr instanceof PrimaryExpression) { 058 return new CollectionIsEmptyResolver(queryEval, (PrimaryExpression) invokedExpr, resultDesc.isNegated()).query(); 059 } 060 else { 061 if (!invokeExprEval.getLeft().getResultSymbols().contains(resultDesc.getSymbol())) 062 return null; 063 return queryCollectionIsEmpty(queryEval, resultDesc.getFieldMeta(), resultDesc.isNegated()); 064 } 065 } 066 067 private Set<Long> queryCollectionIsEmpty( 068 QueryEvaluator queryEval, 069 FieldMeta fieldMeta, 070 boolean negate 071 ) { 072 CryptoContext cryptoContext = queryEval.getCryptoContext(); 073 IndexEntryFactory indexEntryFactory = queryEval.getStoreManager().getIndexFactoryRegistry().getIndexEntryFactoryForContainerSize(); 074 075 Query q = queryEval.getPersistenceManagerForIndex().newQuery(indexEntryFactory.getIndexEntryClass()); 076 q.setFilter( 077 "this.keyStoreRefID == :keyStoreRefID && this.fieldMeta_fieldID == :fieldMeta_fieldID && " + 078 (negate ? "this.indexKey != 0" : "this.indexKey == 0") 079 ); 080 Map<String, Object> params = new HashMap<String, Object>(3); 081 params.put("keyStoreRefID", cryptoContext.getKeyStoreRefID()); 082 params.put("fieldMeta_fieldID", fieldMeta.getFieldID()); 083 084 @SuppressWarnings("unchecked") 085 Collection<? extends IndexEntry> indexEntries = (Collection<? extends IndexEntry>) q.executeWithMap(params); 086 087 Set<Long> result = new HashSet<Long>(); 088 for (IndexEntry indexEntry : indexEntries) { 089 IndexValue indexValue = queryEval.getEncryptionHandler().decryptIndexEntry(cryptoContext, indexEntry); 090 result.addAll(indexValue.getDataEntryIDs()); 091 } 092 q.closeAll(); 093 return result; 094 } 095 096 private class CollectionIsEmptyResolver extends PrimaryExpressionResolver 097 { 098 private boolean negate; 099 100 public CollectionIsEmptyResolver( 101 QueryEvaluator queryEvaluator, PrimaryExpression primaryExpression, 102 boolean negate 103 ) 104 { 105 super(queryEvaluator, primaryExpression); 106 this.negate = negate; 107 } 108 109 @Override 110 protected Set<Long> queryEnd(FieldMeta fieldMeta, ClassMeta classMeta) { 111 return queryCollectionIsEmpty(queryEvaluator, fieldMeta, negate); 112 } 113 } 114 }