de.svws_nrw.data.schild3.reporting.DataSchildReportingDatenquelle Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of svws-db-utils Show documentation
Show all versions of svws-db-utils Show documentation
Diese Bibliothek unterstützt bei dem Zugriff auf Datenbanken für die Schulverwaltungssoftware in NRW
package de.svws_nrw.data.schild3.reporting;
import de.svws_nrw.base.annotations.SchildReportingDate;
import de.svws_nrw.base.annotations.SchildReportingMemo;
import de.svws_nrw.core.data.schild3.reporting.SchildReportingDatenquelle;
import de.svws_nrw.core.data.schild3.reporting.SchildReportingDatenquelleAttribut;
import de.svws_nrw.core.types.schild3.SchildReportingAttributTyp;
import de.svws_nrw.core.types.schule.Schulform;
import de.svws_nrw.data.DataManager;
import de.svws_nrw.db.DBEntityManager;
import de.svws_nrw.db.dto.current.schild.schule.DTOEigeneSchule;
import de.svws_nrw.db.utils.ApiOperationException;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
/**
* Diese Klasse erweitert den abstrakten {@link DataManager} für
* Datenquellen von Schild-Reports.
*
* @param der Typ der zugehörigen DTO-Klasse
* @param der Typ der Masterquelle, im Falle keiner MasterDatenquelle beliebig - z.B. String
*/
public abstract class DataSchildReportingDatenquelle {
/** Eine Map mit der Zuordnung der Datenquellen zu dem Namen der Datenquelle */
private static LinkedHashMap> datenquellen = null;
/** Die Definition der Datenquelle */
final SchildReportingDatenquelle datenquelle;
/** Der Typ der Master-Datenquelle */
private SchildReportingAttributTyp mastertyp = null;
/** Der Java-Typ für das genutzte Attribut der Master-Datenquelle */
private Class masterclass = null;
/** Enthält die Schulformen, auf welche die Datenquelle eingeschränkt ist. Ist die Menge leer, so steht die
* Datenquelle an allen Schulformen zur Verfügung. */
private final HashSet schulformen = new HashSet<>();
private static final String meldungKeinParameter = "Kein Parameter für das Attribut der Master-Datenquelle angegeben";
private static final String meldungUngueltigerParameter = "Ungültiger Parameter für das Attribut der Master-Datenquelle angegeben";
/**
* Erstellt eine neue Datenquelle für Schild-Reports
*
* @param dtoClass die Klasse des Core-DTOs
*/
DataSchildReportingDatenquelle(final Class dtoClass) {
this.datenquelle = new SchildReportingDatenquelle();
this.datenquelle.name = this.getClass().getSimpleName().replace("DataSchildReportingDatenquelle", "");
this.datenquelle.datenart = dtoClass.getSimpleName().replace("SchildReporting", "");
final Schema schema = dtoClass.getAnnotation(Schema.class);
if ((schema == null) || (schema.description() == null))
throw new NullPointerException("Im Core-DTO musse eine Schema-Definition mit einer 'description' vorhanden sein");
this.datenquelle.beschreibung = schema.description();
this.addAttribute(dtoClass);
DataSchildReportingDatenquelle.datenquellen.put(this.datenquelle.name, this);
}
/**
* Setzt die Informationen zu der Master-Datenquelle dieser Datenquelle
*
* @param linkattribut der Name des Attributs dieser Datenquelle, welches für
* die Verbindung zu der Master-Datenquelle genutzt wird
* @param master der Name der Master-Datenquelle
* @param masterattribut das identifizierende Attribut der Master-Datenquelle
* @param mastertyp der Datentyp des identifzierenden Master-Attributes
* @param masterclass die Java-Klasse für den Datentyp des zu identifzierenden Master-Attributes
*/
void setMaster(final @NotNull String linkattribut, final @NotNull String master, final @NotNull String masterattribut,
final @NotNull SchildReportingAttributTyp mastertyp, final @NotNull Class masterclass) {
this.mastertyp = mastertyp;
this.masterclass = masterclass;
this.datenquelle.linkattribut = linkattribut;
this.datenquelle.master = master;
this.datenquelle.masterattribut = masterattribut;
this.datenquelle.mastertyp = mastertyp.toString();
}
/**
* Fügt ein Attribut zu der Definition der Datenquelle hinzu
*
* @param name der Name des Attributes
* @param typ der Datentyp des Attributes
* @param beschreibung eine erläuternde Erklärung zu dem Attribut
*/
private void addAttribut(final @NotNull String name, final @NotNull SchildReportingAttributTyp typ, final @NotNull String beschreibung) {
final SchildReportingDatenquelleAttribut attr = new SchildReportingDatenquelleAttribut();
attr.name = name;
attr.typ = typ.toString();
attr.beschreibung = beschreibung;
datenquelle.attribute.add(attr);
}
/**
* Fügt die Attribute aus dem übergebenen Core-DTO zu dieser Datenquelle hinzu.
*
* @param clazz die Klasse des Core-DTOs
*/
private void addAttribute(final Class> clazz) {
for (final Field field : clazz.getFields()) {
final SchildReportingAttributTyp typ = switch (field.getType().getSimpleName()) {
case "long", "int", "short", "byte", "Long", "Integer", "Short", "Byte" -> SchildReportingAttributTyp.INT;
case "float", "double", "Float", "Double" -> SchildReportingAttributTyp.NUMBER;
case "boolean", "Boolean" -> SchildReportingAttributTyp.BOOLEAN;
default -> {
if (field.getAnnotation(SchildReportingDate.class) != null)
yield SchildReportingAttributTyp.DATE;
if (field.getAnnotation(SchildReportingMemo.class) != null)
yield SchildReportingAttributTyp.MEMO;
yield SchildReportingAttributTyp.STRING;
}
};
final Schema schema = field.getAnnotation(Schema.class);
if ((schema == null) || (schema.description() == null))
throw new NullPointerException("Im Core-DTO musse eine Schema-Definition mit einer 'description' vorhanden sein");
addAttribut(field.getName(), typ, schema.description());
}
}
/**
* Beschränkt die Gültigkeit der Datenquelle auf die übergebenen Schulformen.
* Sollte die Methode bereits vorher aufgerufen worden sein,
* so werden die Schulformen zu den vorher übergebenen Schulformen ergänzt.
*
* @param schulformen die Schulformen, für welche die Datenquelle zulässig ist
*/
public void restrictTo(final Schulform... schulformen) {
for (final Schulform sf : schulformen)
this.schulformen.add(sf);
}
/**
* Bestimmt die Datensätze der Datenquelle, sofern keine Master-Datenquelle
* angegeben wurde.
*
* @param conn die Datenbankverbindung des aktuellen SVWS-Benutzers
*
* @return die Datensätze der Datenquelle
*
* @throws ApiOperationException im Fehlerfall
*/
List getDaten(final DBEntityManager conn) throws ApiOperationException {
throw new UnsupportedOperationException();
}
/**
* Bestimmt die Datensätze der Datenquelle, sofern der Attributtyp des
* Attributes der Master-Datenquelle definiert wurde und BOOLEAN, INT,
* NUMBER, STRING oder MEMO ist.
*
* @param conn die Datenbankverbindung des aktuellen SVWS-Benutzers
* @param params die Parameter für das Attribut der Masterdatenquelle
*
* @return die Datensätze der Datenquelle
*
* @throws ApiOperationException im Fehlerfall
*/
List getDaten(final DBEntityManager conn, final List params) throws ApiOperationException {
throw new UnsupportedOperationException();
}
private List getDatenBoolean(final DBEntityManager conn, final List extends Object> params) throws ApiOperationException {
// Daten vorhanden?
if (params.isEmpty())
throw new ApiOperationException(Status.NOT_FOUND, meldungKeinParameter);
if (this.masterclass != Boolean.class)
throw new ApiOperationException(Status.CONFLICT, meldungUngueltigerParameter);
// Prüfe, ob alle Parameter vom Typ Boolean sind
for (final Object p : params)
if (!(p instanceof Boolean))
throw new ApiOperationException(Status.CONFLICT, meldungUngueltigerParameter);
@SuppressWarnings("unchecked") final List paramListe = (List) params;
return getDaten(conn, paramListe);
}
private List getDatenInteger(final DBEntityManager conn, final List extends Object> params) throws ApiOperationException {
// Daten vorhanden?
if (params.isEmpty())
throw new ApiOperationException(Status.NOT_FOUND, meldungKeinParameter);
if (this.masterclass != Long.class)
throw new ApiOperationException(Status.CONFLICT, meldungUngueltigerParameter);
// Prüfe, ob alle Parameter vom Typ Long sind
final ArrayList paramListe = new ArrayList<>();
for (final Object p : params) {
switch (p) {
case final Long l -> paramListe.add(l);
case final Integer i -> paramListe.add(i.longValue());
case final Short s -> paramListe.add(s.longValue());
case final Byte b -> paramListe.add(b.longValue());
default -> throw new ApiOperationException(Status.CONFLICT, meldungUngueltigerParameter);
}
}
@SuppressWarnings("unchecked") final List paramListeJMT = (List) paramListe;
return getDaten(conn, paramListeJMT);
}
private List getDatenNumber(final DBEntityManager conn, final List extends Object> params) throws ApiOperationException {
// Daten vorhanden?
if (params.isEmpty())
throw new ApiOperationException(Status.NOT_FOUND, meldungKeinParameter);
if (this.masterclass != Double.class)
throw new ApiOperationException(Status.CONFLICT, meldungUngueltigerParameter);
// Prüfe, ob alle Parameter vom Typ Double sind
final ArrayList paramListe = new ArrayList<>();
for (final Object p : params) {
switch (p) {
case final Double d -> paramListe.add(d);
case final Float f -> paramListe.add(f.doubleValue());
default -> throw new ApiOperationException(Status.CONFLICT, meldungUngueltigerParameter);
}
}
@SuppressWarnings("unchecked") final List paramListeJMT = (List) paramListe;
return getDaten(conn, paramListeJMT);
}
private List getDatenString(final DBEntityManager conn, final List extends Object> params) throws ApiOperationException {
// Daten vorhanden?
if (params.isEmpty())
throw new ApiOperationException(Status.NOT_FOUND, meldungKeinParameter);
if (this.masterclass != String.class)
throw new ApiOperationException(Status.CONFLICT, meldungUngueltigerParameter);
// Prüfe, ob alle Parameter vom Typ String sind
for (final Object p : params)
if (!(p instanceof String))
throw new ApiOperationException(Status.CONFLICT, meldungUngueltigerParameter);
@SuppressWarnings("unchecked") final List paramListeJMT = (List) params;
return getDaten(conn, paramListeJMT);
}
/**
* Bestimmt mithilfe des registrierten Datenobjektes die Daten für die
* über den Pfad spezifizierten Datenquelle.
*
* @param conn die aktuelle Datenverbindung (des SVWS-Benutzers)
* @param name der Name der Datenquelle
* @param params die Parameter der Datenquelle, d.h. die Werte für das Attribut der
* Master-Datenquelle, welche bei dieser Datenquelle berücksichtigt
* werden sollen - ist keine Masterquelle definiert, so muss diese Liste leer sein
*
* @return die HTTP-Response, im Erfolgsfall mit den Daten der Datenquelle
*
* @throws ApiOperationException im Fehlerfall
*/
public static Response getDaten(final DBEntityManager conn, final String name, final List extends Object> params) throws ApiOperationException {
final DataSchildReportingDatenquelle, ?> datenquelle = getMapDatenquellen().get(name);
if (datenquelle == null)
throw new ApiOperationException(Status.NOT_FOUND, "Keine Datenquelle \"" + name + "\" vorhanden.");
List extends Object> result = null;
result = switch (datenquelle.mastertyp) {
case BOOLEAN -> datenquelle.getDatenBoolean(conn, params);
case INT -> datenquelle.getDatenInteger(conn, params);
case NUMBER -> datenquelle.getDatenNumber(conn, params);
case STRING, MEMO -> datenquelle.getDatenString(conn, params);
default -> {
if (!params.isEmpty())
throw new ApiOperationException(Status.CONFLICT, "Eine Datenquelle ohne Master-Datenquelle kann keine Parameter entgegennehmen");
yield datenquelle.getDaten(conn);
}
};
if (result == null)
throw new ApiOperationException(Status.NOT_FOUND, "Fehler beim Lesen der Daten aus der Datenquelle \"" + name + "\".");
return Response.status(Status.OK).type(MediaType.APPLICATION_JSON).entity(result).build();
}
/**
* Liefert eine Liste der Definitionen der im SVWS-Server vorhandenen Schild-Datenquellen zurück.
*
* @param conn die Datenbankverbindung des aktuellen SVWS-Benutzers
*
* @return die HTTP-Response mit der Liste der Definitionen der im SVWS-Server vorhandenen Schild-Datenquellen
*
* @throws ApiOperationException im Fehlerfall
*/
public static Response getDatenquellen(final DBEntityManager conn) throws ApiOperationException {
final var datenquellen = getMapDatenquellen();
final DTOEigeneSchule schule = conn.querySingle(DTOEigeneSchule.class);
if (schule == null)
throw new ApiOperationException(Status.INTERNAL_SERVER_ERROR, "Kein gültiger Eintrag für die Schule in der Datenbank vorhanden");
final ArrayList result = new ArrayList<>();
for (final var datenquelle : datenquellen.values()) {
if ((datenquelle.schulformen.isEmpty()) || (datenquelle.schulformen.contains(schule.Schulform)))
result.add(datenquelle.datenquelle);
}
return Response.status(Status.OK).type(MediaType.APPLICATION_JSON).entity(result).build();
}
/**
* Erstellt die Liste der im SVWS-Server verfügbaren Datenquellen. An dieser Stelle
* müssen einzelnen Data-Objekte des svws-openapi- Projektes erzeugt werden.
*
* @return die Liste der im SVWS-Server verfügbaren Datenquellen
*/
@SuppressWarnings("unused")
private static LinkedHashMap> getMapDatenquellen() {
if (datenquellen == null) {
datenquellen = new LinkedHashMap<>();
new DataSchildReportingDatenquelleSchuelerLernabschnitte();
new DataSchildReportingDatenquelleSchuelerLeistungsdaten();
new DataSchildReportingDatenquelleSchuelerSprachpruefungen();
}
return datenquellen;
}
}