Logging mit log4j in Maven Projekt integrieren

Log4j Properties in Maven Projekt integrierenLog4j ist eine logging Library der Apache Software Foundation und ermöglicht es Log-Ausgaben im Programm an verschiedenste Ziele zu schreiben. Das bekannteste Ziel ist sicher das Schreiben der Logmeldungen in eine Log-Datei, aber auch das schreiben der Meldungen in eine Datenbank oder das Verschicken per E-Mail ist möglich. Das Ziel der Meldungen wird über sogenannte Log-Appender in der Datei log4j.properties konfiguriert. Diese liegt in einem Maven Projekt in dem Resourcen Verzeichnis. (siehe Bild)

Datei: log4j.properties

# Root logger option
log4j.rootLogger=DEBUG, file
# LogLeel DEBUG und akive appender Console und Log-Datei

# Log to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Log to file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=2
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Log to mail
log4j.appender.email=org.apache.log4j.net.SMTPAppender
log4j.appender.email.SMTPHost=mail.mydomain.com
log4j.appender.email.SMTPUsername=myuser@mydomain.com
log4j.appender.email.SMTPPassword=mypw
log4j.appender.email.From=myuser@mydomain.com
log4j.appender.email.To=myuser@mydomain.com
log4j.appender.email.Subject=Log of messages
log4j.appender.email.BufferSize=1
log4j.appender.email.EvaluatorClass=TriggerLogEvent
log4j.appender.email.layout=org.apache.log4j.PatternLayout
log4j.appender.email.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Log to DB
log4j.appender.DB=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DB.URL=jdbc:mysql://localhost/DBNAME
log4j.appender.DB.driver=com.mysql.jdbc.Driver
log4j.appender.DB.user=user_name
log4j.appender.DB.password=password
log4j.appender.DB.sql=INSERT INTO LOGS VALUES('%x','%d','%C','%p','%m')
log4j.appender.DB.layout=org.apache.log4j.PatternLayout

# CREATE TABLE LOGS
#   (USER_ID VARCHAR(20) NOT NULL,
#    DATED   DATE NOT NULL,
#    LOGGER  VARCHAR(50) NOT NULL,
#    LEVEL   VARCHAR(10) NOT NULL,
#    MESSAGE VARCHAR(1000) NOT NULL
#   );

Die erste Zeile der obigen Datei wird konfiguriert das Meldungen ab dem DEBUG-Level und darunter in eine Datei geschriebenen werden. Der Detailgrad wird mit steigender Anzahl an Meldungen durch die Level OFF, FATAL, ERROR, WARN, INFO, DEBUG und ALL angegeben.
Um log4j in das Programm zu integrieren reicht es die Dependency in der pom.xml hinzuzufügen. Log4j findet die weiter oben gelistete Konfigurationsdatei von alle, wenn sie sich im Resource-Verzeichnis befindet.

<dependencies>
	<dependency>
		<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.17</version>
	</dependency>
</dependencies>

Das Ausgeben der Logmeldungen auf verschiedenen Log-Ebenen ist mit wenigen Zeilen Code erledigt:

import org.apache.log4j.Logger;
public class LoggingTest{
   private static Logger logger = Logger.getLogger(LoggingTest.class);
   logger.info("Info");
   logger.warn("Warn");
   logger.error("Fehlermeldung");
}

WildFly – Systemproperties konfigurieren und auslesen

Im WildFly Anwendungsserver können über die Systemproperties Werte gesetzt werden auf die die deployten Anwendungen zugreifen können. Dies stellt einen einfachen Weg zum Konfigurieren von Anwendungen dar. Die Konfiguration wird in der Datei „/WILDFLY_HOME/standalone/configuration/standalone.xml“ vorgenommen:

<server xmlns="urn:jboss:domain:1.3">
  <extensions>
  ...
  </extensions>
  <system-properties>
    <property name="property1name" value="property1value"/>
    <property name="property2name" value="property2value"/>
  </system-properties>
	...
</server>

Auslesen der Systemproperties im Java Programm:

String valueProperty1 = System.getProperty("property1name");

Betriebssystem Umgebungsvariablen auslesen

Auch auf die Systemvariablen des Betriebssystem lässt sich zugreifen:

System.getenv("NAME_DER_UMGEBUNGSVARIABLE ");

Raspberry Pi – GPS Empfänger einrichten und mit Java auswerten

Für einige Projekte, z.b: im CarComputer-Bereich, wird die aktuelle GPS Position benötigt. Dazu kann an den Raspberrry Pi ein USB GPS Empfänger angeschlossen und ausgewertet werden. Die meisten der für den USB-Port erhältlichen GPS-Mäuse melden sich als serielles Gerät an und werden von dem Raspberry Pi ohne Treiberinstallation automatisch erkannt. Empfehlenswert ist der GlobalSat BU-353-S4 GPS-USB-Empfänger. Er bietet mit dem SirfStar 4 Chip eine sehr gute Empfangsleistung. Der Zugriff auf die GPS Daten kann über die Tool Suite gpsd erfolgen.

GPS Empfänger einrichten

Wird der GPS-Empfänger an den Raspberry Pi angeschlossen muss er in der Liste der USB Geräte auftauchen. Diese kann mit dem Befehl „lsusb“ aufgerufen werden.

root@raspberrypi:~# sudo lsusb
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 004: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port

Je nach Hersteller ist des GPS-Empfängers unterscheidet sich die Bezeichnung des Gerätes. In diesem Fall ist es das Gerät „Prolific Technology, Inc. PL2303 Serial Port“.
Raspbian weißt dem Gerät automatisch einen virtuellen USB Port zu. Welcher Port zugewiesen wurde kann aus dem Syslog gelesen werden mit dem Befehl: „sudo tail -f /var/log/syslog“. Hier wurde der Port „ttyUSB0“ zugewiesen. Die Logdatei kann wie die meisten Konsolen Programme mit Strg+C beendet werden:

root@raspberrypi:/dev# sudo tail -f /var/log/syslog
Apr  7 17:55:11 raspberrypi kernel: [4926303.396898] usb 1-1.3: New USB device strings: Mfr=0, Product=0, SerialNumber=0
Apr  7 17:55:11 raspberrypi kernel: [4926303.452197] usbcore: registered new interface driver usbserial
Apr  7 17:55:11 raspberrypi kernel: [4926303.454106] usbcore: registered new interface driver usbserial_generic
Apr  7 17:55:11 raspberrypi kernel: [4926303.455879] USB Serial support registered for generic
Apr  7 17:55:11 raspberrypi kernel: [4926303.455924] usbserial: USB Serial Driver core
Apr  7 17:55:11 raspberrypi kernel: [4926303.465107] usbcore: registered new interface driver pl2303
Apr  7 17:55:11 raspberrypi kernel: [4926303.465828] USB Serial support registered for pl2303
Apr  7 17:55:11 raspberrypi kernel: [4926303.465944] pl2303 1-1.3:1.0: pl2303 converter detected
Apr  7 17:55:11 raspberrypi kernel: [4926303.477427] usb 1-1.3: pl2303 converter now attached to ttyUSB0

Um die von dem GPS-Empfänger empfangen GPS-Koordinaten auszulesen empfehlen sich unter Linux die bereits angesprochenen gpsd Tools. Diese können mit folgendem Befehl installiert werden:

sudo apt-get install gpsd gpsd-clients python-gps

Der gpsd Daemon wird wie folgt gestartet:

sudo gpsd /dev/ttyUSB0 -F /var/run/gpsd.sock -G

Das Flag „-G“ sorgt dafür, das der Server unter allen IP-Adressen auf Port 2947 erreichbar ist und nicht nur unter localhost. Unter Windows kann dies z.B. mit Telnet getestet werden. (Telnet muss ab Windows 7 über „Programme und Funktionen“ in der Systemsteuerung nachinstalliert werden)

telnet IP_ADRESSE_RASPI 2947

Für den GlobalSat Empfänger kann es notwendig sein sein Binärprotokoll nach NMEA zu ändern damit dieses korrekt von gpsd verarbeitet wird. Dies kann mit dem Befehl „gpsctl -n“ erreicht werden.

Anzeige der GPS Daten

Die GPS-Daten können auf der Konsole mit dem Programm „cgps“ angezeigt werden. Dabei ist zu beachten das der GPS Empfänger freie Sicht zum Himmel benötigen um Daten zu empfangen.
cgps

sudo cgps -s

Mit dem Befehl „xgps“ steht ein grafische Programm zur Verfügung. Ist an dem Raspberry Pi kein Monitor angeschlossen kann die Ausgabe grafischer Programme auch über SSH erfolgen wie es in diesem Artikel beschrieben.
xgps

sudo xgps

Mit dem Programm „gpsmon“ der gpsd Toolsuite lassen sich die vom GPS Empfänger gesendet Rohdaten, meist in Form von NMEA Sätzen, live auf der Console sehen. Somit kann wunderbar überprüft werden ob Daten empfangen werden.

