Hilfe beim Quartz Scheduler

DaBe1812

Bekanntes Mitglied
Hallo zusammen,

wir hatten den Quartz schonmal zum Laufen gebracht, meine ich, aber das ist schon lange her und wegen Problemen beim CDI hatten wir ihn dann auch wieder abgeschaltet.

Jetzt hatten wir mal wieder Zeit, aber irgendwie klappt es nicht Jobs an zu legen.

Folgende Konfiguration
JavaEE Server WLP mit Java 11 und Jakarta Featureset.
Datenbankverbindungen sind im WLP konfiguriert und funktionieren im Rest der Anwendung einwandfrei.
persistence.xml:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<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_0.xsd" version="3.0">

    <persistence-unit name="atcdb" transaction-type="JTA">
        <jta-data-source>jdbc/atcDataSource</jta-data-source>
        <class>main.java.persistence.entities.DashboardConfig</class>
        <class>main.java.persistence.entities.ActiveObject</class>
        <class>main.java.persistence.entities.AmeiseAbrufDaten</class>
        <class>main.java.persistence.entities.AmeiseDBObject</class>
        <properties>
            <property name="eclipselink.cache.shared.default" value="false" />
        </properties>
    </persistence-unit>
</persistence>

quartz.properties
Code:
org.quartz.scheduler.instanceName=AtcScheduler
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=5
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreCMT
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate

org.quartz.jobStore.dataSource=cmtDS
org.quartz.dataSource.cmtDS.jndiURL=jdbc/atcDataSource

org.quartz.jobStore.nonManagedTXDataSource=nonManDS
org.quartz.dataSource.nonManDS.driver=oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.nonManDS.URL=URL
org.quartz.dataSource.nonManDS.user=USER
org.quartz.dataSource.nonManDS.password=PASSWORD
org.quartz.dataSource.nonManDS.maxConnections=30

org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.dontSetAutoCommitFalse=true
org.quartz.jobStore.useProperties=true

billige implementierung
Java:
package main.java.timer;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import static org.quartz.JobBuilder.*;
import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.ejb.DependsOn;
import jakarta.ejb.Singleton;
import jakarta.ejb.Startup;

@Startup
@Singleton
public class QuartzTimer {

    private final static Logger LOG = LogManager.getLogger(QuartzTimer.class);
    private static Scheduler scheduler;

    @PostConstruct
    public void init() {
        try {
            scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.start();

            // define the job and tie it to our HelloJob class
            JobDetail job = newJob(HelloJob.class).withIdentity("jobDBE", "groupDBE").build();

            // Trigger the job to run now, and then repeat every 40 seconds
            Trigger trigger = newTrigger().withIdentity("triggerDBE", "groupDBE").startNow()
                    .withSchedule(simpleSchedule().withIntervalInSeconds(40).repeatForever()).build();

            // Tell quartz to schedule the job using our trigger
            scheduler.scheduleJob(job, trigger);

        } catch (SchedulerException se) {
            LOG.error("Quartz Timer Exception beim Start:", se);
        }
    }
}

