poornerd

my thoughts on programming and other nerdy stuff

March 8, 2016
by poornerd
0 comments

How to add auto-update the Version Number of a Play Framework 2.X Project

I wanted to have Version numbers that get automatically updated when I want to release a new version, so I set about to find out how to do this with Play Framework.

I discovered that I could base it on the sbt-release plugin, but it was not so straight forward. Here is my strategy, so that in the end all I have to do is run “activator release“:

1. Add the Plugin

Add the plugin by adding this line to your project/plugins.sbt file:

addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.2")

2. Update your build.sbt file:

Add this import near the top of the file:

import ReleaseTransformations._

Change the line with version to this:

version := (version in ThisBuild).value

Next optionally add this piece of code at the end and comment out the pipeline stages you do not want executed (Note: this is apparently the default pipeline):

releaseProcess := Seq[ReleaseStep](
  checkSnapshotDependencies,              // : ReleaseStep
  inquireVersions,                        // : ReleaseStep
  runTest,                                // : ReleaseStep
  setReleaseVersion,                      // : ReleaseStep
  commitReleaseVersion,                   // : ReleaseStep, performs the initial git checks
  tagRelease,                             // : ReleaseStep
  //publishArtifacts,                       // : ReleaseStep, checks whether `publishTo` is properly set up
  setNextVersion,                         // : ReleaseStep
  commitNextVersion                      // : ReleaseStep
  //pushChanges                             // : ReleaseStep, also checks that an upstream branch is properly configured
)

Note: I have commented out the automatic publish and git push

3. Get the Version Number in a controller and pass to a template

public static Result index() {
    String title = Application.class.getPackage().getImplementationTitle();  
    String version = Application.class.getPackage().getImplementationVersion();   
    return ok(index.render(version));
}

And display it in the template:

@(version: String)

...
Version: @version

4. Make sure everything is committed before you release

5. Execute the release

Once you execute the release, the new version will be stored in a file versions.sbt .


activator release

You can lookup more options and possibilities for the sbt-release plugin, including strategies for auto incrementing the version here: https://github.com/sbt/sbt-release

If you have read this far, you may as well follow me on Twitter:

August 6, 2015
by poornerd
0 comments

It’s easy to document your Play Framework REST API with Swagger

This post originally ran on http://swagger.io (7/30/2015)

I having been using Play Framework as a Java-based, lightning-fast REST backend framework for several projects. Later, I was was excited to find Swagger and worked to integrate it into a few projects. As I struggled with it the first time, I thought it would be useful to share my experience and create a “how-to” article describing the steps to succeed quickly.

In order to simplify things, I have started off with an existing Play Framework, Java, JPA, REST project created by James Ward . James’ project is located on GitHub so you should pull it before you start with this how-to.

How-To Steps

1. First, add the dependencies to your build.sbt. I was able to solve a dependency problem with the version of Play Framework 2.3.0 used in the sample project and swagger-core by referring to GitHub issue 55o: https://github.com/swagger-api/swagger-core/issues/550.

"com.wordnik" %% "swagger-play2" % "1.3.12" exclude("org.reflections", "reflections"), 
"org.reflections" % "reflections" % "0.9.8" notTransitive (), 
"org.webjars" % "swagger-ui" % "2.1.8-M1"

2. Add this to your configuration application.conf :

api.version="1.0" swagger.api.basepath="http://localhost:9000"

3. Add the api-docs routes to the routes file:

GET / controllers.Assets.at(path="/public", file="index.html")

GET /api-docs controllers.ApiHelpController.getResources

POST /login controllers.SecurityController.login() POST /logout controllers.SecurityController.logout()

GET /api-docs/api/todos controllers.ApiHelpController.getResource(path = "/api/todos") 
GET /todos controllers.TodoController.getAllTodos() 
POST /todos controllers.TodoController.createTodo()

