21. Dezember 2008

Auf GlobaleEvents mit dem .NET Framework reagieren

Globale Events können mit dem .NET Framework über die Win32-Funktion SetWindowsHookEx behandelt werden. Allerdings lassen sich nur die beiden low-level Hooks WH_KEYBOARD_LL und WH_MOUSE_LL behandeln.

Win32-Funktionen:

public class Win32Helper
{


[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);


public delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);


[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);


[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);



[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);



[StructLayout(LayoutKind.Sequential)]
public class POINT
{
public int x;
public int y;
}


[StructLayout(LayoutKind.Sequential)]
public struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}

public enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205,
}


public enum WindowsHookCodes : int
{

WH_KEYBOARD = 2,
WH_MOUSE = 7,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
}


Die Klasse HookHelper kapselt den Zugriff auf die Win32-Funktionen und stellt ein Event bereit, auf das sich andere Klassen registrieren können.

  public class HookHelper
{
private static Win32Helper.LowLevelMouseProc _proc = LowLevelMouseHookProc;
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

public delegate void GlobalMouseListener(int code, IntPtr wParam, Win32Helper.MSLLHOOKSTRUCT hookStruct);

public static event GlobalMouseListener GlobalMouseListenerEvent;

private static IntPtr hGlobalMouseHook;

public static bool StartGlobalMouseHook()
{
using (Process currentProcess = Process.GetCurrentProcess())
{
using (ProcessModule currentModule = currentProcess.MainModule)
{
hGlobalMouseHook = Win32Helper.SetWindowsHookEx((int)Win32Helper.WindowsHookCodes.WH_MOUSE_LL,
_proc,
Win32Helper.GetModuleHandle(currentModule.ModuleName),
0);
if (hGlobalMouseHook.ToInt32() == 0)
{
log.Error("SetWindowsHookEx Failed");
return false;
}
log.Debug("SetWindowsHookEx called for " + hGlobalMouseHook + " with sucess");
return true;
}
}

}

/// <summary>
/// Stoppt den globalen Maus-Hook.
/// </summary>
public static void StopGlobalMouseHook()
{

bool b = Win32Helper.UnhookWindowsHookEx(hGlobalMouseHook);
if (b)
{
log.Debug("StopGlobalMouseHook called for " + hGlobalMouseHook + " with sucess");
}
else
{
log.Error("StopGlobalMouseHook called for " + hGlobalMouseHook + " failed");
}
}

/// <summary>
/// Diese Methode wird im Falle gerufen im Falle des MouseHooks.
/// Sorgt dafuer, dasd die EventListener von GlobalMouseListenerEvent gerufen werden.
/// </summary>
/// <param name="nCode"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
private static IntPtr LowLevelMouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{

Win32Helper.MSLLHOOKSTRUCT hookStruct = (Win32Helper.MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(Win32Helper.MSLLHOOKSTRUCT));

if (GlobalMouseListenerEvent.GetInvocationList().Length > 0)
{
GlobalMouseListenerEvent(nCode, wParam, hookStruct);
}

return Win32Helper.CallNextHookEx(hGlobalMouseHook, nCode, wParam, lParam);
}

}


In einem Form kann der HookHelper wie folgt verwendet werden:


public MainForm()
{
InitializeComponent();

HookHelper.GlobalMouseListenerEvent += new HookHelper.GlobalMouseListener(MyGlobalMouseListener);
HookHelper.StartGlobalMouseHook();
...
}


public void MyGlobalMouseListener(int code, IntPtr wParam, Win32Helper.MSLLHOOKSTRUCT hookStruct)
{
if (code >= 0 && Win32Helper.MouseMessages.WM_LBUTTONDOWN == (Win32Helper.MouseMessages)wParam)
{
System.Diagnostics.Trace.WriteLine(hookStruct.pt.x + ", " + hookStruct.pt.y);
}
}

18. Dezember 2008

Garbage Collector und Sun´s VM

Folgende GarbageCollectors gibt es bei der Sun VM (Hotspot):

1. serial:
-XX:+UseSerialGC
Besonders sinnvoll
  • bei einer CPU
  • nicht speicherlastigen Anwendungen
JMX: Copy (2 Gen) und MarkSweepCompact (6 Gen)


2. throughput collector:

-XX:+UseParallelGC
Verwendet mehrere Threads für die Minor GC. Schlechtere Performance bei 1 CPU, gleiche Performance bei 2 CPUs wie seriell, bessere Performance ab 3 CPUs zu erwarten. (Die Anzahl der Threads kann über -XX:ParallelGCThreads=[anzahl] gesteuert werden).

Besonders sinnvoll
  • wenn es auf Leistung ankommt (CPU-lastige Anwendungen)

JMX: PS Scavenge (2 Gen) und PS MarkSweep (4 Gen)


3. concurrent low pause collector:
-XX:+UseConcMarkSweepGC
Versucht große Teile der Major GC parallel mit den Applikations-Threads zu machen. Braucht dadurch etwas mehr CPU. Sinnvoll ab 2 CPUs.

Besonders sinnvoll
  • wenn es auf kurze Stopzeiten durch den GC ankommt.
  • wenn viele Daten lang im Speicher gehalten werden (z.B. Katalogdaten, Caches, etc.)
JMX: ParNew (2 Gen) und ConcurrentMarkSweep (4 Gen)


Anmerkung: Die Sun VM kann den GarbageCollector dynamisch ändern, wenn nichts explizit angegeben wird.

Links mit Detailinfos:
Alle VM Options der Sun VM
GC Tuning Java SE 5
GC Tuning Java SE 6

21. November 2008

Anderen DB2Client ohne Setup-Installation verwenden

1. SQLLIB-Verzeichnis kopieren von einem 6er-Client

2. Registry anpassen

[HKEY_LOCAL_MACHINE\SOFTWARE\IBM\DB2\GLOBAL_PROFILE]
"DB2PATH"="c:\\DB2Clients\\SQLLIB\\"


[HKEY_LOCAL_MACHINE\SOFTWARE\IBM\DB2\PROFILES\DB2]
"DB2INSTPROF"="c:\\DB2Clients\\SQLLIB\\"


3. Umgebungsvariablen ändern

SET PATH=c:\DB2Clients\SQLLIB\BIN;c:\DB2Clients\SQLLIB\FUNCTION;c:\Daten\Tools\Java\jdk1.3.1_02\jre\bin\
SET DB2INSTANCE=DB2
SET JAVA_HOME=c:\Daten\Tools\Java\jdk1.3.1_02\jre
REM set db2node=0
set db2node=0
set LANG=De_DE
SET DB2CLP=
set DB2CODEPAGE=850
set DB2PATH=C:\DB2Clients\SQLLIB
SET DB2TEMPDIR=c:\DB2Clients\SQLLIB
SET CLASSPATH=.;c:\DB2Clients\SQLLIB\java\db2java.zip;c:\DB2Clients\SQLLIB\java\runtime.zip
SET INCLUDE=c:\DB2Clients\SQLLIB\INCLUDE;c:\DB2Clients\SQLLIB\LIB;c:\DB2Clients\SQLLIB\SQLLIB\TEMPLATES\INCLUDE
SET LIB=c:\DB2Clients\SQLLIB\LIB



4. Das Katalogisieren ausführen als LokalerUser, der Adminstrator ist (keinen DomänenUser, der Admin ist)

catalog tcpip node node_v6 REMOTE myserver.mydomain.com SERVER 50000

catalog database mydb as myalias at node node_v6

13. November 2008

Oracle Dump erzeugen/einspielen

Erzeugen
exp userid=loginuser/passwd@instance tables=table1,table2,table3 file=C:\mydump.dmp

Einspielen
imp loginuser/passwd@instance file=C:\mydump.dmp touser=user tables=table1,table2,table3


Achtung für den Export/Import von BLOBs müssen die Versionen von Client und Server exakt übereinstimmen!!!

Remote Database Link mit Oracle erstellen

Erstellen des Database-Links:
CREATE DATABASE LINK link_name CONNECT TO myremoteuser IDENTIFIED BY userpassword USING 'instancename';

Aufruf eines Selects über den Link:
select * from tab@link_name

22. Oktober 2008

DB2 Locks analysieren über DB2CMD-Befehle

db2 LIST APPLICATIONS SHOW DETAIL


db2 GET SNAPSHOT FOR LOCKS ON <DBNAME>


db2pd -db wws -locks -tra -dyn -file db2locks.txt


UPDATE MONITOR SWITCHES USING STATEMENT ON GLOBAL

6. Oktober 2008

2 Persistence Context mit Spring und tx:annotation-driven

Problem: Mit zwei Persistence Context, die auf unterschiedliche Datenbanken gehen kann man die Annotation-basierte Spring-Transaktionssteuerung (über @Transactional) nicht verwenden

Ursache: Bei @Transactional kann man den zugehörigen TransactionManager nicht definieren.

Lösung: Verwendung von zwei org.springframework.transaction.interceptor.TransactionInterceptor, die jeweils auf unterschiedliche TransactionManager gehen und Definition des Transaktionsscopes in der beans.xml

15. September 2008

Shale 1.0.5: prerender-Methode des ViewController wird gerufen, aber init-Methode nicht

Problem: bei einer BackingBean, die das ViewController-Interface des Shale-Frameworks verwendet wird zwar die prerender-Methode gerufen, jedoch die init-Methode nicht.

Ursache: Der org.apache.shale.view.faces.LifecycleListener ist nicht geladen. Dieser ist eigentlich im shale-view-1.0.5.jar (META-INF\taglib.tld) enthalten, wird aber wohl in manchen Konstellation (vermutlich wenn man selbst TLDs definiert hat) nicht angezogen.

Lösung: In der web.xml muss folgender Eintrag:
<listener>
<listener-class>
org.apache.shale.view.faces.LifecycleListener
</listener-class>
</listener>

9. September 2008

CodeCoverage Tool Emma mit Tomcat

Emma ist ein kostenloses Java-Tool um CodeCoverage, z.B. von Unit-Tests zu visualisieren.

Schritt 1
: Kompilierte Klassen mit Emma erweitern
<taskdef resource="emma_ant.properties" classpathref="pathtoemmaJars" />

  • instrpathref: Pfad zu den kompilierten klassen, die von Emma instrumentalisiert werden sollen
  • destdir: Verzeichnis, in das die von Emma instrumentalisierten Klassen geschribene werden
<target name="emmaInst" description="Instrument compiled classed with emma coverage collection infos">
<emma enabled="true">
<instr instrpathref="run.classpath" destdir="deploy/inst-classes" metadatafile="deploy/metadata.emma" merge="true" />
</emma>
</target>

Schritt 2: Tomcat starten.

emma.jar muss im Classpath sein

Folgende VMArgs für Emma müssen definiert werden für den Start:

-Demma.coverage.out.file=deploy\coverage.emma
-Demma.coverage.out.merge=true

Schritt 2.1: Test durchführen

Schritt 3: Tomcat stoppen, generiert Coverage-File

Schritt 4: Report generieren
 <target name="emmaReport" >

<emma enabled="true">
<report sourcepathref="sourcepath">
<fileset dir="deploy">
<include name="*.emma" />
</fileset>

<txt outfile="deploy/coverage.txt" />
<html outfile="deploy/coverage.html" />
</report>
</emma>

</target>

JPA Named Queries auslagern

Bei JPA können Named Queries neben der Definition in Klassen (über Annotations) auch in externe XML-Files definiert werden.

Das XML-File (z.B. META-INF/namedQueries.xml) hat folgendes Format:

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
http://java.sun.com/xml/ns/persistence/orm/orm_1_0.xsd"
version="1.0">

<named-query name="findPersonByName">
<query>
<![CDATA[select person from Person person where person.name = :name]]>
</query>
</named-query>
...
</entity-mappings>


Die Datei wird dann in der persistence.xml eingebunden:


<persistence-unit name="MyPU" >
<provider>org.hibernate.ejb.HibernatePersistence</provider>

<mapping-file>
META-INF/namedQueries.xml
</mapping-file>
...
</persistence-unit>

2. September 2008

SOAP 1.2 WebServices mit JMeter testen