Fehlermeldung
Code:
[2023-06-09T15:43:33] [ERROR] [Default Executor-thread-6] main.java.timer.QuartzTimer:98 - Quartz Timer Exception beim Start:
org.quartz.JobPersistenceException: Couldn't store job: Driver's Blob representation is of an unsupported type: oracle.sql.BLOB
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeJob(JobStoreSupport.java:1123) ~[quartz-2.3.2.jar:?]
    at org.quartz.impl.jdbcjobstore.JobStoreSupport$2.executeVoid(JobStoreSupport.java:1067) ~[quartz-2.3.2.jar:?]
    at org.quartz.impl.jdbcjobstore.JobStoreSupport$VoidTransactionCallback.execute(JobStoreSupport.java:3780) ~[quartz-2.3.2.jar:?]
    at org.quartz.impl.jdbcjobstore.JobStoreSupport$VoidTransactionCallback.execute(JobStoreSupport.java:3778) ~[quartz-2.3.2.jar:?]
    at org.quartz.impl.jdbcjobstore.JobStoreCMT.executeInLock(JobStoreCMT.java:245) ~[quartz-2.3.2.jar:?]
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeJobAndTrigger(JobStoreSupport.java:1063) ~[quartz-2.3.2.jar:?]
    at org.quartz.core.QuartzScheduler.scheduleJob(QuartzScheduler.java:855) ~[quartz-2.3.2.jar:?]
    at org.quartz.impl.StdScheduler.scheduleJob(StdScheduler.java:249) ~[quartz-2.3.2.jar:?]
    at main.java.timer.QuartzTimer.init(QuartzTimer.java:44) [classes/:?]
    at jdk.internal.reflect.GeneratedMethodAccessor935.invoke(Unknown Source) ~[?:?]
    at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
    at com.ibm.ejs.container.interceptors.InterceptorProxy.invokeInterceptor(InterceptorProxy.java:200) [com.ibm.ws.ejbcontainer.jakarta_1.0.71.jar:?]
    at [internal classes]
    at jdk.internal.reflect.GeneratedMethodAccessor902.invoke(Unknown Source) ~[?:?]
    at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
    at com.ibm.ejs.container.interceptors.InterceptorProxy.invokeInterceptor(InterceptorProxy.java:189) [com.ibm.ws.ejbcontainer.jakarta_1.0.71.jar:?]
    at [internal classes]
    at org.jboss.weld.module.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:81) [io.openliberty.org.jboss.weld4_1.0.71.jar:4.0.3.Final]
    at com.ibm.ws.cdi.ejb.interceptor.WeldSessionBeanInterceptorWrapper.aroundInvoke(WeldSessionBeanInterceptorWrapper.java:58) [com.ibm.ws.cdi.2.0.ejb.jakarta_1.0.71.jar:?]
    at [internal classes]
    at jdk.internal.reflect.GeneratedMethodAccessor901.invoke(Unknown Source) ~[?:?]
    at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
    at com.ibm.ejs.container.interceptors.InterceptorProxy.invokeInterceptor(InterceptorProxy.java:189) [com.ibm.ws.ejbcontainer.jakarta_1.0.71.jar:?]
    at [internal classes]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
    at java.lang.Thread.run(Thread.java:836) [?:?]
Caused by: java.sql.SQLException: Driver's Blob representation is of an unsupported type: oracle.sql.BLOB
    at org.quartz.impl.jdbcjobstore.oracle.OracleDelegate.writeDataToBlob(OracleDelegate.java:597) ~[quartz-2.3.2.jar:?]
    at org.quartz.impl.jdbcjobstore.oracle.OracleDelegate.insertJobDetail(OracleDelegate.java:183) ~[quartz-2.3.2.jar:?]
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeJob(JobStoreSupport.java:1117) ~[quartz-2.3.2.jar:?]
    ... 51 more

Also Oracle-Treiber verwende ich im Classpath ojdbc8.jar. Oracle.sql.BLOB ist in der Klasse drin. Die häufigsten "Lösungen" die ich bisher gefunden habe, waren alle für andere App-Server.

Wenn ihr spontan keine Lösung für das Problem habt, aber das grundlegende Problem lösen könnt, bin ich gerne bereit etwas anderes zu versuchen.
Grundlegend war unser Problem, dass wir Timer mit @Schedule steuern. Das führt zu mehreren Problemen:
1. Wenn man einen Timer zu anderen Zeiten laufen lassen möchte, muss man neu deployen
2. Wenn man einen redundanten Server hat, dann werden bestimmte Jobs doppelt ausgeführt, d.h. wir bekommen viele Mails doppelt, weil eben zwei Server dasselbe tun.

Wenn ihr diese Probleme mit einer anderen Lösung anpacken könnt, dann gerne her damit. Ich bau gerne nochmal alles um, wenn es dann nur funktioniert.
 

