Java tutorial
/* * 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); } } } } }