/* * 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 java.util.Optional; import java.util.stream.Collectors; import org.apache.geode.cache.Region; import org.apache.geode.cache.lucene.LuceneIndex; import org.apache.geode.cache.lucene.LuceneResultStruct; 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; } public <T, K, V> List<T> project(List<LuceneResultStruct<K, V>> source, Class<T> projectionType) { return source.stream().map(luceneResultStruct -> project(luceneResultStruct, projectionType)) .collect(Collectors.toList()); } public <T, K, V> T project(LuceneResultStruct<K, V> source, Class<T> projectionType) { return project(source.getValue(), projectionType); } public <T> T project(Object source, Class<T> projectionType) { return getProjectionFactory().createProjection(projectionType, source); } }