blob: 3e02b83379fe812715783177ccf0cb290f112b8c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.usergrid.mq;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.collections.comparators.ComparatorChain;
import org.apache.usergrid.mq.Query.FilterOperator;
import org.apache.usergrid.mq.Query.FilterPredicate;
import org.apache.usergrid.mq.Query.SortPredicate;
import org.apache.usergrid.persistence.Entity;
import org.apache.usergrid.utils.NumberUtils;
import static org.apache.usergrid.mq.Query.SortDirection.DESCENDING;
public class QueryProcessor {
private static final Logger logger = LoggerFactory.getLogger( QueryProcessor.class );
Query query;
String cursor;
List<QuerySlice> slices;
List<FilterPredicate> filters;
List<SortPredicate> sorts;
public QueryProcessor( Query query ) {
this.query = query;
cursor = query.getCursor();
filters = query.getFilterPredicates();
sorts = query.getSortPredicates();
process();
}
public Query getQuery() {
return query;
}
public String getCursor() {
return cursor;
}
public List<QuerySlice> getSlices() {
return slices;
}
public List<FilterPredicate> getFilters() {
return filters;
}
public List<SortPredicate> getSorts() {
return sorts;
}
private void process() {
slices = new ArrayList<QuerySlice>();
throw new UnsupportedOperationException( "query not supported" );
// // consolidate all the filters into a set of ranges
// Set<String> names = getFilterPropertyNames();
// for ( String name : names ) {
// FilterOperator operator = null;
// Object value = null;
// RangeValue start = null;
// RangeValue finish = null;
// for ( FilterPredicate f : filters ) {
// if ( f.getPropertyName().equals( name ) ) {
// operator = f.getOperator();
// value = f.getValue();
// RangePair r = getRangeForFilter( f );
// if ( r.start != null ) {
// if ( ( start == null ) || ( r.start.compareTo( start, false ) < 0 ) ) {
// start = r.start;
// }
// }
// if ( r.finish != null ) {
// if ( ( finish == null ) || ( r.finish.compareTo( finish, true ) > 0 ) ) {
// finish = r.finish;
// }
// }
// }
// }
// slices.add( new QuerySlice( name, operator, value, start, finish, null, false ) );
// }
//
// // process sorts
// if ( ( slices.size() == 0 ) && ( sorts.size() > 0 ) ) {
// // if no filters, turn first filter into a sort
// SortPredicate sort = ListUtils.dequeue( sorts );
// slices.add( new QuerySlice( sort.getPropertyName(), null, null, null, null, null,
// sort.getDirection() == DESCENDING ) );
// }
// else if ( sorts.size() > 0 ) {
// // match up sorts with existing filters
// for ( ListIterator<SortPredicate> iter = sorts.listIterator(); iter.hasNext(); ) {
// SortPredicate sort = iter.next();
// QuerySlice slice = getSliceForProperty( sort.getPropertyName() );
// if ( slice != null ) {
// slice.reversed = sort.getDirection() == DESCENDING;
// iter.remove();
// }
// }
// }
//
// // attach cursors to slices
// if ( ( cursor != null ) && ( cursor.indexOf( ':' ) >= 0 ) ) {
// String[] cursors = split( cursor, '|' );
// for ( String c : cursors ) {
// String[] parts = split( c, ':' );
// if ( parts.length == 2 ) {
// int cursorHashCode = parseInt( parts[0] );
// for ( QuerySlice slice : slices ) {
// int sliceHashCode = slice.hashCode();
// logger.info( "Comparing cursor hashcode " + cursorHashCode + " to " + sliceHashCode );
// if ( sliceHashCode == cursorHashCode ) {
// if ( isNotBlank( parts[1] ) ) {
// ByteBuffer cursorBytes = ByteBuffer.wrap( decodeBase64( parts[1] ) );
// slice.setCursor( cursorBytes );
// }
// }
// }
// }
// }
// }
}
@SuppressWarnings("unchecked")
public List<Entity> sort( List<Entity> entities ) {
throw new UnsupportedOperationException( "Unsupported" );
//
// if ( ( entities != null ) && ( sorts.size() > 0 ) ) {
// // Performing in memory sort
// logger.info( "Performing in-memory sort of {} entities", entities.size() );
// ComparatorChain chain = new ComparatorChain();
// for ( SortPredicate sort : sorts ) {
// chain.addComparator(
// new EntityPropertyComparator( sort.getPropertyName(), sort.getDirection() == DESCENDING ) );
// }
// Collections.sort( entities, chain );
// }
// return entities;
}
private Set<String> getFilterPropertyNames() {
Set<String> names = new LinkedHashSet<String>();
for ( FilterPredicate f : filters ) {
names.add( f.getPropertyName() );
}
return names;
}
public QuerySlice getSliceForProperty( String name ) {
for ( QuerySlice s : slices ) {
if ( s.propertyName.equals( name ) ) {
return s;
}
}
return null;
}
public static class RangeValue {
byte code;
Object value;
boolean inclusive;
public RangeValue( byte code, Object value, boolean inclusive ) {
this.code = code;
this.value = value;
this.inclusive = inclusive;
}
public byte getCode() {
return code;
}
public void setCode( byte code ) {
this.code = code;
}
public Object getValue() {
return value;
}
public void setValue( Object value ) {
this.value = value;
}
public boolean isInclusive() {
return inclusive;
}
public void setInclusive( boolean inclusive ) {
this.inclusive = inclusive;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + code;
result = prime * result + ( inclusive ? 1231 : 1237 );
result = prime * result + ( ( value == null ) ? 0 : value.hashCode() );
return result;
}
@Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
RangeValue other = ( RangeValue ) obj;
if ( code != other.code ) {
return false;
}
if ( inclusive != other.inclusive ) {
return false;
}
if ( value == null ) {
if ( other.value != null ) {
return false;
}
}
else if ( !value.equals( other.value ) ) {
return false;
}
return true;
}
public int compareTo( RangeValue other, boolean finish ) {
if ( other == null ) {
return 1;
}
if ( code != other.code ) {
return NumberUtils.sign( code - other.code );
}
@SuppressWarnings({ "unchecked", "rawtypes" }) int c = ( ( Comparable ) value ).compareTo( other.value );
if ( c != 0 ) {
return c;
}
if ( finish ) {
// for finish values, inclusive means <= which is greater than <
if ( inclusive != other.inclusive ) {
return inclusive ? 1 : -1;
}
}
else {
// for start values, inclusive means >= which is lest than >
if ( inclusive != other.inclusive ) {
return inclusive ? -1 : 1;
}
}
return 0;
}
public static int compare( RangeValue v1, RangeValue v2, boolean finish ) {
if ( v1 == null ) {
if ( v2 == null ) {
return 0;
}
return -1;
}
return v1.compareTo( v2, finish );
}
}
public static class RangePair {
RangeValue start;
RangeValue finish;
public RangePair( RangeValue start, RangeValue finish ) {
this.start = start;
this.finish = finish;
}
public RangeValue getStart() {
return start;
}
public void setStart( RangeValue start ) {
this.start = start;
}
public RangeValue getFinish() {
return finish;
}
public void setFinish( RangeValue finish ) {
this.finish = finish;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( finish == null ) ? 0 : finish.hashCode() );
result = prime * result + ( ( start == null ) ? 0 : start.hashCode() );
return result;
}
@Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
RangePair other = ( RangePair ) obj;
if ( finish == null ) {
if ( other.finish != null ) {
return false;
}
}
else if ( !finish.equals( other.finish ) ) {
return false;
}
if ( start == null ) {
if ( other.start != null ) {
return false;
}
}
else if ( !start.equals( other.start ) ) {
return false;
}
return true;
}
}
public static class QuerySlice {
String propertyName;
FilterOperator operator;
Object value;
RangeValue start;
RangeValue finish;
ByteBuffer cursor;
boolean reversed;
QuerySlice( String propertyName, FilterOperator operator, Object value, RangeValue start, RangeValue finish,
ByteBuffer cursor, boolean reversed ) {
this.propertyName = propertyName;
this.operator = operator;
this.value = value;
this.start = start;
this.finish = finish;
this.cursor = cursor;
this.reversed = reversed;
}
public String getPropertyName() {
return propertyName;
}
public void setPropertyName( String propertyName ) {
this.propertyName = propertyName;
}
public RangeValue getStart() {
return start;
}
public void setStart( RangeValue start ) {
this.start = start;
}
public RangeValue getFinish() {
return finish;
}
public void setFinish( RangeValue finish ) {
this.finish = finish;
}
public Object getValue() {
return value;
}
public void setValue( Object value ) {
this.value = value;
}
public ByteBuffer getCursor() {
return cursor;
}
public void setCursor( ByteBuffer cursor ) {
this.cursor = cursor;
}
public boolean isReversed() {
return reversed;
}
public void setReversed( boolean reversed ) {
this.reversed = reversed;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( finish == null ) ? 0 : finish.hashCode() );
result = prime * result + ( ( propertyName == null ) ? 0 : propertyName.hashCode() );
result = prime * result + ( ( start == null ) ? 0 : start.hashCode() );
//NOTE. We have explicitly left out direction. According to IndexTest:testCollectionOrdering,
// a cursor can be used and change direction
//of the ordering.
return result;
}
@Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
QuerySlice other = ( QuerySlice ) obj;
if ( finish == null ) {
if ( other.finish != null ) {
return false;
}
}
else if ( !finish.equals( other.finish ) ) {
return false;
}
if ( propertyName == null ) {
if ( other.propertyName != null ) {
return false;
}
}
else if ( !propertyName.equals( other.propertyName ) ) {
return false;
}
if ( start == null ) {
if ( other.start != null ) {
return false;
}
}
else if ( !start.equals( other.start ) ) {
return false;
}
return true;
}
}
}