sudo gpsmon

NMEA_GPSMON

Auslesen der GPS-Daten in Java

Gpsd stellt die GPS-Daten in JSON codierter Form auf Port 2947 bereit. Dieses können über eine TCP/IP Socketverbindung auslesen werden. Vereinfacht wird dies unter Java mit der Library GPSd4java.

Allerdings war die Library bei mir nicht direkt lauffähig. Ich musste über die Socket-Verbindung zunächst einen Befehl schicken, der die JSON-Ausgabe der GPS-Daten startet.

?WATCH={"enable":true,"json":true};

java_gpsd_testclientDanach können mit der Library die Daten sehr gut ausgelesen werden. Dazu habe ich das kleine, auf dem Screenshot abgebildete, Java Programm geschrieben:

Download ausführbares Programm „jGpsdTest“:


Download des Source-Codes:

Raspberry Pi – GPIO Pins grafisch schalten mit jgRaspiGPIO

Die GPIO Pins des Raspberry Pi lassen sich auf unterschiedlichste weise schalten. Richtig komfortable wird es aber erst mit einer grafischen Benutzeroberfläche. Dazu habe ich das Programm „jgRaspiGPIO“ geschrieben. Es bietet eine GUI mit Raspberry Pi Visualisierung wobei für jeden GPIO Pin einen Button vorhanden ist um den Schaltzustand zu Ändern. Der aktuelle Schaltzustand wird im Programm angezeigt. Der folgende Screenshot zeigt das Programm:

RaspiGPIOSwitcher

Der Weg zum Programmstart:
1. Programm herunterladen 😉

2. Wenn das Programm unter Windows heruntergeladen wird kann es mit WinSCP auf den Raspberry Pi übertragen werden. Dies ist hier beschrieben.

3. Voraussetzung für die Funktion von „jgRaspiGPIO“ ist eine Java JRE auf dem Raspberry Pi. Die aktuellen Versionen von Raspbian bringen Java bereits mit. Ob und welche Java Virtual Machine (JVM) installiert ist kann mit dem Befehl „java -version“ getestet werden.

4. Das Programm nutzt eine grafische Benutzeroberfläche. Wird der Raspberry Pi headless, d.h. ohne Monitor betrieben muss die Grafikausgabe über Netzwerk erfolgen. Dazu muss bei dem SSH Protokoll das X11 Forwarding aktiviert werden. Komfortabler ist der Zugriff von Windows auf den LXDE Desktop des Raspberry Pi mit xrdp.

5. Der Start der Software erfolgt mit Root-Rechten über folgenden Befehl in dem Verzeichnis in dem das Programm liegt:

sudo java -jar jgRaspiGPIO.jar

Hintergrundinformationen für Java Entwickler

Der „Raspi GPIO Switcher“ ist in Java geschrieben und nutzt die Pi4J Library. Um die GPIO Pins zu schalten werden nur wenige Befehle benötigt. Im wesentlichen sind dies folgende:

private static final GpioController gpioController = GpioFactory.getInstance();
// Pin als Ausgabe-Pin initialisieren
GpioPinDigitalOutput pin0 = gpioController.provisionDigitalOutputPin(RaspiPin.GPIO_00, PinState.LOW);       
// Schaltzustand ändern
pin0.toggle();

Für Maven Nutzer ist noch interessant, das die Library „pi4j-native“ ausgeschlossen wird. Ansonsten kann das Projekt nicht kompiliert werden, da versucht wird die nativen Zugriffskomponenten, die nicht in Java geschrieben sind, mit dem Java Kompiler zu kompilieren.

	<dependencies>
		<dependency>
			<groupId>com.pi4j</groupId>
			<artifactId>pi4j-core</artifactId>
			<version>0.0.5</version>
			<exclusions>
				<exclusion>
					<groupId>com.pi4j</groupId>
					<artifactId>pi4j-native</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

Der Quellcode kann hier heruntergeladen werden:

Java – Dateien lesen -> zippen -> speichern

Java ZIP TestDas folgende Beispiel zeigt die Verwendung der JFileChooser Klasse zum Öffnen und Speichern von Dateien sowie das Erstellen von ZIP Archiven. Dabei wird für die Dateien ein „Umweg“ über ein Byte-Array gegangen bevor diese in eine ZIP-Datei geschrieben werden. Byte-Arrays können in BLOB (Binary large Object) Spalten von Datenbanktabellen geschrieben werden, so das dieses Beispiel den Weg zum Byte-Array mit aufzeigt. Der Quelltext ist unten aufgeführt und als Maven Projekt angehängt:

/**
 * File open -> ZIP -> save
 *
 */
public class App {
	
	private class SelectedFile {
		private String fileName;
		private byte[] rawData;
	}

	private List<SelectedFile> filesToZip = new ArrayList<SelectedFile>();
	
	public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                new App().createUI();
            }
        };
        EventQueue.invokeLater(r);
    }

	/**
	 * Creates an zip archive with all entries from List<SelectedFile> filesToZip
	 */
	private void createZipFile(String pathWithFilename) {
		byte[] buffer = new byte[1024 * 4];

		pathWithFilename = pathWithFilename.toLowerCase();
		if(!pathWithFilename.endsWith(".zip")){
			pathWithFilename += ".zip";
		}
		
		try {
			String outputFileName = pathWithFilename;
			FileOutputStream fos = new FileOutputStream(outputFileName);
			ZipOutputStream zos = new ZipOutputStream(fos);

			for (SelectedFile file : filesToZip) {
				ZipEntry ze = new ZipEntry(file.fileName);
				zos.putNextEntry(ze);

				ByteArrayInputStream bis = new ByteArrayInputStream(file.rawData);

				int len;
				while ((len = bis.read(buffer)) > 0) {
					zos.write(buffer, 0, len);
				}
				bis.close();
			}
			zos.closeEntry();
			zos.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
		JOptionPane.showMessageDialog(null, "Die Datei(n) wurde(n) gezipt...",
				"Info", JOptionPane.INFORMATION_MESSAGE);
	}
	
    private void createUI() {
        final JFrame frame = new JFrame();
        frame.setLayout(new BorderLayout());

        JButton btnOpen = new JButton("Datei öffnen");
        JButton btnSave = new JButton("ZIP speichern");

        btnOpen.addActionListener(new ActionListener() {
        	@Override
        	public void actionPerformed(ActionEvent ae) {
        		JFileChooser openDialog = new JFileChooser();
        		int openDialogReturn = openDialog.showOpenDialog(frame);
        		openDialog.setMultiSelectionEnabled(false);
        	        if(openDialogReturn == JFileChooser.APPROVE_OPTION)
        	        {
        	        	SelectedFile sf = new SelectedFile();
        	        	sf.fileName = openDialog.getSelectedFile().getName();
        	        	String pathToFile = openDialog.getSelectedFile().getAbsolutePath();
        	        	try {
							sf.rawData = Files.readAllBytes(Paths.get(pathToFile));
						} catch (IOException e) {
							e.printStackTrace();
						}
        	        	filesToZip.add(sf);
        	        }
        	}
        });

		btnSave.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent ae) {
				JFileChooser saveDialog = new JFileChooser();
			    FileNameExtensionFilter zipExtensionFilter =
			            new FileNameExtensionFilter("ZIP File(*.zip)", "zip");
			    saveDialog.addChoosableFileFilter(zipExtensionFilter);
			    int saveDialogReturn = saveDialog.showSaveDialog(frame);
				
			    if (saveDialogReturn == JFileChooser.APPROVE_OPTION) {
					createZipFile(saveDialog.getSelectedFile().getAbsolutePath());
				}
			}
		});

        frame.add(new JLabel("Bitte zu zippende Datei auswählen:"), BorderLayout.NORTH);
        frame.add(btnOpen, BorderLayout.CENTER);
        frame.add(btnSave, BorderLayout.SOUTH);
        frame.setTitle("ZIP Files");
        frame.pack();
        frame.setLocationRelativeTo(null); // Desktop mittig
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

Java Webanwendungen mit Maven erstellen

Das Grundgerüst einer Java-Webanwendung lässt sich mit Maven schnell erstellen. Webanwendungen stellen das GUI (Graphical User Interface) des Programms in Form von Webseiten mit HTML, CSS und JavaScript dar. Um die Programmoberfläche zu erstellen stehen verschiedene Java Frameworks bereit, wovon einige am Ende des Artikels genannt werden. Das fertige Kompilat / Programm ist eine Datei mit der Dateiendung *.war (Web Archive), welche in einem Servlet Container wie Tomcat oder einem Anwendungsserver wie Wildfly deployed wird.

Falls Maven noch nicht installiert ist, wird hier erklärt wie die Installation unter Windows durchgeführt werden kann.
Als erstes erstellen Sie ein Verzeichnis in dem die Webanwendung erstellt werden soll und navigieren in der Windows Konsole (Windows-Taste + R -> cmd ) in dieses Verzeichnis. Die grundlegende Struktur der neuen Webanwendung kann durch einen einzigen Maven Befehl erzeugt werden.

