Uncategorized


4
Feb 12

Why immutable data objects?

This may be obvious to many, but apprently not to some. Consider the following example:

Car bmw = new Car("BMW");

Wheel wheel = new Wheel();

wheel.setSize(19);

bmw.addWheels(wheel, 4);

save(bmw); // here the car is not saved as underlying mechanism, say Hibernate,
           // decided not to flush until later

Car trabant = new Car("Trabant");

wheel.setSize(13);

trabant.addWheels(wheel, 4);

save(trabant);

flush(); // here the BMW will be saved with 13 inch wheels

What happens here is that the BMW instead of the expected fancy 19 inch wheels ends up having Trabant size, 13 inch, wheels (not that the car looks odd, it just won’t go far). If a unit test does not cover this scenario (there would rather be coverage for a simple scenario with one car, as I don’t believe in perfection of the testing code), the bug may slip into production.

However, this problem can be easily prevented/fixed by introducing immutability.

class Wheel {

private final size;

public Wheel(int size) { this.size = size; }

public int getSize() { return size; }

}

This will force a user of the Wheel class to create a new instance every time instead of reusing existing object if a different configuration required.

Car bmw = new Car("BMW");

bmw.addWheels(new Wheel(19), 4);

Car trabant = new Car("Trabant");

save(bmw);

trabant.addWheels(new Wheel(13), 4);

save(trabant);

flush();

Note, the code becomes slightly shorter as well.

Just to answer a question why don’t we do the same with the Car class and leave the `add` method? – The reason we don’t need to do this is because the internal state of the car is managed via the Car class interface only. However, be careful if a Car instance may be a non-root part of a different objects hierarchy.


24
Apr 11

Plesk + Apache + mod_jk + Tomcat = Good relationship

1. Create an application/domain user:

$ useradd supersite

2. Install Tomcat by copying and unzipping an archive:

$ wget http://apache.mirror.anlx.net/tomcat/tomcat-7/v7.0.12/bin/apache-tomcat-7.0.12.zip
$ unzip apache-tomcat-7.0.12.zip -d tomcat7

3. Create a service configuration for Tomcat 7:

$ cd /etc/init.d
$ edit tomcat7-supersite
#!/bin/bash
#
# tomcat7-supersite
#
# chkconfig: – 81 21
#
# description: Tomcat 7 (supersite) startup script
#

# Source function library.
. /etc/init.d/functions

#Test root privilages
RETVAL=$?
test $EUID = 0  || exit 4

CATALINA_HOME=/home/supersite/tomcat7
JAVA_HOME=/usr/lib/jvm/jdk1.6.0_24
TOMCAT_OWNER=supersite
CATALINA_PID=$CATALINA_HOME/bin/tomcat.pid

export CATALINA_HOME
export JAVA_HOME
export TOMCAT_OWNER
export CATALINA_PID

start() {
        rm -f $CATALINA_PID
        echo -n "Starting Tomcat for $TOMCAT_OWNER:  "
        su $TOMCAT_OWNER -c $CATALINA_HOME/bin/startup.sh
        sleep 2
}

stop() {
        echo -n "Stopping Tomcat for $TOMCAT_OWNER: "
        su $TOMCAT_OWNER -c $CATALINA_HOME/bin/shutdown.sh
}
restart() {
        # Restart
        stop
        echo "Sleeping for 20 seconds …"
        sleep 20
        start
}

status() {
    RETVAL="1"
    if [ -f "${CATALINA_PID}" ]; then
        read kpid < $CATALINA_PID
        if checkpid $kpid 2>&1; then
            echo "$0 is already running (${kpid})"
            RETVAL="0"
        else
            echo "lock file found but no process running for pid $kpid"
        fi
    else
        pid="$(pgrep -u ${TOMCAT_OWNER} java)"
        if [ -n "$pid" ]; then
            echo "$0 running (${pid}) but no PID file exists"
            RETVAL="0"
        else
            echo "$0 is stopped"
        fi
    fi
    return $RETVAL
}

# See how we were called.
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  restart)
        restart
        ;;
  status)
        status
        ;;
  version)
        parseOptions
        "${JAVA_HOME}/bin/java" \
            -classpath "${CATALINA_HOME}/server/lib/catalina.jar" \
            org.apache.catalina.util.ServerInfo
        ;;
  *)
        echo $"Usage: tomcat {start|stop|restart}"
        exit 1
esac

exit $RETVAL

4. Verify the service config with commands:

$ service tomcat7-supersite start
$ service tomcat7-supersite status
$ service tomcat7-supersite restart
$ service tomcat7-supersite stop

5. Configure an AJP connector in $TOMCAT_HOME/conf/service.xml:

<Connector port="8010" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>

If you don’t want your Tomcat to be exposed for direct HTTP requests comment out HTTP/1.1 connector section.

6. Configure Tomcat to respond to the supersite domain (e.g., supersite.com):

<Engine name="Catalina" defaultHost="localhost">
      <Host name="supersite.com" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
            <Alias>www.supersite.com</Alias>
      </Host>
    </Engine>

7. Update your mod_jk to the latest version by getting an appropriate for your system mod_jk*.so file from http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/:

$ cd /etc/httpd/modules
$ mv mod_jk.so mod_jk.bk
$ wget -O mod_jk.so http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/linux/jk-1.2.31/x86_64/mod_jk-1.2.31-httpd-2.2.x.so
$ chmod 755 mod_jk.so

8. Create a new domain (supersite.com) using Plesk panel.

9. Configure your Apache to use mod_jk for the supersite domain:

$ cd /var/www/vhosts/supersite.com/conf
$ edit vhost.conf
ServerAlias www.supersite.com
JkMount /* ajp-veneve

Then execute the following to ask Plesk to include your new vhost.conf into httpd.include:

$ /usr/local/psa/admin/sbin/websrvmng -u –vhost-name=supersite.com

Create jk.conf:

$ cd /etc/httpd/conf.d
$ edit jk.conf
LoadModule jk_module /usr/lib64/httpd/modules/mod_jk.so
JkWorkersFile conf/workers.properties
JkLogFile logs/mod_jk.log
JkLogLevel info
JkLogStampFormat “[%a %b %d %H:%M:%S %Y]“

Create workers.properties in /etc/httpd/conf:

worker.list=ajp-supersite
worker.ajp-supersite.port=8010
worker.ajp-supersite.host=localhost
worker.ajp-supersite.type=ajp13

10. Restart Apache:

$ service httpd restart

11. Deploy you application to Tomcat by copying war file to /home/supersite/tomcat7/webapps. You can also deploy your application as a ROOT application by either renaming the war file to ROOT.war or replacing content of the existing ROOT directory with the war content.

12. Verify if the Tomcat it responding by going to http://supersite.com (also verify http://www.supersite.com).

13. Check Tomcat logs in $TOMCAT_HOME/logs/catalina.out if your application failed to start. This will help to diagnose a possible issue with the application itself.