BookStore 1.0 Enterprise Application, GitExt, Gradle, JBoss, Log4j Óbudai Egyetem, Java Enterprise Edition Műszaki Informatika szak Labor 2 Bedők Dávid 2016.09.30. v1.1
Struktúra I
2
Struktúra II
3
Egyszerűsített könyvesbolt Feladat: hozzunk létre egy alkalmazást, mely egy könyvesbolt könyveinek kezelésére alkalmas (CRUD műveletek). Alkalmazandó technikák: ● Java Enterprise Edition 6 ● Servlet API 3.0.1 ○ Java EE 6 → 3.0.x ○ Java EE 7 → 3.1
● JBoss 6.4 4
Ismeretszerzés ● Gradle projekt hierarchia létrehozása ● Git folytatás ● Enterprise JavaBean (ejb) alapok mint “business layer” ● Egyszerű servlet mint “weblayer” ● Mockolt adatok mint “persistence layer”
5
Enterprise Gradle project Több projekt, hierarchiába szervezve ● Weblayer ○ gradle java és war plugin → war ○ EAR web module-ja
● EJBService ○ gradle java plugin → jar ○ EAR ejb module-ja
● Root project ○ gradle ear plugin → ear
6
WAR - Web application ARchive META-INF/ MANIFEST.MF WEB-INF/ classes/ hu/ qwaevisz/ demo/ Lorem.class Ipsum.class lib/ dummy.jar web.xml index.html public resources logo.jpg base.css
web.xml <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/java ee" xmlns:xsi="http://www.w3.org/2001/XMLS chema-instance" xsi:schemaLocation="http://java.sun.co m/xml/ns/javaee http://java.sun.com/xml/ns/javaee/webapp_3_0.xsd"> ... web application deployment descriptor
7
EAR - Enterprise ARchive META-INF/ MANIFEST.MF application.xml lib/ dummy.jar (3rd party) library ejb module xzy.jar abc.war web module
application.xml
sample <module> <ejb>xzy.jar <module> <web> <web-uri> abc.war abcwebapp lib
8
Könyvtárak és build file-ok bookstore/ bs-ejbservice/ src/ main/ java/ build.gradle bs-weblayer/ src/ main/ java/ build.gradle build.gradle settings.gradle 9
Root EAR project apply plugin: 'eclipse' apply plugin: 'ear'
bookstore\build.gradle dependency configuration (ear plugin): deploy és earlib
dependencies { project(‘[NAME]’) deploy project('bs-ejbservice') deploy project(path: 'bs-weblayer', configuration: 'archives') } bookstore\settings.gradle
include 'bs-ejbservice' include 'bs-weblayer'
>gradle ear 10
EJB Service subproject apply plugin: 'eclipse'
bookstore\bs-ejbservice\build.gradle
apply plugin: 'java' repositories { mavenCentral() }
jar { archiveName 'bs-ejbservice.jar' }
pontosan ez az alapértelmezés is, így elhagyható
dependencies { compile group: 'javax', name:'javaee-api', version:'6.0' } 11
Web Layer subproject apply plugin: 'eclipse'
bookstore\bs-weblayer\build.gradle
apply plugin: 'java' apply plugin: 'war' repositories { mavenCentral() } war { archiveName 'bs-weblayer.war' } dependencies {
dependency configuration (war plugin): providedCompile (kell a fordításhoz, de adja a container) és providedRuntime (adja a container) Használható a ‘java’ plugin compile dc-je is: kell a fordításhoz, és nem adja a container, ezért belekerül a “WEB-INF/lib”-be.
providedCompile project(':bs-ejbservice') providedCompile group: 'javax.servlet', name:'javax.servlet-api', version:'3.0.1'
>gradle war
providedCompile group: 'javax', name:'javaee-api', version:'6.0' }
A “:” jelentése egy project neve előtt azt jelzi, hogy a project-el a root project-től kiindulva kell keresni (absolute elérés lesz, nem pedig relative).
12
Repository BookStore with Gradle GIT
\jboss\bookstore-light
>gradle clean build
DE! Vannak lokális változásaink, miközben az origin/master (branch) szintén változott! Megjegyzés: a gradle build-je ear plugin esetén ear-t, war plugin esetén war-t, java plugin esetén compile-t fog futtatni 13
Git alapok Working copy kiválasztása (root könyvtárban) >git checkout .
Lokális módosítások eldobása >git reset --hard
Új állományok/könyvtárak eldobása >git clean -fd
Változások leszedése a master-ről >git pull
14
GitExtensions http://gitextensions.github.io/ https://github.com/gitextensions Grafikus felületet biztosít a Git parancsok végrehajtásához A Git használat nem lineáris, és ugyanaz a feladat többféleképpen is megoldható. Minden külső eszköz használata e végett magában foglal némi kockázatot (nem biztos hogy a tool azt hajtja végre, amit mi szeretnénk). Alapfunkciók esetén szinte kockázatmentes.
15
Enterprise JavaBeans ● ● ● ●
Szerveroldali üzleti komponensek (back-end services) JSR19, JSR152, JSR220, JSR318, JSR345 IBM (1997), majd Sun Microsystems (1999) Egyfajta “best-practice” annak érdekében, hogy az üzleti értéket “kelljen” csak fejleszteni, ne a “tipikus” keret dolgokat ○ ○ ○ ○ ○ ○
●
Tranzakciókezelés Konkurenciakezelés Aszinkron metódushívás Eseménykezelés Java Message Service integráció (Message Driven Beans) Perzisztencia integráció támogatása (de már nem része a persistence az EJB specifikációnak)
EJB1: minden “remote” EJB2: nagyon “kényelmetlen”, túlbonyolított EJB3: a Spring framework és a Hibernate tapasztalai alapján újraalkotott elképzelés (POJO-kat dolgozik mint Spring FW, és szakít az entity bean-ekkel, és inkább csak támogatja a perzisztens réteget, nem megvalósítja.
16
EJB Típusok ● Session Beans ○ Stateless SB (állapotmentes) SLSB ○ Stateful SB (állapottartó) SFSB ■ Aktiválás/Passziválás (szerializálhatóság fontos) ●
N kliens K db bean probléma esetére, ha N > K
○ Singleton SB (“egyke”) SSB
● Message Driven Beans (üzenetvezérelt) MDB ○ Elsősorban aszinkron feldolgozás ○ Nincs kliens interface
● Entity Beans ○ Deprecated, EJB 3.X-től a JPA helyettesíti 17
Business Layer Definiáljunk néhány üzleti metódust! ● BookStub getBook ( String isbn ) ● List
getBooks ( BookCriteria criteria )
Definiáljuk a hozzájuk szükséges DTO-kat ● BookStub ○ isbn (String), author (String), title (String), category (BookCategoryStub), price (double), numberOfPages (int) ● BookCriteria ○ author (String), title (String), minPrice (int), maxPrice (int) ISBN: International Standard Book Number
18
Domain osztályok létrehozása I package hu.qwaevisz.bookstrore.ejbservice.domain;
BookCategoryStub
public enum BookCategoryStub { SCIFI, LITERATURE, HISTORICAL; } package hu.qwaevisz.bookstore.ejbservice.domain;
BookStub
public class BookStub { private String isbn; private String author; private String title; private BookCategoryStub category; private double price; private int numberOfPages; ... }
19
Domain osztályok létrehozása II BookCriteria package hu.qwaevisz.bookstore.ejbservice.domain; public class BookCriteria { private String author; private String title; private BookCategoryStub category; private int minimumPrice; private int maximumPrice; ... } 20
Stateless Session Bean Local interface BookFacade package hu.qwaevisz.bookstore.ejbservice.facade; import java.util.List; import javax.ejb.Local; import hu.qwaevisz.bookstore.ejbservice.domain.BookCriteriaStub; import hu.qwaevisz.bookstore.ejbservice.domain.BookStub; @Local public interface BookFacade {
@Remote: költséges és lassú (hálózati hívás, serializáció), RMI, eredeti koncepció csak ezt támogatta, különböző JVM-ek között használjuk @Local: olcsó és gyors, azonos JVM-en belül
BookStub getBook(String isbn); List getBooks(BookCriteria criteria); } 21
Stateless Session Bean Implementation BookFacadeImpl import hu.qwaevisz.bookstore.ejbservice.domain.BookStub; @Stateless(mappedName = "ejb/bookFacade") public class BookFacadeImpl implements BookFacade { @Override public BookStub getBook(String isbn) { return new BookStub(...);
@Stateless: Stateless Session Bean name: ejb neve, def: unqualified név mappedName: global JNDI név description: leírás
} @Override public List getBooks(BookCriteria criteria) { List stubs = new ArrayList<>(); stubs.add( new BookStub(...)); return stubs; } }
22
Servlet Tesztelési célból package hu.qwaevisz.bookstore.weblayer.servlet;
BookPingServlet
.. @WebServlet("/BookPing") public class BookPingServlet extends HttpServlet { @EJB private BookFacade facade; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { BookStub book = this.facade.getBook("978-0441172719"); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); out.println(book.toString()); out.close(); } } 23
Red Hat® JBoss® Middleware Enterprise Application Platform http://www.jboss.org/ Install (unzip) v7.0.0 (latest, 2016.05.10.) JEE 7 compliant v6.4.0 (latest, 2015.04.15.) JEE 6 compliant Commercial (!) Standalone/Domain mode Free: http://wildfly.org/ Content (https://access.redhat.com/articles/112673) ● ● ● ● ● ● ● ● ●
RESTEasy - 2.3.10.Final Hibernate Core - 4.2.18.Final Hibernate JPA 2.0 API - 1.0.1.Final JSF2 - 2.1.28.Final HornetQ - 2.3.25.Final (EAP 7.x → JBoss A-MQ) JBoss Logging - 3.1.4.GA JAXB - 2.2.5-redhat-9 Apache Web Server - 2.2.26 ...
24
JBoss - Standalone mode Start standalone (standalone.xml) >[JBOSSHOME]/bin/standalone.bat
Start standalone (custom.xml mint standalone.xml) >[JBOSSHOME]/bin/standalone.bat custom.xml
Stop standalone >[JBOSSHOME]/bin/jboss-cli.sh --connect command=:shutdown
Standalone ([JBOSSHOME]/standalone) ● ● ●
/configuration/standalone.xml /deployments /logs/server.log
25
Deploy [GIT]\oejee\jboss\bookstore\build\libs\bookstore.ear copy to: [JBOSS-HOME]\standalone\deployments\ server.log 13:07:06,946 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-3) JNDI bindings for session bean named BookFacadeImpl in deployment unit subdeployment "bs-ejbservice.jar" of deployment "bookstore.ear" are as follows:
java:global/bookstore/bs-ejbservice/BookFacadeImpl!hu.qwaevisz.ejbservice.facade.BookFacade java:app/bs-ejbservice/BookFacadeImpl!hu.qwaevisz.ejbservice.facade.BookFacade java:module/BookFacadeImpl!hu.qwaevisz.ejbservice.facade.BookFacade java:global/bookstore/bs-ejbservice/BookFacadeImpl java:app/bs-ejbservice/BookFacadeImpl java:module/BookFacadeImpl
13:07:06,975 INFO [org.jboss.web] (ServerService Thread Pool -- 196) JBAS018210: Register web context: /bs-weblayer 13:07:07,047 INFO [org.jboss.as.server] (DeploymentScanner-threads - 2) JBAS015859: Deployed "bookstore.ear" (runtime-name : "bookstore.ear")
26
Teszt http://localhost:8080/bs-weblayer/BookPing BookStub [isbn=978-0441172719, author=Frank Herbert, title=Dune, category=SCIFI, price=3500.0, numberOfPages=896]
27
Gradle Refactor (root project) Módosítás bookstore\build.gradle
ext { testngVersion = '6.9.+' jeeVersion = '6.0' servletapiVersion = '3.0.1' } subprojects { apply plugin: 'eclipse' apply plugin: 'java'
A subprojects{ … } blokk minden gyermek build script-re érvényes (merge), és létezik egy allprojects { … } blokk is, mely mind az aktuális (ez esetben a root), mind a gyermek scriptekre érvényes.
sourceCompatibility = 1.7 targetCompatibility = 1.7 repositories { mavenCentral() } dependencies { compile group: 'javax', name: 'javaee-api', version: jeeVersion testCompile group: 'org.testng', name: 'testng', version: testngVersion } }
28
Gradle Refactor (ejbservice project) Csere
bookstore\bs-ejbservice\build.gradle
jar { archiveName 'bs-ejbservice.jar' } Mivel ez az alapértelmezés, akár üres is lehetne ez a build file.
29
Gradle Refactor (weblayer project) Csere apply plugin: 'war'
bookstore\bs-weblayer\build.gradle
war { archiveName 'bs-weblayer.war' } dependencies { providedCompile project(':bs-ejbservice') providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: servletapiVersion }
30
Log4j http://logging.apache.org/log4j/2.x/ http://logging.apache.org/log4j/1.2/ Latest 2.x: Apache Log4j 2.3 (Log4j2) Latest 1.2: Apache Log4j 1.2.17 JBoss 6.4 egyelőre a Log4j 1.2-őt támogatja.
31
Log4J ● Loggers ○ Összerendeli a Java csomagot, a log level-t és az appendereket (1 logger N appender) ○ Egy ún. Root Logger mindig létezik.
● Appenders ○ Definiálja a log üzenet “pattern”-jét, a logolás típusát (pl. file, rolling file, e-mail, jms message, stb.) ● Standalone alkalmazás esetében log4j(2).xml vagy log4j(2).properties állományban konfiguráljuk ● Jboss esetében a Logging subsystem wrappeli, és
32
Log Levels ●
TRACE ○
●
DEBUG ○
●
Figyelmeztetés. Általában olyan esemény, mely azért nem hiba, mert az alkalmazás lekezeli valamilyen módon, vagy pl. a tranzakció végrehajtódik, de bizonyos korlátozásokkal.
ERROR ○
●
Azok az üzenetek, melyek minden esetben jelenjenek meg a logban. Külünösen fontos és semmiképpen sem gyakori események írhatóak ki ezen a szinten. Az Info szintű üzenetek kb. a “hahó, itt vagyok” típusúak, belőlük pl. hibát keresni, reprodukálni nem lehet.
WARN ○
●
Hibakeresési/fejlesztési szint. Végigkövetik a log üzenetek az üzleti folyamatokat komponens szinten. A Debug logok segítségével reprodukálható pl. a felhasználó tevékenysége.
INFO ○
●
Nagyon részletes adatok, csak kivételes esetben érdemes bekapcsolni (pl. ciklusmagok belsejének logjai)
Hiba. Olyan részletes leírást tartalmazzon, amennyire lehetséges. Ez lesz az az információ, amit a hibajegy javításakor birtokolni fogunk. Ez alapján kérni kell tudni a reprodukciót (mely során már kérhetünk debug logokat is).
FATAL ○
Ritkán alkalmazzuk. Végzetes hiba. Az ügyfelek már az Error esetén is üvöltenek, nem érdemes fatális hibákkal ijesztgetni őket. 33
Log4j és Gradle (root project) Módosítás ext {
bookstore\build.gradle
... log4jVersion = '1.2.17' } subprojects { ... dependencies { compile group: 'log4j', name: 'log4j', version: log4jVersion ... } }
34
Ping Servlet - INFO logolás Módosítás BookPingServlet.java public class BookPingServlet extends HttpServlet { ... private static final Logger LOGGER = Logger.getLogger(BookPingServlet. class); ... @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { LOGGER.info("Get Book by user"); ... } }
35
BookFacade - DEBUG logolás Módosítás public class BookFacadeImpl implements BookFacade {
BookFacadeImpl.java
private static final Logger LOGGER = Logger.getLogger(BookFacadeImpl.class); @Override public BookStub getBook(String isbn) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Get Book (isbn: " + isbn + ")"); } ... }
alternatív megoldás (kevesebb kódsor): LOGGER.debug(String.format("Get Book (isbn: %s)", isbn);
}
Fontos: production kódban a DEBUG üzenetek se a teljesítményt, se a memóriát ne terheljék, mivel valós futás közben általában a DEBUG szintet nem naplózzuk. A bemutatott megoldás egy logikai ellenőrzés költségű, míg az alternatív megoldás egy String literált elhelyez a permspace-en. A String összefűzés futását mindenképpen kerüljük el ilyen esetekben (ebből StringBuilder-t készt a fordító, de feleslegesen optimalizál ha nem naplózzuk).
36
JBoss Logging Subsystem standalone.xml áttekintés <server xmlns="urn:jboss:domain:1.7">
standalone.xml
<extensions> <extension module="org.jboss.as.logging"/> ... <management>... <profile> <subsystem xmlns="urn:jboss:domain:logging:1.5"> [APPENDERS DETAILS] [LOGGER DETAILS] ... ... <socket-binding-group>... 37
JBoss Logging Subsystem standalone.xml módosítás standalone.xml ... ... ...
38
Git - Commit, Push Állapot lekérdezése >git status
Stage >git add [FILENAME]
Commit
(-a/--all, -m/--message)
>git commit -a -m “[COMMIT_MESSAGE]”
Változások felküldése a master-re (authentication) >git push
39