org.cesecore.certificates.ocsp.logging.PatternLogger.java Source code

Java tutorial

Introduction

Here is the source code for org.cesecore.certificates.ocsp.logging.PatternLogger.java

Source

/*************************************************************************
 *                                                                       *
 *  CESeCore: CE Security Core                                           *
 *                                                                       *
 *  This software is free software; you can redistribute it and/or       *
 *  modify it under the terms of the GNU Lesser General Public           *
 *  License as published by the Free Software Foundation; either         *
 *  version 2.1 of the License, or any later version.                    *
 *                                                                       *
 *  See terms of license at gnu.org.                                     *
 *                                                                       *
 *************************************************************************/

package org.cesecore.certificates.ocsp.logging;

import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.FastDateFormat;
import org.apache.log4j.Logger;
import org.bouncycastle.util.encoders.Hex;

/**
 * This class can be extended to create highly configurable log classes. Values that are to be logged are stored in a Hashmap and the output is
 * configured using a Java.util.regex.Matcher and a sortString. The extending classes also need to supply a Logger and a String specifying how to log
 * Dates.
 * 
 * Use paramPut(String key, String value) to add values, Use writeln() to log all the stored values and then use flush() to store them to file.
 * 
 * Roughly based on PatternLogger.java 8663 2010-02-17 10:42:41Z anatom from EJBCA
 * 
 * @version $Id: PatternLogger.java 20599 2015-01-26 16:31:04Z jeklund $
 */
public abstract class PatternLogger implements Serializable {

    private static final long serialVersionUID = 8486004615125959046L;
    public static final String LOG_TIME = "LOG_TIME";// The Date and time the request.
    public static final String LOG_ID = "LOG_ID"; // An integer identifying a log entry for a request
    public static final String SESSION_ID = "SESSION_ID"; // A random 32 bit number identifying a log entry for a request

    public static final String REPLY_TIME = "REPLY_TIME";

    /**
     * Hash of the issuer DN
     */
    public static final String ISSUER_NAME_HASH = "ISSUER_NAME_HASH";
    /**
     * The public key of the issuer of a requested certificate
     */
    public static final String ISSUER_KEY = "ISSUER_KEY";
    /**
     * Serial number of the requested certificate.
     */
    public static final String SERIAL_NOHEX = "SERIAL_NOHEX";
    /**
     * IP of the client making the request
     */
    public static final String CLIENT_IP = "CLIENT_IP";
    /**
     * The status of the OCSP-Request. SUCCESSFUL = 0;MALFORMED_REQUEST = 1;INTERNAL_ERROR = 2;
     */
    public static final String STATUS = "STATUS";

    /**
     * PROCESS_TIME is a marker that is used to record the total time a request takes to process, excluding reading the request. It is replaced with
     * the correct value when the log entry is written. the time measurement start when this param is set in the logger with:
     * 
     * <pre>
     * ocspTransactionLogger(PROCESS_TIME, PROCESS_TIME);
     * </pre>
     * 
     * This means that this variable can be used to measure any time you want to measure in your code.
     * 
     */
    public static final String PROCESS_TIME = "PROCESS_TIME";

    private final Map<String, String> valuepairs = new HashMap<String, String>();
    private final String matchString;
    private final String matchPattern;
    // Matcher is not Serializable
    private transient Matcher m;
    private final String orderString;
    private final Date startTime;
    private Date startProcessTime = null;
    private boolean doLogging;
    final private Class<?> loggerClass;
    // Logger is not Serializable
    private transient Logger logger;

    // for writing the output
    private transient StringWriter sw;
    private transient PrintWriter pw;

    /**
     * @param doLogging
     *            True if you want this pattern logger to do anything upon flush.
     * @param logger
     *            The Class to create Log4j logger for, to log to if doLogging is true
     * @param matchPattern
     *            A string to create a matcher that is used together with matchString to determine how output is formatted
     * @param matchString
     *            A string that matches the pattern in m and specifies the order in which values are logged by the logger
     * @param logger
     *            A log4j Logger that is used for output
     * @param logDateFormat
     *            A string that specifies how the log-time is formatted
     * @param timeZone
     */
    protected PatternLogger(boolean doLogging, Class<?> loggerClass, String matchPattern, String matchString,
            String logDateFormat, String timeZone) {
        this.doLogging = doLogging;
        this.matchString = matchString;
        this.matchPattern = matchPattern;
        this.orderString = matchString;
        this.loggerClass = loggerClass;
        this.startTime = new Date();
        final FastDateFormat dateformat;
        if (timeZone == null) {
            dateformat = FastDateFormat.getInstance(logDateFormat);
        } else {
            dateformat = FastDateFormat.getInstance(logDateFormat, TimeZone.getTimeZone(timeZone));
        }
        paramPut(LOG_TIME, dateformat.format(new Date()));
        this.paramPut(REPLY_TIME, REPLY_TIME);
        this.paramPut(LOG_ID, "0");
    }

