001: /**
002: * Copyright 2007 Jens Dietrich Licensed under the Apache License, Version 2.0 (the "License");
003: * you may not use this file except in compliance with the License.
004: * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
005: * Unless required by applicable law or agreed to in writing, software distributed under the
006: * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
007: * either express or implied. See the License for the specific language governing permissions
008: * and limitations under the License.
009: */package nz.org.take;
010:
011: import java.util.ArrayList;
012: import java.util.List;
013:
014: /**
015: * Function aggregation the results of several other queries.
016: * @author <a href="http://www-ist.massey.ac.nz/JBDietrich/">Jens Dietrich</a>
017: */
018:
019: public class AggregationFunction implements Function {
020:
021: private static final Class[] NUMTYPES = { Character.TYPE,
022: Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE,
023: Double.TYPE, Boolean.class, Character.class, Byte.class,
024: Short.class, Integer.class, Long.class, Float.class,
025: Double.class };
026: private String name = null;
027: private Fact query = null;
028: private Aggregations aggregation = null;
029: private Variable variable = null;
030: // derived
031: private Class[] paramTypes = null;
032: private int variableSlot = -1;
033:
034: /**
035: * Check the integrity of the parameters and set return and parameter types.
036: */
037: private void init(boolean force) throws IllegalArgumentException {
038:
039: if (!force
040: && (query == null || variable == null || aggregation == null))
041: return; // delay initialisation
042:
043: // check whether variable occurs in query fact
044: boolean checkVar = false;
045: int slotNo = -1;
046: for (Term t : query.getTerms()) {
047: slotNo = slotNo + 1;
048: if (this .variable.equals(t)) {
049: checkVar = true;
050: variableSlot = slotNo;
051: }
052: if (t instanceof ComplexTerm) {
053: throw new IllegalArgumentException(
054: "Complex terms in the definition of aggregations are not (yet) supported: "
055: + this .getName());
056: }
057: }
058: if (!checkVar)
059: throw new IllegalArgumentException(
060: "The aggregation variable in " + this .getName()
061: + " does not occur in the query");
062:
063: // check whether output slot is numeric
064: Class oType = this .variable.getType();
065: boolean isPrimitive = false;
066: for (Class numType : NUMTYPES) {
067: if (oType == numType)
068: isPrimitive = true;
069: }
070: if (!isPrimitive && this .getAggregation() != Aggregations.COUNT)
071: throw new IllegalArgumentException(
072: "The return type in aggregation functions must be numeric but is "
073: + oType.getName());
074:
075: // TODO
076: // check variable and also check constants
077: final List<Class> paramTypes = new ArrayList<Class>();
078: KnowledgeBaseVisitor visitor = new AbstractKnowledgeBaseVisitor() {
079: public boolean visit(Variable variable) {
080: paramTypes.add(variable.getType());
081: return false;
082: }
083: };
084: this .query.accept(visitor);
085:
086: this .paramTypes = new Class[paramTypes.size()];
087: for (int i = 0; i < paramTypes.size(); i++)
088: this .paramTypes[i] = paramTypes.get(i);
089:
090: }
091:
092: public Class[] getParamTypes() {
093: if (paramTypes == null)
094: init(true);
095: return paramTypes;
096: }
097:
098: public Class getReturnType() {
099: if (this .getAggregation() == Aggregations.COUNT)
100: return PrimitiveTypeUtils.getDefaultIntegerType();
101: else
102: return this .variable.getType();
103: }
104:
105: public String toString() {
106: return getName();
107: }
108:
109: public String getName() {
110: return name;
111: }
112:
113: public void setName(String name) {
114: this .name = name;
115: }
116:
117: public Aggregations getAggregation() {
118: return aggregation;
119: }
120:
121: public void setAggregation(Aggregations aggregation) {
122: this .aggregation = aggregation;
123: init(false);
124: }
125:
126: public Fact getQuery() {
127: return query;
128: }
129:
130: public void setQuery(Fact query) {
131: this .query = query;
132: init(false);
133: }
134:
135: public Variable getVariable() {
136: return variable;
137: }
138:
139: public void setVariable(Variable variable) {
140: this .variable = variable;
141: init(false);
142: }
143:
144: @Override
145: public int hashCode() {
146: final int prime = 31;
147: int result = 1;
148: result = prime * result
149: + ((aggregation == null) ? 0 : aggregation.hashCode());
150: result = prime * result
151: + ((name == null) ? 0 : name.hashCode());
152: result = prime * result
153: + ((query == null) ? 0 : query.hashCode());
154: result = prime * result
155: + ((variable == null) ? 0 : variable.hashCode());
156: return result;
157: }
158:
159: @Override
160: public boolean equals(Object obj) {
161: if (this == obj)
162: return true;
163: if (obj == null)
164: return false;
165: if (getClass() != obj.getClass())
166: return false;
167: final AggregationFunction other = (AggregationFunction) obj;
168: if (aggregation == null) {
169: if (other.aggregation != null)
170: return false;
171: } else if (!aggregation.equals(other.aggregation))
172: return false;
173: if (name == null) {
174: if (other.name != null)
175: return false;
176: } else if (!name.equals(other.name))
177: return false;
178: if (query == null) {
179: if (other.query != null)
180: return false;
181: } else if (!query.equals(other.query))
182: return false;
183: if (variable == null) {
184: if (other.variable != null)
185: return false;
186: } else if (!variable.equals(other.variable))
187: return false;
188: return true;
189: }
190:
191: public int getVariableSlot() {
192: return variableSlot;
193: }
194:
195: }
|