mvn archetype:create -DgroupId=GROUPID -DartifactId=ARTIFACTID -DarchetypeArtifactId=maven-archetype-webapp

Hier wird Maven (mvn) mit dem Create-Befehl für das archetype Plugin aufgerufen. Parameter werden mit „-D“ eingeleitet. Bei dem Anlegen des Webprojektes muss über die Parameter eine GroupID und eine ArtifactID übergeben werden.

groupId – Der Paketname für das Projekt. Als GroupId wird meist der Domain Name verwendet, unter dem die Anwendung später erreichbar sein soll. Die einzelnen Bestandteile des Domainnamen werden dabei in umgekehrter Reihenfolge angegeben.
artifactId – Der Projektname. Die ArtifactId wird als Verzeichnisname für das Projekt genutzt und ist später in der URL der Webanwendung vorhanden. http://localhost:8080/artifactID
archetypeArtifactId – Der Archetype gibt das von dem Create-Befehl verwendete Template an. In unserem Fall ist dies das Template für eine Webanwendung. Würde der Befehl werggelassen erstellt Maven ein Standard Java-Projekt.

Beispiel:

mvn archetype:create -DgroupId=net.it_adviser.webapp -DartifactId=WebApp -DarchetypeArtifactId=maven-archetype-webapp

Das Programm kann mit dem Maven Befehl Package im Root Verzeichnis der Anwendung kompiliert werden und somit die zur Distribution fertige WAR-Datei erstellt werden. Das fertige Kompilat befindet sich im „target“ Verzeichnis:

mvn package

In Eclipse kann das Mavenprojekt einfach importiert werden. Dazu wird der das neue Verzeichnis mit der Webanwendung in das Workspace Verzeichnis kopiert und anschließend importiert. Dazu sollte in Eclipse nicht das Embedded Maven genutzt werden, sondern die externe Maven-Installation. Dies kann Preferences eingestellt werden. (Window -> Preferences -> Maven -> Installations). Das neue Projekt kann einfach über das Menü importiert werden: (File -> Import -> Maven -> Existing Maven Projekt). Dort wählen Sie das Root Verzeichnis des neuen Webprojektes und importieren die POM-Datei (Project Object Model). Siehe Bild:

Maven_Projekt_Importieren

Projektstruktur im Eclipse Projektexplorer:
Java_Webprojekt_ProjectExplorer

Für die Erstellung einer ansprechenden Weboberfläche stehen eine reihe von Frameworks bereit. u.a:
Die „Klassiker“
JSP – Java Server Pages
JSF – Java Server Faces

Moderner
Primefaces
Richfaces
GWT – Google Webtoolkit
Vaadin (GWT basiert)
Sencha GXT (GWT basiert)

Hilfreiche Eclipse Tastaturkürzel

eclipse_logoDurch die Verwendung von Tastaturkürzeln kann die Arbeit mit der Java IDE Eclipse deutlich beschleunigt werden. Die Tabelle zeigt die von mir am häufigsten verwendeten Shortcuts:

Tastaturkürzel Funktion
STRG + SHIFT + L Liste aller Tastaturkürzel
STRG + ALT + O Importe organisieren
STRG + SHIFT + F Markierten Quelltextbereich oder gesamte Klasse formatieren
STRG + SHIFT + C markierten Quelltext auskommentieren
STRG + D Zeile oder markierten Quelltext löschen
STRG + Leertaste Code Assist
STRG + SHFT + T Kalsse öffnen
STRG + SHIFT + R Resource öffnen
STRG + SHIFT + G Suche nach Referenzen im Workspace
STRG + F lokale Textsuche und Suchen / Ersetzen
STRG + H globale Suche
STRG + T Klassenhierachie
STRG + ALT + H Call Hierachie
STRG + W aktuell geöfnete Klasse schließen
STRG + L zur x ten Zeile springen
STRG + Q zur letzten editierten Stelle springen
STRG + 1 Quickfix
STRG + SHFT + J Statement inspect – makierten Bereich bei Brakepoint auswerten
STRG + ALT + Pfeilhoch oder runter Zeile oder markierten Block duplizieren
ALT + Pfeilhoch oder runter Zeile oder markierten Block verschieben
ALT + SHIFT + R Refactoring -> variable umbenennen
ALT + SHIFT + S – R Getter & Setter generieren
ALT – SHIFT + S – O Constructor generieren
ALT + SHIFT + M markierten Codebereich als Methode extrahieren
ALT , P , N Clean Project