    private Matcher getMatcher() {
        if (this.m == null) {
            // We have to instantiate the Matcher in the class and can not have it as an instance variable.
            // This is because we are sending this object to a remote EJB (at least in system tests)
            this.m = Pattern.compile(matchPattern).matcher(matchString);
        }
        return this.m;
    }

    private Logger getLogger() {
        if (this.logger == null) {
            // We have to instantiate the logger in the class and can not have it as an instance variable.
            // This is because we are sending this object to a remote EJB (at least in system tests) and org.apache.log4j.Logger is not serializable.
            this.logger = Logger.getLogger(loggerClass);
        }
        return this.logger;
    }

    private PrintWriter getPrintWriter() {
        if (this.pw == null) {
            this.sw = new StringWriter();
            this.pw = new PrintWriter(this.sw);
        }
        return pw;
    }

    /**
     * 
     * @return output to be logged
     */
    private String interpolate() {
        final StringBuffer sb = new StringBuffer(this.orderString.length());
        final Matcher matcher = getMatcher();
        matcher.reset();
        while (matcher.find()) {
            // when the pattern is ${identifier}, group 0 is 'identifier'
            final String key = matcher.group(1);
            final String value = this.valuepairs.get(key);

            // if the pattern does exists, replace it by its value
            // otherwise keep the pattern ( it is group(0) )
            if (value != null) {
                matcher.appendReplacement(sb, value);
            } else {
                // I'm doing this to avoid the backreference problem as there will be a $
                // if I replace directly with the group 0 (which is also a pattern)
                matcher.appendReplacement(sb, "");
                final String unknown = matcher.group(0);
                sb.append(unknown);
            }
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * Hex-encodes the bytes.
     * method that makes sure that a "" is inserted instead of null
     * @param key
     * @param value
     */
    public void paramPut(String key, byte[] value) {
        paramPut(key, new String(Hex.encode(value)));
    }

    /**
     * method that makes sure that a "" is inserted instead of null
     * @param key
     * @param value
     */
    public void paramPut(String key, String value) {
        // logger.debug("paramput: "+ key+ ";" +value +";" +valuepairs.toString());
        if (value == null) {
            this.valuepairs.put(key, "");
        } else {
            this.valuepairs.put(key, value);
        }
        if (StringUtils.equals(key, PROCESS_TIME)) {
            startProcessTime = new Date();
        }
    }

    /**
     * method that makes sure that a "" is inserted instead of null
     * @param key
     * @param value
     */
    public void paramPut(String key, Integer value) {
        if (value == null) {
            this.valuepairs.put(key, "");
        } else {
            this.valuepairs.put(key, value.toString());
        }
    }

    /**
     * Method used for creating a log row of all added values
     */
    public void writeln() {
        if (doLogging) {
            getPrintWriter().println(interpolate());
        }
    }

    /**
     * Writes all the rows created by writeln() to the Logger
     */
    public void flush() {
        if (doLogging) {
            getPrintWriter().flush();
            String output = this.sw.toString();
            output = output.replaceAll(REPLY_TIME, String.valueOf(new Date().getTime() - this.startTime.getTime()));
            if (startProcessTime != null) {
                output = output.replaceAll(PROCESS_TIME,
                        String.valueOf(new Date().getTime() - this.startProcessTime.getTime()));
            }
            //Remove an extra linebreak between flushes.
            if (output.endsWith(System.getProperty("line.separator"))) {
                output = output.substring(0, output.length() - 1);
            }
            getLogger().debug(output); // Finally output the log row to the logging device
        }
    }

    /** @return true if this logger is enabled */
    public boolean isEnabled() {
        return doLogging;
    }
}