Tips

chkconfig: Init-Skript für Apache Tomcat

chkconfig und service sind zwei Werkzeuge unter Redhat, die die Runlevel-Verwaltung vereinfachen. Damit chkconfig feststellen kann, für welche Runlevel der betreffende Dienst aktiviert sein soll, muss man Meta-Informationen in den Skript-Header einfügen.

Apache Tomcat bringt in $CATALINE_HOME/bin/jsvc.tar.gz die Quellen eines Verwaltungswerkzeugs für sich mit. Dieses Paket kann man unter Centos 5.2 (installieren der RPMs gcc-c++ und autoconf ist notwendig) folgendermaßen übersetzen:

tar xfz jsvc.tar.gz

cd jsvc-src

./configure –with-java=/usr/java/default

make

cp jsvc ..

Mit dem folgenden Init-Skript kann man nun service und chkconfig für Apache Tomcat nutzen:

#!/bin/sh
#
# Startup script for the Apache Tomcat servlet container
#
# chkconfig: 345 55 25
# description: Apache Tomcat servlet container
# processname: tomcat
# pidfile: /var/run/tomcat/jsvc.pid
# config: /opt/apache-tomcat-6.0.20/conf/server.xml
 
JAVA_HOME=/usr/java/default
CATALINA_HOME=/opt/apache-tomcat-6.0.20
DAEMON_HOME=/var/run/tomcat
TOMCAT_USER=apache
 
# for multi instances adapt those lines.
TMP_DIR=/var/tmp
PID_FILE=/var/run/tomcat/jsvc.pid
 
CATALINA_OPTS=
CLASSPATH=$JAVA_HOME/lib/tools.jar:$CATALINA_HOME/bin/commons-daemon.jar:$CATALINA_HOME/bin/bootstrap.jar
 
prog="Tomcat"
 
# Source function library.
. /etc/rc.d/init.d/functions
 
# Source networking configuration.
. /etc/sysconfig/network
 
case "$1" in
start)
#
# Start Tomcat
#
echo -n "Starting $prog: "
$CATALINA_HOME/bin/jsvc \
-user $TOMCAT_USER \
-home $JAVA_HOME \
-Dcatalina.home=$CATALINA_HOME \
-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 \
if [ $? == 0 ];
then
action
else
action
fi
;;
 
stop)
#
# Stop Tomcat
#
echo -n "Stopping $prog: "
$CATALINA_HOME/bin/jsvc \
-stop \
-pidfile $PID_FILE \
org.apache.catalina.startup.Bootstrap
if [ $? == 0 ];
then
action
else
action
fi
;;
 
*)
echo "Usage tomcat start/stop"
exit 1;;
esac


eclipse

Netbeans vs. Eclipse

eclipse

Ich muss ja zugeben, ich war nie ein großer Fan von Netbeans und habe immer Eclipse vorgezogen. Aber mit der Zeit habe ich das Gefühl, dass Eclipse immer schwächer wird; sei es die unnötig komplizierte Integration von SCM-Plugins oder die immer schwächer werdende WTP (immer mehr Features, aber auch immer mehr Bugs). Auch die lange Reaktionszeit für einige wirklich störende Bugs (z.B. die fehlenden Server-Adapter in Eclipse Ganymede, welche jetzt mit einem Update nachgeschoben wurden) ist wirklich unschön.

netbeansDagegen scheint sich Netbeans langsam zu mausern. Die aktuelle Version bringt nicht nur native Maven-Unterstützung (was ich sehr schätze) mit, sondern auch integrierte SCM-Plugins für SVN/CVS/Mercurial. Außerdem gibt es nun SUN’s Project Kenai direkt aus dem Menü, sodass man seine Opensource-Projekte bei Kenai direkt aus Netbeans heraus verwalten kann. Rein subjektiv finde ich auch, dass die Oberfläche von Netbeans weitaus flotter ist und diese IDE im Vergleich zu Eclipse weniger Speicher verbraucht.

