30. Dezember 2007

Vista: File Associations löschen

Problem: Unter Windows Vista lassen sich File Associations nicht löschen.

Lösung: in der Registry unter diesen Keys die entsprenden Dateiendung löschen:

HKEY_CLASSES_ROOT


und

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts

26. Dezember 2007

Wichtige Grundlagen für JSF-Entwicklung

Allgemein
  • keine Component-Bindings im Session oder Application-Scope!
    • verschwendet Speicher
    • UIComponents sind nicht Thread-Safe
    • gehören in den Request-Scope
  • Wenn eine Seite das erste Mal geladen wird, werden Component-Bindings initialisert wenn die JSP gerendert wird.
    • Aber nur wenn noch keine Instanz der Komponente zuvor erzeugt wurde.
    • In der RestoreView-Phase kann man eine Instanz einer Komponente anlegen und dort Eigenschaften setzen. Dadurch wird dann keine neue Instanz beim Rendern der JSP angelegt, sondern die bestehende verwendet und die in der JSP gesetzten Eigenschaft überschrieben.
  • Komponenten speichern Value Bindings und Method bindings (#{} -- el expressions) als String Literals. Die Backing Beans auf die sie zeigen werden nicht im Component Tree im Page Scope gespeichert.

Oracle ADF
  • Wenn man den <afh:body> Tag verwendet ist immer Partial Page Rendering aktiviert. Sprich Controls werden nur aktualisiert wenn sie die PartialTrigger-Eigenschaft gesetzt haben.
    • Um dies abzuschalten muss man das normale HTML - <body>-Tag verwenden.
  • STATE_SAVING_METHOD auf Client mit ADF. Zusätzlich müssen in die web.xml noch folgende Context-Params:
    • oracle.adf.view.faces.CLIENT_STATE_METHOD
      • token: PageState in der Session, nur ein Token wird in der Html-Seite gespeichert, um Requests des selben Useres von mehreren Seiten zu unterscheiden. Default in JSF 1.2
      • all: Der gesamte PageState wird in der Seite in eine Hidden-Field gespeichert.
    • oracle.adf.view.faces.CLIENT_STATE_MAX_TOKENS
      • optionaler Parameter, wieviele Tokens pro User maximal gespeichert werden sollen. Default ist 15
Links

  • MyFaces
    • http://www.myfaces.org/
    • http://wiki.apache.org/myfaces
  • ADF/Trinidad
    • http://www.orablogs.com/fnimphius/

28. November 2007

Heap Dump erstellen und analysieren

Vor JDK 1.6 kann ein HeapDump nur im Fehlerfall  über folgende VM-Argumente geschrieben werden:

-XX:HeapDumpPath=path -XX:HeapDumpOnOutOfMemoryError

Nachtrag (Danke an Markus Kohler, siehe Kommentar): Mit JDK 1.4 und JDK 1.5 gibt es in den neueren Versionen auch die Option

-XX:+HeapDumpOnCtrlBreak

Das ermöglicht beim Drücken von "Ctrl" + "Break" einen HeapDump in das Ausführungsverzeichnis zu schreiben.
Die
HeapDumpPath hat hier keine Auswirkung.

Ab JDK 1.6 kann über folgendes VM-Argument ein HeapDump geschrieben werden.
Das Schreiben findet aber erst nach Beendung des Programms statt.


-Xrunhprof:format=b,file=mysnapsot.hprof

Alternativ kann man auch zur Laufzeit eines Java-Programms einen
Heap-Dump erzeugen über das Tool jmap im Bin-Verzeichnis des SDK:

jmap -dump:format=b,file=snapshot2.hprof <pid>

Eine weitere Möglichkeit bietet JMX. In der MBean

com.sun.management:type=HotSpotDiagnostic

gibt es die Methode

dumpHeap(String , boolean )


Über diese kann ebenfalls im laufenden Betrieb ein Dump erstellt werden.


Analysiert werden kann der Dump dann z.B. über

  • jhat.exe mysnapsot.hprof
    • (im JDK-Bin-Verzeichnis) Startet per Default einen WebServer auf Port 7000.
    • Den Dump kann man sich im Browser unter der Adresse http://localhost:7000 anschauen
  • den kostenlosen SAP Memory Analyzer - eine komfortabele Oberfläche auf Basis Eclipse RCP

Beispiel: Tomcat Session
org.apache.catalina.session.StandardSession

9. November 2007

Garbage Collection

In der Sun JVM gibt es zwei Modi bei der Garbage Collection
  • Minor
    • Implementierung
      • "Copy"
    • läuft relativ schnell und kann auch oft laufen
    • nur in den Memory Pools "Eden" und "Survivor"
  • Major
    • 2 Implementierungen
      • "Mark-Sweep-Compact"
      • "PS Scavenge"
    • kostspielig, läuft langsam. Alle laufende Threads werden währrend er läuft angehalten.
    • in den Memory Pools "Eden", "Survivor", "Tenured" und "Permanent"

Für optimale Performance sollte die Major GC selten laufen.

8. November 2007

Linktip: Hibernate Issue Tracking

Auf dieser Seite werden Bugs,Lösungen, Worksarounds, etc. für Hibernate aufgenommen. Sie bietet auch eine Suchfunktionalität:

http://opensource.atlassian.com/projects/hibernate/secure/QuickSearch.jspa

12. Oktober 2007

JEE/ J2EE Versionen

Sun definiert folgende J2EE/JEE Versionen:

  • J2EE 1.2
    • JSP 1.1 / Servlet 2.2
  • J2EE 1.3
    • JSP 1.2 / Servlet 2.3
  • J2EE 1.4
    • JSP 2.0 /Servlet 2.4
  • Java EE 5
    • JSP 2.1 / Servlet 2.5
Auflistung einiger ApplicationServer/Tools mit J2EE/JEE-Implementierungen:

J2EE/JEE-Version im JDeveloper
  • JDeveloper 10.1.2: J2EE 1.3
  • JDeveloper 10.1.3: J2EE 1.4 and J2EE 1.3
  • JDeveloper 11 : JEE 5
J2EE/JEE-Version in Oracle OC4J
  • OC4J 10g 9.0.4: J2EE 1.3
  • OC4J 10g 10.1.2: J2EE 1.3
  • OC4J 10g 10.1.3: J2EE 1.4
  • OC4J 11 11.1.1: JEE 5
J2EE/JEE-Version in Apache Tomcat
  • Tomcat 3.3: J2EE 1.2
  • Tomcat 4.0: J2EE 1.3
  • Tomcat 4.1: J2EE 1.3
  • Tomcat 5.0: J2EE 1.4
  • Tomcat 5.5: J2EE 1.4
  • Tomcat 6.0: JEE 5.0

26. September 2007

J2SE Versionen

Jedes .class-File hat folgenden Aufbau:

ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
...
}

