Enterprise Java

Fő kategória: Java.

Áttekintés

Ha egy tipikus vállalati program Java program elér egy bizonyos méretet, akkor szinte törvényszerű, hogy az alábbi problémák nagy többségébe belefutunk:

  • többszálúság, ill. leginkább az ezzel kapcsolatos problémák orvoslása,
  • skálázhatóság, magyarán az, hogy kis és nagy igénybevétel mellett is megbízhatóan működjön a rendszer,
  • perzisztencia, azaz az adatok tartós tárolása, ill. az ezzel kapcsolatos problémák kezelése (pl. kapcsolódás az adatbázishoz, a Java objektumok relációs adattáblákra való leképezése stb.),
  • tranzakció kezelés, tehát mikor történjen commit ill. rollback, és mi történjen mondjuk ez rollback esetén,
  • távoli elérés, ill. általánosabban megfogalmazva bármiféle kommunikáció két távoli rendszer között, az ezzel kapcsolatos problémák kezelése,
  • névszolgáltatás, azaz az erőforrások kezelése, a lekérdezés biztosítása,
  • üzenetkezelés, ami az üzenetek küldését és fogadását is jelenti, általában többféle módon,
  • biztonság, tehát annak a biztosítása, hogy illetéktelenek ne férhessenek hozzá az adatokhoz
  • és a sort még hosszan lehetne sorolni.

Az Enterprise Java (magyarul kb. nagyvállalati Java) ezekre a problémákra nyújt megoldást. Az elkészített program nem önmagában fut, hanem egy futtató környezetben, amely kezeli a fenti problémákat, vagy teljesen elfedve azt a fejlesztő elől (pl. a többszálúsággal kapcsolatos problémák kezelése), vagy arra a minimumra csökkentve a szükséges kódot, amit feltétlenül muszáj megadni (pl. az adatbázis kapcsolat felépítéséhez többnyire elég megadni az alap elérési adatokat, és mondjuk a kapcsolat létrehozásának a részleteivel általában nem kell törődnie a programozónak).

Szerintem nem egyértelmű a határ a Standard és az Enterprise Java között. Szigorú értelemben az Enterprise Java nem más mint egy specifikáció halmaz, amelyet a Java Community Process gondoz, és megtalálható a https://www.jcp.org oldalon. E szerint tehát az Enterprise Java az, ami megfelel a specifikációknak (ill. annak egy részének). Kevésbé szigorú értelemben viszont (szerintem) ide lehet sorolni mindazt, amely a fenti problémákra (vagy azok egy részére) igyekszik megoldást találni mégpedig úgy, hogy a program nem önmagában fut, hanem egy keretrendszerben. Ezen az oldalon e tágabb értelmezést használom, sőt, ide gyűjtöm azokat a rendszereket is, melyek önálló alkalmazásokként futnak, és interfészt nyújtanak a tőlük függetlenül futó Java alkalmazások felé.

Az Enterprise Java közös jellemzője tehát az, hogy a program nem önmagában fut, hanem bele kell tenni egy "konténerbe" és a futtató rendszer futtatja. Itt tipikusan nem a public static void main(String[] args) függvény indul el, hanem a belépési pont a konténertől (és egyéb eseményektől) függ. Klasszikusan kétféle konténert különböztetünk meg: a web konténert és az EJB konténert, és ez alapján különböztetjük meg a webszervereket és alkalmazás szervereket.

Webalkalmazások

Áttekintés

