Java tutorial
/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package ddf.catalog.solr.external; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.apache.commons.lang.StringUtils; import org.apache.solr.client.solrj.SolrClient; import org.codice.ddf.configuration.PropertyResolver; import org.codice.solr.factory.ConfigurationStore; import org.codice.solr.factory.SolrClientFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ddf.catalog.data.ContentType; import ddf.catalog.filter.FilterAdapter; import ddf.catalog.operation.CreateRequest; import ddf.catalog.operation.CreateResponse; import ddf.catalog.operation.DeleteRequest; import ddf.catalog.operation.DeleteResponse; import ddf.catalog.operation.QueryRequest; import ddf.catalog.operation.SourceResponse; import ddf.catalog.operation.UpdateRequest; import ddf.catalog.operation.UpdateResponse; import ddf.catalog.source.CatalogProvider; import ddf.catalog.source.IngestException; import ddf.catalog.source.SourceMonitor; import ddf.catalog.source.UnsupportedQueryException; import ddf.catalog.source.solr.DynamicSchemaResolver; import ddf.catalog.source.solr.SolrCatalogProvider; import ddf.catalog.source.solr.SolrFilterDelegateFactory; import ddf.catalog.util.impl.MaskableImpl; /** * Catalog Provider that interfaces with a Standalone external (HTTP) Solr Server */ public class SolrHttpCatalogProvider extends MaskableImpl implements CatalogProvider { private static final String PING_ERROR_MESSAGE = "Solr Server ping failed."; private static final String OK_STATUS = "OK"; private static final String DESCRIBABLE_PROPERTIES_FILE = "/describable.properties"; private static final String SOLR_CATALOG_CORE_NAME = "catalog"; private static final Logger LOGGER = LoggerFactory.getLogger(SolrHttpCatalogProvider.class); private static Properties describableProperties = new Properties(); static { try (InputStream inputStream = SolrHttpCatalogProvider.class .getResourceAsStream(DESCRIBABLE_PROPERTIES_FILE)) { describableProperties.load(inputStream); } catch (IOException e) { LOGGER.info("Did not load properties properly.", e); } } private String url = SolrClientFactory.getDefaultHttpsAddress(); private CatalogProvider provider = new UnconfiguredCatalogProvider(); private SolrClient client; private FilterAdapter filterAdapter; private SolrFilterDelegateFactory solrFilterDelegateFactory; private DynamicSchemaResolver resolver; private Future<SolrClient> clientFuture; /** * Simple constructor * * @param filterAdapter * @param client - {@link SolrClient} to handle requests */ public SolrHttpCatalogProvider(FilterAdapter filterAdapter, SolrClient client, SolrFilterDelegateFactory solrFilterDelegateFactory, DynamicSchemaResolver resolver) { this.filterAdapter = filterAdapter; this.client = client; this.solrFilterDelegateFactory = solrFilterDelegateFactory; this.resolver = (resolver == null) ? new DynamicSchemaResolver() : resolver; } public SolrHttpCatalogProvider(FilterAdapter filterAdapter, SolrClient client, SolrFilterDelegateFactory solrFilterDelegateFactory) { this(filterAdapter, client, solrFilterDelegateFactory, null); } public SolrHttpCatalogProvider(FilterAdapter filterAdapter, SolrFilterDelegateFactory solrFilterDelegateFactory) { this(filterAdapter, null, solrFilterDelegateFactory, null); updateClient(); } @Override public void maskId(String id) { super.maskId(id); if (!(provider instanceof UnconfiguredCatalogProvider)) { provider.maskId(id); } } /** * Used to signal to the Solr client to commit on every transaction. Updates * the underlying ConfigurationStore so that the property is propagated * throughout the Solr Catalog Provider code * * @param forceAutoCommit */ public void setForceAutoCommit(boolean forceAutoCommit) { ConfigurationStore.getInstance().setForceAutoCommit(forceAutoCommit); } public void setDisableTextPath(boolean disableTextPath) { ConfigurationStore.getInstance().setDisableTextPath(disableTextPath); } @Override public Set<ContentType> getContentTypes() { return getProvider().getContentTypes(); } @Override public boolean isAvailable() { return getProvider().isAvailable(); } @Override public boolean isAvailable(SourceMonitor arg0) { return getProvider().isAvailable(arg0); } @Override public SourceResponse query(QueryRequest queryRequest) throws UnsupportedQueryException { return getProvider().query(queryRequest); } @Override public String getDescription() { return describableProperties.getProperty("description"); } @Override public String getOrganization() { return describableProperties.getProperty("organization"); } @Override public String getTitle() { return describableProperties.getProperty("name"); } @Override public String getVersion() { return describableProperties.getProperty("version"); } @Override public CreateResponse create(CreateRequest createRequest) throws IngestException { return getProvider().create(createRequest); } @Override public DeleteResponse delete(DeleteRequest deleteRequest) throws IngestException { return getProvider().delete(deleteRequest); } @Override public UpdateResponse update(UpdateRequest updateRequest) throws IngestException { return getProvider().update(updateRequest); } /** * Shutdown the connection to Solr and releases resources. */ public void shutdown() { LOGGER.info("Closing connection to solr client."); if (getClient() != null) { try { getClient().close(); } catch (IOException e) { LOGGER.warn("Unable to close Solr client", e); } } } public String getUrl() { return url; } /** * This method exists only as a workaround to a Aries Blueprint bug. If Blueprint is upgraded or * fixed, this method should be removed and a different update(Map properties) method should be * called directly. * * @param url */ public void setUrl(String url) { updateClient(PropertyResolver.resolveProperties(url)); } /** * Updates the configuration of the Solr Server if necessary * * @param urlValue - url to the Solr Server */ public void updateClient(String urlValue) { LOGGER.info("New url {}", urlValue); if (urlValue != null) { if (!StringUtils.equalsIgnoreCase(urlValue.trim(), url) || getClient() == null) { url = urlValue.trim(); if (getClient() != null) { LOGGER.info( "Shutting down the connection manager to the Solr Server and releasing allocated resources."); try { getClient().close(); } catch (IOException e) { LOGGER.warn("Unable to close Solr client", e); } LOGGER.info("Shutdown complete."); } updateClient(); } } else { // sets to null url = null; } } private void updateClient() { clientFuture = SolrClientFactory.getHttpSolrClient(url, SOLR_CATALOG_CORE_NAME); client = null; } private CatalogProvider getProvider() { if (!isClientConnected(getClient())) { return new UnconfiguredCatalogProvider(); } if (provider instanceof UnconfiguredCatalogProvider) { provider = new SolrCatalogProvider(getClient(), filterAdapter, solrFilterDelegateFactory, resolver); } provider.maskId(getId()); return provider; } private boolean isClientConnected(SolrClient solr) { if (solr == null) { return false; } try { return OK_STATUS.equals(solr.ping().getResponse().get("status")); } catch (Exception e) { /* * if we get any type of exception, whether declared by Solr or not, we do not want to * fail, we just want to return false */ LOGGER.warn(PING_ERROR_MESSAGE, e); } return false; } private SolrClient getClient() { if (client == null && clientFuture != null) { try { return clientFuture.get(5, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { LOGGER.debug("Failed to get client from future", e); } } return client; } /** * This class is used to signify an unconfigured CatalogProvider instance. If a user tries to * unsuccessfully connect to Solr, then a message will be displayed to check the * connection. * * @author Ashraf Barakat, Lockheed Martin * @author ddf.isgs@lmco.com */ private static class UnconfiguredCatalogProvider implements CatalogProvider { private static final String CLIENT_DISCONNECTED_MESSAGE = "Solr client is not connected. Please check Solr status or url, and then retry."; @Override public Set<ContentType> getContentTypes() { throw new IllegalArgumentException(CLIENT_DISCONNECTED_MESSAGE); } @Override public boolean isAvailable() { return false; } @Override public boolean isAvailable(SourceMonitor arg0) { return false; } @Override public SourceResponse query(QueryRequest arg0) throws UnsupportedQueryException { throw new IllegalArgumentException(CLIENT_DISCONNECTED_MESSAGE); } @Override public String getDescription() { throw new IllegalArgumentException(CLIENT_DISCONNECTED_MESSAGE); } @Override public String getId() { throw new IllegalArgumentException(CLIENT_DISCONNECTED_MESSAGE); } @Override public String getOrganization() { throw new IllegalArgumentException(CLIENT_DISCONNECTED_MESSAGE); } @Override public String getTitle() { throw new IllegalArgumentException(CLIENT_DISCONNECTED_MESSAGE); } @Override public String getVersion() { throw new IllegalArgumentException(CLIENT_DISCONNECTED_MESSAGE); } @Override public void maskId(String arg0) { // no op } @Override public CreateResponse create(CreateRequest arg0) throws IngestException { throw new IllegalArgumentException(CLIENT_DISCONNECTED_MESSAGE); } @Override public DeleteResponse delete(DeleteRequest arg0) throws IngestException { throw new IllegalArgumentException(CLIENT_DISCONNECTED_MESSAGE); } @Override public UpdateResponse update(UpdateRequest arg0) throws IngestException { throw new IllegalArgumentException(CLIENT_DISCONNECTED_MESSAGE); } } }