Beispiel:

CA FE BA BE 00 00 00 30


Also ergibt sich die Hex-Version 30.0, das entspricht dezimal 48,
also der JDK-Version 1.4



Java-Version Byte-Code-Version
1.0 45.0 (00 00 00 2D)
1.1 45.3 (00 03 00 2D)
1.2 46 (00 00 00 2E)
1.3 47 (00 00 00 2F)
1.4 48 (00 00 00 30)
5.0 (1.5) 49 (00 00 00 31)
6.0 (1.6) 50 (00 00 00 32)

DBCP-Logging in Tomcat

Beim Tomcat kann man wie folgt Connection-Pooling über DBCP einrichten. Dabei ist es möglich
Connections, die nicht mehr geschlossen werden nach einer bestimmten Zeit zu schließen (removeAbandoned). Zusätzlich kann ein Stacktrace der Codestelle geloggt werden, die das Problem verursacht hat (logAbandoned)

<Resource name="jdbc/MyDB2"
scope="Shareable"
type="javax.sql.DataSource"
auth="Container"
url="jdbc:db2:mydb2"
maxIdle="10"
maxOpenPreparedStatements="50"
maxActive="50"
validationQuery="Select name from test FETCH FIRST 1 ROWS ONLY FOR FETCH ONLY"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="600000"
driverClassName="COM.ibm.db2.jdbc.app.DB2Driver"
maxWait="10000"
username="user"
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
poolPreparedStatements="true"
password="pass"
removeAbandoned="true"
removeAbandonedTimeout="180"
logAbandoned="true"
/>

Das Problem mit DBCP ist, dass diese Logausgabe über System.out rausgeschrieben werden und nicht über ein Logging-Framework. Daher muss beim Starten des Tomcats dessen Ausgabe einfach in eine File geschrieben werden:


bin\catalina run >logs_tomcat\console-out-%date%.log


Erzeugt z.B. folgende Ausgabe:

DBCP object created 2007-09-26 12:03:40 by the following code was never closed:
java.lang.Exception
at org.apache.tomcat.dbcp.dbcp.AbandonedTrace.setStackTrace(AbandonedTrace.java:157)
at org.apache.tomcat.dbcp.dbcp.AbandonedObjectPool.borrowObject(AbandonedObjectPool.java:76)
at org.apache.tomcat.dbcp.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:95)
at org.apache.tomcat.dbcp.dbcp.BasicDataSource.getConnection(BasicDataSource.java:540)
at de.rfeest.test.db.ConnectionOpenerJNDIImpl.createConnection(Unknown Source)
at de.rfeest.test.db.Executor.openConnection(Unknown Source)

24. September 2007

Timestamps in DB2-Sql-Abfragen

Timestamps werden in folgendem Format erwartet:

timestamp(yyyy-mm-hh-hh.mm.ss.sss)

Beispiel

select * from mytable where
mytimestamp = timestamp('2007-09-20-14.45.14.394')

18. September 2007

UTF-8 für Log4J-Logfiles

Problem: Es sollen in Log4J-Logfiles UTF-8 geschrieben werden.
Lösung: Definition des Parameters "Encoding"

<appender name="DEBUG_MAIL"
class="org.apache.log4j.RollingFileAppender">
<param name="File" value="logs/mail.log" />
<param name="MaxFileSize" value="2500000" />
<param name="MaxBackupIndex" value="1" />
<param name="encoding" value="UTF-8"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%d %-4r [%t] %-5p (%c:%L) %x - %m%n" />
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMin" value="INFO" />
<param name="LevelMax" value="INFO" />
</filter>
</appender>

27. Juli 2007

Fehler beim Erzeugen eines Ant-Build Files aus dem Projekt mit JDeveloper

Problem: Beim Erzeugen eines Ant-Build-Files aus einem JDeveloper-Projekt kommt die folgende Fehlermeldung:

oracle.ide.net.URLFactory NullPointer

Lösung: Bei den Project Properties unter "Project Content" bei Resources den Hauptordner der Applikation hinzufügen.

6. Juli 2007

Directory-Alias setzen ab Windows 2000

linkd "C:\Program Files" c:\programme
bzw.
junction "C:\Program Files" c:\programme
Junction ist von Sysinternals

Um ein Laufwerk auf ein Verzeichnis zu mounten verwendet man subst:
subst e: "C:\Bilder"

28. Juni 2007

Struts & ApplicationResources FAQ

In welchem Format müssen die Properties-Files vorliegen

Die Dateien müssen wie im ISO-8859-1 Format gespeichert werden (NICHT IN UTF-8!!!). Zeichen die über diesen Zeichensatz hinausgehen müssen in Unicode Escapes gespeichert werden.



Wie findet Struts die Default-Sprache bei
ApplicationResource Sprache?

Der Default für Struts bei ApplicationResources (also das File, das genommen wird, wenn die Browsersprache nicht gefunden) ist nicht das Property-File ohne Sprachendung, sondern das Property-File mit der Endung der Locale, die als System-Property der JVM gesetzt ist.

Diesen Werte kann man setzen über
  1. System-Property -Duser.language=de -Duser.region=DE
  2. über API: Locale.setDefault()

Ein Beispiel dazu:

Die System-Locale ist auf de_DE gesetzt.

Es existieren folgende Property-Files:

myfile.properties (enthält englische Texte)
myfile.properties_de (enthält deutsche Texte)
myfile.properties_it (enthält italienischeTexte)

Ein Benutzer kommt mit der Browser-Sprache russisch in die Applikation. Er bekommt nicht die
englischen Texte aus myfile.propertiesm sondern die deutschen Texte aus myfile.properties_de!


html locale

Um JSPs mit den bean:message - Tags lokalisiert darzustellen, muss der Tag

<html:html locale="true"/>

