# Herausforderungen mit JSF



## xentity (17. Mrz 2020)

Hallo liebe Javaner,

ich habe eine Applikation, die auf folgende Dinge setzt:

JSF 2.2
Java 11
Wildfly 14 als Application Server (vorrangig weil ich CDI nutze und damit fällt der Tomcat raus, TomEE habe ich nicht hinbekommen)
MySQL/MariaDB
Hibernate/JPA 2.1, managed JTA-DataSource vom Wildfly
Meine Schwierigkeiten sind:

Ich benötige leider zwei persistence units (eine als JTA und eine als RESOURCE_LOCAL, die von RunnableClasses genutzt werden), die Datenbank ist aber die gleiche. Ich finde das sehr unschön...
Änderungen direkt in der Datenbank werden von Hibernate nicht (immer) erkannt. Mitunter muss die Applikation neugestartet werden, damit die Änderungen im Web zu sehen sind.
Wildfly erstellt sehr viele Threads, wenn diese Application deployed ist, dabei ist noch nicht viel darauf los. Ist das in meinem Setup normal oder wie könnte ich das Troubleshooten?
Hat jemand von euch schon einmal diese Probleme gehabt?


----------



## mihe7 (17. Mrz 2020)

xentity hat gesagt.:


> Änderungen direkt in der Datenbank werden von Hibernate nicht (immer) erkannt. Mitunter muss die Applikation neugestartet werden, damit die Änderungen im Web zu sehen sind.


Cache. Second-Level-Cache abschalten und/oder in der Anwendung 

```
Cache cache = em.getEntityManagerFactory().getCache();
        cache.evictAll();
```
aufrufen - kannst Du z. B. einfach mittels JAX-RS deployen und dann von extern nach einer Änderung aufrufen.



xentity hat gesagt.:


> Wildfly erstellt sehr viele Threads, wenn diese Application deployed ist, dabei ist noch nicht viel darauf los. Ist das in meinem Setup normal oder wie könnte ich das Troubleshooten?


Schau Dir mal mit jvisualvm an, um welche Art von Threads es sich überhaupt handelt.


----------



## Flown (17. Mrz 2020)

xentity hat gesagt.:


> Ich benötige leider zwei persistence units (eine als JTA und eine als RESOURCE_LOCAL, die von RunnableClasses genutzt werden), die Datenbank ist aber die gleiche. Ich finde das sehr unschön...


ich hab noch sehr wenig use cases gesehen, wo man in einem container umfeld resource_local benötigt. Kannst du das mal etwas erläutern?


xentity hat gesagt.:


> Änderungen direkt in der Datenbank werden von Hibernate nicht (immer) erkannt. Mitunter muss die Applikation neugestartet werden, damit die Änderungen im Web zu sehen sind.


Kommt jetzt drauf an. Du musst dann deine Entities anders laden und öfters mal #refresh auf Entities anwenden.


xentity hat gesagt.:


> Wildfly erstellt sehr viele Threads, wenn diese Application deployed ist, dabei ist noch nicht viel darauf los. Ist das in meinem Setup normal oder wie könnte ich das Troubleshooten?


Es gibt schon vorgewärmte reservierte Threads in den Threadpools, die nur auf Runnables warten. Nur weil sie da sind, heißt das nicht, dass sie auch Resourcen verbrauchen.


----------



## xentity (17. Mrz 2020)

mihe7 hat gesagt.:


> Cache. Second-Level-Cache abschalten und/oder in der Anwendung



Danke, schaue ich mir an.



mihe7 hat gesagt.:


> Schau Dir mal mit jvisualvm an, um welche Art von Threads es sich überhaupt handelt.



OK, ich schau mal, wie ich das zum Fliegen bekomme. Viele Beispiele beziehen sich auf Windows sowie das Tool und den Server auf einem System. Ich gebe Rückmeldung.


----------



## xentity (17. Mrz 2020)

Flown hat gesagt.:


> ich hab noch sehr wenig use cases gesehen, wo man in einem container umfeld resource_local benötigt. Kannst du das mal etwas erläutern?



Da die Applikation auch Nutzer-unabhängige Aktionen durchführt und ich keinen komfortablen Weg gefunden habe, von außen einen HTTP-Request auf JSF abzufeuern (zudem fand ich den Umstand ohne externen Trigger auszukommen sehr charmant), habe ich einen Runnable implementiert:


```
@Named
@RequestScoped
public class Cronjob implements Runnable {
    private EntityManager em;

    public Cronjob() {
        this.em = Persistence.createEntityManagerFactory("RLPU").createEntityManager();
    }

    public void Runner() {
        try {
            this.Demand();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
    
    private void Demand() {
        this.em.getTransaction().begin();
        this.em.createNativeQuery("...").executeUpdate();
        this.em.getTransaction().commit();
    }
}
```

Die Klasse wird von einem *java.util.concurrent.ScheduledExecutorService* alle 60 Minuten aufgerufen. Meine JTA DataSource heißt nur "PU", die konnte ich hier jedoch nicht nehmen, sondern musste eine Resource_Local verwenden, daher "RLPU". Es funktioniert, aber ich habe das Gefühl, das ist alles andere als elegant und bin für Alternativen für einen Crondienst offen.


----------



## thecain (17. Mrz 2020)

Ein Timer Bean


----------



## mihe7 (17. Mrz 2020)

xentity hat gesagt.:


> Da die Applikation auch Nutzer-unabhängige Aktionen durchführt und ich keinen komfortablen Weg gefunden habe, von außen einen HTTP-Request auf JSF abzufeuern (zudem fand ich den Umstand ohne externen Trigger auszukommen sehr charmant), habe ich einen Runnable implementiert:




