Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2018-2019 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright (C) 2018-2019 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
package com.unboundid.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import static com.unboundid.util.UtilityMessages.*;
/**
* This class defines a value pattern component that will generate a timestamp.
* It can be the current time or a randomly selected time within a given range,
* and it supports a number of different formats. The format of the output is
* specified from the pattern used to create the component. At its simplest,
* the format can be just "timestamp", in which case the output will always be
* the current time in generalized time format with millisecond precision.
* However, the pattern can also contain the following additional components,
* where each component is separated by colons:
*
*
min={minimumBoundInGeneralizedTime} -- Indicates that the generated
* timestamps should be randomly selected from a given range rather than
* using the current time, and that the specified time (which must be
* given in generalized time format) should be the minimum bound for that
* range.
*
max={maximumBoundInGeneralizedTime} -- Indicates that the generated
* timestamps should be randomly selected from a given range rather than
* using the current time, and that the specified time (which must be
* given in generalized time format) should be the maximum bound for that
* range.
*
format=milliseconds -- Indicates that the generated timestamp should
* represent the selected timestamp as the number of milliseconds since
* January 1, 1970 at midnight UTC.
*
format=seconds -- Indicates that the generated timestamp should
* represent the selected timestamp as the number of seconds since
* January 1, 1970 at midnight UTC.
*
format={formatString} -- Indicates that the generated timestamp should
* represent the selected timestamp using the {@code SimpleDateFormat}
* class created from the provided format string.
*
* Each of the min, max, and format elements can appear at most once in the
* provided pattern, and they must appear in that order (that is, if a min
* element is present, then it must be before the max element and the optional
* format element, and if a format element is present, then it must be the last
* element in the pattern). If the min element is provided, then the max
* element must also be given (and vice-versa, although the min element must
* always be specified before the max), and both values must be expressed using
* the generalized time format. If the min and max elements are not provided,
* then each generated timestamp will reflect the current time at the time that
* timestamp was generated. If the format element is not provided, then the
* selected timestamps will be generated in the generalized time format with
* millisecond precision (e.g., "20180102030405.678Z").
*/
final class TimestampValuePatternComponent
extends ValuePatternComponent
{
/**
* The serial version uid for this serializable class.
*/
private static final long serialVersionUID = 9209358760604151565L;
// Indicates whether timestamp values should be expressed in generalized time
// format.
private final boolean expressAsGeneralizedTime;
// Indicates whether timestamp values should be expressed in milliseconds
// since the epoch.
private final boolean expressAsMillisecondsSinceEpoch;
// Indicates whether timestamp values should be expressed in seconds since the
// epoch.
private final boolean expressAsSecondsSinceEpoch;
// The number of milliseconds between the upper and lower bounds, inclusive.
private final long boundRange;
// The lower bound for generated timestamp values.
private final long lowerBound;
// The random number generator that will be used to seed the thread-local
// random number generators.
private final Random seedRandom;
// The format string that will be used to format timestamps.
private final String dateFormatString;
// The random-number generators that will be used by this class.
private final ThreadLocal threadLocalRandoms;
// The date formatters that will be used by this class.
private final ThreadLocal threadLocalDateFormatters;
/**
* Creates a new timestamp value pattern component that is parsed from the
* given pattern string.
*
* @param pattern The pattern string that defines how timestamp values
* will be generated.
* @param randomSeed The value that will be used to seed the random number
* generators.
*
* @throws ParseException If the provided pattern cannot be parsed to create
* a valid timestamp value pattern component.
*/
TimestampValuePatternComponent(final String pattern, final long randomSeed)
throws ParseException
{
seedRandom = new Random(randomSeed);
threadLocalRandoms = new ThreadLocal<>();
threadLocalDateFormatters = new ThreadLocal<>();
if (pattern.equals("timestamp"))
{
expressAsGeneralizedTime = true;
expressAsMillisecondsSinceEpoch = false;
expressAsSecondsSinceEpoch = false;
lowerBound = -1L;
boundRange = -1L;
dateFormatString = null;
return;
}
if (pattern.startsWith("timestamp:min="))
{
final int maxPos = pattern.indexOf(":max=");
if (maxPos < 0)
{
throw new ParseException(
ERR_TIMESTAMP_VALUE_PATTERN_MIN_WITHOUT_MAX.get(pattern), 10);
}
final int formatPos = pattern.indexOf(":format");
if ((formatPos > 0) && (formatPos < maxPos))
{
throw new ParseException(
ERR_TIMESTAMP_VALUE_PATTERN_FORMAT_NOT_AT_END.get(pattern),
formatPos);
}
final String lowerBoundString = pattern.substring(14, maxPos);
try
{
lowerBound =
StaticUtils.decodeGeneralizedTime(lowerBoundString).getTime();
}
catch (final Exception e)
{
Debug.debugException(e);
throw new ParseException(
ERR_TIMESTAMP_VALUE_PATTERN_CANNOT_PARSE_MIN.get(pattern,
lowerBoundString, StaticUtils.getExceptionMessage(e)),
14);
}
final long upperBound;
if (formatPos < 0)
{
final String upperBoundString = pattern.substring(maxPos + 5);
try
{
upperBound =
StaticUtils.decodeGeneralizedTime(upperBoundString).getTime();
}
catch (final Exception e)
{
Debug.debugException(e);
throw new ParseException(
ERR_TIMESTAMP_VALUE_PATTERN_CANNOT_PARSE_MAX.get(pattern,
upperBoundString, StaticUtils.getExceptionMessage(e)),
maxPos+5);
}
if (upperBound <= lowerBound)
{
throw new ParseException(
ERR_TIMESTAMP_VALUE_PATTERN_MIN_NOT_LT_MAX.get(pattern,
lowerBoundString, upperBoundString),
maxPos+5);
}
else
{
boundRange = upperBound - lowerBound + 1L;
}
expressAsGeneralizedTime = true;
expressAsMillisecondsSinceEpoch = false;
expressAsSecondsSinceEpoch = false;
dateFormatString = null;
}
else
{
final String upperBoundString = pattern.substring(maxPos+5, formatPos);
try
{
upperBound =
StaticUtils.decodeGeneralizedTime(upperBoundString).getTime();
}
catch (final Exception e)
{
Debug.debugException(e);
throw new ParseException(
ERR_TIMESTAMP_VALUE_PATTERN_CANNOT_PARSE_MAX.get(pattern,
upperBoundString, StaticUtils.getExceptionMessage(e)),
maxPos+5);
}
if (upperBound <= lowerBound)
{
throw new ParseException(
ERR_TIMESTAMP_VALUE_PATTERN_MIN_NOT_LT_MAX.get(pattern,
lowerBoundString, upperBoundString),
maxPos+5);
}
else
{
boundRange = upperBound - lowerBound + 1L;
}
expressAsGeneralizedTime = false;
final String formatString = pattern.substring(formatPos+8);
if (formatString.equals("milliseconds"))
{
expressAsMillisecondsSinceEpoch = true;
expressAsSecondsSinceEpoch = false;
dateFormatString = null;
}
else if (formatString.equals("seconds"))
{
expressAsMillisecondsSinceEpoch = false;
expressAsSecondsSinceEpoch = true;
dateFormatString = null;
}
else
{
expressAsMillisecondsSinceEpoch = false;
expressAsSecondsSinceEpoch = false;
dateFormatString = formatString;
try
{
new SimpleDateFormat(dateFormatString);
}
catch (final Exception e)
{
throw new ParseException(
ERR_TIMESTAMP_VALUE_PATTERN_CANNOT_PARSE_FORMAT_STRING.get(
pattern, dateFormatString),
formatPos+8);
}
}
}
}
else if (pattern.startsWith("timestamp:format="))
{
if (pattern.contains(":min=") || pattern.contains(":max="))
{
throw new ParseException(
ERR_TIMESTAMP_VALUE_PATTERN_FORMAT_NOT_AT_END.get(pattern), 17);
}
lowerBound = -1L;
boundRange = -1L;
expressAsGeneralizedTime = false;
final String formatString = pattern.substring(17);
if (formatString.equals("milliseconds"))
{
expressAsMillisecondsSinceEpoch = true;
expressAsSecondsSinceEpoch = false;
dateFormatString = null;
}
else if (formatString.equals("seconds"))
{
expressAsMillisecondsSinceEpoch = false;
expressAsSecondsSinceEpoch = true;
dateFormatString = null;
}
else
{
expressAsMillisecondsSinceEpoch = false;
expressAsSecondsSinceEpoch = false;
dateFormatString = formatString;
try
{
new SimpleDateFormat(dateFormatString);
}
catch (final Exception e)
{
throw new ParseException(
ERR_TIMESTAMP_VALUE_PATTERN_CANNOT_PARSE_FORMAT_STRING.get(
pattern, dateFormatString),
17);
}
}
}
else
{
throw new ParseException(
ERR_TIMESTAMP_VALUE_PATTERN_MALFORMED.get(pattern), 0);
}
}
/**
* {@inheritDoc}
*/
@Override()
void append(final StringBuilder buffer)
{
final long selectedTime;
if (lowerBound == -1L)
{
selectedTime = System.currentTimeMillis();
}
else
{
final long positiveRandomValue =
(getRandom().nextLong() & 0x7FFF_FFFF_FFFF_FFFFL);
selectedTime = lowerBound + (positiveRandomValue % boundRange);
}
if (expressAsMillisecondsSinceEpoch)
{
buffer.append(selectedTime);
}
else if (expressAsSecondsSinceEpoch)
{
buffer.append(selectedTime / 1000L);
}
else if (expressAsGeneralizedTime)
{
buffer.append(StaticUtils.encodeGeneralizedTime(selectedTime));
}
else
{
buffer.append(getDateFormatter().format(new Date(selectedTime)));
}
}
/**
* {@inheritDoc}
*/
@Override()
boolean supportsBackReference()
{
return true;
}
/**
* Retrieves a random number generator for use by the current thread.
*
* @return A random number generator for use by the current thread.
*/
private Random getRandom()
{
Random random = threadLocalRandoms.get();
if (random == null)
{
synchronized (seedRandom)
{
random = new Random(seedRandom.nextLong());
}
threadLocalRandoms.set(random);
}
return random;
}
/**
* Retrieves a date formatter for use by the current thread.
*
* @return A date formatter for use byt he current thread.
*/
private SimpleDateFormat getDateFormatter()
{
SimpleDateFormat dateFormatter = threadLocalDateFormatters.get();
if (dateFormatter == null)
{
dateFormatter = new SimpleDateFormat(dateFormatString);
threadLocalDateFormatters.set(dateFormatter);
}
return dateFormatter;
}
}