Social Icons

Wednesday 27 November 2013

Customer Experience Management: Putting yourself in the Customer's shoes.

The customer experience has long been considered an important factor in the telecoms industry. But is the industry doing everything it can to enhance existing customer relationships? Operators have to start putting themselves in the customer’s shoes, to really understand the service expected.

The reality of the market challenges operators have faced, such as reduced margins and ARPUs, as well as increasing competition, has meant customer service systems was not such a priority. However, investment is crucial. Traditional CRM systems are not able to provide the customer experience needed to ensure loyalty, especially with the popular rise in new technologies.


Traditional CRM issues

The trouble with traditional CRM systems is that they provide an introverted view of customer interaction. For far too long, companies have focused on quantitative measures, such as the Average Handling Time and First Call Resolution. None of these performance indicators addresses the way the customer felt and responded to the interaction.

An example; a customer calls up to enquire about altering his package because he keeps nearing his usage allowance. The agent informs him that he can’t until he’s been with them for six months and the call ends. Now, the call was quick and during that first call it addressed the customer’s question, but the customer was left with an unsatisfactory response. This most likely left the customer frustrated and created an unsupportive view of the operator.


The customer perspective

The challenge is for the service provider to see things from the customer’s perspective. An IBM whitepaper ‘From Social Media to Social CRM: What Customers Want’ shows just how out of touch businesses can be with what the customers really wants and expect. Demonstrated in the chart below by the misperceptions of the purpose of customer interactions through social sites.

Click to view in full size

Operators need to understand the importance of good customer experience, before anything can be done about it. If customer experience is done right, it can be hugely beneficial to business – from driving profits and an upturn in sales, to creating a more valued and satisfied customer base. Part two of my series on customer experience management will explain more about how to do customer service, the way the customer would.

Read Part Two here

CoralTree Systems is a leading provider of innovative BSS solutions, whose clients include some of the market’s leading communications operators. 

You can find out more at our website www.CoralTreeSystems.com

This article was written by Craig Maxwell-Brown, Business Development Assistant for CoralTree Systems.

Tuesday 12 November 2013

Calling RPG on the AS400 from Java

A practical article on calling RPG on the AS400 from Java

RPG is the native language on the IBM as400 midrange server (aka iSeries, system i and now just "i"). In a recent project I had to find a way to call a number of RPG programs from a Java application. If you're in this situation then there are a few options available.
  • PCML (the subject of this article)
  • SQL Stored procedure
  • Integrated web services server (IWS)
Stored procedure
One possibility is to write a SQL stored procedure using RPG which could be called from Java using JDBC. This option may not be viable depending on the parameters your program needs. A stored procedure is good for returning result sets of records but you can only return one and you can't pass one in.

Integrated web services server (IWS)
If you want to quickly expose an RPG program as a web service then you might want to look at IWS. This is a quick way to get up and running but there are a number of limitations.
  • If you want multiple operations on the same wsdl you have to write them all as procedures in the same service program
  • If using a service program IWS only supports up to 7 parameters including both inputs and outputs
  • IWS only supports contract last development. In other words you have to write the code first to get the wsdl.
  • The generated wsdl has a number of duplicated elements which you have to manually remove to tidy the appearance.
  • If you change the parameters or operations you have to go through the whole wizard again on each machine you deploy to.
  • Arrays are fixed size in RPG so IWS always returns all elements, even if some are simply blanks.
PCML
The most flexible method is Program Call Markup Language (PCML). This is an API that IBM provided for just this scenario. PCML is an XML language for defining the parameter list for an RPG program. This can then be used from a Java application.

Generating the PCML
You could write the pcml file by hand but a better way is to get the RPG compiler to generate it for you. First lets write a simple RPG program that we want to call.

1:  D CONVTEMP    PR         Extpgm('CONVTEMP')   
2:  D iCelsius           9 3 Const            
3:  D oFahrenheit          9 3            
4:  D CONVTEMP    PI                     
5:  D iCelsius           9 3 Const            
6:  D oFahrenheit          9 3            
7:   /free                            
8:    // We could get an API to return whatever we like here  
9:    oFahrenheit = ((iCelsius * 9) / 5) + 32;         
10:    Return;                          
11:   /end-free                          