# Map static resources from the /public folder to the /assets URL path 
GET /assets/*file controllers.Assets.at(path="/public", file)

4. Add Swagger Annotations to the ToDoController ( @Api ):

@Api(value = "/api/todos", description = "Operations with Todos") 
@Security.Authenticated(Secured.class) 
public class TodoController extends Controller {

Then the Annotations for the GET and POST methods:

@ApiOperation(value = "get All Todos",
     notes = "Returns List of all Todos",
     response = Todo.class, 
     httpMethod = "GET") 
public static Result getAllTodos() { 
     return ok(toJson(models.Todo.findByUser(SecurityController.getUser()))); 
}
@ApiOperation( 
     nickname = "createTodo", 
     value = "Create Todo", 
     notes = "Create Todo record", 
     httpMethod = "POST", 
     response = Todo.class
 ) 
@ApiImplicitParams( 
     { 
          @ApiImplicitParam( 
               name = "body", 
               dataType = "Todo", 
               required = true, 
               paramType = "body", 
               value = "Todo" 
          ) 
     } 
) 
@ApiResponses( 
          value = { 
                  @com.wordnik.swagger.annotations.ApiResponse(code = 400, message = "Json Processing Exception") 
          } 
) 
public static Result createTodo() { 
     Form<models.Todo> form = Form.form(models.Todo.class).bindFromRequest(); 
     if (form.hasErrors()) { 
         return badRequest(form.errorsAsJson()); 
     } 
     else { 
          models.Todo todo = form.get(); 
          todo.user = SecurityController.getUser(); 
          todo.save(); 
          return ok(toJson(todo)); 
     } 
}

5. Start the application and go to this URL in your browser:
http://localhost:9000/assets/lib/swagger-ui/index.html?/url=http://localhost:9000/api-docs

Source Code

As mentioned in the beginning, I started with James Ward’s play-rest-security on githuband made these modifications on my fork. For all who are interested, here is the source code: https://github.com/poornerd/play-rest-security

NOTE: meanwhile, James Ward has approved my pull request to add these changes to his project – GitHub so you should pull it

If you have read this far, you may as well follow me on Twitter:

March 20, 2015
by poornerd
2 Comments

How to post data to Play Framework from an IoT Spark Core Arduino!

spark_coreMy goal is to create something with an Arduino from Spark Core that posts data to a web service (server) which I have programmed using Play Framework! This went a smoothly as I had expected, because the Spark Core contains an onboard WiFi chip, and a library which simplifies the http requests. The Spark Core can connect to the Spark Servers (cloud) and store data which can in return be retrieved by any application whether it be Javascript, Python or Java. However, I want to skip all that and just post the data into the database on my web server. I quickly realized that the simplest way would be to just use HTTP GET and pass the values I wanted to post in the API URL request string. This is obviously not the most secure, but sufficient for what I need it for.

Step 1: Play Framework application

Create a simple play service which receives the parameter value and logs it to the console (for the purposes of testing).
Example from my routes:

GET     /test                           controllers.Application.test(state: String)

And in the Application.java a method like this:

    public static Result test(String state) {
        Logger.debug("State: " + state);
        return ok();
    }

Once it is running, you can test the service by calling the following from your browser:

http://localhost:9000/test?state=test

You should see the string “test” logged to your Play Framework server console.

Step 2: Arduino Code

I chose to simply flash the onboard LED and post the state to the Play Framework! server as this would be the simplest requiring no additional components. After I configured and setup my Spark Core, I used the cloud IDE to flash it with the following code (Note: replace your IP in the code ):

// Define the pins we're going to call pinMode on
int led = D0;  // You'll need to wire an LED to this one to see it blink.
String sparkId = "notset";
TCPClient client;
byte server[] = { 192, 191, 1, 206 }; // Play Server IP Number
void setup() {
  pinMode(led, OUTPUT);
  // Make sure your Serial Terminal app is closed before powering your Core
  Serial.begin(9600);
  String myID = Spark.deviceID();
  post_state(myID);
}
void loop() {
  digitalWrite(led, HIGH);   // Turn ON the LED pins
  post_state("ON");
  delay(500);               // Wait for 1000mS = 1 second
  digitalWrite(led, LOW);    // Turn OFF the LED pins
  post_state("OFF");
  delay(500);               // Wait for 1 second in off mode
}

void post_state(String state) {
  Serial.print("connecting...");
  if (client.connect(server, 9000))  // IP from above, and Port 9000 for the Play Server
  {
    Serial.print("connected...");
    //URL of the Play Service defined in the routes
    client.println("GET /test?state="+state+" HTTP/1.0");  
    client.println("Host: 192.191.1.206");
    client.println("Content-Length: 0");
    client.println();
    while (client.available() > 0)
    {
        char c = client.read();
        Serial.print(c);
    }
    Serial.print("disconnecting...");
    delay(100); 
    Serial.println("disconnected.");
    client.stop();
  }
  else
  {
    Serial.println("connection failed");
  }   
}

Step 3: go for it!

Once your Play Server is running, and you have flashed the Spark Core with the code modified to call the URL of your Play Server, you should be able to see it logging the State of the LED on the Play Framework server console like this:

[debug] application - State: ON
[debug] application - State: OFF
[debug] application - State: ON
[debug] application - State: OFF
[debug] application - State: ON
[debug] application - State: OFF

Have fun with this and let me know what you do with it!

I have posted the code on github here – the Arduino code is the the subdirectory /spark-core:

If you have read this far, you may as well follow me on Twitter:

October 15, 2014
by poornerd
0 comments

How to use Hibernate to generate a DDL script from your Play! Framework project

ddl scriptOk, so you have been using the hibernate property name=”hibernate.hbm2ddl.auto” value=”update” to continuously update your database schema, but now you need a complete DDL script?

Use this method from you Global Class onStart to export the DDL scripts.  Just give it the package name (with path) of your Entities as well as a file name:

 


    public void onStart(Application app) {
        exportDatabaseSchema("models", "create_tables.sql");
    }

    public void exportDatabaseSchema(String packageName, String scriptFilename) {

        final Configuration configuration = new Configuration();
        final Reflections reflections = new Reflections(packageName);
        final Set<Class<?>> classes = reflections.getTypesAnnotatedWith(Entity.class);
        // iterate all Entity classes in the package indicated by the name
        for (final Class<?> clazz : classes) {
            configuration.addAnnotatedClass(clazz);
        }
        configuration.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQL9Dialect");

        SchemaExport schema = new SchemaExport(configuration);
        schema.setOutputFile(scriptFilename);
        schema.setDelimiter(";");
        schema.execute(Target.SCRIPT, SchemaExport.Type.CREATE );  // just export the create statements in the script
    }

That is it!

Thanks to @MonCalamari for answering my Question on Stackoverflow here.

If you have read this far, you may as well follow me on Twitter:

October 10, 2014
by poornerd
1 Comment

Yes, it is now this easy to Dockerize a Play! Framework Application

Play Framework DockerizeDo you want to build a dockerized Play! Framework application to deploy on a Docker server?

Nepomuk Seiler actually tweeted about this awhile back, but I didn’t realize until today how easy it was to do.

First off make sure you already have docker  running. I am using OSX, so I used boot2docker and followed these instructions. If you don’t always read all the instructions I like do, then check out these two tips for running boot2docker on OSX:

  • make sure you set the environment variable set like: export DOCKER_HOST=tcp://192.168.59.103:2375
  • make sure that once the application is running you access it with the docker IP, and not localhost

Then follow the README.md instructions here: https://github.com/muuki88/sbt-native-packager-examples/tree/master/play-2.3

  1. Add the dependencies to your build.sbt
    import NativePackagerKeys._
    
    ....
    
    // setting a maintainer which is used for all packaging types</pre>
    maintainer:= "Your Name"
    
    // exposing the play ports
    dockerExposedPorts in Docker := Seq(9000, 9443)
    
    // run this with: docker run -p 9000:9000 <name>:<version>
    
  2. Then build it:
    sbt docker:publishLocal
  3. 
    

    Then run it! (replace the “play-2-3” with your name from the build.sbt, and the “1.0-SNAPSHOT” with your version)

    docker run -p 9000:9000 play-2-3:1.0-SNAPSHOT

Once it is running, use the DOCKER_HOST IP to access it like: http://192.168.59.103:9000

I have yet to try it, but I image you can just copy the target/docker to you docker server and run it as well.

I also need to figure out how to run the the Play!Framework with different configuration files.

If you have read this far, you may as well follow me on Twitter:

August 22, 2014
by poornerd
0 comments

Programming a simple slot machine game using Java

Screen Shot 2014-08-22 at 17.48.55No matter how simple or complex the game is, Java can do the job!

On this post, let’s take a look at how beginners of Java programming can make a simple, yet fully functional slot machine. Slot machines have been around for a long time, but its entertainment value doesn’t seem to fade one bit. InterCasino, the first website to offer online casino gaming to the world in 1996, is still around and its slot games seem to get updated often. In addition, according to the American Gaming Association, slots generate around 62% – 90% of gaming money, making the machines the cash cows of casinos. With these facts in mind, don’t you ever want to create your very own slot machine that millions of casino gaming fans might like in the future? If you’re interested in creating Java-based slot games, the code below might prove useful for you.

package slotMachineGUI;

import java.awt.*;
import javax.swing.*;
import javax.swing.LayoutStyle.ComponentPlacement;
import java.text.DecimalFormat;
import java.util.Random;
import java.util.ArrayList;
import javax.swing.border.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SlotMachineGUI {
    
    private JButton btnCash, btnSpin;
    private JCheckBox cbAlwaysWin, cbSuperJackpot, cbTrollface;
    private JFrame frmFrame;
    private JLabel lblCredits, lblLost, lblMatchThree, lblMatchTwo, lblMoney, lblReel1, lblReel2, lblReel3, lblStatus, lblWon;
    private JPanel pnlReels, pnlReel1, pnlReel2, pnlReel3;
    private JProgressBar prgbarCheatUnlocker;
    private JSeparator sepCheats, sepStats, sepStats2, sepStatus;
    private JToggleButton tgglSound;
    private int credits = 100, boughtCredits = 100, bet = 15, matchThree, matchTwo, win, lost;
    private double payout = 25.0, creditBuyout = 10.0, funds;
    private int reel1 = 7, reel2 = 7, reel3 = 7; // starting values of the reels.
    private ArrayList&lt;ImageIcon&gt; images = new ArrayList&lt;ImageIcon&gt;();
    private DecimalFormat df = new DecimalFormat("0.00");
    
    public SlotMachineGUI(int credits, int boughtCredits, int bet, double payout, double creditBuyout, int reel1, int reel2, int reel3) {
        this.credits=credits;
        this.boughtCredits=boughtCredits;
        this.bet=bet;
        this.payout=payout;
        this.creditBuyout=creditBuyout;
        this.reel1=reel1;
        this.reel2=reel2;
        this.reel3=reel3;
        createForm();
        loadImages();
        addFields();
        addButtons();
        layoutFrame();
        layoutReels();
        layoutOther();
    }
    
    public SlotMachineGUI() {
        createForm();
        loadImages();
        addFields();
        addButtons();
        layoutFrame();
        layoutReels();
        layoutOther();
    }
    
    /** Creates the JFrame and Panels. */
    private void createForm() {
        
        frmFrame = new JFrame();
        frmFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frmFrame.setTitle("Warner Slots");
        frmFrame.setResizable(false);
        frmFrame.setVisible(true);
        
        pnlReels = new JPanel();
        pnlReels.setBorder(BorderFactory.createEtchedBorder());
        
        pnlReel1 = new JPanel();
        pnlReel1.setBackground(new Color(255, 215, 0));
        pnlReel1.setBorder(new SoftBevelBorder(BevelBorder.LOWERED));
        pnlReel2 = new JPanel();
        pnlReel2.setBackground(new Color(255, 216, 0));
        pnlReel2.setBorder(new SoftBevelBorder(BevelBorder.LOWERED));
        pnlReel3 = new JPanel();
        pnlReel3.setBackground(new java.awt.Color(255, 215, 0));
        pnlReel3.setBorder(new SoftBevelBorder(BevelBorder.LOWERED));
        
    }
    
    /** Adds labels to the form. */
    private void addFields() {
        
        lblReel1 = new JLabel();
        lblReel2 = new JLabel();
        lblReel3 = new JLabel();
        
        sepStats = new JSeparator();
        lblMatchTwo = new JLabel();
        lblMatchTwo.setText("Matched Two: ");
        lblMatchThree = new JLabel();
        lblMatchThree.setText("Matched Three: ");
        lblWon = new JLabel();
        lblWon.setText("Won: ");
        
        sepStats2 = new JSeparator();
        sepStats2.setOrientation(SwingConstants.VERTICAL);
        lblCredits = new JLabel();
        lblCredits.setText("Credits: "+credits);
        lblMoney = new JLabel();
        lblMoney.setText("Money: £"+df.format(funds));
        lblLost = new JLabel();
        lblLost.setText("Lost: ");
        
        sepStatus = new JSeparator();
        lblStatus = new JLabel();
        lblStatus.setBackground(new Color(255, 255, 255));
        lblStatus.setFont(new Font("Arial", 1, 14));
        lblStatus.setHorizontalAlignment(SwingConstants.CENTER);
        lblStatus.setText("Welcome to WARNER SLOTS!!! ©2012");
        
        sepCheats = new JSeparator();
        prgbarCheatUnlocker = new JProgressBar();
        prgbarCheatUnlocker.setToolTipText("Fill the bar to unlock the cheat menu.");
        
        lblReel1.setIcon(images.get(reel1));
        lblReel2.setIcon(images.get(reel2));
        lblReel3.setIcon(images.get(reel3));
        
    }
    
    /** Adds buttons to the form. */
    private void addButtons() {
        
        btnSpin = new JButton();
        btnSpin.setBackground(new Color(50, 255, 50));
        btnSpin.setText("Spin");
        btnSpin.setToolTipText("Click to spin the reels!");
        btnSpin.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
        btnSpin.setInheritsPopupMenu(true);
        btnSpin.setMaximumSize(new Dimension(200, 50));
        btnSpin.setMinimumSize(new Dimension(200, 50));
        btnSpin.addActionListener(new SpinHandler());
        
        btnCash = new JButton();
        btnCash.setBackground(new Color(255, 0, 0));
        btnCash.setText("Buy Credits");
        btnCash.setToolTipText("£"+df.format(bet)+" converts to "+boughtCredits+" credits.");
        btnCash.setHorizontalTextPosition(SwingConstants.CENTER);
        btnCash.addActionListener(new BuyCreditsHandler());
        
        tgglSound = new JToggleButton();
        tgglSound.setSelected(false);
        tgglSound.setText("Sound ON");
        tgglSound.addActionListener(new SoundHandler());
        
        cbAlwaysWin = new JCheckBox();
        cbAlwaysWin.setText("Always Win Mode");
        cbAlwaysWin.setEnabled(false);
        cbAlwaysWin.addActionListener(new AlwaysWinHandler());
        
        cbTrollface = new JCheckBox();
        cbTrollface.setText("Trollface");
        cbTrollface.setEnabled(false);
        cbTrollface.addActionListener(new TrollfaceHandler());
        
        cbSuperJackpot = new JCheckBox();
        cbSuperJackpot.setText("Super Jackpot");
        cbSuperJackpot.setEnabled(false);
        cbSuperJackpot.addActionListener(new SuperPrizeHandler());
        
    }
    
    /** Lays out the frame. */
    private void layoutFrame() {
        
        GroupLayout frameLayout = new GroupLayout(frmFrame.getContentPane());
        frmFrame.getContentPane().setLayout(frameLayout);
        frameLayout.setHorizontalGroup(
        frameLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGap(0, 400, Short.MAX_VALUE)
        );
        frameLayout.setVerticalGroup(
        frameLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGap(0, 300, Short.MAX_VALUE)
        );
    }
    
    /** Lays out the panels and reels. */
    private void layoutReels() {
        
        GroupLayout pnlReelsLayout = new GroupLayout(pnlReels);
        pnlReels.setLayout(pnlReelsLayout);
        pnlReelsLayout.setHorizontalGroup(
        pnlReelsLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(pnlReelsLayout.createSequentialGroup()
        .addContainerGap()
        .addComponent(pnlReel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        .addGap(18, 18, 18)
        .addComponent(pnlReel2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        .addGap(18, 18, 18)
        .addComponent(pnlReel3, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        pnlReelsLayout.setVerticalGroup(
        pnlReelsLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(pnlReelsLayout.createSequentialGroup()
        .addContainerGap()
        .addGroup(pnlReelsLayout.createParallelGroup(GroupLayout.Alignment.TRAILING, false)
        .addComponent(pnlReel2, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(pnlReel1, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(pnlReel3, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        
        GroupLayout pnlReel1Layout = new GroupLayout(pnlReel1);
        pnlReel1.setLayout(pnlReel1Layout);
        pnlReel1Layout.setHorizontalGroup(
        pnlReel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(pnlReel1Layout.createSequentialGroup()
        .addContainerGap()
        .addComponent(lblReel1)
        .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        pnlReel1Layout.setVerticalGroup(
        pnlReel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(pnlReel1Layout.createSequentialGroup()
        .addContainerGap()
        .addComponent(lblReel1)
        .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        
        GroupLayout pnlReel2Layout = new GroupLayout(pnlReel2);
        pnlReel2.setLayout(pnlReel2Layout);
        pnlReel2Layout.setHorizontalGroup(
        pnlReel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(pnlReel2Layout.createSequentialGroup()
        .addContainerGap()
        .addComponent(lblReel2)
        .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        pnlReel2Layout.setVerticalGroup(
        pnlReel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(pnlReel2Layout.createSequentialGroup()
        .addContainerGap()
        .addComponent(lblReel2)
        .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        
        GroupLayout pnlReel3Layout = new GroupLayout(pnlReel3);
        pnlReel3.setLayout(pnlReel3Layout);
        pnlReel3Layout.setHorizontalGroup(
        pnlReel3Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(pnlReel3Layout.createSequentialGroup()
        .addContainerGap()
        .addComponent(lblReel3)
        .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        pnlReel3Layout.setVerticalGroup(
        pnlReel3Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(pnlReel3Layout.createSequentialGroup()
        .addContainerGap()
        .addComponent(lblReel3)
        .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        
    }
    
    /** lays out the remaining labels, check boxes, progress bars, etc. */
    private void layoutOther() {
        
        GroupLayout layout = new GroupLayout(frmFrame.getContentPane());
        frmFrame.getContentPane().setLayout(layout);
        
        layout.setHorizontalGroup(
        layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
        .addComponent(sepCheats)
        .addComponent(prgbarCheatUnlocker, GroupLayout.DEFAULT_SIZE, 426, Short.MAX_VALUE))
        .addGap(0, 0, Short.MAX_VALUE))
        .addGroup(layout.createSequentialGroup()
        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
        .addGroup(layout.createSequentialGroup()
        .addComponent(cbAlwaysWin)
        .addGap(18, 18, 18)
        .addComponent(cbTrollface)
        .addGap(18, 18, 18)
        .addComponent(cbSuperJackpot)
        .addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(tgglSound))
        .addComponent(btnSpin, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(pnlReels, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(sepStats, GroupLayout.Alignment.TRAILING)
        .addComponent(lblStatus, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addGroup(layout.createSequentialGroup()
        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING, false)
        .addComponent(lblMatchTwo, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(lblWon, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(lblMatchThree, GroupLayout.DEFAULT_SIZE, 149, Short.MAX_VALUE))
        .addPreferredGap(ComponentPlacement.UNRELATED)
        .addComponent(sepStats2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(ComponentPlacement.UNRELATED)
        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
        .addComponent(lblLost, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(lblCredits, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(lblMoney, GroupLayout.DEFAULT_SIZE, 154, Short.MAX_VALUE))
        .addGap(0, 0, Short.MAX_VALUE)))
        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
        .addComponent(btnCash)
        .addComponent(sepStatus, GroupLayout.PREFERRED_SIZE, 426, GroupLayout.PREFERRED_SIZE)))
        .addContainerGap())))
        );
        
        layout.setVerticalGroup(
        layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addComponent(pnlReels, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(ComponentPlacement.RELATED)
        .addComponent(btnSpin, GroupLayout.PREFERRED_SIZE, 56, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(ComponentPlacement.UNRELATED)
        .addComponent(sepStats, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(ComponentPlacement.UNRELATED)
        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
        .addComponent(lblWon, GroupLayout.PREFERRED_SIZE, 19, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(ComponentPlacement.RELATED)
        .addComponent(lblMatchTwo, GroupLayout.PREFERRED_SIZE, 19, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(ComponentPlacement.RELATED)
        .addComponent(lblMatchThree, GroupLayout.DEFAULT_SIZE, 25, Short.MAX_VALUE))
        .addComponent(sepStats2)
        .addGroup(layout.createSequentialGroup()
        .addComponent(lblLost, GroupLayout.PREFERRED_SIZE, 19, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(ComponentPlacement.RELATED)
        .addComponent(lblCredits, GroupLayout.PREFERRED_SIZE, 19, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(ComponentPlacement.RELATED)
        .addComponent(lblMoney, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        .addComponent(btnCash, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        .addPreferredGap(ComponentPlacement.UNRELATED)
        .addComponent(sepStatus, GroupLayout.PREFERRED_SIZE, 2, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(ComponentPlacement.UNRELATED)
        .addComponent(lblStatus, GroupLayout.PREFERRED_SIZE, 30, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(ComponentPlacement.UNRELATED)
        .addComponent(sepCheats, GroupLayout.PREFERRED_SIZE, 5, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(ComponentPlacement.RELATED)
        .addComponent(prgbarCheatUnlocker, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(ComponentPlacement.UNRELATED)
        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
        .addComponent(cbAlwaysWin)
        .addComponent(cbTrollface)
        .addComponent(cbSuperJackpot)
        .addComponent(tgglSound))
        .addContainerGap())
        );
        
        frmFrame.pack();
        
    }
    
    /** Performs action when Buy Credits button is clicked. */
    class BuyCreditsHandler implements ActionListener {
        public void actionPerformed(ActionEvent event) {
            buyCredits();
        }
    }
    
    /** if the player has enough funds credits are added. */
    public void buyCredits() {
        if (funds &gt;= creditBuyout) {
            funds -= creditBuyout;
            lblMoney.setText("Money: £"+df.format(funds));
            credits += boughtCredits;
            lblCredits.setText("Credits: "+credits);
            lblStatus.setText("+"+boughtCredits+" credits purchased! -£"+df.format(creditBuyout));
            } else {
            lblStatus.setText("Insufficient £ to purchase credits!");
        }
        buyCreditsCheck();
    }
    
    /** if user has enough funds to buy credits changes buttons colour to alert user. */
    public void buyCreditsCheck() {
        if (funds &lt; bet) {
            btnCash.setBackground(new java.awt.Color(255, 0, 0));
            } else {
            btnCash.setBackground(new java.awt.Color(50, 255, 50));
        }
    }
    
    /** Performs action when Spin button is clicked. */
    class SpinHandler implements ActionListener {
        public void actionPerformed(ActionEvent event) {
            if (funds &lt; creditBuyout && credits &lt; bet) {
                lblStatus.setText("&lt;html&gt;<a href='http://www.gambleaware.co.uk/'>www.gambleaware.co.uk</a>&lt;/html&gt;");
                } else if ((credits - bet) &gt;= 0) {
                pnlReel1.setBackground(new java.awt.Color(255, 215, 0));
                pnlReel2.setBackground(new java.awt.Color(255, 215, 0));
                pnlReel3.setBackground(new java.awt.Color(255, 215, 0));
                genReelNumbers();
                matchCheck();
                } else {
                lblStatus.setText("Bet is "+bet+" credits, purchase more with £!");
            }
            buyCreditsCheck();
        }
    }
    
    /** Generates the 3 reel numbers. */
    public void genReelNumbers() {
        Random rand = new Random();
        if (cbAlwaysWin.isSelected() == true) { // If the Always win cheat mode is enabled.
            int winType = rand.nextInt(4); // generates number between 0-3 to determine the type of win
            reel1 = rand.nextInt(images.size());
            if (winType == 0) { // winType = 0 - Reels 1, 2 and 3 will all match.
                reel2 = reel1;
                reel3 = reel1;
                } else if (winType == 1) { // winType = 1 - Reels 1 and 2 will match.
                reel2 = reel1;
                } else if (winType == 2) { // winType = 2 - Reels 1 and 3 will match.
                reel3 = reel1;
                } else {    // winType = 3 - Reels 2 and 3 will match.
                if (reel1 &gt;= 0 ) {
                    reel2 = reel1 + 1;
                    reel3 = reel1 + 1;
                    } if (reel1 == images.size()-1) {
                    reel2 = reel1 - 1;
                    reel3 = reel1 - 1;
                }
            }
            } else { // If the Always win cheat mode is disabled play a normal game.
            reel1 = rand.nextInt(images.size());
            reel2 = rand.nextInt(images.size());
            reel3 = rand.nextInt(images.size());
        }
        setReelIcon(reel1, reel2, reel3); // Set the reel image
    }
    
    /** Sets the reels icon based on loaded image in images ArrayList. */
    public void setReelIcon(int ico1, int ico2, int ico3) {
        lblReel1.setIcon(images.get(ico1)); // icon = the ArrayList index = random reel number
        lblReel2.setIcon(images.get(ico2));
        lblReel3.setIcon(images.get(ico3));
    }
    
    /** Checks for number matches and adjusts score depending on result. */
    public void matchCheck() {
        if (reel1 == reel2 && reel2 == reel3) {
            lblStatus.setText("You matched THREE symbols ("+images.get(reel1).getDescription()+")! +£"+df.format(getPrize(payout))+"!");
            lblMatchThree.setText("Matched Three: "+matchThree());
            pnlReel1.setBackground(new java.awt.Color(255, 0, 0)); // Highlights matched icons.
            pnlReel2.setBackground(new java.awt.Color(255, 0, 0));
            pnlReel3.setBackground(new java.awt.Color(255, 0, 0));
            } else if (reel1 == reel2 || reel1 == reel3) {
            lblStatus.setText("You matched TWO symbols ("+images.get(reel1).getDescription()+")! +£"+df.format(getPrize(payout))+"!");
            lblMatchTwo.setText("Matched Two: "+matchTwo());
            if (reel1 == reel2) {
                pnlReel1.setBackground(new java.awt.Color(255, 0, 0)); // Highlights matched icons.
                pnlReel2.setBackground(new java.awt.Color(255, 0, 0));
                } else if (reel1 == reel3){
                pnlReel1.setBackground(new java.awt.Color(255, 0, 0)); // Highlights matched icons.
                pnlReel3.setBackground(new java.awt.Color(255, 0, 0));
            }
            } else if (reel2 == reel3) {
            lblStatus.setText("You matched TWO symbols ("+images.get(reel2).getDescription()+")! +£"+df.format(getPrize(payout))+"!");
            lblMatchTwo.setText("Matched Two: "+matchTwo());
            pnlReel2.setBackground(new java.awt.Color(255, 0, 0)); // Highlights matched icons.
            pnlReel3.setBackground(new java.awt.Color(255, 0, 0));
            } else {
            lblStatus.setText("Sorry, you didn't match any symbols. -"+bet+" credits!");
            lblLost.setText("Lost: "+lose());
        }
        lblCredits.setText("Credits: "+(credits -= bet)); // deduct bet amount from available credits.
        lblMoney.setText("Money: £"+df.format((funds += getPrize(payout)))); // If there is a win add amount to cash pot.
        lblWon.setText("Wins: "+win()); // increment win amount.
    }
    
    /** sets progress bar equal to the current win count. if bar is full it unlocks cheat menu */
    public void prgBarCheck() {
        if (prgbarCheatUnlocker.getValue() &lt;= 99) {
            prgbarCheatUnlocker.setValue(win);
            } else if (prgbarCheatUnlocker.getValue() == 100) { // after 100 wins unlock the cheats.
            prgbarCheatUnlocker.setValue(100);
            lblStatus.setText("100 wins! Congratulations you've unlocked the cheat menu!");
            cbTrollface.setEnabled(true);
            cbSuperJackpot.setEnabled(true);
            cbAlwaysWin.setEnabled(true);
        }
    }
    
    /** calculates prize to be awarded for win based on number of matches and cheats. */
    public double getPrize(double prize) {
        if (reel1 == reel2 && reel2 == reel3) {
            if (cbSuperJackpot.isSelected() == true) {
                prize *= 100; // if cheating and all are matched return the full pay out x100.
                } else {
                prize = payout; // if all are matched return the full pay out.
            }
            } else if (reel1 == reel2 || reel1 == reel3 || reel2 == reel3) {
            if (cbSuperJackpot.isSelected() == true) {
                prize *= 50; // if cheating and two are matched return the pay out x50.
                } else {
                prize = payout / 5; // if two are matched return 1/5th of the pay out.
            }
            } else {
            prize = 0; // If no win return no prize.
        }
        return prize;
    }
    
    /** Performs action when Super Jack pot check box is clicked. */
    class SuperPrizeHandler implements ActionListener{
        public void actionPerformed(ActionEvent e) {
            if (cbSuperJackpot.isSelected() == true) {
                lblStatus.setText("Super Prize mode ENABLED! The £ won is now x100!");
            }
            if (cbSuperJackpot.isSelected() == false) {
                lblStatus.setText("Super Prize mode DISABLED! :'(");
            }
        }
    }
    
    /** Performs action when Troll face check box is clicked. */
    class AlwaysWinHandler implements ActionListener{
        public void actionPerformed(ActionEvent e) {
            if (cbAlwaysWin.isSelected() == true) {
                lblStatus.setText("Always Win mode ENABLED! 7-7-7's here we come!");
            }
            if (cbAlwaysWin.isSelected() == false) {
                lblStatus.setText("Always Win mode DISABLED! :'(");
            }
        }
    }
    
    /** Performs action when Troll face check box is clicked. */
    class TrollfaceHandler implements ActionListener{
        public void actionPerformed(ActionEvent e) {
            if (cbTrollface.isSelected() == true && images.get(images.size()-1) != createImageIcon("images/Trollface.png", "Trollface")) {
                images.add(createImageIcon("images/Trollface.png", "Trollface")); // adds a bonus image to the images ArrayList.
                lblStatus.setText("Trollface mode ENABLED! Trolololololol!");
            }
            if (cbTrollface.isSelected() == false && images.get(images.size()-1) != createImageIcon("images/Trollface.png", "Trollface")) {
                images.remove(images.size()-1); // removes the bonus image (or last one added to the ArrayList) from the images ArrayList.
                lblStatus.setText("Trollface mode DISABLED! :'(");
            }
        }
    }
    
    /** Performs action when sound toggle button is clicked.
    * NOT IMPLEMENTED
    */
    class SoundHandler implements ActionListener{
        public void actionPerformed(ActionEvent e) {
            if (tgglSound.isSelected() == false) {
                tgglSound.setText("Sound ON");
                lblStatus.setText("Sound effects have been ENABLED!");
                // allowed to play sounds
                } else {
                tgglSound.setText("Sound OFF");
                lblStatus.setText("Sound effects have been DISABLED!");
                // disable sounds
            }
        }
    }
    
    /** Loads ImageIcons into the images ArrayList.
    *    The difficulty is determined by the number of images present in the ArrayList:
    *    •    Add images here to make game more difficult.
    *    •    Remove images here to make game easier.
    */
    public void loadImages() {
        images.add(createImageIcon("images/Banana.png", "Banana"));
        images.add(createImageIcon("images/Bar.png", "Bar"));
        images.add(createImageIcon("images/Bell.png", "Bell"));
        images.add(createImageIcon("images/Cherry.png", "Cherry"));
        images.add(createImageIcon("images/Clover.png", "Clover"));
        images.add(createImageIcon("images/Diamond.png", "Diamond"));
        images.add(createImageIcon("images/Plum.png", "Plum"));
        images.add(createImageIcon("images/Seven.png", "Seven"));
        images.add(createImageIcon("images/Watermelon.png", "Watermelon"));
    }
    
    /** Create a new ImageIcon, unless the URL is not found. */
    public ImageIcon createImageIcon(String path, String description) {
        java.net.URL imgURL = getClass().getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL, description);
            } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }
    
    /** Increments matchThree by 1 and returns value. */
    public int matchThree() {
        matchThree++;
        return matchThree;
    }
    
    /** Increments matchTwo by 1 and returns value. */
    public int matchTwo() {
        matchTwo++;
        return matchTwo;
    }
    
    /** Increments lost by 1 and returns value. */
    public int lose() {
        lost++;
        return lost;
    }
    
    /** Increments win by 1, increases progress bar and returns value. */
    public int win() {
        win = matchThree + matchTwo;
        prgBarCheck(); // Increments the progress bar to unlock cheat menu.
        return win;
    }
    
    public static void main(String args[]) {
        
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
            } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(SlotMachineGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(SlotMachineGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(SlotMachineGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(SlotMachineGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        
        java.awt.EventQueue.invokeLater(new Runnable() {
            
            public void run() {
                new SlotMachineGUI();
            }
        });
        
    }
    
}

Kudos to M ajestic, a YouTube user, for the code above. Here are the images that he used in the creation of the game.

If you have read this far, you may as well follow me on Twitter:

April 1, 2014
by poornerd
13 Comments

How to implement a Session Timeout in Play Framework 2

If you follow the Play Framework 2 guide for implementing authentication: http://www.playframework.com/documentation/2.2.2/JavaGuide4 – you will notice that there is no session timeout in Play Framework 2. It was there in Play Framework 1, but Play Framework 2 follows a different approach.

I you want to implement your own session timeout, then follow the guide for setting up authentication, by extending the Security.Authenticator, and store a timestamp in the session and keep extending it every time a request is made.

Here is how I did it:

public class Secured extends Security.Authenticator {

    public static final String UNAUTHENTICATED = "unauthenticated";

    public static User getLoggedInUser() {
        if (session("userId") == null)
            return null;
        return User.findById(Long.parseLong(session("userId")));
    }

    public static String getLoggedInUsername() {
        if (session("userId") == null)
            return null;
        return User.findById(Long.parseLong(session("userId"))).getUsername();
    }


    @Override
    public String getUsername(Http.Context ctx) {

        // see if user is logged in
        if (session("userId") == null)
            return null;

        // see if the session is expired
        String previousTick = session("userTime");
        if (previousTick != null && !previousTick.equals("")) {
            long previousT = Long.valueOf(previousTick);
            long currentT = new Date().getTime();
            long timeout = Long.valueOf(Play.application().configuration().getString("sessionTimeout")) * 1000 * 60;
            if ((currentT - previousT) > timeout) {
                // session expired
                session().clear();
                return null;
            } 
        }

        // update time in session
        String tickString = Long.toString(new Date().getTime());
        session("userTime", tickString);

        return User.findById(Long.parseLong(session("userId"))).getUsername();
    }
}

Then just add a sessionTimeout=15 (in Minutes) to your conf file.

If you have read this far, you may as well follow me on Twitter:

March 18, 2014
by poornerd
0 comments

Examples for working with JSON in Play Framework 2 with Java

  • String to JSON: 
    JsonNode json = mapper.readTree(notification.getSharedData());
  • Json to Object: 
    Asset asset = mapper.readValue(a.toString(), Asset.class)
  • Json to extisting Object: 
    asset = mapper.readerForUpdating(asset).readValue(assetJson.toString())
  • Object to JsonString:
    mapper.writeValueAsString(new ResultDocument(document))
  • Convert Object ot JsonNode:
    JsonNode documentNode = mapper.convertValue(document, JsonNode.class);

    This causes an error – Caused by: com.fasterxml.jackson.databind.JsonMappingException: Direct self-reference leading to cycle so do this workaround:

    String messageJson = null;
    
    String documentAsString = BaseApiController.mapper.writeValueAsString(document);
    
    JsonNode documentNode = BaseApiController.mapper.readTree(documentAsString);
If you have read this far, you may as well follow me on Twitter:

March 13, 2014
by poornerd
0 comments

Configuring Play2War with Play 2.2 and build.sbt

Screen Shot 2014-03-13 at 21.07.45I had previously used Play2War with Play 2 projects that contained a Build.scala file following the configuration directions from Play2War. However, when attempting to configure a newer project which now uses a build.sbt instead of the Build.scala, It wasn’t immediately apparent how to do it.

  1. Add this to your plugins.sbt: addSbtPlugin(“com.github.play2war” % “play2-war-plugin” % “1.2-beta4”)
  2. Add this to the top of your build.sbt:
     import com.github.play2war.plugin._
  3. Add this at the end of your build.sbt: (yes with the line between them, and the servlet Version you need). 
    Play2WarPlugin.play2WarSettings
    Play2WarKeys.servletVersion := "2.5"
  4. Run “play war” and when it is done, look in the target directory
If you have read this far, you may as well follow me on Twitter:

January 4, 2014
by poornerd
0 comments

How to configure an SSL Certificate with Play Framework for https

sslI spent hours trying to get this to work, and in the end, then problem was that I did not generate the CSR (Certificate Request) myself with the keytool.

I kept getting this error when I tried accessing Play with https:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

The problem ended up being that the keystore I created and imported the SSL certificate into did not have the public key that was used for the CSR (certificate request).

So here it the quick version of generating an SSL Certificate with godaddy.com and installing it with Play Framework 2.1+.

1. Follow these instructions from godaddy.com to generate the CSR like this:
First generate the key pair like this:

keytool -keysize 2048 -genkey -alias tomcat -keyalg RSA -keystore tomcat.keystore

Then generate the CSR:

keytool -certreq -alias tomcat -file csr.txt -keystore tomcat.keystore

2. Use the CSR to apply for certificate

3. Add the Intermediate Certificate Bundle and the Certificate that were generated to your keystore.
NOTE: make sure this is the same keystore that you generated the private key in, in step 1!

keytool -import -alias intermed -keystore tomcat.keystore -trustcacerts -file gd_bundle.crt
keytool -import -alias tomcat -keystore tomcat.keystore -trustcacerts -file mycert.crt

(Replace mycert.crt with the file name and location of the new GoDaddy certificate)

4. Finally, following the instructions for configuring https with Play 2.1+ ( http://www.playframework.com/documentation/2.2.1/ConfiguringHttps ) which had already worked great with the self generated key, I created a shell script for starting Play with the correct parameters:

# script for starting play in production with SSL and the keystore
target/start -Dhttps.port=443 -Dhttps.keyStore=/Users/bp/mypath/tomcat.keystore -Dhttps.keyStorePassword=itl80809

Note: you need to do a “play dist” beforehand, so that the current Software is compiled into a distribution in the target subdirectory.

If you have read this far, you may as well follow me on Twitter: