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 }