
org.zoodb.jdo.QueryResultProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of parent Show documentation
Show all versions of parent Show documentation
ZooDB Java JDO Object Database.
The newest version!
/*
* Copyright 2009-2013 Tilmann Zaeschke. All rights reserved.
*
* This file is part of ZooDB.
*
* ZooDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZooDB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZooDB. If not, see .
*
* See the README and COPYING files for further information.
*/
package org.zoodb.jdo;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import javax.jdo.JDOUserException;
import org.zoodb.jdo.internal.SerializerTools.PRIMITIVE;
import org.zoodb.jdo.internal.ZooClassDef;
import org.zoodb.jdo.internal.ZooFieldDef;
/**
* Processes query results.
*
* See Jdo 2.2 spec 14.6.9.
*
* @author Tilmann Zaeschke
*
*/
class QueryResultProcessor {
private final ArrayList- items = new ArrayList
- ();
private boolean isProjection = false;
private static abstract class Item {
ZooFieldDef field;
Field jField;
Class> resultClass;
boolean isFloat;
void setField(ZooFieldDef field, Class> resultClass) {
this.field = field;
if (field.getJavaField() == null) {
field.getDeclaringType().associateJavaTypes();
}
this.jField = field.getJavaField();
this.resultClass = resultClass;
if (resultClass == null) {
this.resultClass = jField.getType();
}
isFloat = field.getPrimitiveType() == PRIMITIVE.FLOAT ||
field.getPrimitiveType() == PRIMITIVE.DOUBLE;
}
protected Object getValue(Object o) {
try {
return jField.get(o);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
protected double getFloat(Object o) {
try {
switch (field.getPrimitiveType()) {
case DOUBLE: return jField.getDouble(o);
case FLOAT: return jField.getFloat(o);
default:
throw new UnsupportedOperationException(field.getPrimitiveType().name());
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
protected long getInt(Object o) {
try {
switch (field.getPrimitiveType()) {
case BYTE: return jField.getByte(o);
case CHAR: return jField.getChar(o);
case INT: return jField.getInt(o);
case LONG: return jField.getLong(o);
case SHORT: return jField.getShort(o);
default:
throw new UnsupportedOperationException(field.getPrimitiveType().name());
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
Object toFloat(double d) {
switch (field.getPrimitiveType()) {
case DOUBLE: return (double)d;
case FLOAT: return (float)d;
default:
throw new UnsupportedOperationException(field.getPrimitiveType().name());
}
}
Object toInt(long l) {
switch (field.getPrimitiveType()) {
//case BOOLEAN: return (boolean)avg;
case BYTE: return (byte)l;
case CHAR: return (char)l;
case DOUBLE: return (double)l;
case FLOAT: return (float)l;
case INT: return (int)l;
case LONG: return (long)l;
case SHORT: return(short)l;
default:
throw new UnsupportedOperationException(field.getPrimitiveType().name());
}
}
abstract void add(Object o);
abstract Object result();
}
private static class AVG extends Item {
private double d;
private long l;
long n;
@Override
void add(Object o) {
n++;
if (isFloat) {
d += getFloat(o);
} else {
l += getInt(o);
}
}
@Override
Object result() {
if (isFloat) {
double avg = d/(double)n;
return toFloat(avg);
} else {
long avg = l/n;
return toInt(avg);
}
}
}
private static class MAX extends Item {
private double d = Double.NEGATIVE_INFINITY;
private long l = Long.MIN_VALUE;
@Override
void add(Object o) {
if (isFloat) {
double d2 = getFloat(o);
if (d2 > d) {
d = d2;
}
} else {
long i2 = getInt(o);
if (i2 > l) {
l = i2;
}
}
}
@Override
Object result() {
if (isFloat) {
return toFloat(d);
} else {
return toInt(l);
}
}
}
private static class MIN extends Item {
private double d = Double.MAX_VALUE;
private long l = Long.MAX_VALUE;
@Override
void add(Object o) {
if (isFloat) {
double d2 = getFloat(o);
if (d2 < d) {
d = d2;
}
} else {
long i2 = getInt(o);
if (i2 < l) {
l = i2;
}
}
}
@Override
Object result() {
if (isFloat) {
return toFloat(d);
} else {
return toInt(l);
}
}
}
private static class SUM extends Item {
private double d;
private long l;
@Override
void add(Object o) {
if (isFloat) {
d += getFloat(o);
} else {
l += getInt(o);
}
}
@Override
Object result() {
if (isFloat) {
return d;
} else {
return l;
}
}
}
private static class COUNT extends Item {
private long n = 0;
@Override
void add(Object o) {
n++;
}
@Override
Object result() {
return n;
}
}
private static class FIELD extends Item {
private Object ret = null;
@Override
void add(Object o) {
ret = getValue(o);
}
@Override
Object result() {
return ret;
}
}
/**
*
* @param data For example: "avg(salary), sum(salary)". min, max, avg, sum, count
* @param candCls
* @param candClsDef
*/
QueryResultProcessor(String data, Class> candCls, ZooClassDef candClsDef,
Class> resultClass) {
data = data.trim();
while (data.length() > 0) {
Item item;
if (data.startsWith("avg") || data.startsWith("AVG")) {
item = new AVG();
data = data.substring(3);
} else if (data.startsWith("max") || data.startsWith("MAX")) {
item = new MAX();
data = data.substring(3);
} else if (data.startsWith("min") || data.startsWith("MIN")) {
item = new MIN();
data = data.substring(3);
} else if (data.startsWith("sum") || data.startsWith("SUM")) {
item = new SUM();
data = data.substring(3);
} else if (data.startsWith("count") || data.startsWith("COUNT")) {
item = new COUNT();
data = data.substring(5);
} else {
item = new FIELD(); //simple field
isProjection = true;
// throw new JDOUserException("Query result type not recognised: " + data);
}
String fieldName;
if (item instanceof FIELD) {
//field only
int i = data.indexOf(',');
if (i >= 0) {
fieldName = data.substring(0, i).trim();
data = data.substring(i).trim();
} else {
fieldName = data.trim();
data = "";
}
} else {
data = data.trim();
if (data.charAt(0)!='(') {// {startsWith("(")) {
throw new JDOUserException(
"Query result type corrupted, '(' expected at pos 0: " + data);
}
data = data.substring(1);
int i = data.indexOf(')');
if (i < 0) {
throw new JDOUserException(
"Query result type corrupted, ')' not found: " + data);
}
fieldName = data.substring(0, i).trim();
data = data.substring(i).trim();
//remove ')'
data = data.substring(1).trim();
}
items.add(item);
ZooFieldDef def = candClsDef.getAllFieldsAsMap().get(fieldName);
if (def == null) {
throw new JDOUserException("Invalid fieldname in result definition: " + fieldName);
}
item.setField(def, resultClass);//getField(candCls, candClsDef, fieldName));
if (!data.isEmpty() && data.charAt(0) == ',') {
data = data.substring(1).trim();
if (data.isEmpty()) {
throw new JDOUserException("Trailing comma in result definition not allowed.");
}
}
}
//some verification
for (Item i: items) {
if (!(i instanceof FIELD) && isProjection) {
throw new JDOUserException("Mixing of prejection and aggregation is not allowed.");
}
}
}
Object processResult(Collection
© 2015 - 2025 Weber Informatics LLC | Privacy Policy