view src/main/java/de/intevation/lada/rest/AuditTrailService.java @ 1310:c5721e624c0e

Insert timestamp into audit trail changed fields instead of date string.
author Raimund Renkert <raimund.renkert@intevation.de>
date Wed, 08 Mar 2017 15:59:47 +0100
parents d531e8e8afa2
children 6fbfb8f0927a
line wrap: on
line source
/* 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.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
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.
 * <p>
 * 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.
 * <pre>
 * <code>
 * {
 *  "success": [boolean];
 *  "message": [string],
 *  "data":[{
 *      "id": [number],
 *      "identifier: [string]
 *      "audit": [array]
 *  }],
 * }
 * </code>
 * </pre>
 *
 * @author <a href="mailto:rrenkert@intevation.de">Raimund Renkert</a>
 */
@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<String, TableMapper> mappings;

    /**
     * Initialize the object with key <-> table mappings.
     */
    @PostConstruct
    public void initialize() {
        mappings = new HashMap<String, TableMapper>();
        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"));
        mappings.put("probeentnahme_beginn",
            new TableMapper("date", "dd.MM.yy HH:mm"));
        mappings.put("probeentnahme_ende",
            new TableMapper("date", "dd.MM.yy HH:mm"));
    }

    /**
     * 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<AuditTrailProbe> builder =
            new QueryBuilder<AuditTrailProbe>(
                repository.entityManager("land"),
                AuditTrailProbe.class);
        builder.and("objectId", id);
        builder.and("tableName", "probe");
        builder.or("probeId", id);
        builder.orderBy("tstamp", true);
        List<AuditTrailProbe> 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());
        node.put("action", audit.getAction());
        ObjectNode data = (ObjectNode)audit.getChangedFields();
        data = translateValues(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 ("ortszuordnung".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<AuditTrailMessung> builder =
            new QueryBuilder<AuditTrailMessung>(
                repository.entityManager("land"),
                AuditTrailMessung.class);
        builder.and("objectId", mId);
        builder.and("tableName", "messung");
        builder.or("messungsId", mId);
        builder.orderBy("tstamp", true);
        List<AuditTrailMessung> 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());
        node.put("action", audit.getAction());
        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<String> result = query.getResultList();
        return result.get(0);
    }

    private Long formatDate(String format, String date) {
        DateFormat inFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssXXX");
        try {
            return inFormat.parse(date).getTime();
        } catch (ParseException e) {
            return 0L;
        }
    }

    /**
     * Translate all known foreign keys
     */
    private ObjectNode translateValues(ObjectNode node) {
        for (Iterator<String> i = node.fieldNames(); i.hasNext();) {
            String key = i.next();
            if (mappings.containsKey(key)) {
                TableMapper m = mappings.get(key);
                if (m.mappingTable.equals("date")) {
                    Long value = formatDate(m.valueField, node.get(key).asText());
                    node.put(key, value);
                }
                else {
                    String value = translateId(
                        m.mappingTable,
                        m.valueField,
                        node.get(key).asText(),
                        "id",
                        "stamm");
                    node.put(key, value);
                }
            }
        }
        return node;
    }
}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)