/*
* JBoss, Home of Professional Open Source
* Copyright 2014, JBoss Inc., and individual contributors as indicated
* by the @authors tag.
*
* 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.
*/
package org.jboss.as.test.syslogserver;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.jboss.logging.Logger;
import org.productivity.java.syslog4j.server.SyslogServerEventIF;
/**
* Simple implementation of rfc5424 syslog message format (c.f. http://tools.ietf.org/html/rfc5424#section-6).
*
* @author Josef Cacek
*/
public class Rfc5424SyslogEvent implements SyslogServerEventIF {
private static final char SP = ' ';
private static final String CHARSET = "UTF-8";
private static final String NIL = "-";
private static final byte[] UTF_8_BOM = { (byte) 0xef, (byte) 0xbb, (byte) 0xbf };
private static Logger LOGGER = Logger.getLogger(Rfc5424SyslogEvent.class);
private final byte[] raw;
private final String prioVersion;
private final int facility;
private final int level;
private final int version;
private final String timestamp;
private final String host;
private final String appName;
private final String procId;
private final String msgId;
private final String structuredData;
private final String message;
public Rfc5424SyslogEvent(byte[] data, int offset, int length) {
raw = new byte[length - offset];
System.arraycopy(data, offset, raw, 0, length);
int startPos = 0;
int endPos = -1;
endPos = searchChar(raw, startPos, SP);
prioVersion = getString(raw, startPos, endPos);
startPos = endPos + 1;
endPos = searchChar(raw, startPos, ' ');
timestamp = getString(raw, startPos, endPos);
startPos = endPos + 1;
endPos = searchChar(raw, startPos, ' ');
host = getString(raw, startPos, endPos);
startPos = endPos + 1;
endPos = searchChar(raw, startPos, ' ');
appName = getString(raw, startPos, endPos);
startPos = endPos + 1;
endPos = searchChar(raw, startPos, ' ');
procId = getString(raw, startPos, endPos);
startPos = endPos + 1;
endPos = searchChar(raw, startPos, ' ');
msgId = getString(raw, startPos, endPos);
startPos = endPos + 1;
if (raw[startPos] == '[') {
endPos = searchChar(raw, startPos, ']') + 1;
} else {
endPos = searchChar(raw, startPos, ' ');
if (endPos == -1)
endPos = raw.length;
}
structuredData = getString(raw, startPos, endPos);
startPos = endPos + 1;
if (startPos < raw.length) {
if (startPos + 3 < raw.length && raw[startPos] == UTF_8_BOM[0] && raw[startPos + 1] == UTF_8_BOM[1]
&& raw[startPos + 2] == UTF_8_BOM[2]) {
startPos += 3;
}
message = getString(raw, startPos, raw.length);
} else {
message = null;
}
// parse priority and version
endPos = prioVersion.indexOf(">");
final String priorityStr = prioVersion.substring(1, endPos);
int priority = 0;
try {
priority = Integer.parseInt(priorityStr);
} catch (NumberFormatException nfe) {
LOGGER.error("Can't parse priority");
}
level = priority & 7;
facility = (priority - level) >> 3;
startPos = endPos + 1;
int ver = 0;
if (startPos < prioVersion.length()) {
try {
ver = Integer.parseInt(prioVersion.substring(startPos));
} catch (NumberFormatException nfe) {
LOGGER.error("Can't parse version");
ver = -1;
}
}
version = ver;
}
private String getString(byte[] data, int startPos, int endPos) {
try {
return new String(data, startPos, endPos - startPos, CHARSET);
} catch (UnsupportedEncodingException e) {
LOGGER.error("Unsupported encoding", e);
}
return "";
}
/**
* Try to find a character in given byte array, starting from startPos.
*
* @param data
* @param startPos
* @param c
* @return position of the character or -1 if not found
*/
private int searchChar(byte[] data, int startPos, char c) {
for (int i = startPos; i < data.length; i++) {
if (data[i] == c) {
return i;
}
}
return -1;
}
public String getPrioVersion() {
return prioVersion;
}
public int getFacility() {
return facility;
}
public int getLevel() {
return level;
}
public int getVersion() {
return version;
}
public String getTimestamp() {
return timestamp;
}
public String getHost() {
return host;
}
public String getAppName() {
return appName;
}
public String getProcId() {
return procId;
}
public String getMsgId() {
return msgId;
}
public String getStructuredData() {
return structuredData;
}
public String getMessage() {
return message;
}
public String getCharSet() {
return CHARSET;
}
public byte[] getRaw() {
return raw;
}
public Date getDate() {
if (NIL.equals(timestamp)) {
return null;
}
String fixTz = timestamp.replace("Z", "+00:00");
final int tzSeparatorPos = fixTz.lastIndexOf(":");
fixTz = fixTz.substring(0, tzSeparatorPos) + fixTz.substring(tzSeparatorPos + 1);
try {
return new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZ").parse(fixTz);
} catch (ParseException e) {
LOGGER.error("Unable to parse date " + timestamp, e);
}
return null;
}
public void setCharSet(String charSet) {
}
public void setFacility(int facility) {
}
public void setDate(Date date) {
}
public void setLevel(int level) {
}
public void setHost(String host) {
}
public void setMessage(String message) {
}
@Override
public String toString() {
return "Rfc5424SyslogEvent [prioVersion=" + prioVersion + ", facility=" + facility + ", level=" + level + ", version="
+ version + ", timestamp=" + timestamp + ", host=" + host + ", appName=" + appName + ", procId=" + procId
+ ", msgId=" + msgId + ", structuredData=" + structuredData + ", message=" + message + "]";
}
}