Fixes #1357 - Refactored date/time handling and added tests for RolloverFileOutputStream
This commit is contained in:
parent
189cc4e369
commit
b0bead2bc0
|
@ -24,6 +24,7 @@ import java.io.FilterOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -184,35 +185,46 @@ public class RolloverFileOutputStream extends FilterOutputStream
|
||||||
if (__rollover==null)
|
if (__rollover==null)
|
||||||
__rollover=new Timer(RolloverFileOutputStream.class.getName(),true);
|
__rollover=new Timer(RolloverFileOutputStream.class.getName(),true);
|
||||||
|
|
||||||
// Calculate Today's Midnight, based on Configured TimeZone (will be in past, even if by a few milliseconds)
|
_rollTask=new RollTask();
|
||||||
setFile(now);
|
|
||||||
// This will schedule the rollover event to the next midnight
|
midnight = toMidnight(ZonedDateTime.now(), zone.toZoneId());
|
||||||
scheduleNextRollover(now);
|
|
||||||
|
scheduleNextRollover();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Get the "start of day" for the provided DateTime at the zone specified.
|
* Get the "start of day" for the provided DateTime at the zone specified.
|
||||||
*
|
*
|
||||||
* @param now the date time to calculate from
|
* @param dateTime the date time to calculate from
|
||||||
|
* @param zone the zone to return the date in
|
||||||
* @return start of the day of the date provided
|
* @return start of the day of the date provided
|
||||||
*/
|
*/
|
||||||
public static ZonedDateTime toMidnight(ZonedDateTime now)
|
public static ZonedDateTime toMidnight(ZonedDateTime dateTime, ZoneId zone)
|
||||||
{
|
{
|
||||||
return now.toLocalDate().atStartOfDay(now.getZone()).plus(1, ChronoUnit.DAYS);
|
return dateTime.toLocalDate().atStartOfDay(zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/**
|
||||||
private void scheduleNextRollover(ZonedDateTime now)
|
* Get the next "start of day" for the provided date.
|
||||||
|
*
|
||||||
|
* @param dateTime the date to calculate from
|
||||||
|
* @return the start of the next day
|
||||||
|
*/
|
||||||
|
public static ZonedDateTime nextMidnight(ZonedDateTime dateTime)
|
||||||
{
|
{
|
||||||
_rollTask = new RollTask();
|
// Increment to next day.
|
||||||
// Get tomorrow's midnight based on Configured TimeZone
|
// Using Calendar.add(DAY, 1) takes in account Daylights Savings
|
||||||
ZonedDateTime midnight = toMidnight(now);
|
// differences, and still maintains the "midnight" settings for
|
||||||
|
// Hour, Minute, Second, Milliseconds
|
||||||
|
return dateTime.toLocalDate().plus(1, ChronoUnit.DAYS).atStartOfDay(dateTime.getZone());
|
||||||
|
}
|
||||||
|
|
||||||
// Schedule next rollover event to occur, based on local machine's Unix Epoch milliseconds
|
private void scheduleNextRollover()
|
||||||
long delay = midnight.toInstant().toEpochMilli() - now.toInstant().toEpochMilli();
|
{
|
||||||
__rollover.schedule(_rollTask,delay);
|
long lastMs = midnight.toInstant().toEpochMilli();
|
||||||
|
midnight = nextMidnight(midnight);
|
||||||
|
__rollover.schedule(_rollTask,midnight.toInstant().toEpochMilli() - lastMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
|
@ -21,24 +21,12 @@ package org.eclipse.jetty.util;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.attribute.FileTime;
|
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.toolchain.test.FS;
|
|
||||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
|
||||||
import org.eclipse.jetty.util.resource.ResourceTest;
|
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class RolloverFileOutputStreamTest
|
public class RolloverFileOutputStreamTest
|
||||||
|
@ -69,45 +57,21 @@ public class RolloverFileOutputStreamTest
|
||||||
|
|
||||||
for (int i = 0; i < expected.length; i++)
|
for (int i = 0; i < expected.length; i++)
|
||||||
{
|
{
|
||||||
long currentMillis = nextEvent.toInstant().toEpochMilli();
|
long lastMs = nextEvent.toInstant().toEpochMilli();
|
||||||
nextEvent = nextEvent.toLocalDate().plus(1, ChronoUnit.DAYS).atStartOfDay(nextEvent.getZone());
|
nextEvent = RolloverFileOutputStream.nextMidnight(nextEvent);
|
||||||
assertThat("Next Event", toString(nextEvent), is(expected[i][0]));
|
assertThat("Next Event", toString(nextEvent), is(expected[i][0]));
|
||||||
long duration = (nextEvent.toInstant().toEpochMilli() - currentMillis);
|
long duration = (nextEvent.toInstant().toEpochMilli() - lastMs);
|
||||||
assertThat("Duration to next event", duration, is((long) expected[i][1]));
|
assertThat("Duration to next event", duration, is((long) expected[i][1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <a href="Issue #1507">https://github.com/eclipse/jetty.project/issues/1507</a>
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testMidnightRolloverCalc_PDT_Issue1507()
|
|
||||||
{
|
|
||||||
ZoneId zone = toZoneId("PST");
|
|
||||||
ZonedDateTime initialDate = toDateTime("2017.04.26-08:00:00.0 PM PDT", zone);
|
|
||||||
|
|
||||||
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate);
|
|
||||||
assertThat("Midnight", toString(midnight), is("2017.04.27-12:00:00.0 AM PDT"));
|
|
||||||
|
|
||||||
Object expected[][] = {
|
|
||||||
{"2017.04.27-12:00:00.0 AM PDT", 14_400_000L},
|
|
||||||
{"2017.04.28-12:00:00.0 AM PDT", 86_400_000L},
|
|
||||||
{"2017.04.29-12:00:00.0 AM PDT", 86_400_000L},
|
|
||||||
{"2017.04.30-12:00:00.0 AM PDT", 86_400_000L},
|
|
||||||
{"2017.05.01-12:00:00.0 AM PDT", 86_400_000L},
|
|
||||||
{"2017.05.02-12:00:00.0 AM PDT", 86_400_000L},
|
|
||||||
};
|
|
||||||
|
|
||||||
assertSequence(initialDate, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMidnightRolloverCalc_PST_DST_Start()
|
public void testMidnightRolloverCalc_PST_DST_Start()
|
||||||
{
|
{
|
||||||
ZoneId zone = toZoneId("PST");
|
ZoneId zone = toZoneId("PST");
|
||||||
ZonedDateTime initialDate = toDateTime("2016.03.10-01:23:45.0 PM PST", zone);
|
ZonedDateTime initialDate = toDateTime("2016.03.11-01:23:45.0 PM PST", zone);
|
||||||
|
|
||||||
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate);
|
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate, zone);
|
||||||
assertThat("Midnight", toString(midnight), is("2016.03.11-12:00:00.0 AM PST"));
|
assertThat("Midnight", toString(midnight), is("2016.03.11-12:00:00.0 AM PST"));
|
||||||
|
|
||||||
Object expected[][] = {
|
Object expected[][] = {
|
||||||
|
@ -125,9 +89,9 @@ public class RolloverFileOutputStreamTest
|
||||||
public void testMidnightRolloverCalc_PST_DST_End()
|
public void testMidnightRolloverCalc_PST_DST_End()
|
||||||
{
|
{
|
||||||
ZoneId zone = toZoneId("PST");
|
ZoneId zone = toZoneId("PST");
|
||||||
ZonedDateTime initialDate = toDateTime("2016.11.03-11:22:33.0 AM PDT", zone);
|
ZonedDateTime initialDate = toDateTime("2016.11.04-11:22:33.0 AM PDT", zone);
|
||||||
|
|
||||||
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate);
|
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate, zone);
|
||||||
assertThat("Midnight", toString(midnight), is("2016.11.04-12:00:00.0 AM PDT"));
|
assertThat("Midnight", toString(midnight), is("2016.11.04-12:00:00.0 AM PDT"));
|
||||||
|
|
||||||
Object expected[][] = {
|
Object expected[][] = {
|
||||||
|
@ -145,9 +109,9 @@ public class RolloverFileOutputStreamTest
|
||||||
public void testMidnightRolloverCalc_Sydney_DST_Start()
|
public void testMidnightRolloverCalc_Sydney_DST_Start()
|
||||||
{
|
{
|
||||||
ZoneId zone = toZoneId("Australia/Sydney");
|
ZoneId zone = toZoneId("Australia/Sydney");
|
||||||
ZonedDateTime initialDate = toDateTime("2016.09.31-01:23:45.0 PM AEST", zone);
|
ZonedDateTime initialDate = toDateTime("2016.10.01-01:23:45.0 PM AEST", zone);
|
||||||
|
|
||||||
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate);
|
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate, zone);
|
||||||
assertThat("Midnight", toString(midnight), is("2016.10.01-12:00:00.0 AM AEST"));
|
assertThat("Midnight", toString(midnight), is("2016.10.01-12:00:00.0 AM AEST"));
|
||||||
|
|
||||||
Object expected[][] = {
|
Object expected[][] = {
|
||||||
|
@ -165,9 +129,9 @@ public class RolloverFileOutputStreamTest
|
||||||
public void testMidnightRolloverCalc_Sydney_DST_End()
|
public void testMidnightRolloverCalc_Sydney_DST_End()
|
||||||
{
|
{
|
||||||
ZoneId zone = toZoneId("Australia/Sydney");
|
ZoneId zone = toZoneId("Australia/Sydney");
|
||||||
ZonedDateTime initialDate = toDateTime("2016.04.01-11:22:33.0 AM AEDT", zone);
|
ZonedDateTime initialDate = toDateTime("2016.04.02-11:22:33.0 AM AEDT", zone);
|
||||||
|
|
||||||
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate);
|
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate, zone);
|
||||||
assertThat("Midnight", toString(midnight), is("2016.04.02-12:00:00.0 AM AEDT"));
|
assertThat("Midnight", toString(midnight), is("2016.04.02-12:00:00.0 AM AEDT"));
|
||||||
|
|
||||||
Object expected[][] = {
|
Object expected[][] = {
|
||||||
|
@ -180,150 +144,4 @@ public class RolloverFileOutputStreamTest
|
||||||
|
|
||||||
assertSequence(midnight, expected);
|
assertSequence(midnight, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFilehandling() throws Exception
|
|
||||||
{
|
|
||||||
File testDir = MavenTestingUtils.getTargetTestingDir(ResourceTest.class.getName());
|
|
||||||
Path testPath = testDir.toPath();
|
|
||||||
FS.ensureEmpty(testDir);
|
|
||||||
|
|
||||||
ZoneId zone = toZoneId("Australia/Sydney");
|
|
||||||
ZonedDateTime now = toDateTime("2016.04.10-08:30:12.3 AM AEDT", zone);
|
|
||||||
|
|
||||||
File template = new File(testDir,"test-rofos-yyyy_mm_dd.log");
|
|
||||||
|
|
||||||
try (RolloverFileOutputStream rofos =
|
|
||||||
new RolloverFileOutputStream(template.getAbsolutePath(),false,3,TimeZone.getTimeZone(zone),null,null,now))
|
|
||||||
{
|
|
||||||
rofos.write("TICK".getBytes());
|
|
||||||
rofos.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
now = now.plus(5,ChronoUnit.MINUTES);
|
|
||||||
|
|
||||||
try (RolloverFileOutputStream rofos =
|
|
||||||
new RolloverFileOutputStream(template.getAbsolutePath(),false,3,TimeZone.getTimeZone(zone),null,null,now))
|
|
||||||
{
|
|
||||||
rofos.write("TOCK".getBytes());
|
|
||||||
rofos.flush();
|
|
||||||
String[] ls = testDir.list();
|
|
||||||
assertThat(ls.length,is(2));
|
|
||||||
String backup = null;
|
|
||||||
for (String n: ls)
|
|
||||||
{
|
|
||||||
if (!"test-rofos-2016_04_10.log".equals(n))
|
|
||||||
backup = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThat(Arrays.asList(ls),Matchers.containsInAnyOrder(backup,"test-rofos-2016_04_10.log"));
|
|
||||||
|
|
||||||
Files.setLastModifiedTime(testPath.resolve(backup),FileTime.from(now.toInstant()));
|
|
||||||
Files.setLastModifiedTime(testPath.resolve("test-rofos-2016_04_10.log"),FileTime.from(now.toInstant()));
|
|
||||||
|
|
||||||
ZonedDateTime time = now.minus(1,ChronoUnit.DAYS);
|
|
||||||
for (int i=10;i-->5;)
|
|
||||||
{
|
|
||||||
String file = "test-rofos-2016_04_0"+i+".log";
|
|
||||||
Path path = testPath.resolve(file);
|
|
||||||
FS.touch(path);
|
|
||||||
Files.setLastModifiedTime(path,FileTime.from(time.toInstant()));
|
|
||||||
|
|
||||||
if (i%2==0)
|
|
||||||
{
|
|
||||||
file = "test-rofos-2016_04_0"+i+".log.083512300";
|
|
||||||
path = testPath.resolve(file);
|
|
||||||
FS.touch(path);
|
|
||||||
Files.setLastModifiedTime(path,FileTime.from(time.toInstant()));
|
|
||||||
time = time.minus(1,ChronoUnit.DAYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
file = "unrelated-"+i;
|
|
||||||
path = testPath.resolve(file);
|
|
||||||
FS.touch(path);
|
|
||||||
Files.setLastModifiedTime(path,FileTime.from(time.toInstant()));
|
|
||||||
|
|
||||||
time = time.minus(1,ChronoUnit.DAYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
ls = testDir.list();
|
|
||||||
assertThat(ls.length,is(14));
|
|
||||||
assertThat(Arrays.asList(ls),Matchers.containsInAnyOrder(
|
|
||||||
"test-rofos-2016_04_05.log",
|
|
||||||
"test-rofos-2016_04_06.log",
|
|
||||||
"test-rofos-2016_04_07.log",
|
|
||||||
"test-rofos-2016_04_08.log",
|
|
||||||
"test-rofos-2016_04_09.log",
|
|
||||||
"test-rofos-2016_04_10.log",
|
|
||||||
"test-rofos-2016_04_06.log.083512300",
|
|
||||||
"test-rofos-2016_04_08.log.083512300",
|
|
||||||
"test-rofos-2016_04_10.log.083512300",
|
|
||||||
"unrelated-9",
|
|
||||||
"unrelated-8",
|
|
||||||
"unrelated-7",
|
|
||||||
"unrelated-6",
|
|
||||||
"unrelated-5"
|
|
||||||
));
|
|
||||||
|
|
||||||
rofos.removeOldFiles(now);
|
|
||||||
ls = testDir.list();
|
|
||||||
assertThat(ls.length,is(10));
|
|
||||||
assertThat(Arrays.asList(ls),Matchers.containsInAnyOrder(
|
|
||||||
"test-rofos-2016_04_08.log",
|
|
||||||
"test-rofos-2016_04_09.log",
|
|
||||||
"test-rofos-2016_04_10.log",
|
|
||||||
"test-rofos-2016_04_08.log.083512300",
|
|
||||||
"test-rofos-2016_04_10.log.083512300",
|
|
||||||
"unrelated-9",
|
|
||||||
"unrelated-8",
|
|
||||||
"unrelated-7",
|
|
||||||
"unrelated-6",
|
|
||||||
"unrelated-5"));
|
|
||||||
|
|
||||||
|
|
||||||
assertThat(IO.toString(new FileReader(new File(testDir,backup))),is("TICK"));
|
|
||||||
assertThat(IO.toString(new FileReader(new File(testDir,"test-rofos-2016_04_10.log"))),is("TOCK"));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRollover() throws Exception
|
|
||||||
{
|
|
||||||
File testDir = MavenTestingUtils.getTargetTestingDir(ResourceTest.class.getName());
|
|
||||||
FS.ensureEmpty(testDir);
|
|
||||||
|
|
||||||
ZoneId zone = toZoneId("Australia/Sydney");
|
|
||||||
ZonedDateTime now = toDateTime("2016.04.10-11:59:55.0 PM AEDT", zone);
|
|
||||||
|
|
||||||
File template = new File(testDir,"test-rofos-yyyy_mm_dd.log");
|
|
||||||
|
|
||||||
try (RolloverFileOutputStream rofos =
|
|
||||||
new RolloverFileOutputStream(template.getAbsolutePath(),false,0,TimeZone.getTimeZone(zone),null,null,now))
|
|
||||||
{
|
|
||||||
rofos.write("BEFORE".getBytes());
|
|
||||||
rofos.flush();
|
|
||||||
String[] ls = testDir.list();
|
|
||||||
assertThat(ls.length,is(1));
|
|
||||||
assertThat(ls[0],is("test-rofos-2016_04_10.log"));
|
|
||||||
|
|
||||||
TimeUnit.SECONDS.sleep(10);
|
|
||||||
rofos.write("AFTER".getBytes());
|
|
||||||
ls = testDir.list();
|
|
||||||
assertThat(ls.length,is(2));
|
|
||||||
|
|
||||||
for (String n : ls)
|
|
||||||
{
|
|
||||||
String content = IO.toString(new FileReader(new File(testDir,n)));
|
|
||||||
if ("test-rofos-2016_04_10.log".equals(n))
|
|
||||||
{
|
|
||||||
assertThat(content,is("BEFORE"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assertThat(content,is("AFTER"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue