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:
committed by
Gary Russell
parent
a0845b1caf
commit
3d433ca3f8
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
+ "]";
|
||||
|
||||
Reference in New Issue
Block a user