Enterprise Java

J2Pay – Implementing A Gateway

Introduction

We are very excited to welcome contributors, if you have worked on any gateway you can implement that gateway in our library and support the open source world.

You can find our github repository here

Before you begin to implement a gateway there are some other classes you should see first.

Below are the classes defined briefly.

HTTPClient

The main thing when working with gateways you post some data to gateway and parse the response.

To work with http post request this class provides two overloaded static httpPost methods.

  1. public static HTTPResponse httpPost(String url, String postParams, ContentType contentType)
  2. public static HTTPResponse httpPost(String url, String postParams, ContentType contentType, Charset charset)

So you don’t have to worry about handling http requests.

Helpers

While you are working with multiple gateways the main problem developer usually face is some gateways receive xml while some receive JSON or query string since J2pay always returns JSON Response so you do not have to worry about data conversion from between any of these xml, JSON or query string.

Here is the list of helper classes located in com.tranxactive.paymentprocessor.net package.

  1. QueryStringHelper
  2. JSONHelper
  3. StringHelper
  4. XMLHelper

Note: All of the methods defined in helper classes are static.

Responses

To provide generic response j2pay provides five response classes located in com.tranxactive.paymentprocessor.gateways.responses package.

  1. ErrorResponse
  2. PurchaseResponse
  3. RebillResponse
  4. RefundResponse
  5. VoidResponse

As you can identify by their names if you are working with purchase method you will be using PurchaseResponse class if working with rebill method you will be using RebillRespons class and so on

ErrorResponse class is the only class which will be used in all four methods.

One thing you should also know four classes except ErrorResponse considered as success response. So we will be returning them if and only if transaction was successful.

ParamList

ParamList is an enum located in com.tranxactive.paymentprocessor.gateways.parameters package contains the list of variables that must be keep generic in all transactions like if you would like to assign transaction id to variable transactionId there are some chances of typo, but if you will be using paramList enum you are very safe.

Here is how could you use that while assigning transactionId In JSON.

JSONObject json = new JSONObject();
    Json.put(ParamList.TRANSACTION_ID.getName(), "1234567890");

Example

Now you have all the knowledge required to integrate a new gateway. In this example we will be integrating NMI gateway.

While working on this example we assumed you have read the NMI official documentation.

Let’s code.

To integrate NMI gateway we will create a class in com.tranxactive.paymentprocessor.gateways package with the name NMIGateway.

Next we will extends the Gateway class which lead us to implementing all the methods that must be present in a gateway.

Here is how our class will look like.

public class NMIGateway  extends Gateway{

        @Override
        public HTTPResponse purchase(JSONObject apiParameters, Customer customer, CustomerCard customerCard, Currency currency, float amount) { }

        @Override
        public HTTPResponse refund(JSONObject apiParameters, JSONObject refundParameters, float amount) { }

        @Override
        public HTTPResponse rebill(JSONObject apiParameters, JSONObject rebillParameters, float amount) { }

        @Override
        public HTTPResponse voidTransaction(JSONObject apiParameters, JSONObject voidParameters) { }

        @Override
        public JSONObject getApiSampleParameters() { }

        @Override
        public JSONObject getRefundSampleParameters() { }

        @Override
        public JSONObject getRebillSampleParameters() { }

        @Override
        public JSONObject getVoidSampleParameters() { }
    }

Next we will add four below methods at the end of our class. These will be helping us to build the final parameters that need to be posted on the gateway.

private JSONObject buildPurchaseParameters(JSONObject apiParameters, Customer customer, CustomerCard customerCard, Currency currency, float amount){}
    private JSONObject buildVoidParameters(JSONObject apiParameters, JSONObject voidParameters) {}
    private JSONObject buildRefundParameters(JSONObject apiParameters, JSONObject refundParameters, float amount){}
    private JSONObject buildRebillParameters(JSONObject apiParameters, JSONObject rebillParameters, float amount){}

Next we will define apiURL variable globally where all request will be posted.

private final String apiURL = "https://secure.networkmerchants.com/api/transact.php";

Next we will work on four SampleParameters methods.

First and most important is getApiSampleParameters method which is required to perform all transactions.

If you have read the NMI documentation you will see API parameters are username and password.

Here is how getApiSampleParameters method will look like.

