Adjust font size in Swing applications global

Use this snippet to set the size of all fonts of the current Swing look and feel:

public static void setFontSizeGlobal( int size )
{
for ( Enumeration e = UIManager.getDefaults().keys(); e.hasMoreElements(); )
{
Object key = e.nextElement();
Object value = UIManager.get( key );

if ( value instanceof Font )
{
Font f = (Font) value;

UIManager.put( key, new FontUIResource( f.getName(), f.getStyle(), size ) );
}
}
}

Can we compact the code? Not with the extended for! It is true that UIDefaults is a subtype of Hashtable but the methods entrySet() or keySet() returns an empty collection.

JAXB 2.0 und XJC in einem Ant-Skript nutzen

Für Konfigurations-Dateien wollte ich JAXB 2.0 nutzen und es war wirklich einfach. Zuerst habe ich mit XMLBeans begonnen, was ebenfalls sehr einfach zu nutzen ist, doch die Annotationen gefielen mir bei JAXB 2.0 besser. Der Client, der auf die generierten Beans zugreift, muss nur geringfügig verändert werden, denn XMLBeans repräsentiert Unterelemente in einem Array, währenddessen JAXB eine Collection verwendet.

Nach dem Download von JAXB müssen sich für den Client im Pfad befinden: jaxb-api.jar, jaxb-impl.jar, activation.jar, jsr173_1.0.jar. Für den Ant-Task und die Generation von Klassen aus eine Schema-Datei ist jaxb-xjc.jar verantwortlich.

Für den Ant-Task meldet man (für Eclipse) am einfachsten alle genannten Java-Archive unter den Ant > Runtime > Classpath > Global Entries an. Die Ant-Datei nutzt für die Generation der Bean dann folgendes:

<project default="all" basedir=".">

<target name="all">

<xjc schema="schemas/ppt_join.xsd" target="../src/core"
package="com.javatutor.cw.ppt.jaxb.pptjoin" />

 </target>

</project>

Die Schema-Datei sieht für meine Konfigurations-Dateien so aus:

<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:po="http://javatutor.com/pptjoin"
targetNamespace="http://javatutor.com/pptjoin"
elementFormDefault="qualified">
<xs:element name="ppt-join">
<xs:complexType>
<xs:sequence>
<xs:element name="options" type="po:options" minOccurs="0" maxOccurs="1" />
<xs:element name="fileset" type="po:fileset" />
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:complexType name="fileset">
<xs:sequence>
<xs:element name="file" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<xs:complexType name="options">
<xs:sequence>
<xs:element name="removeHidden" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="destination-file" type="xs:string" minOccurs="0" maxOccurs="1" />
</xs:sequence>
</xs:complexType>

</xs:schema>

Nutze ich nun JAXB 2.0? Ehrlich gesagt nicht. Denn für kleine Konfigurationsdateien finde ich persönlich JAXB etwas zu aufwändig. Nun bin ich wieder am Anfang, bei XStream.

Spring, Hibernate und HSQLDB

Nach dem das erste Beispiel das Zusammenspiel von Spring und HSQLDB zeigte, soll das zweite Beispiel statt dem JdbcTemplate das HibernateTemplate nutzen, damit Hibernate die OR-Abbildung übernimmt. Zur Vorbereitung (und Erweiterung) des ersten Beispiels wird zunächst log4j.properties um eine Zeile erweitert:

log4j.rootCategory=ERROR, A1
log4j.logger.net.sf.ehcache=ERROR, A1

log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%m%n

Für Hibernate sind ebenso weitere Jar-Dateien nötig, so dass sich insgesamt
im Pfad befinden müssen:

  • hsqldb.jar
  • log4j-*.jar
  • spring.jar
  • common-logging.jar
  • hibernate3.jar
  • dom4j-*.jar
  • jta.jar
  • common-collections-*.jar
  • ehcache-*.jar
  • cglib-*.jar
  • asm.jar
  • antlr-*.jar

Als erstes zeigt die DAO-Implementierung die Verwendung von HibernateTemplate.

package com.javatutor.dao.hibernate;

import java.util.Collection;

import org.springframework.orm.hibernate3.HibernateTemplate;

import com.javatutor.dao.CustomerDao;
import com.javatutor.domain.Customer;

public class CustomerDaoHibernateImpl extends HibernateTemplate implements CustomerDao
{
@SuppressWarnings("unchecked")
public Collection<Customer> getCustomers()
{
return loadAll( Customer.class );
}

public Customer findCustomerById( int id )
{
return (Customer) load( Customer.class, id );
}

public void save( Customer customer )
{
saveOrUpdate( customer );
}
}

