java ee - fhws 2014 - 5.5 q&a

27
Java EE Full Stack for Business Applications

Upload: matthias-reining

Post on 16-Jul-2015

87 views

Category:

Software


1 download

TRANSCRIPT

Page 1: Java EE - FHWS 2014 - 5.5 Q&A

Java EEFull Stack for Business Applications

Page 2: Java EE - FHWS 2014 - 5.5 Q&A

Java EEFull Stack for Business Applications

2014-12-11 Q&A

Page 3: Java EE - FHWS 2014 - 5.5 Q&A

Referent: MATTHIAS REINING

Technical Manager Insurance at RGI Deutschland GmbH

blog: http://blog.matthias-reining.com

twitter: https://twitter.com/MatthiasReining

about.me: http://about.me/matthiasreining

Page 4: Java EE - FHWS 2014 - 5.5 Q&A

Q&AQuestion & Answers

Page 5: Java EE - FHWS 2014 - 5.5 Q&A

Aber zuerst…… kurze Wiederholung

Page 6: Java EE - FHWS 2014 - 5.5 Q&A

DAS PROGRAMM

Die Spec Idee, Historie

Der App Server Containerkonzept

Paketierung (JAR, WAR, EAR)

Marktüberblick

Das Projekt Entwicklung eines Beispielprojektes

IDE Settings, Oberflächen (Servlets, JSF), Business Logic (EJB), Persistence (JPA), Java EE Patterns (CDI), Web Services (JAX-RS)

Die Produktion Buildmanagement (maven, Jenkins)

Deployment einer Java EE Anwendung in der Cloud bei einem PaaS Anbieter

Page 7: Java EE - FHWS 2014 - 5.5 Q&A

DAS PROGRAMM

Die Spec Idee, Historie

Der App Server Containerkonzept

Paketierung (JAR, WAR, EAR)

Marktüberblick

Das Projekt Entwicklung eines Beispielprojektes

IDE Settings, Oberflächen (Servlets, JSF), Business Logic (EJB), Persistence (JPA), Java EE Patterns (CDI), Web Services (JAX-RS)

Die Produktion Buildmanagement (maven, Jenkins)

Deployment einer Java EE Anwendung in der Cloud bei einem PaaS Anbieter

Page 8: Java EE - FHWS 2014 - 5.5 Q&A

Question

>>>>

Wir versuchen gerade das Projekt zum laufen zu bekommen. Mir ist nicht ganz klar wie sich unsere Applikation mit der Datenbank verbindet. Ich weiß auch nicht genau was ich in der h2 config eintragen muss. Benutzername und Passwort sind im Code nicht eingetragen. Und die der zweiten persistence.xml ist denk ich mal noch von dem memory test. Aber es funktioniert ja irgendwie so, dass es sowohl mit h2 lokal als auch mit MySQL auf dem Server funktioniert.

<<<<

Page 9: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

Applikation – Datenbank

Eine Java EE Applikation kennt idealerweise NIE direkt die Datenbank.

Somit ist es möglich eine Java EE Applikation zu entwickeln die unabhängig vom eingesetzten RDBMS ist (H2, MySQL, Oracle, …)

Die Java EE Applikation connected sich zur Datenbank über eine Datasource.

Die Datasource wird in der Application Server Konfiguration definiert mit dem konkreten Bezug zu einer Datenbank H2 oder MySQL.

Der Applikation wird die Datasource in persistence.xml bekannt gemacht:

Page 10: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

