HTTPCLIENT-1238: Contribute Bundle Activator And Central Proxy Configuration

Contributed by Simone Tripodi <simonetripodi at apache.org>

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1469247 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2013-04-18 09:45:19 +00:00
parent 68243b227f
commit edeee62f8d
17 changed files with 1407 additions and 6 deletions

View File

@ -1,6 +1,9 @@
Changes since release 4.3 BETA1
-------------------
* [HTTPCLIENT-1238] Contribute Bundle Activator And Central Proxy Configuration.
Contributed by Simone Tripodi <simonetripodi at apache.org>
* [HTTPCLIENT-1341] DeflateDecompressingEntity does not call Inflater#end.
Contributed by Oleg Kalnichevski <olegk at apache.org>

View File

@ -48,6 +48,11 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
@ -72,16 +77,30 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>4.2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
<version>4.2.0</version>
<scope>provided</scope>
</dependency>
<!-- test dependencies, mainly OSGi runtime environment -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
<plugins>
@ -103,6 +122,7 @@
org.apache.http.impl.cookie.*;version=${project.version},
org.apache.http.impl.conn.*;version=${project.version},
org.apache.http.impl.client.*;version=${project.version}
org.apache.http.osgi.services;version=${project.version}
</_exportcontents>
<Embed-Dependency>*;scope=compile|runtime;inline=true</Embed-Dependency>
<Import-Package>
@ -111,10 +131,11 @@
javax.net,
javax.net.ssl,
javax.security.auth.x500,
org.ietf.jgss,
org.ietf.jgss,,
org.osgi.framework,
org.osgi.service.cm,
org.apache.commons.logging;version=${commons-logging.version},
org.apache.http;version=${httpcore.version},
org.apache.http.config.*;version=${httpcore.version},
org.apache.http.concurrent;version=${httpcore.version},
org.apache.http.entity;version=${httpcore.version},
org.apache.http.io;version=${httpcore.version},
@ -130,6 +151,7 @@
net.sf.ehcache.*;resolution:=optional,
net.spy.memcached.*;resolution:=optional
</Import-Package>
<Bundle-Activator>org.apache.http.osgi.impl.HttpProxyConfigurationActivator</Bundle-Activator>
<!-- Stop the JAVA_1_n_HOME variables from being treated as headers by Bnd -->
<_removeheaders>JAVA_1_3_HOME,JAVA_1_4_HOME</_removeheaders>
</instructions>

View File

@ -0,0 +1,165 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
package org.apache.http.osgi.impl;
import java.io.Closeable;
import java.io.IOException;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.osgi.services.HttpClientBuilderFactory;
import org.apache.http.osgi.services.ProxyConfiguration;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
/**
* @since 4.3
*/
public final class HttpProxyConfigurationActivator implements BundleActivator, ManagedServiceFactory {
private static final String SERVICE_FACTORY_NAME = "Apache HTTP Client Proxy Configuration Factory";
private static final String SERVICE_PID = "org.apache.http.proxyconfigurator";
private ServiceRegistration configurator;
private ServiceRegistration clientFactory;
private BundleContext context;
private final Map<String, ServiceRegistration> registeredConfigurations = new LinkedHashMap<String, ServiceRegistration>();
private final List<CloseableHttpClient> trackedHttpClients = new LinkedList<CloseableHttpClient>();
/**
* {@inheritDoc}
*/
public void start(final BundleContext context) throws Exception {
this.context = context;
// ensure we receive configurations for the proxy selector
final Hashtable<String, Object> props = new Hashtable<String, Object>();
props.put(Constants.SERVICE_PID, getName());
props.put(Constants.SERVICE_VENDOR, context.getBundle().getHeaders(Constants.BUNDLE_VENDOR));
props.put(Constants.SERVICE_DESCRIPTION, SERVICE_FACTORY_NAME);
configurator = context.registerService(ManagedServiceFactory.class.getName(), this, props);
clientFactory = context.registerService(HttpClientBuilderFactory.class.getName(),
new OSGiClientBuilderFactory(context, registeredConfigurations, trackedHttpClients),
props);
}
/**
* {@inheritDoc}
*/
public void stop(final BundleContext context) throws Exception {
// unregister services
for (final ServiceRegistration registeredConfiguration : registeredConfigurations.values()) {
registeredConfiguration.unregister();
}
// unregister service factory
if (configurator != null) {
configurator.unregister();
}
if (clientFactory != null) {
clientFactory.unregister();
}
// ensure all http clients - generated with the - are terminated
for (final CloseableHttpClient client : trackedHttpClients) {
if (null != client) {
closeQuietly(client);
}
}
// remove all tracked services
registeredConfigurations.clear();
// remove all tracked created clients
trackedHttpClients.clear();
}
/**
* {@inheritDoc}
*/
public String getName() {
return SERVICE_PID;
}
/**
* {@inheritDoc}
*/
public void updated(final String pid, @SuppressWarnings("rawtypes") final Dictionary config) throws ConfigurationException {
final ServiceRegistration registration = registeredConfigurations.get(pid);
OSGiProxyConfiguration proxyConfiguration;
if (registration == null) {
proxyConfiguration = new OSGiProxyConfiguration();
final ServiceRegistration configurationRegistration = context.registerService(ProxyConfiguration.class.getName(),
proxyConfiguration,
config);
registeredConfigurations.put(pid, configurationRegistration);
} else {
proxyConfiguration = (OSGiProxyConfiguration) context.getService(registration.getReference());
}
@SuppressWarnings("unchecked") // data type is known
final
Dictionary<String, Object> properties = config;
proxyConfiguration.update(properties);
}
/**
* {@inheritDoc}
*/
public void deleted(final String pid) {
final ServiceRegistration registeredConfiguration = registeredConfigurations.get(pid);
if (null != registeredConfiguration) {
registeredConfiguration.unregister();
registeredConfigurations.remove(pid);
}
}
private static void closeQuietly(final Closeable closeable) {
try {
closeable.close();
} catch (final IOException e) {
// do nothing
}
}
}

