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