```
@Singleton
class Whatever {
    @PersistenceContext
    private EntityManager em;

    @Schedule(hour="*/1", minute="0", second="0", persistent=false)
    public void doSomethingEveryHour() {
        // mach was mit em
    }
}
```
könnte funktionieren.


----------



## Flown (17. Mrz 2020)

xentity hat gesagt.:


> Da die Applikation auch Nutzer-unabhängige Aktionen durchführt und ich keinen komfortablen Weg gefunden habe, von außen einen HTTP-Request auf JSF abzufeuern (zudem fand ich den Umstand ohne externen Trigger auszukommen sehr charmant), habe ich einen Runnable implementiert:


du kannst ja eine jax-rs schnittstelle bieten genau für solche Sachen. JSF ist ja nur ein View-Layer. Die Business Logik passiert hier nicht.


----------



## xentity (18. Mrz 2020)

mihe7 hat gesagt.:


> ```
> @Singleton
> class Whatever {
> @PersistenceContext
> ...



Das war früher auch mein Ansatz und funktioniert auch mit allerhand Dingen, ABER wenn ich den Code auf @Schedule umstelle, bekomme ich das hier
`A JTA EntityManager cannot use getTransaction()` auf Grund solcher Zeilen:

```
this.em.getTransaction().begin();
this.em.persist(lt);
this.em.getTransaction().commit();
```

Ich hatte einiges mit UserTransactions wie auch in den normalen Named Beans versucht, aber das war eher try'n'error. Vor allem error. Mit dem RESOURCE_LOCAL konnte ich zumindest Transactions verwenden.


----------



## xentity (18. Mrz 2020)

Flown hat gesagt.:


> du kannst ja eine jax-rs schnittstelle bieten genau für solche Sachen. JSF ist ja nur ein View-Layer. Die Business Logik passiert hier nicht.



Muss gestehen, dass ich bislang noch keine Berührungspunkte mit JAX-RS hatte :-/ Die Business Logik habe ich komplett in den Named Beans.


----------



## mihe7 (19. Mrz 2020)

xentity hat gesagt.:


> Das war früher auch mein Ansatz und funktioniert auch mit allerhand Dingen, ABER wenn ich den Code auf @Schedule umstelle, bekomme ich das hier
> `A JTA EntityManager cannot use getTransaction()` auf Grund solcher Zeilen:
> ...
> Ich hatte einiges mit UserTransactions wie auch in den normalen Named Beans versucht, aber das war eher try'n'error. Vor allem error. Mit dem RESOURCE_LOCAL konnte ich zumindest Transactions verwenden.


Ja, RESOURCE_LOCAL brauchst Du hier nicht. Die Klasse Whatever ist eine EJB. Der EJB-Container kümmert sich standardmäßig um die Transaktionsverwaltung, d. h. beim Aufruf der Methode wird sichergestellt, dass diese in einer Transaktion abläuft, die durch den EJB-Container auch wieder abgeschlossen wird. Wenn die Verwaltung der Transaktion dagegen von der EJB durchgeführt werden soll, kannst Du das per @TransactionManagement(TransactionManagementType.BEAN) annotieren.

Bei CDI-Beans (z. B. @Named) verhält es sich andersrum: dort findet im Normalfall keine Transaktionsverwaltung statt. Man kann durch entsprechende Annotationen eine solche in CDI-Beans einführen, wobei ich aber keine Vorteile gegenüber EJBs erkennen kann. Wenn sowieso ein EJB-Container zur Verfügung steht, sehe ich keinen Sinn darin, auf die Transaktionsverwaltung von EJBs zu verzichten.


----------



## Flown (19. Mrz 2020)

xentity hat gesagt.:


> Muss gestehen, dass ich bislang noch keine Berührungspunkte mit JAX-RS hatte :-/ Die Business Logik habe ich komplett in den Named Beans.


Ist kein Problem. Just another Bean. Du kannst dir das in die JAX-RS Schnittstelle injecten lassen und auch die Sachen ausführen lassen. Wobei Service zu schreiben hier sauberer wären (wenn die EJBs mit Transkationsverwatlung wären).


----------



## xentity (19. Mrz 2020)

mihe7 hat gesagt.:


> Der EJB-Container kümmert sich standardmäßig um die Transaktionsverwaltung, d. h. beim Aufruf der Methode wird sichergestellt, dass diese in einer Transaktion abläuft, die durch den EJB-Container auch wieder abgeschlossen wird.



Heißt also, wenn ich den Code beispielhaft in einer EJB so ändere:

```
//this.em.getTransaction().begin();
this.em.persist(lt);
this.em.persist(car);
this.em.persist(driver);
//this.em.getTransaction().commit();
```

wird sichergestellt, dass alle drei Objekte via Hibernate/JPA persistiert werden?

(Notiz an mich: JAX-RS und EJB-Konzept lernen)


----------



## mihe7 (19. Mrz 2020)

xentity hat gesagt.:


> wird sichergestellt, dass alle drei Objekte via Hibernate/JPA persistiert werden?


Exakt.


----------



## xentity (27. Mrz 2020)

Meine erste Rückmeldung nach einer gewissen Zeit: Seitdem ich die zweite PU entfernt habe (Pkt. 1), ist auch die Threat Usage des Wildfly extrem gering (Pkt. 3). Sehr geil  

Das habe ich zum Anlass genommen, den Wildfly auf einen aktuellen Stand zu hieven. Dabei konnte ich nun auch keine Cache-Probleme (Pkt. 2) mehr feststellen. Weiß jetzt nur dummerweise nicht, ob die Beseitigung von 1 sich auf Pkt. 2 ausgewirkt hat oder ob der aktuelle Wildfly einen besseren Cache hat. Auf jeden Fall habe ich mir dokumentiert, was ich tun muss, falls ich nochmal ein Thema damit habe.

Ich danke euch!


----------