View File

@ -0,0 +1,62 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
package org.apache.http.osgi.impl;
import java.util.List;
import java.util.Map;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.osgi.services.HttpClientBuilderFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
/**
* @since 4.3
*/
public final class OSGiClientBuilderFactory implements HttpClientBuilderFactory {
private final BundleContext bundleContext;
private final Map<String, ServiceRegistration> registeredConfigurations;
private final List<CloseableHttpClient> trackedHttpClients;
public OSGiClientBuilderFactory(
final BundleContext bundleContext,
final Map<String, ServiceRegistration> registeredConfigurations,
final List<CloseableHttpClient> trackedHttpClients) {
this.bundleContext = bundleContext;
this.registeredConfigurations = registeredConfigurations;
this.trackedHttpClients = trackedHttpClients;
}
public HttpClientBuilder newBuilder() {
return new OSGiHttpClientBuilder(bundleContext, registeredConfigurations, trackedHttpClients);
}
}

View File

@ -0,0 +1,92 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
package org.apache.http.osgi.impl;
import java.util.Map;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.osgi.services.ProxyConfiguration;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
/**
* @since 4.3
*/
final class OSGiCredentialsProvider implements CredentialsProvider {
private final BundleContext bundleContext;
private final Map<String, ServiceRegistration> registeredConfigurations;
public OSGiCredentialsProvider(
final BundleContext bundleContext,
final Map<String, ServiceRegistration> registeredConfigurations) {
this.bundleContext = bundleContext;
this.registeredConfigurations = registeredConfigurations;
}
/**
* {@inheritDoc}
*/
public void setCredentials(final AuthScope authscope, final Credentials credentials) {
// do nothing, not used in this version
}
/**
* {@inheritDoc}
*/
public Credentials getCredentials(final AuthScope authscope) {
// iterate over all active proxy configurations at the moment of getting the credential
for (final ServiceRegistration registration : registeredConfigurations.values()) {
final Object proxyConfigurationObject = bundleContext.getService(registration.getReference());
if (proxyConfigurationObject != null) {
final ProxyConfiguration proxyConfiguration = (ProxyConfiguration) proxyConfigurationObject;
if (proxyConfiguration.isEnabled()) {
final AuthScope actual = new AuthScope(proxyConfiguration.getHostname(), proxyConfiguration.getPort());
if (authscope.equals(actual)) {
return new UsernamePasswordCredentials(proxyConfiguration.getUsername(),
proxyConfiguration.getPassword());
}
}
}
}
// credentials no longer available!
return null;
}
/**
* {@inheritDoc}
*/
public void clear() {
// do nothing, not used in this version
}
}

View File