A klasszikus web szerverek az alap webes technológiákat szolgálják ki: tipikusan HTML oldalakat (amelyek mögött esetleg lehet PHP) tudunk segítségével letölteni. Talán a legelterjedtebb ilyen rendszer az Apache HTTPD (https://httpd.apache.org/). Ennek a részleteibe itt nem megyünk bele.

Számunkra ebben a témában érdekesebbek azok a web szerverek, amelyek a Java Servlet specifikációt is megvalósítják. Ez technikailag azt jelenti, hogy Java webalkalmazásokat tudunk készíteni, melynek a kiterjesztése .war, amit egy meghatározott könyvtárba másolva tudunk futtatni.

Javaslom, hogy a példákat az Apache Tomcat webszerverrel próbáljuk ki. Ehhez töltsük le a webszervert a http://tomcat.apache.org/ oldalról. Én a 9.0.29-es verziót használom, zip formában töltöttem le, és a c:\programs\apache-tomcat-9.0.29\ könyvtárba csomagoltam ki. Használat:

  • A war fájlt a webapps könyvtárba kell másolni.
  • Indítás: bin/startup.bat

Futás közben a webalkalmazás kicsomagolódik a nevének megfelelő könyvtárba. Az alapértelmezett port a 8080. Ha pl. a webalkalmazás neve example.war, akkor a http://localhost:8080/example/ alatt értjük el azt. Ha felülírjuk a war fájtl, akkor elvileg automatikusan megtörténik a kicsomagolás, bár ha biztosra szeretnénk menni, akkor érdemes előtte magát a könyvtára letörölni.

Fejlesztés során célszerű a kedvenc fejlesztőkörnyezetünkben beállítani a Tomcatet. Pl. Eclipse-ben a következőképpen tudjuk ezt megtenni: View → Show View → Other… → Server → Servers → jobb kattintás → New → Server. Itt felül válasszuk ki a verziót (pl. Tomcat v9.0 Server), majd adjuk meg a pontos elérési útvonalat. Programokat a következőképpen tudunk hozzáadni: jobb kattintás a megfelelő szerver példányon → Add and Remove… → ott bal oldalon találjuk a webalkalmazásokat, amelyeket nyilakkal tudjuk átmozgatni jobbra. A Servers fülön elindíthatjuk normál és hibakereső (debug) módban is; ez utóbbi esetben debuggolni tudjuk a programunkat úgy, hogy az az alkalmazásszerverben fut.

Egy fontos művelet az hogy mikor történjen az eredmény publikálása (publish). Az alapértelmezett beállítás az automatikus, ami azt jelenti, hogy bármely kis változtatás maga után vonja a publikálást. Ez kis programok esetén kétségkívül hasznos, ha viszont a program egyre nagyobbá válik, és pl. egy publikálás mondjuk egy jelentősebb adatbázis lekérdezést vált ki, akkor megfontolandó az automatikus publikálás kikapcsolása. Ezt a következőképpen tudjuk megtenni: dupla kattintás a webszerver nevén → Publishing → Never publish automatically. Ez esetben a publikálásról a fejlesztőnek kell gondoskodnia, amit a következőképpen tud megtenni: jobb kattintás a webszerveren: Publish.

Egy klasszikus servlet web alkalmazás

A web alkalmazások készítésénél a következőkre kell figyelni:

  • A csomagolás (packaging) war kell, hogy legyen, az alapértelmezett jar helyett.
  • Fordítás során szükségünk van a következő függőségre: javax.servlet % javax.servlet-api % 4.0.0.
  • Ahhoz, hogy minél egyszerűbb legyen az elérése, érdemes gondoskodni arról, hogy ne legyen benne az eredményben verziószám.
  • A szerkesztést a maven-war-plugin beépülő segítségével kell végrehajtanunk.

Példaként készítsük el a következő pom.xml fájlt:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>hu.faragocsaba</groupId>
    <artifactId>webapp</artifactId>
    <version>1.0</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.1</version>
            </plugin>
        </plugins>
    </build>
</project>

A web.xml a webalkalmazások központi eleme: itt adhatjuk meg, hogy hogyan fusson. Ennek a helye: src/main/webapp/WEB-INF/web.xml. Példaként hozzuk létre az alábbi tartalommal.

<?xml version="1.0" encoding="UTF-8"?> 
<web-app> 
    <servlet> 
         <servlet-name>Greet</servlet-name> 
         <servlet-class>hu.faragocsaba.webapp.GreetServlet</servlet-class> 
    </servlet> 
    <servlet-mapping> 
         <servlet-name>Greet</servlet-name> 
         <url-pattern>/greet</url-pattern> 
    </servlet-mapping> 
</web-app>

Ezze két dolgot deklaráltunk:

  • A belépési pont a hu.faragocsaba.webapp.GreetServlet osztály.
  • A böngészőből a greet URL-en érhetjük el.

A forrás a következő (src/main/java/hu/faragocsaba/webapp/GreetServlet.java):

package hu.faragocsaba.webapp;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class GreetServlet extends HttpServlet {
    @Override
    public void init() {
        System.out.println("GreetServlet initialized");
    }

    @Override
    public void destroy() {
        System.out.println("GreetServlet destroyed");
    }

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("GreetServlet.doGet() called.");
        PrintWriter out = response.getWriter();
        out.println("Hello world!");
    }
}

