AJAX in 50 simple lines: Requesting HTML and Producing JSP

First we need a simple JSP as a service.
http://localhost:8080/jsp/request.jsp?name=Chris


<%
String name = request.getParameter("name");
if ( name != null )
out.print( name.length() );
%>

The JSP simply returns the length of the string. The format is simple text, no XML.
Then we need a HTML page. It shows two text fields. One with an attached onkeyup() listener and one which displays the result, the length of the string in the first text field. The AJAX-request is inside a function called call() by the listener.


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Der Längenmann</title>
<script type="text/javascript">
var xmlHttp = false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e2) {
xmlHttp = false;
}
}
@end @*/
if (!xmlHttp && typeof XMLHttpRequest != 'undefined') {
xmlHttp = new XMLHttpRequest();
}
function call()
{
var value = document.getElementById("name").value;
if ((value == null) || (value == "")) return;
var url = "/jsp/request.jsp?name=" + escape(value);
xmlHttp.open("GET", url, true);
xmlHttp.onreadystatechange = update;
xmlHttp.send(null);
}
function update()
{
if ( xmlHttp.readyState == 4)
{
var response = xmlHttp.responseText;
document.getElementById("length").value = response;
}
}
</script>
</head>
<body>
Nutzung online: <b>http://localhost:8080/jsp/request.jsp?name=Chris</b>.
<form>
Name: <input type="text" name="name" id="name" onKeyUp="call();" />
<br>
Length: <input type="text" name="length" id="length" />
</form>
</body>
</html>

The best solution is to use an AJAX framework like prototype, but this is only a very simple example „how this stuff works“ (is there a copyright on the sentence?)

Restart a died Thread

If a Thread dies the system can inform you via a Thread.UncaughtExceptionHandler. You can use it to restart a Thread:

import java.awt.Frame;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import javax.swing.JDialog;
import javax.swing.JTextArea;

public class Main
{
public static void main( String[] args )
{
ThreadHandler.startThread();
}
}

class ThreadHandler
{
static void startThread()
{
Thread t = new Thread( new MyCommand() );
UncaughtExceptionHandler ueh = new MyUncaughtExceptionHandler();
t.setUncaughtExceptionHandler( ueh );
t.start();
}

static class MyCommand implements Runnable
{
public void run()
{
int i = 0;

System.out.println( 12 / i ); // Provoke a RuntimeException
}
}
}

class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler
{
public void uncaughtException( Thread thread, Throwable throwable )
{
StringWriter stringWriter = new StringWriter();
PrintWriter w = new PrintWriter( stringWriter );
throwable.printStackTrace( w );

JDialog d = new JDialog( new Frame(), true );
d.add( new JTextArea( stringWriter.toString() ) );
d.setTitle( thread.getName() + " --- " + throwable.getMessage() );
d.pack();
d.setVisible( true );

ThreadHandler.startThread(); // Restart Thread
}
}

Buchkritik "Java 6 Plattform Revealed"

Ein frühes Buch (Juni 2006) zu Java 6, aber es zeigt alle wesentlichen Eigenschaften der neuen Version. Sehr gut gefallen hat mit die Beschreibung von CookieHandler, CookieManager & Co. KG, etwas, was ich noch nie ordentlich erklärt gefunden habe. Der einzige Fehler, der mir aufgefallen ist, befindet sich auf Seite 111, wo eine Variable statt rs (für ResultSet) fälschlicherweise st heißt. Eine präzisere Beschreibung für Web Services und JAXB liefert das Buch leider nicht — nur ein paar Standard-Beispiele und eine schlaffe Aufzählung der Annotationen — aber dafür gibt es ja andere Bücher aus der Ecke der Java EE Literatur. Auch StAX ist nicht sonderlich präzise und späteren Neuerungen, wie Java DB oder GroupLayout finden keine Erwähnung. Das gleiche gilt für neue Funktionen copySign(), getExponent(), nextAfter(), nextUp(), scalb() aus Math/StrictMath. Eigentlich wäre jetzt Zeit für ein Buch-Update.