nur gesetzt werden, wenn der Aufruf der JSP direkt erfolgt (http://myserver/person.jsp) und nicht über die Action (http://myserver/person.do). Über die Action sorgt Struts selbst dafür.


Achtung: Ist seit Struts 1.29 deprecated

Stattdessen muss

<html:html lang="true"/>

verwendet werden.

25. Juni 2007

Hibernate - Filter für 1:n-Beziehungen definieren

Definition des Filters in einem Mapping-File:

<hibernate-mapping>
...
<filter-def name="theFilter">
<filter-param name="theParam" type="int"/>
</filter-def>
...
</hibernate-mapping>

In einer 1:n-Beziehung (hier am Beispiel einer indizierten Liste) wird der Filter angegeben. Die Condition landet in der WHERE-Klausel:

<list name="myListOfSomething" inverse="true" lazy="false" >
<key>
<column name="PF_ID" precision="11" scale="0" not-null="true" />
</key>
<index column="MYPK" />
<one-to-many class="Something" >
<filter name="theFilter" condition="MYPK=:theParam"/>
</list>


Beim Aufruf wird der Filter wie folgt definiert

Filter filter = session.enableFilter("theFilter");
filter.setParameter("theParam",new Integer(2));

20. Juni 2007

ANT Task "JAVAC" aus JDeveloper starten - Problem mit unterschiedlichen JDKs

Problem: JDeveloper wird z.B. mit JDK 1.5 gestartet. Über ein ANT-Buildfile hat man eine JAVAC-Task zum Kompilieren der Sourcen mit dem 1.4er Compiler definiert. Bei der Ausführung kommt es zu Laufzeitfehlern bedingt durch API-Unterschiede, z.B.

java.lang.NoSuchMethodError: java.math.BigDecimal.(I)V


Ursache: Obwohl Ant im JDev so konfiguriert ist, dass es unter 1.4 läuft, wird dennoch die rt.jar von 1.5 geladen.

Lösung: Verwendung des bootclasspath-Attributs unter Angabe des Pfads zur rt.jar

<target name="compile" description="Compile Java source files">
<javac destdir="${output.dir}" classpathref="classpath"
debug="${javac.debug}" nowarn="${javac.nowarn}"
bootclasspath="${jdk.path}lib/rt.jar"
deprecation="${javac.deprecation}" encoding="Cp1252" source="1.4">
<src path="src"/>
</javac>
</target>

Problem bei der Migration von JDEV 10.1.2 Projekten nach höheren Versionen

Problem: Beim Build-Prozess des JDeveloper treten Fehler auf (z.B. dass xml-Dateien nicht mehr in das Build-Verzeichnis kopiert werden). In der Konsolenausgabe der jdev.exe erscheint

java.lang.ClassCastException: oracle.bali.xml.addin.XMLSourceNode

Ursache: Es ist ein fehlerhafter Eintrag im Projektfile (.jpr):

<hash n="ejbModuleContainer">
<value n="ejbVersion" v="NOT SPECIFIED"/>
<url n="orionEjbJarNodeURL" path="src/META-INF/orion-ejb-jar.xml"/>
</hash>


Lösung: Der Eintrag muss entfernt werden.

18. Juni 2007

Java & XML Konfiguration

JAXP

XML-Verarbeitung ist standardisiert durch die Java API for XML Processing (JAXP)
Bis 1.4 war es nicht Bestandteil des JDK und muss separat heruntergeladen werden.

JDK 1.5 beinhaltet JAXP 1.3
JDK 1.6 beinhaltete JAXP 1.4

Interfaces/Abstrakte Klassen, etc
  • xml-apis.jar oder jaxp-api.jar oder xmlPasrserAPIs.jar
  • Optional, wenn nicht in den ersten enthalten:
    • sax.jar: Simple API for XML Processing
    • dom.jar Document Object Model API
JAXP-Implementierungen

Vor JDK 1.6 muss separat eine JAXP-Implementierung bezogen werden. Bei JDK 1.6 kommt eine RI im rt.jar mit (ist Xerces/Xalan)
  • xercexImpl.jar -> Xerces
  • Oracle XML Parser V2 for Java
  • Crimson
  • Saxon
  • xalan.jar -> Xalan (Transformation)

Properties
  • javax.xml.parsers.SAXParserFactory (für SAX-Parser)
  • javax.xml.parsers.DocumentBuilderFactory (für DOM-Parser)
  • javax.xml.transform.TransformerFactory (für XSLT)

Werte, z.B.:
  • org.apache.xerces.jaxp.SAXParserFactoryImpl
  • org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
  • com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl

Diese Properties werden in dieser Reihenfolge ausgelesen:
  • System-Properties mit der Option -D gesetzt (beim Aufruf der java.exe) oder im Java-Code mit System.setProperty()
  • über jaxp.properties (in [PFAD zum JDK]\jre\lib)
  • In einem jar File im Ordner META-INF/services (So wird z.B. bei Tomcat-Distribution im common\endorsed-Ordner der XML-Parser gesetzt).
  • Als Fallback-Lösung, wird die Systemimplementierung verwendet

15. Juni 2007

Deployment von WAR-Files unter Tomcat 6

Problem: Reploy oder Undeploy von per WAR-Files deployten Applikationen unter Tomcat funktioniert nicht:

Ursache: Es werden manche jar gesperrt, so dass sie nicht mehr gelöscht werden können.

Lösung: In das WAR-File muss im META-INF Ordner die Datei context.xml sein.

Diese muss den Eintrag antiResourceLocking="true" haben.

Beispiel:


<Context path="/guardian" crossContext="true" debug="0" reloadable="true"
antiResourceLocking="true"
>
>
</Context>

5. Juni 2007

2. Juni 2007

.NET Security Policies in einer Unternehmensumgebung

Problem: Laufzeitsicherheitsrichtlinen (Runtime Security Policy) in einer Unternehmensumgebung (Active Directory) verteilen.

Lösung: In der .NET Configuration MMC über rechte Maustaste "Create Deployment Package" ein MSI-Paket erstellen, dass dann auf jedem benötigten Rechner verteilt wird.

16. Mai 2007

DataGridView: Eine Property aus einer Parent-Liste als Spalte anzeigen


class Person
{
private string id;
private string name;
private Address homeAddr;

public string ID
{
get { return id;}
set { id = value;}
}

public Address HomeAddr
{
get { return homeAddr;}
set { homeAddr = value;}
}
...
}



class Address
{

private string cityname;
private string postcode;

public string CityName
{
get { return cityname;}
set { cityname = value;}
}
...
}

Man möchte als Inhalt einer Spalte HomeAddr.Cityname der Klasse Person anzeigen:


Folgender Code bringt nur den Klassenname:

myDataGridViewTextBoxColumn1.DataPropertyName = "HomeAddr"


Dieser Code bringt keinen Inhalt

myDataGridViewTextBoxColumn1.DataPropertyName = "HomeAddr.Cityname";


Lösung ist hier beschrieben:
http://blogs.msdn.com/msdnts/archive/2007/01/19/how-to-bind-a-datagridview-column-to-a-second-level-property-of-a-data-source.aspx

10. Mai 2007

Sprache in Struts im Code ändern

Die Sprache, die von Struts für die ApplicationResources verwendet wird, ist in einem SessionKey hinterlegt. Dieser kann durch folgenden Code geändert werden:

request.getSession().setAttribute(Globals.LOCALE_KEY,new Locale("de"));

Anmerkung: das ist deprecated session.setAttribute(org.apache.struts.action.Action.LOCALE_KEY,Locale("de));

18. April 2007

HibernateTools & Ant

Wie funktioniert die Codegenerierung für Hibernate mit ANT?

Task "
reveng" erzeugt xml-Mappingfiles aus Datenbank-Tabellen, die in der Datei "hibernate.reveng.xml" angegeben werden.

Task "javagen" erzeugt POJOs und DAO-Klassen.

Task "ddlgen" erzeugt DDL-Skript zur Erstellung/Änderung der Tabellen

Task "hiberate-docgen" erzeugt eine JavaDoc-ähnliche Dokumentation der Tabellen und generierten Klassen


build.xml:

<project name="MyProj" default="all" basedir=".">
<property file="build.properties"/>

<path id="toolslib">
<path location="${dbjar}"/>
<path location="."/>
<fileset dir="${hibernate.path}">
<include name="**/*.jar"/>
</fileset>
<fileset dir="${hibernate.tools.path}">
<include name="**/*.jar"/>
</fileset>
</path>

<taskdef name="hibernatetool"
classname="org.hibernate.tool.ant.HibernateToolTask"
classpathref="toolslib"/>



<target name="reveng" description="Reverse Engineer from DB">
<hibernatetool destdir="./hib-gen">
<jdbcconfiguration configurationfile="hibernate.cfg.xml"
packagename="de.rfeest.dataaccess.orm"
revengfile="hibernate.reveng.xml"/>
<hbm2hbmxml destdir="./hib-gen"/>
</hibernatetool>
</target>
<target name="javagen" description="Create Java classes from xml">
<hibernatetool destdir="./src">
<configuration configurationfile="./src/hibernate.cfg.xml"/>
<hbm2java destdir="./src"/>
<hbm2dao destdir="src"/>
</hibernatetool>
</target>
<target name="ddlgen" description="Create DDL from xml">
<hibernatetool destdir="./src">
<configuration configurationfile="./src/hibernate.cfg.xml"/>
<hbm2ddl export="false" outputfilename="./create-tables.ddl"/>
<hbm2doc/>
</hibernatetool>
</target>
<target name="hibernate-docgen" description="Create DDL from xml">
<hibernatetool destdir="../orm">
<configuration configurationfile="src/hibernate.cfg.xml"/>
<hbm2doc/>
</hibernatetool>
</target>


</project>

16. April 2007

DataSources unter Tomcat 6

In Tomcat 6 gibt es zur Definition von DataSources keine <ResourceParams> mehr wie unter 4.x und 5.x. Sie werden nun wie folgt definiert:

<Resource name="jdbc/MYDATASOURCE"
scope="Shareable"
type="javax.sql.DataSource"
auth="Container"
url="jdbc:db2:dbinst"
maxIdle="10"
maxOpenPreparedStatements="50"
maxActive="50"
validationQuery="Select xxx from yyy FETCH FIRST 1 ROWS ONLY FOR FETCH ONLY"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="600000"
driverClassName="COM.ibm.db2.jdbc.app.DB2Driver"
maxWait="10000"
username="myuser"
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
poolPreparedStatements="true"
password="hispass"
removeAbandoned="true"
removeAbandonedTimeout="180"
logAbandoned="true"
/>

5. April 2007

ADF TreeTable und Tree Controls zeigen Aufklapp-Symbol obwohl keine Kindelemente vorhanden sind

Problem: Das JSF ADF-Control TreeTable und Tree stellt Daten in hierachischer Form dar.
Es kann vorkommen, dass ein Element ein Aufklapp-Icon hat, obwohl es keine Kindelement hat.

Ursache: Die Kindelement-Variable ist nicht null, sondern hat nur die size=0. Das Control muss aber null vorfinden, damit es das Aufklapp-Icon nicht anzeigt.

Lösung: Die Methode isContainer() überschreiben. Diese Methode wird vom Control verwendelt, um zu ermitteln ob es Kindelemente gibt.

new ChildPropertyTreeModel(serv, "childValues") {
public boolean isContainer() {
if (getRowData() != null) {
IGuardValues value = (IGuardValues) getRowData();

if (value.getChildValues() != null &&

value.getChildValues().size() > 0) {
return true;
}

}

27. März 2007

Spring und Log4J in einer Web-Applikation

Problem: Spring wird in einer Web-Applikation verwendet. Log4J loggt trotz korrekter Konfiguration nicht in die vorgesehenen LogFiles.

Lösung: In der web.xml muss folgender Eintrag stehen:

<web-app>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
...
</web-app>

NHibernate 1.2 HowTo

Zur Codegenerierung aus Datenbanktabellen wird MyGeneration empfohlen. Dort muss zunächst ein NHibernate Template heruntergeladen werden.

Im VisualStudio-Projekt muss folgender Config-Eintrag in die app.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="hibernate-configuration"
type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"
/>
</configSections>

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider
</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="default_schema">dbo</property>
<property name="connection.connection_string">Server=myserver;Initial Catalog=mydb;Integrated Security=True</property>
<property name="show_sql">true</property>
<mapping assembly="MyAssembly" />
</session-factory>
</hibernate-configuration>
</configuration>

Wichtig ist, dass die generierten *.obm.xml-Files in VisualStudio als eingebette Ressource über die Properties definiert sind. Die Mapping-Files müssen nicht explizit im Config-File angegeben werden. Durch den Eintrag mapping assembly werden alle .obm.xml-Files in dieser Assembly verwendet.

Beispiel für das Neuanlegen eines Datensatzes:

Configuration cfg = new Configuration();
ISession session = cfg.Configure().BuildSessionFactory().OpenSession();
ITransaction transaction = session.BeginTransaction();

ProfilProjekt pro = new ProfilProjekt();
pro.Kunde = "Kunde";
pro.LfdNr = 1;
session.Save(pro);
transaction.Commit();

session.Close();

22. März 2007

Umlaute beim Posten falsch verschickt mit UTF-8

Problem: Bei UTF-8 werden Umlaute beim Posten aus einem Formular falsch vom Browser verschickt und kommen fehlerhaft beim Server an.

Lösung: Beim Verwenden eines HttpFilters, muss folgendes aufgenommen werden:


public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) {
HttpServletRequest req = (HttpServletRequest)servletRequest;

try {
req.setCharacterEncoding("UTF-8");
}
catch (UnsupportedEncodingException e) {
logger.error(e);
}
...

21. März 2007

Sonderzeichen in XML

&      &amp;
' &apos;
< &lt;
> &gt;
" &quot;

Expression Language not supported in compile time

Problem: Die Ausdruckssprache wird im compile time-Attribut items nicht unterstützt, Expression Language not supported in compile time
Mögliche andere Fehlermeldung: ExpressionEvaluatorManager JasperException

Lösung:

a)
isELIgnored="true" in der Page directive der jsp:
<%@ page contentType="text/html;charset=windows-1252" isELIgnored="true" %>
b)
oder in der web.xml folgenden Eintrage hinzu:

<jsp-config>
<jsp-property-group>
<display-name>Ignore EL</display-name>
<url-pattern>*.jsp</url-pattern>
<el-ignored>true</el-ignored>
</jsp-property-group>
</jsp-config>


Ursache:

Defaulteinstellung:
  • für JSP-Seiten ab Servlet 2.4 : EL evaluieren
  • für JSP-Seiten bis einschl. Servlet 2.3 : EL ignorieren
Die EL wird erst mit JSP 2.0 ausgeliefert, kann aber auch mit JSP 1.2 betrieben werden, dann werden einige JARs benötigt (jstl.jar, …)

Es gibt älter Taglibs, die eine EL-Syntax für ihre Attribute verwenden. Diese wird bis Servlet 2.3 vom JSP-Compiler ignoriert. Wird die JSP, die diese Taglib enthält nun unter einem Servlet-Container >2.4 betrieben, tritt dieser Fehler auf. Die EL-Syntax darf bei diesen älteren Taglibs aber nicht vom JSP-Compiler evaluiert werden. Die Libs stellen eigene Logik dafür bereit.
Daher muss das Evaluieren von EL-Syntax deaktiviert werden.

Links:
http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSPIntro7.html
http://blogs.oracle.com/Didier/JSTL_1_JSP_2

18. März 2007

Globale Datasourcen unter Tomcat

Stichworte:

JNDI, global, Datasource, DB, JDBC


 

Problem:

Eine Globale Resource in einer Webanwendung verwende.


 

Lösung:

Zunächst muss die Resource global definiert werden


 

<GlobalNamingResources>

    <!-- JNDI-Datasource fuer die Testdatenbank -->

<Resource name="jdbc/DB2TGLOBAL"

        auth="Container"

        type="javax.sql.DataSource"/>


 

    <ResourceParams name="jdbc/DB2TGLOBAL">

        <parameter>

            <name>factory</name>

            <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>

        </parameter>

        

        ...

        

    </ResourceParams>        

</GlobalNamingResources>


 

Im Context der Anwendung muss eine Referenz auf die globale Datasource angegeben werden:


 

<ResourceLink name="jdbc/DB2TPooledDS" global="jdbc/DB2TGLOBAL" type="javax.sql.DataSource" />

    


 

14. März 2007

Eine .NET Collection in ein Array eines bestimmten Typsumwandeln

ArrayList al = (DataGridColumnStyle[])al.ToArray(typeof(DataGridColumnStyle)));

Active Directory DN über SAM-Account via LDAP ermitteln

String searchBase = "DC=xxx,DC=xyz,DC=co,DC=za";

String searchString = "SamAccountName=";

String dn = "";

SearchControls constraints = new SearchControls();

constraints.setSearchScope (SearchControls.SUBTREE_SCOPE);

// Perform seach

NamingEnumeration results =

ctx.search(searchBase, searchString + username.trim(), constraints);

// Loop though results

if (results.hasMore())

{

SearchResult sr = (SearchResult) results.next();

dn = sr.getName();

dn=dn + "," + searchBase

}

ctx.close();

ctx=null;

return dn;

Detailiertes Hibernate-Logging in Log4J

<!-- Limit the org.hibernate category to INFO since logging to DEBUG affects performance badly -->

<category name="org.hibernate">

<priority value="INFO"/>

</category>

<!-- Log SQL statements-->

<category name="org.hibernate.SQL">

<priority value="DEBUG"/>

</category>

<!-- Log the values assigned to the SQL parameters and results -->

<category name="org.hibernate.type">

<priority value="DEBUG"/>

</category>

<!-- Log transaction event/JTA -->

<category name="org.hibernate.transaction">

<priority value="DEBUG"/>

</category>

<category name="org.hibernate.event.def.AbstractFlushingEventListener">

<priority value="

Hibernate Fehler “object references an unsaved transientinstance - save the transient instance before flushing”

Prüfen, ob im Mapping ein unsaved-value definiert ist:

<id name="id" column="id" unsaved-value="0">

JDEV org.hibernate.QueryException bei org.hibernate.hql.ast.HqlToken

Stichworte:

JDev, JDeveloper, org.hibernate.QueryException, ClassNotFoundException : org.hibernate.hql.ast.HqlToken

Problem:

Im JDeveloper bekommt man mit Hibernate folgende Exception zur Laufzeit geworfen:


 

org.hibernate.QueryException: ClassNotFoundException: org.hibernate.hql.ast.


 

Ursache:

In der JDeveloper-Verzeichnisstruktur befindet sich im Toplink-Verzeichnis eine Version von antlr.jar -> Diese verträgt sich nicht mit dem antlr.jar, das Hibernate benötigt.


 

Lösung:

Das antlr.jar von Jdeveloper muss einfach gelöscht/ersetzt werden.

JDeveloper - DB-Schemas im Connection Manager hinzufügen

Stichworte:

JDeveloper 10.1.3 DB Connection Schema

Problem:

Per Default ist immer nur das Schema des Benutzers unter den eingerichteten Conenctions sichtbar

Lösung:

Zum Hinzufügen eines weiteren Schemas, muss unter Database die gewünschte DB gewählt werden und dann oben auf den "Trichter" geklickt werden.

Dort kann man dann sämtliche Schemas hinzufügen.

JDEV OC4J und Log4J Problem

Problem: no class definition found

Lösung: in orion-web.xml:

<web-app-class-loader search-local-classes-first="true"

include-war-manifest-class-path="true" />

JMX ab JDK 1.5

Ab JDK 1.5 kann man java über einen Parameter mitteilen, dass ein JMX-Server gestartet werden soll:

java -Dcom.sun.management.jmxremote AppName

Optional kann auch noch ein Port angegeben werden für den Remotezugriff

-Dcom.sun.management.jmxremote.port=1234
-Dcom.sun.management.jmxremote.authenticate=false

Im Tomcat kann man den Parameter über folgende Variable setzen

set JAVA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=12345

Das ganz kann man sich dann mit JConsole (befindet sich bin-Ordner des SDK) grafisch anschauen.

Wichtig: Folgende Dateien müssen in $JRE\lib\management angelegt werden:

- jmxremote.access (Zugriff für einen User bestimmen)

monitorRole readonly
controlRole readwrite


- jmxremote.password (Passwort für einen User bestimmen)

monitorRole QED
controlRole R&D


Der Zugriff auf Filesystemebne muss so eingeschränkt werden, dass nur der Benutzer, der die java.exe ausführt der Besitzer der Dateien ist und nur er Zugriff darauf hat.


In der Datei management.properties können viele Sicherheitseinstellungen gemacht werden.

Z.B. kann hier konfiguriert werden, ob der Remote-JMX-Zugriff per SSL erfolgen soll.

Connection Pooling unter Tomcat

Stichworte:
Connection Pooling, DB, DBCP, Tomcat, Webserver, Java, JDBC

Problem:
Connection-Pooling in Tomcat nutzen

Ursache:
-

Lösung:

Nutzung von Commons DBCP (http://jakarta.apache.org/commons/dbcp/index.html). Es kann über den Parameter poolPreparedStatements auch Caching von PreparedStatements aktiviert werden.

1) In der server.xml die Datasource definieren

<Resource name="jdbc/DB2PooledDS"
auth="Container"
type="javax.sql.DataSource"/>

<ResourceParams name="jdbc/DB2PooledDS">
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>

<!-- Maximum number of dB connections in pool. Make sure you
configure your mysqld max_connections large enough to handle
all of your db connections. Set to 0 for no limit.
-->
<parameter>
<name>maxActive</name>
<value>100</value>
</parameter>

<!-- Maximum number of idle dB connections to retain in pool.
Set to 0 for no limit.
-->
<parameter>
<name>maxIdle</name>
<value>30</value>
</parameter>

<!-- Maximum time to wait for a dB connection to become available
in ms, in this example 10 seconds. An Exception is thrown if
this timeout is exceeded. Set to -1 to wait indefinitely.
-->
<parameter>
<name>maxWait</name>
<value>10000</value>
</parameter>

<!-- MySQL dB username and password for dB connections -->
<parameter>
<name>username</name>
<value>myuser</value>
</parameter>
<parameter>
<name>password</name>
<value>mypass</value>
</parameter>

<!-- Class name for mm.mysql JDBC driver -->
<parameter>
<name>driverClassName</name>
<value>COM.ibm.db2.jdbc.app.DB2Driver</value>
</parameter>


<!-- Prepared Statement Pooling aktivieren -->
<parameter>
<name>poolPreparedStatements</name>
<value>true</value>
</parameter>
<parameter>
<name>maxOpenPreparedStatements</name>
<value>50</value>
</parameter>



<!-- The JDBC connection url for connecting to your MySQL dB.
The autoReconnect=true argument to the url makes sure that the
mm.mysql JDBC Driver will automatically reconnect if mysqld closed the
connection. mysqld by default closes idle connections after 8 hours.
-->
<parameter>
<name>url</name>
<value>jdbc:db2:mydb</value>
</parameter>

</ResourceParams>


2) In web.xml der Anwendung angeben

<web-app id="WebApp">
...
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/DB2PooledDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

</web-app>


3) Connection im Java-Code öffenen über JNDI

