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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
### Added
- N/A

## 1.2.44 - 2018-08-09
### Added
- Support for fault domains in the Compute service
- Support for configuring a connection pool and an HTTP(S) proxy with the apache connector add-on. More information is available [here](http://github.com/oracle/oci-java-sdk/blob/master/bmc-addons/bmc-apache-connector-provider/README.md)

## 1.2.43 - 2018-07-26
### Added
- Support for the OCI Search service. An example of how to call this service is available [here](https://github.com/oracle/oci-java-sdk/blob/master/bmc-examples/src/main/java/ResourceSearchExample.java)
Expand Down
95 changes: 95 additions & 0 deletions bmc-addons/bmc-apache-connector-provider/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# OCI Java SDK Apache Connector Add-On

## About

The oci-java-sdk-addons-apache is an optional add-on to the OCI Java SDK. It leverages the Jersey `ApacheConnectorProvider` instead of the OCI Java SDK's default `HttpUrlConnectorProvider` when making service calls.

The add-on provides two features:

* **Connection pooling**. A detailed explantation can be found [here](https://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html)
* **HTTP(S) proxy support**.

Note: The `ApacheConnectorProvider` buffers requests into memory and can impact memory utilization of your application. This increased use of memory is especially relavent when using`ObjectStorageClient` to upload large objects to the Object Storage service.

## Installation
1. The OCI Java SDK must be installed and configured before installing the add-on. See [the documentation](https://docs.us-phoenix-1.oraclecloud.com/Content/API/SDKDocs/javasdk.htm) for details.
2. Copy the supplied oci-java-sdk-addons-apache and third-party jar files to your application's classpath.

## Configuration

Create a client with the ```ApacheConfigurator```:

IdentityClient identityClient = IdentityClient.builder()
.region(Region.US_PHOENIX_1)
.clientConfigurator(new ApacheConfigurator())
.build(authenticationDetailsProvider);

### Configure the Connection Pool

Configure the connection pool as follows:

ApacheConnectionPoolConfig poolConfig = ApacheConnectionPoolConfig.builder()
.defaultMaxConnectionsPerRoute(5)
.totalOpenConnections(20)
.ttl(2, TimeUnit.SECONDS)
.build();
ApacheConnectionPoolingClientConfigDecorator poolDecorator =
new ApacheConnectionPoolingClientConfigDecorator(poolConfig);
ApacheConfigurator configurator =
new ApacheConfigurator(Collections.singletonList(poolDecorator));

IdentityClient identityClient = IdentityClient.builder()
.region(Region.US_PHOENIX_1)
.clientConfigurator(configurator)
.build(authenticationDetailsProvider);

Documentation explaining the configuration concepts can be found [here](https://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html).

### Configure the HTTP Proxy

This add-on supports configuring a client to use a HTTP or HTTPS proxy. It is configured configured on a per-client basis, meaning that a proxy must be configured for each new client instance.

Configure an HTTP or HTTPS proxy as follows:

#### Authenticated Proxy

ApacheProxyConfig proxyConfig = ApacheProxyConfig.builder()
.uri("http://proxy.domain.com:8000")
.username("username")
.password("password")
.build();
ClientConfigDecorator proxyConfigDecorator =
new ApacheProxyConfigDecorator(proxyConfig);
ClientConfigurator configurator =
new ApacheConfigurator(Collections.singletonList(proxyConfigDecorator));

IdentityClient identityClient = IdentityClient.builder()
.region(Region.US_PHOENIX_1)
.clientConfigurator(configurator)
.build(authenticationDetailsProvider);

#### Unauthenticated Proxy

ApacheProxyConfig proxyConfig = ApacheProxyConfig.builder()
.uri("https://proxy.domain.com:443")
.build();
ClientConfigDecorator proxyConfigDecorator =
new ApacheProxyConfigDecorator(proxyConfig);
ClientConfigurator configurator =
new ApacheConfigurator(Collections.singletonList(proxyConfigDecorator));

IdentityClient identityClient = IdentityClient.builder()
.region(Region.US_PHOENIX_1)
.clientConfigurator(configurator)
.build(authenticationDetailsProvider);

#### Example
An example of configuring a proxy can be found [here](https://github.com/oracle/oci-java-sdk/tree/master/bmc-examples/src/main/java/HttpProxyExample.java).


## License
Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.

This SDK and sample is dual licensed under the Universal Permissive License 1.0 and the Apache License 2.0.

See [LICENSE](../../LICENSE.txt) for more details.
43 changes: 43 additions & 0 deletions bmc-addons/bmc-apache-connector-provider/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.oracle.oci.sdk</groupId>
<artifactId>oci-java-sdk-addons</artifactId>
<version>1.2.44</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>oci-java-sdk-addons-apache</artifactId>
<name>Oracle Cloud Infrastructure SDK - ApacheHttpConenctorProvider</name>
<description>This project adds support for the ApacheHttpConnectorProvider for the Java SDK</description>
<url>https://docs.us-phoenix-1.oraclecloud.com/Content/API/SDKDocs/javasdk.htm</url>


<dependencies>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>

<dependency>
<groupId>org.glassfish.jersey.connectors</groupId>
<artifactId>jersey-apache-connector</artifactId>
<version>${jersey.version}</version>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>

<dependency>
<groupId>com.oracle.oci.sdk</groupId>
<artifactId>oci-java-sdk-common</artifactId>
<version>1.2.44</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">

<id>release</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>zip</format>
</formats>
<fileSets>
<!-- Include the README.md -->
<fileSet>
<directory>${project.basedir}</directory>
<outputDirectory></outputDirectory>
<includes>
<include>README.md</include>
</includes>
</fileSet>
<!-- Include all of the Javadocs -->
<fileSet>
<directory>${project.build.directory}/apidocs</directory>
<outputDirectory>apidocs</outputDirectory>
</fileSet>
<!-- Include the sources and javadoc jars for developers -->
<fileSet>
<directory>${project.build.directory}</directory>
<includes>
<include>oci-java-sdk-addons-apache-${project.version}-*.jar</include>
</includes>
<outputDirectory>lib</outputDirectory>
</fileSet>
</fileSets>
<files>
<!-- Explicitly copy the signed/unsigned jar and rename it in the release zip file.
If this is for a "signed" release, then the signed jar should be defined; else, the unsigned if the
build profile is "ziponly" -->
<file>
<source>${source.jar.for.zip}</source>
<outputDirectory>lib</outputDirectory>
<destName>oci-java-sdk-addons-apache-${project.version}.jar</destName>
</file>
</files>
<dependencySets>
<!-- 3P dependencies only that's exclusive to this add-on, exclude OCI and its related third-party dependencies -->
<dependencySet>
<includes>
<include>commons-logging:commons-logging</include>
<include>org.glassfish.jersey.connectors:jersey-apache-connector</include>
<include>org.apache.httpcomponents:*</include>
</includes>
<outputDirectory>third-party/lib</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
<useProjectAttachments>false</useProjectAttachments>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
*/
package com.oracle.bmc.http;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.RequestEntityProcessing;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import java.util.LinkedList;
import java.util.List;

/**
* A {@code ClientConfigurator} implementation that uses the Apache HTTP Connector Provider for the Jersey Client
* configuration. This enables support for connection pooling in addition to per-client HTTP(S) proxy support.
*
* Note: Use of the ApacheConnectorProvider will buffer requests into memory and can impact memory utilization within
* your application.
*/
@Slf4j
public class ApacheConfigurator implements ClientConfigurator {
/** The list of {@code ClientConfigDecorator}s to support the ability to decorate {@code ClientConfig} */
protected final List<ClientConfigDecorator> clientConfigDecorators = new LinkedList<>();

/** Creates a new {@code ApacheConfigurator} object. */
public ApacheConfigurator() {}

/**
* Creates a new {@code ApacheConfigurator} and registers the list of provided {@code ClientConfigDecorator}s.
*
* @param clientConfigDecorators the list of client configuration decorators
*/
public ApacheConfigurator(final List<ClientConfigDecorator> clientConfigDecorators) {
this.clientConfigDecorators.addAll(clientConfigDecorators);
}

@Override
public void customizeBuilder(ClientBuilder builder) {
setConnectorProvider(builder);
}

@Override
public void customizeClient(Client client) {
// Use buffered processing to get better error messages on POST and PUT
// but the downside is that this will buffer large uploads in memory.
client.property(
ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.BUFFERED);

// Required for calls to only allow Apache to set the content-length header.
// Otherwise, apache will throw an exception if it already exists. For example, such a case includes
// ObjectStorage where the content-length is explicitly set in the header based on the value in the request.
client.register(new ContentLengthFilter());
}

protected void setConnectorProvider(ClientBuilder builder) {
LOG.info("Setting connector provider to ApacheConnectorProviders");

final ClientConfig clientConfig = new ClientConfig();
clientConfig.connectorProvider(new ApacheConnectorProvider());

// Decorate config with any configured client config decorators
for (ClientConfigDecorator clientConfigDecorator : clientConfigDecorators) {
clientConfigDecorator.customizeClientConfig(clientConfig);
}

builder.withConfig(clientConfig);
}

private static class ContentLengthFilter implements ClientRequestFilter {
@Override
public void filter(ClientRequestContext requestContext) {
String contentLengthHeader = null;
for (String key : requestContext.getHeaders().keySet()) {
if (StringUtils.equalsIgnoreCase("content-length", key)) {
contentLengthHeader = key;
}
}

final String method = requestContext.getMethod();
final String uri = requestContext.getUri().toString();
final Object existingContentLengthValue =
requestContext.getHeaders().remove(contentLengthHeader);
if (existingContentLengthValue != null) {
LOG.debug(
"Removed existing content-length header for Method [{}], URI [{}], Existing Value [{}]",
method,
uri,
existingContentLengthValue);
} else {
LOG.debug("content-length not found for Method [{}], URI [{}]", method, uri);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
*/
package com.oracle.bmc.http;

import lombok.Data;
import org.apache.commons.lang3.tuple.Pair;

import java.util.concurrent.TimeUnit;

/** The configurable parameters for a client's connection pool */
@Data
public class ApacheConnectionPoolConfig {
/**
* Creates a new default {@code ApacheConnectionPoolConfig}.
*
* @return a new default connection pool configuration
*/
public static ApacheConnectionPoolConfig newDefault() {
return ApacheConnectionPoolConfig.builder()
.defaultMaxConnectionsPerRoute(5)
.totalOpenConnections(20)
.build();
}

/** Creates a new {@code Builder} used to construct a new {@code ApacheConnectionPoolConfig} object. **/
public static Builder builder() {
return new Builder();
}

/** The max total number of connections. */
private final int totalOpenConnections;
/** The default max number of connections per route. */
private final int defaultMaxConnectionsPerRoute;
/** The time to live per connection. */
private final Pair<Integer, TimeUnit> ttl;

private ApacheConnectionPoolConfig(final Builder builder) {
totalOpenConnections = builder.totalOpenConnections;
defaultMaxConnectionsPerRoute = builder.defaultMaxConnectionsPerRoute;
ttl = builder.ttl;
}

public final static class Builder {
private int totalOpenConnections;
private int defaultMaxConnectionsPerRoute;
private Pair ttl;

public Builder() {}

public Builder totalOpenConnections(final int totalOpenConnections) {
this.totalOpenConnections = totalOpenConnections;
return this;
}

public Builder defaultMaxConnectionsPerRoute(final int defaultMaxConnectionsPerRoute) {
this.defaultMaxConnectionsPerRoute = defaultMaxConnectionsPerRoute;
return this;
}

public Builder ttlInMillis(final int ttlInMillis) {
this.ttl = Pair.of(ttlInMillis, TimeUnit.MILLISECONDS);
return this;
}

public Builder ttl(final int ttl, final TimeUnit ttlTimeUnit) {
this.ttl = Pair.of(ttl, ttlTimeUnit);
return this;
}

public ApacheConnectionPoolConfig build() {
return new ApacheConnectionPoolConfig(this);
}
}
}
Loading