Wednesday, March 26, 2014

C# Using Moq to mock out parameters on a void method

It has been a long time since I posted any article on my blog. Today presented an interesting scenario where I wanted to mock out a void method that accepted out parameters. The void method does not explicitly return anything but implicitly modify the parameters so there has to be a callback method attached.

Normally, with return methods you'd do something like:
mockObject.Setup(x => x.GetSomething(It.IsAny<string>)).Returns("Whatever");

But with a void method, we do not return anything but still don't want a NullReferenceException to be thrown. So we do something like:
mockObject.Setup(x => x.DoVoid(It.IsAny<object>)).Verifiable();

Please note that I am passing parameters in both methods above just to build up to the actual problem at hand.

So what if we want to pass out parameter? Can we do something like
It.IsAny<List<Person>>()

?

Nope. Ref and out parameters need to be initialized. That takes care of part of the problem.
var myList = new List<Person>();

//Arrange
mockObject.Setup(x => x.GetAllIdiots(out myList)).Returns(null);

Now, what if we have a void method and want to modify something within the method. After all, that's why we use the out and ref parameters.

So we add a callback method. Here's how to do it:
//initialize the out object
var myList = new List<Person>();

//Arrange
mockObject.Setup(x => x.DoVoid(out myList))
.Callback<(List<Person>)>((person) =>
{

//feel free to do whatever here..
});

There you go. Simple. Easy. The variable within the callback can be named anything.

Tuesday, April 9, 2013

Adoption of Agile and Atlassian

Over the past two or three years we have seen companies moving towards adopting Scrum or other variations of agile development. I think the main reasons for this has been to give clients more control over the software that is being developed while having the ability to look at the competitors and apply the changes as seen necessary. This is even truer for products that take more than 6 months from conception to delivery.

Back in late 90s – before the dot com bubble burst – anyone who could write simple HTML could quickly write web pages and in the short term hope to make a lot of money. People did not care about the quality of their products as long as they had it out there. But after that bubble burst, with more and more companies failing, companies started to take software development more seriously. One of the things that came out, although it present decades ago, was adoption of rigid waterfall methodology in software development.

Although, waterfall methodology has its own strengths in documentation, strict scheduling and planning and fixed budget, these last two strengths ultimately becomes its weakness as the complexities of projects grow. This problem increases even more so for lengthier projects. With agile on the other hand, while the problems do not just go away, they’re at the very least addressed. For example, instead of defining all the functions today for a product to be delivered 18 months down the road, we will only look at what can be done within the next sprint. It does not mean that the goal of the project is not understood or unimportant. It just means we’re not cramming our developers, architects, project managers and product owners today with what isn’t possible to do. Instead we want to deliver the client the most important part of the project early so if unforeseen changes are necessary, we can do it early. Changes later in the lifecycle of traditional methodologies mean lots of man hours.

Now how agile fits into Atlassian’s  products is summed up by two words – “Continuous Integration”. Back in 2010 when I worked on project called Project Management Office Dashboard, I was working on integrating JIRA with the PMO Dashboard with the help of Greenhopper’s remote API. We were using Scrum and we needed to be able to streamline JIRA and PMO so that users could access JIRA from within PMO dashboard. While we were working on this, the other tools came in handy such as Crucible for code review. Code review is one of best practices of agile. If we’re writing code and checking in every couple hours with the help of Bamboo (another Atlassian tool) build server, we sure want the code to be reviewed as frequently even if the builds are successful.

So in brief, adoption of agile and using Atlassian tools go hand-in-hand. In the coming years, I am sure there will be some form of agile development and at least a handful of Atlassian set of tools used by most IT companies all over the globe.

Friday, March 1, 2013

Hibernate connection issue with CentOS, MySQL & Tomcat 7

If you are working on CentOS and MySQL, you will want to make sure you verify your connection after the application has been left untouched for some time. Without trying to verify connection you'll end up with a stack trace complaining "Could not open Hibernate Session...". Surprisingly this does not happen on Windows with the same configuration. I am using commons-dbcp.jar and commons-pool.jar. Here is my configuration -

<!--  Define dataSource to use -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${hibernate.jdbc.driver}" />
<property name="url" value="${hibernate.jdbc.url}" />
<property name="username" value="${hibernate.jdbc.user}" />
<property name="password" value="${hibernate.jdbc.password}" />
</bean>

