Installing Glassfish v2.1 and configuring a cluster

I have been a Tomcat guy for the longest time but from time to time I like to play with the other guys software so it was either Jetty or Glassfish. I choose Glassfish. I’ve used Glassfish before for development testing and running rails but have not had any real J2ee apps running inside. Let’s have a look at the installation procedures for Glassfish and what you get after a few minutes of clicking.

Download

Glassfish can be downloaded from https://glassfish.dev.java.net/downloads/v2.1-b60e.html we are going to use the latest stable (production ready) build of v2.1 b60.

Installation

I’m running this on a Linux (Centos) server so here are the steps to install and setup Glassfish WITH the cluster configurations:

[root@heimdull]# java -Xmx256m -jar glassfish-installer-v2.1-b60e-linux-ml.jar [root@heimdull]# cd glassfish [root@heimdull]# chmod -R +x lib/ant/bin [root@heimdull]# lib/ant/bin/ant -s setup-cluster.xml bla bla bla .... BUILD SUCCESSFUL Total time: xx seconds

Configuration

Before we configure some custom settings lets just get this thing started…

[root@heimdull]# export PATH=~/glassfish/bin:$PATH
[root@heimdull]# asadmin start-domain

Now you can access the administration console at http://localhost:4848/ by default the server does NOT bind to localhost but 0.0.0.0 so if you do not have a firewall you can access the console from outside the server too.

PS. There is a issue where the admin console might keep logging you out and asking for your credentials on every click. This is a cookie problem. Clear your browser cookies and you should be fine.

Change admin password

If you want to change the default admin user password (which is adminadmin) run the following command:

[root@heimdull]# asadmin change-admin-password --user=admin

Creating the cluster

Go to http://localhost:4848 and login. After this click on the Clusters menu option and select new, name the cluster something like my-cluster and click ok. You have now created the shell configuration for our cluster.

Now lets repeat the installation process on the cluster node. After you have installed Glassfish on the “node-agent” you are going to run a command to connect this server to the running admin-node that we installed in the initial installation steps. (Do not start the domain on the node-agent before it is connected to the admin server)

[root@heimdull]# asadmin create-node-agent --host admin-node --port 4848 --user admin my-cluster-agent-1
[root@heimdull]# asadmin start-node-agent my-cluster-agent-1
Please enter the admin user name>admin
Redirecting application output to /opt/glassfish/nodeagents/slave.local/agent/logs/server.log
Command start-node-agent executed successfull
Please enter the admin user name>admin Please enter the admin password>password Please enter the master password [Enter to accept the default]:> Redirecting output to /opt/glassfish/nodeagents/slave.local/agent/logs/server.log Redirecting application output to /opt/glassfish/nodeagents/slave.local/agent/logs/server.log Command start-node-agent executed successfully.

You now have a running cluster of 1 node. Login to the admin console and have a look, cluster of one, nice!

Create the server instance

You do now need to create the server instance which will be running in the cluster. Click on the clusters menu and select my-cluster. Now click the Instances menu button and click new.

Name the instance instance-1 and select the newly added node agent.

You now have the following components running/installed:

– (DAS) Domain Admin Server: This is the server that will controller the “cluster”.

– (NA) Node agent: All members of the cluster needs a nodeagent that connects to the admin server. The nodeagent needs to be started on the cluster member before the admin server can do any monitoring/administration of the member.

– (SI) Server Instance: This is where all the action is, this is the actual “server” that will be added to the server and this is where you application will be running.

Advertisements

to_json and associations

The problem was that I wanted to get to a address that was associated with the store. I was using .to_json but this did not include the address information.

First I had var store = @store.to_json but that only gave me the address_id not the address information. After a little digging I got the syntax correct. Here is my code syntax…

This is my head tag:

<script type="text/javascript">var stores=<%=@stores.to_json(:include => {:store_address => {}})%>;</script>

Than I can use the stores variable in my google maps javascript like so:

var storePoint = new GLatLng(stores[i].store.lat, stores[i].store.lng);
var storeText = '<div id="gmap-content">'+
  '<h4>' + stores[i].store.name + '</h4>'+
  '<em>' + stores[i].store.store_address.address + '</em><br />' +
  '<em>' + stores[i].store.store_address.city + '</em><br />' +
  '<em>' + stores[i].store.store_address.phone + '</em>' +
  '</div>';
var storeMarker = new createMarker(storePoint,storeText)

PS. These are just snips and need more code to work..

Running Tomcat as a service on Linux

Running Tomcat as a service is as easy as getting jsvc to run and it’s all documented in … hmmm well anyways this is how I do it…

Compiling JSVC

[root ~]# cd $TOMCAT_HOME/bin && tar -zxf jsvc.tar.gz
[root ~]# cd jsvc-src && chmod +x configure
[root ~]# ./configure
[root ~]# make