John Zukowski. APress. ISBN 1590596609. 220 Seiten

ROME: Lesen/Schreiben von Atom/RSS-Feeds

Rome ist eine Bibliothek zum Lesen/Schreiben/Konvertieren von Atom/RSS-Feeds in den Versionen

  • RSS 0.90
  • RSS 0.91 Netscape
  • RSS 0.91 Userland
  • RSS 0.92/RSS 0.93/RSS 0.94
  • RSS 1.0/RSS 2.0
  • Atom 0.3/Atom 1.0

Ein Beispiel ist schnell programmiert und die API (Doku hier) ist relativ einfach.

package com.sun.syndication.samples; 
import java.io.FileWriter;
import java.net.URL;
import java.util.List;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
public class FeedReader
{
@SuppressWarnings("unchecked")
public static void main( String[] args )
{
try
{
URL feedUrl = new URL( "http://javainsel.blogspot.com/atom.xml" );
SyndFeedInput input = new SyndFeedInput();
SyndFeed feed = input.build( new XmlReader( feedUrl ) );
StringBuilder sb = new StringBuilder( 1024 );
for ( SyndEntry syndFeed : (List<SyndEntry> )feed.getEntries() )
{
sb.append( "<b>" + syndFeed.getTitle() + "</b>" );
sb.append( "<blockquote>" + ((SyndContent)syndFeed.getContents().get(0)).getValue() + "</blockquote>" );
}
// JFrame f = new JFrame( "Einfache Feed Anzeige" );
// f.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
// JEditorPane editor = new JEditorPane( "text/html", sb.toString() );
// editor.setEditable( false );
// f.add( new JScrollPane(editor) );
// f.setSize( 600, 400 );
// f.setVisible( true );
FileWriter w = new FileWriter( "c:/out.html" );
w.write( sb.toString() );
w.close();
}
catch ( Exception e )
{
e.printStackTrace();
}
}
}

Wenn die JEditorPane besser wäre, könnte man auch (schnell) was sehen. Daher schreibt das Programm eine selbst generierte HTML-Seite ins Dateisystem.

Buchkritik zu "Pro Apache Geronimo" von Kishore Kumar

Pro Apache Geronimo. Open Source Lightwave J2EE Container
Kishore Kumar. apress. ISBN 1590596420. April 2006. 252 Seiten
 Ich habe zwar Apache Geronimo nicht im Einsatz (und kann mir auch nicht vorstellen, den Server in der nahen Zukunft zu nutzen, da die Verbreitung zu gering ist), aber dennoch wollte ich etwas über die Architektur kennen lernen. Kumar vermittelt zunächst die Basis vom Geronimo Application-Server 1.x und stellt den Kern, einen IOC-Container, der GBeans verwaltet, vor. Er geht kurz über die üblichen Bean-Typen und zeigt, wie sie deployed werden und welche spezifischen Deployment-Deskriptoren es gibt. Gut gefallen hat mir ein Kapitel zur Web-Service Fassade für eine Session-Bean, und wie J2EE Connectoren programmiert und eingebunden werden. Dass das Buch jedoch etwas zu Java EE 5 enthält — so steht es auf dem Buchrücken „Includes some Java EE 5“ — ist eine glatte Lüge. Januar 2007

Character „Chunking“ bei SAX

Bei langen Zeichenketten ist es nicht zwingend, dass sie in einem Rutsch der characters() Methode übergeben werden.

<TSeq_sequence>
 TAACCCTAACCCTAACCCTAACCCTAAC
</TSeq_sequence>

Denkbar ist hier ein (skizzierter) Aufruf von

characters(„T“);
characters(„AACCCTAAC“);
characters(„CCTAACCCTAACCCTAAC“);

Die Anwendung muss mit Character „Chunking“ rechnen und damit umgehen. Man kann es nicht abstellen! Viele Parser teilen die CDATA-Sektion auf, so dass nach jedem Carriage Returns einmal characters() aufgerufen wird.

Eine Lösung ist, die Zeichen zwischenzuspeichern, etwa in einem StringBuilder/StringBuffer.

