Adding missing files
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package org.springframework.data.elasticsearch;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ElasticsearchException extends RuntimeException{
|
||||
|
||||
private Map<String, String> failedDocuments;
|
||||
|
||||
public ElasticsearchException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ElasticsearchException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ElasticsearchException(String message, Throwable cause, Map<String, String> failedDocuments) {
|
||||
super(message, cause);
|
||||
this.failedDocuments = failedDocuments;
|
||||
}
|
||||
|
||||
public ElasticsearchException(String message, Map<String, String> failedDocuments) {
|
||||
super(message);
|
||||
this.failedDocuments = failedDocuments;
|
||||
}
|
||||
|
||||
public Map<String, String> getFailedDocuments() {
|
||||
return failedDocuments;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.springframework.data.elasticsearch.annotations;
|
||||
|
||||
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Persistent
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
public @interface Document {
|
||||
|
||||
String indexName() default "";
|
||||
String type() default "";
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.springframework.data.elasticsearch.annotations;
|
||||
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
public @interface Query {
|
||||
|
||||
/**
|
||||
* Elasticsearch query to be used when executing query. May contain placeholders eg. ?0
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* Named Query Named looked up by repository.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.springframework.data.elasticsearch.client;
|
||||
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import static org.elasticsearch.node.NodeBuilder.nodeBuilder;
|
||||
|
||||
public class NodeClientFactoryBean implements FactoryBean<NodeClient>, InitializingBean{
|
||||
|
||||
private boolean local;
|
||||
private NodeClient nodeClient;
|
||||
|
||||
NodeClientFactoryBean() {
|
||||
}
|
||||
|
||||
public NodeClientFactoryBean(boolean local) {
|
||||
this.local = local;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeClient getObject() throws Exception {
|
||||
return nodeClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Client> getObjectType() {
|
||||
return NodeClient.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
nodeClient = (NodeClient) nodeBuilder().local(this.local).node().client();
|
||||
}
|
||||
|
||||
public void setLocal(boolean local) {
|
||||
this.local = local;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package org.springframework.data.elasticsearch.client;
|
||||
|
||||
import org.elasticsearch.client.transport.TransportClient;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.apache.commons.lang.StringUtils.substringAfter;
|
||||
import static org.apache.commons.lang.StringUtils.substringBefore;
|
||||
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
|
||||
|
||||
|
||||
public class TransportClientFactoryBean implements FactoryBean<TransportClient>, InitializingBean, DisposableBean {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TransportClientFactoryBean.class);
|
||||
private String[] clusterNodes;
|
||||
private TransportClient client;
|
||||
private Properties properties;
|
||||
static final String COLON = ":";
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
try {
|
||||
logger.info("Closing elasticSearch client");
|
||||
if (client != null) {
|
||||
client.close();
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
logger.error("Error closing ElasticSearch client: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportClient getObject() throws Exception {
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<TransportClient> getObjectType() {
|
||||
return TransportClient.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
buildClient();
|
||||
}
|
||||
|
||||
protected void buildClient() throws Exception {
|
||||
client = new TransportClient(settings());
|
||||
Assert.notEmpty(clusterNodes,"[Assertion failed] clusterNodes settings missing.");
|
||||
for (String clusterNode : clusterNodes) {
|
||||
String hostName = substringBefore(clusterNode, COLON);
|
||||
String port = substringAfter(clusterNode, COLON);
|
||||
Assert.hasText(hostName,"[Assertion failed] missing host name in 'clusterNodes'");
|
||||
Assert.hasText(port,"[Assertion failed] missing port in 'clusterNodes'");
|
||||
logger.info("adding transport node : " + clusterNode);
|
||||
client.addTransportAddress(new InetSocketTransportAddress(hostName, Integer.valueOf(port)));
|
||||
}
|
||||
client.connectedNodes();
|
||||
}
|
||||
|
||||
private Settings settings(){
|
||||
if(properties != null){
|
||||
return settingsBuilder().put(properties).build();
|
||||
}
|
||||
return settingsBuilder()
|
||||
.put("client.transport.sniff",true).build();
|
||||
}
|
||||
|
||||
public void setClusterNodes(String[] clusterNodes) {
|
||||
this.clusterNodes = clusterNodes;
|
||||
}
|
||||
|
||||
public void setProperties(Properties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.springframework.data.elasticsearch.config;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
import org.springframework.data.elasticsearch.repository.config.ElasticsearchRepositoryConfigExtension;
|
||||
import org.springframework.data.repository.config.RepositoryBeanDefinitionParser;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
|
||||
|
||||
|
||||
public class ElasticsearchNamespaceHandler extends NamespaceHandlerSupport{
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
RepositoryConfigurationExtension extension = new ElasticsearchRepositoryConfigExtension();
|
||||
RepositoryBeanDefinitionParser parser = new RepositoryBeanDefinitionParser(extension);
|
||||
|
||||
registerBeanDefinitionParser("repositories", parser);
|
||||
registerBeanDefinitionParser("node-client", new NodeClientBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("transport-client", new TransportClientBeanDefinitionParser());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.springframework.data.elasticsearch.config;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.elasticsearch.client.NodeClientFactoryBean;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
|
||||
public class NodeClientBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(NodeClientFactoryBean.class);
|
||||
setLocalSettings(element,builder);
|
||||
return getSourcedBeanDefinition(builder, element, parserContext);
|
||||
}
|
||||
|
||||
private void setLocalSettings(Element element, BeanDefinitionBuilder builder) {
|
||||
builder.addPropertyValue("local", Boolean.valueOf(element.getAttribute("local")));
|
||||
}
|
||||
|
||||
|
||||
private AbstractBeanDefinition getSourcedBeanDefinition(BeanDefinitionBuilder builder, Element source,
|
||||
ParserContext context) {
|
||||
AbstractBeanDefinition definition = builder.getBeanDefinition();
|
||||
definition.setSource(context.extractSource(source));
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.springframework.data.elasticsearch.config;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.elasticsearch.client.TransportClientFactoryBean;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import static org.apache.commons.lang.StringUtils.split;
|
||||
|
||||
|
||||
public class TransportClientBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
private static final String SEPARATOR_CHARS = ",";
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TransportClientFactoryBean.class);
|
||||
setClusterNodes(element, builder);
|
||||
return getSourcedBeanDefinition(builder,element, parserContext);
|
||||
}
|
||||
|
||||
private void setClusterNodes(Element element, BeanDefinitionBuilder builder){
|
||||
builder.addPropertyValue("clusterNodes", split(element.getAttribute("cluster-nodes"), SEPARATOR_CHARS));
|
||||
}
|
||||
|
||||
private AbstractBeanDefinition getSourcedBeanDefinition(BeanDefinitionBuilder builder, Element source,
|
||||
ParserContext context) {
|
||||
AbstractBeanDefinition definition = builder.getBeanDefinition();
|
||||
definition.setSource(context.extractSource(source));
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core;
|
||||
|
||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||
import org.elasticsearch.index.query.BoostableQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||
import static org.springframework.data.elasticsearch.core.query.Criteria.OperationKey;
|
||||
|
||||
class CriteriaQueryProcessor {
|
||||
|
||||
|
||||
QueryBuilder createQueryFromCriteria(Criteria criteria) {
|
||||
BoolQueryBuilder query = boolQuery();
|
||||
|
||||
ListIterator<Criteria> chainIterator = criteria.getCriteriaChain().listIterator();
|
||||
while (chainIterator.hasNext()) {
|
||||
Criteria chainedCriteria = chainIterator.next();
|
||||
if(chainedCriteria.isOr()){
|
||||
query.should(createQueryFragmentForCriteria(chainedCriteria));
|
||||
}else if(chainedCriteria.isNegating()){
|
||||
query.mustNot(createQueryFragmentForCriteria(chainedCriteria));
|
||||
}else{
|
||||
query.must(createQueryFragmentForCriteria(chainedCriteria));
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
private QueryBuilder createQueryFragmentForCriteria(Criteria chainedCriteria) {
|
||||
Iterator<Criteria.CriteriaEntry> it = chainedCriteria.getCriteriaEntries().iterator();
|
||||
boolean singeEntryCriteria = (chainedCriteria.getCriteriaEntries().size() == 1);
|
||||
|
||||
String fieldName = chainedCriteria.getField().getName();
|
||||
Assert.notNull(fieldName,"Unknown field");
|
||||
QueryBuilder query = null;
|
||||
|
||||
if(singeEntryCriteria){
|
||||
Criteria.CriteriaEntry entry = it.next();
|
||||
query = processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName);
|
||||
}else{
|
||||
query = boolQuery();
|
||||
while (it.hasNext()){
|
||||
Criteria.CriteriaEntry entry = it.next();
|
||||
((BoolQueryBuilder)query).must(processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName));
|
||||
}
|
||||
}
|
||||
|
||||
addBoost(query, chainedCriteria.getBoost());
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
private QueryBuilder processCriteriaEntry(OperationKey key, Object value, String fieldName) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
QueryBuilder query = null;
|
||||
|
||||
switch (key){
|
||||
case EQUALS:
|
||||
query = fieldQuery(fieldName, value); break;
|
||||
case CONTAINS:
|
||||
query = fieldQuery(fieldName,"*" + value + "*").analyzeWildcard(true); break;
|
||||
case STARTS_WITH:
|
||||
query = fieldQuery(fieldName,value +"*").analyzeWildcard(true); break;
|
||||
case ENDS_WITH:
|
||||
query = fieldQuery(fieldName, "*"+value).analyzeWildcard(true); break;
|
||||
case EXPRESSION:
|
||||
query = queryString((String)value).field(fieldName); break;
|
||||
case BETWEEN:
|
||||
Object[] ranges = (Object[]) value;
|
||||
query = rangeQuery(fieldName).from(ranges[0]).to(ranges[1]); break;
|
||||
case FUZZY:
|
||||
query = fuzzyQuery(fieldName, (String) value); break;
|
||||
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private QueryBuilder buildNegationQuery(String fieldName, Iterator<Criteria.CriteriaEntry> it){
|
||||
BoolQueryBuilder notQuery = boolQuery();
|
||||
while (it.hasNext()){
|
||||
notQuery.mustNot(fieldQuery(fieldName, it.next().getValue()));
|
||||
}
|
||||
return notQuery;
|
||||
}
|
||||
|
||||
private void addBoost(QueryBuilder query, float boost){
|
||||
if(Float.isNaN(boost)){
|
||||
return;
|
||||
}
|
||||
if(query instanceof BoostableQueryBuilder){
|
||||
((BoostableQueryBuilder)query).boost(boost);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
|
||||
import org.elasticsearch.action.bulk.BulkResponse;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.query.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ElasticsearchOperations {
|
||||
|
||||
|
||||
/**
|
||||
* @return Converter in use
|
||||
*/
|
||||
ElasticsearchConverter getElasticsearchConverter();
|
||||
|
||||
/**
|
||||
* Create an index
|
||||
* @param clazz
|
||||
* @param <T>
|
||||
*/
|
||||
<T> boolean createIndex(Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Execute the query against elasticsearch and return the first returned object
|
||||
*
|
||||
* @param query
|
||||
* @param clazz
|
||||
* @return the first matching object
|
||||
*/
|
||||
<T> T queryForObject(GetQuery query, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Execute the query against elasticsearch and return the first returned object
|
||||
*
|
||||
* @param query
|
||||
* @param clazz
|
||||
* @return the first matching object
|
||||
*/
|
||||
<T> T queryForObject(CriteriaQuery query, Class<T> clazz);
|
||||
|
||||
|
||||
/**
|
||||
* Execute the query against elasticsearch and return the first returned object
|
||||
*
|
||||
* @param query
|
||||
* @param clazz
|
||||
* @return the first matching object
|
||||
*/
|
||||
<T> T queryForObject(StringQuery query, Class<T> clazz);
|
||||
|
||||
|
||||
/**
|
||||
* Execute the query against elasticsearch and return result as {@link Page}
|
||||
*
|
||||
* @param query
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
<T> Page<T> queryForPage(SearchQuery query, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Execute the query against elasticsearch and return result as {@link Page}
|
||||
*
|
||||
* @param query
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
<T> Page<T> queryForPage(CriteriaQuery query, Class<T> clazz);
|
||||
|
||||
|
||||
/**
|
||||
* Execute the query against elasticsearch and return result as {@link Page}
|
||||
*
|
||||
* @param query
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
<T> Page<T> queryForPage(StringQuery query, Class<T> clazz);
|
||||
|
||||
|
||||
/**
|
||||
* return number of elements found by for given query
|
||||
*
|
||||
* @param query
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
<T> long count(SearchQuery query, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Index an object. Will do save or update
|
||||
*
|
||||
* @param query
|
||||
* @return returns the document id
|
||||
*/
|
||||
String index(IndexQuery query);
|
||||
|
||||
/**
|
||||
* Bulk index all objects. Will do save or update
|
||||
*
|
||||
* @param queries
|
||||
*/
|
||||
void bulkIndex(List<IndexQuery> queries);
|
||||
|
||||
/**
|
||||
* Delete the one object with provided id
|
||||
*
|
||||
* @param indexName
|
||||
* @param type
|
||||
* @param id
|
||||
* @return documentId of the document deleted
|
||||
*/
|
||||
String delete(String indexName, String type, String id);
|
||||
|
||||
/**
|
||||
* Delete the one object with provided id
|
||||
*
|
||||
* @param clazz
|
||||
* @param id
|
||||
* @return documentId of the document deleted
|
||||
*/
|
||||
<T> String delete(Class<T> clazz, String id);
|
||||
|
||||
/**
|
||||
* Delete all records matching the query
|
||||
* @param clazz
|
||||
* @param query
|
||||
*/
|
||||
<T> void delete(DeleteQuery query, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* refresh the index
|
||||
* @param indexName
|
||||
* @param waitForOperation
|
||||
*/
|
||||
void refresh(String indexName,boolean waitForOperation);
|
||||
|
||||
/**
|
||||
* refresh the index
|
||||
* @param clazz
|
||||
* @param waitForOperation
|
||||
*/
|
||||
<T> void refresh(Class<T> clazz,boolean waitForOperation);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import org.codehaus.jackson.map.DeserializationConfig;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.elasticsearch.action.bulk.BulkItemResponse;
|
||||
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
||||
import org.elasticsearch.action.bulk.BulkResponse;
|
||||
import org.elasticsearch.action.count.CountRequestBuilder;
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.Requests;
|
||||
import org.elasticsearch.common.collect.MapBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.elasticsearch.ElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||
import org.springframework.data.elasticsearch.core.query.*;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.commons.lang.StringUtils.isBlank;
|
||||
import static org.elasticsearch.action.search.SearchType.DFS_QUERY_THEN_FETCH;
|
||||
import static org.elasticsearch.client.Requests.indicesExistsRequest;
|
||||
import static org.elasticsearch.client.Requests.refreshRequest;
|
||||
|
||||
|
||||
public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
|
||||
private Client client;
|
||||
private ElasticsearchConverter elasticsearchConverter;
|
||||
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
{
|
||||
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
}
|
||||
|
||||
public ElasticsearchTemplate(Client client) {
|
||||
this(client, null);
|
||||
}
|
||||
|
||||
public ElasticsearchTemplate(Client client, ElasticsearchConverter elasticsearchConverter) {
|
||||
this.client = client;
|
||||
this.elasticsearchConverter = (elasticsearchConverter == null)? new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext()) : elasticsearchConverter ;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> boolean createIndex(Class<T> clazz) {
|
||||
ElasticsearchPersistentEntity<T> persistentEntity = getPersistentEntityFor(clazz);
|
||||
return createIndexIfNotCreated(persistentEntity.getIndexName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElasticsearchConverter getElasticsearchConverter() {
|
||||
return elasticsearchConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T queryForObject(GetQuery query, Class<T> clazz) {
|
||||
ElasticsearchPersistentEntity<T> persistentEntity = getPersistentEntityFor(clazz);
|
||||
GetResponse response = client.prepareGet(persistentEntity.getIndexName(), persistentEntity.getIndexType(), query.getId())
|
||||
.execute().actionGet();
|
||||
return mapResult(response.getSourceAsString(), clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T queryForObject(CriteriaQuery query, Class<T> clazz) {
|
||||
Page<T> page = queryForPage(query,clazz);
|
||||
Assert.isTrue(page.getTotalElements() < 2, "Expected 1 but found "+ page.getTotalElements() +" results");
|
||||
return page.getTotalElements() > 0? page.getContent().get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T queryForObject(StringQuery query, Class<T> clazz) {
|
||||
Page<T> page = queryForPage(query,clazz);
|
||||
Assert.isTrue(page.getTotalElements() < 2, "Expected 1 but found "+ page.getTotalElements() +" results");
|
||||
return page.getTotalElements() > 0? page.getContent().get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Page<T> queryForPage(SearchQuery query, Class<T> clazz) {
|
||||
SearchRequestBuilder searchRequestBuilder = prepareSearch(query,clazz);
|
||||
if(query.getElasticsearchFilter() != null){
|
||||
searchRequestBuilder.setFilter(query.getElasticsearchFilter());
|
||||
}
|
||||
SearchResponse response = searchRequestBuilder.setQuery(query.getElasticsearchQuery()).execute().actionGet();
|
||||
return mapResults(response, clazz, query.getPageable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Page<T> queryForPage(CriteriaQuery query, Class<T> clazz) {
|
||||
QueryBuilder elasticsearchQuery = new CriteriaQueryProcessor().createQueryFromCriteria(query.getCriteria());
|
||||
SearchResponse response = prepareSearch(query,clazz)
|
||||
.setQuery(elasticsearchQuery)
|
||||
.execute().actionGet();
|
||||
return mapResults(response, clazz, query.getPageable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Page<T> queryForPage(StringQuery query, Class<T> clazz) {
|
||||
SearchResponse response = prepareSearch(query,clazz)
|
||||
.setQuery(query.getSource())
|
||||
.execute().actionGet();
|
||||
return mapResults(response, clazz, query.getPageable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> long count(SearchQuery query, Class<T> clazz) {
|
||||
ElasticsearchPersistentEntity<T> persistentEntity = getPersistentEntityFor(clazz);
|
||||
CountRequestBuilder countRequestBuilder = client.prepareCount(persistentEntity.getIndexName())
|
||||
.setTypes(persistentEntity.getIndexType());
|
||||
if(query.getElasticsearchQuery() != null){
|
||||
countRequestBuilder.setQuery(query.getElasticsearchQuery());
|
||||
}
|
||||
return countRequestBuilder.execute().actionGet().count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String index(IndexQuery query) {
|
||||
return prepareIndex(query)
|
||||
.execute()
|
||||
.actionGet().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bulkIndex(List<IndexQuery> queries) {
|
||||
BulkRequestBuilder bulkRequest = client.prepareBulk();
|
||||
for(IndexQuery query : queries){
|
||||
bulkRequest.add(prepareIndex(query));
|
||||
}
|
||||
BulkResponse bulkResponse = bulkRequest.execute().actionGet();
|
||||
if (bulkResponse.hasFailures()) {
|
||||
Map<String, String> failedDocuments = new HashMap<String, String>();
|
||||
for (BulkItemResponse item : bulkResponse.items()) {
|
||||
if (item.failed())
|
||||
failedDocuments.put(item.getId(), item.failureMessage());
|
||||
}
|
||||
throw new ElasticsearchException("Bulk indexing has failures. Use ElasticsearchException.getFailedDocuments() for detailed messages [" + failedDocuments+"]", failedDocuments);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String delete(String indexName, String type, String id) {
|
||||
return client.prepareDelete(indexName, type, id)
|
||||
.execute().actionGet().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> String delete(Class<T> clazz, String id) {
|
||||
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
|
||||
return delete(persistentEntity.getIndexName(), persistentEntity.getIndexType(), id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void delete(DeleteQuery query, Class<T> clazz) {
|
||||
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
|
||||
client.prepareDeleteByQuery(persistentEntity.getIndexName())
|
||||
.setTypes(persistentEntity.getIndexType())
|
||||
.setQuery(query.getElasticsearchQuery())
|
||||
.execute().actionGet();
|
||||
}
|
||||
|
||||
private boolean createIndexIfNotCreated(String indexName) {
|
||||
return indexExists(indexName) || createIndex(indexName);
|
||||
}
|
||||
|
||||
private boolean indexExists(String indexName) {
|
||||
return client.admin()
|
||||
.indices()
|
||||
.exists(indicesExistsRequest(indexName)).actionGet().exists();
|
||||
}
|
||||
|
||||
private boolean createIndex(String indexName) {
|
||||
return client.admin().indices().create(Requests.createIndexRequest(indexName).
|
||||
settings(new MapBuilder<String, String>().put("index.refresh_interval", "-1").map())).actionGet().acknowledged();
|
||||
}
|
||||
|
||||
private <T> SearchRequestBuilder prepareSearch(Query query, Class<T> clazz){
|
||||
int startRecord=0;
|
||||
if(query.getPageable() != null){
|
||||
startRecord = ((query.getPageable().getPageNumber() - 1) * query.getPageable().getPageSize());
|
||||
}
|
||||
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
|
||||
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(persistentEntity.getIndexName())
|
||||
.setSearchType(DFS_QUERY_THEN_FETCH)
|
||||
.setTypes(persistentEntity.getIndexType())
|
||||
.setFrom(startRecord < 0 ? 0 : startRecord)
|
||||
.setSize(query.getPageable() != null ? query.getPageable().getPageSize() : 10);
|
||||
|
||||
if(query.getSort() != null){
|
||||
for(Sort.Order order : query.getSort()){
|
||||
searchRequestBuilder.addSort(order.getProperty(), order.getDirection() == Sort.Direction.DESC? SortOrder.DESC : SortOrder.ASC);
|
||||
}
|
||||
}
|
||||
return searchRequestBuilder;
|
||||
}
|
||||
|
||||
private IndexRequestBuilder prepareIndex(IndexQuery query){
|
||||
try {
|
||||
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(query.getObject().getClass());
|
||||
return client.prepareIndex(persistentEntity.getIndexName(), persistentEntity.getIndexType(), query.getId())
|
||||
.setSource(objectMapper.writeValueAsString(query.getObject()));
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchException("failed to index the document [id: " + query.getId() +"]",e);
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh(String indexName, boolean waitForOperation) {
|
||||
client.admin().indices()
|
||||
.refresh(refreshRequest(indexName).waitForOperations(waitForOperation)).actionGet();
|
||||
}
|
||||
|
||||
public <T> void refresh(Class<T> clazz, boolean waitForOperation) {
|
||||
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
|
||||
client.admin().indices()
|
||||
.refresh(refreshRequest(persistentEntity.getIndexName()).waitForOperations(waitForOperation)).actionGet();
|
||||
}
|
||||
|
||||
private ElasticsearchPersistentEntity getPersistentEntityFor(Class clazz){
|
||||
return elasticsearchConverter.getMappingContext().getPersistentEntity(clazz);
|
||||
}
|
||||
|
||||
private <T> Page<T> mapResults(SearchResponse response, final Class<T> elementType,final Pageable pageable){
|
||||
ResultsMapper<T> resultsMapper = new ResultsMapper<T>(){
|
||||
@Override
|
||||
public Page<T> mapResults(SearchResponse response) {
|
||||
long totalHits = response.getHits().totalHits();
|
||||
List<T> results = new ArrayList<T>();
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
if (hit != null) {
|
||||
results.add(mapResult(hit.sourceAsString(), elementType));
|
||||
}
|
||||
}
|
||||
return new PageImpl<T>(results, pageable, totalHits);
|
||||
}
|
||||
};
|
||||
return resultsMapper.mapResults(response);
|
||||
}
|
||||
|
||||
private <T> T mapResult(String source, Class<T> clazz){
|
||||
if(isBlank(source)){
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(source, clazz);
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchException("failed to map source [ " + source + "] to class " + clazz.getSimpleName() , e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
|
||||
public interface ResultsMapper<T> {
|
||||
|
||||
Page<T> mapResults(SearchResponse response);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.convert;
|
||||
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.LocalDateTime;
|
||||
import org.joda.time.ReadableInstant;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public final class DateTimeConverters {
|
||||
|
||||
private static DateTimeFormatter formatter = ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC);
|
||||
|
||||
public enum JodaDateTimeConverter implements Converter<ReadableInstant, String> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String convert(ReadableInstant source) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
return formatter.print(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum JodaLocalDateTimeConverter implements Converter<LocalDateTime, String> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String convert(LocalDateTime source) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
return formatter.print(source.toDateTime(DateTimeZone.UTC));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum JavaDateConverter implements Converter<Date, String> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String convert(Date source) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatter.print(source.getTime());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.convert;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
|
||||
|
||||
public interface ElasticsearchConverter{
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link org.springframework.data.mapping.context.MappingContext} used by the converter.
|
||||
*
|
||||
* @return never {@literal null}
|
||||
*/
|
||||
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> getMappingContext();
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link org.springframework.core.convert.ConversionService} used by the converter.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
ConversionService getConversionService();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.convert;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
public class MappingElasticsearchConverter implements ElasticsearchConverter, ApplicationContextAware{
|
||||
|
||||
private final MappingContext<? extends ElasticsearchPersistentEntity<?>,ElasticsearchPersistentProperty> mappingContext;
|
||||
private final GenericConversionService conversionService;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
public MappingElasticsearchConverter(MappingContext<? extends ElasticsearchPersistentEntity<?>,ElasticsearchPersistentProperty> mappingContext) {
|
||||
Assert.notNull(mappingContext);
|
||||
this.mappingContext = mappingContext;
|
||||
this.conversionService = new DefaultConversionService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingContext<? extends ElasticsearchPersistentEntity<?>,ElasticsearchPersistentProperty> getMappingContext() {
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConversionService getConversionService() {
|
||||
return this.conversionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.mapping;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
|
||||
public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, ElasticsearchPersistentProperty> {
|
||||
|
||||
String getIndexName();
|
||||
String getIndexType();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.mapping;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
public interface ElasticsearchPersistentProperty extends PersistentProperty<ElasticsearchPersistentProperty>{
|
||||
|
||||
String getFieldName();
|
||||
|
||||
public enum PropertyToFieldNameConverter implements Converter<ElasticsearchPersistentProperty, String> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
public String convert(ElasticsearchPersistentProperty source) {
|
||||
return source.getFieldName();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.mapping;
|
||||
|
||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
|
||||
public class SimpleElasticsearchMappingContext extends
|
||||
AbstractMappingContext<SimpleElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> {
|
||||
|
||||
@Override
|
||||
protected <T> SimpleElasticsearchPersistentEntity<?> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
return new SimpleElasticsearchPersistentEntity<T>(typeInformation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ElasticsearchPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
|
||||
SimpleElasticsearchPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
return new SimpleElasticsearchPersistentProperty(field, descriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.mapping;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.expression.BeanFactoryAccessor;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
/**
|
||||
* Elasticsearch specific {@link org.springframework.data.mapping.PersistentEntity} implementation holding
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntity<T, ElasticsearchPersistentProperty> implements
|
||||
ElasticsearchPersistentEntity<T>, ApplicationContextAware {
|
||||
|
||||
private final StandardEvaluationContext context;
|
||||
private String indexName;
|
||||
private String indexType;
|
||||
|
||||
public SimpleElasticsearchPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
super(typeInformation);
|
||||
this.context = new StandardEvaluationContext();
|
||||
Class<T> clazz = typeInformation.getType();
|
||||
Assert.isTrue(clazz.isAnnotationPresent(Document.class),
|
||||
clazz.getSimpleName() + " is not a Document. Make sure the document class is annotated with @Document(indexName=\"foo\")");
|
||||
Document document = clazz.getAnnotation(Document.class);
|
||||
Assert.hasText(document.indexName(), " Unknown indexName. Make sure the indexName is defined. e.g @Document(indexName=\"foo\")");
|
||||
this.indexName = typeInformation.getType().getAnnotation(Document.class).indexName();
|
||||
this.indexType = hasText(document.type())? document.type() : clazz.getSimpleName().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
context.addPropertyAccessor(new BeanFactoryAccessor());
|
||||
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
|
||||
context.setRootObject(applicationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexName() {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexType() {
|
||||
return indexType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.mapping;
|
||||
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Elasticsearch specific {@link org.springframework.data.mapping.PersistentProperty} implementation processing
|
||||
*/
|
||||
public class SimpleElasticsearchPersistentProperty extends AnnotationBasedPersistentProperty<ElasticsearchPersistentProperty> implements
|
||||
ElasticsearchPersistentProperty {
|
||||
|
||||
private static final Set<Class<?>> SUPPORTED_ID_TYPES = new HashSet<Class<?>>();
|
||||
private static final Set<String> SUPPORTED_ID_PROPERTY_NAMES = new HashSet<String>();
|
||||
|
||||
static {
|
||||
SUPPORTED_ID_TYPES.add(String.class);
|
||||
SUPPORTED_ID_PROPERTY_NAMES.add("id");
|
||||
SUPPORTED_ID_PROPERTY_NAMES.add("documentId");
|
||||
}
|
||||
|
||||
public SimpleElasticsearchPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
|
||||
PersistentEntity<?, ElasticsearchPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFieldName() {
|
||||
return field.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIdProperty() {
|
||||
return super.isIdProperty() || SUPPORTED_ID_PROPERTY_NAMES.contains(getFieldName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Association<ElasticsearchPersistentProperty> createAssociation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.query;
|
||||
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* AbstractQuery
|
||||
*
|
||||
*/
|
||||
abstract class AbstractQuery implements Query{
|
||||
|
||||
private static final Pageable DEFAULT_PAGE = new PageRequest(0, DEFAULT_PAGE_SIZE);
|
||||
|
||||
protected Pageable pageable = DEFAULT_PAGE;
|
||||
protected Sort sort;
|
||||
|
||||
@Override
|
||||
public Sort getSort() {
|
||||
return this.sort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pageable getPageable() {
|
||||
return this.pageable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T extends Query> T setPageable(Pageable pageable) {
|
||||
Assert.notNull(pageable);
|
||||
|
||||
this.pageable = pageable;
|
||||
return (T) this.addSort(pageable.getSort());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T extends Query> T addSort(Sort sort) {
|
||||
if (sort == null) {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
if (this.sort == null) {
|
||||
this.sort = sort;
|
||||
} else {
|
||||
this.sort = this.sort.and(sort);
|
||||
}
|
||||
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.query;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Criteria is the central class when constructing queries. It follows more or less a fluent API style, which allows to
|
||||
* easily chain together multiple criteria.
|
||||
*
|
||||
*/
|
||||
public class Criteria {
|
||||
|
||||
public static final String WILDCARD = "*";
|
||||
public static final String CRITERIA_VALUE_SEPERATOR = " ";
|
||||
|
||||
private static final String OR_OPERATOR = " OR ";
|
||||
private static final String AND_OPERATOR = " AND ";
|
||||
|
||||
private Field field;
|
||||
private float boost = Float.NaN;
|
||||
private boolean negating = false;
|
||||
|
||||
private List<Criteria> criteriaChain = new ArrayList<Criteria>(1);
|
||||
|
||||
private Set<CriteriaEntry> criteria = new LinkedHashSet<CriteriaEntry>();
|
||||
|
||||
public Criteria() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new CriterSimpleFieldia for the Filed with provided name
|
||||
*
|
||||
* @param fieldname
|
||||
*/
|
||||
public Criteria(String fieldname) {
|
||||
this(new SimpleField(fieldname));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Criteria for the given field
|
||||
*
|
||||
* @param field
|
||||
*/
|
||||
public Criteria(Field field) {
|
||||
Assert.notNull(field, "Field for criteria must not be null");
|
||||
Assert.hasText(field.getName(), "Field.name for criteria must not be null/empty");
|
||||
|
||||
this.criteriaChain.add(this);
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
protected Criteria(List<Criteria> criteriaChain, String fieldname) {
|
||||
this(criteriaChain, new SimpleField(fieldname));
|
||||
}
|
||||
|
||||
protected Criteria(List<Criteria> criteriaChain, Field field) {
|
||||
Assert.notNull(criteriaChain, "CriteriaChain must not be null");
|
||||
Assert.notNull(field, "Field for criteria must not be null");
|
||||
Assert.hasText(field.getName(), "Field.name for criteria must not be null/empty");
|
||||
|
||||
this.criteriaChain.addAll(criteriaChain);
|
||||
this.criteriaChain.add(this);
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory method to create a new Criteria for field with given name
|
||||
*
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static Criteria where(String field) {
|
||||
return where(new SimpleField(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory method to create a new Criteria for provided field
|
||||
*
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static Criteria where(Field field) {
|
||||
return new Criteria(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Chain using {@code AND}
|
||||
*
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public Criteria and(Field field) {
|
||||
return new Criteria(this.criteriaChain, field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Chain using {@code AND}
|
||||
*
|
||||
* @param fieldName
|
||||
* @return
|
||||
*/
|
||||
public Criteria and(String fieldName) {
|
||||
return new Criteria(this.criteriaChain, fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Chain using {@code AND}
|
||||
*
|
||||
* @param criteria
|
||||
* @return
|
||||
*/
|
||||
public Criteria and(Criteria criteria) {
|
||||
this.criteriaChain.add(criteria);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chain using {@code AND}
|
||||
*
|
||||
* @param criterias
|
||||
* @return
|
||||
*/
|
||||
public Criteria and(Criteria... criterias) {
|
||||
this.criteriaChain.addAll(Arrays.asList(criterias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chain using {@code OR}
|
||||
*
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public Criteria or(Field field) {
|
||||
return new OrCriteria(this.criteriaChain, field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Chain using {@code OR}
|
||||
*
|
||||
* @param criteria
|
||||
* @return
|
||||
*/
|
||||
public Criteria or(Criteria criteria) {
|
||||
Assert.notNull(criteria, "Cannot chain 'null' criteria.");
|
||||
|
||||
Criteria orConnectedCritiera = new OrCriteria(this.criteriaChain, criteria.getField());
|
||||
orConnectedCritiera.criteria.addAll(criteria.criteria);
|
||||
return orConnectedCritiera;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chain using {@code OR}
|
||||
*
|
||||
* @param fieldName
|
||||
* @return
|
||||
*/
|
||||
public Criteria or(String fieldName) {
|
||||
return or(new SimpleField(fieldName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Crates new CriteriaEntry without any wildcards
|
||||
*
|
||||
* @param o
|
||||
* @return
|
||||
*/
|
||||
public Criteria is(Object o) {
|
||||
criteria.add(new CriteriaEntry(OperationKey.EQUALS, o));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crates new CriteriaEntry with leading and trailing wildcards <br/>
|
||||
* <strong>NOTE: </strong> mind your schema as leading wildcards may not be supported and/or execution might be slow.
|
||||
*
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public Criteria contains(String s) {
|
||||
assertNoBlankInWildcardedQuery(s, true, true);
|
||||
criteria.add(new CriteriaEntry(OperationKey.CONTAINS, s));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crates new CriteriaEntry with trailing wildcard
|
||||
*
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public Criteria startsWith(String s) {
|
||||
assertNoBlankInWildcardedQuery(s, true, false);
|
||||
criteria.add(new CriteriaEntry(OperationKey.STARTS_WITH, s));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crates new CriteriaEntry with leading wildcard <br />
|
||||
* <strong>NOTE: </strong> mind your schema and execution times as leading wildcards may not be supported.
|
||||
*
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public Criteria endsWith(String s) {
|
||||
assertNoBlankInWildcardedQuery(s, false, true);
|
||||
criteria.add(new CriteriaEntry(OperationKey.ENDS_WITH, s));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crates new CriteriaEntry with trailing -
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Criteria not() {
|
||||
this.negating = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crates new CriteriaEntry with trailing ~
|
||||
*
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public Criteria fuzzy(String s) {
|
||||
criteria.add(new CriteriaEntry(OperationKey.FUZZY, s));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Crates new CriteriaEntry allowing native solr expressions
|
||||
*
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public Criteria expression(String s) {
|
||||
criteria.add(new CriteriaEntry(OperationKey.EXPRESSION, s));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Boost positive hit with given factor. eg. ^2.3
|
||||
*
|
||||
* @param boost
|
||||
* @return
|
||||
*/
|
||||
public Criteria boost(float boost) {
|
||||
if (boost < 0) {
|
||||
throw new InvalidDataAccessApiUsageException("Boost must not be negative.");
|
||||
}
|
||||
this.boost = boost;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crates new CriteriaEntry for {@code RANGE [lowerBound TO upperBound]}
|
||||
*
|
||||
* @param lowerBound
|
||||
* @param upperBound
|
||||
* @return
|
||||
*/
|
||||
public Criteria between(Object lowerBound, Object upperBound) {
|
||||
if (lowerBound == null && upperBound == null) {
|
||||
throw new InvalidDataAccessApiUsageException("Range [* TO *] is not allowed");
|
||||
}
|
||||
|
||||
criteria.add(new CriteriaEntry(OperationKey.BETWEEN, new Object[] { lowerBound, upperBound }));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crates new CriteriaEntry for {@code RANGE [* TO upperBound]}
|
||||
*
|
||||
* @param upperBound
|
||||
* @return
|
||||
*/
|
||||
public Criteria lessThanEqual(Object upperBound) {
|
||||
between(null, upperBound);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crates new CriteriaEntry for {@code RANGE [lowerBound TO *]}
|
||||
*
|
||||
* @param lowerBound
|
||||
* @return
|
||||
*/
|
||||
public Criteria greaterThanEqual(Object lowerBound) {
|
||||
between(lowerBound, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crates new CriteriaEntry for multiple values {@code (arg0 arg1 arg2 ...)}
|
||||
*
|
||||
* @param values
|
||||
* @return
|
||||
*/
|
||||
public Criteria in(Object... values) {
|
||||
if (values.length == 0 || (values.length > 1 && values[1] instanceof Collection)) {
|
||||
throw new InvalidDataAccessApiUsageException("At least one element "
|
||||
+ (values.length > 0 ? ("of argument of type " + values[1].getClass().getName()) : "")
|
||||
+ " has to be present.");
|
||||
}
|
||||
return in(Arrays.asList(values));
|
||||
}
|
||||
|
||||
/**
|
||||
* Crates new CriteriaEntry for multiple values {@code (arg0 arg1 arg2 ...)}
|
||||
*
|
||||
* @param values the collection containing the values to match against
|
||||
* @return
|
||||
*/
|
||||
public Criteria in(Iterable<?> values) {
|
||||
Assert.notNull(values, "Collection of 'in' values must not be null");
|
||||
for (Object value : values) {
|
||||
if (value instanceof Collection) {
|
||||
in((Collection<?>) value);
|
||||
} else {
|
||||
is(value);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
private void assertNoBlankInWildcardedQuery(String searchString, boolean leadingWildcard, boolean trailingWildcard) {
|
||||
if (StringUtils.contains(searchString, CRITERIA_VALUE_SEPERATOR)) {
|
||||
throw new InvalidDataAccessApiUsageException("Cannot constructQuery '" + (leadingWildcard ? "*" : "") + "\""
|
||||
+ searchString + "\"" + (trailingWildcard ? "*" : "") + "'. Use epxression or mulitple clauses instead.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Field targeted by this Criteria
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Field getField() {
|
||||
return this.field;
|
||||
}
|
||||
|
||||
public Set<CriteriaEntry> getCriteriaEntries() {
|
||||
return Collections.unmodifiableSet(this.criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Conjunction to be used with this criteria (AND | OR)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getConjunctionOperator() {
|
||||
return AND_OPERATOR;
|
||||
}
|
||||
|
||||
public List<Criteria> getCriteriaChain() {
|
||||
return Collections.unmodifiableList(this.criteriaChain);
|
||||
}
|
||||
|
||||
public boolean isNegating() {
|
||||
return this.negating;
|
||||
}
|
||||
|
||||
public boolean isAnd(){
|
||||
return AND_OPERATOR == getConjunctionOperator();
|
||||
}
|
||||
|
||||
public boolean isOr(){
|
||||
return OR_OPERATOR == getConjunctionOperator();
|
||||
}
|
||||
|
||||
public float getBoost() {
|
||||
return this.boost;
|
||||
}
|
||||
|
||||
static class OrCriteria extends Criteria {
|
||||
|
||||
public OrCriteria() {
|
||||
super();
|
||||
}
|
||||
|
||||
public OrCriteria(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
public OrCriteria(List<Criteria> criteriaChain, Field field) {
|
||||
super(criteriaChain, field);
|
||||
}
|
||||
|
||||
public OrCriteria(List<Criteria> criteriaChain, String fieldname) {
|
||||
super(criteriaChain, fieldname);
|
||||
}
|
||||
|
||||
public OrCriteria(String fieldname) {
|
||||
super(fieldname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConjunctionOperator() {
|
||||
return OR_OPERATOR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum OperationKey {
|
||||
EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, EXPRESSION, BETWEEN, FUZZY;
|
||||
}
|
||||
|
||||
public static class CriteriaEntry {
|
||||
|
||||
private OperationKey key;
|
||||
private Object value;
|
||||
|
||||
CriteriaEntry(OperationKey key, Object value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public OperationKey getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.query;
|
||||
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
public class CriteriaQuery extends AbstractQuery implements Query {
|
||||
|
||||
private Criteria criteria;
|
||||
private CriteriaQuery() {
|
||||
}
|
||||
|
||||
public CriteriaQuery(Criteria criteria) {
|
||||
this(criteria, null);
|
||||
}
|
||||
|
||||
public CriteriaQuery(Criteria criteria, Pageable pageable) {
|
||||
this.criteria = criteria;
|
||||
this.pageable = pageable;
|
||||
if (pageable != null) {
|
||||
this.addSort(pageable.getSort());
|
||||
}
|
||||
}
|
||||
|
||||
public static final Query fromQuery(CriteriaQuery source) {
|
||||
return fromQuery(source, new CriteriaQuery());
|
||||
}
|
||||
|
||||
public static <T extends CriteriaQuery> T fromQuery(CriteriaQuery source, T destination) {
|
||||
if (source == null || destination == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (source.getCriteria() != null) {
|
||||
destination.addCriteria(source.getCriteria());
|
||||
}
|
||||
|
||||
if (source.getSort() != null) {
|
||||
destination.addSort(source.getSort());
|
||||
}
|
||||
|
||||
return destination;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T extends CriteriaQuery> T addCriteria(Criteria criteria) {
|
||||
Assert.notNull(criteria, "Cannot add null criteria.");
|
||||
if (this.criteria == null) {
|
||||
this.criteria = criteria;
|
||||
} else {
|
||||
this.criteria.and(criteria);
|
||||
}
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public Criteria getCriteria() {
|
||||
return this.criteria;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
|
||||
public class DeleteQuery{
|
||||
|
||||
private QueryBuilder elasticsearchQuery;
|
||||
|
||||
public QueryBuilder getElasticsearchQuery() {
|
||||
return elasticsearchQuery;
|
||||
}
|
||||
|
||||
public void setElasticsearchQuery(QueryBuilder elasticsearchQuery) {
|
||||
this.elasticsearchQuery = elasticsearchQuery;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.query;
|
||||
|
||||
/**
|
||||
* Defines a Field that can be used within a Criteria.
|
||||
*
|
||||
*/
|
||||
public interface Field {
|
||||
|
||||
/**
|
||||
* Get the name of the field used in schema.xml of solr server
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getName();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
|
||||
public class GetQuery{
|
||||
|
||||
private String id;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
|
||||
public class IndexQuery{
|
||||
|
||||
private String id;
|
||||
private Object object;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
public interface Query {
|
||||
|
||||
int DEFAULT_PAGE_SIZE = 10;
|
||||
|
||||
|
||||
/**
|
||||
* restrict result to entries on given page. Corresponds to the 'start' and 'rows' parameter in solr
|
||||
*
|
||||
* @param pageable
|
||||
* @return
|
||||
*/
|
||||
<T extends Query> T setPageable(Pageable pageable);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get filter queries if defined
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
//List<FilterQuery> getFilterQueries();
|
||||
|
||||
/**
|
||||
* Get page settings if defined
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Pageable getPageable();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add {@link org.springframework.data.domain.Sort} to query
|
||||
*
|
||||
* @param sort
|
||||
* @return
|
||||
*/
|
||||
<T extends Query> T addSort(Sort sort);
|
||||
|
||||
/**
|
||||
* @return null if not set
|
||||
*/
|
||||
Sort getSort();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
|
||||
import org.elasticsearch.index.query.FilterBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
|
||||
public class SearchQuery extends AbstractQuery{
|
||||
|
||||
private QueryBuilder elasticsearchQuery;
|
||||
private FilterBuilder elasticsearchFilter;
|
||||
|
||||
public QueryBuilder getElasticsearchQuery() {
|
||||
return elasticsearchQuery;
|
||||
}
|
||||
|
||||
public void setElasticsearchQuery(QueryBuilder elasticsearchQuery) {
|
||||
this.elasticsearchQuery = elasticsearchQuery;
|
||||
}
|
||||
|
||||
public FilterBuilder getElasticsearchFilter() {
|
||||
return elasticsearchFilter;
|
||||
}
|
||||
|
||||
public void setElasticsearchFilter(FilterBuilder elasticsearchFilter) {
|
||||
this.elasticsearchFilter = elasticsearchFilter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.core.query;
|
||||
|
||||
/**
|
||||
* The most trivial implementation of a Field
|
||||
*
|
||||
*/
|
||||
public class SimpleField implements Field {
|
||||
|
||||
private final String name;
|
||||
|
||||
public SimpleField(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
public class StringQuery extends AbstractQuery{
|
||||
|
||||
private String source;
|
||||
|
||||
public StringQuery(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public StringQuery(String source, Pageable pageable) {
|
||||
this.source = source;
|
||||
this.pageable = pageable;
|
||||
}
|
||||
|
||||
public StringQuery(String source, Pageable pageable, Sort sort) {
|
||||
this.pageable = pageable;
|
||||
this.sort = sort;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository;
|
||||
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @param <ID>
|
||||
*/
|
||||
public interface ElasticsearchCrudRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
|
||||
|
||||
<S extends T> List<S> save(List<S> entities);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository;
|
||||
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.elasticsearch.core.query.SearchQuery;
|
||||
import org.springframework.data.repository.NoRepositoryBean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @param <ID>
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
public interface ElasticsearchRepository<T, ID extends Serializable> extends ElasticsearchCrudRepository<T,ID> {
|
||||
|
||||
<S extends T> S index(S entity);
|
||||
|
||||
Iterable<T> search(QueryBuilder elasticsearchQuery);
|
||||
|
||||
Page<T> search(QueryBuilder elasticsearchQuery, Pageable pageable);
|
||||
|
||||
Page<T> search(SearchQuery searchQuery);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.cdi;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactory;
|
||||
import org.springframework.data.repository.cdi.CdiRepositoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.enterprise.context.spi.CreationalContext;
|
||||
import javax.enterprise.inject.spi.Bean;
|
||||
import javax.enterprise.inject.spi.BeanManager;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Uses CdiRepositoryBean to create ElasticsearchRepository instances.
|
||||
*
|
||||
*/
|
||||
public class ElasticsearchRepositoryBean<T> extends CdiRepositoryBean<T> {
|
||||
|
||||
private final Bean<ElasticsearchOperations> elasticsearchOperationsBean;
|
||||
|
||||
public ElasticsearchRepositoryBean(Bean<ElasticsearchOperations> operations, Set<Annotation> qualifiers, Class<T> repositoryType,
|
||||
BeanManager beanManager) {
|
||||
super(qualifiers, repositoryType, beanManager);
|
||||
|
||||
Assert.notNull(operations, "Cannot create repository with 'null' for ElasticsearchOperations.");
|
||||
this.elasticsearchOperationsBean = operations;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType) {
|
||||
ElasticsearchOperations elasticsearchOperations = getDependencyInstance(elasticsearchOperationsBean, ElasticsearchOperations.class);
|
||||
return new ElasticsearchRepositoryFactory(elasticsearchOperations).getRepository(repositoryType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> getScope() {
|
||||
return elasticsearchOperationsBean.getScope();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.cdi;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.repository.cdi.CdiRepositoryExtensionSupport;
|
||||
|
||||
import javax.enterprise.event.Observes;
|
||||
import javax.enterprise.inject.UnsatisfiedResolutionException;
|
||||
import javax.enterprise.inject.spi.AfterBeanDiscovery;
|
||||
import javax.enterprise.inject.spi.Bean;
|
||||
import javax.enterprise.inject.spi.BeanManager;
|
||||
import javax.enterprise.inject.spi.ProcessBean;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class ElasticsearchRepositoryExtension extends CdiRepositoryExtensionSupport {
|
||||
|
||||
private final Map<String, Bean<ElasticsearchOperations>> elasticsearchOperationsMap = new HashMap<String, Bean<ElasticsearchOperations>>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> void processBean(@Observes ProcessBean<T> processBean) {
|
||||
Bean<T> bean = processBean.getBean();
|
||||
for (Type type : bean.getTypes()) {
|
||||
if (type instanceof Class<?> && ElasticsearchOperations.class.isAssignableFrom((Class<?>) type)) {
|
||||
elasticsearchOperationsMap.put(bean.getQualifiers().toString(), ((Bean<ElasticsearchOperations>) bean));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
|
||||
for (Entry<Class<?>, Set<Annotation>> entry : getRepositoryTypes()) {
|
||||
|
||||
Class<?> repositoryType = entry.getKey();
|
||||
Set<Annotation> qualifiers = entry.getValue();
|
||||
|
||||
Bean<?> repositoryBean = createRepositoryBean(repositoryType, qualifiers, beanManager);
|
||||
afterBeanDiscovery.addBean(repositoryBean);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> Bean<T> createRepositoryBean(Class<T> repositoryType, Set<Annotation> qualifiers, BeanManager beanManager) {
|
||||
Bean<ElasticsearchOperations> elasticsearchOperationsBean = this.elasticsearchOperationsMap.get(qualifiers.toString());
|
||||
|
||||
if (elasticsearchOperationsBean == null) {
|
||||
throw new UnsatisfiedResolutionException(String.format("Unable to resolve a bean for '%s' with qualifiers %s.",
|
||||
ElasticsearchOperations.class.getName(), qualifiers));
|
||||
}
|
||||
return new ElasticsearchRepositoryBean<T>(elasticsearchOperationsBean, qualifiers, repositoryType, beanManager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.config;
|
||||
|
||||
import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} implementation to trigger configuration of the {@link EnableElasticsearchRepositories}
|
||||
* annotation.
|
||||
*
|
||||
*/
|
||||
class ElasticsearchRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getAnnotation()
|
||||
*/
|
||||
@Override
|
||||
protected Class<? extends Annotation> getAnnotation() {
|
||||
return EnableElasticsearchRepositories.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getExtension()
|
||||
*/
|
||||
@Override
|
||||
protected RepositoryConfigurationExtension getExtension() {
|
||||
return new ElasticsearchRepositoryConfigExtension();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.config;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactoryBean;
|
||||
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
|
||||
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@link org.springframework.data.repository.config.RepositoryConfigurationExtension} implementation to configure Solr repository configuration support,
|
||||
* evaluating the {@link EnableElasticsearchRepositories} annotation or the equivalent XML element.
|
||||
*
|
||||
*/
|
||||
public class ElasticsearchRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtension#getRepositoryFactoryClassName()
|
||||
*/
|
||||
@Override
|
||||
public String getRepositoryFactoryClassName() {
|
||||
return ElasticsearchRepositoryFactoryBean.class.getName();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getModulePrefix()
|
||||
*/
|
||||
@Override
|
||||
protected String getModulePrefix() {
|
||||
return "elasticsearch";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource)
|
||||
*/
|
||||
@Override
|
||||
public void postProcess(BeanDefinitionBuilder builder, AnnotationRepositoryConfigurationSource config) {
|
||||
|
||||
AnnotationAttributes attributes = config.getAttributes();
|
||||
builder.addPropertyReference("elasticsearchOperations", attributes.getString("elasticsearchTemplateRef"));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.XmlRepositoryConfigurationSource)
|
||||
*/
|
||||
@Override
|
||||
public void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfigurationSource config) {
|
||||
|
||||
Element element = config.getElement();
|
||||
builder.addPropertyReference("elasticsearchOperations", element.getAttribute("elasticsearch-template-ref"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.config;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactoryBean;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Annotation to enable Elasticsearch repositories. Will scan the package of the annotated configuration class for Spring Data
|
||||
* repositories by default.
|
||||
*
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
@Import(ElasticsearchRepositoriesRegistrar.class)
|
||||
public @interface EnableElasticsearchRepositories {
|
||||
|
||||
/**
|
||||
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.:
|
||||
* {@code @EnableElasticsearchRepositories("org.my.pkg")} instead of {@code @EnableElasticsearchRepositories(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 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 {};
|
||||
|
||||
/**
|
||||
* Specifies which types are not eligible for component scanning.
|
||||
*/
|
||||
Filter[] excludeFilters() 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. Will default to
|
||||
* {@code META-INFO/elasticsearch-named-queries.properties}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String namedQueriesLocation() default "";
|
||||
|
||||
/**
|
||||
* Returns the key of the {@link org.springframework.data.repository.query.QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to
|
||||
* {@link org.springframework.data.repository.query.QueryLookupStrategy.Key#CREATE_IF_NOT_FOUND}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND;
|
||||
|
||||
/**
|
||||
* Returns the {@link org.springframework.beans.factory.FactoryBean} class to be used for each repository instance. Defaults to
|
||||
* {@link ElasticsearchRepositoryFactoryBean}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Class<?> repositoryFactoryBeanClass() default ElasticsearchRepositoryFactoryBean.class;
|
||||
|
||||
// Solr specific configuration
|
||||
|
||||
/**
|
||||
* Configures the name of the {@link ElasticsearchTemplate} bean definition to be used to create repositories discovered
|
||||
* through this annotation. Defaults to {@code elasticsearchTemplate}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String elasticsearchTemplateRef() default "elasticsearchTemplate";
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.query;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
|
||||
|
||||
public abstract class AbstractElasticsearchRepositoryQuery implements RepositoryQuery {
|
||||
|
||||
protected ElasticsearchQueryMethod queryMethod;
|
||||
protected ElasticsearchOperations elasticsearchOperations;
|
||||
|
||||
public AbstractElasticsearchRepositoryQuery(ElasticsearchQueryMethod queryMethod, ElasticsearchOperations elasticsearchOperations) {
|
||||
this.queryMethod = queryMethod;
|
||||
this.elasticsearchOperations = elasticsearchOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryMethod getQueryMethod() {
|
||||
return queryMethod;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.springframework.data.elasticsearch.repository.query;
|
||||
|
||||
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
|
||||
public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery{
|
||||
|
||||
private final PartTree tree;
|
||||
private final MappingContext<?, ElasticsearchPersistentProperty> mappingContext;
|
||||
|
||||
|
||||
public ElasticsearchPartQuery(ElasticsearchQueryMethod method, ElasticsearchOperations elasticsearchOperations) {
|
||||
super(method, elasticsearchOperations);
|
||||
this.tree = new PartTree(method.getName(), method.getEntityInformation().getJavaType());
|
||||
this.mappingContext = elasticsearchOperations.getElasticsearchConverter().getMappingContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute(Object[] parameters) {
|
||||
ParametersParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
|
||||
CriteriaQuery query = createQuery(accessor);
|
||||
if(queryMethod.isPageQuery()){
|
||||
return elasticsearchOperations.queryForPage(query, queryMethod.getEntityInformation().getJavaType());
|
||||
}
|
||||
return elasticsearchOperations.queryForObject(query, queryMethod.getEntityInformation().getJavaType());
|
||||
}
|
||||
|
||||
public CriteriaQuery createQuery(ParametersParameterAccessor accessor) {
|
||||
return new ElasticsearchQueryCreator(tree, accessor, mappingContext).createQuery();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.springframework.data.elasticsearch.repository.query;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.elasticsearch.annotations.Query;
|
||||
import org.springframework.data.elasticsearch.repository.support.ElasticsearchEntityInformation;
|
||||
import org.springframework.data.elasticsearch.repository.support.ElasticsearchEntityInformationCreator;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
public class ElasticsearchQueryMethod extends QueryMethod {
|
||||
|
||||
private final ElasticsearchEntityInformation<?, ?> entityInformation;
|
||||
private Method method;
|
||||
|
||||
public ElasticsearchQueryMethod(Method method, RepositoryMetadata metadata, ElasticsearchEntityInformationCreator elasticsearchEntityInformationCreator) {
|
||||
super(method, metadata);
|
||||
this.entityInformation = elasticsearchEntityInformationCreator.getEntityInformation(metadata.getReturnedDomainClass(method));
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public boolean hasAnnotatedQuery() {
|
||||
return getQueryAnnotation() != null;
|
||||
}
|
||||
|
||||
public String getAnnotatedQuery() {
|
||||
String query = (String) AnnotationUtils.getValue(getQueryAnnotation(), "value");
|
||||
return StringUtils.hasText(query) ? query : null;
|
||||
}
|
||||
|
||||
private Query getQueryAnnotation() {
|
||||
return this.method.getAnnotation(Query.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.springframework.data.elasticsearch.repository.query;
|
||||
|
||||
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.convert.DateTimeConverters;
|
||||
import org.springframework.data.elasticsearch.core.query.StringQuery;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ElasticsearchStringQuery extends AbstractElasticsearchRepositoryQuery{
|
||||
|
||||
private static final Pattern PARAMETER_PLACEHOLDER = Pattern.compile("\\?(\\d+)");
|
||||
private String query;
|
||||
|
||||
private final GenericConversionService conversionService = new GenericConversionService();
|
||||
|
||||
{
|
||||
if (!conversionService.canConvert(java.util.Date.class, String.class)) {
|
||||
conversionService.addConverter(DateTimeConverters.JavaDateConverter.INSTANCE);
|
||||
}
|
||||
if (!conversionService.canConvert(org.joda.time.ReadableInstant.class, String.class)) {
|
||||
conversionService.addConverter(DateTimeConverters.JodaDateTimeConverter.INSTANCE);
|
||||
}
|
||||
if (!conversionService.canConvert(org.joda.time.LocalDateTime.class, String.class)) {
|
||||
conversionService.addConverter(DateTimeConverters.JodaLocalDateTimeConverter.INSTANCE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ElasticsearchStringQuery(ElasticsearchQueryMethod queryMethod, ElasticsearchOperations elasticsearchOperations, String query) {
|
||||
super(queryMethod, elasticsearchOperations);
|
||||
Assert.notNull(query, "Query cannot be empty");
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute(Object[] parameters) {
|
||||
ParametersParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
|
||||
StringQuery stringQuery = createQuery(accessor);
|
||||
if(queryMethod.isPageQuery()){
|
||||
return elasticsearchOperations.queryForPage(stringQuery, queryMethod.getEntityInformation().getJavaType());
|
||||
}
|
||||
return elasticsearchOperations.queryForObject(stringQuery, queryMethod.getEntityInformation().getJavaType());
|
||||
}
|
||||
|
||||
|
||||
protected StringQuery createQuery(ParametersParameterAccessor parameterAccessor) {
|
||||
String queryString = replacePlaceholders(this.query, parameterAccessor);
|
||||
return new StringQuery(queryString);
|
||||
}
|
||||
|
||||
private String replacePlaceholders(String input, ParametersParameterAccessor accessor) {
|
||||
Matcher matcher = PARAMETER_PLACEHOLDER.matcher(input);
|
||||
String result = input;
|
||||
while (matcher.find()) {
|
||||
String group = matcher.group();
|
||||
int index = Integer.parseInt(matcher.group(1));
|
||||
result = result.replace(group, getParameterWithIndex(accessor, index));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getParameterWithIndex(ParametersParameterAccessor accessor, int index) {
|
||||
Object parameter = accessor.getBindableValue(index);
|
||||
if (parameter == null) {
|
||||
return "null";
|
||||
}
|
||||
if (conversionService.canConvert(parameter.getClass(), String.class)) {
|
||||
return conversionService.convert(parameter, String.class);
|
||||
}
|
||||
return parameter.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package org.springframework.data.elasticsearch.repository.query.parser;
|
||||
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.context.PersistentPropertyPath;
|
||||
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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuery,CriteriaQuery>{
|
||||
|
||||
private final MappingContext<?, ElasticsearchPersistentProperty> context;
|
||||
|
||||
public ElasticsearchQueryCreator(PartTree tree, ParameterAccessor parameters, MappingContext<?, ElasticsearchPersistentProperty> context) {
|
||||
super(tree, parameters);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public ElasticsearchQueryCreator(PartTree tree, MappingContext<?, ElasticsearchPersistentProperty> context) {
|
||||
super(tree);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CriteriaQuery create(Part part, Iterator<Object> iterator) {
|
||||
PersistentPropertyPath<ElasticsearchPersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
|
||||
return new CriteriaQuery(from(part.getType(),
|
||||
new Criteria(path.toDotPath(ElasticsearchPersistentProperty.PropertyToFieldNameConverter.INSTANCE)), iterator));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CriteriaQuery and(Part part, CriteriaQuery base, Iterator<Object> iterator) {
|
||||
if (base == null) {
|
||||
return create(part, iterator);
|
||||
}
|
||||
PersistentPropertyPath<ElasticsearchPersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
|
||||
return base.addCriteria(from(part.getType(),
|
||||
new Criteria(path.toDotPath(ElasticsearchPersistentProperty.PropertyToFieldNameConverter.INSTANCE)), iterator));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CriteriaQuery or(CriteriaQuery base, CriteriaQuery query) {
|
||||
return new CriteriaQuery(base.getCriteria().or(query.getCriteria()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CriteriaQuery complete(CriteriaQuery query, Sort sort) {
|
||||
if (query == null) {
|
||||
return null;
|
||||
}
|
||||
return query.addSort(sort);
|
||||
}
|
||||
|
||||
|
||||
private Criteria from(Part.Type type, Criteria instance, Iterator<?> parameters) {
|
||||
Criteria criteria = instance;
|
||||
if (criteria == null) {
|
||||
criteria = new Criteria();
|
||||
}
|
||||
switch (type) {
|
||||
case TRUE:
|
||||
return criteria.is(true);
|
||||
case FALSE:
|
||||
return criteria.is(false);
|
||||
case SIMPLE_PROPERTY:
|
||||
return criteria.is(parameters.next());
|
||||
case NEGATING_SIMPLE_PROPERTY:
|
||||
return criteria.is(parameters.next()).not();
|
||||
case REGEX:
|
||||
return criteria.expression(parameters.next().toString());
|
||||
case LIKE:
|
||||
case STARTING_WITH:
|
||||
return criteria.startsWith(parameters.next().toString());
|
||||
case ENDING_WITH:
|
||||
return criteria.endsWith(parameters.next().toString());
|
||||
case CONTAINING:
|
||||
return criteria.contains(parameters.next().toString());
|
||||
case AFTER:
|
||||
case GREATER_THAN:
|
||||
case GREATER_THAN_EQUAL:
|
||||
return criteria.greaterThanEqual(parameters.next());
|
||||
case BEFORE:
|
||||
case LESS_THAN:
|
||||
case LESS_THAN_EQUAL:
|
||||
return criteria.lessThanEqual(parameters.next());
|
||||
case BETWEEN:
|
||||
return criteria.between(parameters.next(), parameters.next());
|
||||
case IN:
|
||||
return criteria.in(asArray(parameters.next()));
|
||||
case NOT_IN:
|
||||
return criteria.in(asArray(parameters.next())).not();
|
||||
default:
|
||||
throw new InvalidDataAccessApiUsageException("Illegal criteria found '" + type + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
private Object[] asArray(Object o) {
|
||||
if (o instanceof Collection) {
|
||||
return ((Collection<?>) o).toArray();
|
||||
} else if (o.getClass().isArray()) {
|
||||
return (Object[]) o;
|
||||
}
|
||||
return new Object[] { o };
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.support;
|
||||
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @param <ID>
|
||||
*/
|
||||
public interface ElasticsearchEntityInformation<T, ID extends Serializable> extends EntityInformation<T, ID> {
|
||||
|
||||
String getIdAttribute();
|
||||
String getIndexName();
|
||||
String getType();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface ElasticsearchEntityInformationCreator {
|
||||
|
||||
<T, ID extends Serializable> ElasticsearchEntityInformation<T, ID> getEntityInformation(Class<T> domainClass);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.support;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class ElasticsearchEntityInformationCreatorImpl implements ElasticsearchEntityInformationCreator {
|
||||
|
||||
private final MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext;
|
||||
|
||||
public ElasticsearchEntityInformationCreatorImpl(
|
||||
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext) {
|
||||
Assert.notNull(mappingContext);
|
||||
this.mappingContext = mappingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T, ID extends Serializable> ElasticsearchEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
|
||||
ElasticsearchPersistentEntity<T> persistentEntity = (ElasticsearchPersistentEntity<T>) mappingContext
|
||||
.getPersistentEntity(domainClass);
|
||||
return new MappingElasticsearchEntityInformation<T, ID>(persistentEntity);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.support;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
||||
import org.springframework.data.elasticsearch.repository.query.ElasticsearchPartQuery;
|
||||
import org.springframework.data.elasticsearch.repository.query.ElasticsearchQueryMethod;
|
||||
import org.springframework.data.elasticsearch.repository.query.ElasticsearchStringQuery;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.springframework.data.querydsl.QueryDslUtils.QUERY_DSL_PRESENT;
|
||||
|
||||
/**
|
||||
* Factory to create {@link ElasticsearchRepository}
|
||||
*
|
||||
*/
|
||||
public class ElasticsearchRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
private final ElasticsearchOperations elasticsearchOperations;
|
||||
private final ElasticsearchEntityInformationCreator entityInformationCreator;
|
||||
|
||||
public ElasticsearchRepositoryFactory(ElasticsearchOperations elasticsearchOperations) {
|
||||
Assert.notNull(elasticsearchOperations);
|
||||
this.elasticsearchOperations = elasticsearchOperations;
|
||||
this.entityInformationCreator = new ElasticsearchEntityInformationCreatorImpl(elasticsearchOperations.getElasticsearchConverter()
|
||||
.getMappingContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, ID extends Serializable> ElasticsearchEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
|
||||
return entityInformationCreator.getEntityInformation(domainClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
protected Object getTargetRepository(RepositoryMetadata metadata) {
|
||||
SimpleElasticsearchRepository repository = new SimpleElasticsearchRepository(getEntityInformation(metadata.getDomainType()), elasticsearchOperations);
|
||||
repository.setEntityClass(metadata.getDomainType());
|
||||
return repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
|
||||
if (isQueryDslRepository(metadata.getRepositoryInterface())) {
|
||||
throw new IllegalArgumentException("QueryDsl Support has not been implemented yet.");
|
||||
}
|
||||
return SimpleElasticsearchRepository.class;
|
||||
}
|
||||
|
||||
private static boolean isQueryDslRepository(Class<?> repositoryInterface) {
|
||||
return QUERY_DSL_PRESENT && QueryDslPredicateExecutor.class.isAssignableFrom(repositoryInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected QueryLookupStrategy getQueryLookupStrategy(QueryLookupStrategy.Key key) {
|
||||
return new ElasticsearchQueryLookupStrategy();
|
||||
}
|
||||
|
||||
private class ElasticsearchQueryLookupStrategy implements QueryLookupStrategy {
|
||||
|
||||
@Override
|
||||
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, NamedQueries namedQueries) {
|
||||
|
||||
ElasticsearchQueryMethod queryMethod = new ElasticsearchQueryMethod(method, metadata, entityInformationCreator);
|
||||
String namedQueryName = queryMethod.getNamedQueryName();
|
||||
|
||||
if (namedQueries.hasQuery(namedQueryName)) {
|
||||
String namedQuery = namedQueries.getQuery(namedQueryName);
|
||||
return new ElasticsearchStringQuery(queryMethod, elasticsearchOperations, namedQuery);
|
||||
}
|
||||
else if (queryMethod.hasAnnotatedQuery()) {
|
||||
return new ElasticsearchStringQuery(queryMethod, elasticsearchOperations, queryMethod.getAnnotatedQuery());
|
||||
}
|
||||
return new ElasticsearchPartQuery(queryMethod, elasticsearchOperations);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.support;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Spring {@link org.springframework.beans.factory.FactoryBean} implementation to ease container based configuration for XML namespace and JavaConfig.
|
||||
*
|
||||
*/
|
||||
public class ElasticsearchRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends
|
||||
RepositoryFactoryBeanSupport<T, S, ID> {
|
||||
|
||||
private ElasticsearchOperations operations;
|
||||
|
||||
/**
|
||||
* Configures the {@link ElasticsearchOperations} to be used to create Solr repositories.
|
||||
*
|
||||
* @param operations the operations to set
|
||||
*/
|
||||
public void setElasticsearchOperations(ElasticsearchOperations operations) {
|
||||
Assert.notNull(operations);
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
Assert.notNull(operations, "ElasticsearchOperations must be configured!");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected RepositoryFactorySupport createRepositoryFactory() {
|
||||
return new ElasticsearchRepositoryFactory(operations);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.support;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.data.repository.core.support.AbstractEntityInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Elasticsearch specific implementation of {@link org.springframework.data.repository.core.support.AbstractEntityInformation}
|
||||
*
|
||||
* @param <T>
|
||||
* @param <ID>
|
||||
*/
|
||||
public class MappingElasticsearchEntityInformation<T, ID extends Serializable> extends AbstractEntityInformation<T, ID>
|
||||
implements ElasticsearchEntityInformation<T, ID> {
|
||||
|
||||
private final ElasticsearchPersistentEntity<T> entityMetadata;
|
||||
private final String indexName;
|
||||
private final String type;
|
||||
|
||||
public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity<T> entity) {
|
||||
this(entity, null, null);
|
||||
}
|
||||
|
||||
public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity<T> entity, String indexName, String type) {
|
||||
super(entity.getType());
|
||||
this.entityMetadata = entity;
|
||||
this.indexName = indexName;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ID getId(T entity) {
|
||||
ElasticsearchPersistentProperty id = entityMetadata.getIdProperty();
|
||||
try {
|
||||
return (ID) BeanWrapper.create(entity, null).getProperty(id);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("ID could not be resolved", e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<ID> getIdType() {
|
||||
return (Class<ID>) String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdAttribute() {
|
||||
Assert.notNull(entityMetadata.getIdProperty(),"Unable to identify 'id' property in class " + entityMetadata.getType().getSimpleName() +". Make sure the 'id' property is annotated with @Id or named as 'id' or 'documentId' ");
|
||||
return entityMetadata.getIdProperty().getFieldName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexName() {
|
||||
return indexName != null? indexName : entityMetadata.getIndexName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return type != null? type : entityMetadata.getIndexType();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright 2012 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.elasticsearch.repository.support;
|
||||
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.*;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.GetQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.SearchQuery;
|
||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.index.query.QueryBuilders.inQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
||||
|
||||
/**
|
||||
* Elasticsearch specific repository implementation. Likely to be used as target within {@link ElasticsearchRepositoryFactory}
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class SimpleElasticsearchRepository<T> implements ElasticsearchRepository<T, String> {
|
||||
|
||||
|
||||
private ElasticsearchOperations elasticsearchOperations;
|
||||
private Class<T> entityClass;
|
||||
private ElasticsearchEntityInformation<T, String> entityInformation;
|
||||
|
||||
public SimpleElasticsearchRepository() {
|
||||
}
|
||||
|
||||
public SimpleElasticsearchRepository(ElasticsearchOperations elasticsearchOperations) {
|
||||
Assert.notNull(elasticsearchOperations);
|
||||
this.setElasticsearchOperations(elasticsearchOperations);
|
||||
}
|
||||
|
||||
public SimpleElasticsearchRepository(ElasticsearchEntityInformation<T, String> metadata, ElasticsearchOperations elasticsearchOperations) {
|
||||
this(elasticsearchOperations);
|
||||
Assert.notNull(metadata);
|
||||
this.entityInformation = metadata;
|
||||
setEntityClass(this.entityInformation.getJavaType());
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void createIndex(){
|
||||
elasticsearchOperations.createIndex(getEntityClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T findOne(String id) {
|
||||
GetQuery query = new GetQuery();
|
||||
query.setId(id);
|
||||
return elasticsearchOperations.queryForObject(query, getEntityClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<T> findAll() {
|
||||
int itemCount = (int) this.count();
|
||||
if (itemCount == 0) {
|
||||
return new PageImpl<T>(Collections.<T> emptyList());
|
||||
}
|
||||
return this.findAll(new PageRequest(0, Math.max(1, itemCount)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<T> findAll(Pageable pageable) {
|
||||
SearchQuery query = new SearchQuery();
|
||||
query.setElasticsearchQuery(matchAllQuery());
|
||||
return elasticsearchOperations.queryForPage(query, getEntityClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<T> findAll(Sort sort) {
|
||||
SearchQuery query = new SearchQuery();
|
||||
query.setElasticsearchQuery(matchAllQuery());
|
||||
query.setPageable(new PageRequest(0,Integer.MAX_VALUE, sort));
|
||||
return elasticsearchOperations.queryForPage(query, getEntityClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<T> findAll(Iterable<String> ids) {
|
||||
SearchQuery query = new SearchQuery();
|
||||
query.setElasticsearchQuery(inQuery(entityInformation.getIdAttribute(), ids));
|
||||
return elasticsearchOperations.queryForPage(query, getEntityClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
SearchQuery query = new SearchQuery();
|
||||
return elasticsearchOperations.count(query,getEntityClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T> S save(S entity) {
|
||||
Assert.notNull(entity, "Cannot save 'null' entity.");
|
||||
elasticsearchOperations.index(createIndexQuery(entity));
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
|
||||
return entity;
|
||||
}
|
||||
|
||||
public <S extends T> List<S> save(List<S> entities) {
|
||||
Assert.notNull(entities, "Cannot insert 'null' as a List.");
|
||||
Assert.notEmpty(entities,"Cannot insert empty List.");
|
||||
List<IndexQuery> queries = new ArrayList<IndexQuery>();
|
||||
for(S s:entities){
|
||||
queries.add(createIndexQuery(s));
|
||||
}
|
||||
elasticsearchOperations.bulkIndex(queries);
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
|
||||
return entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T> S index(S entity) {
|
||||
return save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T> Iterable<S> save(Iterable<S> entities) {
|
||||
Assert.notNull(entities, "Cannot insert 'null' as a List.");
|
||||
if (!(entities instanceof Collection<?>)) {
|
||||
throw new InvalidDataAccessApiUsageException("Entities have to be inside a collection");
|
||||
}
|
||||
List<IndexQuery> queries = new ArrayList<IndexQuery>();
|
||||
for(S s: entities){
|
||||
queries.add(createIndexQuery(s));
|
||||
}
|
||||
elasticsearchOperations.bulkIndex(queries);
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
|
||||
return entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String id) {
|
||||
return findOne(id) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<T> search(QueryBuilder elasticsearchQuery) {
|
||||
SearchQuery query = new SearchQuery();
|
||||
query.setElasticsearchQuery(elasticsearchQuery);
|
||||
return elasticsearchOperations.queryForPage(query, getEntityClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<T> search(QueryBuilder elasticsearchQuery, Pageable pageable) {
|
||||
SearchQuery query = new SearchQuery();
|
||||
query.setElasticsearchQuery(elasticsearchQuery);
|
||||
query.setPageable(pageable);
|
||||
return elasticsearchOperations.queryForPage(query, getEntityClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<T> search(SearchQuery query){
|
||||
return elasticsearchOperations.queryForPage(query, getEntityClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String id) {
|
||||
Assert.notNull(id, "Cannot delete entity with id 'null'.");
|
||||
elasticsearchOperations.delete(entityInformation.getIndexName(), entityInformation.getType(),id);
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName(),true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(T entity) {
|
||||
Assert.notNull(entity, "Cannot delete 'null' entity.");
|
||||
delete(extractIdFromBean(entity));
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Iterable<? extends T> entities) {
|
||||
Assert.notNull(entities, "Cannot delete 'null' list.");
|
||||
for (T entity : entities) {
|
||||
delete(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
DeleteQuery query = new DeleteQuery();
|
||||
query.setElasticsearchQuery(matchAllQuery());
|
||||
elasticsearchOperations.delete(query, getEntityClass());
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName(),true);
|
||||
}
|
||||
|
||||
private IndexQuery createIndexQuery(T entity){
|
||||
IndexQuery query = new IndexQuery();
|
||||
query.setObject(entity);
|
||||
query.setId(extractIdFromBean(entity));
|
||||
return query;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class<T> resolveReturnedClassFromGenericType() {
|
||||
ParameterizedType parameterizedType = resolveReturnedClassFromGenericType(getClass());
|
||||
return (Class<T>) parameterizedType.getActualTypeArguments()[0];
|
||||
}
|
||||
|
||||
private ParameterizedType resolveReturnedClassFromGenericType(Class<?> clazz) {
|
||||
Object genericSuperclass = clazz.getGenericSuperclass();
|
||||
if (genericSuperclass instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
|
||||
Type rawtype = parameterizedType.getRawType();
|
||||
if (SimpleElasticsearchRepository.class.equals(rawtype)) {
|
||||
return parameterizedType;
|
||||
}
|
||||
}
|
||||
return resolveReturnedClassFromGenericType(clazz.getSuperclass());
|
||||
}
|
||||
|
||||
public Class<T> getEntityClass() {
|
||||
if (!isEntityClassSet()) {
|
||||
try {
|
||||
this.entityClass = resolveReturnedClassFromGenericType();
|
||||
} catch (Exception e) {
|
||||
throw new InvalidDataAccessApiUsageException("Unable to resolve EntityClass. Please use according setter!", e);
|
||||
}
|
||||
}
|
||||
return entityClass;
|
||||
}
|
||||
|
||||
private boolean isEntityClassSet() {
|
||||
return entityClass != null;
|
||||
}
|
||||
|
||||
public final void setEntityClass(Class<T> entityClass) {
|
||||
Assert.notNull(entityClass, "EntityClass must not be null.");
|
||||
this.entityClass = entityClass;
|
||||
}
|
||||
|
||||
public final void setElasticsearchOperations(ElasticsearchOperations elasticsearchOperations) {
|
||||
Assert.notNull(elasticsearchOperations, "ElasticsearchOperations must not be null.");
|
||||
this.elasticsearchOperations = elasticsearchOperations;
|
||||
}
|
||||
|
||||
|
||||
private String extractIdFromBean(T entity) {
|
||||
if (entityInformation != null) {
|
||||
return entityInformation.getId(entity);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user