A Morsel Of Code

One byte at a time

Restful Webservice in 7 Steps using Spring boot

Last week I was working on a new application which required me to build a web service to access it’s functionality. I decided to check out Spring 4 RestController.

I was amazed at how far we have come from writing all the boiler template code, xmls etc for making a restful call. With Spring4 boot, it was matter of adding simple annotation for RestController.
I will be honest, I have not been up to date on how to use a Restful webservice, I built a couple of Restful service a couple of year ago, but most of the services in my current project are old school (SOAP calls), so I never got a chance to build one from scratch and at peace.

Prerequisites: Read Carefully
1. Spring 4 requires you to use Maven 3 in fact it will force you to use Maven 3. This is very important point because it took me an hour to figure this out. If you try to use Maven 2, it will build and “might” compile but the code will complain that some of the RestController class methods are not found. This happens because by default, maven 2 will pull in Spring 2.5.x jar files.
2. Requires a minimum of JDK 6.

What are we building?
We will build a service that will accept HTTP GET request at: http://localhost:9000/welcome

and respond with a JSON message:

{"content":"Hello Dinesh"}

Step 1: Create a maven project using command line tools or your favorite IDE.

Step 2: In the pom.xml add the following information
a) Parent:

b) Add spring-boot dependency

c) Add spring-boot plugin

d) Add spring repositories

Why do we need Spring Boot Maven Plugin?
You might be wondering what happened to the good old maven build plugin. Well that plugin still works and will compile and build your project, but Spring-boot-maven-plugin searches for the public static void main() method to mark it as runnable class if you use the command “mvn:run”. Secondly, it comes with its own dependency resolver for the version number to match the Spring-boot-starter-web dependencies.

Step 3: Create JSON Message POJO class


