001/* 002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Thierry Delprat 018 */ 019package org.nuxeo.elasticsearch.audit.io; 020 021import java.io.IOException; 022import java.io.Serializable; 023import java.util.Map; 024 025import org.apache.commons.logging.Log; 026import org.apache.commons.logging.LogFactory; 027import org.codehaus.jackson.JsonGenerationException; 028import org.codehaus.jackson.JsonGenerator; 029import org.codehaus.jackson.map.JsonMappingException; 030import org.codehaus.jackson.map.JsonSerializer; 031import org.codehaus.jackson.map.ObjectMapper; 032import org.codehaus.jackson.map.SerializerProvider; 033import org.codehaus.jackson.map.module.SimpleModule; 034import org.elasticsearch.common.jackson.core.JsonProcessingException; 035import org.joda.time.DateTime; 036import org.joda.time.format.ISODateTimeFormat; 037import org.nuxeo.ecm.core.api.impl.blob.AbstractBlob; 038import org.nuxeo.ecm.platform.audit.api.ExtendedInfo; 039import org.nuxeo.ecm.platform.audit.api.LogEntry; 040 041public class AuditEntryJSONWriter { 042 043 protected static final Log log = LogFactory.getLog(AuditEntryJSONWriter.class); 044 045 public static void asJSON(JsonGenerator jg, LogEntry logEntry) throws IOException { 046 ObjectMapper objectMapper = new ObjectMapper(); 047 SimpleModule module = new SimpleModule("esAuditJson", org.codehaus.jackson.Version.unknownVersion()); 048 module.addSerializer(Map.class, new MapEntrySerializer()); 049 module.addSerializer(AbstractBlob.class, new BinaryBlobEntrySerializer()); 050 objectMapper.registerModule(module); 051 jg.setCodec(objectMapper); 052 053 jg.writeStartObject(); 054 jg.writeStringField("entity-type", "logEntry"); 055 056 writeField(jg, "category", logEntry.getCategory()); 057 writeField(jg, "principalName", logEntry.getPrincipalName()); 058 writeField(jg, "comment", logEntry.getComment()); 059 writeField(jg, "docLifeCycle", logEntry.getDocLifeCycle()); 060 writeField(jg, "docPath", logEntry.getDocPath()); 061 writeField(jg, "docType", logEntry.getDocType()); 062 writeField(jg, "docUUID", logEntry.getDocUUID()); 063 writeField(jg, "eventId", logEntry.getEventId()); 064 writeField(jg, "repositoryId", logEntry.getRepositoryId()); 065 jg.writeStringField("eventDate", ISODateTimeFormat.dateTime().print(new DateTime(logEntry.getEventDate()))); 066 jg.writeNumberField("id", logEntry.getId()); 067 jg.writeStringField("logDate", ISODateTimeFormat.dateTime().print(new DateTime(logEntry.getLogDate()))); 068 Map<String, ExtendedInfo> extended = logEntry.getExtendedInfos(); 069 jg.writeObjectFieldStart("extended"); 070 for (String key : extended.keySet()) { 071 ExtendedInfo ei = extended.get(key); 072 if (ei != null && ei.getSerializableValue() != null) { 073 Serializable value = ei.getSerializableValue(); 074 if (value instanceof String) { 075 String strValue = (String) value; 076 if (isJsonContent(strValue)) { 077 jg.writeFieldName(key); 078 jg.writeRawValue(strValue); 079 } else { 080 jg.writeStringField(key, strValue); 081 } 082 } else { 083 try { 084 jg.writeObjectField(key, ei.getSerializableValue()); 085 } catch (JsonMappingException e) { 086 log.error("No Serializer found.", e); 087 } 088 } 089 } else { 090 jg.writeNullField(key); 091 } 092 } 093 jg.writeEndObject(); 094 095 jg.writeEndObject(); 096 jg.flush(); 097 } 098 099 /** 100 * Helper method used to determine if a String field is actually nested JSON 101 * 102 * @since 7.4 103 */ 104 protected static boolean isJsonContent(String value) { 105 if (value != null) { 106 value = value.trim(); 107 if (value.startsWith("{") && value.endsWith("}")) { 108 return true; 109 } else if (value.startsWith("[") && value.endsWith("]")) { 110 return true; 111 } 112 } 113 return false; 114 } 115 116 protected static void writeField(JsonGenerator jg, String name, String value) throws IOException { 117 if (value == null) { 118 jg.writeNullField(name); 119 } else { 120 jg.writeStringField(name, value); 121 } 122 } 123 124 static class MapEntrySerializer extends JsonSerializer<Map> { 125 126 @Override 127 public void serialize(Map map, JsonGenerator jgen, SerializerProvider provider) throws IOException, 128 JsonProcessingException { 129 jgen.writeStartObject(); 130 for (Object key : map.keySet()) { 131 jgen.writeObjectField((String) key, map.get(key)); 132 } 133 jgen.writeEndObject(); 134 } 135 } 136 137 static class BinaryBlobEntrySerializer extends JsonSerializer<AbstractBlob> { 138 139 @Override 140 public void serialize(AbstractBlob blob, JsonGenerator jgen, SerializerProvider provider) 141 throws JsonGenerationException, IOException { 142 // Do not serizalize 143 jgen.writeNull(); 144 } 145 } 146 147}