DaBe1812

Bekanntes Mitglied
Moin,
die Idee kam mir auch schon, aber wenn der Name sich nicht irgendwann grundlegend geändert hat, dann nicht. Es liegt auch noch ein mssql Treiber im Classpath, weil wir den auch noch brauchen, das sollte aber eigentlich nicht stören.
Es gab doch in Eclipse eine Tastenkombination, um nach Klasse zu suchen, da müsste ich doch eine Dopplung erkennen können, oder?
 

Oneixee5

Top Contributor
Der mssql-Treiber kann nicht die Ursache sein. Es sieht so aus als würde die Klasse oracle.sql.BLOB benutzt, welche aber nicht kompatibel mit der erwarteten Klasse oracle.sql.BLOB zu sein scheint. Ich habe das Problem schon einmal bei einem Kollegen gesehen. Dort kam ein ojdbc6.jar aus der Installation des Servers mit, zusätzlich hatte er ojdbc8.jar eingebunden.
Wir verwenden allerdings den Oracle Weblogic Server. Dort lässt sich das relativ einfach lösen, indem man in der weblogic.xml den Classpath so einstellt, das Klassen aus dem Package oracle.* nur aus der Anwendung gezogen werden. Entsprechende Klassen aus dem Classpath des Servers sieht die Anwendung dann nicht mehr.
Normalerweise sollte die JEE-Anwendung selbst überhaupt keinen JDBC-Treiber kennen. Man richtet im Server entsprechende Datasources ein. Diese werden dann per JNDI über ihren Namen verwendet. Alles andere ist eher unüblich unter JEE:
Java:
# Example of a Datasource referenced from an Application Server

org.quartz.dataSource.myOtherDS.jndiURL=jdbc/myDataSource
org.quartz.dataSource.myOtherDS.java.naming.factory.initial=com.evermind.server.rmi.RMIInitialContextFactory
org.quartz.dataSource.myOtherDS.java.naming.provider.url=ormi://localhost
org.quartz.dataSource.myOtherDS.java.naming.security.principal=admin
org.quartz.dataSource.myOtherDS.java.naming.security.credentials=123
 

DaBe1812

Bekanntes Mitglied
Das Problem ist aber, dass Quartz zwei Verbindungen zur Datenbank braucht, wenn man eine Servermanaged Verbindung aufbauen möchte.
Deswegen Muss eben eine Teilverbindung über diese zweite Schiene laufen und dann baut Quartz eben alles selbst auf und greift scheinbar beim Oracle-Treiber ins Klo. Ich finde aber auch nichts, was er stattdessen für oracle.jdbc.driver.OracleDriver ziehen könnte. Aber vielleicht suche ich auch falsch.
 

Oneixee5

Top Contributor
Das Problem ist aber, dass Quartz zwei Verbindungen zur Datenbank braucht, wenn man eine Servermanaged Verbindung aufbauen möchte.
Warum sollte es nicht möglich sein 2 Datasources im Server zu konfigurieren? Ich habe mal eine JEE-Anwendung gebaut, welche PDF für viele andere Anwendungen erzeugen kann. Dort gab es zeitweise über 30 Datasources.
 

DaBe1812

Bekanntes Mitglied
Achso, ne, da haben wir aneinander vorbei geredet. Ich hab in dem Server auch 3 Datasources, aber Quartz sagt halt folgendes für die Config:
JDBCJobStore is used to store scheduling information (job, triggers and calendars) within a relational database. There are actually two seperate JDBCJobStore classes that you can select between, depending on the transactional behaviour you need.

JobStoreCMT relies upon transactions being managed by the application which is using Quartz. A JTA transaction must be in progress before attempt to schedule (or unschedule) jobs/triggers. This allows the “work” of scheduling to be part of the applications “larger” transaction. JobStoreCMT actually requires the use of two datasources - one that has it’s connection’s transactions managed by the application server (via JTA) and one datasource that has connections that do not participate in global (JTA) transactions. JobStoreCMT is appropriate when applications are using JTA transactions (such as via EJB Session Beans) to perform their work.
Also muss diese zweite Verbindung von der Anwendung aufgebaut werden, oder verstehe ich das nicht richtig?
 

