From 3d433ca3f8321ed112673d057292a4e812a7eff8 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Tue, 13 Dec 2016 16:09:33 -0500 Subject: [PATCH] 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 --- .../transformer/SyslogToMapTransformer.java | 19 +++---- .../http/support/DefaultHttpHeaderMapper.java | 54 +++++++++---------- .../redis/util/RedisLockRegistry.java | 11 ++-- 3 files changed, 37 insertions(+), 47 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/SyslogToMapTransformer.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/SyslogToMapTransformer.java index 94d74b2a26..fbdf0b260c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/transformer/SyslogToMapTransformer.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/SyslogToMapTransformer.java @@ -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> { - private static final BlockingQueue dateFormats = new LinkedBlockingQueue(); + 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 transform(String payload) { Map map = new LinkedHashMap(); 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, 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, BeanF WARNING }; - private static final Set HTTP_REQUEST_HEADER_NAMES_LOWER = new HashSet(); + private static final Set 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, 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, 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, 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, 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, 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, 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)); } /** diff --git a/spring-integration-redis/src/main/java/org/springframework/integration/redis/util/RedisLockRegistry.java b/spring-integration-redis/src/main/java/org/springframework/integration/redis/util/RedisLockRegistry.java index b0ce9b6821..1a5e8b42e8 100644 --- a/spring-integration-redis/src/main/java/org/springframework/integration/redis/util/RedisLockRegistry.java +++ b/spring-integration-redis/src/main/java/org/springframework/integration/redis/util/RedisLockRegistry.java @@ -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) + "]";