<!--  The sessionFactory will scan the domain objects and their annotated relationships. -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--  Packages to scan probably works but I will use xml definitions -->
<!--
<property name="packagesToScan">
<list>
<value="com.d2.tej.domain" />
<value="com.d2.tej.dao.impl" />
<value="com.d2.tej.service.impl" />
</list>
</property>
-->
<property name="annotatedClasses">
<list>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.AdminUser</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.AdminLogin</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.Code</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.Patient</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.PatientDetail</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.PodType</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.PodTypeContent</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.Practice</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.Procedure</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.Surgeon</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.Subscription</value>
</list>
</property>
<property name="schemaUpdate" value="true" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.connection.isolation">2</prop>
<prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
<!-- <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>-->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
<!-- org.hibernate.dialect.MySQLMyISAMDialect, org.hibernate.dialect.MySQLDialect, org.hibernate.dialect.MySQLInnoDBDialect -->
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.max_fetch_depth">2</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<!--connection pool-->
<prop key="hibernate.dbcp.maxActive">10</prop>
<prop key="hibernate.dbcp.whenExhaustedAction">1</prop>
<prop key="hibernate.dbcp.maxWait">20000</prop>
<prop key="hibernate.dbcp.maxIdle">10</prop>

<!-- prepared statement cache-->
<prop key="hibernate.dbcp.ps.maxActive">10</prop>
<prop key="hibernate.dbcp.ps.whenExhaustedAction">1</prop>
<prop key="hibernate.dbcp.ps.maxWait">20000</prop>
<prop key="hibernate.dbcp.ps.maxIdle">10</prop>

<!-- optional query to validate pooled connections:-->
<prop key="hibernate.dbcp.validationQuery">select 1</prop>
<prop key="hibernate.dbcp.testOnBorrow">true</prop>
<prop key="hibernate.dbcp.testOnReturn">true</prop>

</props>
</property>
<!--If you want to configure any listeners for any event this is the place to do.  -->
<!--
<property name="eventListeners">
<map>
<entry key="delete">
<bean class="com.tej.core.hibernate.listener.DeleteEventListener" />
</entry>
</map>
</property>
-->
</bean>

Saturday, January 19, 2013

5 Steps to Improve Your Java App’s Performance with New Relic



Overview


The New Relic is a must-have tool when it comes to tuning and monitoring your java web application. The plugin is trivial to install on your application server and once your application is deployed and your app server restarted to take effect, you will quickly have access to a very informative dashboard (see Figure 1). Although the New Relic allows you to monitor different stacks – Servers, Applications, Transactions and Real-time user experience monitoring, while all the stacks are equally important, we’ll be focusing on the Application stack. I will also briefly explain the Transactions stack as this is a new feature that fits well for our tuning purpose.

Application Stack - Dashboard view


The Applications stack in the dashboard displays the applications that are deployed. On the right hand side recent events are displayed. These are important as they list out Alert notifications which are based on customizable parameters, Apdex score which is based on application’s throughput and is also customizable, Critical problems such as Error rate, Downtime and any recent activities performed on the dashboard such as updating application settings. Clicking on any of these notifications will allow you to drill down to view detailed, graphical reports. We should now click on the application name (OPD) in order to set performance monitoring parameters and analyze them.

Dashboard

Figure 1: Dashboard View of Sample Web Application – OPD



Tuning the Application


All of our work for this tutorial is managed under the Monitoring tab. The 5 steps we will be focusing on are –

i.            Database operations – operations that are most time consuming.

ii.            Web transactions – APDEX most dissatisfying.

iii.            Profiling JVM – CPU burn broken down by web requests.

iv.            External Services - Total Response time of external services.

v.            Transactions – Closely monitor ‘key’ web transactions with more precision.

Please note that I have selected only one of the many tuning parameters available on each of the tuning steps.  The last step is found under the Transactions stack.

Database Operations – operations that are most time consuming


Probably, the most important area of tuning a web application apart from the code itself is the database. Here we want to look at database operations (Select, Update, Insert, Delete) that are most time consuming. Figure 2 below shows that ‘SELECT’ queries against table ‘patient_detail’ are being made 45% of the time. When we combine this information with the response time and throughput graph on the right, we will be able to flag this. In this instance, the throughput is less than 2ms. So we’re good. Additionally, we can also examine what pages/resources (jsps, filters, interceptors, etc.) are making this database call.

