# HG changeset patch # User Raimund Renkert # Date 1487942945 -3600 # Node ID a3f281b350f230b51234d83c685b49d65e9aed59 # Parent 03670cc25357adcbad4bad08f659d7a70b324483 Added service for audit trail. diff -r 03670cc25357 -r a3f281b350f2 src/main/java/de/intevation/lada/rest/AuditTrailService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/de/intevation/lada/rest/AuditTrailService.java Fri Feb 24 14:29:05 2017 +0100 @@ -0,0 +1,358 @@ +/* Copyright (C) 2013 by Bundesamt fuer Strahlenschutz + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=3) + * and comes with ABSOLUTELY NO WARRANTY! Check out + * the documentation coming with IMIS-Labordaten-Application for details. + */ +package de.intevation.lada.rest; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; + +import org.apache.log4j.Logger; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import de.intevation.lada.model.land.AuditTrailMessung; +import de.intevation.lada.model.land.AuditTrailProbe; +import de.intevation.lada.model.land.Messung; +import de.intevation.lada.model.land.Probe; +import de.intevation.lada.util.annotation.AuthorizationConfig; +import de.intevation.lada.util.annotation.RepositoryConfig; +import de.intevation.lada.util.auth.Authorization; +import de.intevation.lada.util.auth.AuthorizationType; +import de.intevation.lada.util.data.QueryBuilder; +import de.intevation.lada.util.data.Repository; +import de.intevation.lada.util.data.RepositoryType; + +/** + * REST service for AuditTrail. + *

+ * The services produce data in the application/json media type. + * All HTTP methods use the authorization module to determine if the user is + * allowed to perform the requested action. + * A typical response holds information about the action performed and the data. + *

