com.rossjourdain.XeroClientLive.java Source code

Java tutorial

Introduction

Here is the source code for com.rossjourdain.XeroClientLive.java

Source

/*
 *  Copyright 2011 Ross Jourdain
 *
 *  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.rossjourdain;

import com.google.inject.Singleton;

import com.pi.xerosync.dbconnect.XeroCredentials;
import com.pi.xerosync.service.LogBus;
import com.pi.xerosync.xeroservice.XeroClient;
import com.rossjourdain.jaxb.ArrayOfContact;
import com.rossjourdain.jaxb.ArrayOfInvoice;
import com.rossjourdain.jaxb.ArrayOfPayment;
import com.rossjourdain.jaxb.Contact;
import com.rossjourdain.jaxb.CreditNote;
import com.rossjourdain.jaxb.Invoice;
import com.rossjourdain.jaxb.InvoiceType;
import com.rossjourdain.jaxb.Item;
import com.rossjourdain.jaxb.Report;
import com.rossjourdain.jaxb.ResponseType;
import com.rossjourdain.jaxb.TrackingCategory;

import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthException;
import net.oauth.OAuthMessage;
import net.oauth.OAuthProblemException;
import net.oauth.ParameterStyle;
import net.oauth.client.OAuthClient;
import net.oauth.client.OAuthResponseMessage;
import net.oauth.client.httpclient4.HttpClient4;
import net.oauth.signature.RSA_SHA1;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpHost;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;

import ch.qos.logback.classic.Level;

/**
 * @author ross
 */
@Singleton
public class XeroClientLive implements XeroClient {

    private static final Logger log = LoggerFactory.getLogger(XeroClientLive.class);

    @Inject
    private XeroCredentials xeroCredentials;

    private final String endpointUrl = "https://api.xero.com/api.xro/2.0/";

    private OAuthClient clientObj = null;
    private OAuthAccessor accessorObj = null;

    private synchronized OAuthClient getClient() {
        if (clientObj == null) {
            // set -Dpi.proxy=true to use a local proxy
            HttpHost proxy = null;
            String proxyStr = System.getProperty("pi.proxy", "false");
            if ("true".equalsIgnoreCase(proxyStr)) {
                proxy = new HttpHost("127.0.0.1", 8888, "http");
            }

            clientObj = new OAuthClient(new HttpClient4(proxy));
        }
        return clientObj;
    }

    public OAuthAccessor getAccessor() throws IOException {
        if (accessorObj == null) {
            accessorObj = buildAccessor();
        }
        return accessorObj;
    }

    public OAuthAccessor buildAccessor() throws IOException {
        OAuthConsumer consumer = new OAuthConsumer(null, xeroCredentials.getXeroConsumerKey(), null, null);
        consumer.setProperty(RSA_SHA1.PRIVATE_KEY, getPrivateKey());
        consumer.setProperty(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.RSA_SHA1);

        OAuthAccessor accessor = new OAuthAccessor(consumer);
        accessor.accessToken = xeroCredentials.getXeroConsumerKey();
        accessor.tokenSecret = xeroCredentials.getXeroConsumerSecret();

        return accessor;
    }