Database_Operation_Most_Time_Consuming

Figure 2: Database Operations sorted by ‘Most time consuming’ filter



Web transactions – APDEX most dissatisfying transactions


APDEX or Application Performance Index takes into account averages of response times of each transaction and gives insight about user satisfaction. This is useful in determining what web transactions are taking exponentially longer than others and resulting in user dissatisfaction. Figure 3 shows that ‘/login’ needs to be looked into immediately as it is consuming 88% of the overall wall clock time. At the bottom right we can see ‘App server transaction traces’ that show two separate instances of request made to ‘/login’ took over 6.5 seconds.

Web_Transactions_Apdex_most_dissatisfying

Figure 3: APDEX ‘Most dissatisfying’ web transactions



Profiling JVM – CPU burn broken down by web requests


We can also profile the JVM to look at CPU burn broken down by web requests to view what requests are hogging the CPU. We can then look at that specific part of the code to further examine. Figure 4 displays a sample profile output. There isn’t request that is really hogging the CPU. So we’re good here.

Profile_JVM_CPU_burn

Figure 4: JVM Profiling for CPU burn filtered by Web Requests



External Services - Total Response time of external services


If we have any REST or WS* web service calls or remote messaging, we can view the response times of those external services to see if any of the calls are taking longer than our specified APDEX. To an end user these external services should feel like making a request to any other web transaction. Although our sample application does not make any external service calls, you can easily view these from the ‘External services’ sub tab under the ‘Monitoring’ tab.

Transactions – Closely monitor ‘key’ web transactions with more precision


The new ‘Transactions’ stack allows monitoring of the most important assets of the application. Under the hood this is similar to identifying slow response time for a web transaction. The added benefit of using this is we can view more detailed graph with all the resources associated with the transaction. For example, I’ve created a ‘Security Check’ transaction to monitor the authentication and authorization process of spring security framework.  In figure 5, we can see response times of different filters in the filter chain. Notice also the error rate is very high at around 11:45am till noon. We can view the application server’s log for that period of time to see what is going on.

Track_Key_Transactions

Figure 5: Key Transactions



Summary


All of the steps we took in improving our java application’s performance are only fraction of what we can do with New Relic. Also, the application could easily have been an asp.net application. We can also monitor the server stack in addition to the application stack to get a better picture of how our application(s) make use of the server resources such as I/O, RAM and CPU.

Saturday, October 13, 2012

Snakes and Ladders in Java Swing

Overview

We all know what 'Snakes and ladders' game is all about. In this artice, I am going write a Java Swing based game for two players. Before I begin, in case my rules for the game are different, I want explain this first. If you want to quickly jump over to the solution click here.

Rules of the game

The game has multiple players where players take turns to roll dice.
If on any player's turn the number on the dice is '1' or '6', the player's token moves forward to that many places (1 or 6) and also gets to throw one more time.
To start the game itself, a player needs to roll 1 or 6. This moves the token to the start position on the board or 1. The player again gets to throw.
If a player's token lands on the bottom of a ladder, the token moves to the top of the ladder (always greater than the current position).
Conversely, if the player's token lands on snake's mouth, then token moves to the tail of the snake (always less that the current position).
Whoever gets to the last number or greater wins. I know this logic is a bit off from the regular game where the player's token needs to land on the exact 'final' number in order to win or the token just moves the remaining position backwards.

Technical Requirements

We need a main GUI where the board is visible and allows users to see where their tokens are.
Players need to be created and their current token position maintained.
Users also need to be able to click on a "Roll Dice" button.
Every "roll" needs to randomly generate values from 1 through 6 only.
The tokens need to move to the correct position on the grid/board.
When a player's token reaches the final number in the board, a message should be printed indicating which player won and the game should then stop.
Users should be able to start the game by clicking the top menu on "File -> New game" .

Solution