try {

InitialContext initCtx = new InitialContext();

Context ctx = (Context) initCtx.lookup(“java:comp/env”);

//Context ctx = new InitialContext();

if (ctx == null) {

logger.error("No InitialContext available");

} else {

dataSource = (DataSource) ctx.lookup(“jdbc/DB2PooledDS”);

}

} catch (NamingException ne) {

logger.error(ne);

}

try {

Connection conn = getDataSource().getConnection();

} catch (SQLException e) {

logger.error(e);

}

Tomcat Remote Debuggen

Umgebungsvariablen setzen:

JPDA_ADDRESS=8888
JPDA_TRANSPORT=dt_socket

Tomcat starten mit

catalina jpda start.


Sollte es zu folgender Fehlermeldung kommen:

Transport dt_socket failed to initialize

Dann müssen die

dt_socket.dll und dt_shmem.dll

ins Tomcat-Bin Verzeichnis kopiert werden oder
Umgebungsvariable path=\bin setzen.


Alternative in die Umgebungsvariable JAVA_OPTS folgenden Eintrag:

set JAVA_OPTS=-Xrunjdwp:transport=dt_socket,server=y,address=9999,suspend=n

JSF ADF Projekt nach 10.1.3.1 Migrationsproblem

Stichworte:

JDEV, JDeveloper, JSF, ADF, Migration, Problem, 10.1.3.1, OC4J

