com.klarna.checkout.BasicConnector Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2015 Klarna AB
*
* Licensed 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 com.klarna.checkout;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.conn.BasicClientConnectionManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.json.simple.JSONObject;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.Map;
/**
* Implementation of the connector interface.
*/
public class BasicConnector implements IConnector {
/**
* Default timeout value in milliseconds.
*/
public static final int DEFAULT_TIMEOUT = 10000;
/**
* Digest instance.
*/
protected final Digest digest;
/**
* ClientConnectionManager instance.
*/
private final ClientConnectionManager manager;
/**
* HttpClient implementation.
*/
protected IHttpClient client;
/**
* Connector baseUri.
*/
private String baseUri = IConnector.BASE_URL;
/**
* Constructor.
*
* @param dig Digest instance
*/
public BasicConnector(final Digest dig) {
this(dig, new BasicClientConnectionManager());
}
/**
* Constructor.
*
* @param dig Digest instance
* @param ccm ClientConnectionManager
*/
public BasicConnector(final Digest dig, final ClientConnectionManager ccm) {
if (dig == null) {
throw new IllegalArgumentException("Digest may not be null.");
}
this.digest = dig;
this.manager = ccm;
}
@Override
public String getBaseUri() {
return this.baseUri;
}
@Override
public void setBaseUri(final String base) {
this.baseUri = base;
}
/**
* Create a HTTP Client.
*
* @return HTTP Client to use.
*/
protected IHttpClient createHttpClient() {
final BasicHttpParams params = new BasicHttpParams();
params.setParameter("http.protocol.allow-circular-redirects", false);
HttpConnectionParams.setSoTimeout(params, DEFAULT_TIMEOUT);
return new HttpClientWrapper(this.manager, params);
}
@Override
public void setTimeout(final int milliseconds) {
HttpConnectionParams.setSoTimeout(
this.getClient().getParams(), milliseconds);
}
@Override
public HttpResponse apply(final String method, final IResource resource)
throws IOException {
return apply(method, resource, new ConnectorOptions());
}
@Override
public HttpResponse apply(
final String method,
final IResource resource,
final ConnectorOptions options
) throws IOException {
if (resource == null) {
throw new IllegalArgumentException(
"IResource implementation may not be null.");
}
if (!method.equals("GET") && !method.equals("POST")) {
throw new IllegalArgumentException(
"Unsupported HTTP Method. (" + method + ")");
}
HttpUriRequest req = createRequest(method, resource, options);
HttpContext ctex = new BasicHttpContext();
ctex.setAttribute("klarna_resource", resource);
ctex.setAttribute("klarna_visited", new HashSet());
return getClient().execute(req, new Handler(resource), ctex);
}
/**
* Get a usable URI.
*
* @param options Options for the Connector
* @param resource IResource implementation
* @return URI to use
*/
protected URI getUri(
final ConnectorOptions options, final IResource resource) {
URI uri = null;
if (options != null) {
uri = options.getURI();
}
if (uri == null) {
uri = resource.getLocation();
}
return uri;
}
/**
* Get the data to use.
*
* @param options Options for the Connector
* @param resource IResource implementation
* @return Data to use
*/
protected Map getData(
final ConnectorOptions options, final IResource resource) {
if (options.getData() != null) {
return options.getData();
}
return resource.marshal();
}
/**
* Create a HttpUriRequest object.
*
* @param method HTTP Method
* @param resource IResource implementation
* @param options Options for Connector
* @return the appropriate HttpUriRequest
* @throws UnsupportedEncodingException if the payloads encoding is not
* supported
*/
protected HttpUriRequest createRequest(
final String method,
final IResource resource,
final ConnectorOptions options
) throws UnsupportedEncodingException {
URI uri = this.getUri(options, resource);
HttpUriRequest req;
if (method.equals("GET")) {
req = new HttpGet(uri);
} else {
HttpPost post = new HttpPost(uri);
String payload = JSONObject.toJSONString(
getData(options, resource));
post.setEntity(new ByteArrayEntity(payload.getBytes("UTF-8")));
post.setHeader("Content-Type", resource.getContentType());
req = post;
}
req.setHeader("User-Agent", createUserAgent().toString());
req.setHeader("Accept", resource.getAccept());
return req;
}
/**
* Creates a new UserAgent.
*
* @return User Agent information
*/
protected UserAgent createUserAgent() {
return new UserAgent();
}
/**
* Get a HttpClient object. Reuse existing if possible.
*
* @return A new or the existing HttpClient object.
*/
public IHttpClient getClient() {
if (this.client == null) {
this.client = this.createHttpClient();
this.client.addResponseInterceptor(
new ResourceLocationInterceptor());
this.client.addRequestInterceptor(
new AuthorizationInterceptor(this.digest));
}
return this.client;
}
/**
* An Interceptor to update resource on 201 and 301 statuses.
*/
private static class ResourceLocationInterceptor
implements HttpResponseInterceptor {
/**
* Process a response, update resource if MOVED_PERMANENTLY or CREATED.
*
* @param response A Response from the HTTP request
* @param context Http Context
* @throws HttpException If the response location is invalid
* @throws IOException if an I/O error occurred
*/
public void process(
final HttpResponse response, final HttpContext context)
throws HttpException, IOException {
IResource resource = (IResource) context.getAttribute(
"klarna_resource");
int code = response.getStatusLine().getStatusCode();
if (code != HttpStatus.SC_MOVED_PERMANENTLY
&& code != HttpStatus.SC_CREATED) {
return;
}
try {
Header headerLocation = response.getLastHeader("Location");
if (headerLocation != null) {
URI location = new URI(headerLocation.getValue());
resource.setLocation(location);
}
} catch (URISyntaxException ex) {
throw new ClientProtocolException(ex);
}
}
}
/**
* Intercept HTTP Request and add authorization header.
*/
private static class AuthorizationInterceptor
implements HttpRequestInterceptor {
/**
* Digest object.
*/
private final Digest digest;
/**
* Constructor.
*
* @param dig Digester
*/
public AuthorizationInterceptor(final Digest dig) {
this.digest = dig;
}
/**
* Set the authorization header.
*
* @param request HTTP Request object.
* @param context HTTP Context holder.
* @throws HttpException in case of an HTTP protocol violation
* @throws IOException in case of an I/O error
*/
public void process(
final HttpRequest request, final HttpContext context)
throws HttpException, IOException {
String digestString;
if (request instanceof HttpEntityEnclosingRequest) {
HttpEntityEnclosingRequest her;
her = (HttpEntityEnclosingRequest) request;
digestString = this.digest.create(her.getEntity().getContent());
} else {
digestString = this.digest.create("");
}
request.addHeader("Authorization", "Klarna " + digestString);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy