Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Manoj Mathai committed Oct 28, 2010
0 parents commit d676116
Show file tree
Hide file tree
Showing 26 changed files with 1,045 additions and 0 deletions.
24 changes: 24 additions & 0 deletions README.md
@@ -0,0 +1,24 @@
Recurly Java Client
===================

The Recurly Java Client library is an open source wrapper library to talk to Recurly's subscription management from your Java app/website. The library interacts with Recurly's [REST API](http://support.recurly.com/faqs/api).


Usage
-----

Please refer to the JUnit test cases in [RecurlyTest](http://github.com/gslab/recurly-client-java/blob/master/src/com/kwanzoo/recurly/test/RecurlyTest.java)


Installation
------------

Just add the latest jar(under [dist/](http://github.com/gslab/recurly-client-java/blob/master/dist/recurly-client-java-SNAPSHOT.jar)) to your classpath.


Dependencies
------------

This wrapper relies on the excellent [Jersey REST client API](https://jersey.dev.java.net/)


38 changes: 38 additions & 0 deletions build/build.xml
@@ -0,0 +1,38 @@
<project name="recurly-client-java" default="all" basedir="../">
<path id="build.classpath">
<fileset dir="${basedir}/libs">
<include name="*.jar" />
</fileset>
</path>

<target name="all" depends="build.jar" />

<target name="build.jar" depends="init, clean, compile" >
<jar basedir="${dist.dir}/classes" destfile="${dist.dir}/recurly-client-java-${version}.jar" />
<delete dir="${dist.dir}/classes" includeemptydirs="true" failonerror="false" />
</target>

<target name="init">
<property name="dist.dir" value="${basedir}/dist" />
<property name="src.dir" value="${basedir}/src" />
<property name="version" value="SNAPSHOT" />
</target>

<target name="clean">
<delete includeemptydirs="true" failonerror="false">
<fileset dir="${dist.dir}" includes="**/*" />
</delete>
<mkdir dir="${dist.dir}" />
<mkdir dir="${dist.dir}/classes" />
</target>

<target name="compile">
<javac srcdir="${src.dir}"
destdir="${dist.dir}/classes"
debug="true"
includes="**/*.java"
excludes="com/kwanzoo/recurly/test/**"
classpathref="build.classpath"
verbose="yes" />
</target>
</project>
Binary file added dist/recurly-client-java-SNAPSHOT.jar
Binary file not shown.
Binary file added libs/commons-lang-2.5.jar
Binary file not shown.
Binary file added libs/jersey-client-1.4.jar
Binary file not shown.
Binary file added libs/jersey-core-1.4.jar
Binary file not shown.
Binary file added libs/junit-4.8.2.jar
Binary file not shown.
72 changes: 72 additions & 0 deletions src/com/kwanzoo/recurly/Account.java
@@ -0,0 +1,72 @@
package com.kwanzoo.recurly;

import java.util.Date;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.UniformInterfaceException;

@XmlRootElement(name="account")
public class Account extends Base{
public static String pluralResourceName = "accounts";

//Required
@XmlElement(name="account_code")
public String accountCode;

@XmlElement(name="username")
public String username;

@XmlElement(name="first_name")
public String firstName;

@XmlElement(name="last_name")
public String lastName;

@XmlElement(name="email")
public String email;

@XmlElement(name="company_name")
public String companyName;

@XmlElement(name="balance_in_cents")
public Integer balanceInCents;

@XmlElement(name="created_at")
public Date createdAt;

@XmlElement(name="billing_info")
public BillingInfo billingInfo;

private static String getResourcePath(String accountCode){
return pluralResourceName + "/" + accountCode;
}

public static Account get(final String accountCode) throws Exception{
try{
return getWebResourceBuilder(getResourcePath(accountCode)).get(new GenericType<Account>(){});
}
catch(final UniformInterfaceException uie){
throwStatusBasedException(uie.getResponse());
return null;
}
}

@Override
protected String getResourcePath() {
return getResourcePath(accountCode);
}

@Override
protected String getResourceCreationPath() {
return pluralResourceName;
}

public Account(){}

public Account(final String accountCode){
this.accountCode = accountCode;
}
}
173 changes: 173 additions & 0 deletions src/com/kwanzoo/recurly/Base.java
@@ -0,0 +1,173 @@
package com.kwanzoo.recurly;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.ws.rs.core.MediaType;

import com.kwanzoo.recurly.exception.BadRequestException;
import com.kwanzoo.recurly.exception.ForbiddenAccessException;
import com.kwanzoo.recurly.exception.InternalServerErrorException;
import com.kwanzoo.recurly.exception.PaymentRequiredException;
import com.kwanzoo.recurly.exception.PreconditionFailedException;
import com.kwanzoo.recurly.exception.ResourceNotFoundException;
import com.kwanzoo.recurly.exception.ServiceUnavailableException;
import com.kwanzoo.recurly.exception.UnauthorizedAccessException;
import com.kwanzoo.recurly.exception.UnknownRecurlyException;
import com.kwanzoo.recurly.exception.UnprocessableEntityException;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.client.urlconnection.HTTPSProperties;
import com.sun.jersey.core.util.Base64;

public abstract class Base{
private static final String BaseURI = "https://app.recurly.com";
private static final WebResource webResource;
private static String base64AuthStr = "";
private static final int UNPROCESSABLE_ENTITY_HTTP_CODE = 422;

static{
webResource = getNewWebResource();
}

private static TrustManager[] getTrustManager(){
final X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(final X509Certificate[] arg0, final String arg1) throws CertificateException {
return;
}

@Override
public void checkServerTrusted(final X509Certificate[] arg0, final String arg1) throws CertificateException {
return;
}

@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
return new TrustManager[] {trustManager};
}

private static SSLContext getSSLContext(){
SSLContext context = null;

try {
context = SSLContext.getInstance("SSL");
context.init(null, getTrustManager(), null);
}
catch (final Exception e) {
context = null;
e.printStackTrace();
}
return context;
}

private static HostnameVerifier getHostNameVerifier(){
return new HostnameVerifier() {
@Override
public boolean verify(final String hostname, final SSLSession sslSession) {
return true;
}
};
}

private static WebResource getNewWebResource(){
final ClientConfig config = new DefaultClientConfig();
config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(getHostNameVerifier(), getSSLContext()));
return Client.create(config).resource(BaseURI);
}

public static WebResource.Builder getWebResourceBuilder(final String path){
return webResource.path(path).header("Authorization", base64AuthStr).accept(MediaType.APPLICATION_XML_TYPE);
}

//This method needs to be invoked only once, just before performing the first recurly operation
public static void setAuth(final String recurlyUsername, final String recurlyPassword){
base64AuthStr = new String(Base64.encode(recurlyUsername + ":" + recurlyPassword));
}

//Translates a recurly response to an appropriate recurly exception object.
public static void throwStatusBasedException(final ClientResponse response) throws Exception{
final ClientResponse.Status status = response.getClientResponseStatus();
if(status == null){
final int statusCode = response.getStatus();
if(UNPROCESSABLE_ENTITY_HTTP_CODE == statusCode){
System.out.println(response.getEntity(String.class));
throw new UnprocessableEntityException(response);
}
else{
System.out.println("ClientResponseStatus is null, but found status Code = " + UNPROCESSABLE_ENTITY_HTTP_CODE);
throw new UnknownRecurlyException(response);
}
}
else{
if(status.equals(ClientResponse.Status.BAD_REQUEST)){
throw new BadRequestException(response);
}
else if(status.equals(ClientResponse.Status.UNAUTHORIZED)){
throw new UnauthorizedAccessException(response);
}
else if(status.equals(ClientResponse.Status.PAYMENT_REQUIRED)){
throw new PaymentRequiredException(response);
}
else if(status.equals(ClientResponse.Status.FORBIDDEN)){
throw new ForbiddenAccessException(response);
}
else if(status.equals(ClientResponse.Status.NOT_FOUND)){
throw new ResourceNotFoundException(response);
}
else if(status.equals(ClientResponse.Status.PRECONDITION_FAILED)){
throw new PreconditionFailedException(response);
}
else if(status.equals(ClientResponse.Status.INTERNAL_SERVER_ERROR)){
throw new InternalServerErrorException(response);
}
else if(status.equals(ClientResponse.Status.SERVICE_UNAVAILABLE)){
throw new ServiceUnavailableException(response);
}
}
}

protected abstract String getResourcePath();
protected abstract String getResourceCreationPath();

//default implementations for create, update and delete operation on a resource.
//read operations are static methods within respective resource classes.
public void create() throws Exception{
try{
getWebResourceBuilder(getResourceCreationPath()).post(this);
}
catch(final UniformInterfaceException uie){
throwStatusBasedException(uie.getResponse());
}
}

public void update() throws Exception{
try{
getWebResourceBuilder(getResourcePath()).put(this);
}
catch(final UniformInterfaceException uie){
throwStatusBasedException(uie.getResponse());
}
}

public void delete() throws Exception{
try{
getWebResourceBuilder(getResourcePath()).delete(this);
}
catch(final UniformInterfaceException uie){
throwStatusBasedException(uie.getResponse());
}
}
}

0 comments on commit d676116

Please sign in to comment.