raimund@1301: /* Copyright (C) 2013 by Bundesamt fuer Strahlenschutz
raimund@1301: * Software engineering by Intevation GmbH
raimund@1301: *
raimund@1301: * This file is Free Software under the GNU GPL (v>=3)
raimund@1301: * and comes with ABSOLUTELY NO WARRANTY! Check out
raimund@1301: * the documentation coming with IMIS-Labordaten-Application for details.
raimund@1301: */
raimund@1301: package de.intevation.lada.rest;
raimund@1301:
raimund@1309: import java.text.DateFormat;
raimund@1309: import java.text.ParseException;
raimund@1309: import java.text.SimpleDateFormat;
raimund@1309: import java.util.Date;
raimund@1301: import java.util.HashMap;
raimund@1301: import java.util.Iterator;
raimund@1301: import java.util.List;
raimund@1301: import java.util.Map;
raimund@1301:
raimund@1301: import javax.annotation.PostConstruct;
raimund@1301: import javax.enterprise.context.RequestScoped;
raimund@1301: import javax.inject.Inject;
raimund@1301: import javax.persistence.EntityManager;
raimund@1301: import javax.servlet.http.HttpServletRequest;
raimund@1301: import javax.ws.rs.GET;
raimund@1301: import javax.ws.rs.Path;
raimund@1301: import javax.ws.rs.PathParam;
raimund@1301: import javax.ws.rs.Produces;
raimund@1301: import javax.ws.rs.core.Context;
raimund@1301: import javax.ws.rs.core.MediaType;
raimund@1301:
raimund@1301: import org.apache.log4j.Logger;
raimund@1301:
raimund@1301: import com.fasterxml.jackson.databind.ObjectMapper;
raimund@1301: import com.fasterxml.jackson.databind.node.ArrayNode;
raimund@1301: import com.fasterxml.jackson.databind.node.ObjectNode;
raimund@1301:
raimund@1301: import de.intevation.lada.model.land.AuditTrailMessung;
raimund@1301: import de.intevation.lada.model.land.AuditTrailProbe;
raimund@1301: import de.intevation.lada.model.land.Messung;
raimund@1301: import de.intevation.lada.model.land.Probe;
raimund@1301: import de.intevation.lada.util.annotation.AuthorizationConfig;
raimund@1301: import de.intevation.lada.util.annotation.RepositoryConfig;
raimund@1301: import de.intevation.lada.util.auth.Authorization;
raimund@1301: import de.intevation.lada.util.auth.AuthorizationType;
raimund@1301: import de.intevation.lada.util.data.QueryBuilder;
raimund@1301: import de.intevation.lada.util.data.Repository;
raimund@1301: import de.intevation.lada.util.data.RepositoryType;
raimund@1301:
raimund@1301: /**
raimund@1301: * REST service for AuditTrail.
raimund@1301: *
raimund@1301: * The services produce data in the application/json media type.
raimund@1301: * All HTTP methods use the authorization module to determine if the user is
raimund@1301: * allowed to perform the requested action.
raimund@1301: * A typical response holds information about the action performed and the data.
raimund@1301: *
raimund@1301: *
raimund@1301: * {
raimund@1301: * "success": [boolean];
raimund@1301: * "message": [string],
raimund@1301: * "data":[{
raimund@1301: * "id": [number],
raimund@1301: * "identifier: [string]
raimund@1301: * "audit": [array]
raimund@1301: * }],
raimund@1301: * }
raimund@1301: *
raimund@1301: *
raimund@1301: *
raimund@1301: * @author Raimund Renkert
raimund@1301: */
raimund@1301: @Path("rest/audit")
raimund@1301: @RequestScoped
raimund@1301: public class AuditTrailService {
raimund@1301:
raimund@1301: /**
raimund@1301: * Class to store tablename and value field for foreign key mappings.
raimund@1301: */
raimund@1301: private class TableMapper {
raimund@1301: public String mappingTable;
raimund@1301: public String valueField;
raimund@1301:
raimund@1301: public TableMapper(
raimund@1301: String mappingTable,
raimund@1301: String valueField
raimund@1301: ) {
raimund@1301: this.mappingTable = mappingTable;
raimund@1301: this.valueField = valueField;
raimund@1301: }
raimund@1301: }
raimund@1301:
raimund@1301: @Inject Logger logger;
raimund@1301: /**
raimund@1301: * The data repository granting read/write access.
raimund@1301: */
raimund@1301: @Inject
raimund@1301: @RepositoryConfig(type=RepositoryType.RO)
raimund@1301: private Repository repository;
raimund@1301:
raimund@1301: /**
raimund@1301: * The authorization module.
raimund@1301: */
raimund@1301: @Inject
raimund@1301: @AuthorizationConfig(type=AuthorizationType.HEADER)
raimund@1301: private Authorization authorization;
raimund@1301:
raimund@1301: /**
raimund@1301: * Map foreign key to their associated table and the display value.
raimund@1301: */
raimund@1301: private Map mappings;
raimund@1301:
raimund@1301: /**
raimund@1301: * Initialize the object with key <-> table mappings.
raimund@1301: */
raimund@1301: @PostConstruct
raimund@1301: public void initialize() {
raimund@1301: mappings = new HashMap();
raimund@1301: mappings.put("messgroesse_id",
raimund@1301: new TableMapper("messgroesse", "messgroesse"));
raimund@1301: mappings.put("meh_id",
raimund@1301: new TableMapper("mess_einheit", "einheit"));
raimund@1301: mappings.put("ort_id",
raimund@1301: new TableMapper("ort", "ort_id"));
raimund@1301: mappings.put("datenbasis_id",
raimund@1301: new TableMapper("datenbasis", "datenbasis"));
raimund@1301: mappings.put("ba_id",
raimund@1301: new TableMapper("betriebsart", "name"));
raimund@1301: mappings.put("mpl_id",
raimund@1301: new TableMapper("messprogramm_kategorie", "code"));
raimund@1301: mappings.put("probenart_id",
raimund@1301: new TableMapper("probenart", "probenart"));
raimund@1301: mappings.put("probe_nehmer_id",
raimund@1301: new TableMapper("probenehmer", "prn_id"));
raimund@1309: mappings.put("probeentnahme_beginn",
raimund@1309: new TableMapper("date", "dd.MM.yy HH:mm"));
raimund@1309: mappings.put("probeentnahme_ende",
raimund@1309: new TableMapper("date", "dd.MM.yy HH:mm"));
raimund@1301: }
raimund@1301:
raimund@1301: /**
raimund@1301: * Service to generate audit trail for probe objects.
raimund@1301: */
raimund@1301: @GET
raimund@1301: @Path("/probe/{id}")
raimund@1301: @Produces(MediaType.APPLICATION_JSON)
raimund@1301: public String getProbe(
raimund@1301: @Context HttpServletRequest request,
raimund@1301: @PathParam("id") String id
raimund@1301: ) {
raimund@1301: if (id == null || "".equals(id)) {
raimund@1301: String ret = "{\"success\": false," +
raimund@1301: "\"message\":698,\"data\":null}";
raimund@1301: return ret;
raimund@1301: }
raimund@1301: Integer pId = null;
raimund@1301: try {
raimund@1301: pId = Integer.valueOf(id);
raimund@1301: }
raimund@1301: catch(NumberFormatException nfe) {
raimund@1301: String ret = "{\"success\": false," +
raimund@1301: "\"message\":600,\"data\":null}";
raimund@1301: return ret;
raimund@1301: }
raimund@1301:
raimund@1301: // Get all entries for the probe and its sub objects.
raimund@1301: QueryBuilder builder =
raimund@1301: new QueryBuilder(
raimund@1301: repository.entityManager("land"),
raimund@1301: AuditTrailProbe.class);
raimund@1301: builder.and("objectId", id);
raimund@1301: builder.and("tableName", "probe");
raimund@1301: builder.or("probeId", id);
raimund@1301: builder.orderBy("tstamp", true);
raimund@1301: List audit =
raimund@1301: repository.filterPlain(builder.getQuery(), "land");
raimund@1301:
raimund@1301: // Get the plain probe object to have the hauptproben_nr.
raimund@1301: // If only subobjects
raimund@1301: Probe probe = repository.getByIdPlain(Probe.class, pId, "land");
raimund@1301: // Create an empty JsonObject
raimund@1301: ObjectMapper mapper = new ObjectMapper();
raimund@1301: ObjectNode responseNode = mapper.createObjectNode();
raimund@1301: responseNode.put("success", true);
raimund@1301: responseNode.put("message", 200);
raimund@1301: ObjectNode auditJson = responseNode.putObject("data");
raimund@1301: ArrayNode entries = auditJson.putArray("audit");
raimund@1301: auditJson.put("id", probe.getId());
raimund@1301: auditJson.put("identifier", probe.getHauptprobenNr());
raimund@1301: for (AuditTrailProbe a : audit) {
raimund@1301: entries.add(createEntry(a, mapper));
raimund@1301: }
raimund@1301: return responseNode.toString();
raimund@1301: }
raimund@1301:
raimund@1301: /**
raimund@1301: * Create a JSON object for an AuditTrailProbe entry.
raimund@1301: *
raimund@1301: * @param audit The table entry
raimund@1301: * @param mapper JSON object mapper
raimund@1301: */
raimund@1301: private ObjectNode createEntry(AuditTrailProbe audit, ObjectMapper mapper) {
raimund@1301: ObjectNode node = mapper.createObjectNode();
raimund@1301: node.put("timestamp", audit.getTstamp().getTime());
raimund@1301: node.put("type", audit.getTableName());
raimund@1308: node.put("action", audit.getAction());
raimund@1301: ObjectNode data = (ObjectNode)audit.getChangedFields();
raimund@1309: data = translateValues(data);
raimund@1301: node.putPOJO("changedFields", data);
raimund@1301: if ("kommentar_p".equals(audit.getTableName())) {
raimund@1301: node.put("identifier", audit.getRowData().get("datum").toString());
raimund@1301: }
raimund@1301: if ("zusatz_wert".equals(audit.getTableName())) {
raimund@1301: node.put("identifier", audit.getRowData().get("pzs_id").toString());
raimund@1301: }
raimund@1304: if ("ortszuordnung".equals(audit.getTableName())) {
raimund@1301: String value = translateId(
raimund@1301: "ort",
raimund@1301: "ort_id",
raimund@1301: audit.getRowData().get("ort_id").toString(),
raimund@1301: "id",
raimund@1301: "stamm");
raimund@1301: node.put("identifier", value);
raimund@1301: }
raimund@1301: if ("messung".equals(audit.getTableName())) {
raimund@1301: logger.debug("npr: " + audit.getRowData());
raimund@1301: node.put("identifier",
raimund@1301: audit.getRowData()
raimund@1301: .get("nebenproben_nr").toString().replaceAll("\"", ""));
raimund@1301: }
raimund@1301: if (audit.getMessungsId() != null) {
raimund@1301: Messung m = repository.getByIdPlain(
raimund@1301: Messung.class, audit.getMessungsId(), "land");
raimund@1301: ObjectNode identifier = node.putObject("identifier");
raimund@1301: identifier.put("messung", m.getNebenprobenNr());
raimund@1301: if ("kommentar_m".equals(audit.getTableName())) {
raimund@1301: identifier.put("identifier",
raimund@1301: audit.getRowData().get("datum").toString());
raimund@1301: }
raimund@1301: if ("messwert".equals(audit.getTableName())) {
raimund@1301: String value = translateId(
raimund@1301: "messgroesse",
raimund@1301: "messgroesse",
raimund@1301: audit.getRowData().get("messgroesse_id").toString(),
raimund@1301: "id",
raimund@1301: "stamm");
raimund@1301: identifier.put("identifier", value);
raimund@1301: }
raimund@1301: }
raimund@1301: return node;
raimund@1301: }
raimund@1301:
raimund@1301: /**
raimund@1301: * Service to generate audit trail for messung objects.
raimund@1301: */
raimund@1301: @GET
raimund@1301: @Path("/messung/{id}")
raimund@1301: @Produces(MediaType.APPLICATION_JSON)
raimund@1301: public String getMessung(
raimund@1301: @Context HttpServletRequest request,
raimund@1301: @PathParam("id") String id
raimund@1301: ) {
raimund@1301: if (id == null || "".equals(id)) {
raimund@1301: String ret = "{\"success\": false," +
raimund@1301: "\"message\":698,\"data\":null}";
raimund@1301: return ret;
raimund@1301: }
raimund@1301: Integer mId = null;
raimund@1301: try {
raimund@1301: mId = Integer.valueOf(id);
raimund@1301: }
raimund@1301: catch(NumberFormatException nfe) {
raimund@1301: String ret = "{\"success\": false," +
raimund@1301: "\"message\":600,\"data\":null}";
raimund@1301: return ret;
raimund@1301: }
raimund@1301: QueryBuilder builder =
raimund@1301: new QueryBuilder(
raimund@1301: repository.entityManager("land"),
raimund@1301: AuditTrailMessung.class);
raimund@1301: builder.and("objectId", mId);
raimund@1301: builder.and("tableName", "messung");
raimund@1301: builder.or("messungsId", mId);
raimund@1301: builder.orderBy("tstamp", true);
raimund@1301: List audit =
raimund@1301: repository.filterPlain(builder.getQuery(), "land");
raimund@1301:
raimund@1301: Messung messung = repository.getByIdPlain(Messung.class, mId, "land");
raimund@1301: // Create an empty JsonObject
raimund@1301: ObjectMapper mapper = new ObjectMapper();
raimund@1301: ObjectNode responseNode = mapper.createObjectNode();
raimund@1301: responseNode.put("success", true);
raimund@1301: responseNode.put("message", 200);
raimund@1301: ObjectNode auditJson = responseNode.putObject("data");
raimund@1301: ArrayNode entries = auditJson.putArray("audit");
raimund@1301: auditJson.put("id", messung.getId());
raimund@1301: auditJson.put("identifier", messung.getNebenprobenNr());
raimund@1301: for (AuditTrailMessung a : audit) {
raimund@1301: entries.add(createEntry(a, mapper));
raimund@1301: }
raimund@1301: return responseNode.toString();
raimund@1301: }
raimund@1301:
raimund@1301: /**
raimund@1301: * Create a JSON object for an AuditTrailMessung entry.
raimund@1301: *
raimund@1301: * @param audit The table entry
raimund@1301: * @param mapper JSON object mapper
raimund@1301: */
raimund@1301: private ObjectNode createEntry(AuditTrailMessung audit, ObjectMapper mapper) {
raimund@1301: ObjectNode node = mapper.createObjectNode();
raimund@1301: node.put("timestamp", audit.getTstamp().getTime());
raimund@1301: node.put("type", audit.getTableName());
raimund@1308: node.put("action", audit.getAction());
raimund@1301: ObjectNode data = (ObjectNode)audit.getChangedFields();
raimund@1301: node.putPOJO("changedFields", data);
raimund@1301: if ("kommentar_m".equals(audit.getTableName())) {
raimund@1301: node.put("identifier", audit.getRowData().get("datum").toString());
raimund@1301: }
raimund@1301: if ("messwert".equals(audit.getTableName())) {
raimund@1301: String value = translateId(
raimund@1301: "messgroesse",
raimund@1301: "messgroesse",
raimund@1301: audit.getRowData().get("messgroesse_id").toString(),
raimund@1301: "id",
raimund@1301: "stamm");
raimund@1301: node.put("identifier", value);
raimund@1301: }
raimund@1301: return node;
raimund@1301: }
raimund@1301:
raimund@1301: /**
raimund@1301: * Translate a foreign key into the associated value.
raimund@1301: */
raimund@1301: private String translateId(
raimund@1301: String table,
raimund@1301: String field,
raimund@1301: String id,
raimund@1301: String idField,
raimund@1301: String source
raimund@1301: ) {
raimund@1301: EntityManager manager = repository.entityManager(source);
raimund@1301: String sql = "SELECT " + field + " FROM " + table +
raimund@1301: " WHERE " + idField + " = " + id + ";";
raimund@1301: javax.persistence.Query query = manager.createNativeQuery(sql);
raimund@1301: List result = query.getResultList();
raimund@1301: return result.get(0);
raimund@1301: }
raimund@1301:
raimund@1309: private String formatDate(String format, String date) {
raimund@1309: DateFormat inFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssXXX");
raimund@1309: DateFormat outFormat = new SimpleDateFormat("dd.MM.yyyy hh:mm");
raimund@1309: Date input;
raimund@1309: try {
raimund@1309: input = inFormat.parse(date);
raimund@1309: } catch (ParseException e) {
raimund@1309: return date;
raimund@1309: }
raimund@1309: return outFormat.format(input);
raimund@1309: }
raimund@1309:
raimund@1301: /**
raimund@1301: * Translate all known foreign keys
raimund@1301: */
raimund@1309: private ObjectNode translateValues(ObjectNode node) {
raimund@1301: for (Iterator i = node.fieldNames(); i.hasNext();) {
raimund@1301: String key = i.next();
raimund@1301: if (mappings.containsKey(key)) {
raimund@1301: TableMapper m = mappings.get(key);
raimund@1309: String value = "";
raimund@1309: if (m.mappingTable.equals("date")) {
raimund@1309: value = formatDate(m.valueField, node.get(key).asText());
raimund@1309: }
raimund@1309: else {
raimund@1309: value = translateId(
raimund@1301: m.mappingTable,
raimund@1301: m.valueField,
raimund@1301: node.get(key).asText(),
raimund@1301: "id",
raimund@1301: "stamm");
raimund@1309: }
raimund@1301: node.put(key, value);
raimund@1301: }
raimund@1301: }
raimund@1301: return node;
raimund@1301: }
raimund@1301: }