com.frank.search.solr.repository.support.SimpleSolrRepository.java Source code

Java tutorial

Introduction

Here is the source code for com.frank.search.solr.repository.support.SimpleSolrRepository.java

Source

/*
 * Copyright 2012 - 2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.frank.search.solr.repository.support;

import com.frank.search.solr.core.query.Query;
import org.apache.solr.common.SolrInputDocument;
import org.springframework.dao.InvalidDataAccessApiUsageException;
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 com.frank.search.solr.core.SolrOperations;
import com.frank.search.solr.core.SolrTransactionSynchronizationAdapterBuilder;
import com.frank.search.solr.core.query.Criteria;
import com.frank.search.solr.core.query.SimpleFilterQuery;
import com.frank.search.solr.core.query.SimpleQuery;
import com.frank.search.solr.core.query.SolrPageRequest;
import com.frank.search.solr.repository.SolrCrudRepository;
import com.frank.search.solr.repository.query.SolrEntityInformation;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;

/**
 * Solr specific repository implementation. Likely to be used as target within {@link SolrRepositoryFactory}
 * 
 * @param <T>
 * @Param <ID>
 * @author Christoph Strobl
 */
public class SimpleSolrRepository<T, ID extends Serializable> implements SolrCrudRepository<T, ID> {

    private static final String DEFAULT_ID_FIELD = "id";

    private SolrOperations solrOperations;
    private String idFieldName = DEFAULT_ID_FIELD;
    private Class<T> entityClass;
    private SolrEntityInformation<T, ?> entityInformation;

    public SimpleSolrRepository() {

    }

    /**
     * @param solrOperations must not be null
     */
    public SimpleSolrRepository(SolrOperations solrOperations) {
        Assert.notNull(solrOperations);

        this.setSolrOperations(solrOperations);
    }

    /**
     * @param metadata must not be null
     * @param solrOperations must not be null
     */
    public SimpleSolrRepository(SolrEntityInformation<T, ?> metadata, SolrOperations solrOperations) {
        this(solrOperations);
        Assert.notNull(metadata);

        this.entityInformation = metadata;
        setIdFieldName(this.entityInformation.getIdAttribute());
        setEntityClass(this.entityInformation.getJavaType());
    }

    /**
     * @param solrOperations must not be null
     * @param entityClass
     */
    public SimpleSolrRepository(SolrOperations solrOperations, Class<T> entityClass) {
        this(solrOperations);

        this.setEntityClass(entityClass);
    }

    @Override
    public T findOne(ID id) {
        return getSolrOperations().queryForObject(new SimpleQuery(new Criteria(this.idFieldName).is(id)),
                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 SolrPageRequest(0, itemCount));
    }

    @Override
    public Page<T> findAll(Pageable pageable) {
        return getSolrOperations()
                .queryForPage(new SimpleQuery(new Criteria(Criteria.WILDCARD).expression(Criteria.WILDCARD))
                        .setPageRequest(pageable), getEntityClass());
    }

    @Override
    public Iterable<T> findAll(Sort sort) {
        int itemCount = (int) this.count();
        if (itemCount == 0) {
            return new PageImpl<T>(Collections.<T>emptyList());
        }
        return getSolrOperations()
                .queryForPage(new SimpleQuery(new Criteria(Criteria.WILDCARD).expression(Criteria.WILDCARD))
                        .setPageRequest(new SolrPageRequest(0, itemCount)).addSort(sort), getEntityClass());
    }

    @Override
    public Iterable<T> findAll(Iterable<ID> ids) {
        Query query = new SimpleQuery(new Criteria(this.idFieldName).in(ids));
        query.setPageRequest(new SolrPageRequest(0, (int) count(query)));

        return getSolrOperations().queryForPage(query, getEntityClass());
    }

    @Override
    public long count() {
        return count(new SimpleQuery(new Criteria(Criteria.WILDCARD).expression(Criteria.WILDCARD)));
    }

    protected long count(Query query) {
        Query countQuery = SimpleQuery.fromQuery(query);
        return getSolrOperations().count(countQuery);
    }

    @Override
    public <S extends T> S save(S entity) {
        Assert.notNull(entity, "Cannot save 'null' entity.");
        registerTransactionSynchronisationIfSynchronisationActive();
        this.solrOperations.saveBean(entity);
        commitIfTransactionSynchronisationIsInactive();
        return 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");
        }