A servlet a HttpServlet osztályból származik. Itt alapvetően két dolgot adhatunk meg:

  • Milyen kód fusson le betöltéskor (init()) ill. a végén (destroy). Ezek egyébként nem kötelező elemek, kihagyhatjuk.
  • Mi hajtódjon végre adott művelet hatására, pl. doGet() egy HTTP GET kérés esetén.

Tegyük a következőt:

  • Fordítsuk le hagyományosan a mvn clean install segítségével.
  • Az eredmény ez: target/webapp.war. A fájlt magát másoljuk be a Tomcat webapps könyvtárába (az én esetemben tehát létrejön egy c:\programs\apache-tomcat-9.0.29\webapps\webapp.war fájl).
  • Indítsuk el a Tomcat webalkalmazást (pl. c:\programs\apache-tomcat-9.0.29\bin\startup.bat).
  • A böngészőbe írjuk be a megfelelő URL-t, jelen esetben a következőt: http://localhost:8080/webapp/greet. Ha mindent jól csináltunk, akkor megjelenik a Hello world! felirat.

Servlet annotációval

Az xml konfigurálást sokan nem szeretik, igazából én sem; ha van választási lehetőségem, akkor ugyanazt szívesen készítem el kódban. A 6-os Java verziótól kezdve lehetőség van webalkalmazást web.xml nélkül, annotációk segítségével létrehozni. A fenti példa átírása web.xml nélkülire a következőképpen történik: a pom.xml maradjon meg, a web.xml fájlt töröljük ki, a GreetServlet-ben pedig az osztályt pedig lássuk el a következő annotációval:

@WebServlet(name = "GreetServlet", urlPatterns = "/greet")
public class GreetServlet extends HttpServlet {
    ...

HTTP GET paraméterek lekérdezése

A HttpServletRequest tartalmazza a kérés minden részletét: az URL paramétereket, a HTTP fejléc (header) információkat, a sütiket (cookie) stb. Ebben a lépésben HTML-t adunk vissza. Folytassuk a fenti példát! Módosítsuk a doGet() függvényt az alábbi módon:

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html><body><h1>");
        String name = request.getParameter("name");
        out.println("Hello, " + name + "!");
        out.println("</h></body></html>");
    }

A válasz típusát HTML-re állítjuk, és lekérdezzük a name paraméter értékét. Nyissuk meg a következő oldalt: http://localhost:8080/webappget/httpgetexample?name=Csaba. Ha mindent jól csináltunk, akkor megjelenik nagy vastag betűkkel a "Hello, Csaba!" felirat. Ha megnyitjuk az oldal forrását (tipikusan Ctrl+U), a következőt látjuk:

<html><body><h1>
Hello, Csaba!
</h></body></html>

Egy HTTP POST példa

Most nézzük meg, hogy hogyan működik a HTTP POST! A fenti példát folytatjuk. A forrásban mindössze a doGet függvényt kell átírni erre: doPost, ugyanis a request.getParameter() függvényt kell használnunk a GET és a POST esetben is. Tehát a következő legyen a GreetServlet.java-ban:

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ...
    }

POST üzenetet tipikusan HTML formok segítségével tudunk létrehozni. Hozzuk létre az src/main/webapp/index.html fájtl az alábbi tartalommal:

<html><body><form name="greetForm" action="greet" method="POST">
Your name: <input type="text" name="name"><input type="submit" value="Submit">
</form></body></html>

A fent leírtak szerint fordítsuk és telepítsük a programot. Töltsük be egy böngésző segítségével a http://localhost:8080/webapp/ oldalt (mivel a html fájl neve index.html automatikusan azt fogja betölteni). Ha mindent jól csináltunk, egy formanyomtatványt látunk, ahova beírhatjuk a nevünket, és ha megnyomjuk a Submit gombot, akkor üdvözöl minket.

JSP példa

A JSP a Java Server Pages rövidítése. Ez valójában HTML-be ágyazott Java. A https://www.ntu.edu.sg/home/ehchua/programming/java/JSPByExample.html oldal segített nekem gyorsan és hatékonyan átismételni a lényeget.

