org.openhealthtools.openatna.syslog.protocol.ProtocolMessageFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.openhealthtools.openatna.syslog.protocol.ProtocolMessageFactory.java

Source

/**
 *  Copyright (c) 2009-2011 University of Cardiff and others
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 *  implied. See the License for the specific language governing
 *  permissions and limitations under the License.
 *
 *  Contributors:
 *    University of Cardiff - initial API and implementation
 *    -
 */

package org.openhealthtools.openatna.syslog.protocol;

import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openhealthtools.openatna.syslog.Constants;
import org.openhealthtools.openatna.syslog.LogMessage;
import org.openhealthtools.openatna.syslog.SyslogException;
import org.openhealthtools.openatna.syslog.SyslogMessage;
import org.openhealthtools.openatna.syslog.SyslogMessageFactory;

/**
 * generates RFC 5424 messages from a stream.
 *
 * @author Andrew Harrison
 * @version $Revision:$
 * @created Aug 18, 2009: 12:42:04 PM
 * @date $Date:$ modified by $Author:$
 */

public class ProtocolMessageFactory extends SyslogMessageFactory {

    static Log log = LogFactory.getLog("org.openhealthtools.openatna.syslog.protocol.ProtocolMessageFactory");

    public static final char VERSION_CHAR = '1';

    public static final Pattern DATE = Pattern.compile(
            "(\\d{4})-(\\d{2})-(\\d{2})[T](\\d{2}):(\\d{2}):(\\d{2})(\\.(\\d{1,6}))?([+-](\\d{2}):(\\d{2}))?([Z])?");

    /**
     * reads the priority value and positions the stream at the space after the version number.
     * This reads up to 9 characters to read the priority and version and the following space.
     *
     * @param in
     * @return
     * @throws org.openhealthtools.openatna.syslog.SyslogException
     *
     */
    private int readPriority(InputStream in) throws SyslogException {
        try {
            int max = 9;
            int count = 0;
            String pri = "";
            boolean afterOpen = false;
            while (count < max) {
                char c = (char) in.read();
                count++;
                switch (c) {
                case '<':
                    afterOpen = true;
                    break;
                case '>':
                    int priority = Integer.parseInt(pri);
                    if (!afterOpen || priority < 0 || priority > 191) {
                        throw new SyslogException("syntax error");
                    }
                    c = (char) in.read(); // read version
                    count++;
                    if (c != ProtocolMessageFactory.VERSION_CHAR) {
                        throw new SyslogException("unsupported version");
                    }
                    c = (char) in.read(); // read space
                    count++;
                    if (c != ' ') {
                        throw new SyslogException("not a space");
                    }
                    return priority;
                default:
                    if (afterOpen) {
                        pri += c;
                    }
                    break;
                }
            }
        } catch (Exception e) {
            throw new SyslogException(e);
        }
        throw new SyslogException("too many characters");
    }

    /**
     * This reads up to 256 characters to read headers (excluding SDs). This limit is arbitrary.
     * It is imposed to reduce the risk
     * of badly formed or malicious messages from using too many resources.
     *
     * @param in
     * @return
     * @throws SyslogException
     */
    public SyslogMessage read(InputStream in) throws SyslogException {
        try {
            PushbackInputStream pin = new PushbackInputStream(in, 5);
            int priority = readPriority(pin);
            int facility;
            int severity;
            byte c;
            int spaces = 5;
            int count = 0;
            ByteBuffer buff = ByteBuffer.wrap(new byte[256]);

            String timestamp = null;
            String host = "-";
            String app = "-";
            String proc = "-";
            String mid = "-";
            int max = 256;
            int curr = 0;

            while (count < spaces && curr < max) {
                c = (byte) pin.read();
                curr++;
                if (c == ' ') {
                    count++;
                    String currHeader = new String(buff.array(), 0, buff.position(), Constants.ENC_UTF8);
                    buff.clear();
                    switch (count) {
                    case 1:
                        timestamp = currHeader;
                        break;
                    case 2:
                        host = currHeader;
                        break;
                    case 3:
                        app = currHeader;
                        break;
                    case 4:
                        proc = currHeader;
                        break;
                    case 5:
                        mid = currHeader;
                        break;
                    }
                } else {
                    buff.put(c);
                }
            }
            if (timestamp == null) {
                throw new SyslogException("no timestamp defined");
            }

            c = (byte) pin.read();
            List<StructuredElement> els = new ArrayList<StructuredElement>();
            if (c == '-') {
                c = (byte) pin.read();
                if (c != ' ') {
                    throw new SyslogException("not a space");
                }
            } else if (c == '[') {
                pin.unread(c);
                els = StructuredElement.parse(pin);
            } else {
                throw new SyslogException("Illegal Structured data");
            }
            LogMessage logMessage = getLogMessage(mid);
            String encoding = readBom(pin, logMessage.getExpectedEncoding());
            logMessage.read(pin, encoding);
            facility = priority / 8;
            severity = priority % 8;
            ProtocolMessage sm = new ProtocolMessage(facility, severity, timestamp, host, logMessage, app, mid,
                    proc);
            for (StructuredElement el : els) {
                sm.addStructuredElement(el);
            }
            return sm;
        } catch (IOException e) {
            e.printStackTrace();
            throw new SyslogException(e);
        }
    }

