You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2014/01/28 23:21:58 UTC
[48/96] [abbrv] [partial] Change package namespace to
org.apache.usergrid
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/mq/Message.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/mq/Message.java b/stack/core/src/main/java/org/apache/usergrid/mq/Message.java
new file mode 100644
index 0000000..7676225
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/mq/Message.java
@@ -0,0 +1,512 @@
+/*******************************************************************************
+ * Copyright 2012 Apigee Corporation
+ *
+ * Licensed 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.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.UUID;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.usergrid.utils.UUIDUtils;
+import org.codehaus.jackson.annotate.JsonAnyGetter;
+import org.codehaus.jackson.annotate.JsonAnySetter;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import com.fasterxml.uuid.UUIDComparator;
+
+import static org.apache.commons.collections.IteratorUtils.asEnumeration;
+import static org.apache.commons.collections.MapUtils.getBooleanValue;
+import static org.apache.commons.collections.MapUtils.getByteValue;
+import static org.apache.commons.collections.MapUtils.getDoubleValue;
+import static org.apache.commons.collections.MapUtils.getFloatValue;
+import static org.apache.commons.collections.MapUtils.getIntValue;
+import static org.apache.commons.collections.MapUtils.getLongValue;
+import static org.apache.commons.collections.MapUtils.getShortValue;
+import static org.apache.commons.collections.MapUtils.getString;
+import static org.apache.usergrid.utils.ClassUtils.cast;
+import static org.apache.usergrid.utils.ConversionUtils.bytes;
+import static org.apache.usergrid.utils.ConversionUtils.coerceMap;
+import static org.apache.usergrid.utils.ConversionUtils.getInt;
+import static org.apache.usergrid.utils.ConversionUtils.uuid;
+import static org.apache.usergrid.utils.MapUtils.hashMap;
+import static org.apache.usergrid.utils.UUIDUtils.getTimestampInMillis;
+import static org.apache.usergrid.utils.UUIDUtils.isTimeBased;
+import static org.apache.usergrid.utils.UUIDUtils.newTimeUUID;
+
+
+@XmlRootElement
+public class Message {
+
+ public static final String MESSAGE_CORRELATION_ID = "correlation_id";
+ public static final String MESSAGE_DESTINATION = "destination";
+ public static final String MESSAGE_ID = "uuid";
+ public static final String MESSAGE_REPLY_TO = "reply_to";
+ public static final String MESSAGE_TIMESTAMP = "timestamp";
+ public static final String MESSAGE_TYPE = "type";
+ public static final String MESSAGE_CATEGORY = "category";
+ public static final String MESSAGE_INDEXED = "indexed";
+ public static final String MESSAGE_PERSISTENT = "persistent";
+ public static final String MESSAGE_TRANSACTION = "transaction";
+
+ @SuppressWarnings("rawtypes")
+ public static final Map<String, Class> MESSAGE_PROPERTIES =
+ hashMap( MESSAGE_CORRELATION_ID, ( Class ) String.class ).map( MESSAGE_DESTINATION, String.class )
+ .map( MESSAGE_ID, UUID.class ).map( MESSAGE_REPLY_TO, String.class )
+ .map( MESSAGE_TIMESTAMP, Long.class ).map( MESSAGE_TYPE, String.class )
+ .map( MESSAGE_CATEGORY, String.class ).map( MESSAGE_INDEXED, Boolean.class )
+ .map( MESSAGE_PERSISTENT, Boolean.class ).map( MESSAGE_TRANSACTION, UUID.class );
+
+
+ public static int compare( Message m1, Message m2 ) {
+ if ( ( m1 == null ) && ( m2 == null ) ) {
+ return 0;
+ }
+ else if ( m1 == null ) {
+ return -1;
+ }
+ else if ( m2 == null ) {
+ return 1;
+ }
+ return UUIDComparator.staticCompare( m1.getUuid(), m2.getUuid() );
+ }
+
+
+ public static List<Message> fromList( List<Map<String, Object>> l ) {
+ List<Message> messages = new ArrayList<Message>( l.size() );
+ for ( Map<String, Object> properties : l ) {
+ messages.add( new Message( properties ) );
+ }
+ return messages;
+ }
+
+
+ public static List<Message> sort( List<Message> messages ) {
+ Collections.sort( messages, new Comparator<Message>() {
+ @Override
+ public int compare( Message m1, Message m2 ) {
+ return Message.compare( m1, m2 );
+ }
+ } );
+ return messages;
+ }
+
+
+ public static List<Message> sortReversed( List<Message> messages ) {
+ Collections.sort( messages, new Comparator<Message>() {
+ @Override
+ public int compare( Message m1, Message m2 ) {
+ return Message.compare( m2, m1 );
+ }
+ } );
+ return messages;
+ }
+
+
+ protected Map<String, Object> properties = new TreeMap<String, Object>( String.CASE_INSENSITIVE_ORDER );
+
+
+ public Message() {
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public Message( Map<String, Object> properties ) {
+ this.properties.putAll( coerceMap( ( Map<String, Class<?>> ) cast( MESSAGE_PROPERTIES ), properties ) );
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public void addCounter( String name, int value ) {
+ Map<String, Integer> counters = null;
+ if ( properties.get( "counters" ) instanceof Map ) {
+ counters = ( Map<String, Integer> ) properties.get( "counters" );
+ }
+ else {
+ counters = new HashMap<String, Integer>();
+ properties.put( "counters", counters );
+ }
+ counters.put( name, value );
+ }
+
+
+ public void clearBody() {
+ properties.clear();
+ }
+
+
+ public void clearProperties() {
+ properties.clear();
+ }
+
+
+ public boolean getBooleanProperty( String name ) {
+ return getBooleanValue( properties, name );
+ }
+
+
+ public byte getByteProperty( String name ) {
+ return getByteValue( properties, name );
+ }
+
+
+ @JsonIgnore
+ public String getCategory() {
+ return getString( properties, MESSAGE_CATEGORY );
+ }
+
+
+ @JsonIgnore
+ public String getCorrelationID() {
+ return getString( properties, MESSAGE_CORRELATION_ID );
+ }
+
+
+ @JsonIgnore
+ public byte[] getCorrelationIDAsBytes() {
+ return bytes( properties.get( MESSAGE_CORRELATION_ID ) );
+ }
+
+
+ @JsonIgnore
+ public Map<String, Integer> getCounters() {
+ Map<String, Integer> counters = new HashMap<String, Integer>();
+ if ( properties.get( "counters" ) instanceof Map ) {
+ @SuppressWarnings("unchecked") Map<String, Object> c = ( Map<String, Object> ) properties.get( "counters" );
+ for ( Entry<String, Object> e : c.entrySet() ) {
+ counters.put( e.getKey(), getInt( e.getValue() ) );
+ }
+ }
+ return counters;
+ }
+
+
+ @JsonIgnore
+ public int getDeliveryMode() {
+ return 2;
+ }
+
+
+ @JsonIgnore
+ public Queue getDestination() {
+ return Queue.getDestination( getString( properties, MESSAGE_DESTINATION ) );
+ }
+
+
+ public double getDoubleProperty( String name ) {
+ return getDoubleValue( properties, name );
+ }
+
+
+ @JsonIgnore
+ public long getExpiration() {
+ return 0;
+ }
+
+
+ public float getFloatProperty( String name ) {
+ return getFloatValue( properties, name );
+ }
+
+
+ public int getIntProperty( String name ) {
+ return getIntValue( properties, name );
+ }
+
+
+ public long getLongProperty( String name ) {
+ return getLongValue( properties, name );
+ }
+
+
+ @JsonIgnore
+ public String getMessageID() {
+ return getUuid().toString();
+ }
+
+
+ public Object getObjectProperty( String name ) {
+ return properties.get( name );
+ }
+
+
+ @JsonIgnore
+ public int getPriority() {
+ return 0;
+ }
+
+
+ @JsonAnyGetter
+ public Map<String, Object> getProperties() {
+ sync();
+ return properties;
+ }
+
+
+ @JsonIgnore
+ @SuppressWarnings("unchecked")
+ public Enumeration<String> getPropertyNames() {
+ return asEnumeration( properties.keySet().iterator() );
+ }
+
+
+ @JsonIgnore
+ public boolean getRedelivered() {
+ return false;
+ }
+
+
+ @JsonIgnore
+ public Queue getReplyTo() {
+ return Queue.getDestination( getString( properties, MESSAGE_REPLY_TO ) );
+ }
+
+
+ public short getShortProperty( String name ) {
+ return getShortValue( properties, name );
+ }
+
+
+ public String getStringProperty( String name ) {
+ return getString( properties, name );
+ }
+
+
+ @JsonIgnore
+ public synchronized long getTimestamp() {
+ if ( properties.containsKey( MESSAGE_TIMESTAMP ) ) {
+ long ts = getLongValue( properties, MESSAGE_TIMESTAMP );
+ if ( ts != 0 ) {
+ return ts;
+ }
+ }
+ long timestamp = getTimestampInMillis( getUuid() );
+ properties.put( MESSAGE_TIMESTAMP, timestamp );
+ return timestamp;
+ }
+
+
+ @JsonIgnore
+ public String getType() {
+ return getString( properties, MESSAGE_TYPE );
+ }
+
+
+ @JsonIgnore
+ public synchronized UUID getUuid() {
+ UUID uuid = uuid( properties.get( MESSAGE_ID ), null );
+ if ( uuid == null ) {
+ if ( properties.containsKey( MESSAGE_TIMESTAMP ) ) {
+ long ts = getLongValue( properties, MESSAGE_TIMESTAMP );
+ uuid = newTimeUUID( ts );
+ }
+ else {
+ uuid = newTimeUUID();
+ }
+
+ properties.put( MESSAGE_ID, uuid );
+ properties.put( MESSAGE_TIMESTAMP, getTimestampInMillis( uuid ) );
+ }
+ return uuid;
+ }
+
+
+ @JsonIgnore
+ public boolean isIndexed() {
+ return getBooleanValue( properties, MESSAGE_INDEXED );
+ }
+
+
+ @JsonIgnore
+ public boolean isPersistent() {
+ return getBooleanValue( properties, MESSAGE_PERSISTENT );
+ }
+
+
+ public boolean propertyExists( String name ) {
+ return properties.containsKey( name );
+ }
+
+
+ public void setBooleanProperty( String name, boolean value ) {
+ properties.put( name, value );
+ }
+
+
+ public void setByteProperty( String name, byte value ) {
+ properties.put( name, value );
+ }
+
+
+ public void setCategory( String category ) {
+ if ( category != null ) {
+ properties.put( MESSAGE_CATEGORY, category.toLowerCase() );
+ }
+ }
+
+
+ public void setCorrelationID( String correlationId ) {
+ properties.put( MESSAGE_CORRELATION_ID, correlationId );
+ }
+
+
+ public void setCorrelationIDAsBytes( byte[] correlationId ) {
+ properties.put( MESSAGE_CORRELATION_ID, correlationId );
+ }
+
+
+ public void setCounters( Map<String, Integer> counters ) {
+ if ( counters == null ) {
+ counters = new HashMap<String, Integer>();
+ }
+ properties.put( "counters", counters );
+ }
+
+
+ public void setDeliveryMode( int arg0 ) {
+ }
+
+
+ public void setDestination( Queue destination ) {
+ properties.put( MESSAGE_CORRELATION_ID, destination.toString() );
+ }
+
+
+ public void setDoubleProperty( String name, double value ) {
+ properties.put( name, value );
+ }
+
+
+ public void setExpiration( long expiration ) {
+ }
+
+
+ public void setFloatProperty( String name, float value ) {
+ properties.put( name, value );
+ }
+
+
+ public void setIndexed( boolean indexed ) {
+ properties.put( MESSAGE_INDEXED, indexed );
+ }
+
+
+ public void setIntProperty( String name, int value ) {
+ properties.put( name, value );
+ }
+
+
+ public void setLongProperty( String name, long value ) {
+ properties.put( name, value );
+ }
+
+
+ public void setMessageID( String id ) {
+ if ( UUIDUtils.isUUID( id ) ) {
+ properties.put( MESSAGE_ID, UUIDUtils.tryGetUUID( id ) );
+ }
+ else {
+ throw new RuntimeException( "Not a UUID" );
+ }
+ }
+
+
+ public void setObjectProperty( String name, Object value ) {
+ properties.put( name, value );
+ }
+
+
+ public void setPersistent( boolean persistent ) {
+ properties.put( MESSAGE_PERSISTENT, persistent );
+ }
+
+
+ public void setPriority( int priority ) {
+ }
+
+
+ @JsonAnySetter
+ public void setProperty( String key, Object value ) {
+ properties.put( key, value );
+ }
+
+
+ public void setRedelivered( boolean redelivered ) {
+ }
+
+
+ public void setReplyTo( Queue destination ) {
+ properties.put( MESSAGE_REPLY_TO, destination.toString() );
+ }
+
+
+ public void setShortProperty( String name, short value ) {
+ properties.put( name, value );
+ }
+
+
+ public void setStringProperty( String name, String value ) {
+ properties.put( name, value );
+ }
+
+
+ public void setTimestamp( long timestamp ) {
+ properties.put( MESSAGE_TIMESTAMP, timestamp );
+ }
+
+
+ public void setType( String type ) {
+ properties.put( MESSAGE_TYPE, type );
+ }
+
+
+ public void setUuid( UUID uuid ) {
+ if ( isTimeBased( uuid ) ) {
+ properties.put( MESSAGE_ID, uuid );
+ properties.put( MESSAGE_TIMESTAMP, getTimestampInMillis( uuid ) );
+ }
+ else {
+ throw new IllegalArgumentException( "Not a time-based UUID" );
+ }
+ }
+
+
+ public void setTransaction( UUID transaction ) {
+ properties.put( MESSAGE_TRANSACTION, transaction );
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public UUID getTransaction() {
+ return ( UUID ) properties.get( MESSAGE_TRANSACTION );
+ }
+
+
+ public void sync() {
+ getUuid();
+ getTimestamp();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/mq/Query.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/mq/Query.java b/stack/core/src/main/java/org/apache/usergrid/mq/Query.java
new file mode 100644
index 0000000..40c8a8f
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/mq/Query.java
@@ -0,0 +1,1856 @@
+/*******************************************************************************
+ * Copyright 2012 Apigee Corporation
+ *
+ * Licensed 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.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.commons.lang.StringUtils;
+import org.apache.usergrid.persistence.CounterResolution;
+import org.apache.usergrid.persistence.Entity;
+import org.apache.usergrid.persistence.Identifier;
+import org.apache.usergrid.persistence.Results;
+import org.apache.usergrid.persistence.Results.Level;
+import org.apache.usergrid.utils.JsonUtils;
+
+import static org.apache.commons.codec.binary.Base64.decodeBase64;
+import static org.apache.commons.lang.StringUtils.isBlank;
+import static org.apache.commons.lang.StringUtils.split;
+import static org.apache.usergrid.persistence.Schema.PROPERTY_TYPE;
+import static org.apache.usergrid.persistence.Schema.PROPERTY_UUID;
+import static org.apache.usergrid.utils.ClassUtils.cast;
+import static org.apache.usergrid.utils.ConversionUtils.uuid;
+import static org.apache.usergrid.utils.ListUtils.first;
+import static org.apache.usergrid.utils.ListUtils.firstBoolean;
+import static org.apache.usergrid.utils.ListUtils.firstInteger;
+import static org.apache.usergrid.utils.ListUtils.firstLong;
+import static org.apache.usergrid.utils.ListUtils.firstUuid;
+import static org.apache.usergrid.utils.ListUtils.isEmpty;
+import static org.apache.usergrid.utils.MapUtils.toMapList;
+
+
+public class Query {
+
+ private static final Logger logger = LoggerFactory.getLogger( Query.class );
+
+ public static final int DEFAULT_LIMIT = 10;
+
+ protected String type;
+ protected List<SortPredicate> sortPredicates = new ArrayList<SortPredicate>();
+ protected List<FilterPredicate> filterPredicates = new ArrayList<FilterPredicate>();
+ protected UUID startResult;
+ protected String cursor;
+ protected int limit = 0;
+ protected boolean limitSet = false;
+
+ protected Map<String, String> selectSubjects = new LinkedHashMap<String, String>();
+ protected boolean mergeSelectResults = false;
+ protected Level level = Level.ALL_PROPERTIES;
+ protected String connection;
+ protected List<String> permissions;
+ protected boolean reversed;
+ protected boolean reversedSet = false;
+ protected Long startTime;
+ protected Long finishTime;
+ protected boolean pad;
+ protected CounterResolution resolution = CounterResolution.ALL;
+ protected List<Identifier> users;
+ protected List<Identifier> groups;
+ protected List<Identifier> identifiers;
+ protected List<String> categories;
+ protected List<CounterFilterPredicate> counterFilters;
+
+
+ public Query() {
+ }
+
+
+ public Query( String type ) {
+ this.type = type;
+ }
+
+
+ public Query( Query q ) {
+ if ( q != null ) {
+ type = q.type;
+ sortPredicates = q.sortPredicates != null ? new ArrayList<SortPredicate>( q.sortPredicates ) : null;
+ filterPredicates = q.filterPredicates != null ? new ArrayList<FilterPredicate>( q.filterPredicates ) : null;
+ startResult = q.startResult;
+ cursor = q.cursor;
+ limit = q.limit;
+ limitSet = q.limitSet;
+ selectSubjects = q.selectSubjects != null ? new LinkedHashMap<String, String>( q.selectSubjects ) : null;
+ mergeSelectResults = q.mergeSelectResults;
+ level = q.level;
+ connection = q.connection;
+ permissions = q.permissions != null ? new ArrayList<String>( q.permissions ) : null;
+ reversed = q.reversed;
+ reversedSet = q.reversedSet;
+ startTime = q.startTime;
+ finishTime = q.finishTime;
+ resolution = q.resolution;
+ pad = q.pad;
+ users = q.users != null ? new ArrayList<Identifier>( q.users ) : null;
+ groups = q.groups != null ? new ArrayList<Identifier>( q.groups ) : null;
+ identifiers = q.identifiers != null ? new ArrayList<Identifier>( q.identifiers ) : null;
+ categories = q.categories != null ? new ArrayList<String>( q.categories ) : null;
+ counterFilters =
+ q.counterFilters != null ? new ArrayList<CounterFilterPredicate>( q.counterFilters ) : null;
+ }
+ }
+
+
+ public static Query fromQL( String ql ) {
+ if ( ql == null ) {
+ return null;
+ }
+ ql = ql.trim();
+
+ String qlt = ql.toLowerCase();
+ if ( !qlt.startsWith( "select" ) && !qlt.startsWith( "insert" ) && !qlt.startsWith( "update" ) && !qlt
+ .startsWith( "delete" ) ) {
+ if ( qlt.startsWith( "order by" ) ) {
+ ql = "select * " + ql;
+ }
+ else {
+ ql = "select * where " + ql;
+ }
+ }
+
+ try {
+ ANTLRStringStream in = new ANTLRStringStream( ql.trim() );
+ QueryFilterLexer lexer = new QueryFilterLexer( in );
+ CommonTokenStream tokens = new CommonTokenStream( lexer );
+ QueryFilterParser parser = new QueryFilterParser( tokens );
+ Query q = parser.ql();
+ return q;
+ }
+ catch ( Exception e ) {
+ logger.error( "Unable to parse \"" + ql + "\"", e );
+ }
+ return null;
+ }
+
+
+ public static Query newQueryIfNull( Query query ) {
+ if ( query == null ) {
+ query = new Query();
+ }
+ return query;
+ }
+
+
+ public static Query fromJsonString( String json ) {
+ Object o = JsonUtils.parse( json );
+ if ( o instanceof Map ) {
+ @SuppressWarnings({ "unchecked", "rawtypes" }) Map<String, List<String>> params =
+ cast( toMapList( ( Map ) o ) );
+ return fromQueryParams( params );
+ }
+ return null;
+ }
+
+
+ public static Query fromQueryParams( Map<String, List<String>> params ) {
+ String type = null;
+ Query q = null;
+ String ql = null;
+ String connection = null;
+ UUID start = null;
+ String cursor = null;
+ Integer limit = null;
+ List<String> permissions = null;
+ Boolean reversed = null;
+ Long startTime = null;
+ Long finishTime = null;
+ Boolean pad = null;
+ CounterResolution resolution = null;
+ List<Identifier> users = null;
+ List<Identifier> groups = null;
+ List<Identifier> identifiers = null;
+ List<String> categories = null;
+ List<CounterFilterPredicate> counterFilters = null;
+
+ List<String> l = null;
+
+ ql = first( params.get( "ql" ) );
+ type = first( params.get( "type" ) );
+ reversed = firstBoolean( params.get( "reversed" ) );
+ connection = first( params.get( "connection" ) );
+ start = firstUuid( params.get( "start" ) );
+ cursor = first( params.get( "cursor" ) );
+ limit = firstInteger( params.get( "limit" ) );
+ permissions = params.get( "permission" );
+ startTime = firstLong( params.get( "start_time" ) );
+ finishTime = firstLong( params.get( "end_time" ) );
+
+ l = params.get( "resolution" );
+ if ( !isEmpty( l ) ) {
+ resolution = CounterResolution.fromString( l.get( 0 ) );
+ }
+
+ users = Identifier.fromList( params.get( "user" ) );
+ groups = Identifier.fromList( params.get( "group" ) );
+
+ categories = params.get( "category" );
+
+ l = params.get( "counter" );
+ if ( !isEmpty( l ) ) {
+ counterFilters = CounterFilterPredicate.fromList( l );
+ }
+
+ pad = firstBoolean( params.get( "pad" ) );
+
+ for ( Entry<String, List<String>> param : params.entrySet() ) {
+ if ( ( param.getValue() == null ) || ( param.getValue().size() == 0 ) ) {
+ Identifier identifier = Identifier.from( param.getKey() );
+ if ( identifier != null ) {
+ if ( identifiers == null ) {
+ identifiers = new ArrayList<Identifier>();
+ }
+ identifiers.add( identifier );
+ }
+ }
+ }
+
+ if ( ql != null ) {
+ q = Query.fromQL( ql );
+ }
+
+ l = params.get( "filter" );
+ if ( !isEmpty( l ) ) {
+ q = newQueryIfNull( q );
+ for ( String s : l ) {
+ q.addFilter( s );
+ }
+ }
+
+ l = params.get( "sort" );
+ if ( !isEmpty( l ) ) {
+ q = newQueryIfNull( q );
+ for ( String s : l ) {
+ q.addSort( s );
+ }
+ }
+
+ if ( type != null ) {
+ q = newQueryIfNull( q );
+ q.setEntityType( type );
+ }
+
+ if ( connection != null ) {
+ q = newQueryIfNull( q );
+ q.setConnectionType( connection );
+ }
+
+ if ( permissions != null ) {
+ q = newQueryIfNull( q );
+ q.setPermissions( permissions );
+ }
+
+ if ( start != null ) {
+ q = newQueryIfNull( q );
+ q.setStartResult( start );
+ }
+
+ if ( cursor != null ) {
+ q = newQueryIfNull( q );
+ q.setCursor( cursor );
+ }
+
+ if ( limit != null ) {
+ q = newQueryIfNull( q );
+ q.setLimit( limit );
+ }
+
+ if ( startTime != null ) {
+ q = newQueryIfNull( q );
+ q.setStartTime( startTime );
+ }
+
+ if ( finishTime != null ) {
+ q = newQueryIfNull( q );
+ q.setFinishTime( finishTime );
+ }
+
+ if ( resolution != null ) {
+ q = newQueryIfNull( q );
+ q.setResolution( resolution );
+ }
+
+ if ( categories != null ) {
+ q = newQueryIfNull( q );
+ q.setCategories( categories );
+ }
+
+ if ( counterFilters != null ) {
+ q = newQueryIfNull( q );
+ q.setCounterFilters( counterFilters );
+ }
+
+ if ( pad != null ) {
+ q = newQueryIfNull( q );
+ q.setPad( pad );
+ }
+
+ if ( users != null ) {
+ q = newQueryIfNull( q );
+ q.setUsers( users );
+ }
+
+ if ( groups != null ) {
+ q = newQueryIfNull( q );
+ q.setGroups( groups );
+ }
+
+ if ( identifiers != null ) {
+ q = newQueryIfNull( q );
+ q.setIdentifiers( identifiers );
+ }
+
+ if ( reversed != null ) {
+ q = newQueryIfNull( q );
+ q.setReversed( reversed );
+ }
+
+ return q;
+ }
+
+
+ public static Query searchForProperty( String propertyName, Object propertyValue ) {
+ Query q = new Query();
+ q.addEqualityFilter( propertyName, propertyValue );
+ return q;
+ }
+
+
+ public static Query findForProperty( String propertyName, Object propertyValue ) {
+ Query q = new Query();
+ q.addEqualityFilter( propertyName, propertyValue );
+ q.setLimit( 1 );
+ return q;
+ }
+
+
+ public static Query fromUUID( UUID uuid ) {
+ Query q = new Query();
+ q.addIdentifier( Identifier.fromUUID( uuid ) );
+ return q;
+ }
+
+
+ public static Query fromName( String name ) {
+ Query q = new Query();
+ q.addIdentifier( Identifier.fromName( name ) );
+ return q;
+ }
+
+
+ public static Query fromEmail( String email ) {
+ Query q = new Query();
+ q.addIdentifier( Identifier.fromEmail( email ) );
+ return q;
+ }
+
+
+ public static Query fromIdentifier( Object id ) {
+ Query q = new Query();
+ q.addIdentifier( Identifier.from( id ) );
+ return q;
+ }
+
+
+ public boolean isIdsOnly() {
+ if ( ( selectSubjects.size() == 1 ) && selectSubjects.containsKey( PROPERTY_UUID ) ) {
+ level = Level.IDS;
+ return true;
+ }
+ return false;
+ }
+
+
+ public void setIdsOnly( boolean idsOnly ) {
+ if ( idsOnly ) {
+ selectSubjects = new LinkedHashMap<String, String>();
+ selectSubjects.put( PROPERTY_UUID, PROPERTY_UUID );
+ level = Level.IDS;
+ }
+ else if ( isIdsOnly() ) {
+ selectSubjects = new LinkedHashMap<String, String>();
+ level = Level.ALL_PROPERTIES;
+ }
+ }
+
+
+ public Level getResultsLevel() {
+ isIdsOnly();
+ return level;
+ }
+
+
+ public void setResultsLevel( Level level ) {
+ setIdsOnly( level == Level.IDS );
+ this.level = level;
+ }
+
+
+ public Query withResultsLevel( Level level ) {
+ setIdsOnly( level == Level.IDS );
+ this.level = level;
+ return this;
+ }
+
+
+ public String getEntityType() {
+ return type;
+ }
+
+
+ public void setEntityType( String type ) {
+ this.type = type;
+ }
+
+
+ public Query withEntityType( String type ) {
+ this.type = type;
+ return this;
+ }
+
+
+ public String getConnectionType() {
+ return connection;
+ }
+
+
+ public void setConnectionType( String connection ) {
+ this.connection = connection;
+ }
+
+
+ public Query withConnectionType( String connection ) {
+ this.connection = connection;
+ return this;
+ }
+
+
+ public List<String> getPermissions() {
+ return permissions;
+ }
+
+
+ public void setPermissions( List<String> permissions ) {
+ this.permissions = permissions;
+ }
+
+
+ public Query withPermissions( List<String> permissions ) {
+ this.permissions = permissions;
+ return this;
+ }
+
+
+ public Query addSelect( String select ) {
+
+ return addSelect( select, null );
+ }
+
+
+ public Query addSelect( String select, String output ) {
+ // be paranoid with the null checks because
+ // the query parser sometimes flakes out
+ if ( select == null ) {
+ return this;
+ }
+ select = select.trim();
+
+ if ( select.equals( "*" ) ) {
+ return this;
+ }
+
+ if ( StringUtils.isNotEmpty( output ) ) {
+ mergeSelectResults = true;
+ }
+ else {
+ mergeSelectResults = false;
+ }
+
+ if ( output == null ) {
+ output = "";
+ }
+
+ selectSubjects.put( select, output );
+
+ return this;
+ }
+
+
+ public boolean hasSelectSubjects() {
+ return !selectSubjects.isEmpty();
+ }
+
+
+ public Set<String> getSelectSubjects() {
+ return selectSubjects.keySet();
+ }
+
+
+ public Map<String, String> getSelectAssignments() {
+ return selectSubjects;
+ }
+
+
+ public void setMergeSelectResults( boolean mergeSelectResults ) {
+ this.mergeSelectResults = mergeSelectResults;
+ }
+
+
+ public Query withMergeSelectResults( boolean mergeSelectResults ) {
+ this.mergeSelectResults = mergeSelectResults;
+ return this;
+ }
+
+
+ public boolean isMergeSelectResults() {
+ return mergeSelectResults;
+ }
+
+
+ public Query addSort( String propertyName ) {
+ if ( isBlank( propertyName ) ) {
+ return this;
+ }
+ propertyName = propertyName.trim();
+ if ( propertyName.indexOf( ',' ) >= 0 ) {
+ String[] propertyNames = split( propertyName, ',' );
+ for ( String s : propertyNames ) {
+ addSort( s );
+ }
+ return this;
+ }
+
+ SortDirection direction = SortDirection.ASCENDING;
+ if ( propertyName.indexOf( ' ' ) >= 0 ) {
+ String[] parts = split( propertyName, ' ' );
+ if ( parts.length > 1 ) {
+ propertyName = parts[0];
+ direction = SortDirection.find( parts[1] );
+ }
+ }
+ else if ( propertyName.startsWith( "-" ) ) {
+ propertyName = propertyName.substring( 1 );
+ direction = SortDirection.DESCENDING;
+ }
+ else if ( propertyName.startsWith( "+" ) ) {
+ propertyName = propertyName.substring( 1 );
+ direction = SortDirection.ASCENDING;
+ }
+
+ return addSort( propertyName, direction );
+ }
+
+
+ public Query addSort( String propertyName, SortDirection direction ) {
+ if ( isBlank( propertyName ) ) {
+ return this;
+ }
+ propertyName = propertyName.trim();
+ for ( SortPredicate s : sortPredicates ) {
+ if ( s.getPropertyName().equals( propertyName ) ) {
+ logger.error(
+ "Attempted to set sort order for " + s.getPropertyName() + " more than once, discardng..." );
+ return this;
+ }
+ }
+ sortPredicates.add( new SortPredicate( propertyName, direction ) );
+ return this;
+ }
+
+
+ public Query addSort( SortPredicate sort ) {
+ if ( sort == null ) {
+ return this;
+ }
+ for ( SortPredicate s : sortPredicates ) {
+ if ( s.getPropertyName().equals( sort.getPropertyName() ) ) {
+ logger.error(
+ "Attempted to set sort order for " + s.getPropertyName() + " more than once, discardng..." );
+ return this;
+ }
+ }
+ sortPredicates.add( sort );
+ return this;
+ }
+
+
+ public List<SortPredicate> getSortPredicates() {
+ return sortPredicates;
+ }
+
+
+ public boolean hasSortPredicates() {
+ return !sortPredicates.isEmpty();
+ }
+
+
+ public Query addEqualityFilter( String propertyName, Object value ) {
+ return addFilter( propertyName, FilterOperator.EQUAL, value );
+ }
+
+
+ public Query addFilter( String propertyName, FilterOperator operator, Object value ) {
+ if ( ( propertyName == null ) || ( operator == null ) || ( value == null ) ) {
+ return this;
+ }
+ if ( PROPERTY_TYPE.equalsIgnoreCase( propertyName ) && ( value != null ) ) {
+ if ( operator == FilterOperator.EQUAL ) {
+ type = value.toString();
+ }
+ }
+ else if ( "connection".equalsIgnoreCase( propertyName ) && ( value != null ) ) {
+ if ( operator == FilterOperator.EQUAL ) {
+ connection = value.toString();
+ }
+ }
+ else {
+ for ( FilterPredicate f : filterPredicates ) {
+ if ( f.getPropertyName().equals( propertyName ) && f.getValue().equals( value ) && "*"
+ .equals( value ) ) {
+ logger.error( "Attempted to set wildcard wilder for " + f.getPropertyName()
+ + " more than once, discardng..." );
+ return this;
+ }
+ }
+ filterPredicates.add( FilterPredicate.normalize( new FilterPredicate( propertyName, operator, value ) ) );
+ }
+ return this;
+ }
+
+
+ public Query addFilter( String filterStr ) {
+ if ( filterStr == null ) {
+ return this;
+ }
+ FilterPredicate filter = FilterPredicate.valueOf( filterStr );
+ if ( ( filter != null ) && ( filter.propertyName != null ) && ( filter.operator != null ) && ( filter.value
+ != null ) ) {
+
+ if ( PROPERTY_TYPE.equalsIgnoreCase( filter.propertyName ) ) {
+ if ( filter.operator == FilterOperator.EQUAL ) {
+ type = filter.value.toString();
+ }
+ }
+ else if ( "connection".equalsIgnoreCase( filter.propertyName ) ) {
+ if ( filter.operator == FilterOperator.EQUAL ) {
+ connection = filter.value.toString();
+ }
+ }
+ else {
+ for ( FilterPredicate f : filterPredicates ) {
+ if ( f.getPropertyName().equals( filter.getPropertyName() ) && f.getValue()
+ .equals( filter.getValue() ) && "*"
+ .equals( filter.getValue() ) ) {
+ logger.error( "Attempted to set wildcard wilder for " + f.getPropertyName()
+ + " more than once, discardng..." );
+ return this;
+ }
+ }
+ filterPredicates.add( filter );
+ }
+ }
+ else {
+ logger.error( "Unable to add filter to query: " + filterStr );
+ }
+ return this;
+ }
+
+
+ public Query addFilter( FilterPredicate filter ) {
+ filter = FilterPredicate.normalize( filter );
+ if ( ( filter != null ) && ( filter.propertyName != null ) && ( filter.operator != null ) && ( filter.value
+ != null ) ) {
+
+ if ( PROPERTY_TYPE.equalsIgnoreCase( filter.propertyName ) ) {
+ if ( filter.operator == FilterOperator.EQUAL ) {
+ type = filter.value.toString();
+ }
+ }
+ else if ( "connection".equalsIgnoreCase( filter.propertyName ) ) {
+ if ( filter.operator == FilterOperator.EQUAL ) {
+ connection = filter.value.toString();
+ }
+ }
+ else {
+ filterPredicates.add( filter );
+ }
+ }
+ return this;
+ }
+
+
+ public List<FilterPredicate> getFilterPredicates() {
+ return filterPredicates;
+ }
+
+
+ public boolean hasFilterPredicates() {
+ return !filterPredicates.isEmpty();
+ }
+
+
+ public Map<String, Object> getEqualityFilters() {
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+
+ for ( FilterPredicate f : filterPredicates ) {
+ if ( f.operator == FilterOperator.EQUAL ) {
+ Object val = f.getStartValue();
+ if ( val != null ) {
+ map.put( f.getPropertyName(), val );
+ }
+ }
+ }
+ return map.size() > 0 ? map : null;
+ }
+
+
+ public boolean hasFiltersForProperty( String name ) {
+ return hasFiltersForProperty( FilterOperator.EQUAL, name );
+ }
+
+
+ public boolean hasFiltersForProperty( FilterOperator operator, String name ) {
+ return getFilterForProperty( operator, name ) != null;
+ }
+
+
+ public FilterPredicate getFilterForProperty( FilterOperator operator, String name ) {
+ if ( name == null ) {
+ return null;
+ }
+ ListIterator<FilterPredicate> iterator = filterPredicates.listIterator();
+ while ( iterator.hasNext() ) {
+ FilterPredicate f = iterator.next();
+ if ( f.propertyName.equalsIgnoreCase( name ) ) {
+ if ( operator != null ) {
+ if ( operator == f.operator ) {
+ return f;
+ }
+ }
+ else {
+ return f;
+ }
+ }
+ }
+ return null;
+ }
+
+
+ public void removeFiltersForProperty( String name ) {
+ if ( name == null ) {
+ return;
+ }
+ ListIterator<FilterPredicate> iterator = filterPredicates.listIterator();
+ while ( iterator.hasNext() ) {
+ FilterPredicate f = iterator.next();
+ if ( f.propertyName.equalsIgnoreCase( name ) ) {
+ iterator.remove();
+ }
+ }
+ }
+
+
+ public void setStartResult( UUID startResult ) {
+ this.startResult = startResult;
+ }
+
+
+ public Query withStartResult( UUID startResult ) {
+ this.startResult = startResult;
+ return this;
+ }
+
+
+ public UUID getStartResult() {
+ if ( ( startResult == null ) && ( cursor != null ) ) {
+ byte[] cursorBytes = decodeBase64( cursor );
+ if ( ( cursorBytes != null ) && ( cursorBytes.length == 16 ) ) {
+ startResult = uuid( cursorBytes );
+ }
+ }
+ return startResult;
+ }
+
+
+ public String getCursor() {
+ return cursor;
+ }
+
+
+ public void setCursor( String cursor ) {
+ if ( cursor != null ) {
+ if ( cursor.length() == 22 ) {
+ byte[] cursorBytes = decodeBase64( cursor );
+ if ( ( cursorBytes != null ) && ( cursorBytes.length == 16 ) ) {
+ startResult = uuid( cursorBytes );
+ cursor = null;
+ }
+ }
+ }
+ this.cursor = cursor;
+ }
+
+
+ public Query withCursor( String cursor ) {
+ setCursor( cursor );
+ return this;
+ }
+
+
+ public int getLimit() {
+ return getLimit( DEFAULT_LIMIT );
+ }
+
+
+ public int getLimit( int defaultLimit ) {
+ if ( limit <= 0 ) {
+ if ( defaultLimit > 0 ) {
+ return defaultLimit;
+ }
+ else {
+ return DEFAULT_LIMIT;
+ }
+ }
+ return limit;
+ }
+
+
+ public void setLimit( int limit ) {
+ limitSet = true;
+ this.limit = limit;
+ }
+
+
+ public Query withLimit( int limit ) {
+ limitSet = true;
+ this.limit = limit;
+ return this;
+ }
+
+
+ public boolean isLimitSet() {
+ return limitSet;
+ }
+
+
+ public boolean isReversed() {
+ return reversed;
+ }
+
+
+ public void setReversed( boolean reversed ) {
+ reversedSet = true;
+ this.reversed = reversed;
+ }
+
+
+ public boolean isReversedSet() {
+ return reversedSet;
+ }
+
+
+ public Long getStartTime() {
+ return startTime;
+ }
+
+
+ public void setStartTime( Long startTime ) {
+ this.startTime = startTime;
+ }
+
+
+ public Long getFinishTime() {
+ return finishTime;
+ }
+
+
+ public void setFinishTime( Long finishTime ) {
+ this.finishTime = finishTime;
+ }
+
+
+ public boolean isPad() {
+ return pad;
+ }
+
+
+ public void setPad( boolean pad ) {
+ this.pad = pad;
+ }
+
+
+ public void setResolution( CounterResolution resolution ) {
+ this.resolution = resolution;
+ }
+
+
+ public CounterResolution getResolution() {
+ return resolution;
+ }
+
+
+ public List<Identifier> getUsers() {
+ return users;
+ }
+
+
+ public void addUser( Identifier user ) {
+ if ( users == null ) {
+ users = new ArrayList<Identifier>();
+ }
+ users.add( user );
+ }
+
+
+ public void setUsers( List<Identifier> users ) {
+ this.users = users;
+ }
+
+
+ public List<Identifier> getGroups() {
+ return groups;
+ }
+
+
+ public void addGroup( Identifier group ) {
+ if ( groups == null ) {
+ groups = new ArrayList<Identifier>();
+ }
+ groups.add( group );
+ }
+
+
+ public void setGroups( List<Identifier> groups ) {
+ this.groups = groups;
+ }
+
+
+ public List<Identifier> getIdentifiers() {
+ return identifiers;
+ }
+
+
+ public void addIdentifier( Identifier identifier ) {
+ if ( identifiers == null ) {
+ identifiers = new ArrayList<Identifier>();
+ }
+ identifiers.add( identifier );
+ }
+
+
+ public void setIdentifiers( List<Identifier> identifiers ) {
+ this.identifiers = identifiers;
+ }
+
+
+ public boolean containsUuidIdentifersOnly() {
+ if ( hasFilterPredicates() ) {
+ return false;
+ }
+ if ( ( identifiers == null ) || identifiers.isEmpty() ) {
+ return false;
+ }
+ for ( Identifier identifier : identifiers ) {
+ if ( !identifier.isUUID() ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ public boolean containsSingleUuidIdentifier() {
+ return containsUuidIdentifersOnly() && ( identifiers.size() == 1 );
+ }
+
+
+ public List<UUID> getUuidIdentifiers() {
+ if ( ( identifiers == null ) || identifiers.isEmpty() ) {
+ return null;
+ }
+ List<UUID> ids = new ArrayList<UUID>();
+ for ( Identifier identifier : identifiers ) {
+ if ( identifier.isUUID() ) {
+ ids.add( identifier.getUUID() );
+ }
+ }
+ return ids;
+ }
+
+
+ public UUID getSingleUuidIdentifier() {
+ if ( !containsSingleUuidIdentifier() ) {
+ return null;
+ }
+ return ( identifiers.get( 0 ).getUUID() );
+ }
+
+
+ public boolean containsNameIdentifiersOnly() {
+ if ( hasFilterPredicates() ) {
+ return false;
+ }
+ if ( ( identifiers == null ) || identifiers.isEmpty() ) {
+ return false;
+ }
+ for ( Identifier identifier : identifiers ) {
+ if ( !identifier.isName() ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ public boolean containsSingleNameIdentifier() {
+ return containsNameIdentifiersOnly() && ( identifiers.size() == 1 );
+ }
+
+
+ public List<String> getNameIdentifiers() {
+ if ( ( identifiers == null ) || identifiers.isEmpty() ) {
+ return null;
+ }
+ List<String> names = new ArrayList<String>();
+ for ( Identifier identifier : identifiers ) {
+ if ( identifier.isName() ) {
+ names.add( identifier.getName() );
+ }
+ }
+ return names;
+ }
+
+
+ public String getSingleNameIdentifier() {
+ if ( !containsSingleNameIdentifier() ) {
+ return null;
+ }
+ return ( identifiers.get( 0 ).toString() );
+ }
+
+
+ public boolean containsEmailIdentifiersOnly() {
+ if ( hasFilterPredicates() ) {
+ return false;
+ }
+ if ( ( identifiers == null ) || identifiers.isEmpty() ) {
+ return false;
+ }
+ for ( Identifier identifier : identifiers ) {
+ if ( identifier.isEmail() ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ public boolean containsSingleEmailIdentifier() {
+ return containsEmailIdentifiersOnly() && ( identifiers.size() == 1 );
+ }
+
+
+ public List<String> getEmailIdentifiers() {
+ if ( ( identifiers == null ) || identifiers.isEmpty() ) {
+ return null;
+ }
+ List<String> emails = new ArrayList<String>();
+ for ( Identifier identifier : identifiers ) {
+ if ( identifier.isEmail() ) {
+ emails.add( identifier.getEmail() );
+ }
+ }
+ return emails;
+ }
+
+
+ public String getSingleEmailIdentifier() {
+ if ( !containsSingleEmailIdentifier() ) {
+ return null;
+ }
+ return ( identifiers.get( 0 ).toString() );
+ }
+
+
+ public boolean containsNameOrEmailIdentifiersOnly() {
+ if ( hasFilterPredicates() ) {
+ return false;
+ }
+ if ( ( identifiers == null ) || identifiers.isEmpty() ) {
+ return false;
+ }
+ for ( Identifier identifier : identifiers ) {
+ if ( !identifier.isEmail() && !identifier.isName() ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ public boolean containsSingleNameOrEmailIdentifier() {
+ return containsNameOrEmailIdentifiersOnly() && ( identifiers.size() == 1 );
+ }
+
+
+ public List<String> getNameAndEmailIdentifiers() {
+ if ( ( identifiers == null ) || identifiers.isEmpty() ) {
+ return null;
+ }
+ List<String> ids = new ArrayList<String>();
+ for ( Identifier identifier : identifiers ) {
+ if ( identifier.isEmail() ) {
+ ids.add( identifier.getEmail() );
+ }
+ else if ( identifier.isName() ) {
+ ids.add( identifier.getName() );
+ }
+ }
+ return ids;
+ }
+
+
+ public String getSingleNameOrEmailIdentifier() {
+ if ( !containsSingleNameOrEmailIdentifier() ) {
+ return null;
+ }
+ return ( identifiers.get( 0 ).toString() );
+ }
+
+
+ public List<String> getCategories() {
+ return categories;
+ }
+
+
+ public void addCategory( String category ) {
+ if ( categories == null ) {
+ categories = new ArrayList<String>();
+ }
+ categories.add( category );
+ }
+
+
+ public void setCategories( List<String> categories ) {
+ this.categories = categories;
+ }
+
+
+ public List<CounterFilterPredicate> getCounterFilters() {
+ return counterFilters;
+ }
+
+
+ public void addCounterFilter( String counter ) {
+ CounterFilterPredicate p = CounterFilterPredicate.fromString( counter );
+ if ( p == null ) {
+ return;
+ }
+ if ( counterFilters == null ) {
+ counterFilters = new ArrayList<CounterFilterPredicate>();
+ }
+ counterFilters.add( p );
+ }
+
+
+ public void setCounterFilters( List<CounterFilterPredicate> counterFilters ) {
+ this.counterFilters = counterFilters;
+ }
+
+
+ @Override
+ public String toString() {
+ if ( selectSubjects.isEmpty() && filterPredicates.isEmpty() ) {
+ return "";
+ }
+
+ StringBuilder s = new StringBuilder( "select " );
+ if ( type == null ) {
+ if ( selectSubjects.isEmpty() ) {
+ s.append( "*" );
+ }
+ else {
+ if ( mergeSelectResults ) {
+ s.append( "{ " );
+ boolean first = true;
+ for ( Map.Entry<String, String> select : selectSubjects.entrySet() ) {
+ if ( !first ) {
+ s.append( ", " );
+ }
+ s.append( select.getValue() + " : " + select.getKey() );
+ first = false;
+ }
+ s.append( " }" );
+ }
+ else {
+ boolean first = true;
+ for ( String select : selectSubjects.keySet() ) {
+ if ( !first ) {
+ s.append( ", " );
+ }
+ s.append( select );
+ first = false;
+ }
+ }
+ }
+ }
+ else {
+ s.append( type );
+ }
+ if ( !filterPredicates.isEmpty() ) {
+ s.append( " where " );
+ boolean first = true;
+ for ( FilterPredicate f : filterPredicates ) {
+ if ( !first ) {
+ s.append( " and " );
+ }
+ s.append( f.toString() );
+ first = false;
+ }
+ }
+ return s.toString();
+ }
+
+
+ public static enum FilterOperator {
+ LESS_THAN( "<", "lt" ), LESS_THAN_OR_EQUAL( "<=", "lte" ), GREATER_THAN( ">", "gt" ),
+ GREATER_THAN_OR_EQUAL( ">=", "gte" ), EQUAL( "=", "eq" ), NOT_EQUAL( "!=", "ne" ), IN( "in", null ),
+ CONTAINS( "contains", null ), WITHIN( "within", null );
+
+ private final String shortName;
+ private final String textName;
+
+
+ FilterOperator( String shortName, String textName ) {
+ this.shortName = shortName;
+ this.textName = textName;
+ }
+
+
+ static Map<String, FilterOperator> nameMap = new ConcurrentHashMap<String, FilterOperator>();
+
+
+ static {
+ for ( FilterOperator op : EnumSet.allOf( FilterOperator.class ) ) {
+ if ( op.shortName != null ) {
+ nameMap.put( op.shortName, op );
+ }
+ if ( op.textName != null ) {
+ nameMap.put( op.textName, op );
+ }
+ }
+ }
+
+
+ public static FilterOperator find( String s ) {
+ if ( s == null ) {
+ return null;
+ }
+ return nameMap.get( s );
+ }
+
+
+ @Override
+ public String toString() {
+ return shortName;
+ }
+ }
+
+
+ public static enum SortDirection {
+ ASCENDING, DESCENDING;
+
+
+ public static SortDirection find( String s ) {
+ if ( s == null ) {
+ return ASCENDING;
+ }
+ s = s.toLowerCase();
+ if ( s.startsWith( "asc" ) ) {
+ return ASCENDING;
+ }
+ if ( s.startsWith( "des" ) ) {
+ return DESCENDING;
+ }
+ if ( s.equals( "+" ) ) {
+ return ASCENDING;
+ }
+ if ( s.equals( "-" ) ) {
+ return DESCENDING;
+ }
+ return ASCENDING;
+ }
+ }
+
+
+ public static final class SortPredicate implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private final String propertyName;
+ private final Query.SortDirection direction;
+
+
+ public SortPredicate( String propertyName, Query.SortDirection direction ) {
+ if ( propertyName == null ) {
+ throw new NullPointerException( "Property name was null" );
+ }
+
+ if ( direction == null ) {
+ direction = SortDirection.ASCENDING;
+ }
+
+ this.propertyName = propertyName.trim();
+ this.direction = direction;
+ }
+
+
+ public SortPredicate( String propertyName, String direction ) {
+ this( propertyName, SortDirection.find( direction ) );
+ }
+
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+
+ public Query.SortDirection getDirection() {
+ return direction;
+ }
+
+
+ public FilterPredicate toFilter() {
+ return new FilterPredicate( propertyName, FilterOperator.EQUAL, "*" );
+ }
+
+
+ @Override
+ public boolean equals( Object o ) {
+ if ( this == o ) {
+ return true;
+ }
+ if ( ( o == null ) || ( super.getClass() != o.getClass() ) ) {
+ return false;
+ }
+
+ SortPredicate that = ( SortPredicate ) o;
+
+ if ( direction != that.direction ) {
+ return false;
+ }
+
+ return ( propertyName.equals( that.propertyName ) );
+ }
+
+
+ @Override
+ public int hashCode() {
+ int result = propertyName.hashCode();
+ result = ( 31 * result ) + direction.hashCode();
+ return result;
+ }
+
+
+ @Override
+ public String toString() {
+ return propertyName + ( ( direction == Query.SortDirection.DESCENDING ) ? " DESC" : "" );
+ }
+ }
+
+
+ public static final class FilterPredicate implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private final String propertyName;
+ private final Query.FilterOperator operator;
+ private final Object value;
+ private String cursor;
+
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public FilterPredicate( String propertyName, Query.FilterOperator operator, Object value ) {
+ if ( propertyName == null ) {
+ throw new NullPointerException( "Property name was null" );
+ }
+ if ( operator == null ) {
+ throw new NullPointerException( "Operator was null" );
+ }
+ if ( ( operator == Query.FilterOperator.IN ) || ( operator == Query.FilterOperator.WITHIN ) ) {
+ if ( ( !( value instanceof Collection ) ) && ( value instanceof Iterable ) ) {
+ List newValue = new ArrayList();
+ for ( Iterator i$ = ( ( Iterable ) value ).iterator(); i$.hasNext(); ) {
+ Object val = i$.next();
+ newValue.add( val );
+ }
+ value = newValue;
+ }
+ // DataTypeUtils.checkSupportedValue(propertyName, value, true,
+ // true);
+ }
+ else {
+ // DataTypeUtils.checkSupportedValue(propertyName, value, false,
+ // false);
+ }
+ this.propertyName = propertyName;
+ this.operator = operator;
+ this.value = value;
+ }
+
+
+ public FilterPredicate( String propertyName, String operator, String value, String secondValue,
+ String thirdValue ) {
+ this.propertyName = propertyName;
+ this.operator = FilterOperator.find( operator );
+ Object first_obj = parseValue( value, 0 );
+ Object second_obj = parseValue( secondValue, 0 );
+ Object third_obj = parseValue( thirdValue, 0 );
+ if ( second_obj != null ) {
+ if ( third_obj != null ) {
+ this.value = Arrays.asList( first_obj, second_obj, third_obj );
+ }
+ else {
+ this.value = Arrays.asList( first_obj, second_obj );
+ }
+ }
+ else {
+ this.value = first_obj;
+ }
+ }
+
+
+ public FilterPredicate( String propertyName, String operator, String value, int valueType, String secondValue,
+ int secondValueType, String thirdValue, int thirdValueType ) {
+ this.propertyName = propertyName;
+ this.operator = FilterOperator.find( operator );
+ Object first_obj = parseValue( value, valueType );
+ Object second_obj = parseValue( secondValue, secondValueType );
+ Object third_obj = parseValue( thirdValue, thirdValueType );
+ if ( second_obj != null ) {
+ if ( third_obj != null ) {
+ this.value = Arrays.asList( first_obj, second_obj, third_obj );
+ }
+ else {
+ this.value = Arrays.asList( first_obj, second_obj );
+ }
+ }
+ else {
+ this.value = first_obj;
+ }
+ }
+
+
+ private static Object parseValue( String val, int valueType ) {
+ if ( val == null ) {
+ return null;
+ }
+
+ if ( val.startsWith( "'" ) && ( val.length() > 1 ) ) {
+ return val.substring( 1, val.length() - 1 );
+ }
+
+ if ( val.equalsIgnoreCase( "true" ) || val.equalsIgnoreCase( "false" ) ) {
+ return Boolean.valueOf( val );
+ }
+
+ if ( val.length() == 36 ) {
+ try {
+ return UUID.fromString( val );
+ }
+ catch ( IllegalArgumentException e ) {
+ }
+ }
+
+ try {
+ return Long.valueOf( val );
+ }
+ catch ( NumberFormatException e ) {
+ }
+
+ try {
+ return Float.valueOf( val );
+ }
+ catch ( NumberFormatException e ) {
+
+ }
+
+ return null;
+ }
+
+
+ public static FilterPredicate valueOf( String str ) {
+ if ( str == null ) {
+ return null;
+ }
+ try {
+ ANTLRStringStream in = new ANTLRStringStream( str.trim() );
+ QueryFilterLexer lexer = new QueryFilterLexer( in );
+ CommonTokenStream tokens = new CommonTokenStream( lexer );
+ QueryFilterParser parser = new QueryFilterParser( tokens );
+ FilterPredicate filter = parser.filter();
+ return normalize( filter );
+ }
+ catch ( Exception e ) {
+ logger.error( "Unable to parse \"" + str + "\"", e );
+ }
+ return null;
+ }
+
+
+ public static FilterPredicate normalize( FilterPredicate p ) {
+ if ( p == null ) {
+ return null;
+ }
+ if ( p.operator == FilterOperator.CONTAINS ) {
+ String propertyName = appendSuffix( p.propertyName, "keywords" );
+ return new FilterPredicate( propertyName, FilterOperator.EQUAL, p.value );
+ }
+ else if ( p.operator == FilterOperator.WITHIN ) {
+ String propertyName = appendSuffix( p.propertyName, "coordinates" );
+ return new FilterPredicate( propertyName, FilterOperator.WITHIN, p.value );
+ }
+
+ return p;
+ }
+
+
+ private static String appendSuffix( String str, String suffix ) {
+ if ( StringUtils.isNotEmpty( str ) ) {
+ if ( !str.endsWith( "." + suffix ) ) {
+ str += "." + suffix;
+ }
+ }
+ else {
+ str = suffix;
+ }
+ return str;
+ }
+
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+
+ public Query.FilterOperator getOperator() {
+ return operator;
+ }
+
+
+ public Object getValue() {
+ return value;
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public Object getStartValue() {
+ if ( value instanceof List ) {
+ List<Object> l = ( List<Object> ) value;
+ return l.get( 0 );
+ }
+ if ( ( operator == FilterOperator.GREATER_THAN ) || ( operator == FilterOperator.GREATER_THAN_OR_EQUAL )
+ || ( operator == FilterOperator.EQUAL ) ) {
+ return value;
+ }
+ else {
+ return null;
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public Object getFinishValue() {
+ if ( value instanceof List ) {
+ List<Object> l = ( List<Object> ) value;
+ if ( l.size() > 1 ) {
+ return l.get( 1 );
+ }
+ return null;
+ }
+ if ( ( operator == FilterOperator.LESS_THAN ) || ( operator == FilterOperator.LESS_THAN_OR_EQUAL ) || (
+ operator == FilterOperator.EQUAL ) ) {
+ return value;
+ }
+ else {
+ return null;
+ }
+ }
+
+
+ public void setCursor( String cursor ) {
+ this.cursor = cursor;
+ }
+
+
+ public String getCursor() {
+ return cursor;
+ }
+
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = ( prime * result ) + ( ( operator == null ) ? 0 : operator.hashCode() );
+ result = ( prime * result ) + ( ( propertyName == null ) ? 0 : propertyName.hashCode() );
+ 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;
+ }
+ FilterPredicate other = ( FilterPredicate ) obj;
+ if ( operator != other.operator ) {
+ return false;
+ }
+ if ( propertyName == null ) {
+ if ( other.propertyName != null ) {
+ return false;
+ }
+ }
+ else if ( !propertyName.equals( other.propertyName ) ) {
+ return false;
+ }
+ if ( value == null ) {
+ if ( other.value != null ) {
+ return false;
+ }
+ }
+ else if ( !value.equals( other.value ) ) {
+ return false;
+ }
+ return true;
+ }
+
+
+ @Override
+ public String toString() {
+ String valueStr = "\'\'";
+ if ( value != null ) {
+ if ( value instanceof String ) {
+ valueStr = "\'" + value + "\'";
+ }
+ else {
+ valueStr = value.toString();
+ }
+ }
+ return propertyName + " " + operator.toString() + " " + valueStr;
+ }
+ }
+
+
+ public static final class CounterFilterPredicate implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private final String name;
+ private final Identifier user;
+ private final Identifier group;
+ private final String queue;
+ private final String category;
+
+
+ public CounterFilterPredicate( String name, Identifier user, Identifier group, String queue, String category ) {
+ this.name = name;
+ this.user = user;
+ this.group = group;
+ this.queue = queue;
+ this.category = category;
+ }
+
+
+ public Identifier getUser() {
+ return user;
+ }
+
+
+ public Identifier getGroup() {
+ return group;
+ }
+
+
+ public String getQueue() {
+ return queue;
+ }
+
+
+ public String getCategory() {
+ return category;
+ }
+
+
+ public String getName() {
+ return name;
+ }
+
+
+ public static CounterFilterPredicate fromString( String s ) {
+ Identifier user = null;
+ Identifier group = null;
+ String category = null;
+ String name = null;
+ String[] l = split( s, ':' );
+
+ if ( l.length > 0 ) {
+ if ( !"*".equals( l[0] ) ) {
+ name = l[0];
+ }
+ }
+
+ if ( l.length > 1 ) {
+ if ( !"*".equals( l[1] ) ) {
+ user = Identifier.from( l[1] );
+ }
+ }
+
+ if ( l.length > 2 ) {
+ if ( !"*".equals( l[2] ) ) {
+ group = Identifier.from( l[3] );
+ }
+ }
+
+ if ( l.length > 3 ) {
+ if ( !"*".equals( l[3] ) ) {
+ category = l[3];
+ }
+ }
+
+ if ( ( user == null ) && ( group == null ) && ( category == null ) && ( name == null ) ) {
+ return null;
+ }
+
+ return new CounterFilterPredicate( name, user, group, null, category );
+ }
+
+
+ public static List<CounterFilterPredicate> fromList( List<String> l ) {
+ if ( ( l == null ) || ( l.size() == 0 ) ) {
+ return null;
+ }
+ List<CounterFilterPredicate> counterFilters = new ArrayList<CounterFilterPredicate>();
+ for ( String s : l ) {
+ CounterFilterPredicate filter = CounterFilterPredicate.fromString( s );
+ if ( filter != null ) {
+ counterFilters.add( filter );
+ }
+ }
+ if ( counterFilters.size() == 0 ) {
+ return null;
+ }
+ return counterFilters;
+ }
+ }
+
+
+ public List<Object> getSelectionResults( Results rs ) {
+
+ List<Entity> entities = rs.getEntities();
+ if ( entities == null ) {
+ return null;
+ }
+
+ if ( !hasSelectSubjects() ) {
+ return cast( entities );
+ }
+
+ List<Object> results = new ArrayList<Object>();
+
+ for ( Entity entity : entities ) {
+ if ( isMergeSelectResults() ) {
+ boolean include = false;
+ Map<String, Object> result = new LinkedHashMap<String, Object>();
+ Map<String, String> selects = getSelectAssignments();
+ for ( Map.Entry<String, String> select : selects.entrySet() ) {
+ Object obj = JsonUtils.select( entity, select.getKey(), false );
+ if ( obj == null ) {
+ obj = "";
+ }
+ else {
+ include = true;
+ }
+ result.put( select.getValue(), obj );
+ }
+ if ( include ) {
+ results.add( result );
+ }
+ }
+ else {
+ boolean include = false;
+ List<Object> result = new ArrayList<Object>();
+ Set<String> selects = getSelectSubjects();
+ for ( String select : selects ) {
+ Object obj = JsonUtils.select( entity, select );
+ if ( obj == null ) {
+ obj = "";
+ }
+ else {
+ include = true;
+ }
+ result.add( obj );
+ }
+ if ( include ) {
+ results.add( result );
+ }
+ }
+ }
+
+ if ( results.size() == 0 ) {
+ return null;
+ }
+
+ return results;
+ }
+
+
+ public Object getSelectionResult( Results rs ) {
+ List<Object> r = getSelectionResults( rs );
+ if ( ( r != null ) && ( r.size() > 0 ) ) {
+ return r.get( 0 );
+ }
+ return null;
+ }
+}