Compare commits

..

16 Commits

Author SHA1 Message Date
0451f187f5 uebung2/break-lines 2026-04-25 00:08:04 +02:00
fb9df23db7 uebung2/add persintance xml 2026-04-24 00:15:49 +02:00
db2e755fcb uebung2 2026-04-24 00:11:43 +02:00
96e34686a7 update build command 2026-04-24 00:11:17 +02:00
5c2fe4303f configure hibernate in-memory db 2026-04-24 00:10:49 +02:00
b930f460c8 fix uebung-1.tex imports 2026-04-23 23:45:00 +02:00
a7ecd6f3ab refactor flake 2026-04-20 20:01:16 +02:00
23342a1bf5 cleanup 2026-04-20 08:53:11 +02:00
5b4e30baaa praktikum1/aufgabe3 2026-04-17 11:08:20 +02:00
9edd9ebaeb praktikum1/aufgabe2 2026-04-17 10:39:40 +02:00
b6de6840d3 praktikum1/aufgabe1 2026-04-17 10:23:25 +02:00
32f7cd07d9 refactoring 2026-04-17 10:04:51 +02:00
2c5feb25f6 replace 'web-engineering' with 'componentware' 2026-04-17 00:33:45 +02:00
948671d63a delete package config 2026-04-17 00:31:56 +02:00
4fbd462714 fix 2026-04-17 00:11:06 +02:00
d4502eb762 update sem 2026-04-17 00:11:02 +02:00
41 changed files with 691 additions and 4210 deletions

4
bin/build Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
mvn clean install
mvn clean package

8
bin/deploy Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# deploy the server
#
# usage:
# deploy server/target/ejb-server-1.0-SNAPSHOT.jar
cp -v "$1" "$WILDFLY_BASE_DIR/deployments/"

6
bin/run Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
# usage
# run org.example.demo.uebung1.aufgabe16.Client
(cd client && mvn clean compile && mvn exec:java -Dexec.mainClass="$1")

8
bin/start Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# starts the server
#
# usage:
# start
wildfly-fhs

37
client/pom.xml Normal file
View File

@@ -0,0 +1,37 @@
<?xml version="1.0"?>
<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>
<parent>
<groupId>de.componentware</groupId>
<artifactId>componentware-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>ejb-client</artifactId>
<packaging>jar</packaging>
<dependencies>
<!-- Abhängigkeit zu den EJB-Interfaces des Server-Moduls -->
<dependency>
<groupId>de.componentware</groupId>
<artifactId>ejb-server</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- BOM für alle WildFly EJB-Client Abhängigkeiten -->
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-ejb-client-bom</artifactId>
<version>39.0.0.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,22 @@
package org.example.demo.praktikum1.aufgabe1;
import javax.naming.InitialContext;
import javax.naming.Context;
import java.util.Properties;
public class Client {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.wildfly.naming.client.WildFlyInitialContextFactory");
props.setProperty(Context.PROVIDER_URL, "http-remoting://localhost:8080");
InitialContext ctx = new InitialContext(props);
String jndiName = "ejb:/ejb-server-1.0-SNAPSHOT/Calculator!org.example.demo.praktikum1.aufgabe1.CalculatorRemote";
var calc = (CalculatorRemote) ctx.lookup(jndiName);
System.out.println("6 + 7 = " + calc.addiere(6, 7));
System.out.println("6 - 7 = " + calc.subtrahiere(6, 7));
System.out.println("6 * 7 = " + calc.multipliziere(6, 7));
System.out.println("6 / 7 = " + calc.dividiere(6, 7));
}
}

View File

@@ -0,0 +1,26 @@
package org.example.demo.praktikum1.aufgabe2;
import javax.naming.InitialContext;
import javax.naming.Context;
import java.util.Properties;
public class Client {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.wildfly.naming.client.WildFlyInitialContextFactory");
props.setProperty(Context.PROVIDER_URL, "http-remoting://localhost:8080");
InitialContext ctx = new InitialContext(props);
String jndiName = "ejb:/ejb-server-1.0-SNAPSHOT/StatefulCalculator!org.example.demo.praktikum1.aufgabe2.StatefulCalculatorRemote";
var calc = (StatefulCalculatorRemote) ctx.lookup(jndiName);
System.out.println("6 + 7 = " + calc.addiere(6, 7));
System.out.println("6 + 7 + 8 = " + calc.addiere(8));
System.out.println("6 - 7 = " + calc.subtrahiere(6, 7));
System.out.println("6 - 7 - 8 = " + calc.subtrahiere(8));
System.out.println("6 * 7 = " + calc.multipliziere(6, 7));
System.out.println("6 * 7 * 8 = " + calc.multipliziere(8));
System.out.println("6 / 7 = " + calc.dividiere(6, 7));
System.out.println("6 / 7 / 8 = " + calc.dividiere(8));
}
}

View File

@@ -0,0 +1,53 @@
package org.example.demo.praktikum1.aufgabe3;
import javax.naming.InitialContext;
import javax.naming.Context;
import java.util.Properties;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.wildfly.naming.client.WildFlyInitialContextFactory");
props.setProperty(Context.PROVIDER_URL, "http-remoting://localhost:8080");
InitialContext ctx = new InitialContext(props);
String jndiName = "ejb:/ejb-server-1.0-SNAPSHOT/GuessingGame!org.example.demo.praktikum1.aufgabe3.GuessingGameRemote";
var game = (GuessingGameRemote) ctx.lookup(jndiName);
var scanner = new Scanner(System.in);
var another = true;
while (another) {
playRound(game, scanner);
// todo: input exception handling
System.out.print("Do you want to play another? ");
another = scanner.nextBoolean();
}
scanner.close();
}
private static void playRound(GuessingGameRemote game, Scanner scanner) {
game.init();
GuessResult result;
do {
// todo: input exception handling
System.out.print("Guess a number from 1-100: ");
var guess = scanner.nextInt();
result = game.testGuess(guess);
switch (result) {
case Success:
System.out.println("Correct! The number was "+ guess);
break;
case TooBig:
System.out.println("Your guess was too big!");
break;
case TooSmall:
System.out.println("Your guess was too small!");
break;
}
}
while (result != GuessResult.Success);
}
}

View File