Create a new Swing Application and add a FrameView. I called it SnakesAndLadderView. The snippet below shows the initizalization of the Swing application. Notice the class variables Player: Player1 and Player: Player2. I will come to this later. This takes care of our first requirement.
package snakesandladder;
import java.awt.Color;
import java.awt.Graphics;
import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import snakesandladder.domain.Player;
/**
* The application's main frame.
*/
public class SnakesAndLadderView extends FrameView {
private Player currentPlayer;
Player player1 = new Player("red", "Player1");
Player player2 = new Player("yellow", "Player2");
boolean canRollAgain;
private javax.swing.JButton btnRoll;
private javax.swing.JLabel lblDiceValue;
private javax.swing.JLabel lblMain;
private javax.swing.JLabel lblPlayer1;
private javax.swing.JLabel lblPlayer2;
private javax.swing.JPanel mainPanel;
private javax.swing.JMenuBar menuBar;
private javax.swing.JMenuItem newGameMenuItem;
private javax.swing.JPanel pnlGame;
private javax.swing.JLabel statusAnimationLabel;
private javax.swing.JLabel statusMessageLabel;
private javax.swing.JPanel statusPanel;
private javax.swing.JTextField txtStatus;
// End of variables declaration
private final Timer messageTimer;
private final Timer busyIconTimer;
private final Icon idleIcon;
private final Icon[] busyIcons = new Icon[15];
private int busyIconIndex = 0;
private JDialog aboutBox;
/**
* @return the currentPlayer
*/
public Player getCurrentPlayer() {
return currentPlayer;
}
/**
* @param currentPlayer the currentPlayer to set
*/
public void setCurrentPlayer(Player currentPlayer) {
this.currentPlayer = currentPlayer;
}
public SnakesAndLadderView(SingleFrameApplication app) {
super(app);
initComponents();
this.pnlGame.setVisible(false);
this.btnRoll.setVisible(false);
this.txtStatus.setVisible(false);
this.lblPlayer1.setVisible(false);
this.lblPlayer2.setVisible(false);

// status bar initialization - message timeout, idle icon and busy animation, etc
ResourceMap resourceMap = getResourceMap();
int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
messageTimer = new Timer(messageTimeout, new ActionListener() {
public void actionPerformed(ActionEvent e) {
statusMessageLabel.setText("");
}
});
messageTimer.setRepeats(false);
int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
for (int i = 0; i < busyIcons.length; i++) {
busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
}
busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {
public void actionPerformed(ActionEvent e) {
busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
}
});
idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
statusAnimationLabel.setIcon(idleIcon);
// progressBar.setVisible(false);
// connecting action tasks to status bar via TaskMonitor
TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
public void propertyChange(java.beans.PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if ("started".equals(propertyName)) {
if (!busyIconTimer.isRunning()) {
statusAnimationLabel.setIcon(busyIcons[0]);
busyIconIndex = 0;
busyIconTimer.start();
}
// progressBar.setVisible(true);
// progressBar.setIndeterminate(true);
} else if ("done".equals(propertyName)) {
busyIconTimer.stop();
statusAnimationLabel.setIcon(idleIcon);
//progressBar.setVisible(false);
// progressBar.setValue(0);
} else if ("message".equals(propertyName)) {
String text = (String) (evt.getNewValue());
statusMessageLabel.setText((text == null) ? "" : text);
messageTimer.restart();
} else if ("progress".equals(propertyName)) {
int value = (Integer) (evt.getNewValue());
// progressBar.setVisible(true);
// progressBar.setIndeterminate(false);
// progressBar.setValue(value);
}
}
});

}
@Action
public void showAboutBox() {
if (aboutBox == null) {
JFrame mainFrame = SnakesAndLadderApp.getApplication().getMainFrame();
aboutBox = new SnakesAndLadderAboutBox(mainFrame);
aboutBox.setLocationRelativeTo(mainFrame);
}
SnakesAndLadderApp.getApplication().show(aboutBox);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
mainPanel = new javax.swing.JPanel();
pnlGame = new javax.swing.JPanel();
lblMain = new javax.swing.JLabel();
menuBar = new javax.swing.JMenuBar();
javax.swing.JMenu fileMenu = new javax.swing.JMenu();
newGameMenuItem = new javax.swing.JMenuItem();
javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
javax.swing.JMenu helpMenu = new javax.swing.JMenu();
javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
statusPanel = new javax.swing.JPanel();
javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
statusMessageLabel = new javax.swing.JLabel();
statusAnimationLabel = new javax.swing.JLabel();
txtStatus = new javax.swing.JTextField();
btnRoll = new javax.swing.JButton();
lblPlayer1 = new javax.swing.JLabel();
lblPlayer2 = new javax.swing.JLabel();
lblDiceValue = new javax.swing.JLabel();
mainPanel.setMaximumSize(new java.awt.Dimension(583, 560));
mainPanel.setMinimumSize(new java.awt.Dimension(583, 560));
mainPanel.setName("mainPanel"); // NOI18N
pnlGame.setMaximumSize(new java.awt.Dimension(583, 560));
pnlGame.setName("pnlGame"); // NOI18N
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(snakesandladder.SnakesAndLadderApp.class).getContext().getResourceMap(SnakesAndLadderView.class);
lblMain.setBackground(resourceMap.getColor("lblMain.background")); // NOI18N
lblMain.setIcon(resourceMap.getIcon("lblMain.icon")); // NOI18N
lblMain.setText(resourceMap.getString("lblMain.text")); // NOI18N
lblMain.setName("lblMain"); // NOI18N
javax.swing.GroupLayout pnlGameLayout = new javax.swing.GroupLayout(pnlGame);
pnlGame.setLayout(pnlGameLayout);
pnlGameLayout.setHorizontalGroup(
pnlGameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlGameLayout.createSequentialGroup()
.addGap(27, 27, 27)
.addComponent(lblMain, javax.swing.GroupLayout.PREFERRED_SIZE, 506, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(30, Short.MAX_VALUE))
);
pnlGameLayout.setVerticalGroup(
pnlGameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlGameLayout.createSequentialGroup()
.addComponent(lblMain, javax.swing.GroupLayout.DEFAULT_SIZE, 538, Short.MAX_VALUE)
.addContainerGap())
);
javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
mainPanel.setLayout(mainPanelLayout);
mainPanelLayout.setHorizontalGroup(
mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(mainPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(pnlGame, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
mainPanelLayout.setVerticalGroup(
mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(mainPanelLayout.createSequentialGroup()
.addComponent(pnlGame, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
menuBar.setDoubleBuffered(true);
menuBar.setMaximumSize(new java.awt.Dimension(62, 21));
menuBar.setMinimumSize(new java.awt.Dimension(62, 21));
menuBar.setName("menuBar"); // NOI18N
fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
fileMenu.setName("fileMenu"); // NOI18N
javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(snakesandladder.SnakesAndLadderApp.class).getContext().getActionMap(SnakesAndLadderView.class, this);
newGameMenuItem.setAction(actionMap.get("startGame")); // NOI18N
newGameMenuItem.setText(resourceMap.getString("newGameMenuItem.text")); // NOI18N
newGameMenuItem.setName("newGameMenuItem"); // NOI18N
fileMenu.add(newGameMenuItem);
exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
exitMenuItem.setName("exitMenuItem"); // NOI18N
fileMenu.add(exitMenuItem);
menuBar.add(fileMenu);
helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
helpMenu.setName("helpMenu"); // NOI18N
aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
aboutMenuItem.setName("aboutMenuItem"); // NOI18N
helpMenu.add(aboutMenuItem);
menuBar.add(helpMenu);
statusPanel.setMaximumSize(new java.awt.Dimension(583, 82));
statusPanel.setMinimumSize(new java.awt.Dimension(583, 82));
statusPanel.setName("statusPanel"); // NOI18N
statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N
statusMessageLabel.setName("statusMessageLabel"); // NOI18N
statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N
txtStatus.setText(resourceMap.getString("txtStatus.text")); // NOI18N
txtStatus.setName("txtStatus"); // NOI18N
btnRoll.setText(resourceMap.getString("btnRoll.text")); // NOI18N
btnRoll.setName("btnRoll"); // NOI18N
btnRoll.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnRollActionPerformed(evt);
}
});
lblPlayer1.setIcon(resourceMap.getIcon("lblPlayer1.icon")); // NOI18N
lblPlayer1.setText(resourceMap.getString("lblPlayer1.text")); // NOI18N
lblPlayer1.setName("lblPlayer1"); // NOI18N
lblPlayer2.setIcon(resourceMap.getIcon("lblPlayer2.icon")); // NOI18N
lblPlayer2.setText(resourceMap.getString("lblPlayer2.text")); // NOI18N
lblPlayer2.setName("lblPlayer2"); // NOI18N
lblDiceValue.setText(resourceMap.getString("lblDiceValue.text")); // NOI18N
lblDiceValue.setName("lblDiceValue"); // NOI18N
javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
statusPanel.setLayout(statusPanelLayout);
statusPanelLayout.setHorizontalGroup(
statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(statusPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(statusMessageLabel)
.addGroup(statusPanelLayout.createSequentialGroup()
.addComponent(txtStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(lblDiceValue, javax.swing.GroupLayout.PREFERRED_SIZE, 157, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblPlayer1)
.addComponent(lblPlayer2))
.addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(statusPanelLayout.createSequentialGroup()
.addGap(122, 122, 122)
.addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 24, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, statusPanelLayout.createSequentialGroup()
.addComponent(statusAnimationLabel)
.addContainerGap())))
.addGroup(statusPanelLayout.createSequentialGroup()
.addGap(18, 18, 18)
.addComponent(btnRoll, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())))))
);
statusPanelLayout.setVerticalGroup(
statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(statusPanelLayout.createSequentialGroup()
.addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(statusPanelLayout.createSequentialGroup()
.addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblPlayer1)
.addComponent(btnRoll)))
.addGroup(statusPanelLayout.createSequentialGroup()
.addGap(16, 16, 16)
.addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtStatus, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblDiceValue))))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(statusPanelLayout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 18, Short.MAX_VALUE)
.addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(statusMessageLabel)
.addComponent(statusAnimationLabel))
.addGap(22, 22, 22))
.addGroup(statusPanelLayout.createSequentialGroup()
.addComponent(lblPlayer2)
.addContainerGap())))
);
setComponent(mainPanel);
setMenuBar(menuBar);
setStatusBar(statusPanel);
}