Problem: Bei der Verwendung von JMeter 2.3.1 (SOAP/XML-RPC Request) bekommt man eine SOAP-Exception als Antwort vom WebService: "Transport level information does not match with SOAP Message namespace URI"

Ursache: Der SOAP/XML-RPC Request kann nur Soap 1.1 Nachrichten erzeugen. Diese haben eine SOAPAction als Header-Element, die die aufzurufende Methode beinhaltet also z.B. myFunction. Das akzeptiert aber z.B. Axis2 nicht, dort muss die SOAPAction im HTTP-Header-Element "Content-Type" definiert sein.

Lösung: Einen Http Header Manager bei der JMeter Thread Group hinzufügen. Dort wird Parameter mit dem Name
Content-Type
definiert, der als Wert dann

application/soap+xml; charset=UTF-8; action="urn:myFunction"
hat.

27. August 2008

26. August 2008

Firefox-Plugin -> VersionsCheck

Problem: FireFox meldet, dass ein Plugin (pluginXY.xpi) mit dieser Version nicht kompatibel sei.

Workaround: Die Plugin-Datei (pluginXY.xpi) entpacken (einfach als pluginXY.zip umbennen). Im Archiv ist eine Datei install.rdf enthalten. Dort an dieser Stelle einfach die Firefox-Version anpassen:

<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>1.5</em:minVersion>
<em:maxVersion>2.0.*</em:maxVersion>
</Description>
</em:targetApplication>

Das funktioniert z.B. wunderbar mit dem Steganos Password Manager Plugin (spmplugin.xpi)

4. August 2008

Abfrage für Indexdienst unter Windows XP

Computerverwaltung->Indexdienst->System-Katalog durchsuchen

#Filename *log and #Size>100000000

sucht nach Files die "log" im Dateinamen und einer Größe über 100000000 Bytes haben

18. Juli 2008

Notizen: Axis2 + Spring + JPA + Tomcat 6

  • DB-Libs nach Tomcat/lib kopieren
  • Aus Tomcat/lib annotations-api.jar -> javax.persistences-Klassen raus, da veraltet! (NoSuchMethodException wegen PersistenceAnnotationBeanPostProcessor)
    • nur notwendig, wenn die Klassen neuer als 13.02.2007 sind
  • persistence.xml wird gelesen, auch wenn über Spring definiert
    • Klassen (ORMs) müssen angegeben werden
    • im Element persistence-unit muss transaction-type="RESOURCE_LOCAL" definiert werden (-> BasisDatasource Problem)
  • - beans.xml
    • <property name="persistenceUnitName" value="MyPU" /> kann definiert werden um eindeutig zu sein
  • services.xml anpassen (AXIS2)
    • Definition eines SpringInit-Services zum Laden des SpringContext
    • Eigentlicher Service wird nun über SpringAppContextAwareObjectSupplier (und eine darin definierte SpringBean) gemacht
  • Alle Libs (außer eigene jars und axis2-spring.jar: diese kommen in services\myService\lib) in WEB-INF\lib
  • Eclipse: Im Ordner ".settings" -> Datei org.eclipse.wst.common.component anpassen (deploy-path raus)

16. Mai 2008

Umwandeln eines normalen Java-Projekts in ein WTP-Projekt

Schritt1:

in das .project-File müssen folgende Einträge hinzu

<natures>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
</natures>

Schritt2:

Danach kann über Project-Properties im Unterpunkt "Project Facets" das Facet "Dynamic Web Module" hinzugefügt werden.

Tomcat-Logging mit Eclipse WTP

Problem: Die Logfiles des Tomcats, der unter Eclipse mit WTP konfiguriert ist, werden nicht geschrieben:

Lösung:
  • logging.proerties aus ${catalina.base}/conf muss in den config-Ordner der WTP-Server kopiert werden.
  • Launch configuration folgende VM arguments hinzufügen:
    • -Djava.util.logging.config.file="${catalina.base}\conf\logging.properties"
      -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager

7. April 2008

Enterprise Archtitect: Synchronize Package with Code

Problem: Bei der Synchronisation aus Sparx Enterprise Architect (Merge Project oder Synchronize Package with Code) muss jede Klasse bestätigt werden:

