/**
* 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.source.opensearch;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import org.apache.commons.lang.StringUtils;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.jaxrs.client.Client;
import org.apache.cxf.jaxrs.client.ClientConfiguration;
import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.transport.http.HTTPConduit;
import org.codice.ddf.endpoints.OpenSearch;
import org.codice.ddf.endpoints.rest.RESTService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ddf.catalog.filter.FilterAdapter;
import ddf.catalog.operation.Query;
import ddf.catalog.source.UnsupportedQueryException;
import ddf.security.settings.SecuritySettingsService;
/**
* This class wraps the CXF JAXRS code to make it easier to use and also easier to test. Most of
* the CXF code uses static methods to construct the web clients, which is inherently difficult to
* mock up when testing.
*/
public class OpenSearchConnection {
private static final transient Logger LOGGER = LoggerFactory
.getLogger(OpenSearchConnection.class);
protected OpenSearch openSearch;
protected RESTService restService;
protected Client openSearchClient;
protected Client restServiceClient;
private FilterAdapter filterAdapter;
private String username;
private String password;
private SecuritySettingsService securitySettingsService;
/**
* Default Constructor
* @param endpointUrl - OpenSearch URL to connect to
* @param filterAdapter - adapter to translate between DDF REST and OpenSearch
* @param securitySettings - Service used to obtain settings for secure communications.
* @param username - Basic Auth user name
* @param password - Basic Auth password
*/
public OpenSearchConnection(String endpointUrl, FilterAdapter filterAdapter,
SecuritySettingsService securitySettings, String username, String password) {
this.filterAdapter = filterAdapter;
this.username = username;
this.password = password;
this.securitySettingsService = securitySettings;
openSearch = JAXRSClientFactory.create(endpointUrl, OpenSearch.class);
openSearchClient = WebClient.client(openSearch);
RestUrl restUrl = newRestUrl(endpointUrl);
if (restUrl != null) {
restService = JAXRSClientFactory.create(restUrl.buildUrl(), RESTService.class);
restServiceClient = WebClient.client(restService);
if (StringUtils.startsWithIgnoreCase(endpointUrl, "https")) {
setTLSOptions(openSearchClient);
setTLSOptions(restServiceClient);
}
}
}
/**
* Generates a DDF REST URL from an OpenSearch URL
* @param query
* @param endpointUrl
* @return URL in String format
*/
private String createRestUrl(Query query, String endpointUrl, boolean retrieveResource) {
String url = null;
RestFilterDelegate delegate = null;
RestUrl restUrl = newRestUrl(endpointUrl);
restUrl.setRetrieveResource(retrieveResource);
if (restUrl != null) {
delegate = new RestFilterDelegate(restUrl);
}
if (delegate != null) {
try {
filterAdapter.adapt(query, delegate);
url = delegate.getRestUrl().buildUrl();
} catch (UnsupportedQueryException e) {
LOGGER.debug("Not a REST request.", e);
}
}
return url;
}
/**
* Creates a new RestUrl object based on an OpenSearch URL
* @param url
* @return RestUrl object for a DDF REST endpoint
*/
private RestUrl newRestUrl(String url) {
RestUrl restUrl = null;
try {
restUrl = RestUrl.newInstance(url);
restUrl.setRetrieveResource(true);
} catch (MalformedURLException e) {
LOGGER.info("Bad url given for remote source", e);
} catch (URISyntaxException e) {
LOGGER.info("Bad url given for remote source", e);
}
return restUrl;
}
/**
* Returns the OpenSearch {@link org.apache.cxf.jaxrs.client.WebClient}
* @return {@link org.apache.cxf.jaxrs.client.WebClient}
*/
public WebClient getOpenSearchWebClient() {
return WebClient.fromClient(openSearchClient);
}
/**
* Returns the DDF REST {@link org.apache.cxf.jaxrs.client.WebClient}
* @return {@link org.apache.cxf.jaxrs.client.WebClient}
*/
public WebClient getRestWebClient() {
if (restServiceClient != null) {
return WebClient.fromClient(restServiceClient);
}
return null;
}
/**
* Returns an arbitrary {@link org.apache.cxf.jaxrs.client.WebClient} for any {@link org.apache.cxf.jaxrs.client.Client}
* @param client {@link org.apache.cxf.jaxrs.client.Client}
* @return {@link org.apache.cxf.jaxrs.client.WebClient}
*/
public WebClient getWebClientFromClient(Client client) {
return WebClient.fromClient(client);
}
/**
* Creates a new OpenSearch {@link org.apache.cxf.jaxrs.client.Client} based on a String URL
* @param url
* @return {@link org.apache.cxf.jaxrs.client.Client}
*/
public Client newOpenSearchClient(String url) {
OpenSearch proxy = JAXRSClientFactory.create(url, OpenSearch.class);
Client tmp = WebClient.client(proxy);
if (StringUtils.startsWithIgnoreCase(url, "https")) {
setTLSOptions(tmp);
}
return tmp;
}
/**
* Creates a new DDF REST {@link org.apache.cxf.jaxrs.client.Client} based on an OpenSearch
* String URL.
* @param url - OpenSearch URL
* @param query - Query to be performed
* @param metacardId - MetacardId to search for
* @param retrieveResource - true if this is a resource request
* @return {@link org.apache.cxf.jaxrs.client.Client}
*/
public Client newRestClient(String url, Query query, String metacardId,
boolean retrieveResource) {
if (query != null) {
url = createRestUrl(query, url, retrieveResource);
} else {
RestUrl restUrl = newRestUrl(url);
if (restUrl != null) {
if (StringUtils.isNotEmpty(metacardId)) {
restUrl.setId(metacardId);
}
restUrl.setRetrieveResource(retrieveResource);
url = restUrl.buildUrl();
}
}
Client tmp = null;
if (url != null) {
RESTService proxy = JAXRSClientFactory.create(url, RESTService.class);
tmp = WebClient.client(proxy);
if (StringUtils.startsWithIgnoreCase(url, "https")) {
setTLSOptions(tmp);
}
}
return tmp;
}
/**
* Add TLS and Basic Auth credentials to the underlying {@link org.apache.cxf.transport.http.HTTPConduit}
* @param client
*/
private void setTLSOptions(Client client) {
ClientConfiguration clientConfiguration = WebClient.getConfig(client);
HTTPConduit httpConduit = clientConfiguration.getHttpConduit();
if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password)) {
if (httpConduit.getAuthorization() != null) {
httpConduit.getAuthorization().setUserName(username);
httpConduit.getAuthorization().setPassword(password);
}
}
TLSClientParameters tlsParams = securitySettingsService.getTLSParameters();
tlsParams.setDisableCNCheck(true);
httpConduit.setTlsClientParameters(tlsParams);
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}