INT-4182: Use thread-safe DateTimeFormatter

JIRA: https://jira.spring.io/browse/INT-4182

To avoid extra allocation for the `SimpleDateFormat` use a new Java 8 `DateTimeFormatter` based on new `Temporal` abstraction

Leave test-cases as is to save some time for other tasks

Fix RedisLockRegistry for the proper formatter and ZoneId
This commit is contained in:
Artem Bilan
2016-12-13 16:09:33 -05:00
committed by Gary Russell
parent a0845b1caf
commit 3d433ca3f8
3 changed files with 37 additions and 47 deletions

View File

@@ -17,13 +17,12 @@
package org.springframework.integration.transformer;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.sql.Date;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -44,7 +43,7 @@ import org.springframework.util.StringUtils;
*/
public class SyslogToMapTransformer extends AbstractPayloadTransformer<Object, Map<String, ?>> {
private static final BlockingQueue<SimpleDateFormat> dateFormats = new LinkedBlockingQueue<SimpleDateFormat>();
private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MMM dd HH:mm:ss");
public static final String FACILITY = "FACILITY";
@@ -90,10 +89,6 @@ public class SyslogToMapTransformer extends AbstractPayloadTransformer<Object, M
private Map<String, ?> transform(String payload) {
Map<String, Object> map = new LinkedHashMap<String, Object>();
Matcher matcher = this.pattern.matcher(payload);
SimpleDateFormat dateFormat = dateFormats.poll();
if (dateFormat == null) {
dateFormat = new SimpleDateFormat("MMM dd HH:mm:ss");
}
if (matcher.matches()) {
try {
String facilityString = matcher.group(1);
@@ -103,14 +98,12 @@ public class SyslogToMapTransformer extends AbstractPayloadTransformer<Object, M
map.put(FACILITY, facility);
map.put(SEVERITY, severity);
String timestamp = matcher.group(2);
Date date;
try {
date = dateFormat.parse(timestamp);
dateFormats.offer(dateFormat);
LocalDate localDate = this.dateTimeFormatter.parse(timestamp, LocalDate::from);
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
calendar.setTime(date);
calendar.setTime(Date.valueOf(localDate));
/*
* syslog date doesn't include a year so we
* need to insert the current year - adjusted

View File

@@ -19,10 +19,12 @@ package org.springframework.integration.http.support;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -35,11 +37,9 @@ import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TimeZone;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
@@ -67,15 +67,13 @@ import org.springframework.util.StringUtils;
* @author Gunnar Hillert
* @author Gary Russell
* @author Artem Bilan
*
* @since 2.0
*/
public class DefaultHttpHeaderMapper implements HeaderMapper<HttpHeaders>, BeanFactoryAware, InitializingBean {
private static final Log logger = LogFactory.getLog(DefaultHttpHeaderMapper.class);
private volatile ConversionService conversionService;
private volatile BeanFactory beanFactory;
private static final String ACCEPT = "Accept";
@@ -212,7 +210,7 @@ public class DefaultHttpHeaderMapper implements HeaderMapper<HttpHeaders>, BeanF
WARNING
};
private static final Set<String> HTTP_REQUEST_HEADER_NAMES_LOWER = new HashSet<String>();
private static final Set<String> HTTP_REQUEST_HEADER_NAMES_LOWER = new HashSet<>();
private static final String[] HTTP_RESPONSE_HEADER_NAMES = new String[] {
ACCEPT_RANGES,
@@ -260,14 +258,12 @@ public class DefaultHttpHeaderMapper implements HeaderMapper<HttpHeaders>, BeanF
public static final String HTTP_RESPONSE_HEADER_NAME_PATTERN = "HTTP_RESPONSE_HEADERS";
// Copy of 'org.springframework.http.HttpHeaders#DATE_FORMATS'
private static final String[] DATE_FORMATS = new String[] {
"EEE, dd MMM yyyy HH:mm:ss zzz",
"EEE, dd-MMM-yy HH:mm:ss zzz",
"EEE MMM dd HH:mm:ss yyyy"
private static final DateTimeFormatter[] DATE_FORMATS = new DateTimeFormatter[] {
DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US).withZone(ZoneId.of("GMT")),
DateTimeFormatter.ofPattern("EEE, dd-MMM-yy HH:mm:ss zzz", Locale.US).withZone(ZoneId.of("GMT")),
DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy", Locale.US).withZone(ZoneId.of("GMT"))
};
private static TimeZone GMT = TimeZone.getTimeZone("GMT");
static {
for (String header : HTTP_REQUEST_HEADER_NAMES) {
HTTP_REQUEST_HEADER_NAMES_LOWER.add(header.toLowerCase());
@@ -279,8 +275,6 @@ public class DefaultHttpHeaderMapper implements HeaderMapper<HttpHeaders>, BeanF
private volatile String[] outboundHeaderNames = new String[0];
private volatile String[] outboundHeaderNamesLower = new String[0];
private volatile String[] outboundHeaderNamesLowerWithContentType = new String[0];
private volatile String[] inboundHeaderNames = new String[0];
@@ -297,6 +291,10 @@ public class DefaultHttpHeaderMapper implements HeaderMapper<HttpHeaders>, BeanF
private volatile boolean isDefaultInboundMapper;
private volatile ConversionService conversionService;
private volatile BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
@@ -319,18 +317,18 @@ public class DefaultHttpHeaderMapper implements HeaderMapper<HttpHeaders>, BeanF
}
this.outboundHeaderNames = outboundHeaderNames != null ?
Arrays.copyOf(outboundHeaderNames, outboundHeaderNames.length) : new String[0];
this.outboundHeaderNamesLower = new String[this.outboundHeaderNames.length];
String[] outboundHeaderNamesLower = new String[this.outboundHeaderNames.length];
for (int i = 0; i < this.outboundHeaderNames.length; i++) {
if (HTTP_REQUEST_HEADER_NAME_PATTERN.equals(this.outboundHeaderNames[i])
|| HTTP_RESPONSE_HEADER_NAME_PATTERN.equals(this.outboundHeaderNames[i])) {
this.outboundHeaderNamesLower[i] = this.outboundHeaderNames[i];
outboundHeaderNamesLower[i] = this.outboundHeaderNames[i];
}
else {
this.outboundHeaderNamesLower[i] = this.outboundHeaderNames[i].toLowerCase();
outboundHeaderNamesLower[i] = this.outboundHeaderNames[i].toLowerCase();
}
}
this.outboundHeaderNamesLowerWithContentType =
Arrays.copyOf(this.outboundHeaderNamesLower, this.outboundHeaderNames.length + 1);
Arrays.copyOf(outboundHeaderNamesLower, this.outboundHeaderNames.length + 1);
this.outboundHeaderNamesLowerWithContentType[this.outboundHeaderNamesLowerWithContentType.length - 1]
= MessageHeaders.CONTENT_TYPE.toLowerCase();
}
@@ -1063,13 +1061,13 @@ public class DefaultHttpHeaderMapper implements HeaderMapper<HttpHeaders>, BeanF
// Utility methods
private long getFirstDate(String headerValue, String headerName) {
for (String dateFormat : DATE_FORMATS) {
DateFormat simpleDateFormat = new SimpleDateFormat(dateFormat, Locale.US);
simpleDateFormat.setTimeZone(GMT);
for (DateTimeFormatter dateFormat : DATE_FORMATS) {
try {
return simpleDateFormat.parse(headerValue).getTime();
return dateFormat.parse(headerValue, ZonedDateTime::from)
.toInstant()
.toEpochMilli();
}
catch (ParseException e) {
catch (DateTimeParseException e) {
// ignore
}
}
@@ -1078,9 +1076,7 @@ public class DefaultHttpHeaderMapper implements HeaderMapper<HttpHeaders>, BeanF
}
private String formatDate(long date) {
DateFormat dateFormat = new SimpleDateFormat(DATE_FORMATS[0], Locale.US);
dateFormat.setTimeZone(GMT);
return dateFormat.format(new Date(date));
return DATE_FORMATS[0].format(Instant.ofEpochMilli(date));
}
/**

View File

@@ -19,11 +19,12 @@ package org.springframework.integration.redis.util;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -35,7 +36,6 @@ import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisCallback;
@@ -528,9 +528,10 @@ public final class RedisLockRegistry implements LockRegistry {
@Override
public String toString() {
SimpleDateFormat dateFormat = new SimpleDateFormat("YYYY-MM-dd@HH:mm:ss.SSS");
return "RedisLock [lockKey=" + constructLockKey()
+ ",lockedAt=" + dateFormat.format(new Date(this.lockedAt))
+ ",lockedAt=" + DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(
Instant.ofEpochMilli(this.lockedAt)
.atZone(ZoneId.systemDefault()))
+ ", thread=" + this.threadName
+ ", lockHost=" + new String(this.lockHost)
+ "]";