Index: httpclient-osgi/src/main/java/org/apache/http/osgi/Activator.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient-osgi/src/main/java/org/apache/http/osgi/Activator.java (revision )
+++ httpclient-osgi/src/main/java/org/apache/http/osgi/Activator.java (revision )
@@ -0,0 +1,67 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.osgi;
+
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.impl.conn.ClientConnectionManagerTracker;
+import org.apache.http.osgi.proxy.ConfigurableProxySelector;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * This is the bundle activator. It registers the activator as a service, so it can receive configuration properties.
+ * Once a configuration is updated, it registers a proxy selector based on the configuration properties.
+ *
+ * The activator also is responsible for unregistering the service upon bundle shutdown. Additionally the shutdown
+ * ensures that all open connections of all http-clients are terminated, so the bundle properly stops. Finally, upon
+ * shutdown, the default proxy selector is reverted to java's default.
+ */
+public class Activator implements BundleActivator {
+
+ private ServiceRegistration configurator;
+
+ public void start(BundleContext context) throws Exception {
+ configurator = context
+ .registerService(ConfigurableProxySelector.class.getName(), new ConfigurableProxySelector(), null);
+ }
+
+ public void stop(BundleContext context) throws Exception {
+
+ // stop receiving configuration
+ if (configurator != null) {
+ configurator.unregister();
+ }
+
+ // ensure all clients are terminated
+ for (final ClientConnectionManager manager : ClientConnectionManagerTracker.getInstance().getAll()) {
+ if (null != manager) {
+ manager.shutdown();
+ }
+ }
+ }
+}
Index: httpclient/src/main/java/org/apache/http/impl/conn/BasicClientConnectionManager.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/impl/conn/BasicClientConnectionManager.java (revision 1395548)
+++ httpclient/src/main/java/org/apache/http/impl/conn/BasicClientConnectionManager.java (revision )
@@ -101,6 +101,9 @@
}
this.schemeRegistry = schreg;
this.connOperator = createConnectionOperator(schreg);
+
+ // have this connection manager centrally tracked via weak reference
+ ClientConnectionManagerTracker.getInstance().add(this);
}
public BasicClientConnectionManager() {
Index: httpclient-osgi/src/main/java/org/apache/http/osgi/proxy/ConfigurableProxySelector.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient-osgi/src/main/java/org/apache/http/osgi/proxy/ConfigurableProxySelector.java (revision )
+++ httpclient-osgi/src/main/java/org/apache/http/osgi/proxy/ConfigurableProxySelector.java (revision )
@@ -0,0 +1,216 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.osgi.proxy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+import java.io.IOException;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.osgi.framework.Constants.SERVICE_PID;
+
+@Component(metatype = false)
+public class ConfigurableProxySelector extends ProxySelector {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ private static int MAX_FAILURES = 3;
+
+ /**
+ * This service tracks proxy configurations.
+ */
+ private ServiceTracker serviceTracker;
+
+ /**
+ * The bundle context is used to access tracked service references.
+ */
+ private BundleContext bundleContext;
+
+ /**
+ * The default proxy selector present before this service was started and registered itself as the new default
+ * selector. The previous selector serves as a fallback and will be put back into place upon shutdown of this
+ * service.
+ */
+ private ProxySelector previousSelector;
+
+ /**
+ * The map holding valid and enabled proxy configurations
+ */
+ private final Map proxyConfigurations = new HashMap();
+
+ // ------- API
+
+ @Override
+ public List select(final URI uri) {
+
+ if (null == uri) {
+ throw new IllegalArgumentException("URI must not be null");
+ }
+
+ final List proxies = new ArrayList();
+
+ for (final ProxyConfiguration config : proxyConfigurations.values()) {
+ if (config.accepts(uri)) {
+ proxies.add(config.getProxy());
+ }
+ }
+
+ if (proxies.size() == 0 && null != previousSelector) {
+ return previousSelector.select(uri);
+ } else if (proxies.size() == 0) {
+ proxies.add(Proxy.NO_PROXY);
+ }
+
+ return proxies;
+ }
+
+ @Override
+ public void connectFailed(final URI uri, final SocketAddress address, final IOException ioe) {
+
+ if (null == uri || null == address || null == ioe) {
+ throw new IllegalArgumentException("arguments may not be null.");
+ }
+
+ String toBeRemoved = null;
+
+ for (final Map.Entry entry : proxyConfigurations.entrySet()) {
+ final ProxyConfiguration config = entry.getValue();
+ if (address.equals(config.getAddress())) {
+ final int failures = config.failed();
+ log.error("Connection to proxy [" + config + "] failed (" + failures + " time(s)).");
+ if (failures >= MAX_FAILURES) {
+ toBeRemoved = entry.getKey();
+ log.error("Proxy [" + config + "] failed more than " + MAX_FAILURES + " times, removed.");
+ }
+ break;
+ }
+ }
+
+ if (null != toBeRemoved) {
+ synchronized (proxyConfigurations) {
+ proxyConfigurations.remove(toBeRemoved);
+ }
+ }
+ }
+
+ // ------- OSGI HANDLING
+
+ @Activate
+ @SuppressWarnings("unused")
+ protected void activate(final ComponentContext context) {
+
+ previousSelector = ProxySelector.getDefault();
+ ProxySelector.setDefault(this);
+
+ bundleContext = context.getBundleContext();
+ serviceTracker = new ServiceTracker(bundleContext,
+ ProxyConfiguration.class.getName(),
+ new ProxyTracker());
+ serviceTracker.open();
+ }
+
+ @Deactivate
+ @SuppressWarnings("unused")
+ protected void deactivate() {
+
+ ProxySelector.setDefault(previousSelector);
+
+ if (serviceTracker != null) {
+ serviceTracker.close();
+ serviceTracker = null;
+ }
+
+ proxyConfigurations.clear();
+
+ bundleContext = null;
+ }
+
+ // ------- PRIVATE
+
+ private class ProxyTracker implements ServiceTrackerCustomizer {
+
+ public Object addingService(final ServiceReference reference) {
+
+ final Object service = bundleContext.getService(reference);
+ if (serviceIsValid(service)) {
+ addProxy(reference, service);
+ return service;
+ }
+
+ return null;
+ }
+
+ public void modifiedService(final ServiceReference reference, final Object service) {
+ removeProxy(reference, service);
+ addingService(reference);
+ }
+
+ public void removedService(final ServiceReference reference, final Object service) {
+ removeProxy(reference, service);
+ }
+
+ private boolean serviceIsValid(final Object service) {
+ return service instanceof ProxyConfiguration && ((ProxyConfiguration) service).isValid();
+ }
+
+ private void addProxy(final ServiceReference reference, final Object service) {
+ final ProxyConfiguration config = (ProxyConfiguration) service;
+ synchronized (proxyConfigurations) {
+ proxyConfigurations.put((String) reference.getProperty(SERVICE_PID), config);
+ }
+ if (log.isInfoEnabled()) {
+ log.info("Added new proxy [" + config + "]");
+ }
+ }
+
+ private void removeProxy(final ServiceReference reference, final Object service) {
+ if (log.isInfoEnabled()) {
+ final ProxyConfiguration config = (ProxyConfiguration) service;
+ log.info("Removed proxy [" + config + "]");
+ }
+ synchronized (proxyConfigurations) {
+ proxyConfigurations.remove((String) reference.getProperty(SERVICE_PID));
+ }
+ }
+ }
+}
Index: httpclient/src/main/java/org/apache/http/conn/routing/HttpRoute.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/conn/routing/HttpRoute.java (revision 1395548)
+++ httpclient/src/main/java/org/apache/http/conn/routing/HttpRoute.java (revision )
@@ -27,7 +27,15 @@
package org.apache.http.conn.routing;
+import java.lang.reflect.UndeclaredThrowableException;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
import org.apache.http.annotation.Immutable;
import org.apache.http.util.LangUtils;
@@ -100,6 +108,32 @@
throw new IllegalArgumentException
("Proxies may not be null.");
}
+
+ // select a proxy from the default proxy selector. in an OSGi-environment,
+ // the proxy selector is set to org.apache.http.osgi.proxy.ConfigurableProxySelector
+ // and thus provides centrally configured proxies without the knowledge of the API user
+ if (proxies.length == 0) {
+ try {
+ // get list of proxies from the default proxy selector
+ final List defaultProxyList = ProxySelector.getDefault().select(new URI(target.toURI()));
+ final ArrayList defaultProxyHosts = new ArrayList();
+ for (final Proxy proxy : defaultProxyList) {
+ // downcast to InetSocketAddress for host and port accessors
+ final InetSocketAddress address = (InetSocketAddress) proxy.address();
+
+ // only HTTP proxies are supported, the address of which is not null
+ if (Proxy.Type.HTTP == proxy.type() && null != address) {
+ defaultProxyHosts.add(new HttpHost(address.getHostName(), address.getPort()));
+ }
+ }
+
+ proxies = defaultProxyHosts.toArray(new HttpHost[defaultProxyHosts.size()]);
+
+ } catch (URISyntaxException e) {
+ throw new UndeclaredThrowableException(e);
+ }
+ }
+
if ((tunnelled == TunnelType.TUNNELLED) && (proxies.length == 0)) {
throw new IllegalArgumentException
("Proxy required if tunnelled.");
Index: httpclient-osgi/src/main/java/org/apache/http/osgi/util/PropertiesUtil.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient-osgi/src/main/java/org/apache/http/osgi/util/PropertiesUtil.java (revision )
+++ httpclient-osgi/src/main/java/org/apache/http/osgi/util/PropertiesUtil.java (revision )
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.http.osgi.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * The PropertiesUtil is a utility class providing some
+ * usefull utility methods for converting property types.
+ *
+ * @since 2.1
+ */
+public class PropertiesUtil {
+
+ /**
+ * Returns the boolean value of the parameter or the
+ * defaultValue if the parameter is null.
+ * If the parameter is not a Boolean it is converted
+ * by calling Boolean.valueOf on the string value of the
+ * object.
+ * @param propValue the property value or null
+ * @param defaultValue the default boolean value
+ */
+ public static boolean toBoolean(Object propValue, boolean defaultValue) {
+ propValue = toObject(propValue);
+ if (propValue instanceof Boolean) {
+ return (Boolean) propValue;
+ } else if (propValue != null) {
+ return Boolean.valueOf(String.valueOf(propValue));
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns the parameter as a string or the
+ * defaultValue if the parameter is null.
+ * @param propValue the property value or null
+ * @param defaultValue the default string value
+ */
+ public static String toString(Object propValue, String defaultValue) {
+ propValue = toObject(propValue);
+ return (propValue != null) ? propValue.toString() : defaultValue;
+ }
+
+ /**
+ * Returns the parameter as a long or the
+ * defaultValue if the parameter is null or if
+ * the parameter is not a Long and cannot be converted to
+ * a Long from the parameter's string value.
+ * @param propValue the property value or null
+ * @param defaultValue the default long value
+ */
+ public static long toLong(Object propValue, long defaultValue) {
+ propValue = toObject(propValue);
+ if (propValue instanceof Long) {
+ return (Long) propValue;
+ } else if (propValue != null) {
+ try {
+ return Long.valueOf(String.valueOf(propValue));
+ } catch (NumberFormatException nfe) {
+ // don't care, fall through to default value
+ }
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns the parameter as an integer or the
+ * defaultValue if the parameter is null or if
+ * the parameter is not an Integer and cannot be converted to
+ * an Integer from the parameter's string value.
+ * @param propValue the property value or null
+ * @param defaultValue the default integer value
+ */
+ public static int toInteger(Object propValue, int defaultValue) {
+ propValue = toObject(propValue);
+ if (propValue instanceof Integer) {
+ return (Integer) propValue;
+ } else if (propValue != null) {
+ try {
+ return Integer.valueOf(String.valueOf(propValue));
+ } catch (NumberFormatException nfe) {
+ // don't care, fall through to default value
+ }
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns the parameter as a double or the
+ * defaultValue if the parameter is null or if
+ * the parameter is not a Double and cannot be converted to
+ * a Double from the parameter's string value.
+ * @param propValue the property value or null
+ * @param defaultValue the default double value
+ */
+ public static double toDouble(Object propValue, double defaultValue) {
+ propValue = toObject(propValue);
+ if (propValue instanceof Double) {
+ return (Double) propValue;
+ } else if (propValue != null) {
+ try {
+ return Double.valueOf(String.valueOf(propValue));
+ } catch (NumberFormatException nfe) {
+ // don't care, fall through to default value
+ }
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns the parameter as a single value. If the
+ * parameter is neither an array nor a java.util.Collection the
+ * parameter is returned unmodified. If the parameter is a non-empty array,
+ * the first array element is returned. If the property is a non-empty
+ * java.util.Collection, the first collection element is returned.
+ * Otherwise null is returned.
+ * @param propValue the parameter to convert.
+ */
+ public static Object toObject(Object propValue) {
+ if (propValue == null) {
+ return null;
+ } else if (propValue.getClass().isArray()) {
+ Object[] prop = (Object[]) propValue;
+ return prop.length > 0 ? prop[0] : null;
+ } else if (propValue instanceof Collection>) {
+ Collection> prop = (Collection>) propValue;
+ return prop.isEmpty() ? null : prop.iterator().next();
+ } else {
+ return propValue;
+ }
+ }
+
+ /**
+ * Returns the parameter as an array of Strings. If
+ * the parameter is a scalar value its string value is returned as a single
+ * element array. If the parameter is an array, the elements are converted to
+ * String objects and returned as an array. If the parameter is a collection, the
+ * collection elements are converted to String objects and returned as an array.
+ * Otherwise (if the parameter is null) null is
+ * returned.
+ * @param propValue The object to convert.
+ */
+ public static String[] toStringArray(Object propValue) {
+ return toStringArray(propValue, null);
+ }
+
+ /**
+ * Returns the parameter as an array of Strings. If
+ * the parameter is a scalar value its string value is returned as a single
+ * element array. If the parameter is an array, the elements are converted to
+ * String objects and returned as an array. If the parameter is a collection, the
+ * collection elements are converted to String objects and returned as an array.
+ * Otherwise (if the property is null) a provided default value is
+ * returned.
+ * @param propValue The object to convert.
+ * @param defaultArray The default array to return.
+ */
+ public static String[] toStringArray(Object propValue, String[] defaultArray) {
+ if (propValue == null) {
+ // no value at all
+ return defaultArray;
+
+ } else if (propValue instanceof String) {
+ // single string
+ return new String[] { (String) propValue };
+
+ } else if (propValue instanceof String[]) {
+ // String[]
+ return (String[]) propValue;
+
+ } else if (propValue.getClass().isArray()) {
+ // other array
+ Object[] valueArray = (Object[]) propValue;
+ List values = new ArrayList(valueArray.length);
+ for (Object value : valueArray) {
+ if (value != null) {
+ values.add(value.toString());
+ }
+ }
+ return values.toArray(new String[values.size()]);
+
+ } else if (propValue instanceof Collection>) {
+ // collection
+ Collection> valueCollection = (Collection>) propValue;
+ List valueList = new ArrayList(valueCollection.size());
+ for (Object value : valueCollection) {
+ if (value != null) {
+ valueList.add(value.toString());
+ }
+ }
+ return valueList.toArray(new String[valueList.size()]);
+ }
+
+ return defaultArray;
+ }
+}
\ No newline at end of file
Index: httpclient-osgi/pom.xml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient-osgi/pom.xml (revision 1395548)
+++ httpclient-osgi/pom.xml (revision )
@@ -54,7 +54,13 @@
${commons-codec.version}compile
-
+
+ commons-logging
+ commons-logging
+ ${commons-logging.version}
+ provided
+
+ org.apache.httpcomponentshttpmime${project.version}
@@ -72,6 +78,30 @@
${project.version}compile
+
+ org.osgi
+ org.osgi.core
+ 4.2.0
+ provided
+
+
+ org.osgi
+ org.osgi.compendium
+ 4.2.0
+ provided
+
+
+ org.apache.felix
+ org.apache.felix.scr.annotations
+ 1.7.0
+ provided
+
+
+ junit
+ junit
+ 4.8.2
+ test
+
@@ -79,6 +109,8 @@
UTF-81.51.5
+ true
+ true
@@ -92,12 +124,42 @@
-
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ ${maven.compile.source}
+ ${maven.compile.target}
+ ${maven.compile.optimize}
+ ${maven.compile.deprecation}
+
+
+
- org.apache.felix
+ org.apache.felix
+ maven-scr-plugin
+ 1.8.0
+
+
+ generate-scr-scrdescriptor
+
+ scr
+
+
+
+
+ Apache Software Foundation
+
+
+
+
+
+
+ org.apache.felixmaven-bundle-plugintrue
+ org.apache.http.osgi.ActivatorApache ${project.name}${project.groupId}.httpclient
<_exportcontents>
@@ -113,26 +175,33 @@
*;scope=compile|runtime;inline=true
- javax.crypto,
- javax.crypto.spec,
- javax.net.ssl,javax.security.auth.x500,
- org.ietf.jgss,
+ javax.crypto,
+ javax.crypto.spec,
+ javax.net.ssl,javax.security.auth.x500,
+ org.ietf.jgss,
+ org.osgi.framework,
+ org.osgi.service.cm,
+ org.osgi.service.component,
+ org.osgi.util.tracker,
- org.apache.commons.logging;version=${commons-logging.version},
- org.apache.http;version=${httpcore.version},
- org.apache.http.concurrent;version=${httpcore.version},
- org.apache.http.entity;version=${httpcore.version},
- org.apache.http.io;version=${httpcore.version},
- org.apache.http.message;version=${httpcore.version},
- org.apache.http.params;version=${httpcore.version},
- org.apache.http.pool;version=${httpcore.version},
- org.apache.http.protocol;version=${httpcore.version},
- org.apache.http.util;version=${httpcore.version},
- org.apache.http.impl;version=${httpcore.version},
- org.apache.http.impl.entity;version=${httpcore.version},
- org.apache.http.impl.io;version=${httpcore.version},
- org.apache.http.impl.pool;version=${httpcore.version},
+ org.apache.commons.logging;version=${commons-logging.version},
+ org.apache.http;version=${httpcore.version},
+ org.apache.http.concurrent;version=${httpcore.version},
+ org.apache.http.entity;version=${httpcore.version},
+ org.apache.http.io;version=${httpcore.version},
+ org.apache.http.message;version=${httpcore.version},
+ org.apache.http.params;version=${httpcore.version},
+ org.apache.http.pool;version=${httpcore.version},
+ org.apache.http.protocol;version=${httpcore.version},
+ org.apache.http.util;version=${httpcore.version},
+ org.apache.http.impl;version=${httpcore.version},
+ org.apache.http.impl.entity;version=${httpcore.version},
+ org.apache.http.impl.io;version=${httpcore.version},
+ org.apache.http.impl.pool;version=${httpcore.version},
+ javax.servlet;resolution:=optional,
- net.sf.ehcache.*;resolution:=optional,
- net.spy.memcached.*;resolution:=optional
+ net.sf.ehcache.*;resolution:=optional,
+ net.spy.memcached.*;resolution:=optional
+ org.apache.avalon.framework.logger;resolution:=optional,
+ org.apache.log;resolution:=optional
<_removeheaders>JAVA_1_3_HOME,JAVA_1_4_HOME
Index: httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.properties
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>MacRoman
===================================================================
--- httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.properties (revision )
+++ httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.properties (revision )
@@ -0,0 +1,63 @@
+org.apache.http.osgi.proxy.ConfigurableProxySelector.name = Apache HTTP Components Proxy Selector
+org.apache.http.osgi.proxy.ConfigurableProxySelector.description = Transparently provides central proxy configurations \
+ for the HTTP Clients.
+
+org.apache.http.osgi.proxy.ProxyConfiguration.name = Apache HTTP Components Proxy Configuration
+org.apache.http.osgi.proxy.ProxyConfiguration.description = Defines proxy configurations used by the Apache HTTP \
+ Components Proxy Selector.
+
+proxy.enabled.name = Enable HTTP Proxy
+proxy.enabled.description = Whether to enable or disable HTTP Proxying globally. \
+ Setting this property to false disables HTTP Proxying and the other configurtion \
+ properties have no effect. The default value is false.
+
+proxy.host.name = HTTP Proxy Host
+proxy.host.description = Host name (or IP Address) of the HTTP Proxy. \
+ This property is ignored if HTTP Proxying is disabled. This property does \
+ not have default value. Enabling HTTP Proxying but not setting the HTTP \
+ Proxy Host causes HTTP Proxying to actually be disabled.
+
+proxy.port.name = HTTP Proxy Port
+proxy.port.description = Port number of the HTTP Proxy. \
+ This property is ignored if HTTP Proxying is disabled. This property does \
+ not have default value. Enabling HTTP Proxying but not setting the HTTP \
+ Proxy Host causes HTTP Proxying to actually be disabled.
+
+proxy.user.name = HTTP Proxy User
+proxy.user.description = The name of the user to authenticate as with the HTTP \
+ Proxy Host. If this field is empty, the proxy is considered to not be \
+ authenticated. The default is empty. This property is ignored if proxying is \
+ disabled or the proxy host is not properly configured.
+
+proxy.password.name = HTTP Proxy Password
+proxy.password.description = The password of the HTTP Proxy user to authenticate \
+ with. The default is empty. This property is ignored if proxying is \
+ disabled or the proxy host is not properly configured.
+
+proxy.ntlm.host.name = HTTP Proxy NTLM Host
+proxy.ntlm.host.description = The host the authentication request is \
+ originating from. Essentially, the computer name for this machine. By default \
+ the credentials assume simple username password authentication. If the proxy \
+ happens to be a Microsoft IIS Server using NTLM authentication this property \
+ must be set to the NT Domain name of the user to authenticate as. This is \
+ not set by default.
+
+proxy.ntlm.domain.name = HTTP Proxy NTLM Domain
+proxy.ntlm.domain.description = The NTLM domain to authenticate within. By \
+ default the credentials assume simple username password authentication. If \
+ the proxy happens to be a Microsoft IIS Server using NTLM authentication this \
+ property must be set to the NT Domain name of the user to authenticate as. \
+ This is not set by default.
+
+proxy.exceptions.name = No Proxy For
+proxy.exceptions.description = Lists domain names, host names, IP Addresses or \
+ or network addresses for which the HTTP Proxy Host should not be used. A domain \
+ name indicating all hosts of a domain is indicated by a leading dot, e.g. \
+ ".day.com". A network address is indicated with subnet mask notation indicating \
+ the number of bits make up the network address, e.g 192.168.1.0/24 means the \
+ class C network "192.168.1". Note that for proxy selection, the host name of \
+ URL is not resolved but directly compared to the list of exceptions. For this \
+ reason you might want to indicate both the network address and the domain for \
+ targets which should not be passed through the proxy. This property has no \
+ effect if HTTP Proxying is disabled. The default value is [ localhost, \
+ 127.0.0.1 ].
Index: httpclient/src/main/java/org/apache/http/impl/conn/PoolingClientConnectionManager.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/impl/conn/PoolingClientConnectionManager.java (revision 1395548)
+++ httpclient/src/main/java/org/apache/http/impl/conn/PoolingClientConnectionManager.java (revision )
@@ -113,6 +113,9 @@
this.dnsResolver = dnsResolver;
this.operator = createConnectionOperator(schemeRegistry);
this.pool = new HttpConnPool(this.log, 2, 20, timeToLive, tunit);
+
+ // have this connection manager centrally tracked via weak reference
+ ClientConnectionManagerTracker.getInstance().add(this);
}
@Override
Index: httpclient/src/main/java/org/apache/http/impl/conn/SingleClientConnManager.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/impl/conn/SingleClientConnManager.java (revision 1395548)
+++ httpclient/src/main/java/org/apache/http/impl/conn/SingleClientConnManager.java (revision )
@@ -128,6 +128,9 @@
this.lastReleaseTime = -1L;
this.alwaysShutDown = false; //@@@ from params? as argument?
this.isShutDown = false;
+
+ // have this connection manager centrally tracked via weak reference
+ ClientConnectionManagerTracker.getInstance().add(this);
}
/**
Index: httpclient-osgi/src/main/java/org/apache/http/osgi/proxy/ProxyConfiguration.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient-osgi/src/main/java/org/apache/http/osgi/proxy/ProxyConfiguration.java (revision )
+++ httpclient-osgi/src/main/java/org/apache/http/osgi/proxy/ProxyConfiguration.java (revision )
@@ -0,0 +1,373 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.osgi.proxy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.http.osgi.util.PropertiesUtil;
+
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * ProxyConfiguration...
+ */
+@Component(configurationFactory = true, metatype = true)
+@Service(value = ProxyConfiguration.class)
+@Properties({
+ @Property(name = ProxyConfiguration.PROPERTYNAME_PROXY_ENABLED,
+ boolValue = ProxyConfiguration.PROPERTYDEFAULT_PROXY_ENABLED),
+ @Property(name = ProxyConfiguration.PROPERTYNAME_PROXY_HOSTNAME,
+ value = ProxyConfiguration.PROPERTYDEFAULT_PROXY_HOSTNAME),
+ @Property(name = ProxyConfiguration.PROPERTYNAME_PROXY_PORT,
+ intValue = ProxyConfiguration.PROPERTYDEFAULT_PROXY_PORT),
+ @Property(name = ProxyConfiguration.PROPERTYNAME_PROXY_USERNAME,
+ value = ProxyConfiguration.PROPERTYDEFAULT_PROXY_USERNAME),
+ @Property(name = ProxyConfiguration.PROPERTYNAME_PROXY_PASSWORD,
+ value = ProxyConfiguration.PROPERTYDEFAULT_PROXY_PASSWORD),
+ @Property(name = ProxyConfiguration.PROPERTYNAME_PROXY_NTLMHOST,
+ value = ProxyConfiguration.PROPERTYDEFAULT_PROXY_NTLMHOST),
+ @Property(name = ProxyConfiguration.PROPERTYNAME_PROXY_EXCEPTIONS,
+ unbounded = PropertyUnbounded.ARRAY)
+ })
+public class ProxyConfiguration {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /**
+ * Property indicating whether this particular proxy is enabled (shall be used or not). Defaults to true.
+ */
+ static final String PROPERTYNAME_PROXY_ENABLED = "proxy.enabled";
+ static final boolean PROPERTYDEFAULT_PROXY_ENABLED = true;
+
+ /**
+ * Property representing the hostname of the proxy. Defaults to empty.
+ */
+ static final String PROPERTYNAME_PROXY_HOSTNAME = "proxy.host";
+ static final String PROPERTYDEFAULT_PROXY_HOSTNAME = "";
+
+
+ /**
+ * Property representing the port of the proxy. Defaults to 0.
+ */
+ static final String PROPERTYNAME_PROXY_PORT = "proxy.port";
+ static final int PROPERTYDEFAULT_PROXY_PORT = 0;
+
+ /**
+ * Property representing the username to authenticate with towards the proxy. Defaults to empty.
+ */
+ static final String PROPERTYNAME_PROXY_USERNAME = "proxy.user";
+ static final String PROPERTYDEFAULT_PROXY_USERNAME = "";
+
+ /**
+ * Property representing the password to authenticate with towards the proxy. Defaults to empty.
+ */
+ static final String PROPERTYNAME_PROXY_PASSWORD = "proxy.password";
+ static final String PROPERTYDEFAULT_PROXY_PASSWORD = "";
+
+ /**
+ * Property representing the NTLM domain to use for authentication towards the proxy. If this is set, authentication
+ * is switched from basic to NTLM.
+ */
+ static final String PROPERTYNAME_PROXY_NTLMHOST = "proxy.ntlm.host";
+ static final String PROPERTYDEFAULT_PROXY_NTLMHOST = "";
+
+ /**
+ * A multivalue property representing host patterns for which no proxy shall be used. By default localhost is
+ * excluded.
+ */
+ static final String PROPERTYNAME_PROXY_EXCEPTIONS = "proxy.exceptions";
+ static final String[] PROPERTYDEFAULT_PROXY_EXCEPTIONS = {"localhost", "127.0.0.1"};
+
+ /**
+ * The IP mask pattern against which hosts are matched.
+ */
+ public static final Pattern IP_MASK_PATTERN =
+ Pattern.compile("(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})(/(\\d{1,2}))?");
+
+ private static final String SCHEME_HTTP = "http";
+ private static final String SCHEME_HTTPS = "https";
+
+ private boolean enabled;
+ private String hostname;
+ private int port;
+ private String username;
+ private String password;
+ private String ntlmhost;
+ private HostMatcher[] exceptions;
+
+ private Proxy proxy;
+ private boolean valid;
+ private SocketAddress address;
+ private int failed = 0;
+
+ @Activate
+ @Modified
+ @SuppressWarnings("unused")
+ protected void configure(final Map properties) {
+
+ /**
+ * Map the OSGi configuration properties to local fields in the correct type
+ */
+ enabled = PropertiesUtil.toBoolean(properties.get(PROPERTYNAME_PROXY_ENABLED), PROPERTYDEFAULT_PROXY_ENABLED);
+ hostname = PropertiesUtil.toString(properties.get(PROPERTYNAME_PROXY_HOSTNAME), PROPERTYDEFAULT_PROXY_HOSTNAME);
+ port = PropertiesUtil.toInteger(properties.get(PROPERTYNAME_PROXY_PORT), PROPERTYDEFAULT_PROXY_PORT);
+ username = PropertiesUtil.toString(properties.get(PROPERTYNAME_PROXY_USERNAME), PROPERTYDEFAULT_PROXY_USERNAME);
+ password = PropertiesUtil.toString(properties.get(PROPERTYNAME_PROXY_PASSWORD), PROPERTYDEFAULT_PROXY_PASSWORD);
+ ntlmhost = PropertiesUtil.toString(properties.get(PROPERTYNAME_PROXY_NTLMHOST), PROPERTYDEFAULT_PROXY_NTLMHOST);
+
+ setProxyExceptions(PropertiesUtil.toStringArray(properties.get(PROPERTYNAME_PROXY_EXCEPTIONS),
+ PROPERTYDEFAULT_PROXY_EXCEPTIONS));
+
+ try {
+ // we consider a proxy configuration valid if the address doesn't throw
+ address = new InetSocketAddress(getHostname(), getPort());
+ valid = true;
+ } catch (IllegalArgumentException e) {
+ log.error("Invalid configuration: encountered invalid proxy address: host["
+ + getHostname() + "] - port["
+ + getPort() + "]: ", e);
+ } catch (SecurityException e) {
+ log.error("Invalid configuration: security error while accessing proxy address: host["
+ + getHostname() + "] - port["
+ + getPort() + "]: ", e);
+ }
+ }
+
+ public SocketAddress getAddress() {
+ return address;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public String getNtlmhost() {
+ return ntlmhost;
+ }
+
+ public Proxy getProxy() {
+ if (null == proxy && isValid()) {
+ proxy = new Proxy(Proxy.Type.HTTP, address);
+ }
+ return proxy;
+ }
+
+ /**
+ * Indicates whether this config is valid and can be used. A valid configuration is enabled by configuration and has
+ * a valid proxy address configured.
+ *
+ * @return true if the proxy configuration is valid.
+ */
+ public boolean isValid() {
+ return enabled && valid;
+ }
+
+ /**
+ * Indicates the number of times connecting to the proxy based on this configuration has failed.
+ *
+ * @return An int representing the number of connection failures.
+ */
+ public int failed() {
+ return ++failed;
+ }
+
+ @Override
+ public String toString() {
+ return getHostname() + ":" + getPort() + " (" + getUsername() + "/" + getNtlmhost() + ")";
+ }
+
+ /**
+ * Indicates whether the given uri is accepted by this proxy configuration, i.e. that the proxy is
+ * suitable for usage with that URI. All URIs of scheme HTTP and HTTPS are accepted. Additionally the hostname of
+ * the URI must not be on the configurable exclusion list. By default localhost is exluced.
+ *
+ * @param uri The {@link URI} to check.
+ *
+ * @return true if the URI is accepted.
+ */
+ public boolean accepts(final URI uri) {
+
+ final String scheme = uri.getScheme();
+ if (SCHEME_HTTP.equalsIgnoreCase(scheme) || SCHEME_HTTPS.equalsIgnoreCase(scheme)) {
+
+ // this host is on the exclusion list => no proxy (not this one)
+ for (final HostMatcher matcher : exceptions) {
+ if (matcher.matches(uri.getHost())) {
+ return false;
+ }
+ }
+
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+ private void setProxyExceptions(String[] exceptions) {
+ ArrayList exceptionList = new ArrayList();
+ if (exceptions != null) {
+ for (final String exception : exceptions) {
+ exceptionList.add(createMatcher(exception.trim()));
+ }
+ }
+ this.exceptions = exceptionList.toArray(new HostMatcher[exceptionList.size()]);
+ }
+
+ private static HostMatcher createMatcher(final String name) {
+ final NetworkAddress na = NetworkAddress.parse(name);
+ if (na != null) {
+ return new IPAddressMatcher(na);
+ }
+
+ if (name.startsWith(".")) {
+ return new DomainNameMatcher(name);
+ }
+
+ return new HostNameMatcher(name);
+ }
+
+ private static interface HostMatcher {
+
+ boolean matches(String host);
+ }
+
+ private static class HostNameMatcher implements HostMatcher {
+
+ private final String hostName;
+
+ HostNameMatcher(String hostName) {
+ this.hostName = hostName;
+ }
+
+ public boolean matches(String host) {
+ return hostName.equalsIgnoreCase(host);
+ }
+ }
+
+ private static class DomainNameMatcher implements HostMatcher {
+
+ private final String domainName;
+
+ DomainNameMatcher(String domainName) {
+ this.domainName = domainName.toLowerCase();
+ }
+
+ public boolean matches(String host) {
+ return host.toLowerCase().endsWith(domainName);
+ }
+ }
+
+ private static class IPAddressMatcher implements HostMatcher {
+
+ private final NetworkAddress address;
+
+ IPAddressMatcher(NetworkAddress address) {
+ this.address = address;
+ }
+
+ public boolean matches(String host) {
+ NetworkAddress hostAddress = NetworkAddress.parse(host);
+ return hostAddress != null && address.address == (hostAddress.address & address.mask);
+ }
+ }
+
+ private static class NetworkAddress {
+
+ final int address;
+
+ final int mask;
+
+ static NetworkAddress parse(String adrSpec) {
+
+ if (null != adrSpec) {
+ final Matcher nameMatcher = IP_MASK_PATTERN.matcher(adrSpec);
+ if (nameMatcher.matches()) {
+ try {
+ int i1 = toInt(nameMatcher.group(1), 255);
+ int i2 = toInt(nameMatcher.group(2), 255);
+ int i3 = toInt(nameMatcher.group(3), 255);
+ int i4 = toInt(nameMatcher.group(4), 255);
+ int ip = i1 << 24 | i2 << 16 | i3 << 8 | i4;
+
+ int mask = toInt(nameMatcher.group(6), 32);
+ mask = (mask == 32) ? -1 : -1 - (-1 >>> mask);
+
+ return new NetworkAddress(ip, mask);
+ } catch (NumberFormatException nfe) {
+ // not expected after the pattern match !
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static int toInt(String value, int max) {
+ if (value == null || value.length() == 0) {
+ return max;
+ }
+
+ int number = Integer.parseInt(value);
+ if (number > max) {
+ number = max;
+ }
+ return number;
+ }
+
+ NetworkAddress(int address, int mask) {
+ this.address = address;
+ this.mask = mask;
+ }
+ }
+}
Index: httpclient/src/main/java/org/apache/http/impl/conn/ClientConnectionManagerTracker.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/impl/conn/ClientConnectionManagerTracker.java (revision )
+++ httpclient/src/main/java/org/apache/http/impl/conn/ClientConnectionManagerTracker.java (revision )
@@ -0,0 +1,90 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.impl.conn;
+
+import org.apache.http.conn.ClientConnectionManager;
+
+import java.util.Set;
+import java.util.WeakHashMap;
+
+/**
+ * The ClientConnectionManagerTracker should be used by any implementations of {@link
+ * ClientConnectionManager}, which should in the constructor add its instance via {@link
+ * #add(org.apache.http.conn.ClientConnectionManager)}:
+ *
+ * ClientConnectionManagerTracker.getInstance().add(this);
+ *
+ * ClientConnectionManagers added thus are tracked using {@link java.lang.ref.WeakReference}s. The purpose of the
+ * tracking is such, that all active ClientConnectionManagers can be retrieved via {@link #getAll()} and tasks, such as
+ * shutting down all clients in order to ensure proper stopping of an application using this library.
+ */
+public final class ClientConnectionManagerTracker {
+
+ public static ClientConnectionManagerTracker instance;
+
+ private final WeakHashMap managers
+ = new WeakHashMap();
+
+ // do not allow public construction
+ private ClientConnectionManagerTracker() {
+ }
+
+ /**
+ * Returns a singleton ClientConnectionManagerTracker instance. The first call will construct the
+ * singleton.
+ *
+ * @return The ClientConnectionManagerTracker
+ */
+ public static ClientConnectionManagerTracker getInstance() {
+ if (null == instance) {
+ instance = new ClientConnectionManagerTracker();
+ }
+ return instance;
+ }
+
+ /**
+ * Adds a {@link ClientConnectionManager} as a {@link java.lang.ref.WeakReference} to this tracker.
+ *
+ * @param manager The {@link ClientConnectionManager} to add.
+ */
+ public void add(final ClientConnectionManager manager) {
+ synchronized (managers) {
+ // only the key is weakly referenced, the map value can be ignored
+ managers.put(manager, null);
+ }
+ }
+
+ /**
+ * Returnes a {@link Set} of {@link java.lang.ref.WeakReference}s to {@link ClientConnectionManager}s. An element of
+ * the set may be null.
+ *
+ * @return A Set representing weakly referenced ClientConnectionManagers.
+ */
+ public Set getAll() {
+ return managers.keySet();
+ }
+}
Index: httpclient/src/main/java/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java (revision 1395548)
+++ httpclient/src/main/java/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java (revision )
@@ -41,6 +41,7 @@
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.OperatedClientConnection;
+import org.apache.http.impl.conn.ClientConnectionManagerTracker;
import org.apache.http.params.HttpParams;
import org.apache.http.impl.conn.DefaultClientConnectionOperator;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
@@ -139,6 +140,9 @@
this.connOperator = createConnectionOperator(schreg);
this.pool = createConnectionPool(connTTL, connTTLTimeUnit) ;
this.connectionPool = this.pool;
+
+ // have this connection manager centrally tracked via weak reference
+ ClientConnectionManagerTracker.getInstance().add(this);
}
/**