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