Lösung: Im Menü "Tools->Options" aufrufen. Dort "Source Code Engineering" auswählen und den Haken bei der Checkbox "Prompt when Synchronizing (reversing)" rausnehmen.

19. März 2008

Debuggen einer Tomcat-Webapp aus Sparx Enterprise Architect

Tomcat

1. Der Tomcat muss als VM-Argumente den EA-Agent gesetz haben

"-agentpath:C:\Programme\Sparx Systems\EA\SSJavaProfiler71.dll"

2. Im Classpath des Tomcats muss der Source-Code der Applikation sein.

3. Tomcat starten


Sparx Enterprise Architect

1. Source Code der Tomcat-Applikation importieren

2. Package Build Script erstellen auf dem Basis-Package der Sourcen

2.1 Dazu unter Debug auf "Attach to process" stellen
2.2 Im Directory muss der volle Pfad zu den kompilierten Klassen stehen (web-inf\classes)

3. Auf dem Basis-Package der Sourcen einen "Debug Run" starten
3.1 Es geht ein Fenster mit Prozessen auf, dabei die des javaw.exe des Tomcats wählen

4. Die Stelle in der WebApp einmalig ausführen, bei der ein Breakpoint gesetzt werden soll

5. Den Breakpoint setzten im EA

6. Die Stelle in der WebApp nochmal ausführen, EA springt nun an den Breakpoint.

7. Im View "Debug Workbench" auf "Record Stack Trace for this Thread" drücken

8. Durch die Stellen im Code steppen, zu denen ein Sequenzdiagramm aufgezeichnet werden soll.

9. Zum Abschluss auf "Stop Recording" drücken

10. Schließlich wird das Sequendiagramm erzeugt


Anmerkung: Sollte das MDG Link Plugin für Eclipse verwendet werden, setzt man einen Breakpoint, in dem man im EA eine Klasse auswählt und dann über das Menü View->Source Code auswählt. Dadurch erscheint der EA-interne Codeeditor.

28. Februar 2008

Garbage Collector analysieren

Über folgende Java-Optionen kann ein Garbage-Collector-Logfile geschrieben werden:

-XX:+PrintGC -XX:+PrintGCTimeStamps -Xloggc:logs/gcoutput.log

Zur Analyse können folgende Tools verwendet werden:

- HPjtune, bzw. dessen Nachfolger HPjmeter Console
- Tagtraum GCViewer

13. Februar 2008

jstat, jmap, jps,... funktioniert nicht wenn der Java-Prozess per Windows "Scheduled Task" gestartet wurde

Problem: Ein Java-Prozess wird per Schedulded Task gestartet. Wenn JDK-Tools wie jmap, jps oder jstat auf diesen Prozess verwendet werden, erhält man die Fehlermeldung "process information unavailable" oder "Not enough storage is available to process this command".

Workaround: Eine zweite Scheduled Task anlegen, die das gewünschte Tool ausführt, dann funktioniert der Zugriff auf den anderen, per Scheduled Task gestarteten Java-Prozess.

12. Februar 2008

JMeter und JSF

Problem: Bei JSF gibt es die Besonderheit, dass auf der Clientseite in einem "hidden field" ein ViewState gespeichert wird. Dieser ermöglicht dem Server die Zuordung zu einem ComponentTree. Der Inhalt dieses Feldes variiert bei jedem Aufruf und muss immer mitgeschickt werden. Mit einem Standard-JMeter-Test ist dies nicht möglich.

Lösung: Durch die Verwendung eines "Regular Expression Extractor" kann immer der richtige Feldinhalt mitgeschickt werden.

Schritt 1:

Bei JMeter muss in der Thread Gruppe ein "Regular Expression Extractor" angelegt werden mit folgenden Eigenschaften:

Für die SUN-RI:
  • Respons Field to check: body
  • Reference name: jsfViewState
  • Regular Expression: <input type="hidden" name="com\.sun\.faces\.VIEW" id="com\.sun\.faces\.VIEW" value="(.+?)" />
  • Template: $1$
  • Match No.: 0
  • Default Value: leer