+ * 
+ * {
+ *  "success": [boolean];
+ *  "message": [string],
+ *  "data":[{
+ *      "id": [number],
+ *      "identifier: [string]
+ *      "audit": [array]
+ *  }],
+ * }
+ * 
+ * 
+ * + * @author Raimund Renkert + */ +@Path("rest/audit") +@RequestScoped +public class AuditTrailService { + + /** + * Class to store tablename and value field for foreign key mappings. + */ + private class TableMapper { + public String mappingTable; + public String valueField; + + public TableMapper( + String mappingTable, + String valueField + ) { + this.mappingTable = mappingTable; + this.valueField = valueField; + } + } + + @Inject Logger logger; + /** + * The data repository granting read/write access. + */ + @Inject + @RepositoryConfig(type=RepositoryType.RO) + private Repository repository; + + /** + * The authorization module. + */ + @Inject + @AuthorizationConfig(type=AuthorizationType.HEADER) + private Authorization authorization; + + /** + * Map foreign key to their associated table and the display value. + */ + private Map mappings; + + /** + * Initialize the object with key <-> table mappings. + */ + @PostConstruct + public void initialize() { + mappings = new HashMap(); + mappings.put("messgroesse_id", + new TableMapper("messgroesse", "messgroesse")); + mappings.put("meh_id", + new TableMapper("mess_einheit", "einheit")); + mappings.put("ort_id", + new TableMapper("ort", "ort_id")); + mappings.put("datenbasis_id", + new TableMapper("datenbasis", "datenbasis")); + mappings.put("ba_id", + new TableMapper("betriebsart", "name")); + mappings.put("mpl_id", + new TableMapper("messprogramm_kategorie", "code")); + mappings.put("probenart_id", + new TableMapper("probenart", "probenart")); + mappings.put("probe_nehmer_id", + new TableMapper("probenehmer", "prn_id")); + } + + /** + * Service to generate audit trail for probe objects. + */ + @GET + @Path("/probe/{id}") + @Produces(MediaType.APPLICATION_JSON) + public String getProbe( + @Context HttpServletRequest request, + @PathParam("id") String id + ) { + if (id == null || "".equals(id)) { + String ret = "{\"success\": false," + + "\"message\":698,\"data\":null}"; + return ret; + } + Integer pId = null; + try { + pId = Integer.valueOf(id); + } + catch(NumberFormatException nfe) { + String ret = "{\"success\": false," + + "\"message\":600,\"data\":null}"; + return ret; + } + + // Get all entries for the probe and its sub objects. + QueryBuilder builder = + new QueryBuilder( + repository.entityManager("land"), + AuditTrailProbe.class); + builder.and("objectId", id); + builder.and("tableName", "probe"); + builder.or("probeId", id); + builder.orderBy("tstamp", true); + List audit = + repository.filterPlain(builder.getQuery(), "land"); + + // Get the plain probe object to have the hauptproben_nr. + // If only subobjects + Probe probe = repository.getByIdPlain(Probe.class, pId, "land"); + // Create an empty JsonObject + ObjectMapper mapper = new ObjectMapper(); + ObjectNode responseNode = mapper.createObjectNode(); + responseNode.put("success", true); + responseNode.put("message", 200); + ObjectNode auditJson = responseNode.putObject("data"); + ArrayNode entries = auditJson.putArray("audit"); + auditJson.put("id", probe.getId()); + auditJson.put("identifier", probe.getHauptprobenNr()); + for (AuditTrailProbe a : audit) { + entries.add(createEntry(a, mapper)); + } + return responseNode.toString(); + } + + /** + * Create a JSON object for an AuditTrailProbe entry. + * + * @param audit The table entry + * @param mapper JSON object mapper + */ + private ObjectNode createEntry(AuditTrailProbe audit, ObjectMapper mapper) { + ObjectNode node = mapper.createObjectNode(); + node.put("timestamp", audit.getTstamp().getTime()); + node.put("type", audit.getTableName()); + ObjectNode data = (ObjectNode)audit.getChangedFields(); + data = translateIds(data); + node.putPOJO("changedFields", data); + if ("kommentar_p".equals(audit.getTableName())) { + node.put("identifier", audit.getRowData().get("datum").toString()); + } + if ("zusatz_wert".equals(audit.getTableName())) { + node.put("identifier", audit.getRowData().get("pzs_id").toString()); + } + if ("ortszuordung".equals(audit.getTableName())) { + String value = translateId( + "ort", + "ort_id", + audit.getRowData().get("ort_id").toString(), + "id", + "stamm"); + node.put("identifier", value); + } + if ("messung".equals(audit.getTableName())) { + logger.debug("npr: " + audit.getRowData()); + node.put("identifier", + audit.getRowData() + .get("nebenproben_nr").toString().replaceAll("\"", "")); + } + if (audit.getMessungsId() != null) { + Messung m = repository.getByIdPlain( + Messung.class, audit.getMessungsId(), "land"); + ObjectNode identifier = node.putObject("identifier"); + identifier.put("messung", m.getNebenprobenNr()); + if ("kommentar_m".equals(audit.getTableName())) { + identifier.put("identifier", + audit.getRowData().get("datum").toString()); + } + if ("messwert".equals(audit.getTableName())) { + String value = translateId( + "messgroesse", + "messgroesse", + audit.getRowData().get("messgroesse_id").toString(), + "id", + "stamm"); + identifier.put("identifier", value); + } + } + return node; + } + + /** + * Service to generate audit trail for messung objects. + */ + @GET + @Path("/messung/{id}") + @Produces(MediaType.APPLICATION_JSON) + public String getMessung( + @Context HttpServletRequest request, + @PathParam("id") String id + ) { + if (id == null || "".equals(id)) { + String ret = "{\"success\": false," + + "\"message\":698,\"data\":null}"; + return ret; + } + Integer mId = null; + try { + mId = Integer.valueOf(id); + } + catch(NumberFormatException nfe) { + String ret = "{\"success\": false," + + "\"message\":600,\"data\":null}"; + return ret; + } + QueryBuilder builder = + new QueryBuilder( + repository.entityManager("land"), + AuditTrailMessung.class); + builder.and("objectId", mId); + builder.and("tableName", "messung"); + builder.or("messungsId", mId); + builder.orderBy("tstamp", true); + List audit = + repository.filterPlain(builder.getQuery(), "land"); + + Messung messung = repository.getByIdPlain(Messung.class, mId, "land"); + // Create an empty JsonObject + ObjectMapper mapper = new ObjectMapper(); + ObjectNode responseNode = mapper.createObjectNode(); + responseNode.put("success", true); + responseNode.put("message", 200); + ObjectNode auditJson = responseNode.putObject("data"); + ArrayNode entries = auditJson.putArray("audit"); + auditJson.put("id", messung.getId()); + auditJson.put("identifier", messung.getNebenprobenNr()); + for (AuditTrailMessung a : audit) { + entries.add(createEntry(a, mapper)); + } + return responseNode.toString(); + } + + /** + * Create a JSON object for an AuditTrailMessung entry. + * + * @param audit The table entry + * @param mapper JSON object mapper + */ + private ObjectNode createEntry(AuditTrailMessung audit, ObjectMapper mapper) { + ObjectNode node = mapper.createObjectNode(); + node.put("timestamp", audit.getTstamp().getTime()); + node.put("type", audit.getTableName()); + ObjectNode data = (ObjectNode)audit.getChangedFields(); + node.putPOJO("changedFields", data); + if ("kommentar_m".equals(audit.getTableName())) { + node.put("identifier", audit.getRowData().get("datum").toString()); + } + if ("messwert".equals(audit.getTableName())) { + String value = translateId( + "messgroesse", + "messgroesse", + audit.getRowData().get("messgroesse_id").toString(), + "id", + "stamm"); + node.put("identifier", value); + } + return node; + } + + /** + * Translate a foreign key into the associated value. + */ + private String translateId( + String table, + String field, + String id, + String idField, + String source + ) { + EntityManager manager = repository.entityManager(source); + String sql = "SELECT " + field + " FROM " + table + + " WHERE " + idField + " = " + id + ";"; + javax.persistence.Query query = manager.createNativeQuery(sql); + List result = query.getResultList(); + return result.get(0); + } + + /** + * Translate all known foreign keys + */ + private ObjectNode translateIds(ObjectNode node) { + for (Iterator i = node.fieldNames(); i.hasNext();) { + String key = i.next(); + if (mappings.containsKey(key)) { + TableMapper m = mappings.get(key); + String value = translateId( + m.mappingTable, + m.valueField, + node.get(key).asText(), + "id", + "stamm"); + node.put(key, value); + } + } + return node; + } +}