package dinesh;
public class Welcome {
private final String content;
public Greeting(String content) {
this.content = content;
public String getContent() {
return content;


Note: Spring 4 Boot automatically uses Jackson JSON library to marshal instances of Welcome into JSONObjects.

Step 4: Create a resource Controller
All Spring HTTP requests are handled by Spring controllers. For Restful services Spring 4 comes with a new annotation @RestController annotation. This will handle the requests which are posted to url /welcome by returning a new instance of Welcome class.


package hello;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
public class WelcomeController {
private static final String template = "Hello, %s!";
public Welcome welcome(@RequestParam(value="name", defaultValue="World") String name) {
return new Greeting(String.format(template, name));


If you look closely, you will know why I said Maven 2 will not work. Maven 2 will pull in RequestParm class from old Springmvc jar file which does not have method defined for defaultValue(). It is going cry out loud during compilation.
@RestController – annotation marks the class as controller where every method returns a domain object instead of a view, which is major distinction between @Controller and @RestController which is a short hand for @Controller + @ResponseBody
The @RequestMapping annotation helps Spring to identify what method to invoke when some one accesses “/welcome” url.
The @RequestParam binds the value of paramter “name” into the name parameter of the welcome() method. If you do not pass any value in the query string then the default value is “world” – defaultValue=”World”. If you do not add defaultValue and forget to pass a “name=xx” in the query string, you will hear a loud cracking, lots of smokes, some curses and code will complain of NP exceptions :-).

One important thing that you notice is that we have not done anything to marshall request/response as JSONobject. The old of way of doing this would need you to use Jackson libraries and a lot of annotation to make them as JSON properties. Thanks to Spring 4, it takes of it using Jackson dependencies in the background.

Step 5: Create an executable “jar” file. yes you read it right. Although you can create a war file, for smaller project like the one I build and the one for this example, I am not going to go through those steps. you cn check the Spring documentation on this topic. Just a high level view what is required is that you get right of the boot plugin, change the packaging tag in the pom.xml to war.Here’s a good post 


package dinesh;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan(basePackages = "dinesh.*")
public class Execute {
public static void main(String[] args) {
SpringApplication.run(Execute.class, args);


– @ComponentScan tells the app to check for @component annotation and it makes sure that Spring finds and registers WelcomeController, because it is marked as “@RestController”.

Step 6: Build and run
 Method 1 :
Run ‘mvn clean install’ in the command line
After the jaris built, run

java -jar target/xxx.jar

Method 2:

Run spring-boot:run


Spring 4 comes with built-in Tomcat 7, so you do not need a full-blown JEE application server to deploy and run your web service. Either of the method will fire up the application on port 8080.

How do I change port number?
just run

spring-boot:run -Dserver.port=9000


Step 7: Test your service
Once the service is up, visit http://localhost:8080/welcome?name=your-name and you will get back a response
{“content”:”Hello, your-name!”}



A quick tutorial on SAAJ API

We ran into an issue last week. I had to call a third party web service that was built in PHP. Anyone who wokrs with Java will tell you that calling a web service is not more 15 minutes coding. You take the wsdl, run wsdl2Java command from Axis2 and start calling the service.

Like I said before, things are never so straightforward. No matter what version of Axis or CXF we used, we kept getting this error:

Caused by: org.apache.axiom.soap.SOAPProcessingException: Transport level information does not match with SOAP Message namespace URI
at org.apache.axis2.builder.BuilderUtil.validateSOAPVersion(BuilderUtil.java:772)
at org.apache.axis2.builder.SOAPBuilder.processDocument(SOAPBuilder.java:58)
at org.apache.axis2.transport.TransportUtils.createDocumentElement(TransportUtils.java:179)
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:145)
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:108)
… 13 more

Now what this usually means is that client and server are using different version of SOAP(1.1 vs 1.2). For a long time my colleague tried to look for a solution on various forums, blogs etc. and everyone confirmed the same that the issue is at the service provider end. However, the same service was being used by 20 other vendors without an issue. Our Canada office reported that they were able to call the service without any issue albeit in PHP(OOPS!!).

One fine afternoon it just struck me that Axis, CXF etc. are nothing but a wrapper around Java’s SAAJ API. Imagine how did developers call services before Axis and CXF? They coded QNAME, SOAPMessage manually! Lo and Behold but I went down to … let’s call it low level programming because I had to write code for all the XML node element, define namespaces etc.. which was not fun at all.
So this tutorial will walk you through basics of SAAJ, how and when to use the SAAJ API.

I so badly want to say that when you want to avoid the above error, use SAAJ :-). SAAJ is helpfule when you want complete control over SOAP elements. For example if you need to change name spaces or modify soap message attributes then SAAj comes in handy.

A typical SOAP message looks like this

As you can see SAAJ provides SOAPMessage, SOAPHeader, SOAPBody classes to capture the message. When you create a new SOAPMessage object, it will automatically have the parts that are required to be in a SOAP message. In other words, a new SOAPMessage object has a SOAPPart object that contains a SOAPEnvelope object. The SOAPEnvelope object in turn automatically contains an empty SOAPHeader object followed by an empty SOAPBody object. If you do not need the SOAPHeader object, which is optional, you can delete it. The rationale for having it automatically included is that more often than not you will need it, so it is more convenient to have it provided. The SOAPHeader object may contain one or more headers with information about the sending and receiving parties. The SOAPBody object, which always follows the SOAPHeader object if there is one, provides a simple way to send information intended for the ultimate recipient. For example, if there is a SOAPFault object, it must be in the SOAPBody object.

So If have a service where I need the request SOAP Message should look like

<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:urn=”urn:http://com.mycompany.IamDoingSomething”>

and I need to send this message to web service url “http://some-webservice-url.com”


1. Create a SOAP Message

MessageFactory factory = MessageFactory.newInstance();
SOAPMessage message = factory.createMessage();




2. Access Soap parts or message

SOAPHeader header = message.getSOAPHeader();
SOAPBody body = message.getSOAPBody();


3. Add Message Content

 SOAPBody body = message.getSOAPBody();

SOAPFactory soapFactory = SOAPFactory.newInstance();
Name bodyName = soapFactory.createName(“getPresaleByAddress”,”urn”, “http://com.mycompany.IamDoingSomething”);
SOAPBodyElement bodyElement = body.addBodyElement(bodyName);




4. Add Message Headers namespaces if Any

MimeHeaders headers = soapMessage.getMimeHeaders();
headers.addHeader(“SOAPAction”, leonidUrl+ “/getPresaleByAddress”);
SOAPPart soapPart = soapMessage.getSOAPPart();
// SOAP Envelope
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration(“urn”, “urn:http://com.mycompany.IamDoingSomething”);


5. Add Basic Authentication if any

String authorization = new sun.misc.BASE64Encoder().encode((“myUserName”+”:”+”myPassword”).getBytes());
headers.addHeader(“Authorization”, “Basic ” + authorization);

6. Add child elements

QName bodyName = new QName(“urn:http://com.mycompany.IamDoingSomething”,”getPresaleByAddress”,”urn”) ;
SOAPBodyElement bodyElement = body.addBodyElement(bodyName);
QName node_name = new QName(qName);
SOAPElement node_element = null;
try {
node_element = bodyElement.addChildElement(“stnum”);



7. Get a Soap Connection Object

SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
SOAPConnection connection = soapConnectionFactory.createConnection();


SOAP messages are sent and received over a connection. This connection is represented by a SOAPConnection object, which goes from the sender directly to its destination. This kind of connection is called a point-to-point connection because it goes from one endpoint to another endpoint. Messages sent using the SAAJ API are called request-response messages. They are sent over a SOAPConnection object with the method call, which sends a message (a request) and then blocks until it receives the reply (a response).

8. Send the message

// Create an endpoint point which is either URL or String type
java.net.URL endpoint = new URL(“http://some-webservice-url.com”);

// Send a SOAPMessage (request) and then wait for SOAPMessage (response)
SOAPMessage response = connection.call(message, endpoint);

9. Print the SOAP Response XML

Transformer transformer = transformerFactory.newTransformer();
Source sourceContent = response.getSOAPPart().getContent();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
StreamResult result = new StreamResult(outputStream);
transformer.transform(sourceContent, result);
log.info(“nResponse SOAP Message ::n {}” , result.getOutputStream().toString());

That’s it!!

There are many other things that you can do with SAAJ. To read more about SAAJ and it’s capabilities you can read here and here







Apache POI: How to read and write Excel files in Java

About a year or two ago I was working with finance team where they wanted to pull the credit card transactions for all the customer using various combinations. Ex –

– Get the credit card txns for today or certain date.

– Get the txns for customer who used Mastercard or Visa.

However they wanted this application to generate a Excel file and save it on their local machine so that they could prepare reports for our CEO. I used a Apache POI project to create jar files. This tutorial will walk you through the process of reading and writing excel sheet. So let’s see – How to read and write excel files in Java?

Brief History on Apache POI

Apache POI is a powerful Java library to work with different Microsoft Office file formats such as Excel, Power point, Visio, MS Word etc. The name POI was originally an acronym for Poor Obfuscation Implementation, referring humorously to the file formats that seemed deliberately obfuscated, but poorly, since they were successfully reverse-engineered.  In short, you can read / write MS Excel files using Java. In addition, you can read/write MS Word and MS PowerPoint files using Java. Apache POI is your Java Excel solution .

Apache POI can be used to create both old ( 2003-2008) and new( 2010 – newer) format. I think the newer jar file to create XLSX document is out of BETA phase now. Back when I used this POI it was still in Beta format.

So let’s see what does it entails to read /write Excel files in Java.

I am will be using Maven and IntelliJ to create my project, however you are welcome to use Eclipse or Netbeans.

Apache POI dependencies

There are two different maven dependencies one for creating an older version of excel – XLS format and other for creating new version of Excel – XLSX format. I am listing both the dependencies here.

<!– For Excel 2007 –>

Create a new module in IntelliJ.

Add the dependency in your pom.xml


Before we go ahead here’s quick primer on 3  key classes in POI.

  1. HSSF – Java implementation of the Excel ’97(-2007) file format. e.g. HSSFWorkbookHSSFSheet.
  2. XSSF –  Java implementation of the Excel 2007 OOXML (.xlsx) file format. e.g. XSSFWorkbookXSSFSheet.
  3. SXSSF – Used when very large spreadsheets have to be produced, and heap space is limited. e.g. SXSSFWorkbookSXSSFSheet.

There are other wide range of classes as well which can be used to manipulate the Excel sheet. Ex –  BuiltinFormatsConditionalFormattingRule,ComparisonOperator,CellStyleFontFormattingIndexedColorsPatternFormattingSheetConditionalFormatting. These used for formatting the sheet and formula evaluation.


This involves the following steps.

So go ahead and create a new file called NewExcel.java

package com.dinesh;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
* Created by darora on 4/18/14.
public class NewExcel {
public static void main(String[] args) {
//Create a new Workbook
XSSFWorkbook workbook = new XSSFWorkbook();
//Create a blank sheet
XSSFSheet sheet = workbook.createSheet("Student data");
//Create the data for the excel sheet
Map<string, object[]=""> data = new TreeMap<string, object[]="">();
data.put("1", new Object[] {"ID", "FIRSTNAME", "LASTNAME"});
data.put("2", new Object[] {1, "Randy", "Maven"});
data.put("3", new Object[] {2, "Raymond", "Smith"});
data.put("4", new Object[] {3, "Dinesh", "Arora"});
data.put("5", new Object[] {4, "Barbra", "Klien"});
//Iterate over data and write it to the sheet
Set keyset = data.keySet();
int rownum = 0;
for (String key : keyset)
Row row = sheet.createRow(rownum++);
Object [] objArr = data.get(key);
int cellnum = 0;
for (Object obj : objArr)
Cell cell = row.createCell(cellnum++);
if(obj instanceof String)
else if(obj instanceof Integer)
//Save the excel sheet
FileOutputStream out = new FileOutputStream(new File("c:\Dinesh\javahabitExcelDemo.xlsx"));
System.out.println("javahabitExcelDemo.xlsx Successfully created");
} catch (FileNotFoundException e) {
} catch (IOException e) {




So now that we have written an excel sheet. let’s try to read it back.

The steps involved are


package com.dinesh;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
* Created by darora on 4/18/14.
public class ReadExcel {
//Create Workbook instance from excel sheet
public static void main(String[] args) {
try {
//Get the Excel File
FileInputStream file = new FileInputStream(new File("c:\Dinesh\javahabitExcelDemo.xlsx"));
XSSFWorkbook workbook = new XSSFWorkbook(file);
//Get the Desired sheet
XSSFSheet sheet = workbook.getSheetAt(0);
//Increment over rows
for (Row row : sheet) {
//Iterate and get the cells from the row
Iterator cellIterator = row.cellIterator();
// Loop till you read all the data
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
switch (cell.getCellType()) {
System.out.print(cell.getNumericCellValue() + "t");
System.out.print(cell.getStringCellValue() + "t");
} catch (FileNotFoundException e) {
} catch (IOException e) {



Using formulas in excel sheet

When working on excel sheets, we sometimes have to create cells which use formulas to calculate their values.  Apache POI has supports methods for adding formula to cells and evaluating the already present formula in the cells. Neat!!

So Let’s see an example on setting a formula cells in the excel sheet.

In this code we will try to calculate the Simple interest. Formula – Principal * Interest * Time.


package com.dinesh;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
* Created by darora on 4/18/14.
public class CalculateFormula {
public static void main(String[] args)
//Create the workbook
XSSFWorkbook workbook = new XSSFWorkbook();
//Create the sheet
XSSFSheet sheet = workbook.createSheet("Calculate Simple Interest");
//Create Wor Headers
Row header = sheet.createRow(0);
header.createCell(3).setCellValue("OUTPUT (P * r * t)");
//Create the Rows
Row dataRow = sheet.createRow(1);
//Save the File
try {
FileOutputStream out =  new FileOutputStream(new File("c:\Dinesh\javahabitformulaDemo.xlsx"));
System.out.println("Excel File with formla is created!");
} catch (FileNotFoundException e) {
} catch (IOException e) {



So experiment your way with this jar file and do post your comments and suggestions on topics you had like to see in my future posts.


~ Ciao


13 Most Common Java Keytool Keystore Commands

I was working on a project last month where I had to call a third-party web service. The third-party web service wanted me to add a SSL keystore and I struggled. I could have gone to my UNIX Admin and asked him to do this job but decided to learn about all about keystores. I went through couple of forums and SO and ended my spending 2 – 3 hours reading about keystores and commonly used commands.

To give you a quick run here what I was doing. I had to use a third party wsdl to create a client. I tried to use Maven jaxws plugin to generate the client. I downloaded the wsdl to my local machine and was able to successfully create a client. For production I wanted to generate the client using the current wsdl so decided to generate the client using the wsdl url of the third-party website but ran into keystore issue. I had to download their certificate and add it to my CACERT.

The whole charade led me to compile this post. Before I begin here is a quick run through Keystore

Why Do I need a keystore?

By using a public/private key mechanism. This provides a layer of security that prevents, among other things, remote attackers from pushing malicious updates to your application  (all updates must be signed with the same key)

What is a Java Keytool?

It is a key and certificate management utility. It allows users to manage their own public/private key pairs and certificates. It also allows users to cache certificates. Java Keytool stores the keys and certificates in keystore. It protects private keys with a password. A Keytool keystore has the private key and any certificates necessary to complete a chain of trust and set up the trustworthiness of the primary certificate.

Each certificate in a Java keystore is associated with a unique alias. When creating a Java keystore you will first create the .jks file that will initially only contain the private key. You will then generate a CSR and have a certificate generated from it. Then you will import the certificate to the keystore including any root certificates. 

Here is a list of 13 most common commands


1. Create a Java Keystore and value pair

keytool -genkey -alias yourDomainName -keyalg RSA -keystore YourkeystoreName.jks 

2. Creating a signing request (CSR) for an existing keystore

keytool -certreq -alias yourDomainName -keystore keystore.jks -file yourDomainName.csr

3. Importing a signed primary certificate to an existing  keystore

keytool -import -trustcacerts -alias yourDomainName -file yourDomainName.crt -keystore YourkeystoreName.jks

4. Importing a root or intermediate CA certificate to an existing  keystore

keytool -import -trustcacerts -alias root -file Thawte.crt -keystore YourkeystoreName.jks

5. Creating a keystore and self-signed certificate

keytool -genkey -keyalg RSA -alias selfsigned -keystore Yourkeystore.jks -storepass password -validity 360


When you need to check the information about a certificate or keystore then you use these commands.

6. Checking a particular certificate

keytool -printcert -v -file Yourdomain.crt

7. Checking all certificates in a keystore

keytool -list -v -keystore Yourkeystore.jks

9. Checking a particular keystore entry using an alias

keytool -list -v -keystore Yourkeystore.jks -alias Yourdomain


10. Deleting a certificate from a keystore

keytool -delete -alias Yourdomain -keystore Yourkeystore.jks

11. Changing a keystore password

keytool -storepasswd -new new_password -keystore keystore.jks

12. Exporting a certificate from a keystore

keytool -export -alias Yourdomain -file Yourdomain.crt -keystore Yourkeystore.jks

13. Listing Trusted CA Certs

keytool -list -v -keystore $JAVA_HOME/jre/lib/security/cacerts

P.S. – If you liked the post please click on one of the ads in the right hand column to help me keep up this site and do drop a me a line to suggest some topics that would like to see on this site.

So Long ……

10 IntelliJ IDEA Keyboard Shortcuts That You Must Know

Linux nerds/geeks happily flaunt their keyboard skills when they get a chance. I admit that I am not a shortcut junky but I too have some keyboard shortcuts under my sleeve that I use in day to day work. I have to say that not only have these shortcuts increased my productivity but they have also made my life a lot easier.

I am sharing my 10 most used shortcuts at work.

1. Comment or Un-Comment: CTRL + L

You will often run into situation where you need to add debug statement temporarily and remove or comment the line after the debug is complete. Instead of manually going to the beginning of the line and manually typing //, you can use the keyboard shortcut CTRL + L. A cool thing to know is that you can comment out multiple lines at once.



2. Documentation Comment Block : /** + Enter

I may not follow other coding standard but I do follow this – “Leave the place cleaner before you leave”. One of my biggest pet peeves is developers not documenting about a method or sub routine. What are you conveying or trying to do in a particular method? I hate when I come across such code or even my code when I was beginner. So if commenting single line was not cool enough for you then you can use this to create documentation comments or comment out the code without ugly // marks showing at each line.

To compare the difference, I have commented the same code using CTRL+L and /** + Enter




3. Delete Line : CTRL + Y

This one is easy. If you have any vim experience or have used sublime text in the past then this would come easy. Simply place the cursor on the beginning of the line and hit CTRL + Y. Now it might not seem intuitive because the obvious choice of deleting should have been CTRL + D (It actually adds a new line if you wondered what it does) but a cool way to remember is to think about confirmation dialog boxes in Unix. For example – Are you sure you want to delete this folder? (Y/N)



4. Argument Documentation For Method Calls: CTRL + P

This one is a true life saver. Imagine you are about to call method which accepts 10 parameters. You start by typing – MyClass.someMethodWith10Params(.., ..,) and you forget what was the third parameter that I need to pass. One ugly way of doing is use your mouse and place the cursor at the beginning of the open bracket and wait for a second until the highlight shows you that the third parameter that you need to pass is a String variable. However if you are like me who forgets the fourth and then next parameters, you would be pulling your hair out. Here comes your knight in the shining armor – CTRL+P. This will tell pull up a callout with the information you need.



5. Continuous Code Selection: CTRL + W

Raise your hand if you never had to copy paste the code. Any one? This shortcut lets you select a word, block or comment without touching your mouse. When you press CTRL+W it will select the code next to the cursor and will continue to select intelligently. When I say intelligently I really mean it. Say you place your cursor in the middle of the code block and hit the key combination it will copy code from opening braces to closing braces and so on. Here’s a sample.



6. Paste from history: CTRL + V + Shift

A lot of time I copy and paste code. Sometimes I open multiple projects and files and copy paste code from one project file to another project file. Occasionally I have to use a copy of code which I copied two steps behind and in that case I would think hard what file did I copy it from. Well I found this cool shortcut that saves me all the trouble to recall the file name and line numbers. Usually one uses CTRL + V to paste, but if you use CTRL + V + Shift then IDEA will show the last five copies that you can choose from to paste.



7. Last Changed files: CTRL + SHIFT + E

I used SVN at work and git or Bazaar for my personal project. At times when I am not using either it can be hard to track and remember what files did I change in last 1-2 hours. Usually if you are using SVN then you can see uncommitted files to figure out the file changes. However how do you track the files that changed in the last one hour if you are not using SVN or git or mercurial tools. It turns out that IntelliJ keeps a track of your recent file changes. You can just use the shortcut CTRL + SHIFT + E to see the last edited files.



8. File Structure popup: CTRL + F12

This shortcut comes in handy if you are traversing through a huge file looking for a particular method name. You can either do CTRL + F to search for the method name. But at times you may not remember the name of the method or are not sure what methods or members are present in that file. In that case you use this shortcut.



9. Evaluate Expression : ALT + F8

This is one feature that comes in handy in the debug mode. This features allows you to quickly test the output of an expression. For ex – Say I have a method that accepts a number from user and adds 2. When you are in debug mode and need to test a program that is already running need to figure out what would happen if I add 290.756 instead of adding 2, then you would normally have to make code a change or rerun the program. Some IDEs let you do hot deploy while some do not also in a large project this restart and change may take up long time to test one expression. This is when you can use this shortcut to quickly test different expressions without restarting or making a code change.



10. System.out.println() : sout + tab

I kept the easiest and most used shortcut as the last piece. This is not really a shortcut but when I was looking for a way to avoid typing this verbose piece of code, I was surprised to see that many people did not know this fact. Unlike Netbeans or Eclipse where you can specify shortcut for commonly used text, I could not find this option in IntelliJ until I found the solution in SO. Just type sout and hit TAB to print out the complete text. ~Ciao … Enjoy the shortcuts and more.

P.S. – If you liked the post please click on one of the ads in the right hand column to help me maintain this site and do drop a me a line to suggest some topics that would like to see on this site.

Apache Camel : How to call java webservice

I have made up my mind to get rid of WSO2 ESB at my office. It is clumsy, buggy, hard to test, no body wants to work on it and the documentation is horrible. I looked at various alternative and Apache Camel was free and easy to set up and work with me.

To cut the story short, I was able to run most of the example but was struggling with CXF to call a third party service hosted. The documentation on the website is focused on exposing web service built in Camel. I was finally able to figure this out with a couple of slide show on slideshare.

Here’s the scenario: I have a third party webservice hosted on the web which gives you the the conversion rate between two currencies. I am going to call this web service and log the response.

There are two ways to call this webservice, a) Using

As usual I will start from scratch. My webservice is hosted at this url -http://www.webservicex.net/CurrencyConvertor.asmx?WSDL. This webservice exposes a operation called – “ConversionRate”.

I am using Fuse Ide(free – Developer version) but you can use Intellij Or Eclipse.

Prerequisites – Must have Maven.

Step 1: Create a new Camel-Spring project.

Step 2:  Add the following dependencies in your pom.xml. “camel-cxf”






My pom.xml looks like this –

<!–?xml version=”1.0″ encoding=”UTF-8″?>

xmlns=”http://maven.apache.org/POM/4.0.0″ xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd”>








  <name>A Camel Spring Route</name>









      FuseSource Release Repository











      FuseSource Snapshot Repository













      FuseSource Release Repository











      FuseSource Snapshot Repository






















    <!– logging –>
















    <!– testing –>

































      <!– allows the route to be ran via ‘mvn camel:run’ –>









Step 2: Under src/main.resources/META-INF folder(if not there then create one) create file called camel-context.xml.  Your camel file should like this –

<?xml version=”1.0″ encoding=”UTF-8″?>





        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd

        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd”>

  <cxf:cxfEndpoint id=”wsdlEndpoint”






  <camelContext xmlns=”http://camel.apache.org/schema/spring”>


        here is a sample which processes the input files

         (leaving them in place – see the ‘noop’ flag)

         then performs content based routing on the message using XPath</description>


        <log message=”${body}”/>


         <log message=”${body}”/>





Step 4: Place the payload or input data xml in src/data/input/order.xml. The order.xml should like this –

<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:web=”http://www.webserviceX.NET/”>









That’s it!!!!

The interesting part is all in the camel-context.xml. Here’s what is happening in this file


This line reads the file order.xml. The option noop=true makes the file to be read again and again. By default this values is false. If this value is false, then after one read, camel marks it as read and when you run the example for second time, it will not read this file.

<log message=”${body}”/>

This line will simply log the contents of order.xml.


 This line tells cxf component that it needs to call the webservice –  http://www.webservicex.net/CurrencyConvertor.asmx?wsdl

-URL – is the url of the wsdl http://www.webservicex.net/CurrencyConvertor.asmx?wsdl

  • serviceName – is the name of the service. Remember it is the name of teh service not the oepration!! The value between {} is the namespace. If you do not want to write {http://….} then add another tag xmlns   {http://www.webserviceX.NET/}CurrencyConvertor. 
  • portName – is the name of the port.

portName={http://www.webserviceX.NET/}CurrencyConvertorSoap. This is again preceded by {http://…} which is the namespace value. This value is defined in the wsdl as -<wsdl:port name=”CurrencyConvertorSoap” binding=”tns:CurrencyConvertorSoap”>

The last piece is dataFormat  – dataFormat=MESSAGE. This tells that the body is of type message.

Part 2 – In production you would want to avoid writing cxf in the above format as it is prone to error because the string value is very long and difficult to test independently and cannot be reused if you want to call the service in another route. So the best way is to define this as cxf endpoint. All you need to do is slighly modify the camel-context.xml. 

  1. Add this(be sure to remove the earlier version of <to uri=”cxf….”)

<to uri=”cxf:bean:wsdlEndpoint?dataFormat=MESSAGE”/>

  1. Define the cxf endpoint called wsdlEndpoint (You call it whatever you want).

<cxf:cxfEndpoint id=”wsdlEndpoint”





That’s it.

Now just run the app. This will print the following-

[ead #0 – file://src/data/order] route1                         INFO









[           default-workqueue-1] route1                         INFO  0.8951

~~~~ Enjoy Cameling ….

Launch Website in Amazon EC2

I wrote this blog about a year ago and left it in the draft because this post somehow was not getting auto saved on WordPress and since its long post it took time for me type, take screenshots and paste. I did not have energy and time to do it all over again. I had a copy of it though in my google drive and I cannot tell you how many times this document has helped me.

Now I have a short-term memory. I remember phone numbers which I heard 10-15 years ago but some how command line arguments, street names etc. have always been elusive. My wife keeps poking fun at me when I drive and says that I am “directionally challenged”. I just cannot remember a route. I am absent-minded, not blank, but my mind just keep thinking all the time. I follow the same route to office every day, however as it often happens that I am always lost in my thoughts, I would take I-85 South ramp instead of I-85 north ramp and I am baffled a minute or two later, at the exit signs and wonder why are the exit numbers decreasing.

Anyway the point is that this document will help some absent-minded like me who do the set up once but when something goes wrong do the research all over again and wonder what did I do the last time.

As usual I am going to start from scratch and would put this in steps.

1. Create a new Amazon web services account.

2. Go to your Console and select EC2 tab.

3. Now Lunch and instance. You will be shown a screen to select a wizard. You can choose between classic and quick wizard. The difference is that with classic wizard, you have fine grain control over what instance and software you want to install while Quick wizard is prebuilt server, for example – Ubuntu+Apache+Mysql+PHP. If you want the same instance set up on Classic wizard then you need install on your own.

I choose Classic Wizard. Click Continue.

Next I chose UBUNTU 12.04 32 bit.

Next choose your instance. I choose Micro instance.


You can also chose Request Spot Instance where you basically requests your own quote and can specify the largest amount that you intend to pay. Something like price negotiator.

Click Continue

Click Continue.

Next name your instance and click Continue.

Next create a Key-Value pair. Name your key and click Create and Download your Key Pair


Save the key on your local system and click continue.

Next configure your security settings. It will be named  quick-launch by default  with port 22 for sftp open. You can add more ports if you like. I added port 80(Http) and 443(Https).

Now you are ready to launch your server.

A confirmation page lets you know your instance is launching. Click Close to close the confirmation page.

In the Navigation pane, click Instances to view the status of your instance. It takes a short time for an instance to launch. The instance’s status will be pending while it’s launching.

Record the Public DNS name for your instance because you’ll need it for the next task. If you select the instance, its details (including the public DNS name) are displayed in the lower pane. You can also click Show/Hide in the top right corner of the page to select which columns to display.


4. Connecting to your Linux instance

Just Right click and click Connect…. It will give you option to connect via ssh or java client. Choose java client. For Ubuntu, the user name is ubuntu. Specify the location of your  key-value pair that you downloaded earlier. Hit Connect. You are now connected.

5. Update ubuntu packages. Run this command -

apt-get update

apt-get upgrade –show-upgraded

6. Now we already have default user “ubuntu”. However I wanted to create my username. So create one -

sudo adduser example_user

You will be asked several questions like Full Name, Room number etc. Just click Enter and continue

Enter the new value, or press ENTER for the default

    Full Name []:

    Room Number []:

    Work Phone []:

    Home Phone []:

    Other []:

Is the information correct? [Y/n] y

7. Now we need to allow this new user to administer the system. So to do this we need to give it admin rights. Run this:

sudo usermod -a -G sudo example_user

8. Install Git

sudo apt-get install build-essential git-core curl

9. Install RVM to support different version of Ruby.

curl -L get.rvm.io | bash -s stable

10. Add RVM to bashrc

echo ‘[[ -s “$HOME/.rvm/scripts/rvm” ]] && source “$HOME/.rvm/scripts   /rvm”‘ >> ~/.bashrc

11. Reload bashrc file

. ~/.bashrc

12. Now exit from the session and type

type rvm| head -1

This will give you a message that “rvm is a function”

13. Next we will install ruby.

rvm install 1.9.3

14. Use ruby 1.9.3 as default

rvm –default use 1.9.3

15. To check the version of ruby-

ruby -v

This should tell you that you are using – “ruby 1.9.3p194”

16. Let’s install RAILS now.

gem install rails -v 3.2.1

Now you may run into issue and get this error

ubuntu@domU-12-31-39-09-84-B8:~$ gem install rails -v 3.2.1

ERROR:  Loading command: install (LoadError)

cannot load such file — zlib

ERROR:  While executing gem … (NameError)

uninitialized constant Gem::Commands::InstallCommand

If you get this error that do not worry, it is just telling you that you need to install some more packages.

Run these commands:

rvm pkg install zlib

rvm remove 1.9.3

rvm install 1.9.3

rvm –default use 1.9.3

gem install rails -v 3.2.1

17.  Time to install Mysql

sudo apt-get update

sudo apt-get upgrade –show-upgraded

sudo apt-get install libmysqlclient-dev

sudo apt-get install mysql-server

You will be prompted with Mysql installation screen. Just follow the instructions to set up root user name and password.

18. Update the git configuration

git config –global user.name “Firstname Lastname”

git config –global user.email “your_email@youremail.com

19) Install passenger and Nginx

gem install passenger


If you run into issues then run the following

apt-get install libopenssl-ruby

apt-get install libcurl4-openssl-dev

apt-get install libssl-dev

If you still run into issues where the installation instructions says that openssl-dev is not installed then run this command

rvm pkg install openssl

rvm remove 1.9.3

rvm install 1.9.3

rvm –default use 1.9.3

rvmsudo passenger-install-nginx-module  //You have to use rvmsudo if you are not logged in as root.

20) Download the code from now. To do that you need to create new ssh key and set it up on github.

ssh-keygen -t rsa -C “Your-emial-address@youremial.com”

- Copy the key value from /root/.ssh/id_rsa.pub and copy the key in your git hub account.(If you do not know how to add ssh key then see github help document. Basically just goto github settings–> ssh-keys–> Add Key)

- Now create your app folder. I created mine under /home/apps/. Now go to apps folder and run this command in terminal – git clone git@……….xxxx.git (Your git url).

21) Now we will install bundler.

Switch to your application folder, such as – cd /home/apps/albums and run the command

 gem install bundler

 bundle install

Ran into error below for Rmagick gem

Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.

    /home/ubuntu/.rvm/rubies/ruby-1.9.3-p194/bin/ruby extconf.rb

checking for Ruby version >= 1.8.5… yes

extconf.rb:128: Use RbConfig instead of obsolete and deprecated Config.

checking for gcc… yes

checking for Magick-config… no

Can’t install RMagick 2.13.1. Can’t find Magick-config in /home/ubuntu/.rvm/gems/ruby-1.9.3-p194/bin:/home/ubuntu/.rvm/gems/ruby-1.9.3-p194@global/bin:/home/ubuntu/.rvm/rubies/ruby-1.9.3-p194/bin:/home/ubuntu/.rvm/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

*** extconf.rb failed ***

Could not create Makefile due to some reason, probably lack of

necessary libraries and/or headers.  Check the mkmf.log file for more

details.  You may need configuration options.

Provided configuration options:











Gem files will remain installed in /home/ubuntu/.rvm/gems/ruby-1.9.3-p194/gems/rmagick-2.13.1 for inspection.

Results logged to /home/ubuntu/.rvm/gems/ruby-1.9.3-p194/gems/rmagick-2.13.1/ext/RMagick/gem_make.out

An error occured while installing rmagick (2.13.1), and Bundler cannot continue.

Make sure that `gem install rmagick -v ‘2.13.1’` succeeds before bundling.

If you get the same error for Rmagick or Mysql or anything else, then run the below command.

sudo apt-get install libmagickwand-dev

Now re run the command

bundle install

22) Starting up the passenger now. However before we start passenger we need make sure that our database exist. So let’s create database and do the database migrations. Run the below commands -

rake db:create

rake db:migrate //// Now this will not create a production db, but will create dev, test db for you. If you intend to create a production DB as well then run this command -

RAILS_ENV=production rake db:create

RAILS_ENV=production rake db:migrate

I ran into issue and got the below error -

rake aborted!

Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes.

The forums said that I need to install nodeJs. So here’s the list of command to install nodeJs.

 sudo apt-get install python-software-properties

 sudo add-apt-repository ppa:chris-lea/node.js

 sudo apt-get update

 sudo apt-get install nodejs

Now the last thing you need to before starting passenger is pre compile your assets(css, images, js etc.). If you do not do this you will not be able to see the images and css. So run this command

bundle exec rake assets:precompile

Oh by the way if your images are not being served even after running the above command and starting passenger then you need to read my other post - http://railgaadi.wordpress.com/2012/01/28/engineyard-rails-3-x-nginx-passenger-assets-not-displayed/

P.S> The above issue is pretty common and first time user who are trying to promote run into the above issue and give up eventually. I stopped looking at it after 2 days… took a 3 day break and attacked the issue again :-)

Now start the passenger.(Make sure that you have started Nginx  before starting Passenger else… see my earlier post – http://railgaadi.wordpress.com/2012/01/28/engineyard-rails-3-x-nginx-passenger-assets-not-displayed/)

passenger start -e production

I got error that “can’t connect to mysqlserver through socket tmp/mysql.sock”. If you run into this server then run this command

 mysqladmin variables | grep socket

If you have a root password then use

sudo mysqladmin -p variables | grep socket

The above command will give you socket name. In my case it gave me /tmp/var/mysq.lock.

Note this value and update your database.yml file and update the socket as given below.

 adapter: mysql2
 host: localhost
 username: root
 password: xxxx
 database: xxxx
 socket: /tmp/mysql.sock

After you have updated the database.yml file you should be able to start the passenger.

23) Setting up NGINX

Make sure that you nginx.conf under /opt/nginx/conf file’s server section looks like this

server {

    listen    80;

    server_name  www.mysitename.com;

    access_log /srv/www/mysitename.com/logs/access.log;

    error_log /srv/www/mysitename.com/logs/error.log;

    root /home/myapp/album/public;

    passenger_enabled on;

    passenger_base_uri /home/myapp/album/public;

    #This property allows you to upload huge pictures files else you will get error 413- File too large

    client_max_body_size 5M;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

#    location / {

 #       root   /home/dinesh19aug/album/public;

 #       index  index.html index.htm;

 #   }

Happy launching :-)

In case you are wondering what did I launch —- P.S. If you have been following my blog it’s my wife’s photography website. Wifeys website


P.S. – Look forward for my first hand experience with Node.js in the next post.

How to configure JNDI with Spring and Jboss4/5

This is a simple process but if you try and search on the web you will come across various incomplete solutions which will leave you more confused than you already were. This configuration involves just four simple steps that I will walk through to help you set up JNDI on Jboss. I am using Jboss 4.3, but this should be valid for other version of Jboss as well.

I have a web application which is built on Spring 3.2 and uses Hibernate 4. To set up a new JNDI configuration we will first create a datasource xml file. This file needs to be deployed in Jboss/Deploy folder along with your war file.

Step 1:

Create a datasource file oracle-ds.xml. The content of the file will look like this

<?xml version=”1.0″ encoding=”UTF-8″?>

<!DOCTYPE datasources PUBLIC “-//JBoss//DTD JBOSS JCA Config 1.5//EN” “http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd”>


















Explanation: <jndi-name>jdbc/listener-dss</jndi-name> . This line tells what is the jndi name that we are going to use across configuration files.


Step 2: Now open your web.xml file and add the resource-ref. This tells that jee container that your web application is using JNDI.

Your web.xml should be under WEB-INF folder. Add the below lines in your web.xml (see the highlighted section). This step is common whether you use Jboss or Tomcat or Websphere or any other application server.


<?xml version=”1.0″ encoding=”UTF-8″?>

<web-app version=”2.5″ xmlns=”http://java.sun.com/xml/ns/javaee” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”



  <display-name>ACN Web Application</display-name>


















        <description>Listener Database</description>
















Step 3: Next we will update the Spring context xml file to tell the Spring container that it needs to do a JNDI look up. My Spring context file name is listener-servlet.xml and this is under WEB-INF folder. Add the following(See highlighted section)


<beans xmlns=”http://www.springframework.org/schema/beans”


       xmlns:mvc=”http://www.springframework.org/schema/mvc” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”










        http://www.springframework.org/schema/tx/spring-tx.xsd “>

    <context:component-scan base-package=”com.acn.cslistener” />

    <mvc:annotation-driven />




        <property name=”prefix”>



        <property name=”suffix”>




    <bean id=”sessionFactory” class=”org.springframework.orm.hibernate4.LocalSessionFactoryBean”>

        <property name=”dataSource” ref=”dataSource”/>

        <property name=”hibernateProperties”>


                <prop key=”hibernate.dialect”>org.hibernate.dialect.Oracle10gDialect</prop>

                <prop key=”hibernate.show_sql”>true</prop>



        <property name=”packagesToScan” value=”com.acn.cslistener” />


    <bean id=”dataSource” class=”org.springframework.jndi.JndiObjectFactoryBean”>

        <property name=”jndiName” value=”java:comp/env/jdbc/listener-dss”/>


    <bean id=”transactionManager” class=”org.springframework.orm.hibernate4.HibernateTransactionManager”



    <bean id=”persistenceAnnotation”    class=”org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor” />



Step 4: This is the crucial step. If you are using Jboss then it requires that you tell the web container that Jboss will provide the datasource .xml file where you have defined your jndi properties. Create a new file jboss-web.xml. Place this file under WEB-INF folder. The contents of the file whould like this.

<?xml version=”1.0″ encoding=”UTF-8″?>








That’s all we need to do.


~~~~ Ciao. 


Rails: Jquery is not loading

It’s been a while I have posted anything. I have been extremly busy and have been working on an extremely critical project where we were asked to become PCI 2.0 compliant. I worked on some interesting problems however today I will be discussing on something trivial and discuss my frustration about Rails. I have to admit that a number of times I thought I should just give up and start learning Python or stick to my forte i.e. Java. BUT Ruby/Rails has been a love hate relationship for me. Every few months I pick up Rails again and struggle fixing the set up before I can start working on my website.

So a couple of months back my wife complained that she is not using her website to update client’s picture because there is no client login and the if she upload their album, the album is visible to everyone. So I fixed that and deployed the application. No issues.

So two months later about a week ago, I checked again with her and like all nagging wife she complained that she is still not using it because she cannot upload multiple images. So like a dutiful husband I set out to set up rails on my new mac and begin coding however my production branch was not working fine. I was seeing issue with flexslider and found that non of my images were not showing up and Rails complained that JQuery was not defined. I tried everything but I could not make it work.

So if you have been issues with JQuery make sure that you have checked these things:

1. Your gem file should have this line.

   gem ‘jquery-rails’
gem “flexslider”  — This if you are using flexslider

2. In your application.js, make sure that you have defined jquery and the most important thing …… notice the sequence.

//= require jquery_ujs
//= require jquery
//= require flexslider
//= require_tree .

My sequence was incorrect and I had defined juqery before jquery_ujs which was throwing error in my application.

Hope this post helps.





How to post parameters to a url using Ajax/Javascript between two website

I am working a new project and I recently ran into an interesting problem. One of the web site that I keep up at work was supposed to take the user to another website which required me to add post parameters.

EX – www.mywebsite.makeapayment.com ==> Collects Billing information ex – name, amount, address etc.==> Post this information to www.vendor-website.com.

I did not realize the problem until I started coding and my colleague pointed out that as soon as www.mywebsite.makeapayment.com goes to my servlet, the servlet will not pass params to external web site if use “POST”, I had to use “GET” because servlet will look up relative path only and the HTTPServletRequest/Response object is specific to an application. So if I wanted to send parameters using servlet I could only that using action = GET. Now since I was passing sensitive information so I did not want to use GET.

A couple of solutions were discussed as follows:

1. Insert the params in database and use servlet get from the mywebsite.com to pass the primary key of the database. Ex – www.mywebsite.makeapayment.com ==>  www.vendor-website.com?key=10001. The vendor application look up the required params from the database.

2. Create a new JSP and use JavaScript onLoad() to pass the params as Hidden Input and submit as post to  www.vendor-website.com.

Ex – www.mywebsite.makeapayment.com==> Servlet==> New Blank JSP with Hidden params loaded on onLoad() and submitted to vendor website ==> www.vendor-website.com.

3. Third approach is interesting and I had not tried this ever but looked promising and this is what I eventually implemented. Make an Ajax call to from the JSP page to your servlet and when the Ajax Call returns, post it to vendor web site.

Ex – www.mywebsite.makeapayment.com on hitting submit==> calls the JS, uses DWR to post to call the servlet==> Servlet does back ground processing like saving the records etc ==> Returns the control back to the JavaScript ==> Upon return in Ajax Call ==> Post to www.vendor-website.com.

I implemented the combination of one and three but here I am going to show you how post params to a different URL – i.e. solution 3

Let’s say I have a submit form with Name and address which needs to be saved in database when I submit the form and then I need to post the same information to different web site.





       // I am not showing the code for DWR. You will need to include dwr and engine.js. Add dwr.xml in your web-inf and specify the class name and method you want to use as dwr call. This method is called in the dwr Ajax call back.

function submitAndGoToVendorSite()
var form = document.createElement(“FORM”);
form.method = “POST”;
form.style.display = “none”;
var url=”www.vendor-website.com”;
form.action = url;

            //My dwr ajax call gets a Json string from the servlet response.
var jsonString =      ‘{“transactionId”:”1368505156670″,”requesterType”:”APP”,”billingEmail”:”null@cybersource.com”,”billingState”:”NC”,”amount”:”42.7699999999999999433786257441170164384″,”refund”:”N”,”billingCity”:”CONCORD”,”billingLine1″:”Progress Pl”,”billingFirstname”:”test”,”billingLine2″:””,”shopperIP”:”″,”application”:”OEP2″,”currencyCode”:”USD”,”billingCompany”:”ACN”,”revenueSource”:””,”billingLastname”:”test”,”countryCode”:”US”,”billingAddrNum”:”1000″,”cardType”:”VISA”,”businessPurpose”:”TOOL”,”profileConfig”:”cybersource-MLTEST1″,”language”:”en”,”billingZip”:”28025″,”repOrCustID”:”1233836″,”user”:”DARORATEST”,”paymentMethod”:”CC”,”billingPhone”:””}’

     // Create a JSON object from the JSON String

     var jsonObj = jQuery.parseJSON(jsonString);

//Iterate over Json object and set them as hidden input params to the form
for(obj in jsonObj){
var input = document.createElement(“INPUT”);
input.type = “hidden”;
input.name = obj;
input.value = jsonObj[obj];

//Submit the form





            <label>Name:</label><Input type=”text”/>


            <input type=”button” onclick=”submitAndGoToVendorSite();”/>



That’s It!

~Keep Coding