Lássunk egy példát! A Tomcat webapps könyvtárába hozzunk létre egy alkönyvtárat (pl. jsp), azon belül pedig egy .jsp kiterjesztésű fájlt (pl. add.jps). A példában tehát (nálam) a fájl teljes elérési útvonala ez: c:\programs\apache-tomcat-9.0.29\webapps\jsp\add.jsp, a tartalma pedig legyen a következő:

<html><body>
<%= 2+3 %>
</body></html>

Láthatjuk, hogy ez egy (többé-kevésbé) szabályos HTML kód, viszont tartalmaz egy <%= … %> részt. Oda került a Java kód. Ha elindítjuk a Tomcatet és betöltjük a http://localhost:8080/jsp/add.jsp oldalt, akkor eredményül ezt kapjuk: 5. A háttérben viszont a JSP-ből servlet generálódott, jelen esetben a következő: c:\programs\apache-tomcat-9.0.29\work\Catalina\localhost\jsp\org\apache\jsp\add_jsp.java. Ennek a számunkra lényeges része a következő:

      out.write("<html><body>\r\n");
      out.print( 2+3 );
      out.write("\r\n");
      out.write("</body></html>\r\n");

Ezen az egyszerű példán valószínűleg nem látszik, de az első letöltés mindig lassúbb mint a későbbiek, ugyanis ekkor generálódik le a Java kód, ill. fordul is le, ld. a .java melletti .class-t.

A JSP-ben a szokásos HTML tag-eken túl az alábbiakat használhatjuk:

  • <%= … %>: ide Java kifejezéseket írhatunk, ami egy out.print(…); metódus paramétere lesz. A fenti példa is ezt a formát használja.
  • <% … %>: ide Java kódot írhatunk.
  • <%@ page|include … %>: Java direktívákat írhatunk ide.
  • <%— … —>: JSP megjegyzések.

A JSP definiál néhány objektumot, melyek közül a legfontosabbak:

  • request: HTTP kérés.
  • response: HTTP válasz.
  • out: a HTTP válasz kimenete.
  • stb.

Az alábbi példán keresztül láthatjuk ezek használatát, melyet a fenti módon tudunk beüzemelni:

<%@ page contentType="text/html" %>
<%@ page import="java.util.*" %>
<html><body>
Server: <%= request.getServerName() %>
<br>
Fruits:
<ul>
  <%
    List<String> fruits = Arrays.asList("apple", "orange", "banana");
    for (String fruit: fruits) {
  %>
  <%-- Prints the fruits one by one. --%>
  <li><%= fruit %>
  <%
    }
  %>
</ul>
</body></html>

Webalkalmazást is készíthetünk, ill. inkább az a tipikus: a kód tartalmaz egyszerre Java kódot és JSP-t is. Írjuk át a fenti, üdvözlő példát tisztán JSP-re!

  • pom.xml: hagyjuk meg úgy, ahogy van.
  • web.xml: erre most nincs szükség.
  • Java kód: erre sincs szükség.
  • src/main/webapps/index.jsp: ez igazából maradhatna index.html is, mivel nincs benne JSP kód, de a példa legyen teljesen JSP. A fenti index.html-hez képest egyetlen dolgot kell átírnunk: az action="greet" helyére ezt kell írni: action="greet.jsp". A teljes forrás:
<html><body><form name="greetForm" action="greet.jsp" method="POST">
Your name: <input type="text" name="name"><input type="submit" value="Submit">
</form></body></html>
  • src/main/webapps/greet.jsp: ide írjuk a fenti doPost()-ban megvalósított logikát:
<html><body><h1>
Hello, <%= request.getParameter("name") %>!
</h1></body></html>

Szűrők

Angolul filter.
TODO

Figyelők

Angolul listener.
TODO

Modell - nézet - vezérlő

Web alkalmazás könyvtárak

TODO: ZKoss

Embedded Jetty

Egységtesztelés

EJB alkalmazások

TODO: különbség a webszerverek és alkalmazásszerverek között

TODO: Java EE

Session Beans

Konténer vezérelt perzisztencia

Spring

Apache Servicemix

Apache ActiveMQ

Apache Camel

Apache CXF

Apache Karaf

TODO: OSGi

https://www.baeldung.com/osgi

Adobe Enterprise Manager

Java Content Repository

TODO: Apache Jackrabbit, Adobe CRX

OSGi

Apache Sling

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License