Now to take care of rest of the logic. Notice that I have used x and y co-ordinates to move the player's tokens. "changeActualPosition()" passes an int value and the co-ordinates based on the board's geometry is returned. I simply created two buffered images of ovals with colors 'yellow' and 'red' with size 30px by 30 px. The "rollAgain()" method generates a random double between 1 and 6 and is converted into int. We really want to lose the precision in this case. When the player wins, the "canRollAgain" class level boolean is set to false and the status message displays "Player x" wins the games.
private void btnRollActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:

double l = Math.ceil(Math.random() * 6);
boolean status = getCurrentPlayer().isStatus();
this.lblDiceValue.setText("dice rolles out number.." + (int) l);
if (l == 1 || l == 6) {
canRollAgain = true;
}
//when status is false
if (!status) {
//Not 1 or 6
if ((l < 6) && (l > 1)) {
if (currentPlayer.getName().equals("Player1")) {
this.txtStatus.setText("Player 2's turn to roll the dice!");
this.setCurrentPlayer(player2);
} else {
this.txtStatus.setText("Player 1's turn to roll the dice!");
this.setCurrentPlayer(player1);
}
} else {
if (currentPlayer.getName().equals("Player1")) {
this.player1.setStatus(true);
this.txtStatus.setText("Player " + this.currentPlayer.getName() + "'s turn to roll the dice again!");
} else {
this.player2.setStatus(true);
this.txtStatus.setText("Player " + this.currentPlayer.getName() + "'s turn to roll the dice again!");
}
canRollAgain = false;
}
//when status is true
} else {
if (canRollAgain){
this.move(l);
this.txtStatus.setText("Player " + this.currentPlayer.getName() + "'s turn to roll the dice again!");
canRollAgain = false;
}else{
this.move(l);
if (currentPlayer.getName().equals("Player1")) {
this.txtStatus.setText("Player 2's turn to roll the dice!");
this.setCurrentPlayer(player2);
} else {
this.txtStatus.setText("Player 1's turn to roll the dice!");
this.setCurrentPlayer(player1);
}
}
}
}
@Action
public void startGame() {
txtStatus.setEditable(false);
this.pnlGame.setVisible(true);
this.btnRoll.setVisible(true);
this.txtStatus.setVisible(true);
this.lblPlayer1.setVisible(true);
this.lblPlayer2.setVisible(true);
this.setCurrentPlayer(player1);
this.txtStatus.setText("Player 1's turn to roll the dice");
}
// Variables declaration - do not modify
private javax.swing.JButton btnRoll;
private javax.swing.JLabel lblDiceValue;
private javax.swing.JLabel lblMain;
private javax.swing.JLabel lblPlayer1;
private javax.swing.JLabel lblPlayer2;
private javax.swing.JPanel mainPanel;
private javax.swing.JMenuBar menuBar;
private javax.swing.JMenuItem newGameMenuItem;
private javax.swing.JPanel pnlGame;
private javax.swing.JLabel statusAnimationLabel;
private javax.swing.JLabel statusMessageLabel;
private javax.swing.JPanel statusPanel;
private javax.swing.JTextField txtStatus;
// End of variables declaration
private final Timer messageTimer;
private final Timer busyIconTimer;
private final Icon idleIcon;
private final Icon[] busyIcons = new Icon[15];
private int busyIconIndex = 0;
private JDialog aboutBox;
/**
* @return the currentPlayer
*/
public Player getCurrentPlayer() {
return currentPlayer;
}
/**
* @param currentPlayer the currentPlayer to set
*/
public void setCurrentPlayer(Player currentPlayer) {
this.currentPlayer = currentPlayer;
}
private void move(double l) {
currentPlayer.setPosition(currentPlayer.getPosition() + (int) l);
changeActualPostion();
if (currentPlayer.getPosition()>=64){
this.txtStatus.setText(this.currentPlayer.getName() + " wins!!!!");
this.btnRoll.setEnabled(false);
}
try {
BufferedImage image = ImageIO.read(new File("lib/board.gif"));
Graphics g = image.getGraphics();
int transparency = 90;
Color color =new Color(255, 0, 0, 255 * transparency / 100);
int x = getX(player1.getPosition());
int y = getY(player1.getPosition());
g.setColor(color);
g.fillOval(x, y, 30, 30);

int x2 = getX(player2.getPosition());
int y2 = getY(player2.getPosition());
color = new Color(255, 255, 0, 255 * transparency / 100);
g.setColor(color);
g.fillOval(x2, y2, 30, 30);
ImageIcon icon = new ImageIcon(image);
icon.getImage().flush();
lblMain.setIcon(icon);
//ImageIO.write(image, "jpg", new File("d:\\temp\\output.bmp"));

} catch (Exception e) {
System.out.println(e);
}
if (currentPlayer.getName().equals("Player1")) {
this.player1.setPosition(currentPlayer.getPosition());
} else {
this.player2.setPosition(currentPlayer.getPosition());
}

}