    /**
     * Parse the serialized string form into a java.util.Date
     * NOTE: This only supports millisecond precision. decimals greater than 3 are truncated
     *
     * @param date The serialized string form of the date
     * @return The created java.util.Date
     */
    public static Date createDate(String date) throws SyslogException {
        Matcher m = DATE.matcher(date);
        if (m.find()) {

            log.debug("date groups{" + m.group(1) + "}{" + m.group(2) + "}{" + m.group(3) + "}{" + m.group(4) + "}{"
                    + m.group(5) + "}{" + m.group(6) + "}{" + m.group(7) + "}{" + m.group(8) + "}{" + m.group(9)
                    + "}{" + m.group(10) + "}{" + m.group(11) + "}{" + m.group(12) + "}");
            Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
            int hoff = 0, moff = 0, doff = -1;
            if (m.group(9) != null) {
                doff = m.group(9).equals("-") ? 1 : -1;
                hoff = doff * (m.group(10) != null ? Integer.parseInt(m.group(10)) : 0);
                moff = doff * (m.group(11) != null ? Integer.parseInt(m.group(11)) : 0);
            } else {
                /*
                TODO
                if (m.group(12) == null) {
                throw new SyslogException("Invalid Date Format");
                }*/
            }
            c.set(Calendar.YEAR, Integer.parseInt(m.group(1)));
            c.set(Calendar.MONTH, m.group(2) != null ? Integer.parseInt(m.group(2)) - 1 : 0);
            c.set(Calendar.DATE, m.group(3) != null ? Integer.parseInt(m.group(3)) : 1);
            c.set(Calendar.HOUR_OF_DAY, m.group(4) != null ? Integer.parseInt(m.group(4)) + hoff : 0);
            c.set(Calendar.MINUTE, m.group(5) != null ? Integer.parseInt(m.group(5)) + moff : 0);
            c.set(Calendar.SECOND, m.group(6) != null ? Integer.parseInt(m.group(6)) : 0);
            String millis = m.group(8);
            if (millis == null) {
                millis = "0";
            }
            if (millis.length() > 3) {
                millis = millis.substring(0, 3);
            }
            c.set(Calendar.MILLISECOND, Integer.parseInt(millis));
            return c.getTime();
        } else {
            throw new SyslogException("Invalid Date Format");
        }
    }

    /**
     * Create the serialized string form from a java.util.Date
     *
     * @param date A java.util.Date
     * @return The serialized string form of the date
     */
    public static String formatDate(Date date) {
        StringBuilder sb = new StringBuilder();
        Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        c.setTime(date);
        sb.append(c.get(Calendar.YEAR));
        sb.append('-');
        int f = c.get(Calendar.MONTH);
        if (f < 9) {
            sb.append('0');
        }
        sb.append(f + 1);
        sb.append('-');
        f = c.get(Calendar.DATE);
        if (f < 10) {
            sb.append('0');
        }
        sb.append(f);
        sb.append('T');
        f = c.get(Calendar.HOUR_OF_DAY);
        if (f < 10) {
            sb.append('0');
        }
        sb.append(f);
        sb.append(':');
        f = c.get(Calendar.MINUTE);
        if (f < 10) {
            sb.append('0');
        }
        sb.append(f);
        sb.append(':');
        f = c.get(Calendar.SECOND);
        if (f < 10) {
            sb.append('0');
        }
        sb.append(f);
        sb.append('.');
        f = c.get(Calendar.MILLISECOND);
        if (f < 100) {
            sb.append('0');
        }
        if (f < 10) {
            sb.append('0');
        }
        sb.append(f);
        sb.append('Z');
        return sb.toString();
    }

}