Yes it's the cliche web service example to convert temperature from Celsius into Fahrenheit. It's a good one to start with though because it is has both an input and an output but is still fairly simple. Note that the input parameter has been defined as a const, this is significant when we generate the PCML.

To generate the PCML from here you need to prompt compile and set the following options. Set PGMINFO to *PCML and INFOSTMF to a path on the ifs where you want your generated file to go e.g. /mylib/CONVTEMP.pcml. Doing so gives the following PCML.

1:  <pcml version="4.0">  
2:    <program name="CONVTEMP" path="/QSYS.LIB/PCMLTEST.LIB/CONVTEMP.PGM">  
3:     <data name="ICELSIUS" type="packed" length="9" precision="3" usage="input" />  
4:     <data name="OFAHRENHEIT" type="packed" length="9" precision="3" usage="inputoutput" />  
5:    </program>  
6:  </pcml>                         

We now have an XML file that describes how to call this program. Notice that the iCelsius parameter has been set to input but oFahrenheit is inputoutput. This is a result of setting iCelsius to a const parameter. When making a PCML call you must set a value for all input parameters. The default is inputoutput which can go both ways but is inconvenient if you don't have an input value to set. Unfortunately there's no language feature in RPG to set a parameter to output only so you have to adjust these manually.

1:     <data name="OFAHRENHEIT" type="packed" length="9" precision="3" usage="output" />                        

Java dependencies
To make a PCML program call you just need the jt400 jar on your classpath. You can either use the IBM version that comes bundled with the AS400 or the open source JTOpen version.

If you use maven then you can simply declare it as a dependency like this.
1:  <dependency>  
2:          <groupId>net.sf.jt400</groupId>  
3:          <artifactId>jt400</artifactId>  
4:          <version>6.7</version>  
5:  </dependency>                     

This works fine but sadly the JTOpen developers stopped publishing to maven central at version 6.7 (current version is 7.10 at time of writing).

Calling the program
This is everything you need to make the program call. The Java class below is a simple test that opens a connection, calls the program and returns the result.
1:  import java.math.BigDecimal;  
2:  import com.ibm.as400.access.AS400;  
3:  import com.ibm.as400.data.PcmlException;  
4:  import com.ibm.as400.data.ProgramCallDocument;  
5:  public class ConvertTemperature  
6:  {  
7:          private AS400  as400;  
8:          public ConvertTemperature()  
9:          {  
10:                  as400 = new AS400("SYSTEM", "USERNAME", "PASSWORD");  
11:          }  
12:          public BigDecimal celsiusToFahrenheit(BigDecimal celsius)  
13:          {  
14:                  BigDecimal fahrenheit = null;  
15:                  try  
16:                  {  
17:                          ProgramCallDocument pcml = new ProgramCallDocument(as400, "CONVTEMP");  
18:                          pcml.setValue("CONVTEMP.ICELSIUS", celsius);  
19:                          boolean rc = pcml.callProgram("CONVTEMP");  
20:                          if(rc)  
21:                          {  
22:                                  fahrenheit = (BigDecimal) pcml.getValue("CONVTEMP.OFAHRENHEIT");  
23:                          }  
24:                  }  
25:                  catch(PcmlException e)  
26:                  {  
27:                          e.printStackTrace();  
28:                  }  
29:                  return fahrenheit;  
30:          }  
31:          public static void main(String[] args)  
32:          {  
33:                  ConvertTemperature ct = new ConvertTemperature();  
34:                  ct.celsiusToFahrenheit(new BigDecimal(25.2));  
35:          }  
36:  }  
The second parameter to the ProgramCallDocument constructor is the path on the classpath to the PCML xml document. I created a file called CONVTEMP.pcml and put it in the src/main/resources folder. To keep things simple this is the root classpath folder, the .pcml suffix is not required as it is implied.

The PCML API will automatically handle converting Java types to AS400 types and back again. In this example the packed decimal from the AS400 becomes a BigDecimal in Java.

This is obviously a basic example that works as a proof of concept but there are a few additions worth mentioning if you want to use this in a production environment.

Adding connection pooling
Each time you create an AS400 object you're opening a physical connection to the AS400. Each new connection creates a new job on the AS400. It's obviously a bit wasteful to then throw this away and start with a fresh connection on the next call. A much better solution is to create a connection pool.