public void characters(char[] ch, int start, int length)
throws SAXException {
currentText.append( ch, start, length );
}

Wenn endElement() aufgerufen wird, kann man den Puffer auswerten.

Eine interessante Idee ist, einen Delegate zu bauen, der sich für den SAX-Parser wie ein ContentHandler verhält, aber characters() abfängt und die Zeichen intern speichert. Alle anderen Methoden wie endDocument(), … gehen zum Original.
Zuvor jedoch werden die Methoden „flushen“, also ein Aufruf von characters() auf dem Original durchführen und alle Zeichen übergeben.

Anschauen kann man eine solche unter http://koders.com/java/fid607C6038FB8FD26D12EED5B32042D3EF48038AA7.aspx. Die Implementierung steht unter der Apache-Lizenz.

/*
* Copyright 2004 Outerthought bvba and Schaubroeck nv
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.outerj.daisy.htmlcleaner;


import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.Locator;
import org.xml.sax.Attributes;

class MergeCharacterEventsHandler implements ContentHandler {
private ContentHandler consumer;
private char[] ch;
private int start = 0;
private int length = 0;

public MergeCharacterEventsHandler(ContentHandler consumer) {
this.consumer = consumer;
}

public void characters(char ch[], int start, int length) throws SAXException {
char[] newCh = new char[this.length + length];
if (this.ch != null)
System.arraycopy(this.ch, this.start, newCh, 0, this.length);
System.arraycopy(ch, start, newCh, this.length, length);
this.start = 0;
this.length = newCh.length;
this.ch = newCh;
}

private void flushCharacters() throws SAXException {
if (ch != null) {
consumer.characters(ch, start, length);
ch = null;
start = 0;
length = 0;
}
}

public void endDocument() throws SAXException {
flushCharacters();
consumer.endDocument();
}

public void startDocument() throws SAXException {
flushCharacters();
consumer.startDocument();
}

public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
flushCharacters();
consumer.ignorableWhitespace(ch, start, length);
}

public void endPrefixMapping(String prefix) throws SAXException {
flushCharacters();
consumer.endPrefixMapping(prefix);
}

public void skippedEntity(String name) throws SAXException {
flushCharacters();
consumer.skippedEntity(name);
}

public void setDocumentLocator(Locator locator) {
consumer.setDocumentLocator(locator);
}

public void processingInstruction(String target, String data) throws SAXException {
flushCharacters();
consumer.processingInstruction(target, data);
}

public void startPrefixMapping(String prefix, String uri) throws SAXException {
flushCharacters();
consumer.startPrefixMapping(prefix, uri);
}

public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
flushCharacters();
consumer.endElement(namespaceURI, localName, qName);
}

public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
flushCharacters();
consumer.startElement(namespaceURI, localName, qName, atts);
}
}


Prefuse: Immer wieder schöne Graphen

Das „prefuse visualization toolkit“ ist eine feine API zur Informationsvisualisierung. In der visualization gallery gibt es etwa folgendes zu sehen und auszuprobieren:

 


Small-World Networks by Stephen Frowe Ingram

 

 

Vizster by Jeffrey Heer and danah boyd

 

 

Flow Map Layout by Doantam Phan

 

 
NameVoyager by Martin Wattenberg, rebuilt by Jeffrey Heer

 

 
¢ongress by Jeffrey Heer

 

 
zipdecode by Ben Fry, rebuilt by Jeffrey Heer

 

 
TreeMap Demo by Jeffrey Heer

 

 
RadialGraphView Demo by Jeffrey Heer

 


TreeView Demo by Jeffrey Heer

 

 
GraphView Demo by Jeffrey Heer

 

 
FisheyeMenu Demo by Jeffrey Heer

 

 
DataMountain Demo by Jeffrey Heer

Nice Office Access: Leichter OpenOffice programmieren

Unter http://ubion.ion.ag/solutions/004niceofficeaccess gibt’s eine einfachere API unter der LGPL, um OpenOffice-Aufgaben zu erledigen. Java UNO kann zwar alles, ist aber nicht gerade einfach zu nutzen. Mit Nice Office Access (NOA) soll das ganze einfacher gehen. Es bietet einen leichtgewichtigen Wrapper für viele UNO Schnittstellen.

Da ich das noch nicht genutzt habe, sind Kommentare willkommen.

Closures – Muss das wirklich sein?

Nach dem vierten Proposal (http://www.javac.info/closures-v04.html) für Closures von Gilad Bracha, Neal Gafter (der mit dem Java-Puzzlers), James Gosling und Peter von der Ahé (nach seiner Whishlist unter http://blogs.sun.com/ahe/entry/java_se_7_wish_list werden weitere abgefahrene Sachen möglich sein) wird in der Community heftig diskutiert, ob Closures nötig sind. Ich finde sie toll! Zwar sehe ich schon meine Teilnehmer über den Ausdrücken brüten und zweifeln an der Aussage „Java ist eine einfache objektorientierte Programmiersprache“ zweifeln, doch denke ich, dass es unausweichlich ist, Java mehr sprachliche Möglichkeiten zu bieten.

Java: A simple, object-oriented, network-savvy, interpreted, robust, secure, architecture neutral, portable, high-performance, multithreaded, dynamic language […] Java omits many rarely used, poorly understood, confusing features of C++ that in our experience bring more grief than benefit. [http://java.sun.com/docs/overviews/java/java-overview-1.html]

Dass Java im Moment so viele Veränderungen erfährt ist vielleicht auch eine Frage der Wahrnehmung. Sun war mit Grammatikänderungen bisher sehr konservativ und seit mehr als 10 Jahren haben wir bis auf den Wechsel von Java 1.0 auf Java 1.1 und Java 1.4 auf Java 5.0 kaum Änderungen gesehen; strictfp/Sprachänderungen wäre man so ein Außenseiter. Nun gibt es stärkere Veränderungen, wie wir sie bei anderen Sprachen auch erleben. C# hat sich in den letzten Jahren unglaublich verändert — was als Java-Klon begann, ist heute eigenständig und als Sprache hoch innovativ. Mitunter starke strukturelle Änderungen lassen sich auch bei Skriptsprachen ausmachen, etwa Python (trinärer Operator, try/except/finally), PHP (die ganzen OOP-Eigenschaften), Perl (für Perl 2.6 ebenfalls Änderungen der OOP-Schreibweise/perl6-language-objects und funktionale Programmierelemente geplant) aber auch C++ und SQL. Als Java-Entwickler hat uns Sun nur in den letzten Jahren so „erzogen“ dass es kaum große Änderungen gab, was sich nun ändert. Hier muss Sun uns also wieder „umerziehen“.

Dass Java keine einfache Programmiersprache ist, müsste jedem eigentlich bewusst geworden sein, der didaktisch versucht, Konzepte wie Generics zu vermitteln. Unternehmen müssen auch mit nicht-Cracks Software entwickeln können und können nicht darauf bauen, dass alle Mitarbeiter Spezifikationen lesen und Best-Practices befolgen. (IMHO kann man mit OOP-Spezialisten in jeder Programmiersprache exzellente Ergebnisse erziehlen.) Eine Sprache muss daher auch immer ein bisschen Narrensicher sein. (Ein kleiner Seitenhieb auf Perl, der Sprache, der man „Write Once Read Never“ (WORN) nachsagt.) Da sehe ich in Closures auf jeden Fall ein Problem, denn während Generics doch noch einfach zu lesen sind (von der Deklaration sprechen wir nicht!) sieht das bei Closure-Nutzungen etwas anders aus. Hier muss der Java-Entwickler wieder eine neue Syntax lernen.

Bisher ist in der neuen Syntax kein Wort von neuen Schlüsselwörtern. Das macht die Anwendung einfacher als es bei Java 5 mit enum war. Ein weiterer Punkt ist, dass man über allgemeine Closures Dinge schreiben kann, die wie spezielle Lösungen aussehen. Ein häufig zitiertes Beispiel ist der Lock:

withLock( lock ) {
    System.out.println( "Closures in Java 7" );
}

Das ist eine Kurzform für

 
withLock( lock, {=>
    System.out.println( "Closures in Java 7" );
} );

Es ist gerade nicht withLock() ein spezielles Java-Konstrukt, sondern nur die Anwendung eines allgemeinen Closures. Intern wird das Umgesetzt über übliche Schnittstellen. Und mit { => } sieht man schon, wie Closures in Java aussehen können.

In der Summe finde ich Closures toll und freue mich schon. Zwar habe ich schon die ersten Ideen, wie man das didaktisch umsetzen kann, aber mal sehen, was bis dahin geschrieben wird. Was Madbean unter http://madbean.com/2006/closure/ zeigt, finde ich schon nett. Doch bis Java 7 „freigelassen“ wird, dauert es noch. Wer sich schon einmal vorbereiten möchte, der sollte sich zum Beispiel die Präsentation von Neal Gafter unter http://www.bejug.org/confluenceBeJUG/display/PARLEYS/Closures+for+Java anschauen.

S_t_ring — Hoppala! Ein neues Framework? Habe ich was verpasst?

Beim Durchsehen der Webseiten meine Seminarkonkurrenz ist mir ein Link auf ein Buch aufgefallen, was mich zu http://entwickler-press.de brachte. Interessiert über ein neues Spring 2.0 Buch musste ich erfahren, dass es schon wieder ein neues Framework gibt: String. Interessant. Von der Webseite zitiert:

„Das Buch beschreibt das Spring-Framework im Enterprise-Einsatz. Es zeigt die Erweiterungen und neuen Möglichkeiten der aktuellen Version 2.0 und stellt weitere Frameworks vor, die sich im Projektalltag gut mit String kombinieren lassen. Die Autoren legen Ihren Schwerpunkt auf die Datenbankanbindung und Testing.“

Das oberste Stack-Element duplizieren

Die Klasse Stack besitzt zwar die Basisfunktionalität, die ein Stapel besitzen sollte, aber auch nicht mehr. Hin und wieder wünschen wir uns aber eine Funktion, die das oberste Stack-Element dupliziert, kurz dup().

Bei der Implementierung treten allerdings zwei Fragen auf, mit denen zwei völlig unterschiedliche Lösungsansätze verbunden sind. Da die Klasse Stack wie die anderen Datenstrukturen auf Objekte ausgelegt ist, müssen wir uns darüber Klarheit verschaffen, wie das obere Objekt dupliziert werden soll. Soll eine Kopie der Objekt-Referenz neu auf den Stapel gelegt werden oder etwa das gesamte Objekt geklont werden?

Die einfache Lösung

Die einfachste Lösung besteht darin, das oberste Objekt einfach mittels der schon vorhandenen Stack-Methoden push() und peek() draufzulegen. Nehmen wir an, wir haben eine Unterklasse DupStack, dann sieht die erste Variante zum Clonen so aus:

void dup() /* throws EmptyStackException */
{
push( peek() );
}

peek() gibt aber lediglich eine Referenz auf das Objekt zurück. Und das anschließende push() speichert diese Referenz dann auf dem Stapel. Nehmen wir an, wir haben zwei StringBuffer-Objekte auf dem Stapel. Wenn wir nun dup() aufrufen und den String ändern, der oben auf dem Stapel liegt, so ändern wir automatisch das zweite Element gleich mit. Dies ist aber nicht unbedingt beabsichtigt, und wir müssen uns Gedanken über eine alternative Lösung machen. Wir sehen, dass dup() in der Klasse Stack fehlt, weil seine Implementierung davon abhängt, ob eine Referenz- oder eine Wertsemantik für Kellerelemente gewünscht ist.

Die kompliziertere Lösung mit Klonen

Um das oberste Stack-Element zu kopieren, bietet sich die clone()-Methode von Object an. All die Objekte, die sich klonen lassen, und das sind längst nicht alle, implementieren das Interface Cloneable. Nun ließe sich einfach folgern: Wenn das zu duplizierende Objekt ein Exemplar von Cloneable ist, dann können wir einfach die clone()-Methoden aufrufen und das zurückgegebene Objekt mittels push() auf den Stapel bringen.

void dup2() throws CloneNotSupportedException
{
try
{
Object top = peek();

if ( top instanceof Cloneable )
push( top.clone() );

}
catch ( EmptyStackException e ) { }
}