Mein nächstes Projekt wird jedenfalls ganz sicher mit Netbeans geschrieben werden :-) Unter http://www.certpal.com/blogs/2009/08/your-favorite-java-ide/ gibt es eine Umfrage zur beliebtesten Java-IDE (wenn auch nicht sehr repräsentativ wie ich finde). Bisher liefern sich Eclipse (45%) und Netbeans (47%) ein knappes Rennen.

5 gute Gründe gegen Nachtspeicherheizung

Da ich mich im Moment etwas nach einer neuen Wohnung umschaue, treffe ich häufig auf Wohnungen mit Nachtspeicherheizungen, die für mich aus unten aufgeführten Gründen nicht in Frage kommen:

  1. Heizen mit Strom ist teuer
  2. Heizen mit Strom ist umweltschädlich (-er als Gas)
  3. bei Wetterumschwüngen ist die Wohnung kalt (oder warm)
  4. durch Verschwelen von Staub und Verwirbelung der Asche kann die Wohung stark verdrecken
  5. nicht alle Anbieter bieten Nachtstromzähler und -tarife. Ich möchte nicht wieder bei RWE landen.

SEO-friendly URLs in PHP (5) w/o mod_rewrite

I showed Sebastian my little SEO-friendly PHP example, so why shouldn’t I share it with you people?

Many of you know one or more PHP frameworks like Zend, CakePHP or Symfony which provide SEO-friendy URLs via so called routing functions. Routing it is, because there is a centralized object instance, which delegates function calls to the appropiate class. Implementing this is quite easy with PHP 5 which provides autoloading of classes and (due to its typeless language structure) function loading on demand via “string” variables.

Lets start with a simple class named booking:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class booking
{
	private $params;
 
	function __construct($params)
	{
		$this->params = $params;
		echo 'Constructor of class booking. <br />';
	}
 
	function sayHello()
	{
		echo 'Hello World in class booking. <br />';
		echo var_dump($this->params);
	}
}
?>

The real logic takes place in the class router, which explodes the request uri and resolves the classes/methods we want to call:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
class router
{
	private $origUrl;
	private $controller;
	private $action;
	private $params;
 
	public function __construct($origUrl)
	{
		$this->origUrl = $origUrl;
		$this->extractController();
	}
 
	private function extractController()
	{
		$urlParts = explode('index.php', $this->origUrl);
		$mvcParts = explode('/', $urlParts[1]);
		$this->controller = $mvcParts[1];
		$this->action = $mvcParts[2];
		$this->params = $mvcParts[3];
	}
 
	public function connect()
	{
		$controller = $this->controller;
		$action = $this->action;
		$params = $this->params;
 
		if (class_exists($controller, true))
		{
			$controllerInstance = new $controller($params);
		}
		else
		{
			throw new Exception('There was no controller named ' . $controller);
		}
		if (method_exists($controllerInstance, $action))
		{
			$controllerInstance->$action();
		}
		else
		{
			throw new Exception('There was no action named ' . $action);
		}
	}
}
?>

This is our index.php which instantiates the router object:

1
2
3
4
5
6
7
<?php
 
require_once('config.inc.php');
 
$router = new router($_SERVER['REQUEST_URI']);
$router->connect();
?>

And a config.inc.php, which extends our include path for classes and defines the required autoload function:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
 
set_include_path(get_include_path() 
	. PATH_SEPARATOR 
	. dirname(__FILE__)
	. DIRECTORY_SEPARATOR
	. 'classes');
 
function __autoload($class_name)
{
	require_once $class_name . '.php';
}
?>

A call of index.php/booking/sayHello/123456 will result in the following output:

Constructor of class booking.
Hello World in class booking.
123456

Further explanation needed? Comment please :-)

PS: Attached example files as zip.
PPS: This is no production code!

example