Voucher:Example
From Akorena Wiki
Contents |
Bridges
You can write your own bridge, to extend system connectivity to external entities. As long as your own bridge can talk XML-RPC on other side (or HTTP, using dual stage bridges) the possibility is endless.
Single stage bridge
Dual stage bridge
As plain HTTP GET request much more simpler than XML-RPC, we provide http-xmlrpc-bridge that will convert HTTP request into XML-RPC request.
Source Codes
Java XML-RPC client
import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.xmlrpc.client.TimingOutCallback; import org.apache.xmlrpc.client.XmlRpcClient; import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; import org.apache.xmlrpc.client.TimingOutCallback.TimeoutException; import com.Ostermiller.util.CmdLn; import com.Ostermiller.util.CmdLnOption; import com.Ostermiller.util.CmdLnResult; /** * Spectra Voucher TopUp Software * XML-RPC command line client * @author Ernas Moethar */ public class XmlRpcClientTest { static String server = "http://127.0.0.1:8090"; static String msisdn = ""; static String account = ""; static String pin = ""; static String productCode = ""; private enum EnumOptions { HELP(new CmdLnOption("help", 'h')), SERVER(new CmdLnOption("server", 's').setRequiredArgument().setDescription("Server endpoint, default to http://127.0.0.1:8090")), MSIS DN(new CmdLnOption("msisdn", 'm').setRequiredArgument().setDescription("MSISDN number")), ACCOUNT( new CmdLnOption("account", 'a').setRequiredArgument() .setDescription("Account number")), PIN( new CmdLnOption("password", 'p').setRequiredArgument() .setDescription("PIN")), PRODUCTCODE(new CmdLnOption( "code", 'c').setRequiredArgument().setDescription( "Product Code")); private CmdLnOption option; private EnumOptions(CmdLnOption option) { option.setUserObject(this); this.option = option; } private CmdLnOption getCmdLineOption() { return option; } } public static void main(String[] args) throws Exception { CmdLn cmdLn = new CmdLn(args) .setDescription("Spectra CommandLine TopUp"); for (EnumOptions option : EnumOptions.values()) { cmdLn.addOption(option.getCmdLineOption()); } for (CmdLnResult result : cmdLn.getResults()) { switch ((EnumOptions) result.getOption().getUserObject()) { case HELP: { cmdLn.printHelp(); System.exit(0); } break; case MSISDN: { msisdn = result.getArgument(); } break; case SERVER: { server = result.getArgument(); } break; case ACCOUNT: { account = result.getArgument(); } break; case PIN: { pin = result.getArgument(); } break; case PRODUCTCODE: { productCode = result.getArgument(); } break; } } // Disabling Certificate Validation in an HTTPS Connection // http://exampledepot.com/egs/javax.net.ssl/TrustAll.html // Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) { } public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) { } } }; // Install the all-trusting trust manager try { SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { System.out.println(e.getMessage()); return; } // install the no-verifier HostnameVerifier hv = new HostnameVerifier() { public boolean verify(String urlHostName, SSLSession session) { return true; } }; HttpsURLConnection.setDefaultHostnameVerifier(hv); XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); config.setServerURL(new URL(server)); XmlRpcClient client = new XmlRpcClient(); client.setConfig(config); Map<String, Object> data = new HashMap<String, Object>(); data = new HashMap<String, Object>(); data.put("Method", "topup"); data.put("Pin", pin); data.put("Username", account); data.put("MSISDN", msisdn); data.put("ProductCode", productCode); data.put("ReferenceId", code); params.add(data); System.out.println(params.toString()); result = null; TimingOutCallback callback = new TimingOutCallback(60 * 1000); client.executeAsync("samba.invoke", params, callback); try { result = (Map<String, Object>) callback.waitForResponse(); } catch (TimeoutException e) { System.out.println(e.getMessage()); } catch (Exception e) { System.out.println(e.getMessage()); } catch (Throwable e) { System.out.println(e.getMessage()); } if (result != null) { System.out.println(result.toString()); } } }
PHP XML-RPC client
/* * Copyright Akorena.com * Licensed under the BSD License * * 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. */ // get these file from http://phpxmlrpc.sourceforge.net/ require_once("xmlrpc.inc"); $result = topup("1234", "secret", "08888322366", "R5", "2345sd9wdf"); print_r($result); function topup ($username, $passwd, $msisdn, $product, $referencecode) { $url = "http://127.0.0.1:8090/"; // array to store results $retval = array(); $f=new xmlrpcmsg('samba.invoke'); $r = array( "Username" => new xmlrpcval($username), "Method" => new xmlrpcval("TOPUP"), "MSISDN" => new xmlrpcval($msisdn), "ProductCode" => new xmlrpcval($product), "ReferenceId" => new xmlrpcval($referencecode), ); $v = new xmlrpcval( $r, "struct"); $f->addParam($v); $c=new xmlrpc_client($url); $c->setSSLVerifyHost(0); $c->setSSLVerifyPeer(0); $c->setDebug(0); $r=&$c->send($f, 180, "http"); if(!$r->faultCode()) { $v=$r->value(); $v->structreset(); while (list($key, $val) = $v->structeach()) { $retval[$key] = htmlentities($val->scalarval()); } } else { // bad thing happened print "An error occurred: "; print "Code: " . htmlspecialchars($r->faultCode()) . " Reason: '" . htmlspecialchars($r->faultString()) . "\n"; return; } return $retval; }
Perl XML-RPC client
#!/usr/bin/perl -w # # * Spectra Voucher TopUp Software # * XML-RPC command line client # * @author Ernas Moethar # use RPC::XML; use RPC::XML::Client; use String::Random qw(random_string); use Data::Dumper; use Digest::MD5 qw(md5_hex); use strict; my $cli = RPC::XML::Client->new('http://127.0.0.1:8090/'); $cli->combined_handler(sub { my $fault = shift; print $fault->code, " ", $fault->string, "\n"; }); my %struct = ( 'Username' => 'OWNER', 'MSISDN' => '0888888888', 'ProductCode' => 'R5', 'ReferenceId' => random_string("CcnCCcccnn"), 'Method' => 'TOPUP', ); $req = RPC::XML::request->new('samba.invoke', RPC::XML::struct->new(\%struct)); # print $req->as_string(); $resp = $cli->send_request($req); die "Fault occured when calling topup" if($resp->is_fault); print Data::Dumper->Dump([\%struct, $resp->value], [qw(request response)]);
Gateways
Spectra Topup Software use Apache ActiveMQ to pass messages internally. To be able to pickup top up request, gateway must be capable to talk to ActiveMQ. Check ActiveMQ Language Clients for full list of supported client languages.
Below is a dummy gateway written in Java, that pick message from queue which match with it serviceTag and flag those message as SUCCESS.
TopupMessage.java
package com.akorena.app.vms.model; import java.io.Serializable; import java.util.Date; public class TopupMessage implements Serializable { /** * */ private static final long serialVersionUID = 1L; private Long account; private Long gateway; private Long provider; private Long voucher; private String transactionCode; private Float marketPrice; private String msisdn; private Float nettPrice; private String providerMessage; private String accountMessage; private String providerTransactionCode; private String accountTransactionCode; private Date requestTime; private String md5signature; private String responseCode; private EnumVoucherTransactionStatus status; private String mappedProductCode; private String providerResponseCode; private String gatewayUri; private String gatewayUsername; private String gatewayPassword; private String gatewaySecurityKey; private Short gatewayTimeout; public TopupMessage() { } public Long getAccount() { return this.account; } public void setAccount(Long account) { this.account = account; } public Long getGateway() { return this.gateway; } public void setGateway(Long gateway) { this.gateway = gateway; } public Long getProvider() { return this.provider; } public void setProvider(Long provider) { this.provider = provider; } public Long getVoucher() { return this.voucher; } public void setVoucher(Long voucher) { this.voucher = voucher; } public String getTransactionCode() { return this.transactionCode; } public void setTransactionCode(String transactionCode) { this.transactionCode = transactionCode; } public Float getMarketPrice() { return this.marketPrice; } public void setMarketPrice(Float marketPrice) { this.marketPrice = marketPrice; } public String getMsisdn() { return this.msisdn; } public void setMsisdn(String msisdn) { this.msisdn = msisdn; } public Float getNettPrice() { return this.nettPrice; } public void setNettPrice(Float nettPrice) { this.nettPrice = nettPrice; } public String getProviderMessage() { return this.providerMessage; } public void setProviderMessage(String providerMessage) { this.providerMessage = providerMessage; } public String getAccountMessage() { return this.accountMessage; } public void setAccountMessage(String accountMessage) { this.accountMessage = accountMessage; } public String getProviderTransactionCode() { return this.providerTransactionCode; } public void setProviderTransactionCode(String providerTransactionCode) { this.providerTransactionCode = providerTransactionCode; } public String getAccountTransactionCode() { return this.accountTransactionCode; } public void setAccountTransactionCode(String accountTransactionCode) { this.accountTransactionCode = accountTransactionCode; } public Date getRequestTime() { return this.requestTime; } public void setRequestTime(Date requestTime) { this.requestTime = requestTime; } public String getMd5signature() { return this.md5signature; } public void setMd5signature(String md5signature) { this.md5signature = md5signature; } public String getResponseCode() { return this.responseCode; } public void setResponseCode(String responseCode) { this.responseCode = responseCode; } public EnumVoucherTransactionStatus getStatus() { return this.status; } public void setStatus( EnumVoucherTransactionStatus status) { this.status = status; } public String getMappedProductCode() { return mappedProductCode; } public void setMappedProductCode(String mappedProductCode) { this.mappedProductCode = mappedProductCode; } public String getProviderResponseCode() { return providerResponseCode; } public void setProviderResponseCode(String providerResponseCode) { this.providerResponseCode = providerResponseCode; } public String getGatewayUri() { return gatewayUri; } public void setGatewayUri(String gatewayUri) { this.gatewayUri = gatewayUri; } public String getGatewayUsername() { return gatewayUsername; } public void setGatewayUsername(String gatewayUsername) { this.gatewayUsername = gatewayUsername; } public String getGatewayPassword() { return gatewayPassword; } public void setGatewayPassword(String gatewayPassword) { this.gatewayPassword = gatewayPassword; } public String getGatewaySecurityKey() { return gatewaySecurityKey; } public void setGatewaySecurityKey(String gatewaySecurityKey) { this.gatewaySecurityKey = gatewaySecurityKey; } public Short getGatewayTimeout() { return gatewayTimeout; } public void setGatewayTimeout(Short gatewayTimeout) { this.gatewayTimeout = gatewayTimeout; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TopupMessage pojo = (TopupMessage) o; if (account != null ? !account.equals(pojo.account) : pojo.account != null) return false; if (gateway != null ? !gateway.equals(pojo.gateway) : pojo.gateway != null) return false; if (provider != null ? !provider.equals(pojo.provider) : pojo.provider != null) return false; if (voucher != null ? !voucher.equals(pojo.voucher) : pojo.voucher != null) return false; if (transactionCode != null ? !transactionCode .equals(pojo.transactionCode) : pojo.transactionCode != null) return false; if (marketPrice != null ? !marketPrice.equals(pojo.marketPrice) : pojo.marketPrice != null) return false; if (msisdn != null ? !msisdn.equals(pojo.msisdn) : pojo.msisdn != null) return false; if (nettPrice != null ? !nettPrice.equals(pojo.nettPrice) : pojo.nettPrice != null) return false; if (providerMessage != null ? !providerMessage .equals(pojo.providerMessage) : pojo.providerMessage != null) return false; if (accountMessage != null ? !accountMessage .equals(pojo.accountMessage) : pojo.accountMessage != null) return false; if (providerTransactionCode != null ? !providerTransactionCode .equals(pojo.providerTransactionCode) : pojo.providerTransactionCode != null) return false; if (accountTransactionCode != null ? !accountTransactionCode .equals(pojo.accountTransactionCode) : pojo.accountTransactionCode != null) return false; if (requestTime != null ? !requestTime.equals(pojo.requestTime) : pojo.requestTime != null) return false; if (md5signature != null ? !md5signature.equals(pojo.md5signature) : pojo.md5signature != null) return false; if (responseCode != null ? !responseCode.equals(pojo.responseCode) : pojo.responseCode != null) return false; if (status != null ? !status.equals(pojo.status) : pojo.status != null) return false; return true; } @Override public int hashCode() { int result = 0; result = (account != null ? account.hashCode() : 0); result = 31 * result + (gateway != null ? gateway.hashCode() : 0); result = 31 * result + (provider != null ? provider.hashCode() : 0); result = 31 * result + (voucher != null ? voucher.hashCode() : 0); result = 31 * result + (transactionCode != null ? transactionCode.hashCode() : 0); result = 31 * result + (marketPrice != null ? marketPrice.hashCode() : 0); result = 31 * result + (msisdn != null ? msisdn.hashCode() : 0); result = 31 * result + (nettPrice != null ? nettPrice.hashCode() : 0); result = 31 * result + (providerMessage != null ? providerMessage.hashCode() : 0); result = 31 * result + (accountMessage != null ? accountMessage.hashCode() : 0); result = 31 * result + (providerTransactionCode != null ? providerTransactionCode .hashCode() : 0); result = 31 * result + (accountTransactionCode != null ? accountTransactionCode .hashCode() : 0); result = 31 * result + (requestTime != null ? requestTime.hashCode() : 0); result = 31 * result + (md5signature != null ? md5signature.hashCode() : 0); result = 31 * result + (responseCode != null ? responseCode.hashCode() : 0); // result = 31 * result + (status != null ? status.hashCode() : 0); return result; } @Override public String toString() { StringBuffer sb = new StringBuffer(getClass().getSimpleName()); sb.append(" ["); sb.append("account").append("='").append(getAccount()).append("', "); sb.append("gateway").append("='").append(getGateway()).append("', "); sb.append("provider").append("='").append(getProvider()).append("', "); sb.append("voucher").append("='").append(getVoucher()).append("', "); sb.append("transactionCode").append("='").append(getTransactionCode()) .append("', "); sb.append("marketPrice").append("='").append(getMarketPrice()).append( "', "); sb.append("msisdn").append("='").append(getMsisdn()).append("', "); sb.append("nettPrice").append("='").append(getNettPrice()) .append("', "); sb.append("providerMessage").append("='").append(getProviderMessage()) .append("', "); sb.append("accountMessage").append("='").append(getAccountMessage()) .append("', "); sb.append("providerTransactionCode").append("='").append( getProviderTransactionCode()).append("', "); sb.append("accountTransactionCode").append("='").append( getAccountTransactionCode()).append("', "); sb.append("requestTime").append("='").append(getRequestTime()).append( "', "); sb.append("md5signature").append("='").append(getMd5signature()) .append("', "); sb.append("responseCode").append("='").append(getResponseCode()) .append("', "); sb.append("status").append("='").append(getStatus()).append("', "); sb.append("]"); return sb.toString(); } }
Dummy.java
package com.akorena.app.gateway; import org.apache.camel.CamelContext; import org.apache.camel.Component; import org.apache.camel.Consumer; import org.apache.camel.Endpoint; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultCamelContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.Ostermiller.util.CmdLn; import com.Ostermiller.util.CmdLnOption; import com.Ostermiller.util.CmdLnResult; public class Dummy { private static final Log log = LogFactory.getLog(Dummy.class); private static Component component; private static CamelContext camel; private static Endpoint endpoint; static String serverEndpoint = "tcp://localhost:61616"; static String serviceTag = "Dummy"; private enum EnumOptions { HELP(new CmdLnOption("help", 'h')), SERVER(new CmdLnOption("server", 's').setRequiredArgument().setDescription( "ActiveMQ endpoint, default to tcp://localhost:61616")), SERVICETAG( new CmdLnOption("servicetag", 'i').setRequiredArgument() .setDescription("Service tag identifier")); private CmdLnOption option; private EnumOptions(CmdLnOption option) { option.setUserObject(this); this.option = option; } private CmdLnOption getCmdLineOption() { return option; } } public static void main(String[] args) throws Exception { CmdLn cmdLn = new CmdLn(args).setDescription("Akorena - Dummy Gateway"); for (EnumOptions option : EnumOptions.values()) { cmdLn.addOption(option.getCmdLineOption()); } for (CmdLnResult result : cmdLn.getResults()) { switch ((EnumOptions) result.getOption().getUserObject()) { case HELP: { cmdLn.printHelp(); System.exit(0); } break; case SERVER: { serverEndpoint = result.getArgument(); } break; case SERVICETAG: { serviceTag = result.getArgument(); } break; } } try { camel = new DefaultCamelContext(); if (camel.getComponent("activemq") == null) camel.addComponent("activemq", org.apache.activemq.camel.component.ActiveMQComponent .activeMQComponent(serverEndpoint)); } catch (Exception e) { log.error(e.getMessage()); System.exit(1); } component = camel.getComponent("activemq"); try { endpoint = component .createEndpoint("activemq:queue:topup?requestTimeout=100000&concurrentConsumers=20"); } catch (Exception e) { log.error(e.getMessage()); System.exit(1); } try { camel.addRoutes(new RouteBuilder() { public void configure() { errorHandler(deadLetterChannel("mock:error")); from( "activemq:queue:" + serviceTag.toUpperCase() + "?requestTimeout=110000").process( new TopupProcessor()); } }); } catch (Exception e) { log.error(e.getMessage()); System.exit(1); } try { camel.start(); } catch (Exception e) { log.error(e.getMessage()); System.exit(1); } Runtime runtime = Runtime.getRuntime(); Thread thread = new Thread(new ShutDownListener(camel)); runtime.addShutdownHook(thread); Consumer consumer = endpoint.createPollingConsumer(); consumer.start(); log.info("Akorena - Dummy gateway server started."); log.info("Service endpoint " + serverEndpoint); log.info("Service tag selector " + serviceTag); } } class ShutDownListener implements Runnable { private static final Log log = LogFactory.getLog(ShutDownListener.class); private CamelContext camel; public ShutDownListener(CamelContext camel) { this.camel = camel; } public void run() { log.info("Dummy server shutting down"); try { camel.stop(); } catch (Exception e) { log.error(e.getMessage()); } } }
TopupProcessor.java
package com.akorena.app.gateway; import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.akorena.app.vms.model.EnumVoucherTransactionStatus; import com.akorena.app.vms.model.TopupMessage; public class TopupProcessor implements Processor { private static final Log log = LogFactory.getLog(TopupProcessor.class); static String status = "SUCCESS"; static String responseCode = "200"; static String responseMessage = "OK"; public void process(Exchange exchange) throws Exception { // get the mail body as a String TopupMessage msg = exchange.getIn().getBody(TopupMessage.class); msg.setResponseCode(this.responseCode); msg.setProviderResponseCode(this.responseCode); msg.setStatus(EnumVoucherTransactionStatus.valueOf(this.status)); msg.setProviderMessage(this.responseMessage); msg.setProviderTransactionCode("XXXTESTXXXX"); exchange.getOut().setBody(msg); } }
