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 org.cumulus4j.store.model.ClassMeta; 021 import org.cumulus4j.store.model.FieldMeta; 022 import org.datanucleus.query.symbol.Symbol; 023 024 /** 025 * <p> 026 * Descriptor specifying what kind of result is expected when a query is executed. 027 * This contains the information what candidates a query should search 028 * (usually "this" or a variable) as well as modifiers affecting the query 029 * (e.g. {@link #isNegated() negation}). 030 * </p> 031 * 032 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de 033 */ 034 public class ResultDescriptor 035 { 036 private Symbol symbol; 037 private Class<?> resultType; 038 private FieldMeta fieldMeta; 039 private ClassMeta classMeta; 040 private boolean negated; 041 042 /** 043 * Create a <code>ResultDescriptor</code>. 044 * @param symbol the symbol; must not be <code>null</code>. 045 * @param resultType the type of the searched candidates. This can be <code>null</code>, 046 * if {@link Symbol#getValueType()} is not <code>null</code>. If {@link Symbol#getValueType()} 047 * is not <code>null</code>, this argument is ignored. 048 */ 049 public ResultDescriptor(Symbol symbol, Class<?> resultType) 050 { 051 if (symbol == null) 052 throw new IllegalArgumentException("symbol == null"); 053 054 this.symbol = symbol; 055 056 if (symbol.getValueType() != null) 057 this.resultType = symbol.getValueType(); 058 else 059 this.resultType = resultType; 060 061 if (this.resultType == null) 062 throw new IllegalArgumentException("resultType could not be determined!"); 063 } 064 065 /** 066 * Create a <code>ResultDescriptor</code>. 067 * @param symbol the symbol; must not be <code>null</code>. 068 * @param resultType the type of the searched candidates. This can be <code>null</code>, 069 * if {@link Symbol#getValueType()} is not <code>null</code>. If {@link Symbol#getValueType()} 070 * is not <code>null</code>, this argument is ignored. 071 * @param fieldMeta the field to be queried, if there is no FCO candidate. Must be 072 * <code>null</code>, if an FCO is searched. 073 * @param classMeta TODO 074 */ 075 public ResultDescriptor(Symbol symbol, Class<?> resultType, FieldMeta fieldMeta, ClassMeta classMeta) 076 { 077 this(symbol, resultType); 078 this.fieldMeta = fieldMeta; 079 this.classMeta = classMeta; 080 } 081 082 private ResultDescriptor(Symbol symbol, Class<?> resultType, FieldMeta fieldMeta, ClassMeta classMeta, boolean negated) 083 { 084 this(symbol, resultType, fieldMeta, classMeta); 085 this.negated = negated; 086 } 087 088 /** 089 * Get the symbol specifying what candidates are searched. 090 * 091 * @return the symbol; never <code>null</code>. 092 */ 093 public Symbol getSymbol() { 094 return symbol; 095 } 096 097 /** 098 * Get the type of the searched candidates. Note, that they might be instances of a subclass. 099 * @return the type; never <code>null</code>. 100 */ 101 public Class<?> getResultType() { 102 return resultType; 103 } 104 105 public ClassMeta getClassMeta() { 106 return classMeta; 107 } 108 109 /** 110 * Get the {@link FieldMeta} to query, if there is no FCO candidate. For example, when 111 * querying for a joined <code>Set<String>.contains(variable)</code>. 112 * This is <code>null</code> when querying for an FCO (then the context is clear from the symbol). 113 * @return the {@link FieldMeta} to query or <code>null</code>. 114 */ 115 public FieldMeta getFieldMeta() { 116 return fieldMeta; 117 } 118 119 /** 120 * <p> 121 * Whether the result is the negation of the actual criteria. 122 * </p> 123 * <p> 124 * It is quite expensive to evaluate a negation (JDOQL "!") by first querying the normal (non-negated) 125 * result and then negating it by querying ALL candidates and finally filtering the normal result 126 * out. Therefore, we instead push the negation down the expression-evaluator-tree into the leafs. 127 * Thus {@link NotExpressionEvaluator} simply calls {@link #negate()} and passes the negated 128 * <code>ResultDescriptor</code> down the evaluator-tree. 129 * All nodes in the tree therefore have to take this flag into account. 130 * </p> 131 * 132 * @return whether the result is the negation of the actual criteria. 133 */ 134 public boolean isNegated() { 135 return negated; 136 } 137 138 /** 139 * Create a negation of this <code>ResultDescriptor</code>. The result will be a copy of this 140 * instance with all fields having the same value except for the {@link #isNegated() negated} flag 141 * which will have the opposite value. 142 * @return a negation of this <code>ResultDescriptor</code>. 143 */ 144 public ResultDescriptor negate() 145 { 146 return new ResultDescriptor(symbol, resultType, fieldMeta, classMeta, !negated); 147 } 148 149 @Override 150 public int hashCode() { 151 final int prime = 31; 152 int result = 1; 153 result = prime * result + ((symbol == null) ? 0 : symbol.hashCode()); 154 result = prime * result + ((resultType == null) ? 0 : resultType.hashCode()); 155 result = prime * result + ((fieldMeta == null) ? 0 : fieldMeta.hashCode()); 156 result = prime * result + (negated ? 1231 : 1237); 157 return result; 158 } 159 160 @Override 161 public boolean equals(Object obj) { 162 if (this == obj) return true; 163 if (obj == null) return false; 164 if (getClass() != obj.getClass()) 165 return false; 166 167 ResultDescriptor other = (ResultDescriptor) obj; 168 return ( 169 (this.symbol == other.symbol || (this.symbol != null && this.symbol.equals(other.symbol))) && 170 this.negated == other.negated && 171 (this.resultType == other.resultType || (this.resultType != null && this.resultType.equals(other.resultType))) && 172 (this.fieldMeta == other.fieldMeta || (this.fieldMeta != null && this.fieldMeta.equals(other.fieldMeta))) 173 ); 174 } 175 }