    private String getPrivateKey() throws IOException {
        String privateKeyPath = xeroCredentials.getPrivateKeyPath();

        File file = new File(privateKeyPath);
        if (!file.exists()) {
            String error = String.format("File doesn't exist: %s", file.getAbsolutePath());
            log.error(error);
            throw new IllegalStateException(error);
        }

        BufferedReader reader = new BufferedReader(new FileReader(file));
        try {
            StringBuilder stringBuilder = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line).append("\n");
            }
            return stringBuilder.toString();
        } finally {
            reader.close();
        }
    }

    public Item getItem(String itemNum) throws XeroClientUnexpectedException, IOException {
        List<Item> items = new ArrayList<>();
        try {
            String url = endpointUrl + "Items/" + itemNum;
            OAuthMessage oResponse = getClient().invoke(getAccessor(), OAuthMessage.GET, url, null);
            ResponseType response = XeroXmlManager.xmlToResponse(oResponse.getBodyAsStream());
            items.addAll(response.getItems().getItem());
            log.debug("Response id {}", response.getId());
            if (items.size() > 1) {
                throw new XeroClientUnexpectedException("More than one item found for itemcode " + itemNum);
            }
            return items.get(0);
        } catch (OAuthProblemException ex) {
            if (ex.getHttpStatusCode() == 404) {
                return null;
            } else {
                throw new XeroClientUnexpectedException(ex.getMessage(), ex);
            }
        } catch (OAuthException | URISyntaxException e) {
            throw new XeroClientUnexpectedException(e.getMessage(), e);
        }
    }

    public String getTrackingCategoryOutput() throws XeroClientException, XeroClientUnexpectedException {
        try {
            String url = endpointUrl + "TrackingCategories";
            OAuthMessage oResponse = getClient().invoke(getAccessor(), OAuthMessage.GET, url, null);
            final InputStream stream = oResponse.getBodyAsStream();
            StringWriter strWriter = new StringWriter();
            IOUtils.copy(stream, strWriter, "UTF-8");
            final String output = strWriter.toString();
            strWriter.close();
            return output;
        } catch (OAuthProblemException ex) {
            if (ex.getHttpStatusCode() == 404) {
                log.debug("Server responded with 'not found' for contact search");
                return null;
            } else {
                log.error(ex.getMessage(), ex);
                throw new XeroClientException("Error getting contacts", ex);
            }
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw new XeroClientUnexpectedException(ex.getMessage(), ex);
        }
    }

    public List<TrackingCategory> getTrackingCategories()
            throws XeroClientException, XeroClientUnexpectedException {
        List<TrackingCategory> contact = new ArrayList<>();
        try {
            String url = endpointUrl + "TrackingCategories";
            OAuthMessage oResponse = getClient().invoke(getAccessor(), OAuthMessage.GET, url, null);
            ResponseType response = XeroXmlManager.xmlToResponse(oResponse.getBodyAsStream());
            contact.addAll(response.getTrackingCategories().getTrackingCategory());
            log.debug("Response id {}", response.getId());
        } catch (OAuthProblemException ex) {
            if (ex.getHttpStatusCode() == 404) {
                log.debug("Server responded with 'not found' for tracking search");
                return contact;
            } else {
                log.error(ex.getMessage(), ex);
                throw new XeroClientException("Error getting tracking categories", ex);
            }
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw new XeroClientUnexpectedException(ex.getMessage(), ex);
        }
        return contact;
    }

    public List<Contact> getContacts(String customerNumber)
            throws XeroClientException, XeroClientUnexpectedException {
        List<Contact> contact = new ArrayList<>();
        try {
            String url = endpointUrl + "Contacts/" + customerNumber;
            OAuthMessage oResponse = getClient().invoke(getAccessor(), OAuthMessage.GET, url, null);
            ResponseType response = XeroXmlManager.xmlToResponse(oResponse.getBodyAsStream());
            contact.addAll(response.getContacts().getContact());
            log.debug("Response id {}", response.getId());
        } catch (OAuthProblemException ex) {
            if (ex.getHttpStatusCode() == 404) {
                log.debug("Server responded with 'not found' for contact search");
                return contact;
            } else {
                log.error(ex.getMessage(), ex);
                throw new XeroClientException("Error getting contacts", ex);
            }
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw new XeroClientUnexpectedException(ex.getMessage(), ex);
        }
        return contact;
    }

    public List<Invoice> getInvoices(String invoiceNumber)
            throws XeroClientException, XeroClientUnexpectedException {
        List<Invoice> arrayOfInvoices = new ArrayList<>();
        try {
            OAuthMessage response = getClient().invoke(getAccessor(), OAuthMessage.GET,
                    endpointUrl + "Invoices/" + invoiceNumber, null);
            arrayOfInvoices.addAll(XeroXmlManager.xmlToInvoices(response.getBodyAsStream()).getInvoice());
        } catch (OAuthProblemException ex) {
            if (ex.getHttpStatusCode() == 404) {
                return arrayOfInvoices;
            } else {
                throw new XeroClientException("Error getting invoice", ex);
            }
        } catch (Exception ex) {
            throw new XeroClientUnexpectedException(ex.getMessage(), ex);
        }
        return arrayOfInvoices;
    }

    @Override
    public boolean doesSalesInvoiceNumberExistInXero(String invoiceNumber)
            throws XeroClientException, XeroClientUnexpectedException {
        List<Invoice> invoiceListArray = getInvoices(invoiceNumber);
        boolean foundInvoice = false;
        if (invoiceListArray != null) {
            for (Invoice invoice : invoiceListArray) {
                if (invoice.getType() == InvoiceType.ACCREC) {
                    log.info("Found existing ACCREC sales invoice in xero");
                    foundInvoice = true;
                }
            }
        }
        return foundInvoice;
    }

    public ArrayOfInvoice getInvoices() throws XeroClientException, XeroClientUnexpectedException {
        ArrayOfInvoice arrayOfInvoices;
        try {
            OAuthMessage response = getClient().invoke(getAccessor(), OAuthMessage.GET, endpointUrl + "Invoices",
                    null);
            arrayOfInvoices = XeroXmlManager.xmlToInvoices(response.getBodyAsStream());
        } catch (OAuthProblemException ex) {
            throw new XeroClientException("Error getting invoices", ex);
        } catch (Exception ex) {
            throw new XeroClientUnexpectedException(ex.getMessage(), ex);
        }
        return arrayOfInvoices;
    }

    public Report getReport(String reportUrl) throws XeroClientException, XeroClientUnexpectedException {
        Report report = null;
        try {
            OAuthMessage response = getClient().invoke(getAccessor(), OAuthMessage.GET,
                    endpointUrl + "Reports" + reportUrl, null);
            ResponseType responseType = XeroXmlManager.xmlToResponse(response.getBodyAsStream());
            if (responseType != null && responseType.getReports() != null
                    && responseType.getReports().getReport() != null
                    && responseType.getReports().getReport().size() > 0) {
                report = responseType.getReports().getReport().get(0);
            }
        } catch (OAuthProblemException ex) {
            throw new XeroClientException("Error getting invoices", ex);
        } catch (Exception ex) {
            throw new XeroClientUnexpectedException(ex.getMessage(), ex);
        }
        return report;
    }

    public OAuthMessage postContacts(ArrayOfContact arrayOfContact)
            throws XeroClientException, XeroClientUnexpectedException {
        try {
            String contactsString = XeroXmlManager.contactsToXml(arrayOfContact);
            return getClient().invoke(getAccessor(), OAuthMessage.POST, endpointUrl + "Contacts",
                    OAuth.newList("xml", contactsString));
        } catch (OAuthProblemException ex) {
            throw new XeroClientException("Error posting contacts", ex);
        } catch (Exception ex) {
            throw new XeroClientUnexpectedException(ex.getMessage(), ex);
        }
    }

    @Override
    public OAuthMessage postCreditNote(CreditNote creditNote, @Nullable LogBus logBus)
            throws XeroClientException, XeroClientUnexpectedException {
        try {
            String creditNoteStr = XeroXmlManager.creditNoteToXml(creditNote);
            return getClient().invoke(getAccessor(), OAuthMessage.POST, endpointUrl + "CreditNotes",
                    OAuth.newList("xml", creditNoteStr));
        } catch (OAuthProblemException ex) {
            log.error(ex.toString(), ex);
            if (logBus != null) {
                logBus.log(Level.ERROR, ex.toString());
            }
            throw new XeroClientException("Error posting credit note", ex);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            if (logBus != null) {
                logBus.log(Level.ERROR, ex.toString());
            }
            throw new XeroClientUnexpectedException(ex.getMessage(), ex);
        }
    }

    public OAuthMessage postInvoices(ArrayOfInvoice arrayOfInvoices, @Nullable LogBus logBus)
            throws XeroClientException, XeroClientUnexpectedException {
        try {
            String invString = XeroXmlManager.invoicesToXml(arrayOfInvoices);
            return getClient().invoke(getAccessor(), OAuthMessage.POST, endpointUrl + "Invoices",
                    OAuth.newList("xml", invString));
        } catch (OAuthProblemException ex) {
            log.error(ex.toString(), ex);
            if (logBus != null) {
                logBus.log(Level.ERROR, ex.toString());
            }
            throw new XeroClientException("Error posting invoices", ex);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            if (logBus != null) {
                logBus.log(Level.ERROR, ex.toString());
            }
            throw new XeroClientUnexpectedException(ex.getMessage(), ex);
        }
    }

    public OAuthMessage postPayments(ArrayOfPayment arrayOfPayment)
            throws XeroClientException, XeroClientUnexpectedException {
        try {
            String paymentsString = XeroXmlManager.paymentsToXml(arrayOfPayment);
            return getClient().invoke(getAccessor(), OAuthMessage.POST, endpointUrl + "Payments",
                    OAuth.newList("xml", paymentsString));
        } catch (OAuthProblemException ex) {
            throw new XeroClientException("Error posting payments", ex);
        } catch (Exception ex) {
            throw new XeroClientUnexpectedException(ex.getMessage(), ex);
        }
    }

    public File getInvoiceAsPdf(String invoiceId) throws XeroClientException, XeroClientUnexpectedException {

        File file = null;
        InputStream in = null;
        FileOutputStream out = null;

        try {
            OAuthMessage request = getAccessor().newRequestMessage(OAuthMessage.GET,
                    endpointUrl + "Invoices" + "/" + invoiceId, null);
            request.getHeaders().add(new OAuth.Parameter("Accept", "application/pdf"));
            OAuthResponseMessage response = getClient().access(request, ParameterStyle.BODY);

            file = new File("Invoice-" + invoiceId + ".pdf");

            if (response != null && response.getHttpResponse() != null
                    && (response.getHttpResponse().getStatusCode() / 2) != 2) {
                in = response.getBodyAsStream();
                out = new FileOutputStream(file);

                byte[] buffer = new byte[1024];
                int bytesRead = 0;
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
            } else {
                throw response.toOAuthProblemException();
            }

        } catch (OAuthProblemException ex) {
            throw new XeroClientException("Error getting PDF of invoice " + invoiceId, ex);
        } catch (Exception ex) {
            throw new XeroClientUnexpectedException(ex.getMessage(), ex);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
            }
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                }
            } catch (IOException ex) {
            }
        }
        return file;
    }

}