Skip to content

Commit

Permalink
Merge pull request #1 from SidneyAllen/marshalling
Browse files Browse the repository at this point in the history
Add Support for Marshaling & Un-Marshaling XML
  • Loading branch information
SidneyAllen committed Oct 28, 2016
2 parents 8f3e0c7 + 20f3f46 commit 56926d0
Show file tree
Hide file tree
Showing 173 changed files with 34,923 additions and 141 deletions.
129 changes: 103 additions & 26 deletions README.md
@@ -1,42 +1,92 @@
# Xero-Java
A skinny Java wrapper of the Xero API. Supports Accounting API. All third party libraries dependencies managed with Maven
This is the official Java SDK for the Xero API. Currently, supports Accounting API. All third party libraries dependencies managed with Maven

### Xero App
You'll need to decide which type of Xero app you'll be building (Public, Private or Partner). Go to http://app.xero.com to login and create your app.
You'll need to decide which type of Xero app you'll be building (Public, Private or Partner). Go to [http://app.xero.com](http://app.xero.com) and login with your Xero user account and create an app.

### config.json
Located in src/main/resources is the config.json file. There are examples for public, private and partner - but the Config.java will look in this folder at the config.json file in order to initialize you Java code.
Located in src/main/resources is the config.json file. There are examples for public, private and partner - but the Config.java will look in this folder at the config.json file in order to initialize your Java code.

Below are the unique values you'll set in config.json for each type of Xero app.
Here is an example of config.json for a Partner App.

**Public Xero App**
```javascript
{
"AppType" : "PARTNER",
"UserAgent" : "Xero-Java",
"Accept" : "application/xml",
"SignatureMethod" : "RSA-SHA1",
"ConsumerKey" : "Z7DLBXSOMSQI9GMUHZB8RY6ZXHTTYC",
"ConsumerSecret" : "71K7QL8TKH7CKDVE6TLY02CTQOX36S",
"ApiBaseUrl" : "https://api-partner.network.xero.com",
"ApiEndpointPath" : "/api.xro/2.0/",
"RequestTokenPath": "/oauth/RequestToken",
"AuthenticateUrl" : "https://api.xero.com/oauth/Authorize",
"AccessTokenPath" : "/oauth/AccessToken",
"CallbackBaseUrl" : "https://tranquil-falls-53784.herokuapp.com",
"CallbackPath" : "/CallbackServlet",
"PrivateKeyCert" : "certs/public_privatekey.pfx",
"PrivateKeyPassword" : "1234",
"EntrustCert" : "certs/xero-entrust-20170513.p12",
"EntrustCertPassword" : "123456"
}
```

* Copy and paste, Consumer Key & Secret from app.xero.com
* Set your callback url at app.xero.com to match CallbackBaseUrl
* Set your CallbackPath - this is appended to the CallbackBaseUrl
Below are the possible attributes for each App Type.

| App Type | Attribute | Purpose | Valid Options
| --------------------- | --------------------- |---------------------------------------| -------------
| ALL | AppType | Defines your app type | PUBLIC or PRIVATE or PARTNER
| ALL | UserAgent | for debugging by Xero API ssues | unique string
| ALL | Accept | format of data returned from API | application/xml or application/json
| ALL | ConsumerKey | for oAuth Signature | App Key created at app.xero.com
| ALL | ConsumerSecret | for oAuth Signature | App Secret created at app.xero.com
| ALL | ApiBaseUrl | base URL for API calls | https://api.xero.com or https://api-partner.network.xero.com
| ALL | ApiEndpointPath | path for API Calls | /api.xro/2.0/
| Public or Partner | RequestTokenPath | path for Request Token | /oauth/RequestToken
| Public or Partner | AuthenticateUrl | path for redirect to authorize | /oauth/RequestToken
| Public or Partner | AccessTokenPath | path for Access Token | https://api.xero.com/oauth/Authorize
| Public or Partner | CallbackBaseUrl | base URL for Callback url | unique string
| Public or Partner | CallbackPath | path for Callback url | unique string
| Private or Partner | PrivateKeyCert | path to [Private Key Certificate](https://developer.xero.com/documentation/advanced-docs/public-private-keypair/) | unique string
| Private or Partner | PrivateKeyPassword | password for Private key | unique string
| Partner | EntrustCert | path to [Entrust Certificate](https://developer.xero.com/documentation/getting-started/partner-applications/#certificates) | unique string
| Partner | EntrustCertPassword | password for Entrust certificate | unique string

**Private Xero App**

* Copy and paste, Consumer Key & Secret from app.xero.com
* Upload the public.cer file at app.xero.com
* Copy the public_privatekey.pfx file created with OpenSSL in the certs folder
[Public Private Key Docs](https://developer.xero.com/documentation/advanced-docs/public-private-keypair/)
* Set the private key password
### Xero Model
We've included a complete set of classes in `com.xero.model`. These are generated from the [Xero Schema XSDs](https://github.com/XeroAPI/XeroAPI-Schemas). You can always download and generate updated classes in the future to replace the ones included in this project.

### Xero Client
We've included the XeroClient with methods to perform each action supported by endpoints. Once you instantiate XeroClient, you can begin using classes from the model directory to create, read, update and delete data through Xero's API.

**Partner Xero App**
```java
XeroClient client = new XeroClient(request, response);

/* CREATE ACCOUNT */
ArrayOfAccount accountArray = new ArrayOfAccount();
Account account = new Account();
account.setCode("66000");
account.setName("Office Expense");
account.setType(AccountType.EXPENSE);
accountArray.getAccount().add(account);
List<Account> newAccount = client.createAccounts(accountArray);

/* READ ACCOUNT using a WHERE clause */
List<Account> accountWhere = client.getAccounts(null,"Type==\"BANK\"",null);

* Copy and paste, Consumer Key & Secret from app.xero.com
* Set your callback url at app.xero.com to match CallbackBaseUrl
* Set your CallbackPath - this is appended to the CallbackBaseUrl
* Upload the public.cer file at app.xero.com
* Copy the public_privatekey.pfx file created with OpenSSL in the certs folder
[Public Private Key Docs](https://developer.xero.com/documentation/advanced-docs/public-private-keypair/)
* Set the Private key password
* Copy the xero-entrus.p12 file set to you by Xero API team.
[Entrust Certificates Docs](https://developer.xero.com/documentation/getting-started/partner-applications/#certificates)
* Set the Entrust Certifcate password
/* READ ACCOUNT using the ID */
List<Account> accountList = client.getAccounts();
Account accountOne = client.getAccount(accountList.get(0).getAccountID());

/* UPDATE ACCOUNT */
newAccount.get(0).setName("Entertainment");
newAccount.get(0).setStatus(null);
List<Account> updateAccount = client.updateAccount(newAccount);

/* DELETE ACCOUNT */
String status = client.deleteAccount(newAccount.get(0).getAccountID());

```

### Maven Dependencies

Expand All @@ -53,4 +103,31 @@ The pom.xml file contains two library dependencies.
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
```
```

##License

This software is published under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).

Copyright (c) 2016 Xero Limited

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
24 changes: 23 additions & 1 deletion pom.xml
Expand Up @@ -5,7 +5,7 @@
<artifactId>Xero-Java-Example</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>Xero-Java-Example Maven Webapp</name>
<name>Xero-Java Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
Expand All @@ -30,4 +30,26 @@
<version>1.1.1</version>
</dependency>
</dependencies>
<build>
<finalName>Xero-Java-SDK</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>com.heroku.sdk</groupId>
<artifactId>heroku-maven-plugin</artifactId>
<version>1.0.3</version>
<configuration>
<appName>tranquil-falls-53784</appName>
</configuration>
</plugin>
</plugins>
</build>
</project>
31 changes: 20 additions & 11 deletions src/main/java/com/xero/api/OAuthAccessToken.java
Expand Up @@ -5,8 +5,6 @@
import java.util.Map;
import java.util.Objects;

//import com.google.api.client.auth.oauth.OAuthParameters;

import com.xero.api.OAuthParameters;

import com.google.api.client.auth.oauth.OAuthSigner;
Expand Down Expand Up @@ -96,10 +94,11 @@ public OAuthAccessToken build() throws IOException
return this;
}

public void execute() throws IOException
public boolean execute() throws IOException
{
try {
HttpResponse response = request.execute();

isSuccess = response.isSuccessStatusCode();

if (isSuccess)
Expand All @@ -110,17 +109,22 @@ public void execute() throws IOException
this.tokenSecret = oauthKeys.get("oauth_token_secret");
this.sessionHandle = oauthKeys.get("oauth_session_handle");
this.tokenTimestamp = System.currentTimeMillis() / 1000l;
isSuccess = true;
}
else
{

}
} catch (HttpResponseException e) {
System.out.println("HttpException" + e.toString());
System.out.println("REFRESH EXECPTION");

Map<String, String> oauthError = getQueryMap(e.getMessage());
this.problem = oauthError.get("oauth_problem");
this.advice = oauthError.get("oauth_problem_advice");
//System.out.println("HttpException" + e.toString());
isSuccess = false;
}
return isSuccess;
}

public void setToken(String token)
Expand Down Expand Up @@ -239,14 +243,19 @@ public boolean isStale(String timestamp)
{
boolean bool = false;

long currentTime = System.currentTimeMillis() / 1000l;

long tokenTimestamp = Long.parseLong(timestamp);
long secondsElapsed = (currentTime - tokenTimestamp);
if (timestamp == null || timestamp.isEmpty()) {
bool = false;
} else {

if (secondsElapsed >= 1800)
{
bool = true;
long currentTime = System.currentTimeMillis() / 1000l;

long tokenTimestamp = Long.parseLong(timestamp);
long secondsElapsed = (currentTime - tokenTimestamp);

if (secondsElapsed >= 1800)
{
bool = true;
}
}

return bool;
Expand Down
49 changes: 36 additions & 13 deletions src/main/java/com/xero/api/OAuthRequestResource.java
Expand Up @@ -19,7 +19,6 @@
import com.google.api.client.http.ByteArrayContent;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpContent;
import com.google.api.client.http.HttpMethods;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
Expand All @@ -29,6 +28,9 @@
import com.google.api.client.util.Beta;

import java.io.IOException;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Map;

/**
* Generic OAuth 1.0a URL to request API resource from server.
Expand Down Expand Up @@ -72,6 +74,7 @@ public class OAuthRequestResource extends GenericUrl {
public String accept = "application/json";
private String body = null;
private HttpContent requestBody = null;
private String httpMethod = "GET";

private Config c = Config.getInstance();

Expand All @@ -81,14 +84,20 @@ public class OAuthRequestResource extends GenericUrl {
/**
* @param authorizationServerUrl encoded authorization server URL
*/
public OAuthRequestResource(String resource, String method, String body) {
public OAuthRequestResource(String resource, String method, String body, Map<? extends String, ?> params) {
Url = new GenericUrl(c.getApiUrl() + resource);
if(method.equals("POST")){
this.httpMethod = method;
if(method.equals("POST") || method.equals("PUT")){
usePost = true;
}
}

if (params != null) {
Url.putAll(params);
}

this.body = body;
}

/**
* Executes the HTTP request for a temporary or long-lived token.
*
Expand All @@ -106,23 +115,32 @@ public final HttpResponse execute() throws IOException {
}

HttpRequestFactory requestFactory = transport.createRequestFactory();
HttpRequest request = requestFactory.buildRequest(usePost ? HttpMethods.POST : HttpMethods.GET, Url, requestBody);

HttpRequest request = requestFactory.buildRequest(this.httpMethod, Url, requestBody);
HttpHeaders headers = new HttpHeaders();
headers.setUserAgent(c.getUserAgent());
headers.setAccept(c.getAccept());
headers.setContentType("application/xml");
//headers.setIfModifiedSince(ifModifiedSince);
if(ifModifiedSince != null) {
System.out.println("Set Header " + this.ifModifiedSince);
headers.setIfModifiedSince(this.ifModifiedSince);

}
request.setHeaders(headers);

createParameters().intercept(request);

HttpResponse response = request.execute();
HttpResponse response;

response = request.execute();
response.setContentLoggingLimit(0);

return response;

}


public void setMethod(String method) {
this.httpMethod = method;
}

public void setToken(String token) {
this.token = token;
if(c.getAppType().equals("PRIVATE")) {
Expand All @@ -132,7 +150,12 @@ public void setToken(String token) {
public void setTokenSecret(String secret) {
this.tokenSecret = secret;
}


public void setIfModifiedSince(Date modifiedAfter) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
this.ifModifiedSince = formatter.format(modifiedAfter);
}

public OAuthParameters createParameters()
{

Expand Down
23 changes: 23 additions & 0 deletions src/main/java/com/xero/api/XeroApiException.java
@@ -0,0 +1,23 @@
package com.xero.api;

public class XeroApiException extends RuntimeException {

private static final long serialVersionUID = 1L;

private final int responseCode;

public XeroApiException(int responseCode) {
super(responseCode + " response.");
this.responseCode = responseCode;
}

public XeroApiException(int responseCode, String message) {
super(responseCode + " response: " + message);
this.responseCode = responseCode;
}

public int getResponseCode() {
return responseCode;
}

}

0 comments on commit 56926d0

Please sign in to comment.