@Override
    public JSONObject getApiSampleParameters() {
        return new JSONObject()
            .put("username", "the api user name use demo as the user name for testing")
            .put("password", "the api password use password  as the password for testing");
    }

Below are the three remaining methods after updating.

@Override
    public JSONObject getRefundSampleParameters() {
        return new JSONObject()
                .put(ParamList.TRANSACTION_ID.getName(), "the transaction id which will be refunded");
    }

    @Override
    public JSONObject getRebillSampleParameters() {
        return new JSONObject()
                .put("customerVaultId", "the customer vault id");
    }

    @Override
    public JSONObject getVoidSampleParameters() {
        return new JSONObject()
                .put(ParamList.TRANSACTION_ID.getName(), "the transaction id which will be void");
    }

Next we will be working on four buildparameters methods. Here is how these look like after inserting our code.

private JSONObject buildPurchaseParameters(JSONObject apiParameters, Customer customer, CustomerCard customerCard, Currency currency, float amount) {

        JSONObject object = new JSONObject();
        object
                .put("type", "sale")
                .put("username", apiParameters.getString("username"))
                .put("password", apiParameters.getString("password"))
                .put("ccnumber", customerCard.getNumber())
                .put("ccexp", customerCard.getExpiryMonth() + customerCard.getExpiryYear().substring(2))
                .put("cvv", customerCard.getCvv())
                .put("amount", amount)
                .put("currency", currency)
                .put("first_name", customer.getFirstName())
                .put("last_name", customer.getLastName())
                .put("address1", customer.getAddress())
                .put("city", customer.getCity())
                .put("state", customer.getState())
                .put("zip", customer.getZip())
                .put("country", customer.getCountry().getCodeISO2())
                .put("phone", customer.getPhoneNumber())
                .put("email", customer.getEmail())
                .put("ipaddress", customer.getIp())
                .put("customer_vault", "add_customer");

        return object;

    }

    private JSONObject buildVoidParameters(JSONObject apiParameters, JSONObject voidParameters) {

        JSONObject object = new JSONObject();
        object
                .put("type", "void")
                .put("username", apiParameters.getString("username"))
                .put("password", apiParameters.getString("password"))
                .put("transactionid", voidParameters.getString(ParamList.TRANSACTION_ID.getName()));

        return object;
    }

    private JSONObject buildRefundParameters(JSONObject apiParameters, JSONObject refundParameters, float amount) {

        JSONObject object = new JSONObject();
        object
                .put("type", "refund")
                .put("username", apiParameters.getString("username"))
                .put("password", apiParameters.getString("password"))
                .put("transactionid", refundParameters.getString(ParamList.TRANSACTION_ID.getName()))
                .put("amount", Float.toString(amount));

        return object;
    }

    private JSONObject buildRebillParameters(JSONObject apiParameters, JSONObject rebillParameters, float amount) {

        JSONObject object = new JSONObject();
        object
                .put("username", apiParameters.getString("username"))
                .put("password", apiParameters.getString("password"))
                .put("customer_vault_id", rebillParameters.getString("customerVaultId"))
                .put("amount", Float.toString(amount));

        return object;
    }

Next we will be working on purchase method.

First of all we will build our final parameters that need to be posted on gateway with the help of buildPurchaseParameters method.

JSONObject requestObject = this.buildPurchaseParameters(apiParameters, customer, customerCard, currency, amount);

Next we will define some variables to handle the request don’t worry it’s all depends on how you code.

JSONObject responseObject;
    String requestString;
    String responseString;
    int responseCode;
    requestObject = JSONHelper.encode(requestObject);
    requestString = QueryStringHelper.toQueryString(requestObject);
    HTTPResponse httpResponse;

    PurchaseResponse successResponse = null;
    ErrorResponse errorResponse = new ErrorResponse();

Since NMI requires queryString data to be posted so we are using two helper class.

JSONHelper and QueryStringHelper

First we will urlencode the json returned by buildPurchaseParameters with the help of this code.

requestObject = JSONHelper.encode(requestObject);

Next we converted the encoded json to query string with the help of this code.

requestString = QueryStringHelper.toQueryString(requestObject);

You must be wondering why we initialized errorResponse but set successResponse as null. That all for some programming login to handle the request easily.

Next we will be posting the data to gateway, here is how we will do that.

httpResponse = HTTPClient.httpPost(this.apiURL, requestString, ContentType.APPLICATION_FORM_URLENCODED);