Problem:

Nach der Migration eines JSF/ADF Projekts nach JDeveloper 10.1.3.1gibt es folgende Fehlermeldung zur Laufzeit

500 Internal Server Error

java.lang.NoSuchMethodError: oracle.adf.view.faces.context.AdfFacesContextFactory.createContext(Ljava/lang/Object;Ljava/lang/Object;)Loracle/adf/view/faces/context/AdfFacesContext; at oracle.adfinternal.view.faces.webapp.AdfFacesFilterImpl.doFilter(AdfFacesFilterImpl.java:187) at …

Ursache:

Das Projekt verwendet in seinem WEB-INF\lib-Pfad veraltete Libraries (JSF und ADF), die mit dem neuen OC4J nicht funktionieren.


Lösung:

Es müssen die Libraries aus dem JDEV 10.1.3.1 in Lib-Pfad kopiert werden.


Datum / Zahlen in/von lokale(n) String(s) wandeln


NumberFormat nf = NumberFormat.getNumberInstance();

double d = nf.parse("12,3332").doubleValue());

DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.DEFAULT,new Locale("de", "DE"));

String s = dateFormatter.format(datum);

Log4J Filter für eine Kategorie

Stichworte:

log4j, category, debug, error, info, only, nur eine, LevelRangeFilter