        registerTransactionSynchronisationIfSynchronisationActive();
        this.solrOperations.saveBeans((Collection<? extends T>) entities);
        commitIfTransactionSynchronisationIsInactive();
        return entities;
    }

    @Override
    public boolean exists(ID id) {
        return findOne(id) != null;
    }

    @Override
    public void delete(ID id) {
        Assert.notNull(id, "Cannot delete entity with id 'null'.");

        registerTransactionSynchronisationIfSynchronisationActive();
        this.solrOperations.deleteById(id.toString());
        commitIfTransactionSynchronisationIsInactive();
    }

    @Override
    public void delete(T entity) {
        Assert.notNull(entity, "Cannot delete 'null' entity.");

        delete(Arrays.asList(entity));
    }

    @Override
    public void delete(Iterable<? extends T> entities) {
        Assert.notNull(entities, "Cannot delete 'null' list.");

        ArrayList<String> idsToDelete = new ArrayList<String>();
        for (T entity : entities) {
            idsToDelete.add(extractIdFromBean(entity).toString());
        }

        registerTransactionSynchronisationIfSynchronisationActive();
        this.solrOperations.deleteById(idsToDelete);
        commitIfTransactionSynchronisationIsInactive();
    }

    @Override
    public void deleteAll() {
        registerTransactionSynchronisationIfSynchronisationActive();
        this.solrOperations
                .delete(new SimpleFilterQuery(new Criteria(Criteria.WILDCARD).expression(Criteria.WILDCARD)));
        commitIfTransactionSynchronisationIsInactive();
    }

    public final String getIdFieldName() {
        return idFieldName;
    }

    public final void setIdFieldName(String idFieldName) {
        Assert.notNull(idFieldName, "ID Field cannot be null.");

        this.idFieldName = idFieldName;
    }

    @SuppressWarnings("unchecked")
    private Class<T> resolveReturnedClassFromGernericType() {
        ParameterizedType parameterizedType = resolveReturnedClassFromGernericType(getClass());
        return (Class<T>) parameterizedType.getActualTypeArguments()[0];
    }

    private ParameterizedType resolveReturnedClassFromGernericType(Class<?> clazz) {
        Object genericSuperclass = clazz.getGenericSuperclass();
        if (genericSuperclass instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
            Type rawtype = parameterizedType.getRawType();
            if (SimpleSolrRepository.class.equals(rawtype)) {
                return parameterizedType;
            }
        }
        return resolveReturnedClassFromGernericType(clazz.getSuperclass());
    }

    public Class<T> getEntityClass() {
        if (!isEntityClassSet()) {
            try {
                this.entityClass = resolveReturnedClassFromGernericType();
            } 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 setSolrOperations(SolrOperations solrOperations) {
        Assert.notNull(solrOperations, "SolrOperations must not be null.");

        this.solrOperations = solrOperations;
    }

    public final SolrOperations getSolrOperations() {
        return solrOperations;
    }

    private Object extractIdFromBean(T entity) {
        if (entityInformation != null) {
            return entityInformation.getId(entity);
        }

        SolrInputDocument solrInputDocument = this.solrOperations.convertBeanToSolrInputDocument(entity);
        return extractIdFromSolrInputDocument(solrInputDocument);
    }

    private String extractIdFromSolrInputDocument(SolrInputDocument solrInputDocument) {
        Assert.notNull(solrInputDocument.getField(idFieldName),
                "Unable to find field '" + idFieldName + "' in SolrDocument.");
        Assert.notNull(solrInputDocument.getField(idFieldName).getValue(), "ID must not be 'null'.");

        return solrInputDocument.getField(idFieldName).getValue().toString();
    }

    private void registerTransactionSynchronisationIfSynchronisationActive() {
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            registerTransactionSynchronisationAdapter();
        }
    }

    private void registerTransactionSynchronisationAdapter() {
        TransactionSynchronizationManager.registerSynchronization(SolrTransactionSynchronizationAdapterBuilder
                .forOperations(this.solrOperations).withDefaultBehaviour());
    }

    private void commitIfTransactionSynchronisationIsInactive() {
        if (!TransactionSynchronizationManager.isSynchronizationActive()) {
            this.solrOperations.commit();
        }
    }

}