@@ -11,8 +11,8 @@ public class Client {
props.setProperty(Context.PROVIDER_URL, "http-remoting://localhost:8080");
InitialContext ctx = new InitialContext(props);
EncryptorRemote encryptor = (EncryptorRemote) ctx.lookup(
"ejb:/IhrProjektname/Encryptor!encryption.EncryptorRemote");
String jndiName = "ejb:/ejb-server-1.0-SNAPSHOT/Encryptor!org.example.demo.uebung1.aufgabe16.EncryptorRemote";
EncryptorRemote encryptor = (EncryptorRemote) ctx.lookup(jndiName);
String original = "Hallo Welt";
String encrypted = encryptor.encrypt(original);

View File

@@ -3,7 +3,7 @@ import javax.naming.InitialContext;
import javax.naming.Context;
import java.util.Properties;
public class CounterClient {
public class Client {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
@@ -11,8 +11,8 @@ public class CounterClient {
props.setProperty(Context.PROVIDER_URL, "http-remoting://localhost:8080");
InitialContext ctx = new InitialContext(props);
CounterRemote counter = (CounterRemote) ctx.lookup(
"ejb:/IhrProjektname/Counter!counter.CounterRemote?stateful");
String jndiName = "ejb:/ejb-server-1.0-SNAPSHOT/Counter!org.example.demo.uebung1.aufgabe17.CounterRemote?stateful";
CounterRemote counter = (CounterRemote) ctx.lookup(jndiName);
System.out.println(counter.getAndIncrement());
System.out.println(counter.getAndIncrement());

View File

@@ -0,0 +1,33 @@
package org.example.demo.uebung2.aufgabe22;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.example.demo.uebung2.aufgabe21.Mitarbeiter;
public class Client {
public static void main(String[] args) {
try {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
props.setProperty(Context.PROVIDER_URL, "http-remoting://localhost:8080");
InitialContext ctx = new InitialContext(props);
String jndiName = "ejb:/ejb-server-1.0-SNAPSHOT/MitarbeiterService!org.example.demo.uebung2.aufgabe22.MitarbeiterServiceRemote";
MitarbeiterServiceRemote service = (MitarbeiterServiceRemote) ctx.lookup(jndiName);
Mitarbeiter m = new Mitarbeiter("Max Mustermann", 12345);
int generierteId = service.speichereMitarbeiter(m);
System.out.println("Mitarbeiter gespeichert mit ID: " + generierteId);
System.out.println("Entity nach dem Speichern: " + m);
} catch (NamingException e) {
e.printStackTrace();
}
}
}

View File

@@ -99,19 +99,19 @@
\item \textbf{Erstellen Sie eine Stateless Session Bean, die eine Methode zur Verschlüsselung eines Strings bereitstellt.}
\textbf{Remote-Interface:} \inputminted{java}{../../src/main/java/org/example/demo/uebung1/aufgabe16/EncryptorRemote.java}
\textbf{Remote-Interface:} \inputminted{java}{../../server/src/main/java/org/example/demo/uebung1/aufgabe16/EncryptorRemote.java}
\textbf{Bean-Klasse:} \inputminted{java}{../../src/main/java/org/example/demo/uebung1/aufgabe16/Encryptor.java}
\textbf{Bean-Klasse:} \inputminted{java}{../../server/src/main/java/org/example/demo/uebung1/aufgabe16/Encryptor.java}
\textbf{Standalone-Client:} \inputminted{java}{../../src/main/java/org/example/demo/uebung1/aufgabe16/Client.java}
\textbf{Standalone-Client:} \inputminted{java}{../../client/src/main/java/org/example/demo/uebung1/aufgabe16/Client.java}
\item \textbf{Erstellen Sie eine Stateful Session Bean, die einen Zähler zur Verfügung stellt.}
\textbf{Remote-Interface:} \inputminted{java}{../../src/main/java/org/example/demo/uebung1/aufgabe17/CounterRemote.java}
\textbf{Remote-Interface:} \inputminted{java}{../../server/src/main/java/org/example/demo/uebung1/aufgabe17/CounterRemote.java}
\textbf{Bean-Klasse:} \inputminted{java}{../../src/main/java/org/example/demo/uebung1/aufgabe17/Counter.java}
\textbf{Bean-Klasse:} \inputminted{java}{../../server/src/main/java/org/example/demo/uebung1/aufgabe17/Counter.java}
\textbf{Client (mehrfache Aufrufe auf derselben Instanz):} \inputminted{java}{../../src/main/java/org/example/demo/uebung1/aufgabe17/CounterClient.java}
\textbf{Client (mehrfache Aufrufe auf derselben Instanz):} \inputminted{java}{../../client/src/main/java/org/example/demo/uebung1/aufgabe17/Client.java}
\item \textbf{Warum liefert die get-Methode aus Aufgabe 17 bei einem erneuten Aufruf der Testklasse immer wieder den Startwert des Zählers?}

151
docs/uebungen/uebung-2.tex Normal file
View File

@@ -0,0 +1,151 @@
\documentclass{uebung}
\author{Linus Nagel}
\chapter{2}
\begin{document}
\maketitle
\begin{exercises}
\item \textbf{Was ist eine Entity?}
Eine Entity ist das Java-Pendant zu einem Datensatz aus der Datenbank. Es handelt sich um ein POJO (Plain Old Java Object), das mit der Annotation \texttt{@Entity} ausgezeichnet wird. Entities repräsentieren die Geschäftsobjekte bzw. die Daten einer Anwendung.
\item \textbf{Wie wird eine Entity erstellt und welche Inhalte enthält eine Entity üblicherweise?}
Eine Entity wird erstellt, indem eine gewöhnliche Java-Klasse mit \texttt{@Entity} annotiert wird. Üblicherweise enthält sie:
\begin{itemize}
\item Attribute (z.B. eine ID als Primärschlüssel, fachliche Daten)
\item einen parameterlosen Konstruktor (zwingend)
\item Getter und Setter für die Attribute
\item Implementierung von \texttt{Serializable}
\item optional \texttt{toString()}, \texttt{hashCode()}, \texttt{equals()}
\end{itemize}
\item \textbf{Durch welche Annotation wird ein Attribut als Primärschlüssel gekennzeichnet?}
Mit \texttt{@Id}. Zusätzlich kann \texttt{@GeneratedValue} verwendet werden, um die automatische Generierung des Primärschlüssels zu ermöglichen.
\item \textbf{Was ist ein EntityManager?}
Der EntityManager ist die zentrale Schnittstelle der JPA für Datenbankoperationen. Er stellt Methoden zum Speichern, Suchen, Löschen und Bearbeiten von Entities bereit und synchronisiert diese mit der Datenbank.
\item \textbf{Wie kann eine Klasse ein EntityManager-Objekt auslesen/erhalten?}
Eine Klasse kann den EntityManager über Dependency Injection mittels der Annotation \texttt{@PersistenceContext} erhalten:
\begin{minted}[breaklines]{java}
@PersistenceContext
private EntityManager em;
\end{minted}
Alternativ ist ein JNDI-Lookup möglich.
\item \textbf{Welche Methode des EntityManagers wird verwendet um ein Objekt in der Datenbank anzulegen?}
Die Methode \texttt{persist(Object entity)}. Beispiel: \texttt{em.persist(person);}
\item \textbf{Was ist eine Persistence Unit und welche Datei wird verwendet um eine Persistence Unit zu definieren?}
Eine Persistence Unit legt fest, welche Entities auf welche Weise (O/R-Mapping) auf die Datenbank abgebildet werden. Sie wird in der Datei \texttt{persistence.xml} im Ordner \texttt{META-INF} definiert.
\item \textbf{Welche Zustände existieren im Lebenszyklus einer Entity?}
Die Zustände sind:
\begin{itemize}
\item \textbf{New (transient):} Entity neu erzeugt, noch nicht mit Persistenzkontext verbunden.
\item \textbf{Managed:} Entity wird vom Persistenzkontext verwaltet, Änderungen werden automatisch nachverfolgt.
\item \textbf{Detached:} Entity nicht mehr im Persistenzkontext (z.B. nach Übergabe an den Client).
\item \textbf{Removed:} Entity wurde zum Löschen markiert.
\end{itemize}
\item \textbf{Welchen Zustand hat eine Entity, die an einen Client übergeben wurde?}
Sie befindet sich im Zustand \textbf{detached}.
\item \textbf{Wie kann eine Entity, die an den Client übergeben wurde, wieder in den Zustand managed überführt werden?}
Durch Aufruf der Methode \texttt{merge(entity)} des EntityManagers:
\begin{minted}[breaklines]{java}
person = em.merge(person);
\end{minted}
Oder durch erneutes Laden mit \texttt{find(...)}.
\item \textbf{Welche Rückgabe hat die Methode merge(…) und warum ist eine Rückgabe notwendig?}
\texttt{merge(entity)} gibt eine verwaltete Instanz der Entity zurück. Die Rückgabe ist notwendig, weil die übergebene detached Entity nicht selbst zum managed Zustand wird, sondern der Persistenzkontext eine (möglicherweise andere) verwaltete Instanz liefert. Daher muss das Ergebnis der Variablen zugewiesen werden.
\item \textbf{Worum handelt es sich beim Lazy loading?}
Lazy Loading bezeichnet das verzögerte Laden von Attributen oder Assoziationen einer Entity erst dann, wenn sie tatsächlich verwendet werden. Es wird z.B. mit \texttt{@Basic(fetch=FetchType.LAZY)} oder \texttt{@OneToMany(fetch=FetchType.LAZY)} gesteuert und verbessert die Performance, da nicht alle Daten sofort aus der Datenbank geladen werden.
\item \textbf{Welche Möglichkeiten gibt es um mittels O/R-Mapping Vererbung auf Tabellen abzubilden? Beschreiben Sie diese Strategien grob.}
Es gibt drei Strategien, gesteuert durch \texttt{@Inheritance(strategy=...)}:
\begin{itemize}
\item \textbf{Single Table:} Die gesamte Vererbungshierarchie wird in einer Tabelle abgebildet. Eine Diskriminatorspalte (z.B. \texttt{DTYPE}) speichert den konkreten Typ. Vorteil: einfach, Nachteil: viele leere (\texttt{null}) Spalten.
\item \textbf{Table per Class:} Für jede Entity (auch abstrakte) wird eine eigene Tabelle erzeugt, die alle Attribute der jeweiligen Klasse enthält. Vorteil: keine leeren Spalten, Nachteil: aufwendige Abfragen bei Polymorphie.
\item \textbf{Joined:} Jede Klasse bekommt eine Tabelle. Die Tabellen der Unterklassen enthalten nur die zusätzlichen Attribute sowie eine Fremdschlüsselspalte auf die Tabelle der Oberklasse. Daten werden per Join zusammengesetzt. Vorteil: keine Redundanz, Nachteil: viele Joins bei tiefen Hierarchien.
\end{itemize}
\item \textbf{Mit welcher Annotation wird eine 1:1-Beziehung abgebildet?}
Mit \texttt{@OneToOne} auf beiden Seiten der Beziehung.
\item \textbf{Was ist die „owning side“ einer 1:1-Beziehung und wie kann sie festgelegt werden?}
Die \textit{owning side} (führende Seite) ist diejenige Seite, die den Fremdschlüssel in der Datenbank erhält. Sie wird festgelegt, indem auf der anderen Seite das Attribut \texttt{mappedBy} gesetzt wird:
\begin{minted}[breaklines]{java}
@OneToOne(mappedBy="auto")
private Lenkrad lenkrad;
\end{minted}
Die Klasse ohne \texttt{mappedBy} ist die owning side.
\item \textbf{Welche Annotation erhält eine 1:n-Beziehung?}
Die Annotation \texttt{@OneToMany} auf der Seite des Elternobjekts (z.B. \texttt{Fahrer} hat viele \texttt{Fahrt}).
\item \textbf{Welche Annotation erhält eine n:1-Beziehung?}
Die Annotation \texttt{@ManyToOne} auf der Seite des Kindobjekts (z.B. \texttt{Fahrt} referenziert einen \texttt{Fahrer}).
\item \textbf{Welche ist in einer 1:n- oder n:1-Beziehung die owning side?}
In einer 1:n- / n:1-Beziehung ist die \textbf{n:1-Seite} (die Seite mit \texttt{@ManyToOne}) immer die owning side. Sie erhält den Fremdschlüssel in der Datenbank. Auf der anderen Seite (1:n) verwendet man \texttt{@OneToMany(mappedBy=...)}.
\item \textbf{Wie wird eine m:n-Beziehung annotiert?}
Auf beiden Seiten wird \texttt{@ManyToMany} verwendet. Eine Seite muss \texttt{mappedBy} angeben, die andere ist die owning side. Es wird automatisch eine Relationstabelle generiert.
\item \textbf{Wie kann eine Anfrage in JPQL erzeugt werden in der alle Objekte einer Klasse Auto abgefragt werden? Bitte geben Sie beispielhaft den Quellcode an.}
\begin{minted}[breaklines]{java}
TypedQuery<Auto> query = em.createQuery("SELECT a FROM Auto a", Auto.class);
List<Auto> autos = query.getResultList();
\end{minted}
Oder kurz:
\begin{minted}[breaklines]{java}
List<Auto> autos = em.createQuery("SELECT a FROM Auto a", Auto.class).getResultList();
\end{minted}
\item \textbf{Erstellen Sie eine Entity namens Mitarbeiter, die die fachlichen Attribute name (String) und personalnummer (int) enthält.}
\noindent
\inputminted[breaklines]{java}{../../server/src/main/java/org/example/demo/uebung2/aufgabe21/Mitarbeiter.java}
\item \textbf{Erstellen Sie eine Stateless Session Bean, die eine Methode bereitstellt, die als Parameter ein Objekt der Klasse Mitarbeiter (aus Aufgabe 21) übergeben bekommt. Dieses Objekt soll durch die Methode in der Datenbank gespeichert werden. Die dabei generierte ID soll von der Methode zurückgeliefert werden. Testen Sie ihre Klassen durch einen geeigneten Client über das Remote Interface.}
\textbf{Remote-Interface:}
\inputminted[breaklines]{java}{../../server/src/main/java/org/example/demo/uebung2/aufgabe22/MitarbeiterServiceRemote.java}
\textbf{Stateless Session Bean:}
\inputminted[breaklines]{java}{../../server/src/main/java/org/example/demo/uebung2/aufgabe22/MitarbeiterService.java}
\textbf{Standalone-Client:}
\inputminted[breaklines]{java}{../../client/src/main/java/org/example/demo/uebung2/aufgabe22/Client.java}
\textbf{persistence.xml:}
\inputminted[breaklines]{xml}{../../server/src/main/resources/META-INF/persistence.xml}
\end{exercises}
\end{document}

View File

@@ -1,5 +1,5 @@
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{uebung}[Sem3 Web Engineering Exercise Sheet Class]
\ProvidesClass{uebung}[Sem4 Componentware Exercise Sheet Class]
% Base class with options
\LoadClass[11pt,a4paper]{article}
@@ -60,14 +60,14 @@
% Header and footer setup
\pagestyle{fancy}
\fancyhf{}
\fancyhead[L]{\textbf{Übung Web-Engineering}}
\fancyhead[L]{\textbf{Übung Componentware}}
\fancyhead[R]{\textbf{Aufgabenblatt zu Kapitel \thechapter}}
\fancyfoot[C]{\thepage}
% Title format
\renewcommand{\maketitle}{
\begin{center}
\LARGE\textbf{Übung Web-Engineering}\\
\LARGE\textbf{Übung Componentware}\\
\Large\textbf{Aufgabenblatt zu Kapitel \thechapter}
\vspace{1cm}
@@ -136,7 +136,7 @@
linkcolor=blue,
filecolor=magenta,
urlcolor=cyan,
pdftitle={Web Engineering Übungen},
pdftitle={Componentware Übungen},
pdfauthor={Linus Nagel}
}

67
flake.lock generated
View File

@@ -18,35 +18,36 @@
"type": "github"
}
},
"nixpkgs": {
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib_2"
},
"locked": {
"lastModified": 1762844143,
"narHash": "sha256-SlybxLZ1/e4T2lb1czEtWVzDCVSTvk9WLwGhmxFmBxI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9da7f1cf7f8a6e2a7cb3001b048546c92a8258b4",
"lastModified": 1775087534,
"narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9da7f1cf7f8a6e2a7cb3001b048546c92a8258b4",
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"nixpkgs-angular-cli": {
"nixpkgs": {
"locked": {
"lastModified": 1764947035,
"narHash": "sha256-EYHSjVM4Ox4lvCXUMiKKs2vETUSL5mx+J2FfutM7T9w=",
"lastModified": 1776705249,
"narHash": "sha256-3cg0CfzLLq2ay8SzAoNbI2OJkWY1H3kudrzA6hL14FM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a672be65651c80d3f592a89b3945466584a22069",
"rev": "cc3f2ee0b3909e42334f34720ccac109a7e67068",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a672be65651c80d3f592a89b3945466584a22069",
"type": "github"
}
},
@@ -65,11 +66,47 @@
"type": "github"
}
},
"nixpkgs-lib_2": {
"locked": {
"lastModified": 1774748309,
"narHash": "sha256-+U7gF3qxzwD5TZuANzZPeJTZRHS29OFQgkQ2kiTJBIQ=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "333c4e0545a6da976206c74db8773a1645b5870a",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"root": {
"inputs": {
"flake-parts": "flake-parts",
"nixpkgs": "nixpkgs",
"nixpkgs-angular-cli": "nixpkgs-angular-cli"
"wildfly": "wildfly"
}
},
"wildfly": {
"inputs": {
"flake-parts": "flake-parts_2",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1776706386,
"narHash": "sha256-en72yqmDrm20Q+W0COp9I+Lc4j8NdeqKuGmYuZeD/yQ=",
"owner": "0qln",
"repo": "wildfly",
"rev": "87fdb70a9877ee697790f8e2edfda4bd3091616b",
"type": "github"
},
"original": {
"owner": "0qln",
"repo": "wildfly",
"type": "github"
}
}
},

View File

@@ -1,24 +1,20 @@
{
description = "Web Engineering";
description = "Componentware";
inputs = {
flake-parts.url = "github:hercules-ci/flake-parts";
nixpkgs.url = "github:NixOS/nixpkgs/9da7f1cf7f8a6e2a7cb3001b048546c92a8258b4";
nixpkgs-angular-cli.url = "github:NixOS/nixpkgs/a672be65651c80d3f592a89b3945466584a22069";
nixpkgs.url = "github:NixOS/nixpkgs";
wildfly = {
url = "github:0qln/wildfly";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = inputs @ {
flake-parts,
self,
...
}:
outputs = inputs @ {flake-parts, ...}:
flake-parts.lib.mkFlake {inherit inputs;} {
imports = [];
systems = ["x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin"];
perSystem = {
config,
self',
inputs',
pkgs,
system,
...
@@ -51,40 +47,7 @@
]))
];
wildfly = pkgs.stdenvNoCC.mkDerivation {
name = "wildfly-39.0.0.Final";
src = pkgs.fetchzip {
url = "https://github.com/wildfly/wildfly/releases/download/39.0.0.Final/wildfly-39.0.0.Final.zip";
hash = "sha256-nfdb4doRRn4AwMQZkNYwIDBKIq4iY6diFX/WlPFQqZI=";
};
installPhase = ''
mkdir -p $out
cp -r $src/* $out/
'';
};
wildfly-fhs = pkgs.buildFHSEnv {
name = "wildfly-fhs";
targetPkgs = pkgs:
with pkgs; [
openjdk21
bash
coreutils
];
runScript = "${wildfly}/bin/standalone.sh";
profile =
# bash
''
export WILDFLY_BASE_DIR="$HOME/.wildfly-fhs-base"
mkdir -p "$WILDFLY_BASE_DIR"/{log,data,deployments,tmp,configuration}
if [ ! -f "$WILDFLY_BASE_DIR/configuration/standalone.xml" ]; then
cp -r ${wildfly}/standalone/configuration/* "$WILDFLY_BASE_DIR/configuration/"
chmod -R u+w "$WILDFLY_BASE_DIR/configuration/"
fi
export JBOSS_HOME=${wildfly}
export JBOSS_BASE_DIR="$WILDFLY_BASE_DIR"
'';
};
wildfly-fhs = inputs.wildfly.packages.${system}.wildfly-fhs;
in {
# Per-system attributes can be defined here. The self' and inputs'
# module parameters provide easy access to attributes of the same
@@ -92,7 +55,7 @@
packages = with pkgs; let
fmtNum = strings.fixedWidthNumber 2;
fmtReleaseName = sem: author: chap: "${fmtNum sem} - ${fmtNum chap} - ${author.lastName}, ${author.firstName}.pdf";
fmtRelease = fmtReleaseName 3 {
fmtRelease = fmtReleaseName 4 {
firstName = "Linus";
lastName = "Nagel";
};
@@ -125,17 +88,17 @@
// args;
in {
"uebung-1" = mkUebungPdf 1 {};
"uebung-2" = mkUebungPdf 2 {};
};
devShells.default = with pkgs;
mkShell {
buildInputs = [wildfly-fhs pkgs.openjdk21];
buildInputs = [wildfly-fhs pkgs.openjdk21 maven];
nativeBuildInputs = [];
packages =
[
mermaid-cli
openjdk
jetty
maven
]
++ latexPackages;
@@ -143,21 +106,8 @@
shellHook =
# bash
''
export PATH="bin/:$PATH"
export WILDFLY_BASE_DIR="$HOME/.wildfly-fhs-base"
build() {
# builds target/demo.war
mvn clean package
}
# e.g. 'deploy target/demo.war'
deploy() {
cp -v "$1" "$WILDFLY_BASE_DIR/deployments/"
}
start() {
wildfly-fhs
}
'';
};
};

4035
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +0,0 @@
{
"dependencies": {
"@angular/cli": "^21.0.2",
"@angular/core": "^21.0.3"
}
}

81
pom.xml Executable file → Normal file
View File

@@ -1,76 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<?xml version="1.0"?>
<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>org.example</groupId>
<artifactId>demo</artifactId>
<groupId>de.componentware</groupId>
<artifactId>componentware-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<name>demo</name>
<packaging>war</packaging>
<packaging>pom</packaging>
<modules>
<module>server</module>
<module>client</module>
</modules>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.report.sourceEncoding>UTF-8</project.report.sourceEncoding>
<maven.compiler.release>21</maven.compiler.release>
<junit.version>5.11.0-M2</junit.version>
<compiler-plugin.version>3.13.0</compiler-plugin.version>
<war-plugin.version>3.4.0</war-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>11.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.faces</artifactId>
<version>4.1.3</version>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-el-api</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet-core</artifactId>
<version>5.1.2.Final</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>15.0.3</version>
<classifier>jakarta</classifier>
</dependency>
</dependencies>
<build>
<finalName>demo</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${war-plugin.version}</version>
</plugin>
</plugins>
</build>
</project>

33
server/pom.xml Executable file
View File

@@ -0,0 +1,33 @@
<?xml version="1.0"?>
<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>
<parent>
<groupId>de.componentware</groupId>
<artifactId>componentware-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>ejb-server</artifactId>
<packaging>ejb</packaging>
<dependencies>
<!-- Jakarta EE 10 API (wird von WildFly bereitgestellt) -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>10.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<ejbVersion>4.0</ejbVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,19 @@
package org.example.demo.praktikum1.aufgabe1;
import jakarta.ejb.Stateless;
@Stateless
public class Calculator implements CalculatorRemote {
public double addiere(float zahl1, float zahl2) {
return zahl1 + zahl2;
}
public double subtrahiere(float zahl1, float zahl2) {
return zahl1 - zahl2;
}
public double multipliziere(float zahl1, float zahl2) {
return zahl1 * zahl2;
}
public double dividiere(float zahl1, float zahl2) {
// todo: division by 0 exception?
return zahl1 / zahl2;
}
}

View File

@@ -0,0 +1,10 @@
package org.example.demo.praktikum1.aufgabe1;
import jakarta.ejb.Remote;
@Remote
public interface CalculatorRemote {
double addiere(float zahl1, float zahl2);
double subtrahiere(float zahl1, float zahl2);
double multipliziere(float zahl1, float zahl2);
double dividiere(float zahl1, float zahl2);
}

View File

@@ -0,0 +1,35 @@
package org.example.demo.praktikum1.aufgabe2;
import org.example.demo.praktikum1.aufgabe1.Calculator;
import jakarta.ejb.Stateful;
@Stateful
public class StatefulCalculator implements StatefulCalculatorRemote {
private double state;
public double addiere(float zahl1, float zahl2) {
return state = new Calculator().addiere(zahl1, zahl2);
}
public double subtrahiere(float zahl1, float zahl2) {
return state = new Calculator().subtrahiere(zahl1, zahl2);
}
public double multipliziere(float zahl1, float zahl2) {
return state = new Calculator().multipliziere(zahl1, zahl2);
}
public double dividiere(float zahl1, float zahl2) {
return state = new Calculator().dividiere(zahl1, zahl2);
}
public double addiere(float zahl) {
return state = new Calculator().addiere((float)state, zahl);
}
public double subtrahiere(float zahl) {
return state = new Calculator().subtrahiere((float)state, zahl);
}
public double multipliziere(float zahl) {
return state = new Calculator().multipliziere((float)state, zahl);
}
public double dividiere(float zahl) {
return state = new Calculator().dividiere((float)state, zahl);
}
}

View File

@@ -0,0 +1,15 @@
package org.example.demo.praktikum1.aufgabe2;
import jakarta.ejb.Remote;
@Remote
public interface StatefulCalculatorRemote {
double addiere(float zahl1, float zahl2);
double subtrahiere(float zahl1, float zahl2);
double multipliziere(float zahl1, float zahl2);
double dividiere(float zahl1, float zahl2);
double addiere(float zahl);
double subtrahiere(float zahl);
double multipliziere(float zahl);
double dividiere(float zahl);
}

View File

@@ -0,0 +1,7 @@
package org.example.demo.praktikum1.aufgabe3;
public enum GuessResult {
TooSmall,
TooBig,
Success,
}

View File

@@ -0,0 +1,25 @@
package org.example.demo.praktikum1.aufgabe3;
import java.util.Random;
import jakarta.ejb.Stateful;
@Stateful
public class GuessingGame implements GuessingGameRemote {
private int num;
public void init() {
var rng = new Random();
num = 1 + rng.nextInt(0, 100);
}
public GuessResult testGuess(int guess) {
if (guess < num) {
return GuessResult.TooSmall;
}
if (guess > num) {
return GuessResult.TooBig;
}
return GuessResult.Success;
}
}

View File

@@ -0,0 +1,11 @@
package org.example.demo.praktikum1.aufgabe3;
import jakarta.ejb.Remote;
@Remote
public interface GuessingGameRemote {
// start ein spiel, generiere ein zufallszahl.
void init();
// test whether the guess is correct.
GuessResult testGuess(int guess);
}

View File

@@ -0,0 +1,56 @@
package org.example.demo.uebung2.aufgabe21;
import jakarta.persistence.*;
import java.io.Serializable;
@Entity
public class Mitarbeiter implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private int personalnummer;
public Mitarbeiter() {
}
public Mitarbeiter(String name, int personalnummer) {
this.name = name;
this.personalnummer = personalnummer;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPersonalnummer() {
return personalnummer;
}
public void setPersonalnummer(int personalnummer) {
this.personalnummer = personalnummer;
}
@Override
public String toString() {
return "Mitarbeiter{" +
"id=" + id +
", name='" + name + '\'' +
", personalnummer=" + personalnummer +
'}';
}
}

View File

@@ -0,0 +1,20 @@
package org.example.demo.uebung2.aufgabe22;
import org.example.demo.uebung2.aufgabe21.Mitarbeiter;
import jakarta.ejb.Stateless;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
@Stateless
public class MitarbeiterService implements MitarbeiterServiceRemote {
@PersistenceContext
private EntityManager em;
@Override
public int speichereMitarbeiter(Mitarbeiter m) {
em.persist(m);
return m.getId();
}
}

View File

@@ -0,0 +1,10 @@
package org.example.demo.uebung2.aufgabe22;
import org.example.demo.uebung2.aufgabe21.Mitarbeiter;
import jakarta.ejb.Remote;
@Remote
public interface MitarbeiterServiceRemote {
int speichereMitarbeiter(Mitarbeiter m);
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_2.xsd" version="3.2">
<persistence-unit name="default">
<jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
<properties>
<property name="jakarta.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>
</persistence>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_2.xsd"
version="3.2">
<persistence-unit name="default">
</persistence-unit>
</persistence>