Problem:

Man möchte in einem File nur Logging-Messages einer Kategorie (und nicht der darüber liegenden auch noch), z.B. INFO speichern.

Lösung:

Es muss ein LevelRangeFilter verwendet werden:


<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>


<appender name="INFO" class="org.apache.log4j.DailyRollingFileAppender">

<param name="File" value="logs/PSASAS_info.log"/>

<param name="DatePattern" value="'.'yyyy-MM-dd"/>

<layout class="org.apache.log4j.PatternLayout">

<param name="ConversionPattern" value="%d %-4r [%t] %-5p (%c:%L)/>

</layout>


<filter class="org.apache.log4j.varia.LevelRangeFilter">

<param name="LevelMin" value="INFO" />

<param name="LevelMax" value="INFO" />

</filter>

</appender>



<root>

<priority value="debug"/>

<appender-ref ref="INFO"/>

</root>


</log4j:configuration>


Uncaught-Exceptions in WinForms-Anwendungen

static void Main()
{
// Für nicht abgefangene Exceptions aus dem ApplicationThread einen
// eigenen Exception-Handler definieren

Application.ThreadException += new
System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

try
{
MainFormController controller = new MainFormController();
Application.Run(controller.View);
}

// Exceptions können auch schon währrend new MainFormController()
// auftreten, daher müssen diese auch schon abgefangen werden
catch (Exception ex)
{
ShowExceptionDialog("Main",ex);
}
}