Application / persistence.xmlDie Datasource wird beim Einsatz von JPA in der persistence.xml angegeben (https://github.com/mr678/fhws-2014/blob/master/src/main/resources/META-INF/persistence.xml). In der persistence.xml wird auch eine „persistence-unit“ definiert (PU). Dies ist sinnvoll, wenn eine Java EE Applikation mit mehrere Datenbanken spricht. Bei der Annotation @PersistenceContext kann man dann über den „unitName“ die passende ansprechen. Wird nur eine Persistence Unit verwendet braucht man keine weiteren Angaben bei der Annotation; wie in unserer Beispielapplikation.

Wichtig ist daher in unserem Beispiel nur die „jta-data-source“: java:jboss/datasources/FHWS-DS

Page 11: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

Application Server Konfiguration

Der Application Server kann verschieden Datasources verwalten. Dies kann über die Administrationsoberfläche (localhost:9990) gemacht werden oder per Konfigurationsdatei (in unserem Beispiel : wildfly-8.1.0.Final/standalone/configuration/standalone.xml):

<datasource jndi-name="java:jboss/datasources/FHWS-DS" pool-name="FHWS-DS" enabled="true" use-java-

context="true">

<connection-url>jdbc:h2:tcp://localhost/D:/fhws/servers/database/fhws-db</connection-url>

<driver>h2</driver>

<security>

<user-name>sa</user-name>

<password>sa</password>

</security>

</datasource>

In dem Snippet sehen sie den Parameter “jndi-name”. Dies ist der Name unsere Datasource die mit dem Eintrag in der persistence.xml matchen muss. Die Server Konfiguration (standalone.xml) habe ich gerade eben noch in GitHub eingecheckt (https://github.com/mr678/fhws-2014/blob/master/src/main/script/wildfly-configuration/standalone.xml)

Page 12: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

H2 – username/password

Die H2 Datenbank legt automatisch eine Datenbank (File auf der Platte) an, wenn noch keines da ist. Hierbei wird automatisch das angegebene Passwort verwendet. Ist bereits eine Datenbank vorhanden muss immer das Passwort von der Anlage verwendet werden.

Das Password selbst wird in der standalone.xml in unserem Beispiel eingetragen. In unserem Beispiel im Klartext. Dies ist auch oft ausreichend, da dies nur für Admins zugänglich ist, die eh Zugriff auf den Server haben. Für den Fall, dass man den Admin nicht vertraut und der App-Server Admin keinen Zugriff auf den DB-Server haben darf, kann man dieses PW auch verschlüsselt hinterlegen. Wie? Einfach mal googlen ;-)

Page 13: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

Zweite persistence.xml

Die zweite persistence.xml ist wie sie schreiben nur für den Test und auch eine In-Memory Datenbank.

Page 14: Java EE - FHWS 2014 - 5.5 Q&A

Question

>>>>

ich habe es gerade noch einmal ausprobiert. h2 datenbank im servermodus starten, wildfly server starten, in admin console neue jdbcdatasource hinzufügen (bzw. per hand in standalone.xml) und auf "testconnection" drücken. und genau dass geht nicht. da bekomme ich den fehler aus der letzten mail: "connection is not valid".

<<<<<

Page 15: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

Datenbank Problem:

Ich bekomme die gleiche Fehlermeldungen wenn ich

1. Die Datenbank nicht gestartet habe.Diese muss manuell gestartet werden. Am einfachsten auf der Konsole im Verzeichnis mit der h2-jar Datei: java -jar h2-1.3.173.jaroder

2. Das Passwort nicht passt.In der eingecheckten standalone.xml ist als Password „sa“ angegeben. Das Passwort wird beim Erstellen der DB mit dem ersten Login festgelegt.Wenn Sie bspw. ihre Datenbankdatei löschen (in unserem Beispiel: fhws-db.h2.db) und die H2 erneut starten, können Sie im Web-Interface sich auf die entsprechende Datenbank connection. Das Passwort, dass Sie bei der ersten Verbindung wählen ist anschließend auch das Passwort, dass Sie in der standalone.xml angeben müssen

Die Fehlermeldungen sind in beiden Fällen nicht unbedingt toll und könnten den Fehler besser beschreiben.

Page 16: Java EE - FHWS 2014 - 5.5 Q&A

Question

1. Beim Aufruf der listJobs-View mit unten stehender Adresse bekomme ich die Servlet Exception im Anhang. Wo liegt der Fehler?http://localhost:8080/Auftragsverwaltung-1.0-SNAPSHOT/listJobs.jsf

2. Wie installiere ich den mysql-connector dauerhaft auf dem Wildfly? Ich mache es momentan über das Runtime Deployment Management in der Admin Console, das verschwindet jedoch immer wieder.

Page 17: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

Zur Datasource:

Ich würde den Treiber mysql-xyz.jar in das Deployment Verzeichnis kopieren (einfache Variante, so haben wir das bei dem Bitnami-Cloud-Server gemacht). Alternativ können Sie auch ein JBoss/Wildfly Modul packen mit dem MySQL Treiber.

Die Konfiguration würde ich direkt in der standalone.xml vornehmen und nicht über die Admin Oberfläche. Hier können Sie auch kontrollieren ob die Änderungen angenommen worden sind.

Wenn Sie googlen nach Wildfly oder Jboss und MySQL driver install finden Sie viele Beispiele (https://docs.jboss.org/author/display/WFLY8/DataSource+configuration)

Page 18: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

ich habe die Anwendung auf github geforkt: https://github.com/mr678/auftragsverwaltung. Wenn alles gefunzt hat, haben Sie auch github einen pullrequest erhalten. Als erstes habe ich die Datasource auf Example DS geändert, damit ich bei mir nicht allzu viel einrichten muss.

Beim Aufruf ihrer „Problemseite“ habe ich Browser folgende Fehlermeldung bekommen:

Context Path:/Auftragsverwaltung-1.0-SNAPSHOTServlet Path:/listJobs.jsfPath Info:nullQuery String:nullStack Tracejavax.servlet.ServletException: Bei der Ressourcen-Einspeisung auf dem verwalteten Bean jobListProducer ist ein Fehler aufgetreten.javax.faces.webapp.FacesServlet.service(FacesServlet.java:659)io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61)io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)

