10 changed files with 0 additions and 1210 deletions
@ -1,201 +0,0 @@
@@ -1,201 +0,0 @@
|
||||
/* |
||||
* Copyright 2014 the original author or authors. |
||||
* |
||||
* 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.springframework.data.keyvalue.ehcache; |
||||
|
||||
import java.beans.PropertyDescriptor; |
||||
import java.io.Serializable; |
||||
import java.lang.reflect.Field; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.Map; |
||||
|
||||
import net.sf.ehcache.Cache; |
||||
import net.sf.ehcache.CacheManager; |
||||
import net.sf.ehcache.Element; |
||||
import net.sf.ehcache.config.CacheConfiguration; |
||||
import net.sf.ehcache.config.SearchAttribute; |
||||
import net.sf.ehcache.config.Searchable; |
||||
import net.sf.ehcache.search.Attribute; |
||||
import net.sf.ehcache.search.Direction; |
||||
import net.sf.ehcache.search.expression.Criteria; |
||||
|
||||
import org.springframework.beans.BeanUtils; |
||||
import org.springframework.core.convert.converter.Converter; |
||||
import org.springframework.data.keyvalue.core.AbstractKeyValueAdapter; |
||||
import org.springframework.data.keyvalue.core.QueryEngine; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.ClassUtils; |
||||
import org.springframework.util.ReflectionUtils; |
||||
import org.springframework.util.ReflectionUtils.FieldCallback; |
||||
|
||||
/** |
||||
* @author Christoph Strobl |
||||
*/ |
||||
public class EhCacheKeyValueAdapter extends AbstractKeyValueAdapter { |
||||
|
||||
private CacheManager cacheManager; |
||||
|
||||
public EhCacheKeyValueAdapter() { |
||||
this(CacheManager.create()); |
||||
} |
||||
|
||||
public EhCacheKeyValueAdapter(CacheManager cacheManager) { |
||||
this.cacheManager = cacheManager; |
||||
} |
||||
|
||||
public EhCacheKeyValueAdapter( |
||||
QueryEngine<EhCacheKeyValueAdapter, Criteria, Map<Attribute<?>, Direction>> queryEngine, CacheManager cacheManager) { |
||||
super(queryEngine); |
||||
this.cacheManager = cacheManager; |
||||
} |
||||
|
||||
@Override |
||||
public Object put(Serializable id, Object item, Serializable keyspace) { |
||||
|
||||
Assert.notNull(id, "Id must not be 'null' for adding."); |
||||
Assert.notNull(item, "Item must not be 'null' for adding."); |
||||
|
||||
Element element = new Element(id, item); |
||||
getCache(keyspace, item.getClass()).put(element); |
||||
return item; |
||||
} |
||||
|
||||
@Override |
||||
public boolean contains(Serializable id, Serializable keyspace) { |
||||
return get(id, keyspace) != null; |
||||
} |
||||
|
||||
@Override |
||||
public Object get(Serializable id, Serializable keyspace) { |
||||
|
||||
Cache cache = getCache(keyspace); |
||||
if (cache == null) { |
||||
return null; |
||||
} |
||||
|
||||
Element element = cache.get(id); |
||||
return ElementConverter.INSTANCE.convert(element); |
||||
} |
||||
|
||||
@Override |
||||
public Object delete(Serializable id, Serializable keyspace) { |
||||
|
||||
Cache cache = getCache(keyspace); |
||||
if (cache == null) { |
||||
return null; |
||||
} |
||||
|
||||
Element element = cache.removeAndReturnElement(id); |
||||
return ElementConverter.INSTANCE.convert(element); |
||||
} |
||||
|
||||
@Override |
||||
public Collection<?> getAllOf(Serializable keyspace) { |
||||
|
||||
Cache cache = getCache(keyspace); |
||||
if (cache == null) { |
||||
return Collections.emptyList(); |
||||
} |
||||
|
||||
Collection<Element> values = cache.getAll(cache.getKeys()).values(); |
||||
return new ListConverter<Element, Object>(ElementConverter.INSTANCE).convert(values); |
||||
} |
||||
|
||||
@Override |
||||
public void deleteAllOf(Serializable keyspace) { |
||||
|
||||
Cache cache = getCache(keyspace); |
||||
if (cache == null) { |
||||
return; |
||||
} |
||||
|
||||
cache.removeAll(); |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
cacheManager.clearAll(); |
||||
} |
||||
|
||||
protected Cache getCache(Serializable collection) { |
||||
return getCache(collection, null); |
||||
} |
||||
|
||||
protected Cache getCache(Serializable collection, final Class<?> type) { |
||||
|
||||
Assert.notNull(collection, "Collection must not be 'null' for lookup."); |
||||
Assert.isInstanceOf(String.class, collection, "Collection identifier must be of type String."); |
||||
|
||||
Class<?> userType = ClassUtils.getUserClass(type); |
||||
String collectionName = (String) collection; |
||||
|
||||
if (!cacheManager.cacheExists(collectionName)) { |
||||
|
||||
if (type == null) { |
||||
return null; |
||||
} |
||||
|
||||
CacheConfiguration cacheConfig = cacheManager.getConfiguration().getDefaultCacheConfiguration().clone(); |
||||
|
||||
if (!cacheConfig.isSearchable()) { |
||||
|
||||
cacheConfig = new CacheConfiguration(); |
||||
cacheConfig.setMaxEntriesLocalHeap(0); |
||||
} |
||||
cacheConfig.setName(collectionName); |
||||
final Searchable s = new Searchable(); |
||||
|
||||
// TODO: maybe use mappingcontex information at this point or register generic type using some spel expression
|
||||
// validator
|
||||
ReflectionUtils.doWithFields(userType, new FieldCallback() { |
||||
|
||||
@Override |
||||
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { |
||||
|
||||
PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(type, field.getName()); |
||||
|
||||
if (pd != null && pd.getReadMethod() != null) { |
||||
s.addSearchAttribute(new SearchAttribute().name(field.getName()).expression( |
||||
"value." + pd.getReadMethod().getName() + "()")); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
cacheConfig.addSearchable(s); |
||||
cacheManager.addCache(new Cache(cacheConfig)); |
||||
} |
||||
return cacheManager.getCache(collectionName); |
||||
} |
||||
|
||||
private enum ElementConverter implements Converter<Element, Object> { |
||||
INSTANCE; |
||||
|
||||
@Override |
||||
public Object convert(Element source) { |
||||
|
||||
if (source == null) { |
||||
return null; |
||||
} |
||||
return source.getObjectValue(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void destroy() throws Exception { |
||||
this.cacheManager.shutdown(); |
||||
} |
||||
|
||||
} |
||||
@ -1,153 +0,0 @@
@@ -1,153 +0,0 @@
|
||||
/* |
||||
* Copyright 2014 the original author or authors. |
||||
* |
||||
* 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.springframework.data.keyvalue.ehcache; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
|
||||
import net.sf.ehcache.Cache; |
||||
import net.sf.ehcache.search.Attribute; |
||||
import net.sf.ehcache.search.Direction; |
||||
import net.sf.ehcache.search.Query; |
||||
import net.sf.ehcache.search.Result; |
||||
import net.sf.ehcache.search.Results; |
||||
import net.sf.ehcache.search.expression.Criteria; |
||||
|
||||
import org.springframework.core.convert.converter.Converter; |
||||
import org.springframework.data.domain.Sort; |
||||
import org.springframework.data.keyvalue.core.CriteriaAccessor; |
||||
import org.springframework.data.keyvalue.core.QueryEngine; |
||||
import org.springframework.data.keyvalue.core.SortAccessor; |
||||
import org.springframework.data.keyvalue.core.query.KeyValueQuery; |
||||
import org.springframework.util.CollectionUtils; |
||||
|
||||
/** |
||||
* @author Christoph Strobl |
||||
*/ |
||||
public class EhCacheQueryEngine extends QueryEngine<EhCacheKeyValueAdapter, Criteria, Map<Attribute<?>, Direction>> { |
||||
|
||||
public EhCacheQueryEngine() { |
||||
super(EhCacheCriteriaAccessor.INSTANCE, EhCacheSortAccessor.INSTNANCE); |
||||
} |
||||
|
||||
@Override |
||||
public Collection<?> execute(Criteria criteria, Map<Attribute<?>, Direction> sort, int offset, int rows, |
||||
Serializable keyspace) { |
||||
|
||||
Query cacheQuery = prepareQuery(criteria, sort, keyspace); |
||||
if (cacheQuery == null) { |
||||
return Collections.emptyList(); |
||||
} |
||||
|
||||
Results result = cacheQuery.execute(); |
||||
|
||||
ListConverter<Result, Object> listConc = new ListConverter<Result, Object>(ResultConverter.INSTANCE); |
||||
|
||||
if (rows > 0 && offset >= 0) { |
||||
return listConc.convert(result.range(offset, rows)); |
||||
} |
||||
return listConc.convert(result.all()); |
||||
} |
||||
|
||||
@Override |
||||
public long count(Criteria criteria, Serializable keyspace) { |
||||
|
||||
Query q = prepareQuery(criteria, null, keyspace); |
||||
if (q == null) { |
||||
return 0; |
||||
} |
||||
|
||||
return q.execute().size(); |
||||
} |
||||
|
||||
private Query prepareQuery(Criteria criteria, Map<Attribute<?>, Direction> sort, Serializable keyspace) { |
||||
|
||||
Cache cache = getAdapter().getCache(keyspace); |
||||
if (cache == null) { |
||||
return null; |
||||
} |
||||
|
||||
Query cacheQuery = cache.createQuery().includeValues(); |
||||
|
||||
if (criteria != null) { |
||||
cacheQuery.addCriteria(criteria); |
||||
} |
||||
|
||||
if (!CollectionUtils.isEmpty(sort)) { |
||||
for (Map.Entry<Attribute<?>, Direction> order : sort.entrySet()) { |
||||
cacheQuery.addOrderBy(order.getKey(), order.getValue()); |
||||
} |
||||
} |
||||
cacheQuery.end(); |
||||
return cacheQuery; |
||||
} |
||||
|
||||
static enum EhCacheCriteriaAccessor implements CriteriaAccessor<Criteria> { |
||||
INSTANCE; |
||||
|
||||
@Override |
||||
public Criteria resolve(KeyValueQuery<?> query) { |
||||
|
||||
if (query == null || query.getCritieria() == null) { |
||||
return null; |
||||
} |
||||
|
||||
if (query.getCritieria() instanceof Criteria) { |
||||
return (Criteria) query.getCritieria(); |
||||
} |
||||
|
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
} |
||||
|
||||
static enum EhCacheSortAccessor implements SortAccessor<Map<Attribute<?>, Direction>> { |
||||
|
||||
INSTNANCE; |
||||
|
||||
@SuppressWarnings({ "rawtypes" }) |
||||
@Override |
||||
public Map<Attribute<?>, Direction> resolve(KeyValueQuery<?> query) { |
||||
|
||||
if (query == null || query.getSort() == null) { |
||||
return null; |
||||
} |
||||
|
||||
Map<Attribute<?>, Direction> attributes = new LinkedHashMap<Attribute<?>, Direction>(); |
||||
|
||||
for (Sort.Order order : query.getSort()) { |
||||
attributes.put(new Attribute(order.getProperty()), org.springframework.data.domain.Sort.Direction.ASC |
||||
.equals(order.getDirection()) ? net.sf.ehcache.search.Direction.ASCENDING |
||||
: net.sf.ehcache.search.Direction.DESCENDING); |
||||
} |
||||
|
||||
return attributes; |
||||
} |
||||
} |
||||
|
||||
static enum ResultConverter implements Converter<Result, Object> { |
||||
INSTANCE; |
||||
|
||||
@Override |
||||
public Object convert(Result source) { |
||||
return source.getValue(); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,50 +0,0 @@
@@ -1,50 +0,0 @@
|
||||
/* |
||||
* Copyright 2014 the original author or authors. |
||||
* |
||||
* 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.springframework.data.keyvalue.ehcache; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.springframework.core.convert.converter.Converter; |
||||
|
||||
/** |
||||
* @author Christoph Strobl |
||||
* @param <S> |
||||
* @param <T> |
||||
*/ |
||||
public class ListConverter<S, T> implements Converter<Iterable<S>, List<T>> { |
||||
|
||||
private Converter<S, T> itemConverter; |
||||
|
||||
/** |
||||
* @param itemConverter The {@link Converter} to use for converting individual List items |
||||
*/ |
||||
public ListConverter(Converter<S, T> itemConverter) { |
||||
this.itemConverter = itemConverter; |
||||
} |
||||
|
||||
public List<T> convert(Iterable<S> source) { |
||||
if (source == null) { |
||||
return null; |
||||
} |
||||
List<T> results = new ArrayList<T>(); |
||||
for (S result : source) { |
||||
results.add(itemConverter.convert(result)); |
||||
} |
||||
return results; |
||||
} |
||||
|
||||
} |
||||
@ -1,38 +0,0 @@
@@ -1,38 +0,0 @@
|
||||
/* |
||||
* Copyright 2014 the original author or authors. |
||||
* |
||||
* 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.springframework.data.keyvalue.ehcache.repository.config; |
||||
|
||||
import java.lang.annotation.Annotation; |
||||
|
||||
import org.springframework.data.keyvalue.repository.config.KeyValueRepositoriesRegistrar; |
||||
|
||||
/** |
||||
* Special {@link KeyValueRepositoriesRegistrar} to point the infrastructure to evaluate |
||||
* {@link EnableEhCacheRepositories}. |
||||
* |
||||
* @author Oliver Gierke |
||||
*/ |
||||
class EhCacheRepositoriesRegistrar extends KeyValueRepositoriesRegistrar { |
||||
|
||||
/* |
||||
* (non-Javadoc) |
||||
* @see org.springframework.data.keyvalue.repository.config.KeyValueRepositoriesRegistrar#getAnnotation() |
||||
*/ |
||||
@Override |
||||
protected Class<? extends Annotation> getAnnotation() { |
||||
return EnableEhCacheRepositories.class; |
||||
} |
||||
} |
||||
@ -1,123 +0,0 @@
@@ -1,123 +0,0 @@
|
||||
/* |
||||
* Copyright 2014 the original author or authors. |
||||
* |
||||
* 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.springframework.data.keyvalue.ehcache.repository.config; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Inherited; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
import org.springframework.beans.factory.FactoryBean; |
||||
import org.springframework.context.annotation.ComponentScan.Filter; |
||||
import org.springframework.context.annotation.Import; |
||||
import org.springframework.data.keyvalue.core.KeyValueOperations; |
||||
import org.springframework.data.keyvalue.ehcache.repository.query.EhCacheQueryCreator; |
||||
import org.springframework.data.keyvalue.repository.config.QueryCreatorType; |
||||
import org.springframework.data.keyvalue.repository.support.KeyValueRepositoryFactoryBean; |
||||
import org.springframework.data.repository.query.QueryLookupStrategy; |
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key; |
||||
|
||||
/** |
||||
* Annotation to activate EhCache repositories. If no base package is configured through either {@link #value()}, |
||||
* {@link #basePackages()} or {@link #basePackageClasses()} it will trigger scanning of the package of annotated class. |
||||
* |
||||
* @author Christoph Strobl |
||||
*/ |
||||
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE }) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
@Inherited |
||||
@Import(EhCacheRepositoriesRegistrar.class) |
||||
@QueryCreatorType(EhCacheQueryCreator.class) |
||||
public @interface EnableEhCacheRepositories { |
||||
|
||||
/** |
||||
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.: |
||||
* {@code @EnableJpaRepositories("org.my.pkg")} instead of {@code @EnableJpaRepositories(basePackages="org.my.pkg")}. |
||||
*/ |
||||
String[] value() default {}; |
||||
|
||||
/** |
||||
* Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this |
||||
* attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names. |
||||
*/ |
||||
String[] basePackages() default {}; |
||||
|
||||
/** |
||||
* Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for annotated components. The |
||||
* package of each class specified will be scanned. Consider creating a special no-op marker class or interface in |
||||
* each package that serves no purpose other than being referenced by this attribute. |
||||
*/ |
||||
Class<?>[] basePackageClasses() default {}; |
||||
|
||||
/** |
||||
* Specifies which types are not eligible for component scanning. |
||||
*/ |
||||
Filter[] excludeFilters() default {}; |
||||
|
||||
/** |
||||
* Specifies which types are eligible for component scanning. Further narrows the set of candidate components from |
||||
* everything in {@link #basePackages()} to everything in the base packages that matches the given filter or filters. |
||||
*/ |
||||
Filter[] includeFilters() default {}; |
||||
|
||||
/** |
||||
* Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So |
||||
* for a repository named {@code PersonRepository} the corresponding implementation class will be looked up scanning |
||||
* for {@code PersonRepositoryImpl}. |
||||
* |
||||
* @return |
||||
*/ |
||||
String repositoryImplementationPostfix() default "Impl"; |
||||
|
||||
/** |
||||
* Configures the location of where to find the Spring Data named queries properties file. |
||||
* |
||||
* @return |
||||
*/ |
||||
String namedQueriesLocation() default ""; |
||||
|
||||
/** |
||||
* Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to |
||||
* {@link Key#CREATE_IF_NOT_FOUND}. |
||||
* |
||||
* @return |
||||
*/ |
||||
Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND; |
||||
|
||||
/** |
||||
* Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to |
||||
* {@link KeyValueRepositoryFactoryBean}. |
||||
* |
||||
* @return |
||||
*/ |
||||
Class<?> repositoryFactoryBeanClass() default KeyValueRepositoryFactoryBean.class; |
||||
|
||||
/** |
||||
* Configures the name of the {@link KeyValueOperations} bean to be used with the repositories detected. |
||||
* |
||||
* @return |
||||
*/ |
||||
String keyValueTemplateRef() default "keyValueTemplate"; |
||||
|
||||
/** |
||||
* Configures whether nested repository-interfaces (e.g. defined as inner classes) should be discovered by the |
||||
* repositories infrastructure. |
||||
*/ |
||||
boolean considerNestedRepositories() default false; |
||||
} |
||||
@ -1,127 +0,0 @@
@@ -1,127 +0,0 @@
|
||||
/* |
||||
* Copyright 2014 the original author or authors. |
||||
* |
||||
* 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.springframework.data.keyvalue.ehcache.repository.query; |
||||
|
||||
import java.util.Iterator; |
||||
|
||||
import net.sf.ehcache.search.expression.Criteria; |
||||
import net.sf.ehcache.search.expression.EqualTo; |
||||
import net.sf.ehcache.search.expression.GreaterThan; |
||||
import net.sf.ehcache.search.expression.ILike; |
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException; |
||||
import org.springframework.data.domain.Sort; |
||||
import org.springframework.data.keyvalue.core.query.KeyValueQuery; |
||||
import org.springframework.data.repository.query.ParameterAccessor; |
||||
import org.springframework.data.repository.query.parser.AbstractQueryCreator; |
||||
import org.springframework.data.repository.query.parser.Part; |
||||
import org.springframework.data.repository.query.parser.PartTree; |
||||
|
||||
/** |
||||
* @author Christoph Strobl |
||||
*/ |
||||
public class EhCacheQueryCreator extends AbstractQueryCreator<KeyValueQuery<Criteria>, Criteria> { |
||||
|
||||
/** |
||||
* Creates a new {@link EhCacheQueryCreator} for the given {@link PartTree}. |
||||
* |
||||
* @param tree must not be {@literal null}. |
||||
*/ |
||||
public EhCacheQueryCreator(PartTree tree) { |
||||
super(tree); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new {@link EhCacheQueryCreator} for the given {@link PartTree} and {@link ParameterAccessor}. The latter |
||||
* is used to hand actual parameter values into the callback methods as well as to apply dynamic sorting via a |
||||
* {@link Sort} parameter. |
||||
* |
||||
* @param tree must not be {@literal null}. |
||||
* @param parameters can be {@literal null}. |
||||
*/ |
||||
public EhCacheQueryCreator(PartTree tree, ParameterAccessor parameters) { |
||||
super(tree, parameters); |
||||
} |
||||
|
||||
/* |
||||
|
||||
* (non-Javadoc) |
||||
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#create(org.springframework.data.repository.query.parser.Part, java.util.Iterator) |
||||
*/ |
||||
@Override |
||||
protected Criteria create(Part part, Iterator<Object> iterator) { |
||||
return from(part, iterator); |
||||
} |
||||
|
||||
/* |
||||
* (non-Javadoc) |
||||
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#and(org.springframework.data.repository.query.parser.Part, java.lang.Object, java.util.Iterator) |
||||
*/ |
||||
@Override |
||||
protected Criteria and(Part part, Criteria base, Iterator<Object> iterator) { |
||||
|
||||
if (base == null) { |
||||
return create(part, iterator); |
||||
} |
||||
return base.and(from(part, iterator)); |
||||
} |
||||
|
||||
/* |
||||
* (non-Javadoc) |
||||
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#or(java.lang.Object, java.lang.Object) |
||||
*/ |
||||
@Override |
||||
protected Criteria or(Criteria base, Criteria criteria) { |
||||
return base.or(criteria); |
||||
} |
||||
|
||||
/* |
||||
* (non-Javadoc) |
||||
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#complete(java.lang.Object, org.springframework.data.domain.Sort) |
||||
*/ |
||||
@Override |
||||
protected KeyValueQuery<Criteria> complete(Criteria criteria, Sort sort) { |
||||
|
||||
KeyValueQuery<Criteria> query = new KeyValueQuery<Criteria>(criteria); |
||||
if (sort != null) { |
||||
query.orderBy(sort); |
||||
} |
||||
return query; |
||||
} |
||||
|
||||
private Criteria from(Part part, Iterator<Object> iterator) { |
||||
|
||||
// TODO: complete list of supported types
|
||||
switch (part.getType()) { |
||||
case TRUE: |
||||
return new EqualTo(part.getProperty().toDotPath(), true); |
||||
case FALSE: |
||||
return new EqualTo(part.getProperty().toDotPath(), true); |
||||
case SIMPLE_PROPERTY: |
||||
return new EqualTo(part.getProperty().toDotPath(), iterator.next()); |
||||
case IS_NULL: |
||||
return new EqualTo(part.getProperty().toDotPath(), null); |
||||
case STARTING_WITH: |
||||
case LIKE: |
||||
return new ILike(part.getProperty().toDotPath(), iterator.next() + "*"); |
||||
case GREATER_THAN: |
||||
return new GreaterThan(part.getProperty().toDotPath(), iterator.next()); |
||||
|
||||
default: |
||||
throw new InvalidDataAccessApiUsageException(String.format("Found invalid part '%s' in query", part.getType())); |
||||
} |
||||
} |
||||
} |
||||
@ -1,405 +0,0 @@
@@ -1,405 +0,0 @@
|
||||
/* |
||||
* Copyright 2014 the original author or authors. |
||||
* |
||||
* 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.springframework.data.keyvalue.ehcache; |
||||
|
||||
import static org.hamcrest.collection.IsCollectionWithSize.*; |
||||
import static org.hamcrest.collection.IsEmptyCollection.*; |
||||
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.*; |
||||
import static org.hamcrest.core.Is.*; |
||||
import static org.hamcrest.core.IsNull.*; |
||||
import static org.hamcrest.core.IsSame.*; |
||||
import static org.junit.Assert.*; |
||||
|
||||
import java.io.Serializable; |
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
import java.util.List; |
||||
|
||||
import net.sf.ehcache.CacheManager; |
||||
import net.sf.ehcache.search.expression.Criteria; |
||||
import net.sf.ehcache.search.expression.EqualTo; |
||||
|
||||
import org.junit.After; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.springframework.dao.InvalidDataAccessApiUsageException; |
||||
import org.springframework.data.annotation.Id; |
||||
import org.springframework.data.annotation.Persistent; |
||||
import org.springframework.data.keyvalue.annotation.KeySpace; |
||||
import org.springframework.data.keyvalue.core.KeyValueTemplate; |
||||
import org.springframework.data.keyvalue.core.query.KeyValueQuery; |
||||
import org.springframework.util.ObjectUtils; |
||||
|
||||
/** |
||||
* @author Christoph Strobl |
||||
*/ |
||||
public class KeyValueTemplateTestsUsingEhCache { |
||||
|
||||
private static final Foo FOO_ONE = new Foo("one"); |
||||
private static final Foo FOO_TWO = new Foo("two"); |
||||
private static final Foo FOO_THREE = new Foo("three"); |
||||
private static final Bar BAR_ONE = new Bar("one"); |
||||
private static final ClassWithTypeAlias ALIASED = new ClassWithTypeAlias("super"); |
||||
private static final SubclassOfAliasedType SUBCLASS_OF_ALIASED = new SubclassOfAliasedType("sub"); |
||||
|
||||
private static final KeyValueQuery<Criteria> CACHE_QUERY = new KeyValueQuery<Criteria>(new EqualTo("foo", "two")); |
||||
|
||||
private KeyValueTemplate operations; |
||||
|
||||
@Before |
||||
public void setUp() throws InstantiationException, IllegalAccessException { |
||||
this.operations = new KeyValueTemplate(new EhCacheKeyValueAdapter(new EhCacheQueryEngine(), CacheManager.create())); |
||||
} |
||||
|
||||
@After |
||||
public void tearDown() throws Exception { |
||||
this.operations.destroy(); |
||||
} |
||||
|
||||
@Test |
||||
public void insertShouldNotThorwErrorWhenExecutedHavingNonExistingIdAndNonNullValue() { |
||||
operations.insert("1", FOO_ONE); |
||||
} |
||||
|
||||
@Test(expected = IllegalArgumentException.class) |
||||
public void insertShouldThrowExceptionForNullId() { |
||||
operations.insert(null, FOO_ONE); |
||||
} |
||||
|
||||
@Test(expected = IllegalArgumentException.class) |
||||
public void insertShouldThrowExceptionForNullObject() { |
||||
operations.insert("some-id", null); |
||||
} |
||||
|
||||
@Test(expected = InvalidDataAccessApiUsageException.class) |
||||
public void insertShouldThrowExecptionWhenObjectOfSameTypeAlreadyExists() { |
||||
|
||||
operations.insert("1", FOO_ONE); |
||||
operations.insert("1", FOO_TWO); |
||||
} |
||||
|
||||
@Test |
||||
public void insertShouldWorkCorrectlyWhenObjectsOfDifferentTypesWithSameIdAreInserted() { |
||||
|
||||
operations.insert("1", FOO_ONE); |
||||
operations.insert("1", BAR_ONE); |
||||
} |
||||
|
||||
@Test |
||||
public void createShouldReturnSameInstanceGenerateId() { |
||||
|
||||
ClassWithStringId source = new ClassWithStringId(); |
||||
ClassWithStringId target = operations.insert(source); |
||||
|
||||
assertThat(target, sameInstance(source)); |
||||
} |
||||
|
||||
@Test |
||||
public void createShouldRespectExistingId() { |
||||
|
||||
ClassWithStringId source = new ClassWithStringId(); |
||||
source.id = "one"; |
||||
|
||||
operations.insert(source); |
||||
|
||||
assertThat(operations.findById("one", ClassWithStringId.class), is(source)); |
||||
} |
||||
|
||||
@Test |
||||
public void findByIdShouldReturnObjectWithMatchingIdAndType() { |
||||
|
||||
operations.insert("1", FOO_ONE); |
||||
assertThat(operations.findById("1", Foo.class), is(FOO_ONE)); |
||||
} |
||||
|
||||
@Test |
||||
public void findByIdSouldReturnNullIfNoMatchingIdFound() { |
||||
|
||||
operations.insert("1", FOO_ONE); |
||||
assertThat(operations.findById("2", Foo.class), nullValue()); |
||||
} |
||||
|
||||
@Test |
||||
public void findByIdShouldReturnNullIfNoMatchingTypeFound() { |
||||
|
||||
operations.insert("1", FOO_ONE); |
||||
assertThat(operations.findById("1", Bar.class), nullValue()); |
||||
} |
||||
|
||||
@Test |
||||
public void findShouldExecuteQueryCorrectly() { |
||||
|
||||
operations.insert("1", FOO_ONE); |
||||
operations.insert("2", FOO_TWO); |
||||
|
||||
List<Foo> result = (List<Foo>) operations.find(CACHE_QUERY, Foo.class); |
||||
assertThat(result, hasSize(1)); |
||||
assertThat(result.get(0), is(FOO_TWO)); |
||||
} |
||||
|
||||
@Test |
||||
public void readShouldReturnEmptyCollectionIfOffsetOutOfRange() { |
||||
|
||||
operations.insert("1", FOO_ONE); |
||||
operations.insert("2", FOO_TWO); |
||||
operations.insert("3", FOO_THREE); |
||||
|
||||
assertThat(operations.findInRange(5, 5, Foo.class), empty()); |
||||
} |
||||
|
||||
@Test |
||||
public void updateShouldReplaceExistingObject() { |
||||
|
||||
operations.insert("1", FOO_ONE); |
||||
operations.update("1", FOO_TWO); |
||||
assertThat(operations.findById("1", Foo.class), is(FOO_TWO)); |
||||
} |
||||
|
||||
@Test |
||||
public void updateShouldRespectTypeInformation() { |
||||
|
||||
operations.insert("1", FOO_ONE); |
||||
operations.update("1", BAR_ONE); |
||||
|
||||
assertThat(operations.findById("1", Foo.class), is(FOO_ONE)); |
||||
} |
||||
|
||||
@Test |
||||
public void deleteShouldRemoveObjectCorrectly() { |
||||
|
||||
operations.insert("1", FOO_ONE); |
||||
operations.delete("1", Foo.class); |
||||
assertThat(operations.findById("1", Foo.class), nullValue()); |
||||
} |
||||
|
||||
@Test |
||||
public void deleteReturnsNullWhenNotExisting() { |
||||
|
||||
operations.insert("1", FOO_ONE); |
||||
assertThat(operations.delete("2", Foo.class), nullValue()); |
||||
} |
||||
|
||||
@Test |
||||
public void deleteReturnsRemovedObject() { |
||||
|
||||
operations.insert("1", FOO_ONE); |
||||
assertThat(operations.delete("1", Foo.class), is(FOO_ONE)); |
||||
} |
||||
|
||||
@Test(expected = IllegalArgumentException.class) |
||||
public void deleteThrowsExceptionWhenIdCannotBeExctracted() { |
||||
operations.delete(FOO_ONE); |
||||
} |
||||
|
||||
@Test |
||||
public void countShouldReturnZeroWhenNoElementsPresent() { |
||||
assertThat(operations.count(Foo.class), is(0L)); |
||||
} |
||||
|
||||
@Test |
||||
public void insertShouldRespectTypeAlias() { |
||||
|
||||
operations.insert("1", ALIASED); |
||||
operations.insert("2", SUBCLASS_OF_ALIASED); |
||||
|
||||
assertThat(operations.findAll(ALIASED.getClass()), containsInAnyOrder(ALIASED, SUBCLASS_OF_ALIASED)); |
||||
} |
||||
|
||||
static class Foo implements Serializable { |
||||
|
||||
String foo; |
||||
|
||||
public Foo(String foo) { |
||||
this.foo = foo; |
||||
} |
||||
|
||||
public String getFoo() { |
||||
return foo; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return ObjectUtils.nullSafeHashCode(this.foo); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
if (this == obj) { |
||||
return true; |
||||
} |
||||
if (obj == null) { |
||||
return false; |
||||
} |
||||
if (!(obj instanceof Foo)) { |
||||
return false; |
||||
} |
||||
Foo other = (Foo) obj; |
||||
return ObjectUtils.nullSafeEquals(this.foo, other.foo); |
||||
} |
||||
|
||||
} |
||||
|
||||
static class Bar implements Serializable { |
||||
|
||||
String bar; |
||||
|
||||
public Bar(String bar) { |
||||
this.bar = bar; |
||||
} |
||||
|
||||
public String getBar() { |
||||
return bar; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return ObjectUtils.nullSafeHashCode(this.bar); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
if (this == obj) { |
||||
return true; |
||||
} |
||||
if (obj == null) { |
||||
return false; |
||||
} |
||||
if (!(obj instanceof Bar)) { |
||||
return false; |
||||
} |
||||
Bar other = (Bar) obj; |
||||
return ObjectUtils.nullSafeEquals(this.bar, other.bar); |
||||
} |
||||
|
||||
} |
||||
|
||||
static class ClassWithStringId implements Serializable { |
||||
|
||||
@Id String id; |
||||
String value; |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
final int prime = 31; |
||||
int result = 1; |
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.id); |
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.value); |
||||
return result; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
if (this == obj) { |
||||
return true; |
||||
} |
||||
if (obj == null) { |
||||
return false; |
||||
} |
||||
if (!(obj instanceof ClassWithStringId)) { |
||||
return false; |
||||
} |
||||
ClassWithStringId other = (ClassWithStringId) obj; |
||||
if (!ObjectUtils.nullSafeEquals(this.id, other.id)) { |
||||
return false; |
||||
} |
||||
if (!ObjectUtils.nullSafeEquals(this.value, other.value)) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
} |
||||
|
||||
@ExplicitKeySpace(name = "aliased") |
||||
static class ClassWithTypeAlias implements Serializable { |
||||
|
||||
@Id String id; |
||||
String name; |
||||
|
||||
public ClassWithTypeAlias(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
public String getId() { |
||||
return id; |
||||
} |
||||
|
||||
public void setId(String id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
final int prime = 31; |
||||
int result = 1; |
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.id); |
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.name); |
||||
return result; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
if (this == obj) { |
||||
return true; |
||||
} |
||||
if (obj == null) { |
||||
return false; |
||||
} |
||||
if (!(obj instanceof ClassWithTypeAlias)) { |
||||
return false; |
||||
} |
||||
ClassWithTypeAlias other = (ClassWithTypeAlias) obj; |
||||
if (!ObjectUtils.nullSafeEquals(this.id, other.id)) { |
||||
return false; |
||||
} |
||||
if (!ObjectUtils.nullSafeEquals(this.name, other.name)) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
} |
||||
|
||||
static class SubclassOfAliasedType extends ClassWithTypeAlias { |
||||
|
||||
public SubclassOfAliasedType(String name) { |
||||
super(name); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Documented |
||||
@Persistent |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Target({ ElementType.TYPE }) |
||||
private static @interface ExplicitKeySpace { |
||||
|
||||
@KeySpace |
||||
String name() default ""; |
||||
|
||||
} |
||||
} |
||||
@ -1,105 +0,0 @@
@@ -1,105 +0,0 @@
|
||||
/* |
||||
* Copyright 2014 the original author or authors. |
||||
* |
||||
* 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.springframework.data.keyvalue.ehcache.repository.config; |
||||
|
||||
import static org.hamcrest.collection.IsCollectionWithSize.*; |
||||
import static org.hamcrest.core.Is.*; |
||||
import static org.hamcrest.core.IsNull.*; |
||||
import static org.junit.Assert.*; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.List; |
||||
|
||||
import net.sf.ehcache.CacheManager; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.data.annotation.Id; |
||||
import org.springframework.data.keyvalue.core.KeyValueOperations; |
||||
import org.springframework.data.keyvalue.core.KeyValueTemplate; |
||||
import org.springframework.data.keyvalue.ehcache.EhCacheKeyValueAdapter; |
||||
import org.springframework.data.keyvalue.ehcache.EhCacheQueryEngine; |
||||
import org.springframework.data.repository.CrudRepository; |
||||
import org.springframework.test.context.ContextConfiguration; |
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; |
||||
|
||||
/** |
||||
* @author Christoph Strobl |
||||
*/ |
||||
@RunWith(SpringJUnit4ClassRunner.class) |
||||
@ContextConfiguration |
||||
public class EnableEhCacheRepositoriesIntegrationTests { |
||||
|
||||
@Configuration |
||||
@EnableEhCacheRepositories(considerNestedRepositories = true) |
||||
static class Config { |
||||
|
||||
@Bean |
||||
public KeyValueOperations keyValueTemplate() { |
||||
return new KeyValueTemplate(new EhCacheKeyValueAdapter(new EhCacheQueryEngine(), CacheManager.create())); |
||||
} |
||||
} |
||||
|
||||
@Autowired PersonRepository repo; |
||||
|
||||
@Test |
||||
public void shouldEnableKeyValueRepositoryCorrectly() { |
||||
assertThat(repo, notNullValue()); |
||||
|
||||
Person person = new Person(); |
||||
person.setFirstname("foo"); |
||||
repo.save(person); |
||||
|
||||
List<Person> result = repo.findByFirstname("foo"); |
||||
assertThat(result, hasSize(1)); |
||||
assertThat(result.get(0).firstname, is("foo")); |
||||
} |
||||
|
||||
static class Person implements Serializable { |
||||
|
||||
private static final long serialVersionUID = -1654603912377346292L; |
||||
|
||||
@Id String id; |
||||
String firstname; |
||||
|
||||
public String getId() { |
||||
return id; |
||||
} |
||||
|
||||
public void setId(String id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
public String getFirstname() { |
||||
return firstname; |
||||
} |
||||
|
||||
public void setFirstname(String firstname) { |
||||
this.firstname = firstname; |
||||
} |
||||
|
||||
} |
||||
|
||||
static interface PersonRepository extends CrudRepository<Person, String> { |
||||
|
||||
List<Person> findByFirstname(String firstname); |
||||
|
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue