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 }