Now there whould be a file called jsvc in $TOMCAT_HOME/bin/jsvc-src/native/ please move this file to $TOMCAT_HOME/bin/jsvc this is the Java service executable that will execute your Tomcat server. The next step is to setup your init file, lets create the file /etc/init.d/tomcat that will be used to start Tomcat with jsvc.

#!/bin/sh
##############################################################
# chkconfig: 345 98 98
### BEGIN INIT INFO
# Provides: Tomcat
# Required-Start: $local_fs $network $remote_fs
# Required-Stop: $local_fs $network $remote_fs
# Default-Start:  3 4 5
# Default-Stop: 0 1 6
# Short-Description: start and stop Tomcat
# Description: Tomcat is a J2EE Application server
### END INIT INFO

CATALINA_HOME=/usr/local/tomcat
DAEMON_HOME=/usr/local/tomcat
TOMCAT_USER=tomcat

# Make sure we load the setenv.sh file 
# since we don't use the startup.sh script
. $CATALINA_HOME/bin/setenv.sh

# for multi instances adapt these lines.
TMP_DIR=/var/tmp
PID_FILE=/var/run/jsvc.pid
CATALINA_BASE=/usr/local/tomcat

CLASSPATH=\
$JAVA_HOME/lib/tools.jar:\
$CATALINA_HOME/bin/commons-daemon.jar:\
$CATALINA_HOME/bin/bootstrap.jar

case "$1" in
  start)
    #
    # Start Tomcat
    #
    #-user $TOMCAT_USER \
    echo $"Starting Tomcat..."
    cd $CATALINA_HOME && \
    $DAEMON_HOME/bin/jsvc \
    -home $JAVA_HOME \
    -Dcatalina.home=$CATALINA_HOME \
    -Dcatalina.base=$CATALINA_BASE \
    -Djava.io.tmpdir=$TMP_DIR \
    -wait 10 \
    -pidfile $PID_FILE \
    -outfile $CATALINA_HOME/logs/catalina.out \
    -errfile '&1' \
    $CATALINA_OPTS \
    -cp $CLASSPATH \
    org.apache.catalina.startup.Bootstrap
    #
    # To get a verbose JVM
    #-verbose \
    # To get a debug of jsvc.
    #-debug \
    exit $?
  ;;

  stop)
  #
  # Stop Tomcat
  #
  echo $"Stoping Tomcat..."
    $DAEMON_HOME/bin/jsvc \
    -stop \
    -pidfile $PID_FILE \
    org.apache.catalina.startup.Bootstrap
    exit $?
  ;;

  restart)
    $0 stop
    $0 start
    exit $?
  ;;

  *)
    echo "Usage: tomcat {start|stop}"
    exit 1;;
esac

Now you can start tomcat using /etc/init.d/tomcat start. You will see TWO java processes running on your computer when Tomcat is started in this way. There is one control process and then there is the wrapper for your java process (Tomcat).

Re-Initialize a MySQL slave (replication)

If your MySQL slave is broken/out of sync or you just want to import the master data here are the steps you should take to jumpstart your MySQL replication.

On the slave

mysql> SLAVE REST;
mysql> exit

On the master

root# mysqldump --routines --master-data --single-transaction  --skip-add-locks --skip-lock-tables --default-character-set=utf8 database > db-backup-`date -I`.sql
Now push this dump to the slave server.

This one is just if you don't have the user or want to change the password.
mysql> grant replication slave on *.* to 'replication'@192.168.60.11 identified by 'slave';

On the slave

mysql> drop schema database;
mysql> create schema database;
root# mysql database < dbdump-date.sql
We did the reset so we have to update user information too
mysql> CHANGE MASTER TO MASTER_USER='replication', MASTER_PASSWORD='slave';
mysql> START SLAVE;
mysql> SHOW SLAVE STATUS\G
and look for:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

Done

EXTRA