Zum Mappen der POJOs auf die Datenbank ist eine Mapping-Datei nötig, es sei denn, man arbeitet mit Java 5 Annotationen. In den Klassenpfad kommt die Datei Customer.hbm.xml.

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.javatutor.domain">

<class name="Customer" table="Customers" lazy="false">

<id name="id" column="Id">
<generator class="native" />
</id>

<property name="name" column="Name" />

</class>

</hibernate-mapping>

In der Spring XML-Datei müssen wir den CustomerDaoHibernateImpl anmelden und
mit einer SessionFactory versorgen.

<bean id="CustomerDaoHibernate" class="com.javatutor.dao.hibernate.CustomerDaoHibernateImpl">
<property name="sessionFactory">
<ref local="SessionFactory" />
</property>
</bean>

Die SessionFactory ist für Hibernate nötig und enthält den Hinweis auf die OR-Mappings und die DataSource. Die DataSource haben wir schon verwendet, doch damit alles persistent bleibt, soll HSQLDB diesmal ins Dateisystem schreiben.

<bean id="DataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:file:/c/:Customers;shutdown=true</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value></value>
</property>
</bean>

Es ist sehr wichtig, den Parameter ;shutdown=true an die Verbindungs-URL zu setzen. Die LocalSessionFactoryBean ist der Produzent für unsere SessionFactory:

<bean id="SessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="DataSource" />
</property>
<property name="mappingResources">
<list>
<value>Customer.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.HSQLDialect
</prop>
<!-- <prop key="hibernate.show_sql">true</prop>-->
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>

Mit dem hibernate.hbm2ddl.auto ist dann auch in der Applikation das CREATE TABLE unnötig. Und das war’s dann auch schon.

JSmooth mit Ant Build Skript

JSmooth nutze ich schon eine ganze Zeit, um unter Windows ausführbare EXE zu
erzeugen. Statt der Gui lässt sich JSmooth aber auch über Ant steuern.

Zunächst muss ein neuer Ant-Task definiert werden:

<property name="jsmooth.dir" value="C:/Programme/JSmooth 0.9.7">
<taskdef name="jsmoothgen" classname="net.charabia.jsmoothgen.ant.JSmoothGen"
         classpath="${jsmooth.dir}/lib/jsmoothgen-ant.jar">

Jetzt kann man den neuen Task jsmoothgen nutzen:

<target name="build-exe-createmetadata">
  <jsmoothgen project="createmetadata.jsmooth"
              skeletonroot="${jsmooth.dir}/skeletons" />
</target>

Mit Spring und dem JdbcTemplate auf eine Hibernate-Datenbank

Das folgende Beispiel soll zeigen, wie man mit Spring arbeitet und Daten in einer relationalen Datenbank persistent macht. Um das Bespiel zum Laufen zu bringen müssen im Klassenpfad sein: hsqldb.jar, spring.jar, log4j-1.2.9.jar und common-logging.jar. Für die Log-Meldungen setzen wir in den Klassenpfad die Datei log4j.properties:

log4j.rootCategory=WARN, A1

log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%m%n

Beginnen wir mit unserem Geschäftsobjekt, einem Kunden:

package com.javatutor.domain;

public class Customer
{
private int id;

private String name;

public int getId()
{
return id;
}

public void setId( int id )
{
this.id = id;
}

public String getName()
{
return name;
}

public void setName( String name )
{
this.name = name;
}

@Override
public String toString()
{
return String.format( "Customer[id=%d, name=%s]", id, name );
}
}

Für diesen Kunden definieren wir eine DAO-Schnittstelle, die uns später Exemplare der Geschäftsobjekte gibt und die Speicherung ermöglichen.

package com.javatutor.dao;

import java.util.Collection;

import com.javatutor.domain.Customer;

public interface CustomerDao
{
Collection<Customer> getCustomers();

Customer findCustomerById( int id );

void save( Customer customer );
}

Zum Testen der Applikation beginnen wir mit einer einfach DAO-Implementierung, die Kunden in einer HashMap speichert.


package com.javatutor.dao.map;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import com.javatutor.dao.CustomerDao;
import com.javatutor.domain.Customer;

public class CustomerDaoMapImpl implements CustomerDao
{
private Map<Integer, Customer> map = new HashMap<Integer, Customer>();

public Collection<Customer> getCustomers()
{
return map.values();
}

public Customer findCustomerById( int id )
{
return map.get( id );
}

public void save( Customer customer )
{
map.put( customer.getId(), customer );
}
}

