Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ public class GeoWebCacheConfiguration {

private Boolean wmtsCiteCompliant;

private HttpConnectionSettings httpConnectionSettings;

/** The persisted list of layers */
private List<TileLayer> layers;

Expand Down Expand Up @@ -286,4 +288,14 @@ public boolean isWmtsCiteCompliant() {
public void setWmtsCiteCompliant(boolean wmtsCiteCompliant) {
this.wmtsCiteCompliant = wmtsCiteCompliant;
}

/** @return the HTTP connection settings */
public HttpConnectionSettings getHttpConnectionSettings() {
return httpConnectionSettings;
}

/** @param httpConnectionSettings the HTTP connection settings to set */
public void setHttpConnectionSettings(HttpConnectionSettings httpConnectionSettings) {
this.httpConnectionSettings = httpConnectionSettings;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/**
* This program 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 (at your option) 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 General Public License for more details.
*
* <p>You should have received a copy of the GNU Lesser General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*
* @author Lennart Juette, PTV AG (http://www.ptvag.com) 2010
*/
package org.geowebcache.config;

import java.util.Objects;

/**
* Configuration class for global HTTP connection settings used by all WMS layers. This replaces the per-layer
* concurrency parameter which was ineffective due to the static singleton connection manager.
*/
public class HttpConnectionSettings {

/** Default maximum total connections */
public static final int DEFAULT_MAX_CONNECTIONS_TOTAL = 20;

/** Default maximum connections per route */
public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 2;

/** Default connection timeout in seconds */
public static final int DEFAULT_CONNECTION_TIMEOUT = 30;

/** Default socket timeout in seconds */
public static final int DEFAULT_SOCKET_TIMEOUT = 60;

private Integer maxConnectionsTotal;
private Integer maxConnectionsPerRoute;
private Integer connectionTimeout;
private Integer socketTimeout;

public HttpConnectionSettings() {
// Default constructor for XStream
}

public HttpConnectionSettings(
Integer maxConnectionsTotal,
Integer maxConnectionsPerRoute,
Integer connectionTimeout,
Integer socketTimeout) {
this.maxConnectionsTotal = maxConnectionsTotal;
this.maxConnectionsPerRoute = maxConnectionsPerRoute;
this.connectionTimeout = connectionTimeout;
this.socketTimeout = socketTimeout;
}

/** @return the maximum total number of connections in the connection pool */
public int getMaxConnectionsTotal() {
return maxConnectionsTotal != null ? maxConnectionsTotal : DEFAULT_MAX_CONNECTIONS_TOTAL;
}

/** @param maxConnectionsTotal the maximum total number of connections to set */
public void setMaxConnectionsTotal(Integer maxConnectionsTotal) {
this.maxConnectionsTotal = maxConnectionsTotal;
}

/** @return the maximum number of connections per route (per backend server) */
public int getMaxConnectionsPerRoute() {
return maxConnectionsPerRoute != null ? maxConnectionsPerRoute : DEFAULT_MAX_CONNECTIONS_PER_ROUTE;
}

/** @param maxConnectionsPerRoute the maximum connections per route to set */
public void setMaxConnectionsPerRoute(Integer maxConnectionsPerRoute) {
this.maxConnectionsPerRoute = maxConnectionsPerRoute;
}

/** @return the connection timeout in seconds */
public int getConnectionTimeout() {
return connectionTimeout != null ? connectionTimeout : DEFAULT_CONNECTION_TIMEOUT;
}

/** @param connectionTimeout the connection timeout to set */
public void setConnectionTimeout(Integer connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}

/** @return the socket timeout in seconds */
public int getSocketTimeout() {
return socketTimeout != null ? socketTimeout : DEFAULT_SOCKET_TIMEOUT;
}

/** @param socketTimeout the socket timeout to set */
public void setSocketTimeout(Integer socketTimeout) {
this.socketTimeout = socketTimeout;
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
HttpConnectionSettings that = (HttpConnectionSettings) obj;
return Objects.equals(maxConnectionsTotal, that.maxConnectionsTotal)
&& Objects.equals(maxConnectionsPerRoute, that.maxConnectionsPerRoute)
&& Objects.equals(connectionTimeout, that.connectionTimeout)
&& Objects.equals(socketTimeout, that.socketTimeout);
}

@Override
public int hashCode() {
return Objects.hash(maxConnectionsTotal, maxConnectionsPerRoute, connectionTimeout, socketTimeout);
}

@Override
public String toString() {
return "HttpConnectionSettings{" + "maxConnectionsTotal="
+ getMaxConnectionsTotal() + ", maxConnectionsPerRoute="
+ getMaxConnectionsPerRoute() + ", connectionTimeout="
+ getConnectionTimeout() + ", socketTimeout="
+ getSocketTimeout() + '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
import org.geowebcache.storage.UnsuitableStorageException;
import org.geowebcache.util.ApplicationContextProvider;
import org.geowebcache.util.ExceptionUtils;
import org.geowebcache.util.HttpClientConnectionManagerFactory;
import org.geowebcache.util.URLs;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -799,6 +800,9 @@ public void afterPropertiesSet() throws GeoWebCacheException {

this.setGwcConfig(loadConfiguration());

// Initialize HTTP connection manager with configuration settings
initializeHttpConnectionManager();

log.config("Initializing GridSets from " + getIdentifier());

getGridSetsInternal();
Expand Down Expand Up @@ -853,6 +857,29 @@ private void initialize(final TileLayer layer) {
layer.initialize(gridSetBroker);
}

/**
* Initialize the HTTP connection manager with settings from the configuration. This replaces the static singleton
* approach with a configurable solution.
*/
private void initializeHttpConnectionManager() {
try {
HttpConnectionSettings settings = getGwcConfig().getHttpConnectionSettings();
if (settings == null) {
// Use default settings if none configured
settings = new HttpConnectionSettings();
log.info("No HTTP connection settings found in configuration, using defaults: " + settings);
} else {
log.info("Initializing HTTP connection manager with settings: " + settings);
}

HttpClientConnectionManagerFactory.getInstance().initialize(settings);
} catch (Exception e) {
log.warning("Failed to initialize HTTP connection manager with configuration settings: " + e.getMessage());
// Fall back to default settings
HttpClientConnectionManagerFactory.getInstance().initialize(new HttpConnectionSettings());
}
}

/** @see TileLayerConfiguration#getIdentifier() */
@Override
public String getIdentifier() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ public enum HttpRequestMode {
@SuppressWarnings("unused")
private String cachePrefix;

/**
* @deprecated This parameter is deprecated and ineffective due to the static singleton connection manager. Use
* global HTTP connection settings in geowebcache.xml instead.
*/
@Deprecated
private Integer concurrency;

// private transient int expireCacheInt = -1;
Expand Down Expand Up @@ -685,6 +690,9 @@ public void setSourceHelper(WMSSourceHelper source) {
log.fine("Setting sourceHelper on " + this.name);
this.sourceHelper = source;
if (concurrency != null) {
log.warning("Layer '" + this.name + "' uses deprecated 'concurrency' parameter. "
+ "This parameter is ineffective due to the static singleton connection manager. "
+ "Use global HTTP connection settings in geowebcache.xml instead.");
this.sourceHelper.setConcurrency(concurrency);
} else {
this.sourceHelper.setConcurrency(32);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.geotools.util.logging.Logging;

/** Builder class for HttpClients */
Expand All @@ -35,7 +33,8 @@ public class HttpClientBuilder {
private AuthScope authscope = null;

private Integer backendTimeoutMillis = null;
private static final HttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
private static final HttpClientConnectionManagerFactory connectionManagerFactory =
HttpClientConnectionManagerFactory.getInstance();

private boolean doAuthentication = false;

Expand Down Expand Up @@ -71,8 +70,9 @@ public HttpClientBuilder(

clientBuilder = org.apache.http.impl.client.HttpClientBuilder.create();
clientBuilder.useSystemProperties();
clientBuilder.setConnectionManager(connectionManager);
clientBuilder.setMaxConnTotal(concurrency);
clientBuilder.setConnectionManager(connectionManagerFactory.getConnectionManager());
// Note: concurrency parameter is now handled globally via HttpConnectionSettings
// The per-layer concurrency parameter is deprecated and ineffective
}

/*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/**
* This program 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 (at your option) 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 General Public License for more details.
*
* <p>You should have received a copy of the GNU Lesser General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*
* @author Lennart Juette, PTV AG (http://www.ptvag.com) 2010
*/
package org.geowebcache.util;

import java.util.logging.Logger;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.geotools.util.logging.Logging;
import org.geowebcache.config.HttpConnectionSettings;

/**
* Factory class for creating and managing HTTP connection managers. This replaces the static singleton approach with a
* configurable solution that properly respects the connection settings.
*/
public class HttpClientConnectionManagerFactory {

static final Logger log = Logging.getLogger(HttpClientConnectionManagerFactory.class.toString());

private static volatile HttpClientConnectionManagerFactory instance;
private volatile HttpClientConnectionManager connectionManager;
private volatile HttpConnectionSettings settings;

private HttpClientConnectionManagerFactory() {
// Private constructor for singleton
}

/** Get the singleton instance of the factory */
public static HttpClientConnectionManagerFactory getInstance() {
if (instance == null) {
synchronized (HttpClientConnectionManagerFactory.class) {
if (instance == null) {
instance = new HttpClientConnectionManagerFactory();
}
}
}
return instance;
}

/**
* Initialize the connection manager with the given settings. This method should be called once during application
* startup.
*
* @param settings the HTTP connection settings to use
*/
public synchronized void initialize(HttpConnectionSettings settings) {
if (this.settings != null && this.settings.equals(settings)) {
// Settings haven't changed, no need to recreate
return;
}

this.settings = settings != null ? settings : new HttpConnectionSettings();

// Close existing connection manager if it exists
if (connectionManager != null) {
try {
connectionManager.shutdown();
} catch (Exception e) {
log.warning("Error closing existing connection manager: " + e.getMessage());
}
}

// Create new connection manager with proper settings
PoolingHttpClientConnectionManager newManager = new PoolingHttpClientConnectionManager();
newManager.setMaxTotal(this.settings.getMaxConnectionsTotal());
newManager.setDefaultMaxPerRoute(this.settings.getMaxConnectionsPerRoute());

this.connectionManager = newManager;

log.info("Initialized HTTP connection manager with settings: " + this.settings);
}

/**
* Get the current connection manager. If not initialized, creates one with default settings.
*
* @return the HTTP connection manager
*/
public HttpClientConnectionManager getConnectionManager() {
if (connectionManager == null) {
synchronized (this) {
if (connectionManager == null) {
// Initialize with default settings if not already done
initialize(new HttpConnectionSettings());
}
}
}
return connectionManager;
}

/**
* Get the current connection settings
*
* @return the current HTTP connection settings
*/
public HttpConnectionSettings getSettings() {
return settings != null ? settings : new HttpConnectionSettings();
}

/** Shutdown the connection manager and release resources. This should be called during application shutdown. */
public synchronized void shutdown() {
if (connectionManager != null) {
try {
connectionManager.shutdown();
connectionManager = null;
settings = null;
log.info("HTTP connection manager shutdown completed");
} catch (Exception e) {
log.warning("Error during connection manager shutdown: " + e.getMessage());
}
}
}
}
7 changes: 7 additions & 0 deletions geowebcache/core/src/main/resources/geowebcache.xml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@

</blobStores>

<httpConnectionSettings>
<maxConnectionsTotal>20</maxConnectionsTotal>
<maxConnectionsPerRoute>6</maxConnectionsPerRoute>
<connectionTimeout>30</connectionTimeout>
<socketTimeout>60</socketTimeout>
</httpConnectionSettings>

<gridSets>
<!-- Grid Set Example, by default EPSG:900913 and EPSG:4326 are defined -->
<gridSet>
Expand Down
Loading
Loading