SGF-402 - Add support for Lucene query result projections.

(cherry picked from commit 5113152b8f85c74c799926f53fefea1f80833745)
Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
John Blum
2017-03-17 16:42:30 -07:00
parent 9e2a3011d6
commit 96aefa8f1a
15 changed files with 1584 additions and 62 deletions

View File

@@ -106,6 +106,7 @@ public interface LuceneOperations {
* to execute as well as de/serialize to distribute across the cluster.
* @param projectionFields array of {@link String} values specifying the query projection.
* @return a {@link List} of {@link LuceneResultStruct} containing the query results.
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @see org.apache.geode.cache.lucene.LuceneResultStruct
* @see #query(LuceneQueryProvider, int, String...)
* @see java.util.List
@@ -126,6 +127,7 @@ public interface LuceneOperations {
* @param resultLimit limit on the number of query results to return.
* @param projectionFields array of {@link String} values specifying the query projection.
* @return a {@link List} of {@link LuceneResultStruct} containing the query results.
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @see org.apache.geode.cache.lucene.LuceneResultStruct
* @see java.util.List
*/
@@ -144,6 +146,7 @@ public interface LuceneOperations {
* @param pageSize number of results per page.
* @param projectionFields array of {@link String} values specifying the query projection.
* @return a {@link PageableLuceneQueryResults} data structure containing the results of the Lucene query.
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @see org.apache.geode.cache.lucene.PageableLuceneQueryResults
*/
<K, V> PageableLuceneQueryResults<K, V> query(LuceneQueryProvider queryProvider,
@@ -192,6 +195,7 @@ public interface LuceneOperations {
* @param queryProvider {@link LuceneQueryProvider} is a provider implementation supplying the Lucene query
* to execute as well as de/serialize to distribute across the cluster.
* @return a {@link Collection} of keys matching the Lucene query clause (predicate).
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @see #queryForKeys(String, String, int)
* @see java.util.Collection
*/
@@ -208,6 +212,7 @@ public interface LuceneOperations {
* to execute as well as de/serialize to distribute across the cluster.
* @param resultLimit limit on the number of keys returned.
* @return a {@link Collection} of keys matching the Lucene query clause (predicate).
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @see #queryForKeys(String, String, int)
* @see java.util.Collection
*/
@@ -256,6 +261,7 @@ public interface LuceneOperations {
* @param queryProvider {@link LuceneQueryProvider} is a provider implementation supplying the Lucene query
* to execute as well as de/serialize to distribute across the cluster.
* @return a {@link Collection} of values matching Lucene query clause (predicate).
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @see #queryForValues(String, String, int)
* @see java.util.Collection
*/
@@ -272,6 +278,7 @@ public interface LuceneOperations {
* to execute as well as de/serialize to distribute across the cluster.
* @param resultLimit limit on the number of values returned.
* @return a {@link Collection} of values matching Lucene query clause (predicate).
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @see #queryForValues(String, String, int)
* @see java.util.Collection
*/

View File

@@ -1,62 +0,0 @@
/*
* Copyright 2016 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.gemfire.search.lucene;
import java.util.List;
import org.apache.geode.cache.lucene.LuceneQueryProvider;
import org.springframework.data.domain.Page;
/**
* The {@link MappingLuceneOperations} interface defines a contract for implementing classes to execute
* Lucene data access operations and mapping the results to entity domain {@link Class types}.
*
* @author John Blum
* @see org.springframework.data.domain.Page
* @see org.springframework.data.gemfire.search.lucene.LuceneOperations
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @since 1.1.0
*/
@SuppressWarnings("unused")
public interface MappingLuceneOperations extends LuceneOperations {
default <T> List<T> query(Class<T> entityType, String query, String defaultField,
String... projectionFields) {
return query(entityType, query, defaultField, DEFAULT_RESULT_LIMIT, projectionFields);
}
<T> List<T> query(Class<T> entityType, String query, String defaultField,
int resultLimit, String... projectionFields);
<T> Page<T> query(Class<T> entityType, String query, String defaultField,
int resultLimit, int pageSize, String... projectionFields);
default <T> List<T> query(Class<T> entityType, LuceneQueryProvider queryProvider,
String... projectionFields) {
return query(entityType, queryProvider, DEFAULT_RESULT_LIMIT, projectionFields);
}
<T> List<T> query(Class<T> entityType, LuceneQueryProvider queryProvider,
int resultLimit, String... projectionFields);
<T> Page<T> query(Class<T> entityType, LuceneQueryProvider queryProvider,
int resultLimit, int pageSize, String... projectionFields);
}

View File

@@ -0,0 +1,197 @@
/*
* Copyright 2016 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.gemfire.search.lucene;
import java.util.Optional;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.lucene.LuceneIndex;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.data.gemfire.search.lucene.support.PdxInstanceMethodInterceptorFactory;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
/**
* {@link ProjectingLuceneAccessor} is an abstract class supporting implementations of
* the {@link ProjectingLuceneOperations} interface encapsulating common functionality
* necessary to execute Lucene queries and work with application domain object views.
*
* @author John Blum
* @see java.lang.ClassLoader
* @see org.springframework.beans.factory.BeanClassLoaderAware
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.data.gemfire.search.lucene.ProjectingLuceneOperations
* @see org.springframework.data.gemfire.search.lucene.support.PdxInstanceMethodInterceptorFactory
* @see org.springframework.data.projection.ProjectionFactory
* @see org.springframework.data.projection.SpelAwareProxyProjectionFactory
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.lucene.LuceneIndex
* @see org.apache.geode.cache.lucene.LuceneQuery
* @see org.apache.geode.cache.lucene.LuceneQueryFactory
* @see org.apache.geode.cache.lucene.LuceneService
* @see org.apache.geode.cache.lucene.LuceneServiceProvider
* @since 1.1.0
*/
public abstract class ProjectingLuceneAccessor extends LuceneTemplate
implements BeanClassLoaderAware, BeanFactoryAware, ProjectingLuceneOperations {
private BeanFactory beanFactory;
private ClassLoader beanClassLoader;
private ProjectionFactory projectionFactory;
/**
* Constructs a default, uninitialized instance of the {@link ProjectingLuceneAccessor}.
*/
public ProjectingLuceneAccessor() {
}
/**
* Constructs an instance of the {@link ProjectingLuceneAccessor} initialized with the given {@link LuceneIndex}
* used to perform Lucene queries (searches).
*
* @param luceneIndex {@link LuceneIndex} used in Lucene queries.
* @see org.apache.geode.cache.lucene.LuceneIndex
*/
public ProjectingLuceneAccessor(LuceneIndex luceneIndex) {
super(luceneIndex);
}
/**
* Constructs an instance of the {@link ProjectingLuceneAccessor} initialized with the given Lucene index name
* and {@link Region} reference upon which Lucene queries are executed.
*
* @param indexName {@link String} containing the name of the {@link LuceneIndex} used in Lucene queries.
* @param region {@link Region} on which Lucene queries are executed.
* @see org.apache.geode.cache.Region
*/
public ProjectingLuceneAccessor(String indexName, Region<?, ?> region) {
super(indexName, region);
}
/**
* Constructs an instance of the {@link ProjectingLuceneAccessor} initialized with the given Lucene index name
* and {@link Region} reference upon which Lucene queries are executed.
*
* @param indexName {@link String} containing the name of the {@link LuceneIndex} used in Lucene queries.
* @param regionPath {@link String} containing the name of the {@link Region} on which Lucene queries are executed.
*/
public ProjectingLuceneAccessor(String indexName, String regionPath) {
super(indexName, regionPath);
}
/**
* @inheritDoc
* @see #resolveProjectionFactory()
*/
@Override
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
this.projectionFactory = resolveProjectionFactory();
}
/**
* Null-safe method to resolve the Spring Data {@link ProjectionFactory} used to create projections
* out of the Lucene query results.
*
* @return a resolved instance of the Spring Data {@link ProjectionFactory} used to create projections
* out of the Lucene query results.
* @see org.springframework.data.projection.ProjectionFactory
* @see org.springframework.data.projection.SpelAwareProxyProjectionFactory
* @see #afterPropertiesSet()
*/
protected ProjectionFactory resolveProjectionFactory() {
return Optional.ofNullable(getProjectionFactory()).orElseGet(() -> {
SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory();
projectionFactory.setBeanClassLoader(getBeanClassLoader());
projectionFactory.setBeanFactory(getBeanFactory());
projectionFactory.registerMethodInvokerFactory(PdxInstanceMethodInterceptorFactory.INSTANCE);
return setThenGetProjectionFactory(projectionFactory);
});
}
/**
* @inheritDoc
*/
@Override
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
/**
* Returns a reference to the {@link ClassLoader} used by the Spring {@link BeanFactory container}
* to load bean class definitions.
*
* @return a reference to the {@link ClassLoader} used by the Spring {@link BeanFactory container}
* to load bean class definitions.
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(ClassLoader)
* @see java.lang.ClassLoader
*/
protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
/**
* @inheritDoc
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/**
* Returns a reference to the Spring {@link BeanFactory container}.
*
* @return a reference to the Spring {@link BeanFactory container}.
* @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(BeanFactory)
* @see org.springframework.beans.factory.BeanFactory
*/
protected BeanFactory getBeanFactory() {
return this.beanFactory;
}
protected ProjectionFactory setThenGetProjectionFactory(ProjectionFactory projectionFactory) {
setProjectionFactory(projectionFactory);
return getProjectionFactory();
}
/**
* Sets the Spring Data {@link ProjectionFactory} used to create projections out of query results.
*
* @param projectionFactory Spring Data {@link ProjectionFactory} used to created projects out of query results.
* @see org.springframework.data.projection.ProjectionFactory
*/
public void setProjectionFactory(ProjectionFactory projectionFactory) {
this.projectionFactory = projectionFactory;
}
/**
* Returns the Spring Data {@link ProjectionFactory} used to create projections out of query results.
*
* @return the Spring Data {@link ProjectionFactory} used to created projects out of query results.
* @see org.springframework.data.projection.ProjectionFactory
*/
protected ProjectionFactory getProjectionFactory() {
return this.projectionFactory;
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright 2016 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.gemfire.search.lucene;
import java.util.List;
import org.apache.geode.cache.lucene.LuceneQueryProvider;
import org.springframework.data.domain.Page;
/**
* The {@link ProjectingLuceneOperations} interface defines a contract for implementing classes to execute
* Lucene data access operations and mapping the results to entity domain {@link Class types}.
*
* @author John Blum
* @see java.util.List
* @see org.springframework.data.domain.Page
* @see org.springframework.data.gemfire.search.lucene.LuceneOperations
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @since 1.1.0
*/
@SuppressWarnings("unused")
public interface ProjectingLuceneOperations extends LuceneOperations {
/**
* Executes the given {@link String query} with the results projected as instances of
* the {@link Class projectionType}.
*
* @param <T> {@link Class} type of the projection.
* @param query Lucene {@link String query} to execute.
* @param defaultField {@link String} specifying the default field used in Lucene queries when a field
* is not explicitly defined in the Lucene query clause.
* @param projectionType {@link Class} type of the individual elements in the query results.
* @return a {@link List} of Lucene query results projected as instances of {@link Class projectionType}.
* @see #query(String, String, int, Class)
* @see java.util.List
*/
default <T> List<T> query(String query, String defaultField, Class<T> projectionType) {
return query(query, defaultField, DEFAULT_RESULT_LIMIT, projectionType);
}
/**
* Executes the given {@link String query} with the limited results projected as instances of
* the {@link Class projectionType}.
*
* @param <T> {@link Class} type of the projection.
* @param query Lucene {@link String query} to execute.
* @param defaultField {@link String} specifying the default field used in Lucene queries when a field
* is not explicitly defined in the Lucene query clause.
* @param resultLimit limit on the number of query results to return.
* @param projectionType {@link Class} type of the individual elements in the query results.
* @return a {@link List} of Lucene query results projected as instances of {@link Class projectionType}.
* @see #query(String, String, int, Class)
* @see java.util.List
*/
<T> List<T> query(String query, String defaultField, int resultLimit, Class<T> projectionType);
/**
* Executes the given {@link String query} with the limited results projected as instances of
* the {@link Class projectionType}.
*
* @param <T> {@link Class} type of the projection.
* @param query Lucene {@link String query} to execute.
* @param defaultField {@link String} specifying the default field used in Lucene queries when a field
* is not explicitly defined in the Lucene query clause.
* @param resultLimit limit on the number of query results to return.
* @param pageSize number of results on a {@link Page}.
* @param projectionType {@link Class} type of the individual elements in the query results.
* @return the first {@link Page} of results returned from the Lucene query.
* @see org.springframework.data.domain.Page
*/
<T> Page<T> query(String query, String defaultField, int resultLimit, int pageSize, Class<T> projectionType);
/**
* Executes the provided {@link String query} with the results projected as instances of
* the {@link Class projectionType}.
*
* @param <T> {@link Class} type of the projection.
* @param queryProvider {@link LuceneQueryProvider} providing the Lucene {@link String query} to execute.
* @param projectionType {@link Class} type of the individual elements in the query results.
* @return a {@link List} of Lucene query results projected as instances of {@link Class projectionType}.
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @see #query(LuceneQueryProvider, int, Class)
* @see java.util.List
*/
default <T> List<T> query(LuceneQueryProvider queryProvider, Class<T> projectionType) {
return query(queryProvider, DEFAULT_RESULT_LIMIT, projectionType);
}
/**
* Executes the provided {@link String query} with the limited results projected as instances of
* the {@link Class projectionType}.
*
* @param <T> {@link Class} type of the projection.
* @param queryProvider {@link LuceneQueryProvider} providing the Lucene {@link String query} to execute.
* @param resultLimit limit on the number of query results to return.
* @param projectionType {@link Class} type of the individual elements in the query results.
* @return a {@link List} of Lucene query results projected as instances of {@link Class projectionType}.
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @see java.util.List
*/
<T> List<T> query(LuceneQueryProvider queryProvider, int resultLimit, Class<T> projectionType);
/**
* Executes the provided {@link String query} with the limited results projected as instances of
* the {@link Class projectionType}.
*
* @param <T> {@link Class} type of the projection.
* @param queryProvider {@link LuceneQueryProvider} providing the Lucene {@link String query} to execute.
* @param resultLimit limit on the number of query results to return.
* @param pageSize number of results on a {@link Page}.
* @param projectionType {@link Class} type of the individual elements in the query results.
* @return the first {@link Page} of results returned from the Lucene query.
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @see org.springframework.data.domain.Page
*/
<T> Page<T> query(LuceneQueryProvider queryProvider, int resultLimit, int pageSize, Class<T> projectionType);
}

View File

@@ -0,0 +1,129 @@
/*
* Copyright 2016 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.gemfire.search.lucene;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newUnsupportedOperationException;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.lucene.LuceneIndex;
import org.apache.geode.cache.lucene.LuceneQueryProvider;
import org.springframework.data.domain.Page;
/**
* {@link ProjectingLuceneTemplate} is a Lucene data access operations class encapsulating functionality
* for performing Lucene queries and other Lucene data access operations and returning the query results
* as application-specific domain object views.
*
* @author John Blum
* @see org.springframework.data.gemfire.search.lucene.ProjectingLuceneAccessor
* @see org.springframework.data.gemfire.search.lucene.ProjectingLuceneOperations
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.lucene.LuceneIndex
* @see org.apache.geode.cache.lucene.LuceneQuery
* @see org.apache.geode.cache.lucene.LuceneQueryFactory
* @see org.apache.geode.cache.lucene.LuceneQueryProvider
* @see org.apache.geode.cache.lucene.LuceneResultStruct
* @see org.apache.geode.cache.lucene.PageableLuceneQueryResults
* @since 1.1.0
*/
@SuppressWarnings("unused")
public class ProjectingLuceneTemplate extends ProjectingLuceneAccessor {
/**
* Constructs a default, uninitialized instance of the {@link ProjectingLuceneTemplate}.
*/
public ProjectingLuceneTemplate() {
}
/**
* Constructs an instance of the {@link ProjectingLuceneTemplate} initialized with the given {@link LuceneIndex}
* used to perform Lucene queries (searches).
*
* @param luceneIndex {@link LuceneIndex} used in Lucene queries.
* @see org.apache.geode.cache.lucene.LuceneIndex
*/
public ProjectingLuceneTemplate(LuceneIndex luceneIndex) {
super(luceneIndex);
}
/**
* Constructs an instance of the {@link ProjectingLuceneTemplate} initialized with the given Lucene index name
* and {@link Region} reference upon which Lucene queries are executed.
*
* @param indexName {@link String} containing the name of the {@link LuceneIndex} used in Lucene queries.
* @param region {@link Region} on which Lucene queries are executed.
* @see org.apache.geode.cache.Region
*/
public ProjectingLuceneTemplate(String indexName, Region<?, ?> region) {
super(indexName, region);
}
/**
* Constructs an instance of the {@link ProjectingLuceneTemplate} initialized with the given Lucene index name
* and {@link Region} reference upon which Lucene queries are executed.
*
* @param indexName {@link String} containing the name of the {@link LuceneIndex} used in Lucene queries.
* @param regionPath {@link String} containing the name of the {@link Region} on which Lucene queries are executed.
*/
public ProjectingLuceneTemplate(String indexName, String regionPath) {
super(indexName, regionPath);
}
/**
* @inheritDoc
*/
@Override
public <T> List<T> query(String query, String defaultField, int resultLimit, Class<T> projectionType) {
return query(query, defaultField, resultLimit).stream()
.map(luceneResultStruct -> getProjectionFactory().createProjection(projectionType, luceneResultStruct.getValue()))
.collect(Collectors.toList());
}
/**
* @inheritDoc
*/
@Override
public <T> Page<T> query(String query, String defaultField, int resultLimit, int pageSize,
Class<T> projectionType) {
throw newUnsupportedOperationException("Not Implemented");
}
/**
* @inheritDoc
*/
@Override
public <T> List<T> query(LuceneQueryProvider queryProvider, int resultLimit, Class<T> projectionType) {
return query(queryProvider, resultLimit).stream()
.map(luceneResultStruct -> getProjectionFactory().createProjection(projectionType, luceneResultStruct.getValue()))
.collect(Collectors.toList());
}
/**
* @inheritDoc
*/
@Override
public <T> Page<T> query(LuceneQueryProvider queryProvider, int resultLimit, int pageSize,
Class<T> projectionType) {
throw newUnsupportedOperationException("Not Implemented");
}
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright 2016 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.gemfire.search.lucene.support;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.geode.pdx.PdxInstance;
import org.apache.geode.pdx.WritablePdxInstance;
import org.springframework.data.projection.Accessor;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
/**
* The {@link PdxInstanceMethodInterceptor} class is a {@link MethodInterceptor} wrapping a {@link PdxInstance}
* to back a proxy during intercepted method invocations.
*
* @author John Blum
* @see org.aopalliance.intercept.MethodInterceptor
* @see org.apache.geode.pdx.PdxInstance
* @see org.apache.geode.pdx.WritablePdxInstance
* @since 1.1.0
*/
public class PdxInstanceMethodInterceptor implements MethodInterceptor {
private PdxInstance source;
/**
* Factory method used to construct an instance of {@link PdxInstanceMethodInterceptor} initialized with
* the given {@link Object source}.
*
* @param source {@link Object} serving as the source to back the proxy in method invocations.
* Source must be an instance of {@link PdxInstance}.
* @return a new instance of {@link PdxInstanceMethodInterceptor} initialized with the given {@link Object source}.
* @throws IllegalArgumentException if {@link Object source} is not an instance of {@link PdxInstance}.
* @see #newPdxInstanceMethodInterceptor(PdxInstance)
*/
public static PdxInstanceMethodInterceptor newPdxInstanceMethodInterceptor(Object source) {
Assert.isInstanceOf(PdxInstance.class, source, () -> String.format("Source [%1$s] is not an instance of [%2$s]",
ObjectUtils.nullSafeClassName(source), PdxInstance.class.getName()));
return newPdxInstanceMethodInterceptor((PdxInstance) source);
}
/**
* Factory method used to construct an instance of {@link PdxInstanceMethodInterceptor} initialized
* with the given {@link PdxInstance}.
*
* @param source {@link PdxInstance} serving as the source to back the proxy in method invocations.
* Source must not be {@literal null}.
* @return a new instance of {@link PdxInstanceMethodInterceptor} initialized with
* the given {@link PdxInstance source}.
* @throws IllegalArgumentException if {@link PdxInstance source} is {@literal null}.
* @see #PdxInstanceMethodInterceptor(PdxInstance)
* @see org.apache.geode.pdx.PdxInstance
*/
public static PdxInstanceMethodInterceptor newPdxInstanceMethodInterceptor(PdxInstance source) {
return new PdxInstanceMethodInterceptor(source);
}
/**
* Constructs an instance of {@link PdxInstanceMethodInterceptor} initialized with
* the given {@link PdxInstance source}.
*
* @param source {@link PdxInstance} used as the source to back the proxy in method invocations.
* @throws IllegalArgumentException if {@link PdxInstance source} is {@literal null}.
* @see org.apache.geode.pdx.PdxInstance
*/
public PdxInstanceMethodInterceptor(PdxInstance source) {
Assert.notNull(source, "Source must not be null");
this.source = source;
}
/**
* Returns the {@link PdxInstance source} backing the proxy for intercepted method invocations.
*
* @return the {@link PdxInstance source} backing the proxy for intercepted method invocations.
* @see org.apache.geode.pdx.PdxInstance
*/
protected PdxInstance getSource() {
return this.source;
}
/**
* @inheritDoc
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
if (ReflectionUtils.isObjectMethod(method)) {
return invocation.proceed();
}
else {
Accessor methodAccessor = new Accessor(method);
PdxInstance pdxInstance = getSource();
String propertyName = methodAccessor.getPropertyName();
Assert.state(pdxInstance.hasField(propertyName), () -> String.format(
"Source [%1$s] does not contain field with name [%2$s]", pdxInstance, propertyName));
if (methodAccessor.isGetter()) {
return pdxInstance.getField(propertyName);
}
else { // is setter
Assert.isTrue(invocation.getArguments().length == 1, () ->
String.format("Invoked setter method [%1$s] must expect exactly 1 argument; Arguments were [%2$s]",
method.getName(), Arrays.toString(invocation.getArguments())));
Object value = invocation.getArguments()[0];
WritablePdxInstance writablePdxInstance = pdxInstance.createWriter();
Assert.state(writablePdxInstance != null, () -> String.format(
"No writer for PdxInstance [%1$s] was found for setting field [%2$s] to value [%3$s]",
pdxInstance, propertyName, value));
writablePdxInstance.setField(propertyName, value);
this.source = writablePdxInstance;
return null;
}
}
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2016 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.gemfire.search.lucene.support;
import static org.springframework.data.gemfire.search.lucene.support.PdxInstanceMethodInterceptor.newPdxInstanceMethodInterceptor;
import org.aopalliance.intercept.MethodInterceptor;
import org.apache.geode.pdx.PdxInstance;
import org.springframework.data.projection.MethodInterceptorFactory;
/**
* The {@link PdxInstanceMethodInterceptorFactory} class is a Spring Data {@link MethodInterceptorFactory} used to
* identify {@link PdxInstance} types and instantiates an instance of the {@link PdxInstanceMethodInterceptor}
* in order to intercept and handle invocations on the {@link PdxInstance} for the proxied projection.
*
* @author John Blum
* @see org.aopalliance.intercept.MethodInterceptor
* @see org.apache.geode.pdx.PdxInstance
* @see org.springframework.data.gemfire.search.lucene.support.PdxInstanceMethodInterceptor
* @see org.springframework.data.projection.MethodInterceptorFactory
* @since 1.0.0
*/
public enum PdxInstanceMethodInterceptorFactory implements MethodInterceptorFactory {
INSTANCE;
/**
* @inheritDoc
*/
@Override
public MethodInterceptor createMethodInterceptor(Object source, Class<?> targetType) {
return newPdxInstanceMethodInterceptor(source);
}
/**
* @inheritDoc
*/
@Override
public boolean supports(Object source, Class<?> targetType) {
return PdxInstance.class.isInstance(source);
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2016 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.gemfire.search.lucene.support;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newUnsupportedOperationException;
import java.util.List;
import org.apache.geode.cache.lucene.LuceneQueryProvider;
import org.springframework.data.domain.Page;
import org.springframework.data.gemfire.search.lucene.ProjectingLuceneAccessor;
import org.springframework.data.gemfire.util.RuntimeExceptionFactory;
/**
* {@link ProjectingLuceneAccessorSupport} is a {@link ProjectingLuceneAccessor} class implementation providing support
* for extending classes.
*
* @author John Blum
* @see org.springframework.data.gemfire.search.lucene.ProjectingLuceneAccessor
* @since 1.1.0
*/
@SuppressWarnings("unused")
public abstract class ProjectingLuceneAccessorSupport extends ProjectingLuceneAccessor {
/**
* @inheritDoc
*/
@Override
public <T> List<T> query(String query, String defaultField, int resultLimit, Class<T> projectionType) {
throw newUnsupportedOperationException(RuntimeExceptionFactory.NOT_IMPLEMENTED);
}
/**
* @inheritDoc
*/
@Override
public <T> Page<T> query(String query, String defaultField, int resultLimit, int pageSize,
Class<T> projectionType) {
throw newUnsupportedOperationException(RuntimeExceptionFactory.NOT_IMPLEMENTED);
}
/**
* @inheritDoc
*/
@Override
public <T> List<T> query(LuceneQueryProvider queryProvider, int resultLimit, Class<T> projectionType) {
throw newUnsupportedOperationException(RuntimeExceptionFactory.NOT_IMPLEMENTED);
}
/**
* @inheritDoc
*/
@Override
public <T> Page<T> query(LuceneQueryProvider queryProvider, int resultLimit, int pageSize,
Class<T> projectionType) {
throw newUnsupportedOperationException(RuntimeExceptionFactory.NOT_IMPLEMENTED);
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2016 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.gemfire.search.lucene.support;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newUnsupportedOperationException;
import java.util.List;
import org.apache.geode.cache.lucene.LuceneQueryProvider;
import org.springframework.data.domain.Page;
import org.springframework.data.gemfire.search.lucene.ProjectingLuceneOperations;
import org.springframework.data.gemfire.util.RuntimeExceptionFactory;
/**
* {@link ProjectingLuceneOperationsSupport} is a abstract supporting class for implementations
* of the {@link ProjectingLuceneOperations} interface.
*
* @author John Blum
* @see org.springframework.data.gemfire.search.lucene.ProjectingLuceneOperations
* @since 1.1.0
*/
@SuppressWarnings("unused")
public abstract class ProjectingLuceneOperationsSupport extends LuceneOperationsSupport
implements ProjectingLuceneOperations {
/**
* @inheritDoc
*/
@Override
public <T> List<T> query(String query, String defaultField, int resultLimit, Class<T> projectionType) {
throw newUnsupportedOperationException(RuntimeExceptionFactory.NOT_IMPLEMENTED);
}
/**
* @inheritDoc
*/
@Override
public <T> Page<T> query(String query, String defaultField, int resultLimit, int pageSize,
Class<T> projectionType) {
throw newUnsupportedOperationException(RuntimeExceptionFactory.NOT_IMPLEMENTED);
}
/**
* @inheritDoc
*/
@Override
public <T> List<T> query(LuceneQueryProvider queryProvider, int resultLimit, Class<T> projectionType) {
throw newUnsupportedOperationException(RuntimeExceptionFactory.NOT_IMPLEMENTED);
}
/**
* @inheritDoc
*/
@Override
public <T> Page<T> query(LuceneQueryProvider queryProvider, int resultLimit, int pageSize,
Class<T> projectionType) {
throw newUnsupportedOperationException(RuntimeExceptionFactory.NOT_IMPLEMENTED);
}
}