Oneixee5

Top Contributor
Die JNDI-Datasource kann ich im Oracle-Weblogic als JTA- oder Non-JTA-Datasource anlegen. Also JNDI und JTA sind nicht das Gleiche.
 

DaBe1812

Bekanntes Mitglied
Okay, und dann binde ich das in Quatz einfach auch über seinen JNDI Namen ein?
Auf die Idee bin ich einfach nicht gekommen, weil ich nicht wusste, dass das über die Persistence.xml auch geht.
Heißt das ich nehme eine weitere Source mit rein und stelle die auf RESSOURCE_LOCAL?
Und kann ich da einen JNDI vom Server doppelt verwenden?
Bzw. was muss die Source auf dem Server können, damit es funktiniert?
 

DaBe1812

Bekanntes Mitglied
Ergänzung:
Ich habe jetzt auf dem Server eine neue DS eingerichtet:
XML:
<dataSource jndiName="jdbc/nonJtaAtc" id="nonJtaAtc" type="javax.sql.DataSource" isolationLevel="TRANSACTION_READ_COMMITTED" transactional="false">
    <jdbcDriver libraryRef="OracleJDBC"></jdbcDriver>
    <properties.oracle URL="jdbc:oracle:thin:@SERVER:1521/DB" user="einer" password="geheim"></properties.oracle>
</dataSource>
Bei der scheint er auch den JNDI zu fressen.
Fehler bleibt derselbe.
Ist das Problem evtl. der Treiber auf dem Sever?
 

Oneixee5

Top Contributor
Das hat doch gar nichts mit der Persistence.xml zu tun. Du musst die 2. Datasource in die quartz.properties einbinden. Natürlich musst du dann auch den Oracle-JDBC-Treiber aus dem Classpath entfernen.
 

DaBe1812

Bekanntes Mitglied
Jetzt hab ich mal zwei Tage lang versucht statt Quartz JobRunr zu verwenden. Zumindest läuft das besser an, als Quartz. Aber zurück zu Quartz:
Ich habe die Datasource aus meinem letzten Post in Quartz als zweite Datenquelle eingebunden. Die Sache mit der persistence.xml war ein Brainlag. Leider kommt es zum selben Fehler. Die Oracle Klasse brauche ich im System, weil ich auch noch manuelle Oracle-Verbindungen zu anderen Systemen aufbaue. Außerdem verwende ich dieselbe Klasse, die ich auch im Server verwende, somit müsste es in beiden Klassen zum selben Fehler kommen.

Dann noch zu JobRunr, hier habe ich wohl ein einfaches CDI-Problem:
Java:
@ApplicationScoped
@DependsOn("DatabaseCheck")
public class JobRunrJobs {

    private final static Logger LOG = LogManager.getLogger(JobRunrJobs.class);

    @Inject    transient private AvailableInterface availableInterface;
    
    public void onStart(@Observes @Initialized(ApplicationScoped.class) Object pointless) {
        try {
            OracleDataSource dataSource = createDataSource();
            StorageProvider provider = new OracleStorageProvider(dataSource, DatabaseOptions.SKIP_CREATE);
            JobScheduler jobScheduler = JobRunr.configure().useStorageProvider(provider)
                    .useBackgroundJobServer().useDashboard(65432).initialize().getJobScheduler();

            jobScheduler.enqueue(() -> availableInterface.checkAllSystems());
            
        } catch (Exception e) {
            LOG.error("JobRunr Exception beim Start:", e);
        }
    }
}
In Zeile 16 komme ich ohne Probleme an, aber in der AvailableInterface ist jede Injection null zur Laufzeit:
Java:
@Dependent
public class AvailableInterface {

