/**
* 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 org.codice.ddf.ui.searchui.standard.properties;
import static org.boon.Boon.toJson;
import static us.bpsm.edn.parser.Parsers.defaultConfiguration;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.activation.MimeType;
import javax.activation.MimeTypeParseException;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.collections.Factory;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.webconsole.BrandingPlugin;
import org.codice.proxy.http.HttpProxyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ddf.catalog.data.BinaryContent;
import ddf.catalog.data.BinaryContentImpl;
import us.bpsm.edn.EdnIOException;
import us.bpsm.edn.EdnSyntaxException;
import us.bpsm.edn.parser.Parser;
import us.bpsm.edn.parser.Parsers;
/**
* Stores external configuration properties.
*
* @author ddf.isgs@lmco.com
*/
@Path("/")
public class ConfigurationStore {
public static final String SERVLET_PATH = "/proxy";
public static final String URL = "url";
public static final String ENDPOINT_NAME = "standard";
public static final Factory NEW_SET_FACTORY = new Factory() {
public Object create() {
return new TreeSet();
}
};
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationStore.class);
private static MimeType jsonMimeType;
static {
MimeType mime = null;
try {
String jsonMimeType_STRING = "application/json";
mime = new MimeType(jsonMimeType_STRING);
} catch (MimeTypeParseException e) {
LOGGER.warn("Failed to create json mimetype.");
}
jsonMimeType = mime;
}
private String format;
private List<String> imageryProviders = new ArrayList<>();
private List<Map<String, Object>> proxiedImageryProviders = new ArrayList<>();
private String terrainProvider;
private Map<String, Object> proxiedTerrainProvider;
private List<String> imageryEndpoints = new ArrayList<>();
private String terrainEndpoint;
private Boolean isSignIn = true;
private Boolean isTask = false;
private Boolean isGazetteer = true;
private Boolean isIngest = true;
private BrandingPlugin branding;
private Integer timeout = 15000;
private HttpProxyService httpProxy;
private int incrementer = 0;
private Integer resultCount = 250;
private String projection = "EPSG:3857";
private String bingKey = "";
private String helpUrl = "help.html";
private Map<String, Set<String>> typeNameMapping = new HashMap<String, Set<String>>();
public ConfigurationStore() {
}
public void destroy() {
if (imageryEndpoints.size() > 0) {
for (String endpoint : imageryEndpoints) {
try {
httpProxy.stop(endpoint);
} catch (Exception e) {
LOGGER.error("Unable to stop proxy endpoint.", e);
}
}
}
if (terrainEndpoint != null) {
try {
httpProxy.stop(terrainEndpoint);
} catch (Exception e) {
LOGGER.error("Unable to stop proxy endpoint.", e);
}
}
}
@GET
@Path("/config")
public Response getDocument(@Context UriInfo uriInfo, @Context HttpServletRequest httpRequest) {
Response response;
Map<String, Object> config = new HashMap<>();
config.put("branding", getProductName());
config.put("version", getProductVersion());
config.put("showWelcome", isSignIn);
config.put("showTask", isTask);
config.put("format", format);
config.put("timeout", timeout);
config.put("resultCount", resultCount);
config.put("typeNameMapping", typeNameMapping);
config.put("terrainProvider", proxiedTerrainProvider);
config.put("imageryProviders", proxiedImageryProviders);
config.put("gazetteer", isGazetteer);
config.put("showIngest", isIngest);
config.put("projection", projection);
config.put("helpUrl", helpUrl);
config.put("bingKey", bingKey);
String configJson = toJson(config);
BinaryContent content = new BinaryContentImpl(
new ByteArrayInputStream(configJson.getBytes()), jsonMimeType);
response = Response.ok(content.getInputStream(), content.getMimeTypeValue()).build();
return response;
}
public String getProductName() {
if (branding != null) {
// Remove the version number
return StringUtils.substringBeforeLast(branding.getProductName(), " ");
} else {
return "";
}
}
public String getProductVersion() {
if (branding != null) {
// Remove the version number
return StringUtils.substringAfterLast(branding.getProductName(), " ");
} else {
return "";
}
}
public BrandingPlugin getBranding() {
return branding;
}
public void setBranding(BrandingPlugin branding) {
this.branding = branding;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
public Integer getTimeout() {
return timeout;
}
public void setTimeout(Integer timeout) {
this.timeout = timeout;
}
public List<Map<String, Object>> getProxiedImageryProviders() {
return proxiedImageryProviders;
}
public List<String> getImageryProviders() {
return imageryProviders;
}
public void setImageryProviders(String imageryProviders) {
setImageryProviders(Arrays.asList(imageryProviders.split(",")));
}
public void setImageryProviders(List<String> imageryProviders) {
List<String> itemList = new ArrayList<String>();
for (String item : imageryProviders) {
if (item.contains(",")) {
String[] items = item.split(",");
itemList.addAll(Arrays.asList(items));
} else {
itemList.add(item);
}
}
this.imageryProviders = itemList;
setProxiesForImagery(itemList);
}
public Map<String, Object> getProxiedTerrainProvider() {
return proxiedTerrainProvider;
}
public String getTerrainProvider() {
return terrainProvider;
}
public void setTerrainProvider(String terrainProvider) {
this.terrainProvider = terrainProvider;
setProxyForTerrain(terrainProvider);
}
private void setProxiesForImagery(List<String> imageryProviders) {
if (imageryEndpoints.size() > 0) {
for (String endpoint : imageryEndpoints) {
try {
httpProxy.stop(endpoint);
} catch (Exception e) {
LOGGER.error("Unable to stop proxy endpoint.", e);
}
}
}
proxiedImageryProviders.clear();
for (String provider : imageryProviders) {
Map<String, Object> proxiedProvider = getProxiedProvider(provider, true);
if (proxiedProvider != null) {
proxiedImageryProviders.add(proxiedProvider);
}
}
}
private void setProxyForTerrain(String terrainProvider) {
if (terrainEndpoint != null) {
try {
httpProxy.stop(terrainEndpoint);
} catch (Exception e) {
LOGGER.error("Unable to stop proxy endpoint.", e);
}
}
proxiedTerrainProvider = getProxiedProvider(terrainProvider, false);
}
private Map<String, Object> getProxiedProvider(String provider, boolean imagery) {
if (StringUtils.isBlank(provider)) {
return null;
}
Parser parser = Parsers.newParser(defaultConfiguration());
Map<String, Object> config;
try {
Object value = parser.nextValue(Parsers.newParseable(provider));
if (value instanceof Map) {
config = new HashMap<String, Object>((Map) value);
} else {
LOGGER.warn("Expected a map for provider configuration but got {} instead: {}",
value.getClass().getName(), provider);
return null;
}
} catch (EdnSyntaxException | EdnIOException e) {
LOGGER.warn("Unable to parse provider configuration: " + provider, e);
return null;
}
if (config.containsKey(URL)) {
String url = config.get(URL).toString();
try {
String endpointName = ENDPOINT_NAME + incrementer;
incrementer++;
endpointName = httpProxy.start(endpointName, url, timeout);
if (imagery) {
imageryEndpoints.add(endpointName);
} else {
terrainEndpoint = endpointName;
}
config.put(URL, SERVLET_PATH + "/" + endpointName);
} catch (Exception e) {
LOGGER.error("Unable to configure proxy for: {}", url, e);
}
}
return config;
}
public HttpProxyService getHttpProxy() {
return httpProxy;
}
public void setHttpProxy(HttpProxyService httpProxy) {
this.httpProxy = httpProxy;
}
public Integer getResultCount() {
return resultCount;
}
public void setResultCount(Integer resultCount) {
this.resultCount = resultCount;
}
public Boolean getSignIn() {
return isSignIn;
}
public void setSignIn(Boolean isSignIn) {
this.isSignIn = isSignIn;
}
public Boolean getTask() {
return isTask;
}
public void setTask(Boolean isTask) {
this.isTask = isTask;
}
public Boolean getGazetteer() {
return isGazetteer;
}
public void setGazetteer(Boolean isGazetteer) {
this.isGazetteer = isGazetteer;
}
public Boolean getIngest() {
return this.isIngest;
}
public void setIngest(Boolean isIngest) {
this.isIngest = isIngest;
}
public void setTypeNameMapping(String[] mappings) {
if (mappings != null) {
typeNameMapping = MapUtils.lazyMap(new TreeMap(), NEW_SET_FACTORY);
for (String mappingValue : mappings) {
// workaround for KARAF-1701
for (String mapping : StringUtils.split(mappingValue, ",")) {
String[] nameAndType = StringUtils.split(mapping, "=");
if (nameAndType.length == 2) {
String displayName = StringUtils.strip(nameAndType[0]);
String type = StringUtils.strip(nameAndType[1]);
if (StringUtils.isNotBlank(displayName) && StringUtils.isNotBlank(type)) {
typeNameMapping.get(displayName).add(type);
}
} else {
LOGGER.info("Invalid type display name mapping format {}", mapping);
}
}
}
}
}
public void setTypeNameMapping(List<String> mappings) {
if (mappings != null) {
this.setTypeNameMapping(mappings.toArray(new String[mappings.size()]));
}
}
public Map<String, Set<String>> getTypeNameMapping() {
return typeNameMapping;
}
public void setTypeNameMapping(String string) {
if (string != null) {
this.setTypeNameMapping(new String[] {string});
}
}
public String getProjection() {
return projection;
}
public void setProjection(String projection) {
this.projection = projection;
}
public String getBingKey() {
return bingKey;
}
public void setBingKey(String bingKey) {
this.bingKey = bingKey;
}
public String getHelpUrl() {
return helpUrl;
}
public void setHelpUrl(String helpUrl) {
this.helpUrl = helpUrl;
}
}