1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 import java.io.ByteArrayInputStream; 24 import java.io.ByteArrayOutputStream; 25 import java.io.IOException; 26 import java.io.ObjectInputStream; 27 import java.io.ObjectOutputStream; 28 import java.time.Instant; 29 import java.util.Objects; 30 import java.util.logging.Level; 31 import java.util.logging.LogRecord; 32 import java.util.logging.SimpleFormatter; 33 34 /** 35 * @test 36 * @bug 8072645 8144262 37 * @summary tests the new methods added to LogRecord. 38 * @run main LogRecordWithNanosAPI 39 * @author danielfuchs 40 */ 41 public class LogRecordWithNanosAPI { 42 43 static final int MILLIS_IN_SECOND = 1000; 44 static final int NANOS_IN_MILLI = 1000_000; 45 static final int NANOS_IN_SECOND = 1000_000_000; 46 47 static final boolean verbose = true; 48 49 static final class TestAssertException extends RuntimeException { TestAssertException(String msg)50 TestAssertException(String msg) { super(msg); } 51 } 52 assertEquals(long expected, long received, String msg)53 private static void assertEquals(long expected, long received, String msg) { 54 if (expected != received) { 55 throw new TestAssertException("Unexpected result for " + msg 56 + ".\n\texpected: " + expected 57 + "\n\tactual: " + received); 58 } else if (verbose) { 59 System.out.println("Got expected " + msg + ": " + received); 60 } 61 } 62 assertEquals(Object expected, Object received, String msg)63 private static void assertEquals(Object expected, Object received, String msg) { 64 if (!Objects.equals(expected, received)) { 65 throw new TestAssertException("Unexpected result for " + msg 66 + ".\n\texpected: " + expected 67 + "\n\tactual: " + received); 68 } else if (verbose) { 69 System.out.println("Got expected " + msg + ": " + received); 70 } 71 } 72 73 // The nano second fractional part of a second, contained in a time expressed 74 // as a number of millisecond from the epoch. nanoInSecondFromEpochMilli(long millis)75 private static long nanoInSecondFromEpochMilli(long millis) { 76 return (((millis%MILLIS_IN_SECOND) + MILLIS_IN_SECOND)%MILLIS_IN_SECOND)*NANOS_IN_MILLI; 77 } 78 79 /** 80 * Serializes a log record, then deserializes it and check that both 81 * records match. 82 * @param record the log record to serialize & deserialize. 83 * @param hasExceedingNanos whether the record has a nano adjustment whose 84 * value exceeds 1ms. 85 * @throws IOException Unexpected. 86 * @throws ClassNotFoundException Unexpected. 87 */ test(LogRecord record, boolean hasExceedingNanos)88 public static void test(LogRecord record, boolean hasExceedingNanos) 89 throws IOException, ClassNotFoundException { 90 91 // Format the given logRecord using the SimpleFormatter 92 SimpleFormatter formatter = new SimpleFormatter(); 93 String str = formatter.format(record); 94 95 // Serialize the given LogRecord 96 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 97 final ObjectOutputStream oos = new ObjectOutputStream(baos); 98 oos.writeObject(record); 99 oos.flush(); 100 oos.close(); 101 102 // First checks that the log record can be deserialized 103 final ByteArrayInputStream bais = 104 new ByteArrayInputStream(baos.toByteArray()); 105 final ObjectInputStream ois = new ObjectInputStream(bais); 106 final LogRecord record2 = (LogRecord)ois.readObject(); 107 108 assertEquals(record.getMillis(), record2.getMillis(), "getMillis()"); 109 assertEquals(record.getInstant().getEpochSecond(), 110 record2.getInstant().getEpochSecond(), 111 "getInstant().getEpochSecond()"); 112 assertEquals(record.getInstant().getNano(), 113 record2.getInstant().getNano(), 114 "getInstant().getNano()"); 115 assertEquals(record.getInstant().toEpochMilli(), 116 record2.getInstant().toEpochMilli(), 117 "getInstant().toEpochMilli()"); 118 long millis = record.getMillis(); 119 millis = hasExceedingNanos 120 ? Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 121 (millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI 122 + record.getInstant().getNano() % NANOS_IN_MILLI).toEpochMilli() 123 : millis; 124 assertEquals(millis, record.getInstant().toEpochMilli(), 125 "getMillis()/getInstant().toEpochMilli()"); 126 millis = record2.getMillis(); 127 millis = hasExceedingNanos 128 ? Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 129 (millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI 130 + record2.getInstant().getNano() % NANOS_IN_MILLI).toEpochMilli() 131 : millis; 132 assertEquals(millis, record2.getInstant().toEpochMilli(), 133 "getMillis()/getInstant().toEpochMilli()"); 134 long nanos = nanoInSecondFromEpochMilli(record.getMillis()) 135 + record.getInstant().getNano() % NANOS_IN_MILLI; 136 assertEquals(nanos, record.getInstant().getNano(), 137 "nanoInSecondFromEpochMilli(record.getMillis())" 138 + " + record.getInstant().getNano() % NANOS_IN_MILLI /getInstant().getNano()"); 139 nanos = nanoInSecondFromEpochMilli(record2.getMillis()) 140 + record2.getInstant().getNano() % NANOS_IN_MILLI; 141 assertEquals(nanos, record2.getInstant().getNano(), 142 "nanoInSecondFromEpochMilli(record2.getMillis())" 143 + " + record2.getInstant().getNano() % NANOS_IN_MILLI /getInstant().getNano()"); 144 145 // Format the deserialized LogRecord using the SimpleFormatter, and 146 // check that the string representation obtained matches the string 147 // representation of the original LogRecord 148 String str2 = formatter.format(record2); 149 if (!str.equals(str2)) 150 throw new RuntimeException("Unexpected values in deserialized object:" 151 + "\n\tExpected: " + str 152 + "\n\tRetrieved: "+str); 153 154 } 155 156 main(String[] args)157 public static void main(String[] args) throws Exception { 158 int count=0; 159 LogRecord record = new LogRecord(Level.INFO, "Java Version: {0}"); 160 record.setLoggerName("test"); 161 record.setParameters(new Object[] {System.getProperty("java.version")}); 162 final int nanos = record.getInstant().getNano() % NANOS_IN_MILLI; 163 final long millis = record.getMillis(); 164 final Instant instant = record.getInstant(); 165 if (millis != instant.toEpochMilli()) { 166 throw new RuntimeException("Unexpected millis: " 167 + record.getMillis()); 168 } 169 test(record, false); 170 171 // nano adjustment < 1ms (canonical case) 172 int newNanos = (nanos + 111111) % NANOS_IN_MILLI; 173 record.setInstant(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 174 (millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + newNanos)); 175 assertEquals(newNanos, record.getInstant().getNano() % NANOS_IN_MILLI, 176 "record.getInstant().getNano() % NANOS_IN_MILLI"); 177 assertEquals(millis, record.getMillis(), "record.getMillis()"); 178 assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 179 (millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newNanos), 180 record.getInstant(), "record.getInstant()"); 181 test(record, false); 182 assertEquals(newNanos, record.getInstant().getNano() % NANOS_IN_MILLI, 183 "record.getInstant().getNano() % NANOS_IN_MILLI"); 184 assertEquals(millis, record.getMillis(), "record.getMillis()"); 185 assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 186 (millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newNanos), 187 record.getInstant(), "record.getInstant()"); 188 189 // nano adjustment > 1ms - non canonical - should still work 190 int newExceedingNanos = 2111_111; 191 record.setInstant(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 192 (millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + newExceedingNanos)); 193 assertEquals(newExceedingNanos % NANOS_IN_MILLI, 194 record.getInstant().getNano() % NANOS_IN_MILLI, 195 "record.getInstant().getNano() % NANOS_IN_MILLI"); 196 assertEquals(millis + newExceedingNanos / NANOS_IN_MILLI, 197 record.getMillis(), "record.getMillis()"); 198 assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 199 (millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newExceedingNanos), 200 record.getInstant(), "record.getInstant()"); 201 test(record, true); 202 assertEquals(newExceedingNanos % NANOS_IN_MILLI, 203 record.getInstant().getNano() % NANOS_IN_MILLI, 204 "record.getInstant().getNano() % NANOS_IN_MILLI"); 205 assertEquals(millis + newExceedingNanos / NANOS_IN_MILLI, 206 record.getMillis(), "record.getMillis()"); 207 assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 208 (millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newExceedingNanos), 209 record.getInstant(), "record.getInstant()"); 210 211 // nano adjustement > 1s - non canonical - should still work 212 newExceedingNanos = 1111_111_111; 213 record.setInstant(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 214 (millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + newExceedingNanos)); 215 assertEquals(newExceedingNanos % NANOS_IN_MILLI, 216 record.getInstant().getNano() % NANOS_IN_MILLI, 217 "record.getInstant().getNano() % NANOS_IN_MILLI"); 218 assertEquals(millis + newExceedingNanos / NANOS_IN_MILLI, 219 record.getMillis(), "record.getMillis()"); 220 assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 221 (millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newExceedingNanos), 222 record.getInstant(), "record.getInstant()"); 223 test(record, true); 224 assertEquals(newExceedingNanos % NANOS_IN_MILLI, 225 record.getInstant().getNano() % NANOS_IN_MILLI, 226 "record.getInstant().getNano() % NANOS_IN_MILLI"); 227 assertEquals(millis + newExceedingNanos / NANOS_IN_MILLI, 228 record.getMillis(), "record.getMillis()"); 229 assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 230 (millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newExceedingNanos), 231 record.getInstant(), "record.getInstant()"); 232 233 // nano adjustement < 0 - non canonical - should still work 234 newExceedingNanos = -1; 235 record.setInstant(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 236 (millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + newExceedingNanos)); 237 assertEquals(newExceedingNanos + NANOS_IN_MILLI, 238 record.getInstant().getNano() % NANOS_IN_MILLI, 239 "record.getInstant().getNano() % NANOS_IN_MILLI"); 240 assertEquals(millis -1, record.getMillis(), "record.getMillis()"); 241 assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 242 (millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newExceedingNanos), 243 record.getInstant(), "record.getInstant()"); 244 test(record, true); 245 record.setInstant(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 246 (millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + newExceedingNanos)); 247 assertEquals(millis -1, record.getMillis(), "record.getMillis()"); 248 assertEquals(Instant.ofEpochSecond(millis/MILLIS_IN_SECOND, 249 (millis%MILLIS_IN_SECOND)*NANOS_IN_MILLI + newExceedingNanos), 250 record.getInstant(), "record.getInstant()"); 251 252 // setMillis 253 record.setMillis(millis-1); 254 assertEquals(millis-1, record.getInstant().toEpochMilli(), 255 "record.getInstant().toEpochMilli()"); 256 assertEquals(millis-1, record.getMillis(), 257 "record.getMillis()"); 258 assertEquals(0, record.getInstant().getNano() % NANOS_IN_MILLI, 259 "record.getInstant().getNano() % NANOS_IN_MILLI"); 260 test(record, false); 261 assertEquals(millis-1, record.getInstant().toEpochMilli(), 262 "record.getInstant().toEpochMilli()"); 263 assertEquals(millis-1, record.getMillis(), 264 "record.getMillis()"); 265 assertEquals(0, record.getInstant().getNano() % NANOS_IN_MILLI, 266 "record.getInstant().getNano() % NANOS_IN_MILLI"); 267 268 // setMillis to 0 269 record.setMillis(0); 270 assertEquals(0, record.getInstant().toEpochMilli(), 271 "record.getInstant().toEpochMilli()"); 272 assertEquals(0, record.getMillis(), 273 "record.getMillis()"); 274 assertEquals(0, record.getInstant().getNano() % NANOS_IN_MILLI, 275 "record.getInstant().getNano() % NANOS_IN_MILLI"); 276 test(record, false); 277 assertEquals(0, record.getInstant().toEpochMilli(), 278 "record.getInstant().toEpochMilli()"); 279 assertEquals(0, record.getMillis(), 280 "record.getMillis()"); 281 assertEquals(0, record.getInstant().getNano() % NANOS_IN_MILLI, 282 "record.getInstant().getNano() % NANOS_IN_MILLI"); 283 284 // setMillis to -1 285 record.setMillis(-1); 286 assertEquals(-1, record.getInstant().toEpochMilli(), 287 "record.getInstant().toEpochMilli()"); 288 assertEquals(-1, record.getMillis(), 289 "record.getMillis()"); 290 assertEquals(0, record.getInstant().getNano() % NANOS_IN_MILLI, 291 "record.getInstant().getNano() % NANOS_IN_MILLI"); 292 test(record, false); 293 assertEquals(-1, record.getInstant().toEpochMilli(), 294 "record.getInstant().toEpochMilli()"); 295 assertEquals(-1, record.getMillis(), 296 "record.getMillis()"); 297 assertEquals(0, record.getInstant().getNano() % NANOS_IN_MILLI, 298 "record.getInstant().getNano() % NANOS_IN_MILLI"); 299 300 try { 301 record.setInstant(null); 302 throw new RuntimeException("Expected NullPointerException not thrown"); 303 } catch (NullPointerException x) { 304 System.out.println("Got expected NPE when trying to call record.setInstant(null): " + x); 305 } 306 307 // This instant is the biggest for which toEpochMilli will not throw... 308 final Instant max = Instant.ofEpochMilli(Long.MAX_VALUE).plusNanos(999_999L); 309 record.setInstant(max); 310 assertEquals(Long.MAX_VALUE / 1000L, 311 record.getInstant().getEpochSecond(), 312 "max instant seconds [record.getInstant().getEpochSecond()]"); 313 assertEquals(Long.MAX_VALUE, 314 record.getInstant().toEpochMilli(), 315 "max instant millis [record.getInstant().toEpochMilli()]"); 316 assertEquals(Long.MAX_VALUE, record.getMillis(), 317 "max instant millis [record.getMillis()]"); 318 assertEquals((Long.MAX_VALUE % 1000L)*1000_000L + 999_999L, 319 record.getInstant().getNano(), 320 "max instant nanos [record.getInstant().getNano()]"); 321 322 // Too big by 1 ns. 323 final Instant tooBig = max.plusNanos(1L); 324 try { 325 record.setInstant(tooBig); 326 throw new RuntimeException("Expected ArithmeticException not thrown"); 327 } catch (ArithmeticException x) { 328 System.out.println("Got expected ArithmeticException when trying" 329 + " to call record.setInstant(Instant.ofEpochMilli(Long.MAX_VALUE)" 330 + ".plusNanos(999_999L).plusNanos(1L)): " + x); 331 } 332 333 } 334 335 } 336