Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2013-2014 Richard M. Hightower
* 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.
*
* __________ _____ __ .__
* \______ \ ____ ____ ____ /\ / \ _____ | | _|__| ____ ____
* | | _// _ \ / _ \ / \ \/ / \ / \\__ \ | |/ / |/ \ / ___\
* | | ( <_> | <_> ) | \ /\ / Y \/ __ \| <| | | \/ /_/ >
* |______ /\____/ \____/|___| / \/ \____|__ (____ /__|_ \__|___| /\___ /
* \/ \/ \/ \/ \/ \//_____/
* ____. ___________ _____ ______________.___.
* | |____ ___ _______ \_ _____/ / _ \ / _____/\__ | |
* | \__ \\ \/ /\__ \ | __)_ / /_\ \ \_____ \ / | |
* /\__| |/ __ \\ / / __ \_ | \/ | \/ \ \____ |
* \________(____ /\_/ (____ / /_______ /\____|__ /_______ / / ______|
* \/ \/ \/ \/ \/ \/
*/
package org.boon.datarepo;
import org.boon.core.Typ;
import org.boon.core.reflection.BeanUtils;
import org.boon.core.reflection.Fields;
import org.boon.core.reflection.fields.FieldAccess;
import org.boon.criteria.internal.Criteria;
import org.boon.datarepo.impl.decorators.FilterWithSimpleCache;
import org.boon.datarepo.spi.SPIFactory;
import org.boon.datarepo.spi.SearchIndex;
import org.boon.datarepo.spi.SearchableCollectionComposer;
import org.boon.core.Function;
import java.util.*;
import static org.boon.Exceptions.requireNonNull;
/**
* Wraps regular collections in data repo searchable collections.
*/
public class Collections {
/**
* $q turns a listStream into a querying listStream.
*
* @param list the listStream you want to convert
* @param classes classes you want to be able to criteria.
* @param The type this criteria listStream will return
* @return generic listStream decorated with criteria features.
*/
public static List $q( final List list, Class... classes ) {
return listQuery( list, true, true, classes );
}
/**
* $c turns a listStream back into a regular listStream.
* This is the reverse of $q.
*
* @param list the listStream
* @param the type of the listStream.
* @return the new decorated listStream.
* @see Collections#plainList(java.util.List)
*/
public static List $c( final List list ) {
return plainList( list );
}
/**
* $c turns a listStream back into a regular listStream.
* This is the reverse of $q.
*
* @param list the listStream
* @param the type of the listStream.
* @return the new decorated listStream.
* @see Collections#$c(java.util.List)
*/
private static List plainList( List list ) {
if ( list instanceof QList ) {
return ( ( QList ) list ).list;
} else {
return list;
}
}
/**
* listQuery turns a listStream into a querying listStream.
*
* @param list the listStream you want to convert
* @param The type this criteria listStream will return
* @return generic listStream decorated with criteria features.
* @see Collections#$q(java.util.List, Class[])
*/
public static List listQuery( final List list ) {
return listQuery( list, true, true );
}
/**
* listQuery turns a listStream into a querying listStream.
*
* @param list the listStream you want to convert
* @param classes classes you want to be able to criteria.
* @param The type this criteria listStream will return
* @param useField use the field instead of the property
* @param useUnSafe use unsafe
* @param classes listStream of classes that we can criteria against, these can be component classes
* @return generic listStream decorated with criteria features.
*/
public static List listQuery( final List list, boolean useField, boolean useUnSafe, Class... classes ) {
if ( list == null || list.size() == 0 ) {
return list;
}
SearchableCollectionComposer query = null;
if ( classes == null || classes.length == 0 ) {
Class clazz = list.get( 0 ).getClass();
query = getSearchableCollectionComposer( list, useField, useUnSafe, clazz );
} else {
query = getSearchableCollectionComposer( list, useField, useUnSafe, classes );
}
return new QList( list, ( SearchableCollection ) query );
}
/**
* Decorates a set with additional criteria capabilities.
*
* @param set set to decorate
* @param generic type
* @return new decorated listStream
*/
public static Set $q( final Set set ) {
return setQuery( set, true, true );
}
/**
* Un-decorates a set with additional criteria capabilities.
*
* @param set set to un-decorate
* @param generic type
* @return new decorated listStream
*/
public static Set $c( final Set set ) {
return plainSet( set );
}
/**
* Un-decorates a set with additional criteria capabilities.
*
* @param set set to un-decorate
* @param generic type
* @return new decorated listStream
*/
private static Set plainSet( Set set ) {
if ( set instanceof QSet ) {
return ( ( QSet ) set ).set;
} else {
return set;
}
}
/**
* Decorates a set with additional criteria capabilities.
*
* @param set set to un-decorate
* @param generic type
* @return new decorated listStream
*/
public static Set setQuery( final Set set ) {
return setQuery( set, true, true );
}
/**
* Decorates a set with all sorts of chocolaty richness
*
* @param set
* @param useField
* @param useUnSafe
* @param
* @return
*/
public static Set setQuery( final Set set, boolean useField, boolean useUnSafe ) {
if ( set == null || set.size() == 0 ) {
return set;
}
Class clazz = set.iterator().next().getClass();
SearchableCollectionComposer query = getSearchableCollectionComposer( set, useField, useUnSafe, clazz );
return new QSet( set, ( SearchableCollection ) query );
}
/**
* This is the internal method that does it all. :)
*
* @param set
* @param useField
* @param useUnSafe
* @param classes
* @param
* @return
*/
private static SearchableCollectionComposer getSearchableCollectionComposer( Collection set, boolean useField, boolean useUnSafe, Class... classes ) {
SearchableCollectionComposer query = SPIFactory.getSearchableCollectionFactory().get();
Map fields = new LinkedHashMap<>();
for ( Class cls : classes ) {
Map fieldsSubType
= BeanUtils.getFieldsFromObject( cls );
for ( String sKey : fieldsSubType.keySet() ) {
if ( !fields.containsKey( sKey ) ) {
fields.put( sKey, fieldsSubType.get( sKey ) );
}
}
}
String primaryKey = findPrimaryKey( fields );
FieldAccess field = fields.get( primaryKey );
Function keyGetter = createKeyGetter( field );
query.setFields( fields );
query.setPrimaryKeyGetter( keyGetter );
query.setPrimaryKeyName( primaryKey );
Filter filter = SPIFactory.getFilterFactory().get();
query.setFilter( filter );
LookupIndex index = SPIFactory.getUniqueLookupIndexFactory().apply( fields.get( primaryKey ).type() );
index.setKeyGetter( keyGetter );
( ( SearchableCollection ) query ).addLookupIndex( primaryKey, index );
for ( FieldAccess f : fields.values() ) {
if ( f.name().equals( primaryKey ) ) {
continue;
}
if ( Typ.isBasicType( f.type() ) ) {
configIndexes( ( SearchableCollection ) query, f.name(), fields );
}
}
query.init();
query.setFilter( new FilterWithSimpleCache( filter ) );
( ( SearchableCollection ) query ).addAll( set );
return query;
}
/**
* Allow you to criteria a criteria-able listStream.
*
* @param list the listStream you want to criteria
* @param expressions array of expressions
* @param the type of the listStream
* @return the criteria results or an empty listStream if the listStream was not a criteria-able listStream.
*/
public static List query( final List list, Criteria... expressions ) {
if ( list instanceof QList ) {
QList qlist = ( QList ) list;
return qlist.searchCollection().query( expressions );
} else {
throw new DataRepoException( "Not a criteria-able listStream." );
}
}
/**
* Allow you to criteria a criteria-able listStream.
*
* @param list the listStream you want to criteria
* @param expressions array of expressions
* @param the type of the listStream
* @return the criteria results or an empty listStream if the listStream was not a criteria-able listStream.
*/
public static List sortedQuery( final List list, String sortBy, Criteria... expressions ) {
if ( list instanceof QList ) {
QList qlist = ( QList ) list;
return qlist.searchCollection().sortedQuery( sortBy, expressions );
} else {
throw new DataRepoException( "Not a criteria-able listStream." );
}
}
/**
* Allow you to criteria a criteria-able listStream.
*
* @param set the set you want to criteria
* @param expressions array of expressions
* @param the type of the listStream
* @return the criteria results or an empty listStream if the listStream was not a criteria-able listStream.
*/
public static List query( final Set set, Criteria... expressions ) {
if ( set instanceof QSet ) {
QSet qset = ( QSet ) set;
return qset.searchCollection().query( expressions );
}
return null;
}
/**
* Allow you to criteria a criteria-able listStream.
*
* @param set the set you want to criteria
* @param expressions array of expressions
* @param the type of the listStream
* @return the criteria results or an empty listStream if the listStream was not a criteria-able listStream.
*/
public static List sortedQuery( final Set set, String sortBy, Criteria... expressions ) {
if ( set instanceof QSet ) {
QSet qset = ( QSet ) set;
return qset.searchCollection().sortedQuery( sortBy, expressions );
}
return null;
}
/**
* placeholder for a generic way to discover a primary key.
* Right now the primarykey must be called id.
*
* @param fields fields we are going to search for the primary key
* @return
*/
private static String findPrimaryKey( Map fields ) {
return "id";
}
/**
* Create key getter.
*
* @param field
* @return
*/
private static Function createKeyGetter( final FieldAccess field ) {
requireNonNull( field, "field cannot be null" );
return new Function() {
@Override
public Object apply( Object o ) {
if ( Fields.hasField( o.getClass(), field.name() ) ) {
return field.getValue( o );
} else {
return null;
}
}
};
}
/**
* Helper class that holds an inner set and a searchable collection.
* TODO we need a navigable version of this.
*
* @param
*/
static class QSet extends AbstractSet implements CollectionDecorator {
final Set set;
final SearchableCollection searchCollection;
QSet( Set set, SearchableCollection searchCollection ) {
this.set = set;
this.searchCollection = searchCollection;
}
@Override
public boolean add( T item ) {
searchCollection.add( item );
return set.add( item );
}
@Override
public boolean remove( Object item ) {
searchCollection.delete( ( T ) item );
return set.remove( item );
}
@Override
public Iterator iterator() {
return set.iterator();
}
@Override
public int size() {
return set.size();
}
@Override
public SearchableCollection searchCollection() {
return searchCollection;
}
@Override
public Collection collection() {
return set;
}
}
/**
* @param
*/
static class QList extends AbstractList implements CollectionDecorator {
List list;
SearchableCollection query;
QList( List list, SearchableCollection query ) {
this.list = list;
this.query = query;
}
@Override
public boolean add( T item ) {
query.add( item );
return list.add( item );
}
@Override
public boolean remove( Object item ) {
query.delete( ( T ) item );
return list.remove( item );
}
@Override
public T get( int index ) {
return list.get( index );
}
@Override
public int size() {
return list.size();
}
@Override
public SearchableCollection searchCollection() {
return query;
}
@Override
public Collection collection() {
return this.list;
}
}
/**
* Configures the indexes.
*
* @param query the search criteria
* @param prop the prop
* @param fields the reflected fields
*/
private static void configIndexes( SearchableCollection query, String prop,
Map fields ) {
SearchIndex searchIndex = SPIFactory.getSearchIndexFactory().apply( fields.get( prop ).type() );
searchIndex.init();
Function kg = createKeyGetter( fields.get( prop ) );
searchIndex.setKeyGetter( kg );
query.addSearchIndex( prop, searchIndex );
LookupIndex index = SPIFactory.getLookupIndexFactory().apply( fields.get( prop ).type() );
index.setKeyGetter( kg );
query.addLookupIndex( prop, index );
}
}