Beziehungsweise

void dup3() throws CloneNotSupportedException /*, EmptyStackException */
{
push( peek().clone() );
}

Dies funktioniert für die meisten Objekte, allerdings nicht für Objekte der Klasse Object. Denn clone() der Klasse Object ist protected – wir dürfen also von außen nicht dran, nur eine Unterklasse und die Klasse selbst. Hier haben wir also zwei Probleme.

  • Leider lässt sich nur mit Aufwand überprüfen, ob das Objekt auf dem Stapel auch wirklich ein pures Object ist, denn alle Objekte sind instanceof Object. Glücklicherweise gibt es kaum eine Anwendung, wo reine Object-Elemente gesichert werden müssen.
  • Was machen wir mit Objekten, die nicht klonbar sind? Leider gibt es für diese Frage keine direkte Antwort. Eine universelle Stack-Klasse mit einer uneingeschränkten dup()-Methode gibt es nicht. Wir müssen als Stack-Benutzer festlegen, dass das oberste Element Clonable ist, um zumindest eine eigene Implementierung nutzen zu können. Oder wir bleiben dabei, bei nicht klonbaren Objekten doch nur die Referenz zu duplizieren. Das wäre zumindest für eineindeutige Objekte mit Wertsemantik die ideale Lösung.

@ManagedResource in Spring is really cool

