In an earlier discussion about Smalltalk we observed that image-based persistence does not work very well with Cloud Foundry’s model where several application instances may be run at the same time to support scaling. With a Pharo-based Smalltalk, each instance has its own image so data stored in the image is not shared among instances. One way to solve that problem is to use an external database, and Cloud Foundry includes built-in support for MySQL 5.1. In this post we look at adding MySQL to the client and creating an AidaWeb application that uses the database. Deploying this application on Cloud Foundry will require a few modifications that we will discuss in the next post.

MySQL Setup

We start by adding MySQL to our client so we can develop and test our application locally. On this page, select the appropriate download for your machine; I used Mac OS X 10.6 (AMD64, installer format) (13 Feb 2011, 78.1M). Follow the instructions for installing and starting MySQL. For convenience, we will add an alias to the MySQL command-line interface:

alias mysql="/user/local/mysql/bin/mysql"

It is a good practice to secure the database, so from a command shell we connect to the database:

mysql -u root

Once connected, we add a password for the root user:

SELECT User, Host, Password from mysql.user;
UPDATE mysql.user 
  SET Password = PASSWORD('swordfish') 
  WHERE User = 'root';
FLUSH PRIVILEGES;
SELECT User, Host, Password from mysql.user;
EXIT

Now, from the command shell try various ways of connecting (note that there is no space after the -p option:

mysql -u root
mysql -u root -p
mysql -u root -pswordfish

You should find that the first one fails, the second one prompts for a password, and the third one logs in immediately. Once logged in we can perform various queries. Note that we need to specify a database as part of the query if it is not explicitly used. Try each of the following individually:

SELECT User FROM user;
SELECT User FROM mysql.user;
USE mysql; SELECT User FROM user;

The first should result in an error while the next two should succeed. You can avoid the USE command by specifying the database as a command-line argument (exit from MySQL and try the following):

mysql -u root -pswordfish mysql

Next we create a non-root administrative user:

CREATE USER 'jfoster'@'localhost' IDENTIFIED BY 'swordfish';
GRANT ALL PRIVILEGES ON *.* TO 'jfoster'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EXIT

Now we can login as our new user and specify the test database:

mysql -u jfoster -pswordfish test

The MySQL driver that we will use has a couple hundred tests that expect a particular user to be defined. We enter the following to create a new user:

CREATE USER 'stdbtestuser'@'localhost' IDENTIFIED BY 'stdbtestpass';
GRANT ALL PRIVILEGES ON stdbtestschema.* TO 'stdtestuser'@'localhost';
FLUSH PRIVILEGES;

Creating a Smalltalk Application

Now that we have MySQL running on our client machine, we will create a Smalltalk application that uses MySQL. (In creating this AidaWeb application I got help from Janko Mivšek.) Open a web browser on http://ss3.gemstone.com/ss/CloudFoundryDemos.html and click on the ‘Latest’ tab. There should be several packages listed. For this demo we want the following:

  • JSON
  • Stdb-Core
  • Stdb-MysqlProtocol
  • Stdb-MysqlImpl
  • BalanceDemo

At the right end of each row is a “download” action; for each of the above packages click this link. Move the downloaded files from the Downloads directory to ~/cloud/aida/app (which we created earlier).

Now we edit ~/cloud/aida/app/aida.st to install the packages for our application and register two entry points with Aida:

Author fullName: 'CloudFoundry'. "Name for edits"
MczInstaller installFileNamed: 'app/JSON-ul.35.mcz'.
MczInstaller installFileNamed: 'app/Stdb-Core-ah.7.mcz'.
MczInstaller installFileNamed: 'app/Stdb-MysqlProtocol-ah.15.mcz'.
MczInstaller installFileNamed: 'app/Stdb-MysqlImpl-ah.9.mcz'.
MczInstaller installFileNamed: 'app/BalanceDemo-JamesFoster.1.mcz'.
MySqlBalanceApp register.
ImageBalanceApp register.

Recall that this script runs once, during the “staging” process, and then the image is saved and made read-only so it can be deployed in multiple instances. Now we edit ~/cloud/aida/start so that it defines environment variables that will be provided by Cloud Foundry:

#! /bin/bash 
export VCAP_SERVICES='{
  "mysql-5.1":[ { 
    "credentials":{ 
      "name":"test", 
      "host":"localhost", 
      "port":3306, 
      "user":"jfoster", 
      "password":"swordfish" 
    } 
  }
]}'
export VCAP_APP_PORT=8888
open -a /opt/smalltalk/cog/CogVM.app/ --args \ 
  ~/cloud/aida/Aida.image \ 
  ~/cloud/aida/app/aida.st \ 
  $VCAP_APP_PORT

Now, try launching the application locally:

~/cloud/aida/start

It should take some time loading the packages and then you should be able to open a Test Runner and run the JSON and Stdb-Mysql* tests. You should have 223 tests all pass. You can now open a System Browser and look at the BalanceDemo category (it should be the last one in the first column). You can see that there is a BalanceApp, an abstract superclass that provides the AidaWeb behavior, and two subclasses that implement image-based persistence and persistence using MySQL. Browse the code and then open a web browser on http://localhost:8888/ImageBalance and http://localhost:8888/MySqlBalance. (The first time you may need to login to AidaWeb using the user ‘admin’ and the password ‘password’.) With each of them you should be able to enter a value in the ‘Adjustment:’ field, then click the ‘Adjust’ button, and see a new balance. Try entering both positive and negative integers.

From a MySQL command-line interface try the following lines and look at the change in the application by refreshing the web page:

SHOW TABLES;
SELECT * FROM account;
UPDATE account SET balance = 42;

We can see that changes from the web are reflected in the database and changes in the database are reflected in the web.