private static void Application_ThreadException(object sender,System.Threading.ThreadExceptionEventArgs e)
{
// Diese Methode wird aufgerufen, wenn eine Exception nicht behandelt wurde
ShowExceptionDialog(sender,e.Exception);
}

ComboBox Items in verschiedenen Farben

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace WindowsApplication7
{
public class Form1 : System.Windows.Forms.Form
{
private System.ComponentModel.Container components = null;
private String[] arr;

private Image[] imageArr;
private System.Windows.Forms.ComboBox comboBox1;
public Font myFont;
public Form1()
{
InitializeComponent();
myFont = new System.Drawing.Font("Comic Sans", 11);
arr = new String[4];
arr[0] = "Smiley Red Face";
arr[1] = "Smiley Cry";
arr[2] = "Smiley Big Grin";
arr[3] = "Smiley Suss";
this.comboBox1.DataSource = arr; //set the combo's data source to out array
imageArr = new Image[4];

imageArr[0] = new Bitmap("C:\\smiley_redface.gif");
imageArr[1] = new Bitmap("C:\\smiley_cry.gif");
imageArr[2] = new Bitmap("C:\\smiley_biggrin.gif");
imageArr[3] = new Bitmap("C:\\smiley_suss.gif");
}
//You have your windows forms designer generated code here
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void comboBox1_DrawItem(object sender,
System.Windows.Forms.DrawItemEventArgs e)
{
// Let's highlight the currently selected item like any well
// behaved combo box should
e.Graphics.FillRectangle(Brushes.Bisque, e.Bounds);
e.Graphics.DrawString(arr[e.Index], myFont, Brushes.Blue,
new Point(imageArr[e.Index].Width*2,e.Bounds.Y));
e.Graphics.DrawImage(imageArr[e.Index], new Point(e.Bounds.X, e.Bounds.Y));
//is the mouse hovering over a combobox item??
if((e.State & DrawItemState.Focus)==0)
{
//this code keeps the last item drawn from having a Bisque background.
e.Graphics.FillRectangle(Brushes.White, e.Bounds);
e.Graphics.DrawString(arr[e.Index], myFont, Brushes.Blue,
new Point(imageArr[e.Index].Width*2,e.Bounds.Y));
e.Graphics.DrawImage(imageArr[e.Index], new Point(e.Bounds.X, e.Bounds.}
}
}
}

Events aus der WindowsMessageQueue direkt behandeln

protected override void WndProc(ref Message m)

{

// Werte aus winuser.h

System.IntPtr SC_MINIMIZE = new IntPtr(0xF020);

System.IntPtr SC_MAXIMIZE = new IntPtr(0xF030);

System.IntPtr SC_RESTORE= new IntPtr(0xF120);

if (m.WParam == SC_MINIMIZE)

{

if (this.WindowState!=FormWindowState.Maximized)

sizeBeforeMin=this.Size;

}

if (m.WParam == SC_MAXIMIZE)

{

sizeBeforeMin=this.Size;

}

if (m.WParam ==SC_RESTORE )

{

System.Diagnostics.Debug.WriteLine("WNDPROC wieder");

}

base.WndProc (ref m);

}

Erste x Zeilen zurückgeben

Appending FETCH FIRST 10 ROWS ONLY to the end of your SQL should do
the trick

Merges-Statement under 8i und 9i

Oracle9i Implementation:
In Oracle9i, the MERGE statement INSERTS and UPDATES the data with a single SQL statement.
MERGE INTO SALES_FACT D
USING SALES_JUL01 S
ON (D.TIME_ID = S.TIME_ID
AND D.STORE_ID = S.STORE_ID
AND D.REGION_ID = S.REGION_ID)
WHEN MATCHED THEN
UPDATE
SET d_parts = d_parts + s_parts,
d_sales_amt = d_sales_amt + s_sales_amt,
d_tax_amt = d_tax_amt + s_tax_amt,
d_discount = d_discount + s_discount
WHEN NOT MATCHED THEN
INSERT (D.TIME_ID ,D.STORE_ID ,D.REGION_ID,
D.PARTS ,D.SALES_AMT ,D.TAX_AMT ,D.DISCOUNT)
VALUES (
S.TIME_ID ,S.STORE_ID ,S.REGION_ID,
S.PARTS ,S.SALES_AMT ,S.TAX_AMT ,S.DISCOUNT);

Oracle8i Implementation:
In Oracle8i, you could choose to implement it as a sequence of DML statements.
UPDATE
(SELECT
S.TIME_ID ,S.STORE_ID ,S.REGION_ID,
S.PARTS s_parts ,S.SALES_AMT s_sales_amt ,S.TAX_AMT s_tax_amt ,S.DISCOUNT s_discount,
D.PARTS d_parts ,D.SALES_AMT d_sales_amt ,D.TAX_AMT d_tax_amt ,D.DISCOUNT d_discount
FROM SALES_JUL01 S, SALES_FACT D
WHERE D.TIME_ID = S.TIME_ID
AND D.STORE_ID = S.STORE_ID
AND D.REGION_ID = S.REGION_ID) JV
SET d_parts = d_parts + s_parts,
d_sales_amt = d_sales_amt + s_sales_amt,
d_tax_amt = d_tax_amt + s_tax_amt,
d_discount = d_discount + s_discount
;
INSERT INTO SALES_FACT (
TIME_ID,STORE_ID ,REGION_ID,
PARTS ,SALES_AMT ,TAX_AMT ,DISCOUNT)
SELECT
S.TIME_ID ,S.STORE_ID ,S.REGION_ID,
S.PARTS ,S.SALES_AMT ,S.TAX_AMT ,S.DISCOUNT
FROM SALES_JUL01 S
WHERE (S.TIME_ID, S.STORE_ID, S.REGION_ID) NOT IN (
SELECT D.TIME_ID, D.STORE_ID, D.REGION_ID
FROM SALES_FACT D
)
;



http://www.oracle.com/technology/products/oracle9i/daily/Aug24.html

Thema: Java-Code als Oracle Stored Procedure

1. Java Code in DB kompilieren:

create or replace and compile java source named helloworldinthedatabase as

public class HelloWorldInTheDatabase{

public static int test(int num) {

int temp;

temp = num + 42;

return temp;

}

}

**************************************************************************************************

2. Proz. oder Funktion erstellen: (Veröffentlichen der Klassen in der DB, Namen der

Java-Prozeduren und Parametertypen auf ihre Gegenstücke in PL/SQL abbilden)

create or replace function start_helloworld (num in number) return number

authid current_user

as language java name 'HelloWorldInTheDatabase.test(int) return int';

**************************************************************************************************

3. Prozedur start_helloword ausführen

SQL Server 2000 startet 1433 Port nicht unter XP SP 2

JDBC kann dadurch nicht zugreifen

Ursache:

Sie verwenden eine Version von Microsoft SQL Server 2000 oder Microsoft SQL Server 2000 Desktop Engine (auch MSDE), die bei Verwendung mit dieser Windows-Version bekannte Sicherheitsrisiken enthält. Der TCP/IP-Netzwerkport und der UDP- Netzwerkport von Microsoft SQL Server 2000, MSDE oder von beiden wurde deaktiviert, um das Sicherheitsrisiko möglicher Virusattacken auf dem Computer zu reduzieren.

Lösung:

Installieren Sie einen Patch oder das letzte Servicepack für Microsoft SQL Server 2000 oder MSDE von http://www.microsoft.com/sql/downloads/default.asp

13. März 2007

JMX mit Tomcat 4.x und JDK 1.4

Stichworte:

JMX, MX4J, J2K, JDK1.4

Problem:

Zur Serverüberwachung des Tomcat soll JMX unter JDK 1.4 verwendet werden.

Ursache:

JDK 1.4 unterstützt von Haus aus JMX noch nicht.

Lösung:

Es gibt ein JMX-Toolkit: MX4J unter http://mx4j.sourceforge.net/ (dort allerdings nur in Version 3, die keine RMI-Adaptor zur Verfügung stellt).

Mit MC4J gibt es einen grafischen Client (http://mc4j.org). In diesem sind noch die alten MX4J-Libs mit dem richtigen Adaptor vorhanden.

Die mx4j-tools-1.1.1.jar muss server\lib kopiert werden.



In der Datei conf\jk2.properties muss folgendes eingetragen werden:

mx.enabled=true

#RMI enablen

mx.jrmpPort=1099

mx.jrmpHost=localhost

#Optional auch den HttpAdaptor anschalten

mx.httpPort=9999

mx.httpHost=localhost


Einen Connect über einen Java-Client geht so:

import java.util.Hashtable;

import javax.naming.Context;

import mx4j.connector.rmi.jrmp.JRMPConnector;

public class JMXTest {

public JMXTest() {

}

static public void main(String[] sarr) {

try {

String jndiName = "jrmp";

JRMPConnector connector = new JRMPConnector();

Hashtable environment = new Hashtable();

environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");

environment.put(Context.PROVIDER_URL, "rmi://localhost:9000");

connector.connect(jndiName, environment);

mx4j.connector.RemoteMBeanServer server = connector.getRemoteMBeanServer();

Integer count = server.getMBeanCount();

System.out.println("MBeans: "+count.intValue());

}

catch (Exception e) {

e.printStackTrace();

}

}

}


Eigen MBean erstellen. Es sollte die mx4j-jmx.jar (befindet sich in der Standard-Distribution in server\lib) in common\lib kopiert werden, damit alle WebApps Zugriff auf die selbe JMX-Implementierung haben.

Zunächst ein Interface erstellen, dieses muss im Tomcat immer die Namensgebung

xxxxMBean

haben.

public interface SystemInfoMBean
{
public long getMaxMemory();

}

Die Implementierung der MBean sieht wie folgt aus:

public class SystemInfo implements SystemInfoMBean {


public SystemInfo() {
MBeanServer server = getServer();

ObjectName name = null;
try {
name = new ObjectName("Application:Name=SystemInfoBean,Type=System");
server.registerMBean(this, name);
} catch (Exception e) {
e.printStackTrace();
}

}


private MBeanServer getServer() {
MBeanServer mbserver = null;

ArrayList mbservers = MBeanServerFactory.findMBeanServer(null);

if (mbservers.size() > 0) {
mbserver = (MBeanServer) mbservers.get(0);
}

if (mbserver != null) {
System.out.println("Found our MBean server");
} else {
mbserver = MBeanServerFactory.createMBeanServer();
}

return mbserver;
}



public long getMaxMemory() {
return Runtime.getRuntime().maxMemory()/1024;
}
}