org.springframework.data.solr.server.support.SolrServerUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.data.solr.server.support.SolrServerUtils.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 org.springframework.data.solr.server.support;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.client.solrj.impl.CloudSolrServer;
import org.apache.solr.client.solrj.impl.LBHttpSolrServer;
import org.apache.solr.core.CoreContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.solr.VersionUtil;
import org.springframework.data.solr.core.mapping.SolrDocument;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

/**
 * @author Christoph Strobl
 */
public class SolrServerUtils {

    private static final Logger logger = LoggerFactory.getLogger(SolrServerUtils.class);
    private static final String SLASH = "/";

    private SolrServerUtils() {
    }

    /**
     * Resolve solr core/collection name for given type.
     * 
     * @param type
     * @return empty string if {@link SolrDocument} not present or {@link SolrDocument#solrCoreName()} is blank.
     * @since 1.1
     */
    public static String resolveSolrCoreName(Class<?> type) {
        SolrDocument annotation = AnnotationUtils.findAnnotation(type, SolrDocument.class);
        if (annotation != null && StringUtils.isNotBlank(annotation.solrCoreName())) {
            return annotation.solrCoreName();
        }
        return "";
    }

    public static <T extends SolrServer> T clone(T solrServer) {
        return clone(solrServer, null);
    }

    /**
     * Create a clone of given {@link SolrServer} and modify baseUrl of clone to point to the given core.
     * 
     * @param solrServer Non null reference {@link SolrServer} to copy properties from.
     * @param core Name of solr core to point to.
     * @return
     * @throws BeanInstantiationException if creating instance failed
     */
    @SuppressWarnings("unchecked")
    public static <T extends SolrServer> T clone(T solrServer, String core) {
        Assert.notNull(solrServer);
        String shortName = getSolrServerTypeName(solrServer);
        if (shortName.equals("SolrServer")) { // cannot create instance of interface,
            return solrServer;
        }

        SolrServer clone = null;
        if (shortName.equals("HttpSolrServer") || shortName.equals("CommonsHttpSolrServer")) {
            clone = cloneHttpSolrServer(solrServer, core);
        } else if (shortName.equals("LBHttpSolrServer")) {
            clone = cloneLBHttpSolrServer(solrServer, core);
        } else if (shortName.equals("CloudSolrServer")) {
            clone = cloneCloudSolrServer(solrServer, core);
        } else if (shortName.equals("EmbeddedSolrServer")) {
            clone = cloneEmbeddedSolrServer(solrServer, core);
        }

        if (clone == null) {
            throw new BeanInstantiationException(solrServer.getClass(),
                    "Cannot create instace of " + shortName + ".");
        }

        copyProperties(solrServer, clone);
        return (T) clone;
    }

    /**
     * Append core to given baseUrl
     * 
     * @param baseUrl
     * @param core
     * @return
     */
    public static String appendCoreToBaseUrl(String baseUrl, String core) {
        Assert.notNull(baseUrl);

        if (!org.springframework.util.StringUtils.hasText(core)) {
            return baseUrl;
        }
        String url = baseUrl;
        if (!StringUtils.endsWith(baseUrl, SLASH)) {
            url = url + SLASH;
        }
        url = url + core;
        return url;
    }