Eine Applikation wird über die Spring-Konfigurationsdatei später mit einem konkreten CustomerDao gespritzt. Die Methode haveFun() legt einige Business-Objekte an und speichert sie über das DAO.


package com.javatutor;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;

import com.javatutor.dao.CustomerDao;
import com.javatutor.domain.Customer;

public class Application
{
private CustomerDao customerDao;

public void setCustomerDao( CustomerDao customerDao )
{
this.customerDao = customerDao;
}

private void haveFun()
{
System.out.println( customerDao.getCustomers() );

Customer c1 = new Customer();
c1.setId( 0 );
c1.setName( "Christian Ullenboom" );
customerDao.save( c1 );

System.out.println( customerDao.findCustomerById( 0 ) );

System.out.println( customerDao.getCustomers() );

Customer c2 = new Customer();
c2.setId( 1 );
c2.setName( "Tantiana Roujitcher" );
customerDao.save( c2 );

System.out.println( customerDao.getCustomers() );
}

//

public static void main( String[] args )
{
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "spring.xml" );
Application bean = (Application) context.getBean( "Application" );
bean.haveFun();
}
}

Jetzt fehlt nur noch die XML-Datei für Spring:


<?xml version="1.0"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
<bean id="Application" class="com.javatutor.Application">
<property name="customerDao">
<ref local="CustomerDao" />
</property>
</bean>
<bean id="CustomerDao" class="com.javatutor.dao.map.CustomerDaoMapImpl" />
</beans>

Startet man das Programm, ist die Ausgabe


[]
Customer[id=0, name=Christian Ullenboom]
[Customer[id=0, name=Christian Ullenboom]]
[Customer[id=1, name=Tantiana Roujitcher], Customer[id=0, name=Christian Ullenboom]]

Prima. Es klappt. Jetzt kommt eine DAO-Implementierung für JDBC. Zunächst die Klasse.


package com.javatutor.dao.jdbc;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;

import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import com.javatutor.dao.CustomerDao;
import com.javatutor.domain.Customer;

public class CustomerDaoJdbcImpl extends JdbcTemplate implements CustomerDao
{
@SuppressWarnings("unchecked")
public Collection<Customer> getCustomers()
{
return query( "SELECT Id, Name FROM Customers", new CustomerRowMapper() );
}

public Customer findCustomerById( int id )
{
String sql = "SELECT Id, Name FROM Customers WHERE Id = ?";

try
{
return (Customer) queryForObject( sql,
new Object[] { id },
new CustomerRowMapper());
}
catch ( IncorrectResultSizeDataAccessException e ) { }

return null;
}

public void save( Customer customer )
{
if ( findCustomerById( customer.getId() ) == null )
{
Object[] args = { customer.getId(), customer.getName() };
update( "INSERT INTO Customers (Id, Name) VALUES (?,?)", args );
}
else
{
Object[] args = { customer.getName(), customer.getId() };
update( "UPDATE Customers SET Name = ? WHERE Id = ?", args );
}
}
}

class CustomerRowMapper implements RowMapper
{
public Object mapRow( ResultSet rs, int rowNum ) throws SQLException
{
Customer c = new Customer();
c.setId( rs.getInt( "Id" ) );
c.setName( rs.getString( "Name" ) );
return c;
}
}

Und in der XML-Datei ergänzen wir für den JDBC-DAO:

<bean id="CustomerDaoJdbc" class="com.javatutor.dao.jdbc.CustomerDaoJdbcImpl">
<property name="dataSource"><ref local="DataSource" /></property>
</bean>

<bean id="DataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:mem:customers</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value></value>
</property>
</bean>

Damit unsere Applikation mit dem neuen JDBC-DAO gespritzt wird setzt man.

 <bean id="Application" class="com.javatutor.Application">
<property name="customerDao">
<ref local="CustomerDaoJdbc" />
</property>
<property name="dataSource">
<ref local="DataSource" />
</property>
</bean>

Gleichzeitig geben wir der Applikation eine DataSource, damit sie die Tabelle für die Datenbank anlegen kann.


public void setDataSource( DataSource dataSource )
{
new JdbcTemplate( dataSource ).execute( "CREATE TABLE Customers( Id INTEGER, Name VARCHAR(128) ) " );
}

Das gestartet Programm gibt nun die gleiche Ausgabe.