/*
Copyright (C) 2007 Mobixess Inc. http://www.java-objects-database.com
This file is part of the JODB (Java Objects Database) open source project.
JODB is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation.
JODB 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 this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package com.mobixess.jodb.core.query;
import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
import com.mobixess.jodb.core.IllegalClassTypeException;
import com.mobixess.jodb.core.JODBConfig;
import com.mobixess.jodb.core.JodbIOException;
import com.mobixess.jodb.core.JODBConstants.COMPARE_RESULT;
import com.mobixess.jodb.core.index.IndexDataIterator;
import com.mobixess.jodb.core.index.JODBIndexingAgent;
import com.mobixess.jodb.core.index.JODBIndexingRootAgent;
import com.mobixess.jodb.core.io.IOBase;
import com.mobixess.jodb.core.io.IOTicket;
import com.mobixess.jodb.core.io.JODBOperationContext;
import com.mobixess.jodb.core.io.ObjectDataContainer;
import com.mobixess.jodb.core.io.ObjectDataContainer.FIELD_CATEGORIES;
import com.mobixess.jodb.core.io.ObjectDataContainer.FieldRecord;
import com.mobixess.jodb.core.io.ObjectDataContainer.FieldsIterator;
import com.mobixess.jodb.core.plugin.IClassProcessor;
import com.mobixess.jodb.core.plugin.JODBPluginRegistry;
import com.mobixess.jodb.core.query.SortDataCache.SortNodeRecord;
import com.mobixess.jodb.core.transaction.JODBSession;
import com.mobixess.jodb.core.transaction.TransactionUtils;
import com.mobixess.jodb.core.transaction.JODBSession.ClassDescriptor;
import com.mobixess.jodb.core.transaction.JODBSession.FieldAndIDRecord;
import com.mobixess.jodb.core.transaction.TransactionUtils.DataContainersCache;
//import com.mobixess.jodb.query.api.Evaluation;
import com.mobixess.jodb.query.api.ObjectSet;
import com.mobixess.jodb.soda.api.Constraint;
import com.mobixess.jodb.soda.api.Constraints;
import com.mobixess.jodb.soda.api.Evaluation;
import com.mobixess.jodb.soda.api.Query;
import com.mobixess.jodb.util.ArrayUtils;
import com.mobixess.jodb.util.LongVector;
import com.mobixess.jodb.util.PrimitiveJavaTypesUtil;
import com.mobixess.jodb.util.PrimitiveJavaTypesUtil.PRIMITIVES_ENUMERATION;
@SuppressWarnings("unchecked")
public class QueryNode implements Query, Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String _name;
private transient JODBSession _session;
private Hashtable< String, QueryNode > _descendants = new Hashtable<String, QueryNode>();//TODO HashMap???
//private static enum CONSTRAINT_SUBJECT{CLASS_TYPE, EXAMPLE_OBJECT, COMPARISON_OBJECT, EVALUATION};
private static enum QUERY_SORTING_TYPE{NONE,ASCENDING,DESCENDING};
private static enum CONSTRAINT_EVALUATION_STATUS{UNKNOWN, ACCEPTED, REJECTED, EXCLUDED};
private static enum CONSTRAINT_TYPE{CONTAINS,EQUAL,GREATER,SMALLER,NOT,LIKE,IDENTITY};
private ConstraintsImpl _constraints = new ConstraintsImpl();
private QueryNode _masterNode;
private int _masterNodeSortCounter;
private static HashSet<Object> _defaultByExampleIgnore;
private transient ThreadLocal<ThreadLocalAuxDataHolder> _threadLocalAuxData;
static{
_defaultByExampleIgnore = new HashSet<Object>();
PRIMITIVES_ENUMERATION[] primitivesEnum = PRIMITIVES_ENUMERATION.values();
_defaultByExampleIgnore.add(null);
for (int i = 0; i < primitivesEnum.length; i++) {
try {
Object wrapper = PrimitiveJavaTypesUtil.getDefaultWrapperInstance(primitivesEnum[i]);
_defaultByExampleIgnore.add(wrapper);
} catch (JodbIOException e) {
throw new Error(e);
}
}
}
public QueryNode() {
initThreadLocalData();
}
private void initThreadLocalData(){
_threadLocalAuxData = new ThreadLocal<ThreadLocalAuxDataHolder>() {
@Override
protected ThreadLocalAuxDataHolder initialValue()
{
return new ThreadLocalAuxDataHolder();
}
};
}
public QueryNode(String name, JODBSession session, QueryNode masterNode) {
this();
_name = name;
_session = session;
setMasterNode(masterNode);
}
public QueryNode(Object pattern, Collection defaultIgnoreValues, JODBSession session, QueryNode masterNode) {
this();
_name = "";
_session = session;
assembleForPattern(pattern, defaultIgnoreValues);
setMasterNode(masterNode);
}
public Object readResolve() throws ObjectStreamException{
initThreadLocalData();
return this;
}
private void setMasterNode(QueryNode masterNode){
if(masterNode == null){
_masterNode = this;
}else{
_masterNode = masterNode;
}
}
public void setSession(JODBSession session) {
_session = session;
_constraints.updateSession(session);
Iterator<QueryNode> iterator = _descendants.values().iterator();
while (iterator.hasNext()) {
QueryNode descendant = iterator.next();
descendant.setSession(session);
}
}
public JODBSession getSession() {
return _session;
}
public Constraint constrain(Object constraint) {
return _constraints.addConsraint(constraint);
}
public Constraints constraints() {
return _constraints;
}
public Query descend(String fieldName) {
synchronized (_descendants) {
QueryNode descendant = _descendants.get(fieldName);
if (descendant == null) {
descendant = new QueryNode(fieldName, _session, _masterNode);
}
_descendants.put(fieldName, descendant);
return descendant;
}
}
public int getNextMasterNodeSortCounter() {
return _masterNodeSortCounter++;
}
public ObjectSet execute() throws IOException, IllegalClassTypeException {
IOBase base = _session.getBase();
return base.executeQuery(this);
}
public JODBQueryList runQuery() throws IOException, IllegalClassTypeException{
return runQuery(null,null);
}
public JODBQueryList runQuery(LongVector excludedObjects, LongVector dynamicLongArray) throws IOException, IllegalClassTypeException{
IOBase base = _session.getBase();
IOTicket ticket = base.getIOTicket(true, false);
SortDataCache sortDataCache = new SortDataCache();
initSortDataCache(sortDataCache, new StringBuffer());
if(sortDataCache.getSortNodesCacheSize()>0){
sortDataCache.setValuesAccumulationMode();
}else{
sortDataCache.clearAll();
sortDataCache = null;
}
JODBOperationContext context = new JODBOperationContext(_session,ticket,sortDataCache,null,null,excludedObjects,true);
IndexDataIterator indexIterator = null;
boolean skipConventionalSorting = false;
FieldRecord indexDataIteratorFieldRecord = null;//used for iteraion through indexed data
QueryNode indexedNode = null;
TypeConstraint typeConstraint = null;
try{
Vector<ConstraintBase> vectorOfConstraints = _constraints._constraints;
for (int i = 0; i < vectorOfConstraints.size(); i++) {
ConstraintBase nextCandidate = vectorOfConstraints.elementAt(i);
if(nextCandidate instanceof TypeConstraint){
if(typeConstraint == null){
typeConstraint = (TypeConstraint) nextCandidate;
}else{
typeConstraint = null;//multiple type constraints
break;
}
}
}
if(typeConstraint != null){
//boolean useIndexDataFromIterator = false;
JODBIndexingRootAgent indexingRootAgent = _session.getIndexingRootAgent();
ClassDescriptor classDescriptor = _session.getDescriptorForClass((Class)typeConstraint.getObject());
JODBIndexingAgent indexingAgent = null;
if(sortDataCache!=null){
//lookup indexing data to optimize query
SortNodeRecord[] sortRecords = sortDataCache.getSortNodes();
int fieldId = classDescriptor.getFieldIDForName(sortRecords[0]._fullPath);
if(fieldId!=-1){
indexingAgent = indexingRootAgent.getIndexingAgent(fieldId, base);
if(indexingAgent!=null){
indexIterator = indexingAgent.getIndexIterator(sortRecords[0]._orderAscending);
indexedNode = _descendants.get(sortRecords[0]._fullPath);
skipConventionalSorting = sortRecords.length == 1;
}
}
}
if(indexIterator == null){
//search first index
Iterator<String> descendants = _descendants.keySet().iterator();
while (descendants.hasNext() && indexIterator == null) {
String next = descendants.next();
Field field = classDescriptor.getFieldForName(next);
if(field==null){
continue;
}
indexingAgent = indexingRootAgent.getIndexingAgent(field, base);
if(indexingAgent!=null){
indexIterator = indexingAgent.getIndexIterator(true);
indexedNode = _descendants.get(next);
}
}
}
if(indexingAgent!=null && indexedNode != null){
Field field = classDescriptor.getFieldForID(indexingAgent.getFieldId(), null);
Class fieldType = field.getType();
if(fieldType.isPrimitive()){
indexDataIteratorFieldRecord = new FieldRecord();
indexDataIteratorFieldRecord._fieldID = indexingAgent.getFieldId();
indexDataIteratorFieldRecord._category = FIELD_CATEGORIES.PRIMITIVE;
indexDataIteratorFieldRecord._fieldTypeID = base.getClassTypeSubstitutionID(fieldType.getName());
}
}
}
if(indexIterator==null){
indexIterator = new LArrayIndexIterator(base.getForAllObjects(ticket));
}
LArrayChunkedBuffer acceptedIds = new LArrayChunkedBuffer();
while (indexIterator.hasNext()) {
resetStateOfConstraints();
CONSTRAINT_EVALUATION_STATUS status = CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
long nextObjectId;
if(indexDataIteratorFieldRecord!=null){
indexDataIteratorFieldRecord._primitiveRawDataBuffer.clear();
nextObjectId = indexIterator.next(indexDataIteratorFieldRecord._primitiveRawDataBuffer);
if(excludedObjects!=null && excludedObjects.binarySearch(nextObjectId)>=0){
continue;
}
if(_session.getObjectFromCache(nextObjectId) == null){
//do not analize active objects
indexDataIteratorFieldRecord._primitiveRawDataBuffer.flip();
if(sortDataCache!=null){
sortDataCache.setCandidateID(nextObjectId);
}
indexedNode.analize(-1, indexDataIteratorFieldRecord, context);
typeConstraint.setStatus(CONSTRAINT_EVALUATION_STATUS.ACCEPTED);
_constraints.markExistanceConstrantAsAccepted();
indexedNode._constraints.markExistanceConstrantAsAccepted();
status = getCumulativeStatus();
}
}else{
nextObjectId = indexIterator.next();
if(excludedObjects!=null && excludedObjects.binarySearch(nextObjectId)>=0){
continue;
}
}
if(status == CONSTRAINT_EVALUATION_STATUS.UNKNOWN){
if(sortDataCache!=null){
sortDataCache.setCandidateID(nextObjectId);
}
status = analize(nextObjectId,context);
}
if(status == CONSTRAINT_EVALUATION_STATUS.EXCLUDED){
if( !context.isExcludedObjectId(nextObjectId) ){
dynamicLongArray.addElement(nextObjectId);
}
continue;
}
if(status == CONSTRAINT_EVALUATION_STATUS.ACCEPTED){
if(sortDataCache!=null && JODBConfig.useCacheOnSortOperations()){
sortDataCache.acceptCandidate();
}
acceptedIds.add(nextObjectId);
}
}
long[] resultingOffsets = acceptedIds.toArray();
if(!skipConventionalSorting){
handleSortInstructions(sortDataCache, context, resultingOffsets);
}
return new SimpleArrayQueryList(resultingOffsets, _session);
}finally {
if(sortDataCache!=null){
sortDataCache.clearAll();
}
ticket.close();
}
}
private void handleSortInstructions(SortDataCache sortDataCache, JODBOperationContext context, long[] items) throws IOException{
if(sortDataCache == null){
return;
}
SortingDataProvider sortingDataProvider = new SortingDataProvider(sortDataCache,context,this);
QueryUtils.quickQuerySort(items, sortingDataProvider, sortDataCache.getSortNodes());
}
private CONSTRAINT_EVALUATION_STATUS analize(long offset, JODBOperationContext context) throws IOException{
Object activeObject = _session.getObjectFromCache(offset);
if(activeObject!=null && !context.isServerMode()){
return analize(activeObject, null, context);
}else{
return analize(offset, null, context);
}
}
private CONSTRAINT_EVALUATION_STATUS analize(Object object, Field field, JODBOperationContext context) throws IOException{
_constraints.evaluateActiveObject(object, field, context);
if(field!=null && field.getType().isPrimitive()){
return getCumulativeStatus();
}
if(field!=null){
if (object!=null) {
try {
object = field.get(object);
} catch (Exception e) {
e.printStackTrace();
throw new JodbIOException(e);
}
}
}else if(object == null){
return getCumulativeStatus();
}
ClassDescriptor classDescriptor;
classDescriptor = _session.getDescriptorForClass(object!=null?object.getClass():field.getType());
Iterator<QueryNode> iterator = _descendants.values().iterator();
while (iterator.hasNext()) {
QueryNode descendant = iterator.next();
Field descendantField = classDescriptor.getFieldForName(descendant._name);
if (descendantField != null) {
descendant.analize(object, descendantField, context);
}
}
return getCumulativeStatus();
}
private CONSTRAINT_EVALUATION_STATUS analize(long objectOffset, FieldRecord fieldRecord, JODBOperationContext context) throws IOException{
if(context.isServerMode() && context.isExcludedObjectId(objectOffset)){
_constraints.setStatus(CONSTRAINT_EVALUATION_STATUS.EXCLUDED);
return CONSTRAINT_EVALUATION_STATUS.EXCLUDED;
}
ClassDescriptor classDescriptor = null;
if( fieldRecord!=null ){
try {
classDescriptor = _session.getDescriptorForClass(fieldRecord._fieldTypeID);
} catch (Exception e) {
e.printStackTrace();
throw new JodbIOException(e);
}
if(fieldRecord._category == FIELD_CATEGORIES.PRIMITIVE){
_constraints.evaluatePersistentCopy(classDescriptor, null, fieldRecord, context);
return getCumulativeStatus();
}
objectOffset = fieldRecord._objectOffset;
}else{
if(objectOffset <= 0){
throw new JodbIOException("illegal query state");
}
}
if(objectOffset == 0){
_constraints.evaluatePersistentCopy(classDescriptor, null, null, context);
return getCumulativeStatus();
}
DataContainersCache dataContainersCache = TransactionUtils.getObjectDataContainerCache();
ObjectDataContainer dataContainer = dataContainersCache.pullObjectDataContainer();
IOBase base = _session.getBase();
IOTicket ticket = base.getIOTicket(true, true);
try {//TODO need handling for arrays
dataContainer.readObject(ticket.getRandomAccessBuffer(), base, context.getSession(), objectOffset, true);
return analize(classDescriptor, dataContainer, context);
} finally {
TransactionUtils.getObjectDataContainerCache().pushObjectDataContainer(dataContainer);
ticket.close();
}
}
private CONSTRAINT_EVALUATION_STATUS analize(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, JODBOperationContext context) throws IOException{
FieldsIterator fieldsIterator = dataContainer.getActiveFieldsIterator();
if(fieldsIterator==null){
return getCumulativeStatus();
}
//int[] hierarchy = dataContainer.getClassHierarchy();
int typeID = dataContainer.getOriginalClassType();
try {
classDescriptor = _session.getDescriptorForClass(typeID);
} catch (Exception e) {
e.printStackTrace();
throw new JodbIOException(e);
}
_constraints.evaluatePersistentCopy(classDescriptor, dataContainer, null, context);
HashMap<String, Field> unProcessedDescendantFields = _threadLocalAuxData.get()._processedFieldsBuffer;
unProcessedDescendantFields.clear();
FieldAndIDRecord[] fields = classDescriptor.getAllFields();
for (int i = 0; i < fields.length; i++) {
String name = fields[i]._field.getName();
if( _descendants.containsKey(name)){
unProcessedDescendantFields.put(name,fields[i]._field);
}
}
FieldRecord record = dataContainer.getRecordCache();
while (unProcessedDescendantFields.size() > 0 && fieldsIterator.hasNext()) {
fieldsIterator.next(record,context.getBase(),false);
Field field = classDescriptor.getFieldForID(record._fieldID, null);
String name = field.getName();
QueryNode descendant = _descendants.get(name);
if(descendant == null){
continue;
}
if(!unProcessedDescendantFields.containsKey(name)){//TODO can only happen if private fields with same name exist
continue;
}
descendant.analize(0, record, context);
unProcessedDescendantFields.remove(name);
}
// TODO commented because iterrator now guarantee iterration through all field
// Iterator<Field> remainingFields = unProcessedDescendantFields.values().iterator();
// while(remainingFields.hasNext()){
// Field field = remainingFields.next();
// QueryNode descendant = _descendants.get(field.getName());
// if(descendant == null){
// continue;//TODO should never happen, print log???
// }
// descendant.analize(null,field, context);
// }
return getCumulativeStatus();
}
private void assembleForPattern(Object pattern, Collection defaultIgnoreValues){
ClassDescriptor classDescriptor = _session.getDescriptorForClass(pattern.getClass());
constrain(pattern.getClass());
FieldAndIDRecord[] fields = classDescriptor.getAllFields();
for (int i = 0; i < fields.length; i++) {
Field descendant = fields[i]._field;
Object descendantValue;
try {
descendantValue = descendant.get(pattern);
} catch (Exception e) {
e.printStackTrace();
continue;
}
if(defaultIgnoreValues.contains(descendantValue)){
continue;
}
Query descendantQuery = (QueryNode) descend(descendant.getName());
descendantQuery.constrain(descendantValue);
}
return;
}
public CONSTRAINT_EVALUATION_STATUS getCumulativeStatus(){
CONSTRAINT_EVALUATION_STATUS status = _constraints.getCumulativeStatus();
if(status == CONSTRAINT_EVALUATION_STATUS.REJECTED){
return status;
}
int totalDescendants = _descendants.size();
int totalAccepted = 0;
Iterator<QueryNode> descendantsIterator = _descendants.values().iterator();
while(descendantsIterator.hasNext()){
CONSTRAINT_EVALUATION_STATUS descStatus = descendantsIterator.next().getCumulativeStatus();
switch (descStatus) {
case ACCEPTED:
totalAccepted++;
break;
case REJECTED:
case EXCLUDED:
return descStatus;
}
}
if(status == CONSTRAINT_EVALUATION_STATUS.ACCEPTED && totalDescendants == totalAccepted ){
return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
}else{
return CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
}
}
public void markAsUnreachable(){
_constraints.setStatus(CONSTRAINT_EVALUATION_STATUS.REJECTED);
}
public Query orderAscending() {
_constraints.orderAscending();
return this;
}
public Query orderDescending() {
_constraints.orderDescending();
return this;
}
public void resetStateOfConstraints(){
_constraints.resetStatus();
Iterator<QueryNode> iterator = _descendants.values().iterator();
while (iterator.hasNext()) {
QueryNode descendant = iterator.next();
descendant.resetStateOfConstraints();
}
}
public void refillSortData(long objectID, SortDataCache sortDataCache, JODBOperationContext context) throws IOException{
sortDataCache.setCandidateID(objectID);
if(!hasSortInstructions()){
return;
}
readSortData(objectID, sortDataCache, context);
}
private void readSortData(long objectID, SortDataCache sortDataCache, JODBOperationContext context) throws IOException{
if(sortDataCache.isValuesAccumulationComplete()){
return;
}
Object activeObject = context.getSession().getObjectFromCache(objectID);
if(activeObject!=null){
readSortData(activeObject, null, sortDataCache, context);
return;
}
IOBase base = context.getBase();
DataContainersCache dataContainersCache = TransactionUtils.getObjectDataContainerCache();
ObjectDataContainer dataContainer = dataContainersCache.pullObjectDataContainer();
IOTicket ticket = context.getIoTicket();
try {
dataContainer.readObject(ticket.getRandomAccessBuffer(), base, context.getSession(), objectID, true);
readSortData( dataContainer, (FieldRecord)null, sortDataCache, context);
} finally {
TransactionUtils.getObjectDataContainerCache().pushObjectDataContainer(dataContainer);
}
}
private void readSortData(Object activeObject, Field field, SortDataCache sortDataCache, JODBOperationContext context) throws JodbIOException{
activeObject =_constraints.processSortValuesCache(activeObject, field, context);
if(_descendants.isEmpty() && sortDataCache.isValuesAccumulationComplete()){
return;
}
if(activeObject!=null){
Enumeration<QueryNode> descendants = _descendants.elements();
while (descendants.hasMoreElements()) {
QueryNode descendantQueryNode = descendants.nextElement();
if(descendantQueryNode.hasSortInstructions()){
ClassDescriptor classDescriptor = context.getSession().getDescriptorForClass(activeObject.getClass());
Field descendantField = classDescriptor.getFieldForName(descendantQueryNode._name);
if(descendantField!=null){
descendantQueryNode.readSortData(activeObject, descendantField, sortDataCache, context);
}
}
}
return;
}
}
private void readSortData(ObjectDataContainer dataContainer, FieldRecord fieldRecord, SortDataCache sortDataCache, JODBOperationContext context) throws IOException{
_constraints.processSortValuesCache(dataContainer, fieldRecord, context);
if(_descendants.isEmpty() && sortDataCache.isValuesAccumulationComplete()){
return;
}
if(fieldRecord!=null){
if(fieldRecord._category == FIELD_CATEGORIES.PRIMITIVE){
return;
}
long nextObjectID = fieldRecord._objectOffset;
readSortData(nextObjectID, sortDataCache, context);
return;
} else {
FieldsIterator fieldsIterator = dataContainer.getActiveFieldsIterator();
if(fieldsIterator == null){
return;//TODO add warning?
}
FieldRecord iterratorFieldRecord = dataContainer.getRecordCache();
IOBase base = context.getBase();
while(fieldsIterator.hasNext()){
fieldsIterator.next(iterratorFieldRecord, context.getBase(),false);
QueryNode descendant = _descendants.get(base.getSimpleFieldNameForID(iterratorFieldRecord._fieldID));
if(descendant!=null && descendant.hasSortInstructions()){
descendant.readSortData(null, iterratorFieldRecord, sortDataCache, context);
}
if(sortDataCache.isValuesAccumulationComplete()){
return;
}
}
}
}
private boolean hasSortInstructions(){
if(_constraints._sortingNodeId!=-1){
return true;
}
return descendantsHaveSortInstructions();
}
private boolean descendantsHaveSortInstructions(){
if(_descendants.isEmpty()){
return false;
}
Enumeration<QueryNode> descendants = _descendants.elements();
while (descendants.hasMoreElements()) {
QueryNode element = descendants.nextElement();
if(element.hasSortInstructions()){
return true;
}
}
return false;
}
public void initSortDataCache(SortDataCache sortDataCache, StringBuffer path)
{
_constraints.initSortDataCache(sortDataCache,path);
Iterator<QueryNode> iterator = _descendants.values().iterator();
int pathLen = path.length();
while (iterator.hasNext()) {
QueryNode descendant = iterator.next();
if(path.length()!=0){
path.append('.');
}
path.append(descendant._name);
descendant.initSortDataCache(sortDataCache,path);
path.setLength(pathLen);
}
}
private static class ThreadLocalAuxDataHolder{
private HashMap<String, Field> _processedFieldsBuffer = new HashMap<String, Field>();
}
private class ConstraintsImpl extends ConstraintBase implements Constraints, Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
Vector<ConstraintBase> _constraints = new Vector<ConstraintBase>();
QUERY_SORTING_TYPE _sortingType = QUERY_SORTING_TYPE.NONE;
int _sortingNodeId = -1;
private boolean _recursiveSatusRequest;
public ConstraintsImpl() {
_constraints.add(new ExistanceConstraint());
}
@Override
public void resetStatus()
{
int len = _constraints.size();
for (int i = 0; i < len; i++) {
ConstraintBase constraint = _constraints.elementAt(i);
if (constraint == this) {
continue;
}
constraint.resetStatus();
}
}
@Override
public void setStatus(CONSTRAINT_EVALUATION_STATUS newStatus)
{
int len = _constraints.size();
for (int i = 0; i < len; i++) {
ConstraintBase constraint = _constraints.elementAt(i);
if (constraint == this) {
continue;
}
constraint.setStatus(newStatus);
}
}
public void initSortDataCache(SortDataCache sortDataCache, StringBuffer path)
{
if(_sortingType!= QUERY_SORTING_TYPE.NONE){
sortDataCache.addNode(_sortingNodeId,path.toString(), _sortingType ==QUERY_SORTING_TYPE.ASCENDING);
}
}
public void markExistanceConstrantAsAccepted(){
int len = _constraints.size();
for (int i = 0; i < len; i++) {
ConstraintBase constraint = _constraints.elementAt(i);
if (constraint == this) {
continue;
}
if(constraint instanceof ExistanceConstraint){
constraint.setStatus(CONSTRAINT_EVALUATION_STATUS.ACCEPTED);
}
}
}
public ConstraintBase addConsraint(Object constraint){
ConstraintBase result;
if(constraint instanceof Class){
result = new TypeConstraint((Class) constraint);
}else if(constraint instanceof Evaluation){
result = new EvaluationCallbackConstraint((Evaluation) constraint);
}else{
Class constraintClass = constraint.getClass();
if(constraint instanceof String || constraint instanceof Enum ||
constraintClass.isArray() ||
PrimitiveJavaTypesUtil.isPrimitiveWrapper(constraintClass) )
{
result = new ValueComparisonConstraint(constraint);
}else{
result = new QueryByExample(constraint,_defaultByExampleIgnore, _session);
}
}
_constraints.add(result);
return result;
}
@Override
public CONSTRAINT_EVALUATION_STATUS getStatus()
{
return getCumulativeStatus();
}
@Override
public CONSTRAINT_EVALUATION_STATUS getCumulativeStatus()
{// statis calculated in accordance with AND operation for all contained constraints
if(_recursiveSatusRequest || _constraints.size() == 0){
return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
}
_recursiveSatusRequest = true;
try {
int len = _constraints.size();
int totalAccepted = 0;
for (int i = 0; i < len; i++) {
ConstraintBase constraint = _constraints.elementAt(i);
if (constraint == this) {
continue;
}
if (constraint.getCumulativeStatus() == CONSTRAINT_EVALUATION_STATUS.REJECTED)
{
return CONSTRAINT_EVALUATION_STATUS.REJECTED;
}
if (constraint.getCumulativeStatus() == CONSTRAINT_EVALUATION_STATUS.ACCEPTED)
{
totalAccepted++;
}
}
if (totalAccepted == len) {
return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
} else {
return CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
}
} finally {
_recursiveSatusRequest = false;
}
}
public Constraint[] toArray() {
throw new RuntimeException("Not Implemented");
//return null;
}
public Constraint and(Constraint with) {
int len = _constraints.size();
for (int i = 0; i < len; i++) {
_constraints.elementAt(i).and(with);
}
return this;
}
public Constraint contains() {
int len = _constraints.size();
for (int i = 0; i < len; i++) {
_constraints.elementAt(i).contains();
}
return this;
}
public Constraint equal() {
int len = _constraints.size();
for (int i = 0; i < len; i++) {
_constraints.elementAt(i).equal();
}
return this;
}
public Object getObject() {
return null;//TODO check correctness
}
public Constraint greater() {
int len = _constraints.size();
for (int i = 0; i < len; i++) {
_constraints.elementAt(i).greater();
}
return this;
}
public Constraint identity() {
int len = _constraints.size();
for (int i = 0; i < len; i++) {
_constraints.elementAt(i).identity();
}
return this;
}
public Constraint like() {
int len = _constraints.size();
for (int i = 0; i < len; i++) {
_constraints.elementAt(i).like();
}
return this;
}
public Constraint not() {
int len = _constraints.size();
for (int i = 0; i < len; i++) {
_constraints.elementAt(i).not();
}
return this;
}
public Constraint or(Constraint with) {
int len = _constraints.size();
for (int i = 0; i < len; i++) {
_constraints.elementAt(i).or(with);
}
return this;
}
public Constraint smaller() {
int len = _constraints.size();
for (int i = 0; i < len; i++) {
_constraints.elementAt(i).smaller();
}
return this;
}
@Override
void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
{
int totalConstraints = _constraints.size();
for (int i = 0; i < totalConstraints; i++) {
_constraints.elementAt(i).evaluateActiveObject(activeObject, field, context);
}
if(JODBConfig.useCacheOnSortOperations()){
processSortValuesCache(activeObject, field, context);
}
}
/**
*
* @param activeObject
* @param field
* @param context
* @return active object for descendant analysis - can be result of extraction from 'field', original activeObject or null
* @throws JodbIOException
*/
private Object processSortValuesCache(Object activeObject, Field field, JODBOperationContext context) throws JodbIOException{
if(_sortingNodeId==-1){
return activeObject;
}
if(field!=null){
Class type = field.getType();
if (type == String.class || type == Enum.class || type.isPrimitive() || PrimitiveJavaTypesUtil.isPrimitiveWrapper(type)) {
try {
activeObject = field.get(activeObject);
} catch (Exception e) {
throw new JodbIOException(e);
}
}else{
activeObject = null;
}
}
if(activeObject!=null && (activeObject instanceof String || activeObject instanceof Enum || PrimitiveJavaTypesUtil.isPrimitiveWrapper(activeObject.getClass()))){
SortDataCache sortDataCache = context.getSortDataCache();
if(sortDataCache!=null){
sortDataCache.addSortValue(_sortingNodeId, activeObject);
}
return null;
}
return activeObject;
}
@Override
void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord primitiveRecord, JODBOperationContext context) throws IOException
{
int totalConstraints = _constraints.size();
for (int i = 0; i < totalConstraints; i++) {
_constraints.elementAt(i).evaluatePersistentCopy(classDescriptor, dataContainer, primitiveRecord, context);
if(dataContainer!=null && i < totalConstraints){
FieldsIterator fieldsIterator = dataContainer.getActiveFieldsIterator();
if(fieldsIterator != null){
fieldsIterator.reset();
}
}
}
if(JODBConfig.useCacheOnSortOperations()){
processSortValuesCache(dataContainer, primitiveRecord, context);
}
}
@Override
void updateSession(JODBSession session)
{
int totalConstraints = _constraints.size();
for (int i = 0; i < totalConstraints; i++) {
_constraints.elementAt(i).updateSession(session);
}
}
private void processSortValuesCache(ObjectDataContainer dataContainer, FieldRecord primitiveRecord, JODBOperationContext context) throws IOException{
if(_sortingNodeId==-1){
return;
}
if(primitiveRecord!=null){
SortDataCache sortDataCache = context.getSortDataCache();
if(primitiveRecord._category == FIELD_CATEGORIES.PRIMITIVE){
if(sortDataCache!=null){
PRIMITIVES_ENUMERATION fieldTypeEnum = PrimitiveJavaTypesUtil.getEnumeratedType(primitiveRecord._fieldTypeID, context.getBase());
sortDataCache.addSortValue(_sortingNodeId, PrimitiveJavaTypesUtil.getAsWrappedPrimitive(fieldTypeEnum, primitiveRecord._primitiveRawDataBuffer));
}
}else if(primitiveRecord._fieldTypeName.equals(String.class.getName())){//TODO check for enum?
Object value = TransactionUtils.launchObject(context.getSession(), primitiveRecord._objectOffset , null, 1);
sortDataCache.addSortValue(_sortingNodeId, value);
}
return;
}
if(dataContainer!=null){
Class persistentObjectClass;
try {
persistentObjectClass = context.getSession().resolveClassForID(dataContainer.getOriginalClassType());
} catch (ClassNotFoundException e) {
//TODO debug output???
throw new JodbIOException(e);
}
if(persistentObjectClass==String.class || Enum.class.isAssignableFrom(persistentObjectClass)){
SortDataCache sortDataCache = context.getSortDataCache();
if(sortDataCache!=null){
Object value = TransactionUtils.launchObject(context.getSession(), dataContainer.getOffset(), null, 1);
if(value!=null && (value instanceof String || value instanceof Enum)){
sortDataCache.addSortValue(_sortingNodeId,value);
}else{
System.err.println(" Warning internal state mismatch");//TODO add log
}
}
}
}
}
public void orderAscending() {
_sortingType = QUERY_SORTING_TYPE.ASCENDING;
setSortConstraintIndex();
}
public void orderDescending() {
_sortingType = QUERY_SORTING_TYPE.DESCENDING;
setSortConstraintIndex();
}
private void setSortConstraintIndex(){
if(_sortingNodeId == -1){
_sortingNodeId = _masterNode.getNextMasterNodeSortCounter();
}
}
}
private static class ConstraintLink extends ConstraintBase{
/**
*
*/
private static final long serialVersionUID = 1L;
private boolean _linkTypeIsOr;
private ConstraintBase _constraint1;
private ConstraintBase _constraint2;
/**
* @param linkTypeIsOr
* @param constraint1
* @param constraint2
*/
public ConstraintLink(boolean linkTypeIsOr, ConstraintBase constraint1, ConstraintBase constraint2) {
_linkTypeIsOr = linkTypeIsOr;
_constraint1 = constraint1;
_constraint2 = constraint2;
}
@Override
public CONSTRAINT_EVALUATION_STATUS getCumulativeStatus()
{
CONSTRAINT_EVALUATION_STATUS status1 = _constraint1.getStatus();
CONSTRAINT_EVALUATION_STATUS status2 = _constraint2.getStatus();
if(_linkTypeIsOr){
if(status1 == CONSTRAINT_EVALUATION_STATUS.ACCEPTED || status2 == CONSTRAINT_EVALUATION_STATUS.ACCEPTED ){
return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
}
if(status1 == CONSTRAINT_EVALUATION_STATUS.UNKNOWN || status2 == CONSTRAINT_EVALUATION_STATUS.UNKNOWN ){
return CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
}
return CONSTRAINT_EVALUATION_STATUS.REJECTED;
}else{
if(status1 == CONSTRAINT_EVALUATION_STATUS.REJECTED || status2 == CONSTRAINT_EVALUATION_STATUS.REJECTED ){
return CONSTRAINT_EVALUATION_STATUS.REJECTED;
}
if(status1 == CONSTRAINT_EVALUATION_STATUS.UNKNOWN || status2 == CONSTRAINT_EVALUATION_STATUS.UNKNOWN ){
return CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
}
return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
}
}
public Constraint contains() {
return this;
}
public Constraint equal() {
return this;
}
public Object getObject() {
return null;
}
public Constraint greater() {
return this;
}
public Constraint identity() {
return this;
}
public Constraint like() {
return this;
}
public Constraint not() {
return this;
}
public Constraint smaller() {
return this;
}
@Override
void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context)
{
throw new RuntimeException("Not Implemented");
//
}
@Override
void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord primitiveRecord, JODBOperationContext context)
{
throw new RuntimeException("Not Implemented");
//
}
}
private class QueryByExample extends ValueComparisonConstraint{
/**
*
*/
private static final long serialVersionUID = 1L;
private QueryNode _queryNode;
public QueryByExample(Object constraintOrigin, Collection defaultIgnoreValues, JODBSession session) {
super(null);
_queryNode = new QueryNode(constraintOrigin,defaultIgnoreValues, session, _masterNode);
}
@Override
void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
{
_queryNode.analize(activeObject, field, context);
processEvaluationResult();
}
@Override
void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord record, JODBOperationContext context) throws IOException
{
_queryNode.analize(classDescriptor, dataContainer, context);
processEvaluationResult();
}
private void processEvaluationResult(){
CONSTRAINT_EVALUATION_STATUS status = _queryNode.getCumulativeStatus();
switch (_type) {
case EQUAL:
case LIKE:
setStatus(status);
break;
case NOT:
if(status == CONSTRAINT_EVALUATION_STATUS.ACCEPTED){
setStatus(CONSTRAINT_EVALUATION_STATUS.REJECTED);
}else{
setStatus(CONSTRAINT_EVALUATION_STATUS.ACCEPTED);
}
default:
setStatus(CONSTRAINT_EVALUATION_STATUS.UNKNOWN);
}
}
@Override
public void resetStatus()
{
super.resetStatus();
_queryNode._constraints.resetStatus();
}
@Override
void updateSession(JODBSession session)
{
_queryNode.setSession(session);
}
// @Override
// public CONSTRAINT_EVALUATION_STATUS getCumulativeStatus()
// {
// return _queryNode.getCumulativeStatus();
// }
//
// @Override
// public CONSTRAINT_EVALUATION_STATUS getStatus()
// {
// return getCumulativeStatus();
// }
}
private static class ValueComparisonConstraint extends ConstraintBase{
/**
*
*/
private static final long serialVersionUID = 1L;
private Object _constraintOrigin;
private transient WeakReference<Object> _translatedOrigin = new WeakReference<Object>(null);
CONSTRAINT_TYPE _type = CONSTRAINT_TYPE.EQUAL;
/**
* @param constraintOrigin
*/
public ValueComparisonConstraint(Object constraintOrigin) {
super();
_constraintOrigin = constraintOrigin;
}
public Constraint contains() {
_type=CONSTRAINT_TYPE.CONTAINS;
return this;
}
public Constraint equal() {
_type=CONSTRAINT_TYPE.EQUAL;
return this;
}
public Object getObject() {
return _constraintOrigin;
}
public Constraint greater() {
_type=CONSTRAINT_TYPE.GREATER;
return this;
}
public Constraint identity() {
_type=CONSTRAINT_TYPE.IDENTITY;
return this;
}
public Constraint like() {
_type=CONSTRAINT_TYPE.LIKE;
return this;
}
public Constraint not() {
_type=CONSTRAINT_TYPE.NOT;
return this;
}
public Constraint smaller() {
_type=CONSTRAINT_TYPE.SMALLER;
return this;
}
Object getTranslatedOrigin() throws IOException{
Object result = null;
if(_translatedOrigin!=null){
result = _translatedOrigin.get();
}
if(result == null){
Class originClass = getObject().getClass();
if(PrimitiveJavaTypesUtil.isPrimitiveWrapper(originClass)){
return getObject();
}
IClassProcessor classProcessor = JODBPluginRegistry.getInstance().getClassProcessor(originClass);
result = classProcessor.translate(getObject());
_translatedOrigin = new WeakReference(result);
}
return result;
}
@Override
void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
{
Class originClass = getObject().getClass();
if(field!= null && field.getType().isPrimitive()){
COMPARE_RESULT compareResult;
if(!PrimitiveJavaTypesUtil.isPrimitiveWrapper(originClass)){
compareResult = COMPARE_RESULT.UNKNOWN;
}else{
compareResult = PrimitiveJavaTypesUtil.compare(_constraintOrigin, field, activeObject);
}
processCompareResult(compareResult);
return;
}
if(field!=null && activeObject!=null){
try {
activeObject = field.get(activeObject);
} catch (Exception e) {
e.printStackTrace();
throw new JodbIOException(e);
}
}
if(activeObject!=null){
if(originClass != activeObject.getClass()){
processCompareResult(COMPARE_RESULT.UNKNOWN);
return;
}
IClassProcessor processor = JODBPluginRegistry.getInstance().getClassProcessor(originClass);
COMPARE_RESULT compareResult = processor.compare(getObject(),activeObject, context, null);
processCompareResult(compareResult);
return;
}
}
/*package*/ void processCompareResult(COMPARE_RESULT compareResult) throws JodbIOException{
CONSTRAINT_EVALUATION_STATUS status = getStatusForCompareResult(compareResult, _type);
setStatus(status);
}
private CONSTRAINT_EVALUATION_STATUS getStatusForCompareResult(COMPARE_RESULT compareResult, CONSTRAINT_TYPE type ) throws JodbIOException{
if(compareResult == COMPARE_RESULT.UNKNOWN){
return CONSTRAINT_EVALUATION_STATUS.REJECTED;
}
switch (type) {
case EQUAL:
case IDENTITY:
case LIKE:
if(compareResult == COMPARE_RESULT.EQUAL){
return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
}else{
return CONSTRAINT_EVALUATION_STATUS.REJECTED;
}
case GREATER:
if(compareResult == COMPARE_RESULT.SMALLER){
return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
}else{
return CONSTRAINT_EVALUATION_STATUS.REJECTED;
}
case SMALLER:
if(compareResult == COMPARE_RESULT.GREATER){
return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
}else{
return CONSTRAINT_EVALUATION_STATUS.REJECTED;
}
case NOT:
if(compareResult != COMPARE_RESULT.EQUAL){
return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
}else{
return CONSTRAINT_EVALUATION_STATUS.REJECTED;
}
default:
throw new JodbIOException();
}
}
@Override
void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord record, JODBOperationContext context) throws IOException
{
Class originClass = getObject().getClass();
if(record!=null && record._category == FIELD_CATEGORIES.PRIMITIVE){
COMPARE_RESULT compareResult;
if(!PrimitiveJavaTypesUtil.isPrimitiveWrapper(originClass)){
compareResult = COMPARE_RESULT.UNKNOWN;
}else{
PRIMITIVES_ENUMERATION fieldTypeEnum = PrimitiveJavaTypesUtil.getEnumeratedType(record._fieldTypeID, context.getBase());
compareResult = PrimitiveJavaTypesUtil.compare(_constraintOrigin, record, fieldTypeEnum);
}
processCompareResult(compareResult);
return;
}
if(dataContainer!=null){
Class persistentObjectClass;
try {
persistentObjectClass = context.getSession().resolveClassForID(dataContainer.getOriginalClassType());
} catch (ClassNotFoundException e) {
//TODO debug output???
throw new JodbIOException(e);
}
if(originClass!=persistentObjectClass){
processCompareResult(COMPARE_RESULT.UNKNOWN);
return;
}
IClassProcessor processor = JODBPluginRegistry.getInstance().getClassProcessor(originClass);
if(_type == CONSTRAINT_TYPE.EQUAL || _type == CONSTRAINT_TYPE.NOT){//equals methods can be better optimized
boolean equal = processor.equals(getTranslatedOrigin(), dataContainer, context, null);
processCompareResult(equal? COMPARE_RESULT.EQUAL : COMPARE_RESULT.SMALLER);
return;
}else{
COMPARE_RESULT compareResult = processor.compare(getTranslatedOrigin(), dataContainer, context, null, originClass);
processCompareResult(compareResult);
return;
}
}
}
}
private static class TypeConstraint extends ValueComparisonConstraint{
/**
*
*/
private static final long serialVersionUID = 1L;
int _constraintClassTypeID = -1;
public TypeConstraint(Class constraintOrigin) {
super(constraintOrigin);
}
@Override
void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
{
Class constaintClass = (Class) getObject();
boolean isInstanceOf = false;
if(field!=null){
isInstanceOf = field.getType().isAssignableFrom(constaintClass);
if(!isInstanceOf && activeObject!=null){
try {
activeObject = field.get(activeObject);
} catch (Exception e) {
e.printStackTrace();
throw new JodbIOException(e);
}
}
}
if(!isInstanceOf){
if( activeObject!=null){
isInstanceOf = constaintClass.isInstance(activeObject);
}else{
setStatus(CONSTRAINT_EVALUATION_STATUS.REJECTED);
return;
}
}
setStatus(evaluateObject(isInstanceOf, _type ));
}
@Override
public void resetStatus()
{
_constraintClassTypeID=-1;
}
private CONSTRAINT_EVALUATION_STATUS evaluateObject(boolean isInstanceOfConstraint, CONSTRAINT_TYPE type) throws JodbIOException{
switch (type) {
case EQUAL:
case IDENTITY:
case LIKE:
if(isInstanceOfConstraint ){
return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
}else{
return CONSTRAINT_EVALUATION_STATUS.REJECTED;
}
case GREATER:
case SMALLER:
return CONSTRAINT_EVALUATION_STATUS.REJECTED;
case NOT:
if(!isInstanceOfConstraint ){
return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
}else{
return CONSTRAINT_EVALUATION_STATUS.REJECTED;
}
default:
throw new JodbIOException();
}
}
@Override
void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord record, JODBOperationContext context) throws JodbIOException
{
setStatus(evaluatePersistentCopyForType(_type, classDescriptor, dataContainer, record, context.getSession()));
}
CONSTRAINT_EVALUATION_STATUS evaluatePersistentCopyForType(CONSTRAINT_TYPE type, ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord record, JODBSession session) throws JodbIOException
{
boolean isInstanceOf;
if(classDescriptor == null){
isInstanceOf = false;
}else{
String[] hierarchy = classDescriptor.getTypes();
String className = ((Class)getObject()).getName();
if(ArrayUtils.indexOf(hierarchy, className)==-1){
isInstanceOf = false;
}else{
isInstanceOf = true;
}
}
return evaluateObject(isInstanceOf, type);
}
public int getConstraintClassTypeID(JODBSession session) throws JodbIOException {
int result = _constraintClassTypeID;//precaution in case of multi threading
if(result == -1){
result = session.getBase().getClassTypeSubstitutionID(((Class)getObject()).getName());
_constraintClassTypeID = result;
}
return result;
}
}
/*private class ByExampleConstraint extends ValueComparisonConstraint{
Field[] _fieldsToIgnore;
public ByExampleConstraint(Object constraintOrigin) {
super(constraintOrigin);
Object translatedOrigin = getTranslatedOrigin();
try {//TODO should have two copies of ignore fields for original object and translated
ClassDescriptor classDescriptor = _session.getDescriptorForClass(translatedOrigin.getClass());
Vector<Field> fieldsToIgnore = new Vector<Field>();
Field[] fields = classDescriptor.getFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
Object val = field.get(translatedOrigin);
if(val == null){
fieldsToIgnore.add(field);
continue;
}
Class type = field.getType();
if(type.isPrimitive()){
Object wrapperObj = PrimitiveJavaTypesUtil.getDefaultWrapperInstance(type.getName());
if(val.equals( wrapperObj ) ){
fieldsToIgnore.add(field);
continue;
}
}
}
_fieldsToIgnore = new Field[fieldsToIgnore.size()];
_fieldsToIgnore = fieldsToIgnore.toArray(_fieldsToIgnore);
} catch (Exception e) {
e.printStackTrace();
_fieldsToIgnore = new Field[0];
processCompareResult(COMPARE_RESULT.UNKNOWN);
}
}
@Override
void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
{
if(field!=null && activeObject!=null){
try {
activeObject = field.get(activeObject);
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
if(activeObject!=null){
Object byExapleConstraint = getObject();
if(activeObject.getClass()!=byExapleConstraint.getClass()){
processCompareResult(COMPARE_RESULT.GREATER);
return;
}
IClassProcessor processor = JODBPluginRegistry.getInstance().getClassProcessor(byExapleConstraint.getClass());
COMPARE_RESULT compare_result = processor.compare(byExapleConstraint, activeObject, context, _fieldsToIgnore);
processCompareResult(compare_result);
}
}
@Override
void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord record, JODBOperationContext context) throws IOException
{
if(record!=null){
if(record._category == FIELD_CATEGORIES.PRIMITIVE){
processCompareResult(COMPARE_RESULT.GREATER);
return;
}
}
if(dataContainer!=null){
// Class originClass = getObject().getClass();
// Class persistentObjectClass;
// try {
// persistentObjectClass = context.getSession().resolveClassForID(dataContainer.getOriginalClassType());
// } catch (ClassNotFoundException e) {
// //TODO debug output???
// throw new IOException(e.getMessage());
// }
// if(originClass!=persistentObjectClass){
// processCompareResult(COMPARE_RESULT.UNKNOWN);
// return;
// }
Object byExapleConstraint = getObject();
if(classDescriptor.getType()!=byExapleConstraint.getClass()){
processCompareResult(COMPARE_RESULT.GREATER);
return;
}
IClassProcessor processor = JODBPluginRegistry.getInstance().getClassProcessor(byExapleConstraint.getClass());
if(_type == CONSTRAINT_TYPE.EQUAL || _type == CONSTRAINT_TYPE.NOT){//equals methods can be better optimized
boolean equal = processor.equals(getTranslatedOrigin(), dataContainer, context, _fieldsToIgnore);
processCompareResult(equal? COMPARE_RESULT.EQUAL : COMPARE_RESULT.SMALLER);
return;
}else{
COMPARE_RESULT compareResult = processor.compare(getTranslatedOrigin(), dataContainer, context, _fieldsToIgnore);
processCompareResult(compareResult);
return;
}
}
}
}*/
private static class EvaluationCallbackConstraint extends ValueComparisonConstraint{
private ThreadLocal<CandidateImpl> _candidateImpl = new ThreadLocal<CandidateImpl>() {
@Override
protected CandidateImpl initialValue()
{
return new CandidateImpl();
}
};
public EvaluationCallbackConstraint(Evaluation constraintOrigin) {
super(constraintOrigin);
}
@Override
void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
{
if(field!=null && activeObject!=null){
try {
activeObject = field.get(activeObject);
} catch (Exception e) {
throw new JodbIOException(e);
}
}
if(activeObject!=null){
Evaluation evaluation = (Evaluation) getObject();
CandidateImpl candidateImpl = _candidateImpl.get();
candidateImpl.init(activeObject);
evaluation.evaluate(candidateImpl);
if(candidateImpl.isInclude()){
processCompareResult(COMPARE_RESULT.EQUAL);
}else{
processCompareResult(COMPARE_RESULT.SMALLER);
}
}
}
@Override
void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord record, JODBOperationContext context) throws IOException
{
if(record!=null && record._category == FIELD_CATEGORIES.PRIMITIVE){
PRIMITIVES_ENUMERATION fieldTypeEnum = PrimitiveJavaTypesUtil.getEnumeratedType(record._fieldTypeID, context.getBase());
Object obj = PrimitiveJavaTypesUtil.getAsWrappedPrimitive(fieldTypeEnum,record._primitiveRawDataBuffer);
evaluateActiveObject(obj, null, context);
return;
}
if(dataContainer!=null){
Evaluation evaluation = (Evaluation) getObject();
int activationDepth = evaluation.getActivationDepth() >= 0 ? evaluation.getActivationDepth() : JODBConfig.getDefaultActivationDepth();
Object obj = context.getSession().getObjectForOffset(dataContainer.getOffset(), activationDepth);
evaluateActiveObject(obj, null, context);
return;
}
}
}
/**
* Constraint to ensure that field actually exists
*
* @author Mobixess
*
*/
private static class ExistanceConstraint extends ConstraintBase{
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
{
setStatus(CONSTRAINT_EVALUATION_STATUS.ACCEPTED);
}
@Override
void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord primitiveRecord, JODBOperationContext context) throws IOException
{
setStatus(CONSTRAINT_EVALUATION_STATUS.ACCEPTED);
}
public Constraint contains() {
// TODO Auto-generated method stub
throw new RuntimeException("Not Implemented");
//return null;
}
public Constraint equal() {
// TODO Auto-generated method stub
throw new RuntimeException("Not Implemented");
//return null;
}
public Object getObject() {
// TODO Auto-generated method stub
throw new RuntimeException("Not Implemented");
//return null;
}
public Constraint greater() {
// TODO Auto-generated method stub
throw new RuntimeException("Not Implemented");
//return null;
}
public Constraint identity() {
// TODO Auto-generated method stub
throw new RuntimeException("Not Implemented");
//return null;
}
public Constraint like() {
// TODO Auto-generated method stub
throw new RuntimeException("Not Implemented");
//return null;
}
public Constraint not() {
// TODO Auto-generated method stub
throw new RuntimeException("Not Implemented");
//return null;
}
public Constraint smaller() {
// TODO Auto-generated method stub
throw new RuntimeException("Not Implemented");
//return null;
}
}
private abstract static class ConstraintBase implements Constraint, Serializable{
private transient ThreadLocal<CONSTRAINT_EVALUATION_STATUS> _status;
private Vector<ConstraintBase> _links = new Vector<ConstraintBase>(2);
public ConstraintBase() {
initStatus();
}
void updateSession(JODBSession session){
}
private void initStatus(){
_status = new ThreadLocal<CONSTRAINT_EVALUATION_STATUS>() {
@Override
protected CONSTRAINT_EVALUATION_STATUS initialValue()
{
return CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
}
};
}
public void resetStatus(){
_status.set(CONSTRAINT_EVALUATION_STATUS.UNKNOWN);
}
public Object readResolve() throws ObjectStreamException{
initStatus();
return this;
}
public void setStatus(CONSTRAINT_EVALUATION_STATUS newStatus){
_status.set(newStatus);
}
public Constraint and(Constraint with) {
ConstraintBase withImpl = (ConstraintBase) with;
ConstraintLink link = new ConstraintLink(false,this, withImpl);
_links.add(link);
withImpl._links.add(link);
return link;
}
public CONSTRAINT_EVALUATION_STATUS getStatus() {
return _status.get();
}
public CONSTRAINT_EVALUATION_STATUS getCumulativeStatus() {
synchronized (_links) {
if(_links.size()==0){
return _status.get();
}
int acceptedCount = 0;
for (int i = 0; i < _links.size(); i++) {
switch (_links.elementAt(i).getCumulativeStatus()) {
case ACCEPTED:
acceptedCount++;
break;
case REJECTED:
return CONSTRAINT_EVALUATION_STATUS.REJECTED;
}
}
if(acceptedCount == _links.size()){
return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
}else{
return CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
}
}
}
abstract void evaluatePersistentCopy( ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord primitiveRecord, JODBOperationContext context) throws IOException;
abstract void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException;
public Constraint or(Constraint with) {
ConstraintBase withImpl = (ConstraintBase) with;
ConstraintLink link = new ConstraintLink(true,this, withImpl);
_links.add(link);
withImpl._links.add(link);
return link;
}
}
}