diff --git a/pom.xml b/pom.xml
index ab81976..6e5a01f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -73,7 +73,7 @@
4.6
2.9.2
5.0.2
- 2.12.0
+ 2.28.2
B1606F22
true
diff --git a/src/main/java/com/github/jcustenborder/cef/CEFParserImpl.java b/src/main/java/com/github/jcustenborder/cef/CEFParserImpl.java
index 969a3b6..774273b 100644
--- a/src/main/java/com/github/jcustenborder/cef/CEFParserImpl.java
+++ b/src/main/java/com/github/jcustenborder/cef/CEFParserImpl.java
@@ -37,33 +37,19 @@ class CEFParserImpl implements CEFParser {
private static final Logger log = LoggerFactory.getLogger(CEFParserImpl.class);
private static final Pattern PATTERN_CEF_PREFIX = Pattern.compile("^((?.+)\\s+(?\\S+)\\s+).*?(?CEF:\\d+)|^.*?(?CEF:\\d+)");
private static final Pattern PATTERN_OSSEC_PREFIX = Pattern.compile("^(?[A-Za-z]+\\s+\\d{1,2}\\s+\\d{1,2}:\\d{2}:\\d{2})\\s+(?:ASM:)?(?CEF:\\d+)");
-
private static final Pattern PATTERN_CEF_MAIN = Pattern.compile("(? DATE_FORMATS = Arrays.asList(
- "MMM dd yyyy HH:mm:ss.SSS zzz",
- "MMM dd yyyy HH:mm:ss.SSS",
- "MMM dd yyyy HH:mm:ss zzz",
- "MMM dd yyyy HH:mm:ss",
- "MMM dd HH:mm:ss.SSS zzz",
- "MMM dd HH:mm:ss.SSS",
- "MMM dd HH:mm:ss zzz",
- "MMM dd HH:mm:ss",
- "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
- "yyyy-MM-dd'T'HH:mm:ssZ",
- "yyyy-MM-dd'T'HH:mm:ss.SSS zzz",
- "yyyy-MM-dd'T'HH:mm:ss zzz",
- "yyyy-MM-dd'T'HH:mm:ss.SSS ZZZ",
- "yyyy-MM-dd'T'HH:mm:ss ZZZ",
- "yyyy-MM-dd'T'HH:mm:ss.SSS XXX",
- "yyyy-MM-dd'T'HH:mm:ss XXX",
- "yyyy-MM-dd'T'HH:mm:ssXXX",
- "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
- );
+
final MessageFactory messageFactory;
+ private DateParser dateParser;
public CEFParserImpl(MessageFactory messageFactory) {
+ this(messageFactory, new DateParserImpl());
+ }
+
+ public CEFParserImpl(MessageFactory messageFactory, DateParser dateParser) {
this.messageFactory = messageFactory;
+ this.dateParser = dateParser;
}
@Override
@@ -98,8 +84,8 @@ public Message parse(final String event, final TimeZone timeZone, final Locale l
final int cefstartIndex;
if (isOssec) {
- final String df = "MMM dd HH:mm:ss";
- final SimpleDateFormat dateFormat = new SimpleDateFormat(df);
+ final String dateFormatPattern = "MMM dd HH:mm:ss";
+ final SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatPattern);
dateFormat.setTimeZone(timeZone);
final Date timestamp;
try {
@@ -110,7 +96,7 @@ public Message parse(final String event, final TimeZone timeZone, final Locale l
calendar.set(Calendar.YEAR, thisYear);
timestamp = calendar.getTime();
} catch (ParseException e) {
- log.trace("parse() - Could not parse '{}' with '{}'.", timestampText, df);
+ log.trace("parse() - Could not parse '{}' with '{}'.", timestampText, dateFormatPattern);
throw new IllegalStateException("Could not parse timestamp. '" + timestampText + "'");
}
@@ -119,49 +105,13 @@ public Message parse(final String event, final TimeZone timeZone, final Locale l
cefstartIndex = ossecPrefixMatcher.start("cs");
} else if (timestampText != null && !timestampText.isEmpty() && host != null && !host.isEmpty()) {
- Long longTimestamp = null;
+ final Date timestamp;
try {
- longTimestamp = Long.parseLong(timestampText);
- } catch (NumberFormatException e) {
- log.trace("Unable to parse timestamp '{}'", timestampText);
+ timestamp = this.dateParser.parseDate(timestampText, timeZone, locale);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalStateException(e);
}
- Date timestamp = null;
- if (null != longTimestamp) {
- log.trace("parse() - Detected timestamp is stored as a long.");
- timestamp = new Date(longTimestamp);
- } else {
- log.trace("parse() - Trying to parse the timestamp.");
- // SimpleDateFormat is not threadsafe so we have to create them each time.
- for (String df : DATE_FORMATS) {
- SimpleDateFormat dateFormat = new SimpleDateFormat(df, locale);
- dateFormat.setTimeZone(timeZone);
- try {
- log.trace("parse() - Trying to parse '{}' with format '{}'", timestampText, df);
- timestamp = dateFormat.parse(timestampText);
- final boolean alterYear = !df.contains("yyyy");
-
- if (alterYear) {
- log.trace("parse() - date format '{}' does not specify the year. Might need to alter the year.", df);
- Calendar calendar = Calendar.getInstance(timeZone);
- int thisYear = calendar.get(Calendar.YEAR);
- calendar.setTime(timestamp);
- final int year = calendar.get(Calendar.YEAR);
- if (1970 == year) {
- log.trace("parse() - altering year from {} to {}", year, thisYear);
- calendar.set(Calendar.YEAR, thisYear);
- timestamp = calendar.getTime();
- }
- }
- break;
- } catch (ParseException e) {
- log.trace("parse() - Could not parse '{}' with '{}'.", timestampText, df);
- }
- }
- if (null == timestamp) {
- throw new IllegalStateException("Could not parse timestamp. '" + timestampText + "'");
- }
- }
log.trace("parse() - timestamp = {}, {}", timestamp.getTime(), timestamp);
builder.timestamp(timestamp);
builder.host(host);
diff --git a/src/main/java/com/github/jcustenborder/cef/DateParser.java b/src/main/java/com/github/jcustenborder/cef/DateParser.java
new file mode 100644
index 0000000..abf0ee6
--- /dev/null
+++ b/src/main/java/com/github/jcustenborder/cef/DateParser.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright © 2017 Jeremy Custenborder (jcustenborder@gmail.com)
+ *
+ * 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 com.github.jcustenborder.cef;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * This interface attempts to parse a string containing a date and time.
+ */
+public interface DateParser {
+
+ /**
+ * Attempts to parse supplied dateTime
string.
+ * @param timestampText Text representing a valid timestamp
+ * @param timeZone A valid time zone.
+ * @param locale The parsed date
+ * @return
+ * @throws IllegalArgumentException
+ */
+ Date parseDate(final String timestampText, final TimeZone timeZone, final Locale locale);
+
+}
diff --git a/src/main/java/com/github/jcustenborder/cef/DateParserImpl.java b/src/main/java/com/github/jcustenborder/cef/DateParserImpl.java
new file mode 100644
index 0000000..981619e
--- /dev/null
+++ b/src/main/java/com/github/jcustenborder/cef/DateParserImpl.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright © 2017 Jeremy Custenborder (jcustenborder@gmail.com)
+ *
+ * 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 com.github.jcustenborder.cef;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DateParserImpl implements DateParser {
+ private static final List DATE_FORMATS = Arrays.asList(
+ "MMM dd yyyy HH:mm:ss.SSS zzz",
+ "MMM dd yyyy HH:mm:ss.SSS",
+ "MMM dd yyyy HH:mm:ss zzz",
+ "MMM dd yyyy HH:mm:ss",
+ "MMM dd HH:mm:ss.SSS zzz",
+ "MMM dd HH:mm:ss.SSS",
+ "MMM dd HH:mm:ss zzz",
+ "MMM dd HH:mm:ss",
+ "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
+ "yyyy-MM-dd'T'HH:mm:ssZ",
+ "yyyy-MM-dd'T'HH:mm:ss.SSS zzz",
+ "yyyy-MM-dd'T'HH:mm:ss zzz",
+ "yyyy-MM-dd'T'HH:mm:ss.SSS ZZZ",
+ "yyyy-MM-dd'T'HH:mm:ss ZZZ",
+ "yyyy-MM-dd'T'HH:mm:ss.SSS XXX",
+ "yyyy-MM-dd'T'HH:mm:ss XXX",
+ "yyyy-MM-dd'T'HH:mm:ssXXX",
+ "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
+ );
+ private static final Logger log = LoggerFactory.getLogger(DateParserImpl.class);
+
+ @Override
+ public Date parseDate(String timestampText, final TimeZone timeZone, final Locale locale) {
+ try {
+ Long longTimestamp = Long.parseLong(timestampText);
+ log.trace("parse() - Detected timestamp is stored as a long.");
+
+ return new Date(longTimestamp);
+ } catch (NumberFormatException e) {
+ log.trace("Unable to parse timestamp '{}'", timestampText);
+ }
+
+ log.trace("parse() - Trying to parse the timestamp.");
+ // SimpleDateFormat is not threadsafe so we have to create them each time.
+ for (String pattern : DATE_FORMATS) {
+ SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, locale);
+ dateFormat.setTimeZone(timeZone);
+ try {
+ log.trace("parse() - Trying to parse '{}' with format '{}'", timestampText, pattern);
+ Date timestamp = dateFormat.parse(timestampText);
+ final boolean alterYear = !pattern.contains("yyyy");
+
+ if (alterYear) {
+ log.trace("parse() - date format '{}' does not specify the year. Might need to alter the year.", pattern);
+ Calendar calendar = Calendar.getInstance(timeZone);
+ int thisYear = calendar.get(Calendar.YEAR);
+ calendar.setTime(timestamp);
+ final int year = calendar.get(Calendar.YEAR);
+ if (1970 == year) {
+ log.trace("parse() - altering year from {} to {}", year, thisYear);
+ calendar.set(Calendar.YEAR, thisYear);
+
+ return calendar.getTime();
+ }
+ }
+
+ return timestamp;
+ } catch (ParseException e) {
+ log.trace("parse() - Could not parse '{}' with '{}'.", timestampText, pattern);
+ }
+ }
+
+ throw new IllegalArgumentException("Could not parse timestamp. '" + timestampText + "'");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/jcustenborder/cef/MessageAssertions.java b/src/test/java/com/github/jcustenborder/cef/MessageAssertions.java
index 5dd3213..dc3ae1a 100644
--- a/src/test/java/com/github/jcustenborder/cef/MessageAssertions.java
+++ b/src/test/java/com/github/jcustenborder/cef/MessageAssertions.java
@@ -19,6 +19,8 @@
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
+import java.util.Date;
+
public class MessageAssertions {
public static void assertMessage(Message expected, Message actual) {
if (null == expected) {
@@ -27,6 +29,14 @@ public static void assertMessage(Message expected, Message actual) {
assertNotNull(actual, "actual should not be null.");
}
+ // Force actual year to match the year that the tests were recorded
+ final Date expectedTimestamp = expected.timestamp(), actualTimestamp = actual.timestamp();
+ if (expectedTimestamp != null && actualTimestamp != null
+ && expectedTimestamp.getYear() != actualTimestamp.getYear()) {
+ assertEquals(actualTimestamp.getYear(), new Date().getYear(), "year does not match");
+ actual.timestamp().setYear(expected.timestamp().getYear());
+ }
+
assertEquals(expected.timestamp(), actual.timestamp(), "timestamp() does not match");
assertEquals(expected.host(), actual.host(), "host() does not match");
assertEquals(expected.cefVersion(), actual.cefVersion(), "cefVersion() does not match");