First you need to create the connection pool object. This code should live in it's own class so the pool can be shared by different parts of the application. You could also load a properties file from the classpath to set the connection pool properties.
1:  AS400ConnectionPool pool = new AS400ConnectionPool();  
Now each time you want a connection you simply ask the pool. If no connections exist then one will be created.
1:  AS400 as400 = pool.getConnection("SYSTEM", "USERNAME", "PASSWORD");  
Remember to always return the connection back to the pool once you're finished with it. This should be done in the finally section of the try/catch block to ensure the connection is returned if an exception is thrown.
1:  pool.returnConnectionToPool(as400);  
Setting a library list
The PCML file generated had a fixed path to a specific library. In practice you may find the program exists in different libraries and you want to use the one at the top of the library list. To do this we must first change the PCML file to not hardcode the library.

Change this:
1:  <program name="CONVTEMP" path="/QSYS.LIB/PCMLTEST.LIB/CONVTEMP.PGM">  
To this:
1:  <program name="CONVTEMP" path="/QSYS.LIB/%LIBL%.LIB/CONVTEMP.PGM">  
1:  import com.ibm.as400.access.AS400;  
2:  import com.ibm.as400.access.AS400Message;  
3:  import com.ibm.as400.access.CommandCall;  
4:  import com.ibm.as400.access.ConnectionListener;  
5:  import com.ibm.as400.access.ConnectionPoolEvent;  
6:  import com.ibm.as400.access.ConnectionPoolListener;  
7:  public class AS400ConnectionPoolListener implements ConnectionPoolListener  
8:  {  
9:    @Override  
10:    public void connectionCreated(ConnectionPoolEvent event)  
11:          {  
12:                  AS400 as400 = (AS400) event.getSource();  
13:                  CommandCall command = new CommandCall(as400);  
14:                  try  
15:                  {  
16:        String liblCommand = "CHGLIBL(QTEMP PCMLTEST QGPL)";  
17:                          if(command.run(liblCommand) != true)  
18:                          {  
19:                                  // Show the messages (returned whether or not there was an  
20:                                  // error.)  
21:                                  AS400Message[] messagelist = command.getMessageList();  
22:                                  for(int count = 0; count < messagelist.length; count++)  
23:                                  {  
24:                                          // Show each message.  
25:                                          System.out.println("System message: " + messagelist[count].getText());  
26:                                  }  
27:                          }  
28:      }  
29:          @Override  
30:          public void connectionExpired(ConnectionPoolEvent event)  
31:          {  
32:                  // Not currently overriden  
33:          }  
34:          @Override  
35:          public void connectionPoolClosed(ConnectionPoolEvent event)  
36:          {  
37:                  // Not currently overriden  
38:          }  
39:          @Override  
40:          public void connectionReleased(ConnectionPoolEvent event)  
41:          {  
42:                  // Not currently overriden  
43:          }  
44:          @Override  
45:          public void connectionReturned(ConnectionPoolEvent event)  
46:          {  
47:                  // Not currently overriden  
48:          }  
49:          @Override  
50:          public void maintenanceThreadRun(ConnectionPoolEvent event)  
51:          {  
52:                  // Not currently overriden  
53:          }  
54:  }  
Finally the event listener needs to be registered as an observer of the connection pool.
1:  pool.addConnectionPoolListener(new AS400ConnectionPoolListener());  
Summary
This is a basic example that shows how to call an RPG program from Java. To brush this up a bit for production you only really need a few classes to wrap the connection pool and loading of properties. This would allow you to set the library list on different servers with a simple properties file. I would use spring to load the properties and register a bean that holds the connection pool. If you have to support multiple environments then you could set the library list each time you get a connection. Alternatively it might be more efficient to pass the environment to the RPG program and handle it on the AS400.

Ben Thurley,
Senior Software Engineer at CoralTree Systems Ltd

You can view Ben's wordpress blog, with more articles, here

Ben has worked for CoralTree for over 5 years. In that time, his expertise and knowledge in new coding techniques and methods have helped us develop even better solutions for our customers.

The views expressed in this article are not necessarily the views of CoralTree Systems Ltd.