Let’s review these parameters and see their effect:

  • -u or --user: This is the user which initiates the dump. Depending on other parameters, the user may need to have quite a few privileges, such as SELECT, RELOAD, FILE, REPLICATION CLIENT etc. Since I do not usually allow for remote root access into mysql, I create a temporary user solely for the purpose of the dump (many times it’s a one-time action), for the specific machine from which the dump is run, and provide this user with all necessary permissions.
  • --routines: It is really an annoyance to have to remember this flag. In contrast to –triggers, which is by default TRUE, the --routines parameter is by default FALSE, which means if you forget it – you don’t get the stored functions and procedures in your schema.
  • --master-data: I always enable binary logs on the MySQL nodes I work on. While binary logs may lead to more IO operations (writing binary logs make for more disk writes, obviously, but also disable some InnoDB optimizations), may consume more disk space (once I’ve worked with a company which had such a burst of traffic, that the binary logs to completely filled their disk in less than one day). If binary logs are enabled, the --master-data parameter allows for easy replication setup: the dump includes the CHANGE MASTER TO MASTER_LOG_FILE='...', MASTER_LOG_POS=... statement, so no need to do stuff like SHOW MASTER STATUS on the dumped node. Optionally, you can set --master-data=2 to have the statement commented.
  • --single-transaction --skip-add-locks --skip-lock-tables: When working with transactional-only storage engines (InnoDB is the most popular choice, but new engines are coming: Falcon, PBXT, Transactional-Maria, SolidDB and more), these parameters allow for a non-interruptive backup, which does not place read locks on all tables. It is possible to keep on reading and writing to the database while mysqldump is running with single transaction. Running in this mode does have its penalty: more IO operations (due to MVCC’s duplication of data while many transactions access the same data for Read/Write). The server is likely to perform more slowly during the dump time.
  • --default-character-set=utf8: I’ve seen so many MySQL installations in which world-wide textual data was stored in the Latin1 charset than I can remember. Many developers, who are testing using standard English data, are not even aware of the issues arrising from changing the data later on to utf8. But even those who are, are usually unaware of the necessity to configure the character set on a per connection basis, or for their specific clients (JDBC or PHP connectors, etc). mysqldump is no different, and if you have non-latin text in your tables, always remember to set this option.

My Upgrade to Snow Leopard Journey

After the upgrade I had a ton of issues getting my rails environment back online which I could have avoided IF I just would have uninstalled all my ports.

The problem was that I had both Ruby 1.8.6 and 1.8.7 installed as ports and that was conflicting to the new 1.8.7 that was installed from the upgrade. I could not get passenger to boot after the upgrade…

SO what I did was upgrade xcode, upgrade port then force uninstall ALL ports and install the ports that I wanted. (Reboot 🙂 ) and then I installed the passenger gem using the native 1.8.7 Ruby install.

Installing Tomcat 6.0.x (5.5.x) on Windows 2008 with IIS7

Download Tomcat binaries for Windows x64

Install Tomcat (Catalina)

  • Run normal 32 bit Tomcat install but install as if it were a 64 bit install. Install to “C:\Tomcat”. Make sure to point Tomcat to a 64 bit JRE.
  • If you chose to install “Tomcat Native” in the above step, replace tomcat native dll’s (found in tomcat’s bin directory) with 64 bit versions
  • Replace tomcat6.exe and tomcat6w.exe (found in tomcat’s bin directory) with 64 bit versions
  • Unblock the exe’s (Properties -> Unblock)
  • Allow tomcat6w.exe to run as Administrator

Configure Tomcat (Catalina)

I recommend using the default 8080 and 8009 first if you are planning on none-default port install. When you have 8080 (telent) and 8009 (IIS7) working you can change the ports.

Configure IIS 7

  • Open IIS 7 Manager
  • Navigate to your host.
  • Double click on the ISAPI and CGI Restrictions icon
  • On the right hand panel, click Add…
  • Point the path to your isapi_redirect.dll file and give it a description eg. tomcat
  • Check “Allow extension path to execute”
  • Now, click on the Default Website and navigate to ISAPI Filters.
  • On the right hand panel, click on Add… and point to your isapi_redirect.dll file, give the filter a name (eg. tomcat)
  • Navigate to your Default Website again
  • Add a virtual directory and name it catalina, point this to the directory containing isapi_redirect.dll
  • Click on the newly created virtual directory catalina
  • Navigate into Handler Mappings, on the right hand side you will see a panel called Actions. Click on Edit Feature Permissions and tick the execute permission.
  • Finally, navigate to your host context again and do a restart.

Thanks to http://jspors.blogspot.com/

Ruby’n Rails AASM or state machine

I wanted to use a state machine plugin for my Order model and found that ttilley-aasm was a good fit for me.

Here is how I installed it:

RAILS_ROOT/config/environmet.rb
config.gem 'ttilley-aasm', :source => 'http://gems.github.com', :lib => 'aasm'
# rake gems:install
# ./script/generate migration add_aasm_state_to_Order aasm_state:string
# rake db:migrate

And now how I test that it worked:

>> require 'aasm'
=> true
>> class Order
>> include AASM
>> aasm_initial_state :new
>> aasm_state :new
>> aasm_state :shipped
>> aasm_event :ship do
?> transitions :to => :shipped, :from => [:new]
>> end
>> end
=> #
>> Order.new.ship!
=> true

That worked now my Order class…

class Order < ActiveRecord::Base

include AASM
aasm_initial_state :in_progress

aasm_state :in_progress, :exit => :generate_order_number
aasm_state :shipped

aasm_event :ship do

transitions :to => :shipped, :from => [:in_progress], :if => :paid?

end

def generate_order_number; …; end
def paid?; …; end

end

That looks great!