@ -0,0 +1,62 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
package org.apache.http.osgi.impl;
import java.util.List;
import java.util.Map;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
/**
* @since 4.3
*/
final class OSGiHttpClientBuilder extends HttpClientBuilder {
private final List<CloseableHttpClient> trackedHttpClients;
public OSGiHttpClientBuilder(
final BundleContext bundleContext,
final Map<String, ServiceRegistration> registeredConfigurations,
final List<CloseableHttpClient> trackedHttpClients) {
this.trackedHttpClients = trackedHttpClients;
setDefaultCredentialsProvider(
new OSGiCredentialsProvider(bundleContext, registeredConfigurations));
setRoutePlanner(
new OSGiHttpRoutePlanner(bundleContext, registeredConfigurations));
}
@Override
public CloseableHttpClient build() {
final CloseableHttpClient httpClient = super.build();
trackedHttpClients.add(httpClient);
return httpClient;
}
}

View File

@ -0,0 +1,206 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
package org.apache.http.osgi.impl;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.impl.conn.DefaultRoutePlanner;
import org.apache.http.osgi.services.ProxyConfiguration;
import org.apache.http.protocol.HttpContext;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
/**
* @since 4.3
*/
final class OSGiHttpRoutePlanner extends DefaultRoutePlanner {
private static final String DOT = ".";
/**
* The IP mask pattern against which hosts are matched.
*/
public static final Pattern IP_MASK_PATTERN = Pattern.compile("^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
private final BundleContext bundleContext;
private final Map<String, ServiceRegistration> registeredConfigurations;
public OSGiHttpRoutePlanner(
final BundleContext bundleContext,
final Map<String, ServiceRegistration> registeredConfigurations) {
super(null);
this.bundleContext = bundleContext;
this.registeredConfigurations = registeredConfigurations;
}
/**
* {@inheritDoc}
*/
@Override
protected HttpHost determineProxy(final HttpHost target, final HttpRequest request, final HttpContext context) throws HttpException {
ProxyConfiguration proxyConfiguration = null;
for (final ServiceRegistration registration : registeredConfigurations.values()) {
final Object proxyConfigurationObject = bundleContext.getService(registration.getReference());
if (proxyConfigurationObject != null) {
proxyConfiguration = (ProxyConfiguration) proxyConfigurationObject;
if (proxyConfiguration.isEnabled()) {
for (final String exception : proxyConfiguration.getProxyExceptions()) {
if (createMatcher(exception).matches(target.getHostName())) {
return null;
} else {
return new HttpHost(proxyConfiguration.getHostname(), proxyConfiguration.getPort());
}
}
}
}
}
return null;
}
private static HostMatcher createMatcher(final String name) {
final NetworkAddress na = NetworkAddress.parse(name);
if (na != null) {
return new IPAddressMatcher(na);
}
if (name.startsWith(DOT)) {
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(final String hostName) {
this.hostName = hostName;
}
public boolean matches(final String host) {
return hostName.equalsIgnoreCase(host);
}
}
private static class DomainNameMatcher implements HostMatcher {
private final String domainName;
DomainNameMatcher(final String domainName) {
this.domainName = domainName.toLowerCase(Locale.ENGLISH);
}
public boolean matches(final String host) {
return host.toLowerCase(Locale.ENGLISH).endsWith(domainName);
}
}
private static class IPAddressMatcher implements HostMatcher {
private final NetworkAddress address;
IPAddressMatcher(final NetworkAddress address) {
this.address = address;
}
public boolean matches(final String host) {
final 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(final String adrSpec) {
if (null != adrSpec) {
final Matcher nameMatcher = IP_MASK_PATTERN.matcher(adrSpec);
if (nameMatcher.matches()) {
try {
final int i1 = toInt(nameMatcher.group(1), 255);
final int i2 = toInt(nameMatcher.group(2), 255);
final int i3 = toInt(nameMatcher.group(3), 255);
final int i4 = toInt(nameMatcher.group(4), 255);
final 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 (final NumberFormatException nfe) {
// not expected after the pattern match !
}
}
}
return null;
}
private static int toInt(final String value, final int max) {
if (value == null || value.length() == 0) {
return max;
}
int number = Integer.parseInt(value);
if (number > max) {
number = max;
}
return number;
}
NetworkAddress(final int address, final int mask) {
this.address = address;
this.mask = mask;
}
}
}

View File

@ -0,0 +1,135 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
package org.apache.http.osgi.impl;
import static java.lang.String.format;
import static org.apache.http.osgi.impl.PropertiesUtils.to;
import java.util.Dictionary;
import org.apache.http.osgi.services.ProxyConfiguration;
/**
* @since 4.3
*/
public final class OSGiProxyConfiguration implements ProxyConfiguration {
/**
* Property indicating whether this particular proxy is enabled (shall be used or not). Defaults to true.
*/
private static final String PROPERTYNAME_PROXY_ENABLED = "proxy.enabled";
private static final boolean PROPERTYDEFAULT_PROXY_ENABLED = true;
/**
* Property representing the hostname of the proxy. Defaults to empty.
*/
private static final String PROPERTYNAME_PROXY_HOSTNAME = "proxy.host";
private static final String PROPERTYDEFAULT_PROXY_HOSTNAME = "";
/**
* Property representing the port of the proxy. Defaults to 0.
*/
private static final String PROPERTYNAME_PROXY_PORT = "proxy.port";
private static final int PROPERTYDEFAULT_PROXY_PORT = 0;
/**
* Property representing the username to authenticate with towards the proxy. Defaults to empty.
*/
private static final String PROPERTYNAME_PROXY_USERNAME = "proxy.username";
private static final String PROPERTYDEFAULT_PROXY_USERNAME = "";
/**
* Property representing the password to authenticate with towards the proxy. Defaults to empty.
*/
private static final String PROPERTYNAME_PROXY_PASSWORD = "proxy.password";
private static final String PROPERTYDEFAULT_PROXY_PASSWORD = "";
/**
* A multivalue property representing host patterns for which no proxy shall be used. By default localhost is
* excluded.
*/
private static final String PROPERTYNAME_PROXY_EXCEPTIONS = "proxy.exceptions";
private static final String[] PROPERTYDEFAULT_PROXY_EXCEPTIONS = new String[]{"localhost", "127.0.0.1"};
private boolean enabled;
private String hostname;
private int port;
private String username;
private String password;
private String[] proxyExceptions;
public boolean isEnabled() {
return enabled;
}
public String getHostname() {
return hostname;
}
public int getPort() {
return port;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String[] getProxyExceptions() {
return proxyExceptions;
}
public void update(final Dictionary<String, Object> config) {
enabled = to(config.get(PROPERTYNAME_PROXY_ENABLED), boolean.class, PROPERTYDEFAULT_PROXY_ENABLED);
hostname = to(config.get(PROPERTYNAME_PROXY_HOSTNAME), String.class, PROPERTYDEFAULT_PROXY_HOSTNAME);
port = to(config.get(PROPERTYNAME_PROXY_PORT), int.class, PROPERTYDEFAULT_PROXY_PORT);
username = to(config.get(PROPERTYNAME_PROXY_USERNAME), String.class, PROPERTYDEFAULT_PROXY_USERNAME);
password = to(config.get(PROPERTYNAME_PROXY_PASSWORD), String.class, PROPERTYDEFAULT_PROXY_PASSWORD);
proxyExceptions = to(config.get(PROPERTYNAME_PROXY_EXCEPTIONS), String[].class, PROPERTYDEFAULT_PROXY_EXCEPTIONS);
}
@Override
public String toString() {
return format("ProxyConfiguration [enabled=%s, hostname=%s, port=%s, username=%s, password=%s, proxyExceptions=%s]",
proxyExceptions, enabled, hostname, port, username, password, proxyExceptions);
}
}

View File

@ -0,0 +1,199 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
package org.apache.http.osgi.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @since 4.3
*/
final class PropertiesUtils {
private static final Map<Class<?>, PropertyConverter<?>> CONVERTERS_REGISTRY =
new HashMap<Class<?>, PropertiesUtils.PropertyConverter<?>>();
static {
register(new BooleanPropertyConverter(), boolean.class, Boolean.class);
register(new StringPropertyConverter(), String.class);
register(new StringArrayPropertyConverter(), String[].class);
register(new IntegerPropertyConverter(), int.class, Integer.class);
register(new LongPropertyConverter(), long.class, Long.class);
register(new DoublePropertyConverter(), double.class, Double.class);
}
private static void register(PropertyConverter<?> converter, Class<?>...targetTypes) {
for (Class<?> targetType : targetTypes) {
CONVERTERS_REGISTRY.put(targetType, converter);
}
}
public static <T> T to(Object propValue, Class<T> targetType, T defaultValue) {
if (propValue == null) {
return defaultValue;
}
if (!targetType.isArray()) {
propValue = toObject(propValue);
}
if (targetType.isInstance(propValue)) {
return targetType.cast(propValue);
}
if (CONVERTERS_REGISTRY.containsKey(targetType)) {
@SuppressWarnings("unchecked") // type driven by targetType
PropertyConverter<T> converter = (PropertyConverter<T>) CONVERTERS_REGISTRY.get(targetType);
try {
return converter.to(propValue);
} catch (Throwable t) {
// 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 <code>java.util.Collection</code> 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
* <code>java.util.Collection</code>, the first collection element is returned.
*
* @param propValue the parameter to convert.
*/
private static Object toObject(Object propValue) {
if (propValue.getClass().isArray()) {
Object[] prop = (Object[]) propValue;
return prop.length > 0 ? prop[0] : null;
}
if (propValue instanceof Collection<?>) {
Collection<?> prop = (Collection<?>) propValue;
return prop.isEmpty() ? null : prop.iterator().next();
}
return propValue;
}
/**
* Hidden constructor, this class must not be instantiated.
*/
private PropertiesUtils() {
// do nothing
}
private static interface PropertyConverter<T> {
T to(Object propValue);
}
private static class BooleanPropertyConverter implements PropertyConverter<Boolean> {
public Boolean to(Object propValue) {
return Boolean.valueOf(String.valueOf(propValue));
}
}
private static class StringPropertyConverter implements PropertyConverter<String> {
public String to(Object propValue) {
return String.valueOf(propValue);
}
}
private static class StringArrayPropertyConverter implements PropertyConverter<String[]> {
public String[] to(Object propValue) {
if (propValue instanceof String) {
// single string
return new String[] { (String) propValue };
}
if (propValue.getClass().isArray()) {
// other array
Object[] valueArray = (Object[]) propValue;
List<String> values = new ArrayList<String>(valueArray.length);
for (Object value : valueArray) {
if (value != null) {
values.add(value.toString());
}
}
return values.toArray(new String[values.size()]);
}
if (propValue instanceof Collection<?>) {
// collection
Collection<?> valueCollection = (Collection<?>) propValue;
List<String> valueList = new ArrayList<String>(valueCollection.size());
for (Object value : valueCollection) {
if (value != null) {
valueList.add(value.toString());
}
}
return valueList.toArray(new String[valueList.size()]);
}
// don't care, fall through to default value
throw new IllegalArgumentException();
}
}
private static class IntegerPropertyConverter implements PropertyConverter<Integer> {
public Integer to(Object propValue) {
return Integer.valueOf(String.valueOf(propValue));
}
}
private static class LongPropertyConverter implements PropertyConverter<Long> {
public Long to(Object propValue) {
return Long.valueOf(String.valueOf(propValue));
}
}
private static class DoublePropertyConverter implements PropertyConverter<Double> {
public Double to(Object propValue) {
return Double.valueOf(String.valueOf(propValue));
}
}
}

View File

@ -0,0 +1,27 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
package org.apache.http.osgi.impl;

View File

@ -0,0 +1,31 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
/**
* @since 4.3
*/
package org.apache.http.osgi;

View File

@ -0,0 +1,38 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
package org.apache.http.osgi.services;
import org.apache.http.impl.client.HttpClientBuilder;
/**
* @since 4.3
*/
public interface HttpClientBuilderFactory {
HttpClientBuilder newBuilder();
}

View File

@ -0,0 +1,46 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
package org.apache.http.osgi.services;
/**
* @since 4.3
*/
public interface ProxyConfiguration {
boolean isEnabled();
String getHostname();
int getPort();
String getUsername();
String getPassword();
String[] getProxyExceptions();
}

View File

@ -0,0 +1,31 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
/**
* @since 4.3
*/
package org.apache.http.osgi.services;

View File

@ -0,0 +1,77 @@
#
# 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.
#
proxyconfigurator.name = Apache HTTP Components Proxy Configurator
proxyconfigurator.description = Factory configuration for transparent proxies used by every HTTP Client.
proxyconfig.name = Apache HTTP Components Proxy Configuration
proxyconfig.description = Proxy configuration for central and transparent proxying of http client connections.
proxy.enabled.name = Enable HTTP Proxy
proxy.enabled.description = Whether to enable or disable this particular proxy configuration. \
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 \
this proxy configuration is disabled. This property does not have a default value. Enabling \
this proxy but not setting the HTTP Proxy Host effectively disables this configuration.
proxy.port.name = HTTP Proxy Port
proxy.port.description = TCP port of the HTTP Proxy. This property is ignored if \
this proxy configuration is disabled. This property does not have a default value. Enabling \
this proxy but not setting the HTTP Proxy Port effectively disables this configuration.
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 this proxy configuration 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 this proxy configuration is disabled. The default value is [ localhost, \
127.0.0.1 ].

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
====================================================================
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
<http://www.apache.org />.
-->
<metatype:MetaData xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0" localization="metatype">
<OCD id="org.apache.http.proxyconfigurator"
name="%proxyconfig.name"
description="%proxyconfig.description">
<AD id="proxy.enabled"
type="Boolean"
default="false"
name="%proxy.enabled.name"
description="%proxy.enabled.description" />
<AD id="proxy.host"
type="String"
default=""
name="%proxy.host.name"
description="%proxy.host.description" />
<AD id="proxy.port"
type="Integer"
default=""
name="%proxy.port.name"
description="%proxy.port.description" />
<AD id="proxy.user"
type="String"
default=""
name="%proxy.user.name"
description="%proxy.user.description" />
<AD id="proxy.password"
type="String"
default=""
name="%proxy.password.name"
description="%proxy.password.description" />
<AD id="proxy.exceptions"
type="String"
default="localhost,127.0.0.1"
cardinality="2147483647"
name="%proxy.exceptions.name"
description="%proxy.exceptions.description" />
</OCD>
<Designate pid="org.apache.http.proxyconfigurator">
<Object ocdref="org.apache.http.proxyconfigurator" />
</Designate>
</metatype:MetaData>

View File

@ -0,0 +1,129 @@
/*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
package org.apache.http.osgi.impl;
import static org.apache.http.osgi.impl.PropertiesUtils.to;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
/**
* @since 4.3
*/
public final class TestPropertiesUtils {
@Test
public void toBoolean() {
assertConverted(true, null, boolean.class, true);
assertConverted(true, null, Boolean.class, true);
assertConverted(false, "false", boolean.class, null);
assertConverted(false, "false", Boolean.class, null);
// whatever value is interpreted as `false` by Boolean.valueOf
assertConverted(false, "not a boolean", boolean.class, true);
assertConverted(false, "not a boolean", Boolean.class, true);
}
@Test
public void toSingleString() {
assertConverted("fallback to default value", null, String.class, "fallback to default value");
// use an object which represents the string
assertConverted("use the passed value", new StringBuilder("use the passed value"), String.class, null);
// use the "identity" converter
assertConverted("use the passed value", "use the passed value", String.class, null);
// convert another object
assertConverted("456789", 456789, String.class, null);
}
@Test
public void toStringArray() {
assertConvertedArray(new String[]{"fallback to default value"},
null,
String[].class,
new String[]{"fallback to default value"});
// a string is converted to an array with 1 element
assertConvertedArray(new String[]{"a single string"},
"a single string",
String[].class,
null);
// use an object which represents the string
assertConvertedArray(new String[]{"null objects", "will be ignored"},
new Object[]{new StringBuilder("null objects"), null, new StringBuilder("will be ignored")},
String[].class,
null);
// use the "identity" converter
assertConvertedArray(new String[]{"null objects", "will be ignored"},
new Object[]{"null objects", null, "will be ignored"},
String[].class,
null);
assertConvertedArray(new String[]{"fallback to default value"},
456789,
String[].class,
new String[]{"fallback to default value"});
}
@Test
public void toInt() {
assertConverted(123, null, int.class, 123);
assertConverted(123, null, Integer.class, 123);
assertConverted(456, "456", int.class, null);
assertConverted(456, "456", Integer.class, null);
assertConverted(789, "not an integer", int.class, 789);
assertConverted(789, "not an integer", Integer.class, 789);
}
@Test
public void toLong() {
assertConverted(123l, null, long.class, 123l);
assertConverted(123l, null, Long.class, 123l);
assertConverted(456l, "456", long.class, null);
assertConverted(456l, "456", Long.class, null);
assertConverted(789l, "not a long", long.class, 789l);
assertConverted(789l, "not a long", Long.class, 789l);
}
@Test
public void toDouble() {
assertConverted(123d, null, double.class, 123d);
assertConverted(123d, null, Double.class, 123d);
assertConverted(456d, "456", double.class, null);
assertConverted(456d, "456", Double.class, null);
assertConverted(789d, "not a double", double.class, 789d);
assertConverted(789d, "not a double", Double.class, 789d);
}
private static <T> void assertConverted(T expected, Object propValue, Class<T> targetType, T defaultValue) {
T actual = to(propValue, targetType, defaultValue);
assertEquals(expected, actual);
}
private static <T> void assertConvertedArray(T[] expected, Object propValue, Class<T[]> targetType, T[] defaultValue) {
T[] actual = to(propValue, targetType, defaultValue);
assertArrayEquals(expected, actual);
}
}