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:51 UTC
[41/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/persistence/Query.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/Query.java b/stack/core/src/main/java/org/apache/usergrid/persistence/Query.java
new file mode 100644
index 0000000..65c1240
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/Query.java
@@ -0,0 +1,1309 @@
+/*******************************************************************************
+ * 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.persistence;
+
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.UUID;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.ClassicToken;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenRewriteStream;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.commons.lang.StringUtils;
+import org.apache.usergrid.persistence.Results.Level;
+import org.apache.usergrid.persistence.exceptions.QueryParseException;
+import org.apache.usergrid.persistence.query.tree.AndOperand;
+import org.apache.usergrid.persistence.query.tree.ContainsOperand;
+import org.apache.usergrid.persistence.query.tree.Equal;
+import org.apache.usergrid.persistence.query.tree.EqualityOperand;
+import org.apache.usergrid.persistence.query.tree.GreaterThan;
+import org.apache.usergrid.persistence.query.tree.GreaterThanEqual;
+import org.apache.usergrid.persistence.query.tree.LessThan;
+import org.apache.usergrid.persistence.query.tree.LessThanEqual;
+import org.apache.usergrid.persistence.query.tree.Operand;
+import org.apache.usergrid.persistence.query.tree.QueryFilterLexer;
+import org.apache.usergrid.persistence.query.tree.QueryFilterParser;
+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_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;
+
+ public static final int MAX_LIMIT = 1000;
+
+ private String type;
+ private List<SortPredicate> sortPredicates = new ArrayList<SortPredicate>();
+ private Operand rootOperand;
+ private UUID startResult;
+ private String cursor;
+ private int limit = 0;
+
+ private Map<String, String> selectAssignments = new LinkedHashMap<String, String>();
+ private boolean mergeSelectResults = false;
+ private Level level = Level.ALL_PROPERTIES;
+ private String connection;
+ private List<String> permissions;
+ private boolean reversed;
+ private boolean reversedSet = false;
+ private Long startTime;
+ private Long finishTime;
+ private boolean pad;
+ private CounterResolution resolution = CounterResolution.ALL;
+ private List<Identifier> identifiers;
+ private List<CounterFilterPredicate> counterFilters;
+ private String collection;
+ private String ql;
+
+
+ public Query() {
+ }
+
+
+ public Query( Query q ) {
+ if ( q != null ) {
+ type = q.type;
+ sortPredicates = q.sortPredicates != null ? new ArrayList<SortPredicate>( q.sortPredicates ) : null;
+ startResult = q.startResult;
+ cursor = q.cursor;
+ limit = q.limit;
+ selectAssignments =
+ q.selectAssignments != null ? new LinkedHashMap<String, String>( q.selectAssignments ) : 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;
+ rootOperand = q.rootOperand;
+ identifiers = q.identifiers != null ? new ArrayList<Identifier>( q.identifiers ) : null;
+ counterFilters =
+ q.counterFilters != null ? new ArrayList<CounterFilterPredicate>( q.counterFilters ) : null;
+ collection = q.collection;
+ }
+ }
+
+
+ public static Query fromQL( String ql ) throws QueryParseException {
+ if ( ql == null ) {
+ return null;
+ }
+ String originalQl = ql;
+ 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;
+ }
+ }
+
+ ANTLRStringStream in = new ANTLRStringStream( qlt.trim() );
+ QueryFilterLexer lexer = new QueryFilterLexer( in );
+ CommonTokenStream tokens = new CommonTokenStream( lexer );
+ QueryFilterParser parser = new QueryFilterParser( tokens );
+
+ try {
+ Query q = parser.ql().query;
+ q.setQl( originalQl );
+ return q;
+ }
+ catch ( RecognitionException e ) {
+ logger.error( "Unable to parse \"{}\"", ql, e );
+
+ int index = e.index;
+ int lineNumber = e.line;
+ Token token = e.token;
+
+ String message = String.format(
+ "The query cannot be parsed. The token '%s' at column %d on line %d cannot be " + "parsed",
+ token.getText(), index, lineNumber );
+
+ throw new QueryParseException( message, e );
+ }
+ }
+
+
+ private static Query newQueryIfNull( Query query ) {
+ if ( query == null ) {
+ query = new Query();
+ }
+ return query;
+ }
+
+
+ public static Query fromJsonString( String json ) throws QueryParseException {
+ 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 ) throws QueryParseException {
+ Query q = null;
+ CounterResolution resolution = null;
+ List<Identifier> identifiers = null;
+ List<CounterFilterPredicate> counterFilters = null;
+
+ String ql = QueryUtils.queryStrFrom( params );
+ String type = first( params.get( "type" ) );
+ Boolean reversed = firstBoolean( params.get( "reversed" ) );
+ String connection = first( params.get( "connection" ) );
+ UUID start = firstUuid( params.get( "start" ) );
+ String cursor = first( params.get( "cursor" ) );
+ Integer limit = firstInteger( params.get( "limit" ) );
+ List<String> permissions = params.get( "permission" );
+ Long startTime = firstLong( params.get( "start_time" ) );
+ Long finishTime = firstLong( params.get( "end_time" ) );
+
+ List<String> l = params.get( "resolution" );
+ if ( !isEmpty( l ) ) {
+ resolution = CounterResolution.fromString( l.get( 0 ) );
+ }
+
+ l = params.get( "counter" );
+
+ if ( !isEmpty( l ) ) {
+ counterFilters = CounterFilterPredicate.fromList( l );
+ }
+
+ Boolean pad = firstBoolean( params.get( "pad" ) );
+
+ for ( Entry<String, List<String>> param : params.entrySet() ) {
+ Identifier identifier = Identifier.from( param.getKey() );
+ if ( ( param.getValue() == null ) || ( param.getValue().size() == 0 ) || identifier.isUUID() ) {
+ if ( identifier != null ) {
+ if ( identifiers == null ) {
+ identifiers = new ArrayList<Identifier>();
+ }
+ identifiers.add( identifier );
+ }
+ }
+ }
+
+ if ( ql != null ) {
+ q = Query.fromQL( decode( ql ) );
+ }
+
+ l = params.get( "filter" );
+
+ if ( !isEmpty( l ) ) {
+ q = newQueryIfNull( q );
+ for ( String s : l ) {
+ q.addFilter( decode( s ) );
+ }
+ }
+
+ l = params.get( "sort" );
+ if ( !isEmpty( l ) ) {
+ q = newQueryIfNull( q );
+ for ( String s : l ) {
+ q.addSort( decode( 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 ( counterFilters != null ) {
+ q = newQueryIfNull( q );
+ q.setCounterFilters( counterFilters );
+ }
+
+ if ( pad != null ) {
+ q = newQueryIfNull( q );
+ q.setPad( pad );
+ }
+
+ 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 fromIdentifier( Object id ) {
+ Query q = new Query();
+ q.addIdentifier( Identifier.from( id ) );
+ return q;
+ }
+
+
+ public boolean hasQueryPredicates() {
+ return rootOperand != null;
+ }
+
+
+ public boolean containsNameOrEmailIdentifiersOnly() {
+ if ( hasQueryPredicates() ) {
+ return false;
+ }
+ if ( ( identifiers == null ) || identifiers.isEmpty() ) {
+ return false;
+ }
+ for ( Identifier identifier : identifiers ) {
+ if ( !identifier.isEmail() && !identifier.isName() ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ @JsonIgnore
+ public String getSingleNameOrEmailIdentifier() {
+ if ( !containsSingleNameOrEmailIdentifier() ) {
+ return null;
+ }
+ return ( identifiers.get( 0 ).toString() );
+ }
+
+
+ public boolean containsSingleNameOrEmailIdentifier() {
+ return containsNameOrEmailIdentifiersOnly() && ( identifiers.size() == 1 );
+ }
+
+
+ @JsonIgnore
+ public Identifier getSingleIdentifier() {
+ return identifiers != null && identifiers.size() == 1 ? identifiers.get( 0 ) : null;
+ }
+
+
+ public boolean containsSingleUuidIdentifier() {
+ return containsUuidIdentifiersOnly() && ( identifiers.size() == 1 );
+ }
+
+
+ boolean containsUuidIdentifiersOnly() {
+ if ( hasQueryPredicates() ) {
+ return false;
+ }
+ if ( ( identifiers == null ) || identifiers.isEmpty() ) {
+ return false;
+ }
+
+ for ( Identifier identifier : identifiers ) {
+ if ( !identifier.isUUID() ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ public Query addSort( SortPredicate sort ) {
+ if ( sort == null ) {
+ return this;
+ }
+
+ for ( SortPredicate s : sortPredicates ) {
+ if ( s.getPropertyName().equals( sort.getPropertyName() ) ) {
+ throw new QueryParseException(
+ String.format( "Attempted to set sort order for %s more than once", s.getPropertyName() ) );
+ }
+ }
+ sortPredicates.add( sort );
+ return this;
+ }
+
+
+ @JsonIgnore
+ public UUID getSingleUuidIdentifier() {
+ if ( !containsSingleUuidIdentifier() ) {
+ return null;
+ }
+ return ( identifiers.get( 0 ).getUUID() );
+ }
+
+
+ @JsonIgnore
+ boolean isIdsOnly() {
+ if ( ( selectAssignments.size() == 1 ) && selectAssignments.containsKey( PROPERTY_UUID ) ) {
+ level = Level.IDS;
+ return true;
+ }
+ return false;
+ }
+
+
+ private void setIdsOnly( boolean idsOnly ) {
+ if ( idsOnly ) {
+ selectAssignments = new LinkedHashMap<String, String>();
+ selectAssignments.put( PROPERTY_UUID, PROPERTY_UUID );
+ level = Level.IDS;
+ }
+ else if ( isIdsOnly() ) {
+ selectAssignments = 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 Query withReversed( boolean reversed ) {
+ setReversed( reversed );
+ return this;
+ }
+
+
+ public String getEntityType() {
+ return type;
+ }
+
+
+ public void setEntityType( String type ) {
+ this.type = type;
+ }
+
+
+ public String getConnectionType() {
+ return connection;
+ }
+
+
+ public void setConnectionType( String connection ) {
+ this.connection = connection;
+ }
+
+
+ public List<String> getPermissions() {
+ return permissions;
+ }
+
+
+ public void setPermissions( List<String> permissions ) {
+ this.permissions = permissions;
+ }
+
+
+ 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;
+ }
+
+ mergeSelectResults = StringUtils.isNotEmpty( output );
+
+ if ( output == null ) {
+ output = "";
+ }
+
+ selectAssignments.put( select, output );
+
+ return this;
+ }
+
+
+ public boolean hasSelectSubjects() {
+ return !selectAssignments.isEmpty();
+ }
+
+
+ @JsonIgnore
+ public Set<String> getSelectSubjects() {
+ return selectAssignments.keySet();
+ }
+
+
+ public Map<String, String> getSelectAssignments() {
+ return selectAssignments;
+ }
+
+
+ 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, discarding..." );
+ return this;
+ }
+ }
+ sortPredicates.add( new SortPredicate( propertyName, direction ) );
+ return this;
+ }
+
+
+ @JsonIgnore
+ public boolean isSortSet() {
+ return !sortPredicates.isEmpty();
+ }
+
+
+ public List<SortPredicate> getSortPredicates() {
+ return sortPredicates;
+ }
+
+
+ public Query addFilter( String filter ) {
+ ANTLRStringStream in = new ANTLRStringStream( filter );
+ QueryFilterLexer lexer = new QueryFilterLexer( in );
+ TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+ QueryFilterParser parser = new QueryFilterParser( tokens );
+
+ Operand root;
+
+ try {
+ root = parser.ql().query.getRootOperand();
+ }
+ catch ( RecognitionException e ) {
+ // todo: should we create a specific Exception for this? checked?
+ throw new RuntimeException( "Unknown operation: " + filter, e );
+ }
+
+ if ( root != null ) {
+ addClause( root );
+ }
+
+ return this;
+ }
+
+
+ /** Add a less than filter to this query. && with existing clauses */
+ public Query addLessThanFilter( String propName, Object value ) {
+ LessThan equality = new LessThan( null );
+
+ addClause( equality, propName, value );
+
+ return this;
+ }
+
+
+ /** Add a less than equal filter to this query. && with existing clauses */
+ public Query addLessThanEqualFilter( String propName, Object value ) {
+ LessThanEqual equality = new LessThanEqual( null );
+
+ addClause( equality, propName, value );
+
+ return this;
+ }
+
+
+ /** Add a equal filter to this query. && with existing clauses */
+ public Query addEqualityFilter( String propName, Object value ) {
+ Equal equality = new Equal( new ClassicToken( 0, "=" ) );
+
+ addClause( equality, propName, value );
+
+ return this;
+ }
+
+
+ /** Add a greater than equal filter to this query. && with existing clauses */
+ public Query addGreaterThanEqualFilter( String propName, Object value ) {
+ GreaterThanEqual equality = new GreaterThanEqual( null );
+
+ addClause( equality, propName, value );
+
+ return this;
+ }
+
+
+ /** Add a less than filter to this query. && with existing clauses */
+ public Query addGreaterThanFilter( String propName, Object value ) {
+ GreaterThan equality = new GreaterThan( null );
+
+ addClause( equality, propName, value );
+
+ return this;
+ }
+
+
+ public Query addContainsFilter( String propName, String keyword ) {
+ ContainsOperand equality = new ContainsOperand( new ClassicToken( 0, "contains" ) );
+
+ equality.setProperty( propName );
+ equality.setLiteral( keyword );
+
+ addClause( equality );
+
+ return this;
+ }
+
+
+ private void addClause( EqualityOperand equals, String propertyName, Object value ) {
+ equals.setProperty( propertyName );
+ equals.setLiteral( value );
+ addClause( equals );
+ }
+
+
+ private void addClause( Operand equals ) {
+
+ if ( rootOperand == null ) {
+ rootOperand = equals;
+ return;
+ }
+
+ AndOperand and = new AndOperand();
+ and.addChild( rootOperand );
+ and.addChild( equals );
+
+ // redirect the root to new && clause
+ rootOperand = and;
+ }
+
+
+ @JsonIgnore
+ public Operand getRootOperand() {
+ if ( rootOperand == null ) { // attempt deserialization
+ if ( ql != null ) {
+ try {
+ Query q = Query.fromQL( ql );
+ rootOperand = q.rootOperand;
+ }
+ catch ( QueryParseException e ) {
+ logger.error( "error parsing sql for rootOperand", e ); // shouldn't happen
+ }
+ }
+ }
+ return rootOperand;
+ }
+
+
+ public void setRootOperand( Operand root ) {
+ this.rootOperand = root;
+ }
+
+
+ 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 ) {
+ 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 ) {
+
+ // TODO tnine. After users have had time to change their query limits,
+ // this needs to be uncommented and enforced.
+ // if(limit > MAX_LIMIT){
+ // throw new IllegalArgumentException(String.format("Query limit must be <= to %d", MAX_LIMIT));
+ // }
+
+ if ( limit > MAX_LIMIT ) {
+ limit = MAX_LIMIT;
+ }
+
+ this.limit = limit;
+ }
+
+
+ public Query withLimit( int limit ) {
+ setLimit( limit );
+ return this;
+ }
+
+
+ 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 void addIdentifier( Identifier identifier ) {
+ if ( identifiers == null ) {
+ identifiers = new ArrayList<Identifier>();
+ }
+ identifiers.add( identifier );
+ }
+
+
+ void setIdentifiers( List<Identifier> identifiers ) {
+ this.identifiers = identifiers;
+ }
+
+
+ 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 );
+ }
+
+
+ void setCounterFilters( List<CounterFilterPredicate> counterFilters ) {
+ this.counterFilters = counterFilters;
+ }
+
+
+ @Override
+ public String toString() {
+ if ( ql != null ) {
+ return ql;
+ }
+ StringBuilder s = new StringBuilder( "select " );
+ if ( selectAssignments.isEmpty() ) {
+ s.append( "*" );
+ }
+ else {
+ if ( mergeSelectResults ) {
+ s.append( "{ " );
+ boolean first = true;
+ for ( Map.Entry<String, String> select : selectAssignments.entrySet() ) {
+ if ( !first ) {
+ s.append( ", " );
+ }
+ s.append( select.getValue() ).append( " : " ).append( select.getKey() );
+ first = false;
+ }
+ s.append( " }" );
+ }
+ else {
+ boolean first = true;
+ for ( String select : selectAssignments.keySet() ) {
+ if ( !first ) {
+ s.append( ", " );
+ }
+ s.append( select );
+ first = false;
+ }
+ }
+ }
+ s.append( " from " );
+ s.append( type );
+ if ( !sortPredicates.isEmpty() ) {
+ boolean first = true;
+ s.append( " order by " );
+ for ( SortPredicate sp : sortPredicates ) {
+ if ( !first ) {
+ s.append( ", " );
+ }
+ s.append( sp );
+ first = false;
+ }
+ }
+ // 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 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;
+ }
+
+
+ @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 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.getValue(), false );
+ if ( obj != null ) {
+ include = true;
+ }
+ result.put( select.getKey(), 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 ) {
+ 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;
+ }
+
+
+ private static String decode( String input ) {
+ try {
+ return URLDecoder.decode( input, "UTF-8" );
+ }
+ catch ( UnsupportedEncodingException e ) {
+ // shouldn't happen, but just in case
+ throw new RuntimeException( e );
+ }
+ }
+
+
+ // note: very likely to be null
+ public String getCollection() {
+ return collection;
+ }
+
+
+ public void setCollection( String collection ) {
+ this.collection = collection;
+ }
+
+
+ // may be null
+ public String getQl() {
+ return ql;
+ }
+
+
+ public void setQl( String ql ) {
+ this.ql = ql;
+ }
+
+
+ public List<Identifier> getIdentifiers() {
+ return identifiers;
+ }
+
+
+ public String getConnection() {
+ return connection;
+ }
+
+
+ public String getType() {
+ return type;
+ }
+
+
+ public Level getLevel() {
+ return level;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/QueryUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/QueryUtils.java b/stack/core/src/main/java/org/apache/usergrid/persistence/QueryUtils.java
new file mode 100644
index 0000000..cfc7aac
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/QueryUtils.java
@@ -0,0 +1,34 @@
+package org.apache.usergrid.persistence;
+
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.usergrid.utils.ListUtils;
+
+
+/**
+ * Utilities to deal with query extraction and generation
+ *
+ * @author zznate
+ */
+public class QueryUtils {
+
+ public static final String PARAM_QL = "ql";
+ public static final String PARAM_Q = "q";
+ public static final String PARAM_QUERY = "query";
+
+
+ public static String queryStrFrom( Map<String, List<String>> params ) {
+ if ( params.containsKey( PARAM_QL ) ) {
+ return ListUtils.first( params.get( PARAM_QL ) );
+ }
+ else if ( params.containsKey( PARAM_Q ) ) {
+ return ListUtils.first( params.get( PARAM_Q ) );
+ }
+ else if ( params.containsKey( PARAM_QUERY ) ) {
+ return ListUtils.first( params.get( PARAM_QUERY ) );
+ }
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/RelationManager.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/RelationManager.java b/stack/core/src/main/java/org/apache/usergrid/persistence/RelationManager.java
new file mode 100644
index 0000000..70b68d5
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/RelationManager.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * 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.persistence;
+
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.usergrid.persistence.Results.Level;
+
+
+public interface RelationManager {
+
+ public Set<String> getCollectionIndexes( String collectionName ) throws Exception;
+
+ public Map<String, Map<UUID, Set<String>>> getOwners() throws Exception;
+
+
+ /**
+ * Returns true if the entity ref if a member of the owner ref for the current relation manager
+ *
+ * @param collectionName The name of the collection
+ */
+ public boolean isCollectionMember( String collectionName, EntityRef entity ) throws Exception;
+
+ /** Returns true if the target entity is currently connected to the owner ref of this relation manager */
+ public boolean isConnectionMember( String connectionName, EntityRef entity ) throws Exception;
+
+ public Set<String> getCollections() throws Exception;
+
+ public Results getCollection( String collectionName, UUID startResult, int count, Results.Level resultsLevel,
+ boolean reversed ) throws Exception;
+
+ public Results getCollection( String collectionName, Query query, Results.Level resultsLevel ) throws Exception;
+
+ public Entity addToCollection( String collectionName, EntityRef itemRef ) throws Exception;
+
+ public Entity addToCollections( List<EntityRef> owners, String collectionName ) throws Exception;
+
+ public Entity createItemInCollection( String collectionName, String itemType, Map<String, Object> properties )
+ throws Exception;
+
+ public void removeFromCollection( String collectionName, EntityRef itemRef ) throws Exception;
+
+ public void copyRelationships( String srcRelationName, EntityRef dstEntityRef, String dstRelationName )
+ throws Exception;
+
+ public Results searchCollection( String collectionName, Query query ) throws Exception;
+
+ public ConnectionRef createConnection( ConnectionRef connection ) throws Exception;
+
+ public ConnectionRef createConnection( String connectionType, EntityRef connectedEntityRef ) throws Exception;
+
+ public ConnectionRef createConnection( String pairedConnectionType, EntityRef pairedEntity, String connectionType,
+ EntityRef connectedEntityRef ) throws Exception;
+
+ public ConnectionRef createConnection( ConnectedEntityRef... connections ) throws Exception;
+
+ public ConnectionRef connectionRef( String connectionType, EntityRef connectedEntityRef ) throws Exception;
+
+ public ConnectionRef connectionRef( String pairedConnectionType, EntityRef pairedEntity, String connectionType,
+ EntityRef connectedEntityRef ) throws Exception;
+
+ public ConnectionRef connectionRef( ConnectedEntityRef... connections );
+
+ public void deleteConnection( ConnectionRef connectionRef ) throws Exception;
+
+ public Set<String> getConnectionTypes( UUID connectedEntityId ) throws Exception;
+
+ public Set<String> getConnectionTypes() throws Exception;
+
+ public Set<String> getConnectionTypes( boolean filterConnection ) throws Exception;
+
+ /**
+ * Get all entities connected to this entity. Also get all
+ *
+ * @param connectionType The type/name of the connection
+ * @param connectedEntityType The type of
+ */
+ public Results getConnectedEntities( String connectionType, String connectedEntityType, Results.Level resultsLevel )
+ throws Exception;
+
+ public Results getConnectingEntities( String connectionType, String connectedEntityType,
+ Results.Level resultsLevel ) throws Exception;
+
+ // public Results searchConnectedEntitiesForProperty(String connectionType,
+ // String connectedEntityType, String propertyName,
+ // Object searchStartValue, Object searchFinishValue,
+ // UUID startResult, int count, boolean reversed, Level resultsLevel)
+ // throws Exception;
+
+ public Results getConnectingEntities(String connectionType, String entityType, Level level, int count) throws Exception;
+
+ public Results searchConnectedEntities( Query query ) throws Exception;
+
+
+ public Set<String> getConnectionIndexes( String connectionType ) throws Exception;
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/Results.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/Results.java b/stack/core/src/main/java/org/apache/usergrid/persistence/Results.java
new file mode 100644
index 0000000..585666a
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/Results.java
@@ -0,0 +1,1294 @@
+/*******************************************************************************
+ * 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.persistence;
+
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+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 javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.usergrid.persistence.cassandra.QueryProcessor;
+import org.apache.usergrid.persistence.query.ir.SearchVisitor;
+import org.apache.usergrid.utils.MapUtils;
+import org.apache.usergrid.utils.StringUtils;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import static org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString;
+import static org.apache.usergrid.persistence.SimpleEntityRef.ref;
+import static org.apache.usergrid.utils.ClassUtils.cast;
+import static org.apache.usergrid.utils.ConversionUtils.bytes;
+
+
+@XmlRootElement
+public class Results implements Iterable<Entity> {
+
+
+ public enum Level {
+ IDS, REFS, CORE_PROPERTIES, ALL_PROPERTIES, LINKED_PROPERTIES
+ }
+
+
+ Level level = Level.IDS;
+ UUID id;
+ List<UUID> ids;
+ Set<UUID> idSet;
+
+ EntityRef ref;
+ List<EntityRef> refs;
+ Map<UUID, EntityRef> refsMap;
+ Map<String, List<EntityRef>> refsByType;
+
+ Entity entity;
+ List<Entity> entities;
+ Map<UUID, Entity> entitiesMap;
+ Map<String, List<Entity>> entitiesByType;
+
+ List<ConnectionRef> connections;
+ boolean forwardConnections = true;
+
+ List<AggregateCounterSet> counters;
+
+ Set<String> types;
+
+ Map<UUID, Map<String, Object>> metadata;
+ boolean metadataMerged = true;
+
+ UUID nextResult;
+ String cursor;
+
+ Query query;
+ Object data;
+ String dataName;
+
+ private QueryProcessor queryProcessor;
+ private SearchVisitor searchVisitor;
+
+
+ public Results() {
+ }
+
+
+ public Results( Results r ) {
+ if ( r != null ) {
+ level = r.level;
+
+ id = r.id;
+ ids = r.ids;
+ idSet = r.idSet;
+
+ ref = r.ref;
+ refs = r.refs;
+ refsMap = r.refsMap;
+ refsByType = r.refsByType;
+
+ entity = r.entity;
+ entities = r.entities;
+ entitiesMap = r.entitiesMap;
+ entitiesByType = r.entitiesByType;
+
+ connections = r.connections;
+ forwardConnections = r.forwardConnections;
+
+ counters = r.counters;
+
+ types = r.types;
+
+ metadata = r.metadata;
+ metadataMerged = r.metadataMerged;
+
+ nextResult = r.nextResult;
+ cursor = r.cursor;
+
+ query = r.query;
+ data = r.data;
+ dataName = r.dataName;
+ }
+ }
+
+
+ public void init() {
+ level = Level.IDS;
+
+ id = null;
+ ids = null;
+ idSet = null;
+
+ ref = null;
+ refs = null;
+ refsMap = null;
+ refsByType = null;
+
+ entity = null;
+ entities = null;
+ entitiesMap = null;
+ entitiesByType = null;
+
+ connections = null;
+ forwardConnections = true;
+
+ counters = null;
+
+ types = null;
+
+ // metadata = null;
+ metadataMerged = false;
+
+ query = null;
+ data = null;
+ dataName = null;
+ }
+
+
+ public static Results fromIdList( List<UUID> l ) {
+ Results r = new Results();
+ r.setIds( l );
+ return r;
+ }
+
+
+ public static Results fromIdList( List<UUID> l, String type ) {
+ if ( type == null ) {
+ return fromIdList( l );
+ }
+ List<EntityRef> refs = new ArrayList<EntityRef>();
+ for ( UUID u : l ) {
+ refs.add( ref( type, u ) );
+ }
+ Results r = new Results();
+ r.setRefs( refs );
+ return r;
+ }
+
+
+ public static Results fromId( UUID id ) {
+ Results r = new Results();
+ if ( id != null ) {
+ List<UUID> l = new ArrayList<UUID>();
+ l.add( id );
+ r.setIds( l );
+ }
+ return r;
+ }
+
+
+ public static Results fromRefList( List<EntityRef> l ) {
+ Results r = new Results();
+ r.setRefs( l );
+ return r;
+ }
+
+
+ public static Results fromEntities( List<? extends Entity> l ) {
+ Results r = new Results();
+ r.setEntities( l );
+ return r;
+ }
+
+
+ public static Results fromEntity( Entity e ) {
+ Results r = new Results();
+ r.setEntity( e );
+ return r;
+ }
+
+
+ public static Results fromRef( EntityRef ref ) {
+ if ( ref instanceof Entity ) {
+ return fromEntity( ( Entity ) ref );
+ }
+ Results r = new Results();
+ r.setRef( ref );
+ return r;
+ }
+
+
+ public static Results fromData( Object obj ) {
+ Results r = new Results();
+ r.setData( obj );
+ return r;
+ }
+
+
+ public static Results fromCounters( AggregateCounterSet counters ) {
+ Results r = new Results();
+ List<AggregateCounterSet> l = new ArrayList<AggregateCounterSet>();
+ l.add( counters );
+ r.setCounters( l );
+ return r;
+ }
+
+
+ public static Results fromCounters( List<AggregateCounterSet> counters ) {
+ Results r = new Results();
+ r.setCounters( counters );
+ return r;
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public static Results fromConnections( List<? extends ConnectionRef> connections ) {
+ Results r = new Results();
+ r.setConnections( ( List<ConnectionRef> ) connections, true );
+ return r;
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public static Results fromConnections( List<? extends ConnectionRef> connections, boolean forward ) {
+ Results r = new Results();
+ r.setConnections( ( List<ConnectionRef> ) connections, forward );
+ return r;
+ }
+
+
+ public Level getLevel() {
+ return level;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public Query getQuery() {
+ return query;
+ }
+
+
+ public void setQuery( Query query ) {
+ this.query = query;
+ }
+
+
+ public Results withQuery( Query query ) {
+ this.query = query;
+ return this;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public UUID getId() {
+ if ( id != null ) {
+ return id;
+ }
+ if ( entity != null ) {
+ id = entity.getUuid();
+ return id;
+ }
+ if ( ( ids != null ) && ( ids.size() > 0 ) ) {
+ id = ids.get( 0 );
+ return id;
+ }
+ if ( ( entities != null ) && ( entities.size() > 0 ) ) {
+ entity = entities.get( 0 );
+ id = entity.getUuid();
+ return id;
+ }
+ if ( ( refs != null ) && ( refs.size() > 0 ) ) {
+ EntityRef ref = refs.get( 0 );
+ id = ref.getUuid();
+ }
+ return id;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public List<UUID> getIds() {
+ if ( ids != null ) {
+ return ids;
+ }
+ /*
+ * if (connectionTypeAndEntityTypeToEntityIdMap != null) { ids = new
+ * ArrayList<UUID>(); Set<UUID> entitySet = new LinkedHashSet<UUID>();
+ * for (String ctype : connectionTypeAndEntityTypeToEntityIdMap
+ * .keySet()) { Map<String, List<UUID>> m =
+ * connectionTypeAndEntityTypeToEntityIdMap .get(ctype); for (String
+ * etype : m.keySet()) { List<UUID> l = m.get(etype); for (UUID id : l)
+ * { if (!entitySet.contains(id)) { ids.add(id); } } } } return ids; }
+ */
+ if ( connections != null ) {
+ ids = new ArrayList<UUID>();
+ for ( ConnectionRef connection : connections ) {
+ if ( forwardConnections ) {
+ ConnectedEntityRef c = connection.getConnectedEntity();
+ if ( c != null ) {
+ ids.add( c.getUuid() );
+ }
+ }
+ else {
+ EntityRef c = connection.getConnectingEntity();
+ if ( c != null ) {
+ ids.add( c.getUuid() );
+ }
+ }
+ }
+ return ids;
+ }
+ if ( ( entities != null )
+ /* || (connectionTypeAndEntityTypeToEntityMap != null) */ ) {
+ // getEntities();
+ ids = new ArrayList<UUID>();
+ for ( Entity entity : entities ) {
+ ids.add( entity.getUuid() );
+ }
+ return ids;
+ }
+ if ( refs != null ) {
+ ids = new ArrayList<UUID>();
+ for ( EntityRef ref : refs ) {
+ ids.add( ref.getUuid() );
+ }
+ return ids;
+ }
+ if ( id != null ) {
+ ids = new ArrayList<UUID>();
+ ids.add( id );
+ return ids;
+ }
+ if ( entity != null ) {
+ ids = new ArrayList<UUID>();
+ ids.add( entity.getUuid() );
+ return ids;
+ }
+ return new ArrayList<UUID>();
+ }
+
+
+ public void setIds( List<UUID> resultsIds ) {
+ init();
+ ids = resultsIds;
+ level = Level.IDS;
+ }
+
+
+ public Results withIds( List<UUID> resultsIds ) {
+ setIds( resultsIds );
+ return this;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public Set<UUID> getIdSet() {
+ if ( idSet != null ) {
+ return idSet;
+ }
+ getIds();
+ if ( ids != null ) {
+ idSet = new LinkedHashSet<UUID>();
+ idSet.addAll( ids );
+ return idSet;
+ }
+ return new LinkedHashSet<UUID>();
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ @SuppressWarnings("unchecked")
+ public List<EntityRef> getRefs() {
+ if ( refs != null ) {
+ return refs;
+ }
+ List<?> l = getEntities();
+ if ( ( l != null ) && ( l.size() > 0 ) ) {
+ return ( List<EntityRef> ) l;
+ }
+ if ( connections != null ) {
+ refs = new ArrayList<EntityRef>();
+ for ( ConnectionRef connection : connections ) {
+ if ( forwardConnections ) {
+ ConnectedEntityRef c = connection.getConnectedEntity();
+ if ( c != null ) {
+ refs.add( c );
+ }
+ }
+ else {
+ EntityRef c = connection.getConnectingEntity();
+ if ( c != null ) {
+ refs.add( c );
+ }
+ }
+ }
+ return refs;
+ }
+ if ( ref != null ) {
+ refs = new ArrayList<EntityRef>();
+ refs.add( ref );
+ return refs;
+ }
+ return new ArrayList<EntityRef>();
+ }
+
+
+ public void setRefs( List<EntityRef> resultsRefs ) {
+ init();
+ refs = resultsRefs;
+ level = Level.REFS;
+ }
+
+
+ public Results withRefs( List<EntityRef> resultsRefs ) {
+ setRefs( resultsRefs );
+ return this;
+ }
+
+
+ public void setRef( EntityRef ref ) {
+ init();
+ this.ref = ref;
+ level = Level.REFS;
+ }
+
+
+ public Results withRef( EntityRef ref ) {
+ setRef( ref );
+ return this;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public EntityRef getRef() {
+ if ( ref != null ) {
+ return ref;
+ }
+ ref = getEntity();
+ if ( ref != null ) {
+ return ref;
+ }
+ UUID u = getId();
+ if ( u != null ) {
+ return ref( u );
+ }
+ return null;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public Map<UUID, EntityRef> getRefsMap() {
+ if ( refsMap != null ) {
+ return refsMap;
+ }
+ getEntitiesMap();
+ if ( entitiesMap != null ) {
+ refsMap = cast( entitiesMap );
+ return refsMap;
+ }
+ getRefs();
+ if ( refs != null ) {
+ refsMap = new LinkedHashMap<UUID, EntityRef>();
+ for ( EntityRef ref : refs ) {
+ refsMap.put( ref.getUuid(), ref );
+ }
+ }
+ return refsMap;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public Entity getEntity() {
+ mergeEntitiesWithMetadata();
+ if ( entity != null ) {
+ return entity;
+ }
+ if ( ( entities != null ) && ( entities.size() > 0 ) ) {
+ entity = entities.get( 0 );
+ return entity;
+ }
+ return null;
+ }
+
+
+ public void setEntity( Entity resultEntity ) {
+ init();
+ entity = resultEntity;
+ level = Level.CORE_PROPERTIES;
+ }
+
+
+ public Results withEntity( Entity resultEntity ) {
+ setEntity( resultEntity );
+ return this;
+ }
+
+
+ public Iterator<UUID> idIterator() {
+ List<UUID> l = getIds();
+ if ( l != null ) {
+ return l.iterator();
+ }
+ return ( new ArrayList<UUID>( 0 ) ).iterator();
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public List<Entity> getEntities() {
+ mergeEntitiesWithMetadata();
+ if ( entities != null ) {
+ return entities;
+ }
+ /*
+ * if (connectionTypeAndEntityTypeToEntityMap != null) { entities = new
+ * ArrayList<Entity>(); Map<UUID, Entity> eMap = new LinkedHashMap<UUID,
+ * Entity>(); for (String ctype :
+ * connectionTypeAndEntityTypeToEntityMap.keySet()) { Map<String,
+ * List<Entity>> m = connectionTypeAndEntityTypeToEntityMap .get(ctype);
+ * for (String etype : m.keySet()) { List<Entity> l = m.get(etype); for
+ * (Entity e : l) { if (!eMap.containsKey(e.getUuid())) { entities.add(e);
+ * eMap.put(e.getUuid(), e); } } } } return entities; }
+ */
+ if ( entity != null ) {
+ entities = new ArrayList<Entity>();
+ entities.add( entity );
+ return entities;
+ }
+ return new ArrayList<Entity>();
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public Map<UUID, Entity> getEntitiesMap() {
+ if ( entitiesMap != null ) {
+ return entitiesMap;
+ }
+ if ( entities != null ) {
+ entitiesMap = new LinkedHashMap<UUID, Entity>();
+ for ( Entity entity : entities ) {
+ entitiesMap.put( entity.getUuid(), entity );
+ }
+ }
+ return entitiesMap;
+ }
+
+
+ public List<EntityRef> getEntityRefsByType( String type ) {
+ if ( entitiesByType != null ) {
+ return refsByType.get( type );
+ }
+ List<EntityRef> l = cast( getEntitiesByType( type ) );
+ if ( l != null ) {
+ return l;
+ }
+ getRefs();
+ if ( refs == null ) {
+ return null;
+ }
+ refsByType = new LinkedHashMap<String, List<EntityRef>>();
+ for ( Entity entity : entities ) {
+ l = refsByType.get( entity.getType() );
+ if ( l == null ) {
+ l = new ArrayList<EntityRef>();
+ refsByType.put( entity.getType(), l );
+ }
+ l.add( entity );
+ }
+ return l;
+ }
+
+
+ public List<Entity> getEntitiesByType( String type ) {
+ if ( entitiesByType != null ) {
+ return entitiesByType.get( type );
+ }
+ getEntities();
+ if ( entities == null ) {
+ return null;
+ }
+ List<Entity> l = null;
+ entitiesByType = new LinkedHashMap<String, List<Entity>>();
+ for ( Entity entity : entities ) {
+ l = entitiesByType.get( entity.getType() );
+ if ( l == null ) {
+ l = new ArrayList<Entity>();
+ entitiesByType.put( entity.getType(), l );
+ }
+ l.add( entity );
+ }
+ return l;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public Set<String> getTypes() {
+ if ( types != null ) {
+ return types;
+ }
+ getEntityRefsByType( "entity" );
+ if ( entitiesByType != null ) {
+ types = entitiesByType.keySet();
+ }
+ else if ( refsByType != null ) {
+ types = refsByType.keySet();
+ }
+ return types;
+ }
+
+
+ public void merge( Results results ) {
+ getEntitiesMap();
+ results.getEntitiesMap();
+ if ( entitiesMap != null || results.entitiesMap != null ) {
+
+ level = Level.ALL_PROPERTIES;
+
+ // do nothing, nothing to union
+ if ( entitiesMap != null && results.entitiesMap == null ) {
+ return;
+ // other side has the results, assign and return
+ }
+ else if ( entitiesMap == null && results.entitiesMap != null ) {
+ entities = results.entities;
+ return;
+ }
+
+ entitiesMap.putAll( results.entitiesMap );
+ entities = new ArrayList<Entity>( entitiesMap.values() );
+
+ return;
+ }
+
+ getRefsMap();
+ results.getRefsMap();
+ if ( ( refsMap != null ) || ( results.refsMap != null ) ) {
+
+ level = Level.REFS;
+
+ // do nothing, nothing to union
+ if ( refsMap != null && results.refsMap == null ) {
+ return;
+ // other side has the results, assign and return
+ }
+ else if ( refsMap == null && results.refsMap != null ) {
+ refs = results.refs;
+ return;
+ }
+
+ refsMap.putAll( results.refsMap );
+ refs = new ArrayList<EntityRef>( refsMap.values() );
+
+ return;
+ }
+
+ getIdSet();
+ results.getIdSet();
+ if ( ( idSet != null ) && ( results.idSet != null ) ) {
+
+ level = Level.IDS;
+
+ // do nothing, nothing to union
+ if ( idSet != null && results.idSet == null ) {
+ return;
+ // other side has the results, assign and return
+ }
+ else if ( idSet == null && results.idSet != null ) {
+ ids = results.ids;
+ return;
+ }
+
+ idSet.addAll( results.idSet );
+ ids = new ArrayList<UUID>( idSet );
+
+ return;
+ }
+ }
+
+
+ /** Remove the passed in results from the current results */
+ public void subtract( Results results ) {
+ getEntitiesMap();
+ results.getEntitiesMap();
+
+ if ( ( entitiesMap != null ) && ( results.entitiesMap != null ) ) {
+ Map<UUID, Entity> newMap = new LinkedHashMap<UUID, Entity>();
+ for ( Map.Entry<UUID, Entity> e : entitiesMap.entrySet() ) {
+ if ( !results.entitiesMap.containsKey( e.getKey() ) ) {
+ newMap.put( e.getKey(), e.getValue() );
+ }
+ }
+ entitiesMap = newMap;
+ entities = new ArrayList<Entity>( entitiesMap.values() );
+ level = Level.ALL_PROPERTIES;
+ return;
+ }
+
+ getRefsMap();
+ results.getRefsMap();
+ if ( ( refsMap != null ) && ( results.refsMap != null ) ) {
+ Map<UUID, EntityRef> newMap = new LinkedHashMap<UUID, EntityRef>();
+ for ( Map.Entry<UUID, EntityRef> e : refsMap.entrySet() ) {
+ if ( !results.refsMap.containsKey( e.getKey() ) ) {
+ newMap.put( e.getKey(), e.getValue() );
+ }
+ }
+ refsMap = newMap;
+ refs = new ArrayList<EntityRef>( refsMap.values() );
+ level = Level.REFS;
+ return;
+ }
+
+ getIdSet();
+ results.getIdSet();
+ if ( ( idSet != null ) && ( results.idSet != null ) ) {
+ Set<UUID> newSet = new LinkedHashSet<UUID>();
+ for ( UUID uuid : idSet ) {
+ if ( !results.idSet.contains( uuid ) ) {
+ newSet.add( uuid );
+ }
+ }
+ idSet = newSet;
+ ids = new ArrayList<UUID>( idSet );
+ level = Level.IDS;
+ return;
+ }
+ }
+
+
+ /** Perform an intersection of the 2 results */
+ public void and( Results results ) {
+ getEntitiesMap();
+ results.getEntitiesMap();
+
+ if ( ( entitiesMap != null ) && ( results.entitiesMap != null ) ) {
+ Map<UUID, Entity> newMap = new LinkedHashMap<UUID, Entity>();
+ for ( Map.Entry<UUID, Entity> e : entitiesMap.entrySet() ) {
+ if ( results.entitiesMap.containsKey( e.getKey() ) ) {
+ newMap.put( e.getKey(), e.getValue() );
+ }
+ }
+ entitiesMap = newMap;
+ entities = new ArrayList<Entity>( entitiesMap.values() );
+ level = Level.ALL_PROPERTIES;
+ return;
+ }
+
+ getRefsMap();
+ results.getRefsMap();
+ if ( ( refsMap != null ) && ( results.refsMap != null ) ) {
+ Map<UUID, EntityRef> newMap = new LinkedHashMap<UUID, EntityRef>();
+ for ( Map.Entry<UUID, EntityRef> e : refsMap.entrySet() ) {
+ if ( results.refsMap.containsKey( e.getKey() ) ) {
+ newMap.put( e.getKey(), e.getValue() );
+ }
+ }
+ refsMap = newMap;
+ refs = new ArrayList<EntityRef>( refsMap.values() );
+ level = Level.REFS;
+ ids = null;
+ return;
+ }
+
+ getIdSet();
+ results.getIdSet();
+ if ( ( idSet != null ) && ( results.idSet != null ) ) {
+ Set<UUID> newSet = new LinkedHashSet<UUID>();
+ for ( UUID uuid : idSet ) {
+ if ( results.idSet.contains( uuid ) ) {
+ newSet.add( uuid );
+ }
+ }
+ idSet = newSet;
+ ids = new ArrayList<UUID>( idSet );
+ level = Level.IDS;
+ return;
+ }
+
+ // should be empty
+ init();
+ }
+
+
+ public void replace( Entity entity ) {
+ entitiesMap = null;
+ if ( ( this.entity != null ) && ( this.entity.getUuid().equals( entity.getUuid() ) ) ) {
+ this.entity = entity;
+ }
+ if ( entities != null ) {
+ ListIterator<Entity> i = entities.listIterator();
+ while ( i.hasNext() ) {
+ Entity e = i.next();
+ if ( e.getUuid().equals( entity.getUuid() ) ) {
+ i.set( entity );
+ }
+ }
+ }
+ }
+
+
+ public Results startingFrom( UUID entityId ) {
+ if ( entities != null ) {
+ for ( int i = 0; i < entities.size(); i++ ) {
+ Entity entity = entities.get( i );
+ if ( entityId.equals( entity.getUuid() ) ) {
+ if ( i == 0 ) {
+ return this;
+ }
+ return Results.fromEntities( entities.subList( i, entities.size() ) );
+ }
+ }
+ }
+ if ( refs != null ) {
+ for ( int i = 0; i < refs.size(); i++ ) {
+ EntityRef entityRef = refs.get( i );
+ if ( entityId.equals( entityRef.getUuid() ) ) {
+ if ( i == 0 ) {
+ return this;
+ }
+ return Results.fromRefList( refs.subList( i, refs.size() ) );
+ }
+ }
+ }
+ if ( ids != null ) {
+ for ( int i = 0; i < ids.size(); i++ ) {
+ UUID uuid = ids.get( i );
+ if ( entityId.equals( uuid ) ) {
+ if ( i == 0 ) {
+ return this;
+ }
+ return Results.fromIdList( ids.subList( i, ids.size() ) );
+ }
+ }
+ }
+ return this;
+ }
+
+
+ @SuppressWarnings("unchecked")
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public <E extends Entity> List<E> getList() {
+ List<Entity> l = getEntities();
+ return ( List<E> ) l;
+ }
+
+
+ public <E extends Entity> Iterator<E> iterator( Class<E> cls ) {
+ List<E> l = getList();
+ if ( l != null ) {
+ return l.iterator();
+ }
+ return ( new ArrayList<E>( 0 ) ).iterator();
+ }
+
+
+ @Override
+ public Iterator<Entity> iterator() {
+ List<Entity> l = getEntities();
+ if ( l != null ) {
+ return l.iterator();
+ }
+ return ( new ArrayList<Entity>( 0 ) ).iterator();
+ }
+
+
+ public Results findForProperty( String propertyName, Object propertyValue ) {
+ return findForProperty( propertyName, propertyValue, 1 );
+ }
+
+
+ public Results findForProperty( String propertyName, Object propertyValue, int count ) {
+ if ( propertyValue == null ) {
+ return new Results();
+ }
+ List<Entity> l = getEntities();
+ if ( l == null ) {
+ return new Results();
+ }
+ List<Entity> found = new ArrayList<Entity>();
+ for ( Entity e : l ) {
+ if ( propertyValue.equals( e.getProperty( propertyName ) ) ) {
+ found.add( e );
+ if ( ( count > 0 ) && ( found.size() == count ) ) {
+ break;
+ }
+ }
+ }
+ return Results.fromEntities( found );
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public void setEntities( List<? extends Entity> resultsEntities ) {
+ init();
+ entities = ( List<Entity> ) resultsEntities;
+ level = Level.CORE_PROPERTIES;
+ }
+
+
+ public Results withEntities( List<? extends Entity> resultsEntities ) {
+ setEntities( resultsEntities );
+ return this;
+ }
+
+
+ public boolean hasConnections() {
+ return connections != null;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public List<ConnectionRef> getConnections() {
+ return connections;
+ }
+
+
+ private void setConnections( List<ConnectionRef> connections, boolean forwardConnections ) {
+ init();
+ this.connections = connections;
+ this.forwardConnections = forwardConnections;
+ level = Level.REFS;
+ for ( ConnectionRef connection : connections ) {
+ if ( forwardConnections ) {
+ this.setMetadata( connection.getConnectedEntity().getUuid(), "connection",
+ connection.getConnectionType() );
+ }
+ else {
+ this.setMetadata( connection.getConnectingEntity().getUuid(), "connection",
+ connection.getConnectionType() );
+ }
+ }
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public Object getObject() {
+ if ( data != null ) {
+ return data;
+ }
+ if ( entities != null ) {
+ return entities;
+ }
+ if ( ids != null ) {
+ return ids;
+ }
+ if ( entity != null ) {
+ return entity;
+ }
+ if ( id != null ) {
+ return id;
+ }
+ if ( counters != null ) {
+ return counters;
+ }
+ return null;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public String getObjectName() {
+ if ( dataName != null ) {
+ return dataName;
+ }
+ if ( entities != null ) {
+ return "entities";
+ }
+ if ( ids != null ) {
+ return "ids";
+ }
+ if ( entity != null ) {
+ return "entity";
+ }
+ if ( id != null ) {
+ return "id";
+ }
+ return null;
+ }
+
+
+ public void setDataName( String dataName ) {
+ this.dataName = dataName;
+ }
+
+
+ public Results withDataName( String dataName ) {
+ this.dataName = dataName;
+ return this;
+ }
+
+
+ public boolean hasData() {
+ return data != null;
+ }
+
+
+ public void setData( Object data ) {
+ this.data = data;
+ }
+
+
+ public Results withData( Object data ) {
+ this.data = data;
+ return this;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public Object getData() {
+ return data;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public List<AggregateCounterSet> getCounters() {
+ return counters;
+ }
+
+
+ public void setCounters( List<AggregateCounterSet> counters ) {
+ this.counters = counters;
+ }
+
+
+ public Results withCounters( List<AggregateCounterSet> counters ) {
+ this.counters = counters;
+ return this;
+ }
+
+
+ public int size() {
+ if ( entities != null ) {
+ return entities.size();
+ }
+ if ( refs != null ) {
+ return refs.size();
+ }
+ if ( ids != null ) {
+ return ids.size();
+ }
+ if ( entity != null ) {
+ return 1;
+ }
+ if ( ref != null ) {
+ return 1;
+ }
+ if ( id != null ) {
+ return 1;
+ }
+ return 0;
+ }
+
+
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public UUID getNextResult() {
+ return nextResult;
+ }
+
+
+ public Results excludeCursorMetadataAttribute() {
+ if ( metadata != null ) {
+ for ( Entry<UUID, Map<String, Object>> entry : metadata.entrySet() ) {
+ Map<String, Object> map = entry.getValue();
+ if ( map != null ) {
+ map.remove( Schema.PROPERTY_CURSOR );
+ }
+ }
+ }
+ return new Results( this );
+ }
+
+
+ public Results trim( int count ) {
+ if ( count == 0 ) {
+ return this;
+ }
+
+ int size = size();
+ if ( size <= count ) {
+ return this;
+ }
+
+ List<UUID> ids = getIds();
+ UUID nextResult = null;
+ String cursor = null;
+ if ( ids.size() > count ) {
+ nextResult = ids.get( count );
+ ids = ids.subList( 0, count );
+ if ( metadata != null ) {
+ cursor = StringUtils.toString( MapUtils.getMapMap( metadata, nextResult, "cursor" ) );
+ }
+ if ( cursor == null ) {
+ cursor = encodeBase64URLSafeString( bytes( nextResult ) );
+ }
+ }
+
+ Results r = new Results( this );
+ if ( r.entities != null ) {
+ r.entities = r.entities.subList( 0, count );
+ }
+ if ( r.refs != null ) {
+ r.refs = r.refs.subList( 0, count );
+ }
+ if ( r.ids != null ) {
+ r.ids = r.ids.subList( 0, count );
+ }
+ r.setNextResult( nextResult );
+ r.setCursor( cursor );
+
+ return r;
+ }
+
+
+ public boolean hasMoreResults() {
+ return nextResult != null;
+ }
+
+
+ public void setNextResult( UUID nextResult ) {
+ this.nextResult = nextResult;
+ }
+
+
+ public Results withNextResult( UUID nextResult ) {
+ this.nextResult = nextResult;
+ return this;
+ }
+
+
+ @JsonSerialize(include = Inclusion.NON_NULL)
+ public String getCursor() {
+ return cursor;
+ }
+
+
+ public boolean hasCursor() {
+ return cursor != null && cursor.length() > 0;
+ }
+
+
+ public void setCursor( String cursor ) {
+ this.cursor = cursor;
+ }
+
+
+ public Results withCursor( String cursor ) {
+ this.cursor = cursor;
+ return this;
+ }
+
+
+ public void setMetadata( UUID id, String name, Object value ) {
+ if ( metadata == null ) {
+ metadata = new LinkedHashMap<UUID, Map<String, Object>>();
+ }
+ Map<String, Object> entityMetadata = metadata.get( id );
+ if ( entityMetadata == null ) {
+ entityMetadata = new LinkedHashMap<String, Object>();
+ metadata.put( id, entityMetadata );
+ }
+ entityMetadata.put( name, value );
+ metadataMerged = false;
+ // updateIndex(id, name, value);
+ }
+
+
+ public Results withMetadata( UUID id, String name, Object value ) {
+ setMetadata( id, name, value );
+ return this;
+ }
+
+
+ public void setMetadata( UUID id, Map<String, Object> data ) {
+ if ( metadata == null ) {
+ metadata = new LinkedHashMap<UUID, Map<String, Object>>();
+ }
+ Map<String, Object> entityMetadata = metadata.get( id );
+ if ( entityMetadata == null ) {
+ entityMetadata = new LinkedHashMap<String, Object>();
+ metadata.put( id, entityMetadata );
+ }
+ entityMetadata.putAll( data );
+ metadataMerged = false;
+ /*
+ * for (Entry<String, Object> m : data.entrySet()) { updateIndex(id,
+ * m.getKey(), m.getValue()); }
+ */
+ }
+
+
+ public Results withMetadata( UUID id, Map<String, Object> data ) {
+ setMetadata( id, data );
+ return this;
+ }
+
+
+ public void setMetadata( Map<UUID, Map<String, Object>> metadata ) {
+ this.metadata = metadata;
+ }
+
+
+ public Results withMetadata( Map<UUID, Map<String, Object>> metadata ) {
+ this.metadata = metadata;
+ return this;
+ }
+
+
+ public void mergeEntitiesWithMetadata() {
+ if ( metadataMerged ) {
+ return;
+ }
+ if ( metadata == null ) {
+ return;
+ }
+ metadataMerged = true;
+ getEntities();
+ if ( entities != null ) {
+ for ( Entity entity : entities ) {
+ entity.clearMetadata();
+ Map<String, Object> entityMetadata = metadata.get( entity.getUuid() );
+ if ( entityMetadata != null ) {
+ entity.mergeMetadata( entityMetadata );
+ }
+ }
+ }
+ }
+
+
+ protected QueryProcessor getQueryProcessor() {
+ return queryProcessor;
+ }
+
+
+ public void setQueryProcessor( QueryProcessor queryProcessor ) {
+ this.queryProcessor = queryProcessor;
+ }
+
+
+ public void setSearchVisitor( SearchVisitor searchVisitor ) {
+ this.searchVisitor = searchVisitor;
+ }
+
+
+ /** uses cursor to get next batch of Results (returns null if no cursor) */
+ public Results getNextPageResults() throws Exception {
+ if ( !hasCursor() ) {
+ return null;
+ }
+
+ Query q = new Query( query );
+ q.setCursor( getCursor() );
+ queryProcessor.setQuery( q );
+
+ return queryProcessor.getResults( searchVisitor );
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/RoleRef.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/RoleRef.java b/stack/core/src/main/java/org/apache/usergrid/persistence/RoleRef.java
new file mode 100644
index 0000000..f194a2b
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/RoleRef.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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.persistence;
+
+
+import java.util.UUID;
+
+
+public interface RoleRef extends EntityRef {
+
+ public UUID getGroupId();
+
+ public EntityRef getGroupRef();
+
+ public String getRoleName();
+
+ public String getApplicationRoleName();
+}