private void rollAgain() {
double l = Math.ceil(Math.random() * 6);
this.lblDiceValue.setText("Dice rolles out number......." + (int) l);
move(l);
}
private void changeActualPostion() {
switch (currentPlayer.getPosition()) {
case 3:
currentPlayer.setPosition(18);
break;
case 19:
currentPlayer.setPosition(5);
break;
case 24:
currentPlayer.setPosition(39);
break;
case 27:
currentPlayer.setPosition(8);
break;
case 29:
currentPlayer.setPosition(53);
break;
case 62:
currentPlayer.setPosition(32);
break;
case 58:
currentPlayer.setPosition(41);
break;
case 48:
currentPlayer.setPosition(63);
break;
}
}
private int getX(int pos) {
int x = 0;
switch (pos) {
case 1:
x = 20;
break;
case 2:
x = 82;
break;
case 3:
x = 82 + 62;
break;
case 4:
x = 82 + 62 + 62;
break;
case 5:
x = 82 + 62 + 62 + 62;
break;
case 6:
x = 82 + 62 + 62 + 62 + 62;
break;
case 7:
x = 82 + 62 + 62 + 62 + 62 + 62;
break;
case 8:
x = 82 + 62 + 62 + 62 + 62 + 62 + 62;
break;
case 9:
x = 82 + 62 + 62 + 62 + 62 + 62 + 62;
break;
case 10:
x = 82 + 62 + 62 + 62 + 62 + 62;
break;
case 11:
x = 82 + 62 + 62 + 62 + 62;
break;
case 12:
x = 82 + 62 + 62 + 62;
break;
case 13:
x = 82 + 62 + 62;
break;
case 14:
x = 82 + 62;
break;
case 15:
x = 82;
break;
case 16:
x = 20;
break;
case 17:
x = 20;
break;
case 18:
x = 82;
break;
case 19:
x = 82 + 62;
break;
case 20:
x = 82 + 62 + 62;
break;
case 21:
x = 82 + 62 + 62 + 62;
break;
case 22:
x = 82 + 62 + 62 + 62 + 62;
break;
case 23:
x = 82 + 62 + 62 + 62 + 62 + 62;
break;
case 24:
x = 82 + 62 + 62 + 62 + 62 + 62 + 62;
break;
case 25:
x = 82 + 62 + 62 + 62 + 62 + 62 + 62;
break;
case 26:
x = 82 + 62 + 62 + 62 + 62 + 62;
break;
case 27:
x = 82 + 62 + 62 + 62 + 62;
break;
case 28:
x = 82 + 62 + 62 + 62;
break;
case 29:
x = 82 + 62 + 62;
break;
case 30:
x = 82 + 62;
break;
case 31:
x = 82;
break;
case 32:
x = 20;
break;
case 33:
x = 20;
break;
case 34:
x = 82;
break;
case 35:
x = 82 + 62;
break;
case 36:
x = 82 + 62 + 62;
break;
case 37:
x = 82 + 62 + 62 + 62;
break;
case 38:
x = 82 + 62 + 62 + 62 + 62;
break;
case 39:
x = 82 + 62 + 62 + 62 + 62 + 62;
break;
case 40:
x = 82 + 62 + 62 + 62 + 62 + 62 + 62;
break;
case 41:
x = 82 + 62 + 62 + 62 + 62 + 62 + 62;
break;
case 42:
x = 82 + 62 + 62 + 62 + 62 + 62;
break;
case 43:
x = 82 + 62 + 62 + 62 + 62;
break;
case 44:
x = 82 + 62 + 62 + 62;
break;
case 45:
x = 82 + 62 + 62;
break;
case 46:
x = 82 + 62;
break;
case 47:
x = 82;
break;
case 48:
x = 20;
break;
case 49:
x = 20;
break;
case 50:
x = 82;
break;
case 51:
x = 82 + 62;
break;
case 52:
x = 82 + 62 + 62;
break;
case 53:
x = 82 + 62 + 62 + 62;
break;
case 54:
x = 82 + 62 + 62 + 62 + 62;
break;
case 55:
x = 82 + 62 + 62 + 62 + 62 + 62;
break;
case 56:
x = 82 + 62 + 62 + 62 + 62 + 62 + 62;
break;
case 57:
x = 82 + 62 + 62 + 62 + 62 + 62 + 62;
break;
case 58:
x = 82 + 62 + 62 + 62 + 62 + 62;
break;
case 59:
x = 82 + 62 + 62 + 62 + 62;
break;
case 60:
x = 82 + 62 + 62 + 62;
break;
case 61:
x = 82 + 62 + 62;
break;
case 62:
x = 82 + 62;
break;
case 63:
x = 82;
break;
case 64:
x = 20;
break;
}
return x;
}
private int getY(int pos) {
int y = 0;
if (pos > 0 && pos < 9) {
y = 60 + 62 + 62 + 62 + 62 + 62 + 62 + 62;
}
if (pos > 8 && pos < 17) {
y = 60 + 62 + 62 + 62 + 62 + 62 + 62;
}
if (pos > 16 && pos < 25) {
y = 60 + 62 + 62 + 62 + 62 + 62;
}
if (pos > 24 && pos < 33) {
y = 60 + 62 + 62 + 62 + 62;
}
if (pos > 32 && pos < 41) {
y = 60 + 62 + 62 + 62;
}
if (pos > 40 && pos < 49) {
y = 60 + 62 + 62;
}
if (pos > 48 && pos < 57) {
y = 60 + 62;
}
if (pos > 56) {
y = 60;
}
return y;
}

Finally the missing piece is the Player domain itself. We need to maintain the status, position, name and icon. Status is basically "turn". Position is the token's position. Icon is basically what color - "yellow" or "red".
package snakesandladder.domain;
/**
*
* @author tesnep
*/
public class Player {
private boolean status;
private String icon;
private String name;
private int position;
public Player(String icon, String name){
setPosition(0);
setStatus(false);
setIcon(icon);
setName(name);
}
/**
* @return the status
*/
public boolean isStatus() {
return status;
}
/**
* @param status the status to set
*/
public void setStatus(boolean status) {
this.status = status;
}
/**
* @return the icon
*/
public String getIcon() {
return icon;
}
/**
* @param icon the icon to set
*/
public void setIcon(String icon) {
this.icon = icon;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the position
*/
public int getPosition() {
return position;
}
/**
* @param position the position to set
*/
public void setPosition(int position) {
this.position = position;
}
}

When you run, you may need to resize the GUI. Please also note that I did not show all the IDE generated GUI code as that would make it too long to read.

FYI: http://forum.codecall.net/topic/71330-java-swing-game-snakes-ladders/#axzz294rcg3MR

This is the same contribution I made to CodeCall.NET