Nach einer längeren Beta-Phase wurde heute die erste finale Version von Hibernate OGM veröffentlicht! Im Gegensatz zu Hibernate ORM, mit dem Entity-Modelle auf relationale Datenbanken abgebildet werden, kümmert sich Hibernate OGM um das Mapping von JPA-Entities auf NoSQL-Datenbanken.
Hibernate OGM erhebt dabei gar nicht erst den Anspruch, zu jedem Anwendungsfall von NoSQL-Datenbanken zu passen. Dazu gibt es zu viele unterschiedliche Ideen und Konzepte, wie nicht-relationale Daten gespeichert werden können (unstrukturiert, als Graph, als Dokument etc.). In der Praxis wird in den schemafreien NoSQL-Datenbanken aber dennoch oft mit strukturierten Daten gearbeitet, die häufig von Hand auf ein Objektmodell abgebildet werden. Der wichtige Unterschied zu den relationalen SQL-Datenbanken besteht in den flexiblen, nicht starren Schemata, d.h. Schema-Evolution (Migration) ist im laufenden Betrieb möglich und üblich.
Und genau hier glänzt Hibernate OGM: Liegt der Anwendungsfall vor, ein flexibles Entity-Modell in einer NoSQL-Datenbank zu persistieren, kann man mit den bekannten JPA-Annotationen und -Konzepten programmieren. Der Einstieg ist also denkbar einfach, wobei bei Bedarf auch produktspezifische Optimierungen möglich sind, z.B. mit nativen Abfragen (JavaScript-Abfrage-Dokumente für MongoDB, Cypher-Abfragen für Neo4j etc.).
OGM versucht, für jedes NoSQL-Produkt ein möglichst "natürliches" Mapping zu nutzen, u.a. damit andere Clients eine für das jeweilige Produkt gewohnte Datenbankstruktur vorfinden. Weil aber die API immer dieselbe ist (JPA), muss man sich nicht am Anfang auf ein NoSQL-Produkt festlegen, sondern kann das Mapping – und die Performance! – in diversen NoSQL-Stores ausprobieren und vergleichen.
In diesem Jahr habe ich Hibernate OGM auf einigen Konferenzen vorgestellt – die Folien der Vorträge kann man hier anschauen bzw. runterladen. Die Folien behandeln zwar noch die Beta-Versionen, gelten aber weitestgehend auch für die erste finale Version (die übrigens nicht die Nummer 1.0, sondern 4.1 trägt).
Ansonsten: Einfach mal ausprobieren! Wer grundlegende JPA-Kenntnisse hat, wird sich schnell mit MongoDB, Neo4J & Co. zurecht finden :-)
Mittwoch, 17. Dezember 2014
Dienstag, 17. Dezember 2013
Schema-Export mit JPA 2.1
Eine der Neuerungen in Java Persistence 2.1 ist die standardisierte Möglichkeit, aus den Mapping-Informationen des Datenmodells das Datenbank-Schema generieren zu können. Seit gestern Abend steht mit Hibernate 4.3 eine weitere Implementierung des aktuellen JPA-Standards zur Verfügung, mit der folgender Code zur Schema-Generierung ausgeführt werden kann:
Leider scheint im Standard keine Möglichkeit vorgesehen zu sein, eine Differenz zum aktuell in der Datenbank vorhandenen Schema zu ermitteln.
import javax.persistence.Persistence;
...
try (FileWriter out
= new FileWriter("schema-komplett.sql")) {
Map<String, Object> props = new HashMap<>();
props.put(
"javax.persistence.schema-generation.scripts.action",
"create");
props.put(
"javax.persistence.schema-generation.scripts.create-target",
out);
Persistence.generateSchema(
"name-der-persistence-unit", props);
}
Leider scheint im Standard keine Möglichkeit vorgesehen zu sein, eine Differenz zum aktuell in der Datenbank vorhandenen Schema zu ermitteln.
Freitag, 29. November 2013
JPA-Schema-Export mit Hibernate
Die Hibernate-Tools bieten mit den Klassen
Mit der ermittelten Configuration kann nun das komplette Schema ...
... oder aber nur die Differenz zum aktuell in der Datenbank vorhandenen Schema ermittelt werden:
Das
Im kommenden Hibernate 4.3, das die JPA-2.1-Spezifikation implementiert, wird Ejb3Configuration nicht mehr enthalten sein. Dann muss bzw. kann endlich die mit JPA 2.1 standardisierte Schema-Generierung verwendet werden.
SchemaExport und SchemaUpdate die Möglichkeit, das Datenbank-Schema (Tabellen, Indizes, Fremdschlüssel-Constraints etc.) aus den Mapping-Informationen des Datenmodells zu generieren. Da es sich um Hibernate-spezifische API handelt, wird von den Klassen eine Hibernate-Configuration erwartet. Mit Hilfe der kleinen, von Hibernate nicht offiziell unterstützten (und mittlerweile auf "deprecated" gesetzten) Klasse Ejb3Configuration kann aber auch eine Java-Persistence-Konfigurationsdatei persistence.xml eingelesen werden:import org.hibernate.cfg.Configuration;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
...
Configuration cfg =
new Ejb3Configuration()
.configure("name-der-persistence-unit", null)
.getHibernateConfiguration();
Mit der ermittelten Configuration kann nun das komplette Schema ...
SchemaExport schemaExport = new SchemaExport(cfg);
schemaExport.setOutputFile("schema-komplett.sql");
schemaExport.create(true, false);
... oder aber nur die Differenz zum aktuell in der Datenbank vorhandenen Schema ermittelt werden:
SchemaUpdate schemaUpdate = new SchemaUpdate(cfg);
schemaUpdate.setOutputFile("schema-diff.sql");
schemaUpdate.execute(true, false);
Das
true beim jeweils letzten Aufruf sorgt dafür, dass das SQL-Skript in die angegebene Datei geschrieben wird. Das false verhindert, dass die SQL-Anweisungen in der Datenbank ausgeführt werden.Im kommenden Hibernate 4.3, das die JPA-2.1-Spezifikation implementiert, wird Ejb3Configuration nicht mehr enthalten sein. Dann muss bzw. kann endlich die mit JPA 2.1 standardisierte Schema-Generierung verwendet werden.
Donnerstag, 24. Oktober 2013
Java in OS X 10.9 "Mavericks"
Das Upgrade von OS X 10.8 nach 10.9 lief komplett problemlos, so soll es sein. Allerdings war anschließend Java 6 (Apples Implementation) nicht mehr vorhanden – wer diese Version benötigt, muss Java for OS X 2013-005 manuell herunterladen und installieren. Man hat dann Java 1.6.0_65 auf der Platte (im Gegensatz zu Oracle veröffentlicht Apple noch kostenfreie Updates für Java SE 6).
Ein bereits installiertes JDK 7 von Oracle bleibt normalerweise erhalten. Wer zu den Nutzern gehört, bei denen auch diese Java-Installation nach dem Upgrade nicht mehr aktiv ist, installiert einfach das aktuelle JDK 7u45. Java-7-Versionen bis einschließlich 7u25 wurden/werden von Apple aus Sicherheitsgründen deaktiviert.
Ein bereits installiertes JDK 7 von Oracle bleibt normalerweise erhalten. Wer zu den Nutzern gehört, bei denen auch diese Java-Installation nach dem Upgrade nicht mehr aktiv ist, installiert einfach das aktuelle JDK 7u45. Java-7-Versionen bis einschließlich 7u25 wurden/werden von Apple aus Sicherheitsgründen deaktiviert.
Freitag, 11. Oktober 2013
Java-Batch-Anwendungen
Mal ein bisschen Werbung in eigener Sache. Im Frühjahr wurde der neue Standard "Batch Applications for the Java Platform" (JSR-352) – oder kurz "Java Batch" – in der Version 1.0 freigegeben. Der Standard bietet einen Rahmen, um Massendaten transaktional, blockweise und im Fehlerfall mit Wiederaufsetzpunkten zu verarbeiten. Und das unabhängig davon, ob die Batch-Verarbeitung in Java SE oder in Java EE stattfinden soll.
Dieser Bereich der Datenverarbeitung war lange Zeit ganz klar vom Großrechner (Host) dominiert, aber im Rahmen der allgemeinen Migrationsbestrebungen weg von COBOL (ja, das ist immer noch ein wichtiges Thema) entstehen Batch-Anwendungen mehr und mehr im Java-Umfeld.
Nachdem ich bereits auf dem Herbstcampus in Nürnberg zu diesem Thema gesprochen habe, halte ich nun einen weiteren Vortrag im Rahmen der Reihe "GFU Semicolon" in Köln. Nach einem Überblick über die Batch-Architektur schauen wir uns die Grundlagen der Batch-Programmierung in Java SE mit der Referenzimplementation JBatch an. Die Integration in Java EE 7 zeige ich am Beispiel von GlassFish 4.
Der Vortrag findet statt am Dienstag, 22.10.2013, von 18:00 bis 19:00 Uhr. Im Anschluss gibt es bei einem kleinen Imbiss Gelegenheit zur Diskussion. Die Teilnahme ist kostenlos, eine Anmeldung ist aber erforderlich.
[Update 24.10.]
Die Folien sind nun verfügbar – und ein Foto vom Vortrag:
Dieser Bereich der Datenverarbeitung war lange Zeit ganz klar vom Großrechner (Host) dominiert, aber im Rahmen der allgemeinen Migrationsbestrebungen weg von COBOL (ja, das ist immer noch ein wichtiges Thema) entstehen Batch-Anwendungen mehr und mehr im Java-Umfeld.
Nachdem ich bereits auf dem Herbstcampus in Nürnberg zu diesem Thema gesprochen habe, halte ich nun einen weiteren Vortrag im Rahmen der Reihe "GFU Semicolon" in Köln. Nach einem Überblick über die Batch-Architektur schauen wir uns die Grundlagen der Batch-Programmierung in Java SE mit der Referenzimplementation JBatch an. Die Integration in Java EE 7 zeige ich am Beispiel von GlassFish 4.
Der Vortrag findet statt am Dienstag, 22.10.2013, von 18:00 bis 19:00 Uhr. Im Anschluss gibt es bei einem kleinen Imbiss Gelegenheit zur Diskussion. Die Teilnahme ist kostenlos, eine Anmeldung ist aber erforderlich.
[Update 24.10.]
Die Folien sind nun verfügbar – und ein Foto vom Vortrag:
Montag, 22. April 2013
REST-Web-Services mit JAX-RS portabel aktivieren
... und dennoch implementationsspezifisch konfigurieren? Eins nach dem anderen. Seit Java EE 6 kann man JAX-RS in einem Application-Server portabel dadurch aktivieren, dass man eine Klasse von
D.h. dass man nun REST-Web-Services anbieten kann, ohne sich um die konkrete Implementierung – beispielsweise Jersey als Referenz-Implementation – kümmern zu müssen. Gut.
Was aber, wenn man doch gewisse produktspezifische Features nutzen möchte, wie beispielsweise ausführliches Trace-Logging bei Jersey? Dann greift man auf den Deployment-Deskriptor
javax.ws.rs.core.Application ableitet und mit @ApplicationPath annotiert:package com.muchsoft.rest;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/rest")
public class ApplicationWithRESTWebServices
extends Application {
}
D.h. dass man nun REST-Web-Services anbieten kann, ohne sich um die konkrete Implementierung – beispielsweise Jersey als Referenz-Implementation – kümmern zu müssen. Gut.
Was aber, wenn man doch gewisse produktspezifische Features nutzen möchte, wie beispielsweise ausführliches Trace-Logging bei Jersey? Dann greift man auf den Deployment-Deskriptor
web.xml zurück und mappt dort ein Servlet mit den entsprechenden Init-Parametern. Allerdings muss das nicht eine Jersey-Klasse (mit entsprechendem servlet-mapping) sein, sondern es reicht, die eigene Application-Unterklasse als Servlet einzutragen (ohne servlet-mapping-Element):
<servlet>
<servlet-name>
com.muchsoft.rest.ApplicationWithRESTWebServices
</servlet-name>
<init-param>
<param-name>
com.sun.jersey.api.json.POJOMappingFeature
</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>
com.sun.jersey.config.feature.Trace
</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
Donnerstag, 21. März 2013
REST-Web-Services mit BASIC-Auth und HTTPS in GlassFish
Nehmen wir mal einen einfachen REST-Web-Service wie den folgenden, der alle Bestellungen des Benutzers liefern soll:
Mit beispielsweise Wget könnte dieser Service dann wie folgt aufgerufen werden, wenn der Applikationspfad auf "rest" gemappt ist:
Fast immer muss ein solcher Service abgesichert werden, damit nur bestimmte Anwender Zugriff darauf haben. Man könnte natürlich den UserPrincipal programmatisch auswerten, aber sofern die berechtigten Benutzer im Application-Server als User eingetragen sind, ist eine deklarative Absicherung einfacher - und erfordert keine Änderungen am Quelltext.
Am Beispiel von GlassFish 3.1.2 schauen wir uns das an. Wir erlauben dem GlassFish-Admin-User, den Web-Service aufzurufen. Dazu sichern wir am Ende des Deployment-Deskriptors
Die BASIC-Authentication, bei der Benutzername und Passwort im Klartext (!) übertragen werden, ist hier dennoch in Ordnung, weil wir gleichzeitig mit https die verschlüsselte Datenübertragung aktivieren.
Die berechtigten Anwender müssen im "admin-realm" eingetragen sein, das ist der Realm mit allen GlassFish-Admins (der in der Standardinstallation den User "admin" enthält). Als Beispiel für einen Security-Realm ist das hier ausreichend; in der Praxis wird man aus Sicherheitsgründen eher einen separaten Realm im GlassFish konfigurieren und in
Nun müssen wir dem Application-Server noch – produktspezifisch – mitteilen, welche Benutzernamen aus dem Realm auf welche Rollen gemappt werden. Dies erfolgt in der Datei
Fertig. Der Aufruf des Web-Services erfolgt über Wget nun mit
Ein Aufruf über unverschlüsseltes http ist nicht mehr möglich. Während wir hier der Einfachheit halber auf die Prüfung des https-Zertifikats verzichten, sollte man in der Praxis besser ein geeignetes eigenes Zertifikat im Server installieren und auf Client-Seite verwenden.
@Path("/bestellungen")
public class BestellungWebService {
@Context
private SecurityContext securityContext;
@Produces({ MediaType.APPLICATION_JSON,
MediaType.APPLICATION_XML })
@GET
public Response getAlleBestellungen() {
final String username =
securityContext.getUserPrincipal().getName();
try {
List<Bestellung> bestellungen = ...;
return Response.ok( bestellungen ).build();
}
catch (Exception e) {
return Response.serverError()
.entity( e.getMessage() ).build();
}
}
}
Mit beispielsweise Wget könnte dieser Service dann wie folgt aufgerufen werden, wenn der Applikationspfad auf "rest" gemappt ist:
wget http://localhost:8080/meinewebapp/rest/bestellungenFast immer muss ein solcher Service abgesichert werden, damit nur bestimmte Anwender Zugriff darauf haben. Man könnte natürlich den UserPrincipal programmatisch auswerten, aber sofern die berechtigten Benutzer im Application-Server als User eingetragen sind, ist eine deklarative Absicherung einfacher - und erfordert keine Änderungen am Quelltext.
Am Beispiel von GlassFish 3.1.2 schauen wir uns das an. Wir erlauben dem GlassFish-Admin-User, den Web-Service aufzurufen. Dazu sichern wir am Ende des Deployment-Deskriptors
web.xml alle Ressourcen unterhalb /rest so ab, dass nur die "admin"-Rolle darauf zugreifen darf. Mit CONFIDENTIAL erzwingen wir zudem, dass die Übertragung der Daten per https (SSL bzw. TLS) stattfindet:<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
...
<security-constraint>
<web-resource-collection>
<url-pattern>/rest/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>admin-realm</realm-name>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
</web-app>
Die BASIC-Authentication, bei der Benutzername und Passwort im Klartext (!) übertragen werden, ist hier dennoch in Ordnung, weil wir gleichzeitig mit https die verschlüsselte Datenübertragung aktivieren.
Die berechtigten Anwender müssen im "admin-realm" eingetragen sein, das ist der Realm mit allen GlassFish-Admins (der in der Standardinstallation den User "admin" enthält). Als Beispiel für einen Security-Realm ist das hier ausreichend; in der Praxis wird man aus Sicherheitsgründen eher einen separaten Realm im GlassFish konfigurieren und in
web.xml referenzieren.Nun müssen wir dem Application-Server noch – produktspezifisch – mitteilen, welche Benutzernamen aus dem Realm auf welche Rollen gemappt werden. Dies erfolgt in der Datei
glassfish-web.xml (früher sun-web.xml):<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC
"-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN"
"http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app>
<context-root>meinewebapp</context-root>
<security-role-mapping>
<role-name>admin</role-name>
<principal-name>admin</principal-name>
</security-role-mapping>
</glassfish-web-app>
Fertig. Der Aufruf des Web-Services erfolgt über Wget nun mit
wget https://localhost:8081/meinewebapp/rest/bestellungen
--user ... --password ... --no-check-certificate
Ein Aufruf über unverschlüsseltes http ist nicht mehr möglich. Während wir hier der Einfachheit halber auf die Prüfung des https-Zertifikats verzichten, sollte man in der Praxis besser ein geeignetes eigenes Zertifikat im Server installieren und auf Client-Seite verwenden.
Abonnieren
Posts (Atom)


