Java tutorial
/* * Copyright (C) 2007 - 2011 GeoSolutions S.A.S. * http://www.geo-solutions.it * * GPLv3 + Classpath exception * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package it.geosolutions.httpproxy.service.impl; import it.geosolutions.httpproxy.service.ProxyConfig; import it.geosolutions.httpproxy.utils.Utils; import java.io.IOException; import java.lang.reflect.Field; import java.util.Enumeration; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.ServletContext; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.springframework.util.ReflectionUtils; import org.springframework.web.context.support.ServletContextResource; /** * ProxyConfig class to define the proxy configuration. * * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it * @author Alejandro Diaz */ public final class ProxyConfigImpl implements ProxyConfig { /* Writable properties to be parsed */ private String hostNameList; private String mimeTypeWhiteList; private String methodsWhiteList; private String hostsWhiteList; private String reqtypeWhitelistCapabilities; private String reqtypeWhitelistGeostore; private String reqtypeWhitelistCsw; private String reqtypeWhitelistFeatureinfo; private String reqtypeWhitelistGeneric; private String defaultStreamByteSizeTmp; private String timeoutTmp; private String connection_timeout; private String max_total_connections; private String default_max_connections_per_host; private final static Logger LOGGER = Logger.getLogger(ProxyConfigImpl.class.toString()); /** * A list of regular expressions describing hostnames the proxy is permitted to forward to */ private Set<String> hostnameWhitelist = new HashSet<String>(); /** * A list of regular expressions describing MIMETypes the proxy is permitted to forward */ private Set<String> mimetypeWhitelist = new HashSet<String>(); /** * A list of regular expressions describing Request Types the proxy is permitted to forward */ private Set<String> reqtypeWhitelist = new HashSet<String>(); /** * A list of regular expressions describing request METHODS the proxy is permitted to forward */ private Set<String> methodsWhitelist = new HashSet<String>(); /** * A list of regular expressions describing request HOSTS the proxy is permitted to forward */ private Set<String> hostsWhitelist = new HashSet<String>(); /** * The servlet context */ private ServletContext context; /** * The path of the properties file */ private String propertiesFilePath; /** * The request timeout */ private int soTimeout = 30000; /** * The connection timeout */ private int connectionTimeout = 30000; /** * The maximum total connections available */ private int maxTotalConnections = 60; /** * The maximum connections available per host */ private int defaultMaxConnectionsPerHost = 6; private int defaultStreamByteSize = 1024; /** * Locations proxy configuration list * @see http-proxy-default.xml */ private Resource[] locations; /** * Default this bean name 'proxyConfig'. */ private String beanName = "proxyConfig"; /** * */ private Map<String, Long> timeModificationByLocation = new ConcurrentHashMap<String, Long>(); /** * Default constructor */ public ProxyConfigImpl() { super(); configProxy(); } /** * Provide the proxy configuration * * @throws IOException */ public void configProxy() { try { // Load properties in getters getHostnameWhitelist(); getMimetypeWhitelist(); getMethodsWhitelist(); getHostnameWhitelist(); getReqtypeWhitelist(); // ///////////////////////////////////////////////// // Load byte size configuration // ///////////////////////////////////////////////// String bytesSize = defaultStreamByteSizeTmp; this.setDefaultStreamByteSize( bytesSize != null ? Integer.parseInt(bytesSize) : this.defaultStreamByteSize); // ///////////////////////////////////////////////// // Load connection manager configuration // ///////////////////////////////////////////////// String timeout = timeoutTmp; this.setSoTimeout(timeout != null ? Integer.parseInt(timeout) : this.soTimeout); String conn_timeout = connection_timeout; this.setConnectionTimeout( conn_timeout != null ? Integer.parseInt(conn_timeout) : this.connectionTimeout); String max_conn = max_total_connections; this.setMaxTotalConnections(max_conn != null ? Integer.parseInt(max_conn) : this.maxTotalConnections); String def_conn_host = default_max_connections_per_host; this.setMaxTotalConnections( def_conn_host != null ? Integer.parseInt(def_conn_host) : this.defaultMaxConnectionsPerHost); } catch (NumberFormatException e) { if (LOGGER.isLoggable(Level.SEVERE)) LOGGER.log(Level.SEVERE, "Error parsing the proxy properties file using default", e); this.setSoTimeout(this.soTimeout); this.setConnectionTimeout(this.connectionTimeout); this.setMaxTotalConnections(this.maxTotalConnections); this.setMaxTotalConnections(this.defaultMaxConnectionsPerHost); this.setDefaultStreamByteSize(this.defaultStreamByteSize); } } /** * Reload proxy configuration reading {@link ProxyConfigImpl#locations} */ public void reloadProxyConfig() { if (locations != null) { for (Resource location : locations) { try { if (location.exists()) { trackLocation(location); } else { // Try to load from file system: String path = null; if (location instanceof ClassPathResource) { // This instance is running without web context path = ((ClassPathResource) location).getPath(); } else if (location instanceof ServletContextResource) { // This instance is running in a web context path = ((ServletContextResource) location).getPath(); } if (path != null) { Resource alternative = new UrlResource("file:/" + path); if (alternative.exists()) { trackLocation(alternative); } } } } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error overriding the proxy configuration ", e); } } } else { LOGGER.log(Level.SEVERE, "Can't observe locations for proxy configuration"); } } /** * Save last modification of the file to track it and override this bean * properties if the file has been changed * * @param location * Resource location of the file * * @throws IOException */ private void trackLocation(Resource location) throws IOException { String fileName = location.getFilename(); Long lastModified = location.lastModified(); if (!(timeModificationByLocation.containsKey(fileName))) { // Save last modification timestamp timeModificationByLocation.put(fileName, lastModified); } else if (isModified(fileName, lastModified)) { // Override proxy configuration LOGGER.log(Level.INFO, "Proxy configuration has changed at runtime in file '" + fileName + "'"); overrideProperties(location); } } /** * Determines if the file has been modified since the last check. */ public boolean isModified(String fileName, long lastModified) { long interval = lastModified - timeModificationByLocation.get(fileName); timeModificationByLocation.put(fileName, lastModified); return Math.abs(interval) > 0; } /** * Override this fields with a location properties * * @param location * * @throws IOException if read properties throw an error */ private void overrideProperties(Resource location) throws IOException { Properties props = new Properties(); props.load(location.getInputStream()); Enumeration<Object> keys = props.keys(); while (keys.hasMoreElements()) { try { String key = (String) keys.nextElement(); if (key.startsWith(beanName + ".")) { String parameter = key.replace(beanName + ".", ""); Field field = ReflectionUtils.findField(this.getClass(), parameter); ReflectionUtils.makeAccessible(field); ReflectionUtils.setField(field, this, props.getProperty(key)); LOGGER.log(Level.INFO, "[override]: " + key + "=" + props.getProperty(key)); } } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error overriding the proxy configuration ", e); } } } /** * @return the soTimeout */ public int getSoTimeout() { return soTimeout; } /** * @param soTimeout the soTimeout to set */ public void setSoTimeout(int soTimeout) { this.soTimeout = soTimeout; } /** * @return the connectionTimeout */ public int getConnectionTimeout() { return connectionTimeout; } /** * @param connectionTimeout the connectionTimeout to set */ public void setConnectionTimeout(int connectionTimeout) { this.connectionTimeout = connectionTimeout; } /** * @return the maxTotalConnections */ public int getMaxTotalConnections() { return maxTotalConnections; } /** * @param maxTotalConnections the maxTotalConnections to set */ public void setMaxTotalConnections(int maxTotalConnections) { this.maxTotalConnections = maxTotalConnections; } /** * @return the defaultMaxConnectionsPerHost */ public int getDefaultMaxConnectionsPerHost() { return defaultMaxConnectionsPerHost; } /** * @param defaultMaxConnectionsPerHost the defaultMaxConnectionsPerHost to set */ public void setDefaultMaxConnectionsPerHost(int defaultMaxConnectionsPerHost) { this.defaultMaxConnectionsPerHost = defaultMaxConnectionsPerHost; } /** * @return the hostnameWhitelist */ public Set<String> getHostnameWhitelist() { // //////////////////////////////////////////////////////////// // Load proxy configuration white lists from properties file // //////////////////////////////////////////////////////////// Set<String> p = Utils.parseWhiteList(hostNameList); if (p != null) this.hostnameWhitelist = p; return hostnameWhitelist; } /** * @param hostnameWhitelist the hostnameWhitelist to set */ public void setHostnameWhitelist(Set<String> hostnameWhitelist) { this.hostnameWhitelist = hostnameWhitelist; } /** * @return the mimetypeWhitelist */ public Set<String> getMimetypeWhitelist() { Set<String> p = Utils.parseWhiteList(mimeTypeWhiteList); if (p != null) this.setHostnameWhitelist(p); return mimetypeWhitelist; } /** * @param mimetypeWhitelist the mimetypeWhitelist to set */ public void setMimetypeWhitelist(Set<String> mimetypeWhitelist) { this.mimetypeWhitelist = mimetypeWhitelist; } /** * @return the reqtypeWhitelist */ public Set<String> getReqtypeWhitelist() { // //////////////////////////////////////// // Read various request type properties // //////////////////////////////////////// Set<String> rt = new HashSet<String>(); String s = reqtypeWhitelistCapabilities; if (s != null) rt.add(s); s = reqtypeWhitelistGeostore; if (s != null) rt.add(s); s = reqtypeWhitelistCsw; if (s != null) rt.add(s); s = reqtypeWhitelistFeatureinfo; if (s != null) rt.add(s); s = reqtypeWhitelistGeneric; if (s != null) rt.add(s); this.reqtypeWhitelist = rt; return reqtypeWhitelist; } /** * @param reqtypeWhitelist the reqtypeWhitelist to set */ public void setReqtypeWhitelist(Set<String> reqtypeWhitelist) { this.reqtypeWhitelist = reqtypeWhitelist; } /** * @return the methodsWhitelist */ public Set<String> getMethodsWhitelist() { Set<String> p = Utils.parseWhiteList(methodsWhiteList); if (p != null) this.methodsWhitelist = p; return methodsWhitelist; } /** * @param methodsWhitelist the methodsWhitelist to set */ public void setMethodsWhitelist(Set<String> methodsWhitelist) { this.methodsWhitelist = methodsWhitelist; } /** * @return the hostsWhitelist */ public Set<String> getHostsWhitelist() { Set<String> p = Utils.parseWhiteList(hostsWhiteList); if (p != null) this.hostsWhitelist = p; return hostsWhitelist; } /** * @param hostsWhitelist the hostsWhitelist to set */ public void setHostsWhitelist(Set<String> hostsWhitelist) { this.hostsWhitelist = hostsWhitelist; } /** * @return the context */ public ServletContext getContext() { return context; } /** * @param context the context to set */ public void setContext(ServletContext context) { this.context = context; } /** * @return the propertiesFilePath */ public String getPropertiesFilePath() { return propertiesFilePath; } /** * @param propertiesFilePath the propertiesFilePath to set */ public void setPropertiesFilePath(String propertiesFilePath) { this.propertiesFilePath = propertiesFilePath; } /** * @return the defaultStreamByteSize */ public int getDefaultStreamByteSize() { return defaultStreamByteSize; } /** * @param defaultStreamByteSize the defaultStreamByteSize to set */ public void setDefaultStreamByteSize(int defaultStreamByteSize) { this.defaultStreamByteSize = defaultStreamByteSize; } /** * @return the hostNameList */ public String getHostNameList() { return hostNameList; } /** * @param hostNameList the hostNameList to set */ public void setHostNameList(String hostNameList) { this.hostNameList = hostNameList; } /** * @return the mimeTypeWhiteList */ public String getMimeTypeWhiteList() { return mimeTypeWhiteList; } /** * @param mimeTypeWhiteList the mimeTypeWhiteList to set */ public void setMimeTypeWhiteList(String mimeTypeWhiteList) { this.mimeTypeWhiteList = mimeTypeWhiteList; } /** * @return the methodsWhiteList */ public String getMethodsWhiteList() { return methodsWhiteList; } /** * @param methodsWhiteList the methodsWhiteList to set */ public void setMethodsWhiteList(String methodsWhiteList) { this.methodsWhiteList = methodsWhiteList; } /** * @return the hostsWhiteList */ public String getHostsWhiteList() { return hostsWhiteList; } /** * @param hostsWhiteList the hostsWhiteList to set */ public void setHostsWhiteList(String hostsWhiteList) { this.hostsWhiteList = hostsWhiteList; } /** * @return the reqtypeWhitelistCapabilities */ public String getReqtypeWhitelistCapabilities() { return reqtypeWhitelistCapabilities; } /** * @param reqtypeWhitelistCapabilities the reqtypeWhitelistCapabilities to set */ public void setReqtypeWhitelistCapabilities(String reqtypeWhitelistCapabilities) { this.reqtypeWhitelistCapabilities = reqtypeWhitelistCapabilities; } /** * @return the reqtypeWhitelistGeostore */ public String getReqtypeWhitelistGeostore() { return reqtypeWhitelistGeostore; } /** * @param reqtypeWhitelistGeostore the reqtypeWhitelistGeostore to set */ public void setReqtypeWhitelistGeostore(String reqtypeWhitelistGeostore) { this.reqtypeWhitelistGeostore = reqtypeWhitelistGeostore; } /** * @return the reqtypeWhitelistCsw */ public String getReqtypeWhitelistCsw() { return reqtypeWhitelistCsw; } /** * @param reqtypeWhitelistCsw the reqtypeWhitelistCsw to set */ public void setReqtypeWhitelistCsw(String reqtypeWhitelistCsw) { this.reqtypeWhitelistCsw = reqtypeWhitelistCsw; } /** * @return the reqtypeWhitelistFeatureinfo */ public String getReqtypeWhitelistFeatureinfo() { return reqtypeWhitelistFeatureinfo; } /** * @param reqtypeWhitelistFeatureinfo the reqtypeWhitelistFeatureinfo to set */ public void setReqtypeWhitelistFeatureinfo(String reqtypeWhitelistFeatureinfo) { this.reqtypeWhitelistFeatureinfo = reqtypeWhitelistFeatureinfo; } /** * @return the reqtypeWhitelistGeneric */ public String getReqtypeWhitelistGeneric() { return reqtypeWhitelistGeneric; } /** * @param reqtypeWhitelistGeneric the reqtypeWhitelistGeneric to set */ public void setReqtypeWhitelistGeneric(String reqtypeWhitelistGeneric) { this.reqtypeWhitelistGeneric = reqtypeWhitelistGeneric; } /** * @return the defaultStreamByteSizeTmp */ public String getDefaultStreamByteSizeTmp() { return defaultStreamByteSizeTmp; } /** * @param defaultStreamByteSizeTmp the defaultStreamByteSizeTmp to set */ public void setDefaultStreamByteSizeTmp(String defaultStreamByteSizeTmp) { this.defaultStreamByteSizeTmp = defaultStreamByteSizeTmp; } /** * @return the timeoutTmp */ public String getTimeoutTmp() { return timeoutTmp; } /** * @param timeoutTmp the timeoutTmp to set */ public void setTimeoutTmp(String timeoutTmp) { this.timeoutTmp = timeoutTmp; } /** * @return the connection_timeout */ public String getConnection_timeout() { return connection_timeout; } /** * @param connection_timeout the connection_timeout to set */ public void setConnection_timeout(String connection_timeout) { this.connection_timeout = connection_timeout; } /** * @return the max_total_connections */ public String getMax_total_connections() { return max_total_connections; } /** * @param max_total_connections the max_total_connections to set */ public void setMax_total_connections(String max_total_connections) { this.max_total_connections = max_total_connections; } /** * @return the default_max_connections_per_host */ public String getDefault_max_connections_per_host() { return default_max_connections_per_host; } /** * @param default_max_connections_per_host the default_max_connections_per_host to set */ public void setDefault_max_connections_per_host(String default_max_connections_per_host) { this.default_max_connections_per_host = default_max_connections_per_host; } public String getBeanName() { return beanName; } public void setBeanName(String beanName) { this.beanName = beanName; } /** * @return location array */ public Resource[] getLocations() { return locations; } /** * Set default locations for proxy config * @param locations array */ public void setLocations(Resource[] locations) { this.locations = locations; } }