Here are two scenarios that must keep in mind.

  1. Communication with gateway servers was successful.
  2. There was some network issue or gateway server was temporary not available.

Here is how you will handle second scenario.

if (httpResponse.getStatusCode() == -1) {
        return httpResponse;
    }

If the communication with gateway server was successful then our code will not return from this point and continue.

Next we will get the gateway response and parse it to JSON so we can easily work on response.

responseString = httpResponse.getContent();
    responseObject = JSONHelper.decode(QueryStringHelper.toJson(responseString));
    responseCode = responseObject.getInt("response_code");

As you can see we again used the QueryStringHelper and JSONHelper. Wasn’t that easy with the help of helper class.

As we know if gateway response was successful than it must return response code 100. See below code.

if (responseCode == 100) {
        httpResponse.setSuccessful(true);
        successResponse = new PurchaseResponse();
        successResponse.setMessage(responseObject.getString("responsetext"));
        successResponse.setTransactionId(responseObject.get("transactionid").toString());
        successResponse.setCardValuesFrom(customerCard);
        successResponse.setAmount(amount);
        successResponse.setCurrencyCode(currency);

        successResponse.setRebillParams(new JSONObject()
                .put("customerVaultId", responseObject.get("customer_vault_id").toString())
        );

        successResponse.setRefundParams(new JSONObject()
                .put(ParamList.TRANSACTION_ID.getName(), responseObject.get("transactionid").toString())
        );

        successResponse.setVoidParams(new JSONObject()
                .put(ParamList.TRANSACTION_ID.getName(), responseObject.get("transactionid").toString())
        );

    } else {
        errorResponse.setMessage(responseObject.getString("responsetext"));
    }

Let’s understand the above code line by line.

httpResponse.setSuccessful(true);

httpResponse by default set the success to false, so we are only setting it to true in success case as we did above.

successResponse = new PurchaseResponse();

We initialized successResponse variable defined in the beginning of method.

When you take a look at the code of PurchaseResponse class you will see all the parameters that must be set before returning the response.

//this sets the gateway success message.
    successResponse.setMessage(responseObject.getString("responsetext"));
//this sets the gateway returned transaction id.
    successResponse.setTransactionId(responseObject.get("transactionid").toString());
//this is our standard we provide some card detail in purchase response. You will see in final response.
    successResponse.setCardValuesFrom(customerCard);
successResponse.setAmount(amount);
    successResponse.setCurrencyCode(currency);

Next we set the amount and currency that was charged.

Since it’s our responsibility to provide the ready to use parameters required for rebill, refund or void.

Here is how we did this.

successResponse.setRebillParams(new JSONObject()
        .put("customerVaultId", responseObject.get("customer_vault_id").toString())
    );

    successResponse.setRefundParams(new JSONObject()
        .put(ParamList.TRANSACTION_ID.getName(), responseObject.get("transactionid").toString())
    );

    successResponse.setVoidParams(new JSONObject()
        .put(ParamList.TRANSACTION_ID.getName(), responseObject.get("transactionid").toString())
    );

But what if response what not success and we got some error like insufficient fund or avs error.

Here is how we did this in else block.

errorResponse.setMessage(responseObject.getString("responsetext"));

Next we will return the final response that will be HTTPResponse.

if (successResponse != null) {
        successResponse.setGatewayResponse(responseObject);
        httpResponse.setContent(successResponse.getResponse().toString());
    } else {
        errorResponse.setGatewayResponse(responseObject);
        httpResponse.setContent(errorResponse.getResponse().toString());
    }

    return httpResponse;

That’s all we have successfully integrated the NMI purchase method, next three methods will be same except you will be using different Response classes for each of them i.e. you will be using

RebillResponse in rebill method.
RefundResponse in refund method.
VoidResponse in voidTransaction method.
Instead of PurchaseResponse.

It is highly recommended to see source of all the these response class and also sample responses (given here)

To see the complete code of NMI gateway you can see on our github repository.

Published on Java Code Geeks with permission by Muhammad Ilyas, partner at our JCG program. See the original article here: Implementing A Gateway

Opinions expressed by Java Code Geeks contributors are their own.

Muhammad Ilyas

Muhammad is a senior Software Engineer having expertise in famous programming languages like Java, php, c#, perl. He has also worked on mysql and mongodb. He is a co-founder of J2pay.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button