    private static String getSolrServerTypeName(SolrServer solrServer) {
        Class<?> solrServerType = ClassUtils.isCglibProxy(solrServer) ? ClassUtils.getUserClass(solrServer)
                : solrServer.getClass();
        String shortName = ClassUtils.getShortName(solrServerType);
        return shortName;
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private static SolrServer cloneEmbeddedSolrServer(SolrServer solrServer, String core) {

        CoreContainer coreContainer = ((EmbeddedSolrServer) solrServer).getCoreContainer();
        try {
            Constructor constructor = ClassUtils.getConstructorIfAvailable(solrServer.getClass(),
                    CoreContainer.class, String.class);
            return (SolrServer) BeanUtils.instantiateClass(constructor, coreContainer, core);
        } catch (Exception e) {
            throw new BeanInstantiationException(solrServer.getClass(),
                    "Cannot create instace of " + solrServer.getClass() + ".", e);
        }
    }

    private static SolrServer cloneHttpSolrServer(SolrServer solrServer, String core) {
        if (solrServer == null) {
            return null;
        }

        Method baseUrlGetterMethod = ClassUtils.getMethodIfAvailable(solrServer.getClass(), "getBaseURL");
        if (baseUrlGetterMethod == null) {
            return null;
        }

        String baseUrl = (String) ReflectionUtils.invokeMethod(baseUrlGetterMethod, solrServer);
        String url = appendCoreToBaseUrl(baseUrl, core);

        try {

            HttpClient clientToUse = readAndCloneHttpClient(solrServer);

            if (clientToUse != null) {
                Constructor<? extends SolrServer> constructor = (Constructor<? extends SolrServer>) ClassUtils
                        .getConstructorIfAvailable(solrServer.getClass(), String.class, HttpClient.class);
                if (constructor != null) {
                    return (SolrServer) BeanUtils.instantiateClass(constructor, url, clientToUse);
                }
            }

            Constructor<? extends SolrServer> constructor = (Constructor<? extends SolrServer>) ClassUtils
                    .getConstructorIfAvailable(solrServer.getClass(), String.class);
            return (SolrServer) BeanUtils.instantiateClass(constructor, url);
        } catch (Exception e) {
            throw new BeanInstantiationException(solrServer.getClass(),
                    "Cannot create instace of " + solrServer.getClass() + ". ", e);
        }
    }

    private static LBHttpSolrServer cloneLBHttpSolrServer(SolrServer solrServer, String core) {
        if (solrServer == null) {
            return null;
        }

        LBHttpSolrServer clone = null;
        try {
            if (VersionUtil.isSolr3XAvailable()) {
                clone = cloneSolr3LBHttpServer(solrServer, core);
            } else if (VersionUtil.isSolr4XAvailable()) {
                clone = cloneSolr4LBHttpServer(solrServer, core);
            }
        } catch (Exception e) {
            throw new BeanInstantiationException(solrServer.getClass(),
                    "Cannot create instace of " + solrServer.getClass() + ". ", e);
        }
        Object o = readField(solrServer, "interval");
        if (o != null) {
            clone.setAliveCheckInterval(Integer.valueOf(o.toString()).intValue());
        }
        return clone;
    }

    private static SolrServer cloneCloudSolrServer(SolrServer solrServer, String core) {
        if (VersionUtil.isSolr3XAvailable() || solrServer == null) {
            return null;
        }

        CloudSolrServer cloudServer = (CloudSolrServer) solrServer;
        String zkHost = readField(solrServer, "zkHost");

        Constructor<? extends SolrServer> constructor = (Constructor<? extends SolrServer>) ClassUtils
                .getConstructorIfAvailable(solrServer.getClass(), String.class, LBHttpSolrServer.class);

        CloudSolrServer clone = (CloudSolrServer) BeanUtils.instantiateClass(constructor, zkHost,
                cloneLBHttpSolrServer(cloudServer.getLbServer(), core));

        if (org.springframework.util.StringUtils.hasText(core)) {
            clone.setDefaultCollection(core);
        }
        return clone;
    }

    private static LBHttpSolrServer cloneSolr3LBHttpServer(SolrServer solrServer, String core)
            throws MalformedURLException {
        CopyOnWriteArrayList<?> list = readField(solrServer, "aliveServers");

        String[] servers = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
            servers[i] = appendCoreToBaseUrl(list.get(i).toString(), core);
        }
        return new LBHttpSolrServer(servers);
    }

    private static LBHttpSolrServer cloneSolr4LBHttpServer(SolrServer solrServer, String core)
            throws MalformedURLException, InstantiationException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
        Map<String, ?> map = readField(solrServer, "aliveServers");

        String[] servers = new String[map.size()];
        int i = 0;
        for (String key : map.keySet()) {
            servers[i] = appendCoreToBaseUrl(key, core);
            i++;
        }

        Boolean isInternalCient = readField(solrServer, "clientIsInternal");

        if (isInternalCient != null && !isInternalCient) {
            HttpClient clientToUse = readAndCloneHttpClient(solrServer);
            return new LBHttpSolrServer(clientToUse, servers);
        }
        return new LBHttpSolrServer(servers);
    }

    private static HttpClient readAndCloneHttpClient(SolrServer solrServer) throws InstantiationException,
            IllegalAccessException, IllegalArgumentException, InvocationTargetException {

        HttpClient sourceClient = readField(solrServer, "httpClient");
        return cloneHttpClient(sourceClient);
    }

    private static HttpClient cloneHttpClient(HttpClient sourceClient) throws InstantiationException,
            IllegalAccessException, IllegalArgumentException, InvocationTargetException {

        if (sourceClient == null) {
            return null;
        }

        Class<?> clientType = ClassUtils.getUserClass(sourceClient);
        Constructor<?> constructor = ClassUtils.getConstructorIfAvailable(clientType, HttpParams.class);
        if (constructor != null) {

            HttpClient targetClient = (HttpClient) constructor.newInstance(sourceClient.getParams());
            BeanUtils.copyProperties(sourceClient, targetClient);
            return targetClient;
        } else {
            return new DefaultHttpClient(sourceClient.getParams());
        }

    }

    @SuppressWarnings("unchecked")
    private static <T> T readField(SolrServer solrServer, String fieldName) {
        Field field = ReflectionUtils.findField(solrServer.getClass(), fieldName);
        if (field == null) {
            return null;
        }
        ReflectionUtils.makeAccessible(field);
        return (T) ReflectionUtils.getField(field, solrServer);
    }

    /**
     * Solr property names do not match the getters/setters used for them. Check on any write method, try to find the
     * according property and set the value for it. Will ignore all other, and nested properties
     * 
     * @param source
     * @param target
     */
    private static void copyProperties(SolrServer source, SolrServer target) {
        BeanWrapperImpl wrapperImpl = new BeanWrapperImpl(source);
        for (PropertyDescriptor pd : wrapperImpl.getPropertyDescriptors()) {
            Method writer = pd.getWriteMethod();
            if (writer != null) {
                try {
                    Field property = ReflectionUtils.findField(source.getClass(), pd.getName());
                    if (property != null) {
                        ReflectionUtils.makeAccessible(property);
                        Object o = ReflectionUtils.getField(property, source);
                        if (o != null) {
                            writer.invoke(target, o);
                        }
                    }
                } catch (Exception e) {
                    logger.warn("Could not copy property value for: " + pd.getName(), e);
                }
            }
        }
    }

}