Ist mehr oder wengier “bla bla bla”. Wichtig ist hier, dass Sie immer auch auf der Server schauen. Dies liegt daran, dass viele Frameworks (in diesem Fall JSF) verschiedene Wrapper und Abstraktionsschichten um den eigentlichen Code legen. Daher sieht man nicht immer direkt die Fehlermeldung im Browser.

Im Server:

19:46:04,669 SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (default task-13) Error Rendering View[/listJobs.xhtml]: com.sun.faces.mgbean.ManagedBeanCreationException: Bei der Ressourcen-Einspeisung auf dem verwalteten Bean jobListProducer ist ein Fehler aufgetreten.

at com.sun.faces.mgbean.BeanBuilder.invokePostConstruct(BeanBuilder.java:227) [jsf-impl-2.2.6-jbossorg-4.jar:]at com.sun.faces.mgbean.BeanBuilder.build(BeanBuilder.java:103) [jsf-impl-2.2.6-jbossorg-4.jar:]at com.sun.faces.mgbean.BeanManager.createAndPush(BeanManager.java:409) [jsf-impl-2.2.6-jbossorg-4.jar:]

„1000“ Zeilen im Logfile später

Caused by: java.lang.NullPointerExceptionat de.fresko.auftragsverwaltung.data.JobListProducer.createMockJobs(JobListProducer.java:39) [classes:]at de.fresko.auftragsverwaltung.data.JobListProducer.init(JobListProducer.java:20) [classes:]... 97 more

Und hier ist auch schon das Problem: NullPointerException in JobListProducer#createMockJobs Line 39

Fix in Line 17: private List<Auftrag> jobs = new ArrayList<>();

Page 19: Java EE - FHWS 2014 - 5.5 Q&A

QUESTION

d.h. in den Backing Beans arbeite ich immer ohne Konstruktoren, stattdessen mit der init()-Methode und muss dann aber die Felder schon bei der Deklaration vorinitialisieren?

Page 20: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

Konstruktoren:

Alle von einem Container gemangten Objekte benötigen immer auch einen Non-Parameter Kontruktor(weitere Konstruktoren sind hier aber natürlich erlaubt).

Gemangte Objekte: Servlets, Filter, Listener, JSF Managed Beans, EJBs, CDI Objekte, RESTful Servlets

Wieso?

Der Container initalisiert diese Objekte (via Reflection API, habe ganz am Anfang mal gezeigt wie das funktioniert – der Container macht da auch nichts anders…)

Nachdem der Container die Parameter nicht kennen kann, benötigt er immer auch einen leeren Konstruktor zum Anlegen der Objekte.

Das heißt der Container verwaltet den Lifecycle bei der Erzeugung.

Wenn Sie allerdings im Konstruktor auf andere gemangte Objekte zugreifen wollen, wie bspw. injizierte Objekte mit @EJB oder @Inject funktioniert dies im Konstruktor noch nicht, da zu diesem Zeitpunkt die Objekte noch nicht injiziert wurden.

Page 21: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

Der Grobe Lifecycle

Container legt Objekt an

Felder bei denen direkt Objekte angelegt werden, werden ausgeführt (bspw. private List<Auftrag> jobs = new ArrayList<>();)

Konstruktor wird aufgerufen (eventueller Code im Konstruktor wird ausgeführt –hier schreibt man daher selten Code aus dem oben beschrieben Problem)

Der Container injiziert gekennzeichnete Objekte

Der Container ruft die annotierte Methode @PostConstruct auf.

Wie Sie sehen, haben Sie unterschiedliche Möglichkeiten Werte zu initialisieren. Wenn man dabei den Lifecycle des Objektes grob kennt, kann man für die Klasse dann entsprechend die beste Variante raussuchen.

Page 22: Java EE - FHWS 2014 - 5.5 Q&A

Question

• #1: Warum ist checkPassword() in der Entity definiert und nicht im UserService?

• #2: Was ist der Unterschied zwischen Boundary (UserService) und Controller (PWService)? Sind Boundaries Controller, die auf die DB zugreifen?

• #3: Wieso verwendet UserService kein begin()/commit() und CreateDummyUser die UserTransaction und nicht die Methoden vom EntityManager?

• #4: Für was ist das init() in TestServletTest gut?

• #5: Werden wir in der nächsten Vorlesung den Login mit Rest programmieren?!

Page 23: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

#1: Warum ist checkPassword() in der Entity definiert und nicht im UserService?