First, write a class and annotate it:

package com.javatutor.spring.jmx;

import java.util.HashMap;

import java.util.Map;

import org.springframework.jmx.export.annotation.ManagedAttribute;

import org.springframework.jmx.export.annotation.ManagedOperation;

import org.springframework.jmx.export.annotation.ManagedResource;

@ManagedResource( objectName = "com.javatutor.spring.jmx:name=StringMap" )

public class StringMapImpl

{

private Map<String, String> map = new HashMap<String, String>();

@ManagedAttribute

public int getSize()

{

return map.size();

}

@ManagedOperation

public String get( String key )

{

return map.get( key );

}

@ManagedOperation

public String put( String key, String value )

{

return map.put( key, value );

}

public void remove( String key )

{

map.remove( key );

}

}

Next, write a spring config file:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<bean id="StringMap" class="com.javatutor.spring.jmx.StringMapImpl" />

<bean id="MBeanExporter"

class="org.springframework.jmx.export.MBeanExporter">

<property name="assembler" ref="MBeanInfoAssembler" />

<property name="autodetect" value="true" />

<property name="namingStrategy" ref="NamingStrategy" />

</bean>

<bean id="AnnotationJmxAttributeSource"

class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"

/>

<bean id="NamingStrategy"

class="org.springframework.jmx.export.naming.MetadataNamingStrategy">

<property name="attributeSource" ref="AnnotationJmxAttributeSource" />

</bean>

<bean id="MBeanInfoAssembler"

class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">

<property name="attributeSource" ref="AnnotationJmxAttributeSource" />

</bean>

</beans>

Now the client:

package com.javatutor;

import javax.swing.JOptionPane;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.javatutor.spring.jmx.StringMapImpl;

public class SpringWithJmxExample

{

public static void main( String[] args )

{

ApplicationContext beFac = new ClassPathXmlApplicationContext( "springJmx.xml"

);

StringMapImpl cacheBean = (StringMapImpl) beFac.getBean( "StringMap" );

cacheBean.put( "Key", "Value" );

System.out.println( cacheBean.get("Key") );

JOptionPane.showMessageDialog( null, "End" );

}

}

Start the program. Do not forgett to start with -Dcom.sun.management.jmxremote.
Start JConsole and enjoy.

 

Inselraus: Die Datenbank Derby

