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.eval; 019 020 import java.util.HashSet; 021 import java.util.Set; 022 023 import org.cumulus4j.store.crypto.CryptoContext; 024 import org.cumulus4j.store.query.QueryEvaluator; 025 import org.cumulus4j.store.query.QueryHelper; 026 import org.datanucleus.query.expression.DyadicExpression; 027 import org.datanucleus.query.expression.Expression; 028 import org.datanucleus.util.NucleusLogger; 029 030 /** 031 * <p> 032 * Evaluator handling the boolean operation "||" (OR). 033 * </p> 034 * <p> 035 * This evaluator works just like the {@link AndExpressionEvaluator} with the only difference 036 * that it unites the partial results instead of intersecting them. 037 * </p> 038 * <p> 039 * If the {@link ResultDescriptor} indicates a {@link ResultDescriptor#isNegated() negation}, this evaluator 040 * delegates to the {@link AndExpressionEvaluator}, because a query like 041 * "!( a > 5 || b <= 12 )" is internally converted to "a <= 5 && b > 12" for performance reasons. 042 * See {@link NotExpressionEvaluator} as well as 043 * <a target="_blank" href="http://en.wikipedia.org/wiki/De_Morgan%27s_laws">De Morgan's laws</a> in wikipedia for details. 044 * </p> 045 * 046 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de 047 * @see AndExpressionEvaluator 048 */ 049 public class OrExpressionEvaluator 050 extends AbstractExpressionEvaluator<DyadicExpression> 051 { 052 private AndExpressionEvaluator negatedExpressionEvaluator; 053 054 public OrExpressionEvaluator(QueryEvaluator queryEvaluator, AbstractExpressionEvaluator<?> parent, DyadicExpression expression) { 055 super(queryEvaluator, parent, expression); 056 } 057 058 public OrExpressionEvaluator(AndExpressionEvaluator negatedExpressionEvaluator) 059 { 060 this(negatedExpressionEvaluator.getQueryEvaluator(), negatedExpressionEvaluator.getParent(), negatedExpressionEvaluator.getExpression()); 061 this.negatedExpressionEvaluator = negatedExpressionEvaluator; 062 } 063 064 @Override 065 public AbstractExpressionEvaluator<? extends Expression> getLeft() { 066 if (negatedExpressionEvaluator != null) 067 return negatedExpressionEvaluator.getLeft(); 068 069 return super.getLeft(); 070 } 071 072 @Override 073 public AbstractExpressionEvaluator<? extends Expression> getRight() { 074 if (negatedExpressionEvaluator != null) 075 return negatedExpressionEvaluator.getRight(); 076 077 return super.getRight(); 078 } 079 080 @Override 081 protected Set<Long> _queryResultDataEntryIDs(ResultDescriptor resultDescriptor) 082 { 083 if (resultDescriptor.isNegated()) 084 return new AndExpressionEvaluator(this)._queryResultDataEntryIDsIgnoringNegation(resultDescriptor); 085 else 086 return _queryResultDataEntryIDsIgnoringNegation(resultDescriptor); 087 } 088 089 protected Set<Long> _queryResultDataEntryIDsIgnoringNegation(ResultDescriptor resultDescriptor) 090 { 091 if (getLeft() == null) 092 throw new IllegalStateException("getLeft() == null"); 093 094 if (getRight() == null) 095 throw new IllegalStateException("getRight() == null"); 096 097 Set<Long> leftResult = null; 098 boolean leftEvaluated = true; 099 try { 100 leftResult = getLeft().queryResultDataEntryIDs(resultDescriptor); 101 } 102 catch (UnsupportedOperationException uoe) { 103 leftEvaluated = false; 104 getQueryEvaluator().setIncomplete(); 105 NucleusLogger.QUERY.debug("Unsupported operation in LEFT : "+getLeft().getExpression() + " so deferring evaluation to in-memory"); 106 } 107 108 Set<Long> rightResult = null; 109 boolean rightEvaluated = true; 110 try { 111 rightResult = getRight().queryResultDataEntryIDs(resultDescriptor); 112 } 113 catch (UnsupportedOperationException uoe) { 114 rightEvaluated = false; 115 getQueryEvaluator().setIncomplete(); 116 NucleusLogger.QUERY.debug("Unsupported operation in RIGHT : "+getRight().getExpression() + " so deferring evaluation to in-memory"); 117 } 118 119 if (leftEvaluated && !rightEvaluated) { 120 CryptoContext cryptoContext = getQueryEvaluator().getCryptoContext(); 121 rightResult = QueryHelper.getAllDataEntryIdsForCandidate(cryptoContext, 122 getQueryEvaluator().getPersistenceManagerForData(), getQueryEvaluator().getQuery().getCandidateClass(), getQueryEvaluator().getQuery().isSubclasses()); 123 } 124 else if (!leftEvaluated && rightEvaluated) { 125 CryptoContext cryptoContext = getQueryEvaluator().getCryptoContext(); 126 leftResult = QueryHelper.getAllDataEntryIdsForCandidate(cryptoContext, 127 getQueryEvaluator().getPersistenceManagerForData(), getQueryEvaluator().getQuery().getCandidateClass(), getQueryEvaluator().getQuery().isSubclasses()); 128 } 129 else if (!leftEvaluated && !rightEvaluated) { 130 CryptoContext cryptoContext = getQueryEvaluator().getCryptoContext(); 131 leftResult = QueryHelper.getAllDataEntryIdsForCandidate(cryptoContext, 132 getQueryEvaluator().getPersistenceManagerForData(), getQueryEvaluator().getQuery().getCandidateClass(), getQueryEvaluator().getQuery().isSubclasses()); 133 } 134 135 if (leftResult != null && rightResult != null) { 136 Set<Long> result = new HashSet<Long>(leftResult.size() + rightResult.size()); 137 result.addAll(leftResult); 138 result.addAll(rightResult); 139 return result; 140 } 141 else if (leftResult != null) 142 return leftResult; 143 else 144 return rightResult; 145 } 146 }