    private static final Logger LOG = LogManager.getLogger(AvailableInterface.class);
    private static final int MAX_CHAR = 299;
    
    private LocalDateTime time;
    private UnavailableConfig unavailableConfig;

    @Resource private ManagedExecutorService mes;
    
    @Inject    transient private ActiveObjectDbInterface activeObjectDbInterface;
    @Inject    transient private ConnectorStatusDbInterface connectorStatusDbInterface;
    @Inject transient private ToolAvailableInterface toolAvailableInterface;
    @Inject transient private ToolMaintenanceTimeInterface toolMaintenanceTimesInterface;
    @Inject transient private ConfigurationFactory configurationFactory;
    @Inject private Mailer mailer;

    @Inject private Instance<ReferenceController> refControllers;

    public void checkAllSystems() {
        unavailableConfig = configurationFactory.getUnavailableConfig();
        time = LocalDateTime.now();
        // alle Tasks ausführen, auf das Ergebnis warten.
        List<Future<ConnectorStatus>> results = new ArrayList<>();
        try {
            results = mes.invokeAll(createTasks());
        } catch (InterruptedException e) {
            LOG.error("Fehler im Available Executor:", e);
        }

        List<ConnectorStatus> stateList = new ArrayList<>();
        List<ToolAvailable> availableList = toolAvailableInterface.loadAllToolsByServer();
        
        for (Future<ConnectorStatus> result : results) {
            try {
                ConnectorStatus c = result.get();
                stateList.add(c);
            } catch (Exception ex) {
                LOG.error("Fehler im Available Executor:", ex);
            }
        }

        updateAvailableList(stateList, availableList);
        checkMailSend(availableList);
        toolAvailableInterface.persistList(availableList);
        connectorStatusDbInterface.insertConnectorStates(stateList);
    }
}