Derby (http://db.apache.org/derby/) ist ein pures Java-RDBMS unter der freien Apache-Lizenz. Die Datenbank geht auf Cloudscape zurück, was IBM Mitte 2004 auf der LinuxWorld in San Francisco der Apache Software Foundation übergeben hat. (1999 übernahm Informix Software Inc.XE „Informix Software Inc.“ die Datenbank Cloudscape von Cloudscape Inc., doch IBM übernahm die Datenbanktechnologien von Informix im Jahre 2001.) Ein großer Vorteil von Derby sind neben dem geringen Speicherbedarf die Transaktionsunterstützung, Trigger und SQL-Kompatibilität mit DB2.

Download und Vorbereitung

Auf der Download-Seite befinden sich drei Archive, wovon wir eine Datei mit der Endung -bin beziehen (etwa db-derby-10.1.1.0-bin.zip) und auspacken. Wir nehmen zu Testzwecken c:\Programme\derby an, sodass in C:\Programme\derby\frameworks\NetworkServer\bin die Skripte zum Starten und Stoppen des Servers zu finden sein sollten.

Derby lässt sich in zwei Modi fahren: als eingebettetes Datenbanksystem und als Netzwerkserver. Im Fall eines eingebauten Datenbanksystems ist lediglich die Klasse für den eingebetteten Treiber zu laden und die Datenbank zu bestimmen, schon geht’s los:

Class.forName( „org.apache.derby.jdbc.EmbeddedDriver“ );
Connection con = DriverManager.getConnection( „jdbc:derby:OpenGeoDB;create=true“ );

Wir wollen Derby als Netzwerkserver starten, um mit unterschiedlichen Clients – etwa einem Eclipse-Plugin – auf die Datenbank zugreifen zu können. In diesem Modus horcht Derby über TCP/IP an einem Port (standardmäßig 1527) auf eingehende Verbindungen.

Vor dem Start muss die Umgebungsvariable JAVA_HOME gesetzt sein, und DERBY_INSTALL auf das Installationsverzeichnis zeigen. Zunächst gehen wir in startNetworkServer.bat und setzen dort die nötigen Umgebungsvariablen:

Listing 20.1 startNetworkServer.bat


@REM — This file for use on Windows systems
@REM ———————————————————

@echo off
set JAVA_HOME=C:\Programme\Java\jdk1.5.0
set DERBY_INSTALL=C:\Programme\derby\

Ebenso setzen wir in startNetworkServer.bat die Umgebungsvariablen passend, da wir den Server auch wieder stoppen wollen.

Server-Start und weitere Tools

Nun lässt sich – etwa mit Doppelklick – das Skript startNetworkServer.bat starten, und die Datenbank quittiert freundlich:

Der Server ist bereit, am Port 1527 Verbindungen zu akzeptieren.

Das Programm sysinfo zeigt Versionsnummer und Klassenpfad an. Mit dem interaktiven Werkzeug ij lassen sich SQL-Anweisungen abschicken und so die ersten Versuche mit der Datenbank aufnehmen. dblook extrahiert das Datenbankschema.

JDBC-Treiber

Für einen JDBC-Zugriff ist ein JDBC-Treiber nötig, der bei Derby für eine Client-/Server-Kommunikation nicht dabei ist, denn Derby nutzt die Distributed Relational Database ArchitectureXE „Distributed Relational Database Architecture“ (DRDAXE „DRDA“), die auch DB2 verwendet. DRDA ist eine von der Open GroupXE „Open Group“ definierte Möglichkeit, von einem Client eine entfernte relationale Datenbank anzusteuern. Auf http://www-128.ibm.com/developerworks/db2/downloads/jcc/ ist die Datei db2jcc_for_derby.zip aufgeführt, die – nach einer Registrierung – auf der nächsten Seite unter »Released product: IBM Cloudscape (IBM DB2 JDBC Universal Driver, for Cloudscape/Derby)« heruntergeladen werden kann. Die beiden Jar-Dateien aus dem Archiv, db2jcc.jar und db2jcc_license_c.jar, sind in den Klassenpfad aufzunehmen. Für den Client-/Server- Modus von Derby benötigen wir keine weiteren Jar-Dateien, insbesondere keine aus dem lib-Verzeichnis von Derby.