Example: account transfer

About this task
In this example, an SMS solution for account transferring by sending short messages is created. The message format is:
FT <Customer ID=""> {Source account number} <Payee nick=""> <Amount>
<>: mandatory 
{}: optional

This service is only available during 9:00am - 20:00pm.

To develop this solution, perform the following steps:

  1. Install the SMS gateway server and do the configuration. The knowledge about the SMS gateway is needed to develop the SMS solution according to the specific gateway. Use the SMS gateway named gateway A. The gateway is installed in machine 9.186.64.161 and the service port is 9501. Create a user test2 for the application.
  2. Development using BTT framework and BTT SMS Handler. To develop this solution, you can do following steps:
    1. Create an enterprise application project named SMSEAR, create a dynamic web project named SMSWeb. Copy the bttchannels.jar, bttcore.jar, bttruleprovider.jar into the EAR project and add them to build path and J2EE dependency.
    2. Right click the SMSWeb project, and select BTT Tools->Add BTT Nature. This step creates a default btt.xml file under the definitionfolder. Add the following code into the btt.xml:
      <kColl id="sms">			   <field id="encoding" value="UTF-8"/>
        <field id="requestHandler"
      value="com.ibm.btt.channel.sms.SMSRequestHandler"/>
        <field id="presentationHandler"
      value="com.ibm.btt.channel.sms.SMSPresentationHandler"/>	 	   
      
      <!-- channel policy configuration  -->	   
      <field id="channelPolicyHandler" value="com.ibm.btt.test.MyC hannelPolicyHandler"/>
        <field id="ruleService" value="javaCodeChannelRuleService"/>
      </kColl>

      Create the BTT other definition files: format.xml, operation.xml, processor.xml, invoker.xml. The content can be left empty as the data in these definition files are not used here.

      Create the following BTT definition files with the sample code: data.xml

      <data.xml>
      	<!-- Data collection for the branch context--> 	<kColl id="branchData"
      dynamic="true">
      		<field id="BranchId"/>
      		<field id="REPLY_SMS_MSG"/>
      		<iColl id="titles" size="2">
      			<kColl id="title">
      				<field id="name"/>
      				<field id="value"/>
      			</kColl>
      		</iColl>
      	</kColl>
       	<!-- Data collection for the html session context--> 	<kColl
      id="sessionData">
      	</kColl>
      </data.xml>

      context.xml:

      <context.xml>
      	 	<!--root context--> 	<context id="branchServer" type="branch"
      parent="nil">
      		<refKColl refId="branchData"/>
      		<refService alias="realCSServer" refId="realCSServer" type="cs"/>
      	</context>
        	<!-- The session context is created by the StartHtmlSession operation -->     <!-- This context is dynamically chained to the root context by the operation --> 	<context
      id="htmlSessionCtx" type="session" parent="branchServer">
      		<refKColl refId="sessionData"/>
      	</context>
      		
      </context.xml>

      type.xml:

      <type.xml>
      	<type id="String" implClass="com.ibm.btt.base.DataField">
      		<descriptor id="typeDefault"
      implClass="com.ibm.btt.base.types.ext.StringPropertyDescriptor">
      			<Converter convTypes="default,host"
      implClass="com.ibm.btt.base.types.ext.StringConverter"/>
      			<Validator implClass="com.ibm.btt.base.types.ext.StringValidator"/>
      		</descriptor>
      	</type>
      	<type id="Integer" implClass="com.ibm.btt.base.DataField">
      		<descriptor id="typeDefault"
      implClass="com.ibm.btt.base.types.ext.IntegerPropertyDescriptor">
      			<param id="initialValue" value=""/>
       			<Converter convTypes="default,host"
      implClass="com.ibm.btt.base.types.ext.IntegerConverter"/>
      			<Validator implClass="com.ibm.btt.base.types.ext.IntegerValidator"
      lowerLimit="10" upperLimit="90"/>
      		</descriptor>
      	</type>
      </type.xml>

      service.xml:

      <service.xml>
      	<!-- Client-Server Service--> 	<CSServer id="realCSServer"
      inactivityClientTimeout="1800000" timeBetweenSessionCheck="20000"/>
      	<com.ibm.btt.channel.ruleprovider.ilog.ILogRuleProviderService
      id="checkTransferAmountILogRule"
      ruleID="/checkChannelRuleApp/BTTChannelRules"/>	 		 	<com.ibm.btt.test.JavaCodeChannelRuleService
      id="javaCodeChannelRuleService"/>
      		
      </service.xml>

      accountTransferOp.xml:

      <Op_Account_Transfer>
        <operation context="accountTransferCtx" id="accountTransferOp"
      implClass="com.ibm.btt.test.TransferOperation"></operation>
              <context id="accountTransferCtx" type="op">
          <refKColl refId="TransferData"/>
        </context>
           <kColl id="TransferData">
          <field id="custid"/>
          <field id="sourceAccount"/>
          <field id="nickName"/>
          <field id="amount"/>
          <field id="amountLimit"/>
        </kColl>
      </Op_Account_Transfer>
    3. Create a package named com.ibm.btt.test under src folder. Create the SMS Handler configuration XML file named SMSHandlerConfig.xml in this folder. Add the following code into the SMSHandlerConfig.xml file:
      <SMSHandler>
      	<com.ibm.btt.channel.sms.config.InboundHandlerConfiguration
      id="inbound1">
      		<com.ibm.btt.channel.sms.config.ParameterNames
      Injection="parameterNames" fromParamName="sender"
      messageIDParamName="msgid" messageParamName="msgdata"/>
      			<ref Injection="replyMsgOutboundHandler" refId="outbound1"/>
      		<ref Injection="smsCommands" refId="SMSCommandTable"/>
      		 	</com.ibm.btt.channel.sms.config.InboundHandlerConfiguration>
       	<list id="SMSCommandTable">
      		<com.ibm.btt.channel.sms.config.CommandMetaData id="Tansfer"
      shortCode="FT" bttOperationName="accountTransferOp">
      			<list Injection="parameters">
      				<com.ibm.btt.channel.sms.config.CommandParamter name="custid"
      type="java.lang.String"/>
      				<com.ibm.btt.channel.sms.config.CommandParamter name="sourceAccount"
      type="java.lang.String" optional="true"/>
      				<com.ibm.btt.channel.sms.config.CommandParamter name="nickName"
      type="java.lang.String"/>
      				<com.ibm.btt.channel.sms.config.CommandParamter name="amount"
      type="java.lang.Double"/>
      			</list>
      		</com.ibm.btt.channel.sms.config.CommandMetaData>
      	</list>
       	<com.ibm.btt.channel.sms.outbound.BTTOutboundMessageHandler
      id="outbound1">
      		<com.ibm.btt.channel.sms.config.OutboundHandlerConfiguration
      Injection="config" hostName="9.186.64.161" port="9501"
      programName="api?action=sendmessage" account="tester2"
      password="q1w2e3r4">
          <com.ibm.btt.channel.sms.config.ParameterNames
      Injection="parameterNames" messageParamName="messagedata"
      accountParamName="username" passwordParamName="password"
      toParamName="recipient"/>
      			<ref Injection="dlrConfig"
      refId="OZEKIOutboundResponseDLRHandlerConfig"/>
      		</com.ibm.btt.channel.sms.config.OutboundHandlerConfiguration>
      	</com.ibm.btt.channel.sms.outbound.BTTOutboundMessageHandler>
       	<com.ibm.btt.channel.sms.config.DLRHandlerConfiguration
      id="OZEKIOutboundResponseDLRHandlerConfig">
        <com.ibm.btt.channel.sms.config.ParameterNames
      Injection="parameterNames" messageIDParamName="messageid"
      toParamName="recipient" statusParamName="statuscode"/>
      		<map Injection="statusCodeConverter">
      			<entry key="0" value="0"></entry>
      			<entry key="1" value="1"></entry>
      			<entry key="2" value="2"></entry>
      		</map>
      		<ref Injection="dlrStore" refId="dlrMemoryStore"/>
      	</com.ibm.btt.channel.sms.config.DLRHandlerConfiguration>
      	<com.ibm.btt.channel.sms.dlr.DLRMemoryStore id="dlrMemoryStore"/> 
      </SMSHandler>
    4. In the package com.ibm.btt.test, create the following Java file with the sample code: TransferOperation.java
      package com.ibm.btt.test;
      
      import com.ibm.btt.base.BTTServerOperation;
      import com.ibm.btt.channel.sms.SMSHandlerConstant;
      
      @SuppressWarnings("serial")
      public class TransferOperation extends BTTServerOperation {
      
      	public void execute() throws Exception {
      		try {
      			Thread.sleep(200);
      
      		} catch (Exception e) {
      			 e.printStackTrace();
      		}
      		
      		super.execute();
      		System.out.println("====== TransferOp Start =====with context: \n"+getContext().getKeyedCollection());
      		
      		if (getValueAt(SMSHandlerConstant.REPLYMSG)==""||getValueAt(SMSHandlerConstant.REPLYMSG)==null)
      			setValueAt(SMSHandlerConstant.REPLYMSG, "==== Transfer Successfully!==== \n Recipient:"
      				+getContext().getValueAt("nickName")+"\n Amount:"+getContext().getValueAt("amount")
      				+"\n Balance: 9201.20");
      	}
      
      }

      JavaCodeChannelRuleService.java

      package com.ibm.btt.test;
      
      import java.util.Calendar;
      import java.util.Map;
      import com.ibm.btt.channel.PolicyResult;
      import com.ibm.btt.channel.ruleprovider.java.JavaCodeRuleProviderService;
      
      public class JavaCodeChannelRuleService extends JavaCodeRuleProviderService {
      
      	public Map<String> checkRule(Map<String> params) { 		System.out.println("JavaCodeChannelRuleService: checking the channel rule...");  		PolicyResult result = (PolicyResult) params.get("result"); 		ChannelPolicyData data = (ChannelPolicyData) params.get("data"); 		   		Calendar now = data.getNow(); 		int hours = now.get(Calendar.HOUR_OF_DAY); 		if (hours >= 20 || hours < 9) { 			result.reject(); 			String message = "The Internet Bank is just opening for 9:00-20:00, please try later.”; 			result.addToMessages(message); 		  		} 		System.out.println("JavaCodeChannelRuleService: the result message is:" + result.getMessages()); 		return null; 	}  }
      </String></String>

      MyChannelPolicyHandler.java

      package com.ibm.btt.test;
      
      import java.util.Calendar;
      import java.util.HashMap;
      import java.util.Map;
      import com.ibm.btt.channel.AbstractChannelPolicy;
      import com.ibm.btt.channel.PolicyResult;
      import com.ibm.btt.clientserver.ChannelContext;
      
      public class MyChannelPolicyHandler extends AbstractChannelPolicy {
      
      	private PolicyResult result;
      
      	@Override
      	protected Map<String> getInputParameter(ChannelContext ctx) { 		Map<String> input = new HashMap<String>(); 		result = new PolicyResult(); 		ChannelPolicyData data = new ChannelPolicyData(); 		data.setDeviceType(ctx.getDeviceType()); 		data.setNow(Calendar.getInstance());  		input.put("data", data); 		input.put("result", result); 		return input; 	}  	@Override 	protected PolicyResult processResult(Map<String> resultMap) { 		return result; 	} }
      </String></String></String></String>

      StartServerServlet.java:

      package com.ibm.btt.test;
      
      import javax.servlet.Servlet;
      import javax.servlet.ServletConfig;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      
      import com.ibm.btt.base.Context;
      import com.ibm.btt.base.ContextFactory;
      import com.ibm.btt.config.InitManager;
      
      @SuppressWarnings("serial")
      public class StartServerServlet extends HttpServlet implements Servlet {
      
      	public void init(ServletConfig arg0) throws ServletException {
      		try {
      				final String bttPath = (String) arg0
      						.getInitParameter("bttConfigPath");
      				InitManager.reset(bttPath);
      				Context root = ContextFactory.createContext("branchServer",
      						true);
      		} catch (Exception e) {
      			e.printStackTrace();
      		}
      	}
      
      }
    5. Update the file web.xml in the SMSWeb project with following code:
      <servlet>
        <description></description>
        <display-name>InitServlet</display-name>
        <servlet-name>InitServlet</servlet-name>
        <servlet-class>com.ibm.btt.test.StartServerServlet</servlet-class>
        <init-param>
        	<description></description>
        	<param-name>bttConfigPath</param-name>
        	<param-value>jar:///definitions/btt.xml</param-value>
        </init-param>
        <load-on-startup>-1</load-on-startup>
      </servlet><servlet-mapping>
        <servlet-name>InitServlet</servlet-name>
        <url-pattern>/InitServlet</url-pattern>
      </servlet-mapping><servlet>
        <servlet-name>OZEKIBTTInboundMessageHandler01</servlet-name>
        <servlet-class>com.ibm.btt.channel.sms.inbound.BTTInboundMessageHandler</servlet-class>
        <init-param>
        	<description> Configuration File path	</description>
        	<param-name>configFile</param-name>
        	<param-value>jar:///com/ibm/btt/test/SMSHandlerConfig.xml</param-value>
        </init-param>
        <init-param>
        	<description> ID of Inbound handler configuration defined config file 	</description>
        	<param-name>inboundConfigID</param-name>
        	<param-value>inbound1</param-value>
        </init-param>
      </servlet><servlet-mapping>
        <servlet-name>OZEKIBTTInboundMessageHandler01</servlet-name>
        <url-pattern>/OZEKIBTTInboundMessageHandler01</url-pattern>
      </servlet-mapping>
    6. Configure the SMS gateway incoming HTTP URL to be called if an SMS message arrives.
      http://localhost:9080/SMSWeb/servlet/OZEKIBTTInboundMessageHandler01?sender=$originator&receiver=$recipient&msgdata=$messagedata&recvtime=$receivedtime&msgid=$messageid
  3. Deploy the solution and use mobile phone to do the test. Deploy the EAR to the WebShpere Application Server. Then use the mobile phone to send a transfer command to the SMS gateway number, such as:
    FT user01 payee01 1200

    After a while, the mobile will receive the reply message:

    ==== Transfer Successfully!====
      Recipient: payee01
      Amount:1200.0
      Balance: 9201.20

    If you send the message not during 9:00am - 20:00pm, then the mobile will receive the reply message:

    SMS command is rejected by channel policy. Reason= The Internet Bank is just opening for 9:00-20:00, please try later.