/* * Copyright (c) 2012 EMC Corporation * All Rights Reserved */ package com.emc.storageos.api.service.impl.resource.utils; import java.io.BufferedWriter; import java.io.IOException; import java.io.Writer; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.map.AnnotationIntrospector; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion; import org.codehaus.jackson.xc.JaxbAnnotationIntrospector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.security.audit.AuditLogUtils; import com.emc.storageos.db.client.model.AuditLog; import java.util.Locale; import java.util.ResourceBundle; /** * A JSON auditlog marshaler based on Jersey-Jackson API */ public class JSONAuditLogMarshaller implements AuditLogMarshaller { final private Logger _logger = LoggerFactory.getLogger(JSONAuditLogMarshaller.class); private static volatile Locale locale = null; private static volatile ResourceBundle resb = null; private ObjectMapper _mapper = null; /** * internal count of auditlogs streamed from all threads. */ private final AtomicLong _count = new AtomicLong(0); /** * atomic boolean indicating whether the very first auditlog has been streamed. * This is important since in JSON format, the first element is streamed * differently from all the rest elements. */ private final AtomicBoolean _firstWritten = new AtomicBoolean(false); public JSONAuditLogMarshaller() { _mapper = new ObjectMapper(); AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(); _mapper.getDeserializationConfig().withAnnotationIntrospector(introspector); _mapper.getSerializationConfig().withAnnotationIntrospector(introspector); _mapper.setSerializationInclusion(Inclusion.NON_NULL); } @Override public void header(Writer writer) throws MarshallingExcetion { BufferedWriter ow = ((BufferedWriter) writer); try { ow.write("{ \"auditlogs\": ["); } catch (IOException e) { throw new MarshallingExcetion("JSON head Streaming failed", e); } } @Override public void marshal(AuditLog auditlog, Writer writer) throws MarshallingExcetion { marshal(auditlog, writer, null); } public boolean marshal(AuditLog auditlog, Writer writer, String keyword) throws MarshallingExcetion { BufferedWriter ow = ((BufferedWriter) writer); if (auditlog == null) { _logger.warn("null auditlog dropped"); return false; } return matchAndwriteOneAuditLog(ow, auditlog, null); } /** * Match if auditlog description contains expected keyword ,Stream out the auditlog if * matched,Otherwise ignore this one piece of auditlog. * Since the streaming format for the first auditlog is slightly different from all the * rest of auditlogs, this method uses a boolean to block auditlog being streamed until * the first auditlog is streamed by a thread. * * @param writer * - the output writer to stream the auditlog. * @param auditlog * - the auditlog to be streamed. * @param keyword * - keyword if audit log description contain * @return true if the Auditlog outputted to the writer,else false * @throws MarshallingExcetion * - failure during streaming. */ private boolean matchAndwriteOneAuditLog(BufferedWriter writer, AuditLog auditlog,String keyword) throws MarshallingExcetion { try { AuditLogUtils.resetDesc(auditlog, resb); if (AuditLogUtils.isKeywordContained(auditlog,keyword)) { if (_count.getAndIncrement() > 0) { while (!_firstWritten.get()) { // wait until the thread which writes the first auditlog is done try { Thread.sleep(1); } catch (InterruptedException e) { _logger.warn("Sleep interrupted"); } } writer.write("," + _mapper.writeValueAsString(auditlog)); } else { writer.write(_mapper.writeValueAsString(auditlog)); _firstWritten.set(true); } return true; } _logger.debug("{} filter out by description keyword {}",auditlog.getDescription(),keyword); return false; } catch (JsonGenerationException e) { throw new MarshallingExcetion("JSON Generation Error", e); } catch (JsonMappingException e) { throw new MarshallingExcetion("JSON Mapping Error", e); } catch (IOException e) { throw new MarshallingExcetion("JSON streaming failed: ", e); } } @Override public void tailer(Writer writer) throws MarshallingExcetion { BufferedWriter ow = ((BufferedWriter) writer); try { ow.write("] }"); } catch (IOException e) { throw new MarshallingExcetion("JSON tail Streaming failed", e); } _logger.info("{} JSON auditlogs streamed", _count); } @Override public void setLang(String lang) { String language, country; String[] array = lang.split("_"); if (array.length != 2) { language = "en"; country = "US"; } else { language = array[0]; country = array[1]; } locale = new Locale(language, country); resb = ResourceBundle.getBundle("SDSAuditlogRes", locale); } }