Ich verstehe nicht ganz warum das alles null ist, und was ich ändern sollte. Wenn ich die Klasse ApplicationScoped mache, dann knallt es schon beim einfachen Aufruf.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
G suche Hilfe beim TreeView Servlet Allgemeines EE 8
B Hilfe zu Design mit EJB Allgemeines EE 50
L Spring REST Application (Data Retrive) API und Architectur hilfe Allgemeines EE 11
fiesematente JSF ajax innerhalb DataTable und verschachtelte EL (Brauch dringend hilfe) Allgemeines EE 8
O JSF Login mit Hilfe eines Sharepoint 2013 Users Allgemeines EE 4
F ein wenig Hilfe - Webservice Allgemeines EE 1
X Anfänger braucht Hilfe Allgemeines EE 9
E Servlet Wie kann ich ohne Hilfe von Eclipse in JBoss mein servlet aufrufen Allgemeines EE 2
P Hilfe: Tomcat periodischer Absturz Allgemeines EE 5
M kurze array hilfe, 2x 1d array --> 1x 2d array Allgemeines EE 2
H Hilfe! Wie erstelle ich einen Interceptor unter jBoss? Allgemeines EE 3
R HILFE: Problem mit JSF examples Allgemeines EE 10
C Brauche HILFE: HelloWorld mit JSF und Tomcat 5.517 Allgemeines EE 15
G Validierung mittels Struts. Benötige Hilfe. Allgemeines EE 7
W Brauche Hilfe bei meinem Programm Allgemeines EE 3
P J2EE Struts - Database connection failed - Hilfe?:( Allgemeines EE 6
B Hilfe (dringend) - Wann lieber JDBC anstatt CMP? Allgemeines EE 5
J Hilfe. brauche Dokumente für die Diplomarbeit Allgemeines EE 9
D Probleme beim Umstieg auf Jakarta EE Allgemeines EE 5
K Konfiguration beim AppServer Allgemeines EE 4
A JPA Fehler beim JPA-Projekt Allgemeines EE 12
M Servlet Fehler beim Start der Serveranwendung Allgemeines EE 3
B @Startup - FileWatcher - Probleme beim Hochfahren des Servers Allgemeines EE 4
I Erhöhte Sicherheit beim Login Allgemeines EE 1
S MessageDrivenBean Problem beim Zugriff auf Stateful EJB Allgemeines EE 2
S OpenJPA-Exception beim Tomee Allgemeines EE 0
B Problem beim Lesen des Codes... Allgemeines EE 2
R JPA Problem beim Speichern eines Users Allgemeines EE 2
D Jboss löscht Archiv nicht beim Redeployed Allgemeines EE 3
Fu3L Probleme beim Einrichten Allgemeines EE 3
B Cookie beim erstem Zugriff auf Web-App ablegen Allgemeines EE 3
J Fehler beim deployen von seam 2.2.2-Projekt Allgemeines EE 9
B Problem beim einbinden einer CSS in eine JSP Allgemeines EE 8
S Eclipse: Teilmodule beim Testen werden nicht gestartet Allgemeines EE 2
S Embedded JBoss Problem beim Deployment Allgemeines EE 4
H fehler beim deployen von ear file Allgemeines EE 2
G Exception beim versenden einer Mail Allgemeines EE 3
A Tomcat, Exceptions beim redeploy Allgemeines EE 4
H GWT Problem beim Ausführen Allgemeines EE 8
E Performance-Problem beim ersten Request Allgemeines EE 4
MQue URL im Brower beim Starten der Anwendung richtig setzen Allgemeines EE 4
M J2EE beim SCJA Allgemeines EE 4
M JSP: Tomcat: Serverfehler 500 nur beim IE. Allgemeines EE 2
M Absturz beim Einbinden des PostgreSQL-Treibers Allgemeines EE 4
K BatchUpdateException beim schreiben in DB Allgemeines EE 12
M EJB Löschen von DB-Daten beim Deployen verhindern Allgemeines EE 2
M tomcat beim booten mit starten Allgemeines EE 4
G JBoss nutzt beim starten ständig das Root.war Allgemeines EE 12
B Fehlermeldung beim ausführen des Clients // Need Help Allgemeines EE 2
P jar-File aus war-File beim Deploy automatisch entpacken Allgemeines EE 2
M servlet --> jsp - problem beim umstrukturieren Allgemeines EE 5
T Probleme beim Einsatz von J2EE / JBoss Allgemeines EE 4
F Wie Heapsize beim Tomcat erhöhen? Allgemeines EE 3
A Problem / Fehler beim Einbinden einer Klasse in ein JSP Allgemeines EE 20
N Wie heisst das was der Client beim Http Server anfragt? Allgemeines EE 6
F richtige vorgehensweise beim logout Allgemeines EE 6
F Fehlermeldung beim redirect in der JSP Allgemeines EE 4
F Package beim Cookie-setzten über BEAN nicht gefunden Allgemeines EE 4
T Design/Performance-Frage beim servlet (static oder nicht) Allgemeines EE 35
F Fehler beim deployen von jsp und servlet Allgemeines EE 7
M NetBeans 5.5 installiert und schon hängt was beim Deployen Allgemeines EE 5
G Servlet beim Absenden eines Formulars aufrufen Allgemeines EE 11
M Probleme beim Performancetuning des Servlets Allgemeines EE 2
T Änderung des Wertes einer Variable beim Klick auf Link Allgemeines EE 7
K [Sun AppServer 8.1] Fehler beim deployen Allgemeines EE 12
FsMarine Probleme beim ausführen von JSP dateien unter Tomcat Allgemeines EE 4
M Probleme beim Webservice Deployment(Sun ApplicationServer) Allgemeines EE 2
B Problem beim Deployen auf Sun AS 8.1 Allgemeines EE 12
R Problem beim hochladen einer Web Application Allgemeines EE 16
H Problem beim Umstieg von 1.3 auf 1.4 Allgemeines EE 5

Ähnliche Java Themen

Neue Themen


Oben