Hier gibt es unterschiedliche Ansichten, wieviel Logik in einer Entity liegen sollte…

Ich bin eher Fan von „dummen Entities“. Das Beispiel checkPassword() haben wir glaube ich initial ganz einfach gehalten und anschließend nicht refactored.

Ich gebe Ihnen recht, sollte auch meiner Ansicht nach im UserServicesein.

Page 24: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

#2: Was ist der Unterschied zwischen Boundary (UserService) und Controller (PWService)? Sind BoundariesController, die auf die DB zugreifen?

ECB Pattern (http://www.cs.sjsu.edu/~pearce/modules/patterns/enterprise/ecb/ecb.htm)

Boundary ist die Schnittstelle nach „außen“ (bspw. zum Presentation Layer oder auch zu einem BPMS als Service Orchestrator.

Bei der Entwicklung einfach im Boundary anfangen und wenn man das Gefühl hat es wird zu viel für eine Klasse / Methode in Controller auslagern.

Der „Meister“ Adam Bien (Java Champion usw…) erklärt dies regelmäßig; auch in seinem letzten Q&A Video.http://www.adam-bien.com/roller/abien/entry/9th_airhacks_tv_q_a Stelle: 15min:20sec

Wichtig: eine Boundary ruft nie eine andere Boundary auf! Sonst hätte man eine enge Kopplung. Aus Architektur-Sicht sollte aber ein „decoupling“ ja meist das Ziel sein.

Nach Adam Bien ist es aber ok, wenn eine Boundary die Controller Klasse einer anderen Boundary aufruft…

Page 25: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

#3: Wieso verwendet UserService kein begin()/commit() und CreateDummyUser die UserTransaction und nicht die Methoden vom EntityManager?

UserService ist eine EJB (Enterprise Java Bean), genauer eine Stateless Session Bean (SLSB). Erkennt man durch die Annotation @Stateless.

SLSB sind per Transaktional – Container Managed Transaction (CMT).

Ohne weitere Annotation hat jede public Methode die über die SLSB aufgerufen wird die Transaktion @TransactionAttribute(TransactionAttributeType.REQUIRED).

Das heißt, der Container baut um die Methode automatisch ein begin() und ein commit().

Dazu gibt es auch ein paar Folien im EJB Teil.

Es geht auch anders bei SLSB: Man kann diese als Bean Managed Transaction (BMT) kennzeichnen, dann muss der Entwickler sich selbst um die Transaktionen kümmern.

CreateDummyUser ist ein Servlet und keine SLSB und besist daher kein transaktionales Verhalten. Hier muss sich der Entwickler um Transaktionen mit begin() und commit() selbst kümmern.

Aus dem Grund sind SLSB ja recht cool. Spart eine Menge Routinearbeiten…

Page 26: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

#4: Für was ist das init() in TestServletTest gut?

Die Methode init() ist mit der Annotation @Before von jUnit gekennzeichnet.

Das heißt die Methode wird vor jedem Test-Case aufgerufen. In der Beispielklasse gibt es nur einen @Test public void shouldWork(). Wären mehrere vorhanden, wird die Methode vor jedem TestCase aufgerufen und kann somit eine allgemein Initalisierung der Testcases vornehmen.

Hier würde bspw. soetwas wie „testServlet = new TestServlet();“ gut passen. Jeder Test hätte dann eine neue „saubere“ Instanz der Klasse.

Ansonsten steht in init() ja in diesem Fall nichts drin – kann somit auch gelöscht werden.

Page 27: Java EE - FHWS 2014 - 5.5 Q&A

ANSWER

#5: Werden wir in der nächsten Vorlesung den Login mit Rest programmieren?!

Wenn dann am SA – für FR steht CDI auf der Agenda.

Login ist hierbei allerdings gleich ein etwas komplizierteres Beispiel….

JavaEE hat natürlich auch eine Variante zur Authentifizierung – allerdings haben wir über diese noch gar nicht gesprochen. Ich habe dies bewusst etwas außen vor gelassen, da es hier unterschiedliche Alternativen zum JavaEE Weg gibt (OAuth2.0 bspw., wird von google, twitter, facebook, xing, linkedin verwendet…). Hierzu werde ich das nächste mal etwas mehr erzählen.

Generell sind REST Services Zustandslos (Stateless), weshalb hier in der Regel etwas anders verfahren wird als bei einer normalen Webanwendung (hier wird das oft einfach über das Cockie mit der jSessionID gesteuert). Bei einem Stateless Server sollte man die Authentifizierung jedesmal mit geben.

Wir werden einige Zugriffe auf unsere Applikation machen – ob wir allerdings eine saubere Authentifizierung in der Zeit hinbekommen kann ich jetzt noch nicht versprechen…