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.joda.time.DateTime; 035import org.joda.time.format.ISODateTimeFormat; 036import org.nuxeo.ecm.core.api.impl.blob.AbstractBlob; 037import org.nuxeo.ecm.platform.audit.api.ExtendedInfo; 038import org.nuxeo.ecm.platform.audit.api.LogEntry; 039 040import com.fasterxml.jackson.core.JsonProcessingException; 041 042public class AuditEntryJSONWriter { 043 044 protected static final Log log = LogFactory.getLog(AuditEntryJSONWriter.class); 045 046 public static void asJSON(JsonGenerator jg, LogEntry logEntry) throws IOException { 047 ObjectMapper objectMapper = new ObjectMapper(); 048 SimpleModule module = new SimpleModule("esAuditJson", org.codehaus.jackson.Version.unknownVersion()); 049 module.addSerializer(Map.class, new MapEntrySerializer()); 050 module.addSerializer(AbstractBlob.class, new BinaryBlobEntrySerializer()); 051 objectMapper.registerModule(module); 052 jg.setCodec(objectMapper); 053 054 jg.writeStartObject(); 055 jg.writeStringField("entity-type", "logEntry"); 056 057 writeField(jg, "category", logEntry.getCategory()); 058 writeField(jg, "principalName", logEntry.getPrincipalName()); 059 writeField(jg, "comment", logEntry.getComment()); 060 writeField(jg, "docLifeCycle", logEntry.getDocLifeCycle()); 061 writeField(jg, "docPath", logEntry.getDocPath()); 062 writeField(jg, "docType", logEntry.getDocType()); 063 writeField(jg, "docUUID", logEntry.getDocUUID()); 064 writeField(jg, "eventId", logEntry.getEventId()); 065 writeField(jg, "repositoryId", logEntry.getRepositoryId()); 066 jg.writeStringField("eventDate", ISODateTimeFormat.dateTime().print(new DateTime(logEntry.getEventDate()))); 067 jg.writeNumberField("id", logEntry.getId()); 068 jg.writeStringField("logDate", ISODateTimeFormat.dateTime().print(new DateTime(logEntry.getLogDate()))); 069 Map<String, ExtendedInfo> extended = logEntry.getExtendedInfos(); 070 jg.writeObjectFieldStart("extended"); 071 for (String key : extended.keySet()) { 072 ExtendedInfo ei = extended.get(key); 073 if (ei != null && ei.getSerializableValue() != null) { 074 Serializable value = ei.getSerializableValue(); 075 if (value instanceof String) { 076 String strValue = (String) value; 077 if (isJsonContent(strValue)) { 078 jg.writeFieldName(key); 079 jg.writeRawValue(strValue); 080 } else { 081 jg.writeStringField(key, strValue); 082 } 083 } else { 084 try { 085 jg.writeObjectField(key, ei.getSerializableValue()); 086 } catch (JsonMappingException e) { 087 log.error("No Serializer found.", e); 088 } 089 } 090 } else { 091 jg.writeNullField(key); 092 } 093 } 094 jg.writeEndObject(); 095 096 jg.writeEndObject(); 097 jg.flush(); 098 } 099 100 /** 101 * Helper method used to determine if a String field is actually nested JSON 102 * 103 * @since 7.4 104 */ 105 protected static boolean isJsonContent(String value) { 106 if (value != null) { 107 value = value.trim(); 108 if (value.startsWith("{") && value.endsWith("}")) { 109 return true; 110 } else if (value.startsWith("[") && value.endsWith("]")) { 111 return true; 112 } 113 } 114 return false; 115 } 116 117 protected static void writeField(JsonGenerator jg, String name, String value) throws IOException { 118 if (value == null) { 119 jg.writeNullField(name); 120 } else { 121 jg.writeStringField(name, value); 122 } 123 } 124 125 static class MapEntrySerializer extends JsonSerializer<Map> { 126 127 @Override 128 public void serialize(Map map, JsonGenerator jgen, SerializerProvider provider) throws IOException, 129 JsonProcessingException { 130 jgen.writeStartObject(); 131 for (Object key : map.keySet()) { 132 jgen.writeObjectField((String) key, map.get(key)); 133 } 134 jgen.writeEndObject(); 135 } 136 } 137 138 static class BinaryBlobEntrySerializer extends JsonSerializer<AbstractBlob> { 139 140 @Override 141 public void serialize(AbstractBlob blob, JsonGenerator jgen, SerializerProvider provider) 142 throws JsonGenerationException, IOException { 143 // Do not serizalize 144 jgen.writeNull(); 145 } 146 } 147 148}