Für Apache MyFaces:
  • Respons Field to check: body
  • Reference name: jsfViewState
  • Regular Expression: <input type="hidden" name="javax\.faces\.ViewState" id="javax\.faces\.ViewState" value="(.+?)" />
  • Template: $1$
  • Match No.: o
  • Default Value: leer
Schritt 2:

Bei jeder aufgezeichneten JSP im Recording Controller muss unter "Parameter die mit dem Request gesendet werden" die oben definierte Variable gesetzt werden:
  • bei SUN RI
    • Das Feld "com.sun.faces.VIEW" mit dem Wert "${jsfViewState}" überschrieben werden
  • bei Apache MyFaces
    • Das Feld "javax.faces.ViewState" mit dem Wert "${jsfViewState}" überschrieben werden

8. Februar 2008

JMeter Webtest aufzeichnen und abspielen

Schritt 1: Vorbereitung im JMeter
  • Unter Testplan
    • Eine neue Threadgruppe anlegen
      • Einen HTTP Cookie Manager anlegen (damit Cookie-basierte Anwendungen funktionieren und die Session zugeordnet werden kann)
      • Alternativ kann auch ein HTTP URL Re-writing Modifier angelegt werden
        • als Session Argument Name muss dort z.B. jsessonid hinterlegt werden
      • Einen Recording Controller anlegen
        • in diesem werden die Aufzeichnungen des Http Proxy Server abgelegt
  • Unter Workbench
    • Einen Http Proxy Server anlegen
      • Als Target Controller den Recording Controller auswählen

Schritt 2: Test aufzeichnen
  • Browser öffnen und als Proxy Server den Port eingeben der im JMeter beim Http Proxy Server angegeben wurde (Default=8080)
  • Browser-Cache und Cookies löschen
  • Im JMeter beim Http Proxy Server auf "Start" drücken
  • Gewünschte Seiten im Browser aufrufen
  • Im JMeter beim Http Proxy Server auf "Stop" drücken
Schritt 3: Test nachbearbeiten
  • Die Seiten wurden im Recording Controller abgelegt, dort können Sie nachträglich nachbearbeitet werden, z.B. durch Variablen
Schritt 4: Tests abspielen
  • In der Threadgruppe kann nun die Häufigkeit und Parallelität der Ausführung gewählt werden
  • Zur Auswertung des Ergebnis sollten der Threadgruppe nun noch Lauscher (Listeners) hinzugefügt werden (z.B. Summary Report)
  • Über das Menü Start/Start kann der Test gestartet werde

5. Februar 2008

synchronized bei Methoden

normales Methoden-synchronized

public class MyClass
{
...
public synchronized int rechne()
{
// Code hier
}
...

}

entspricht

public class MyClass
{
...
public int rechne()
{
synchronized(this)
{
// Code hier
}
}
...

}

synchronized bei einer statischen Methode

public class MyClass
{
...
public static synchronized int machwas()
{
// Code hier
}
...

}

entspricht

public class MyClass
{
...
public static int machwas()
{
synchronized(MyClass.class)
{
// Code hier
}
}
...

}

4. Februar 2008

Thread Dumps erzeugen unter Java

Vor JDK 1.5

Windows:


"Ctrl" + "Break" erzeugt einen Thread Dump in Standard-Out

Linux/Unix:

kill -3 <pid> erzeugt einen Thread Dump in Standard-Out


Ab JDK 1.5


Über das Tool jstack aus dem Java SDK:

jstack <pid> >stack.txt


Analyse-Tools:
  • TDA (OpenSource-Tool) Thread Dump Analyzer zur Analyse von Textfiles-Dumps:
    • Threads waiting for a monitor:
      • Ein Thread wartet vor einem synchronized-Block, der gerade von einem anderen Thread durchlaufen wird
    • Threads sleeping on a monitor:
      • Ein Thread ist innerhalb eines sychronized-Blocks und ruft dort wait() auf

11. Januar 2008

SQLServer JDBC Treiber und Integrated Authentication

Es wird der SQLServer-JDBC-Treiber benötigt.

Die Datei sqljdbc_auth.dll muss sich im Windows Path befinden

Demo URL mit Instanz:

jdbc:sqlserver://localhost;instanceName=rfinstance;integratedSecurity=true;