Compare commits

..

6 commits
2.1.1 ... main

144 changed files with 11634 additions and 884 deletions

View file

@ -1,14 +0,0 @@
# xbib Time
image:https://api.travis-ci.org/xbib/time.svg[title="Build status", link="https://travis-ci.org/xbib/time/"]
image:https://img.shields.io/sonar/http/nemo.sonarqube.com/org.xbib%3Atime/coverage.svg?style=flat-square[title="Coverage", link="https://sonarqube.com/dashboard/index?id=org.xbib%3Atime"]
image:https://maven-badges.herokuapp.com/maven-central/org.xbib/time/badge.svg[title="Maven Central", link="http://search.maven.org/#search%7Cga%7C1%7Cxbib%20time"]
image:https://img.shields.io/badge/License-Apache%202.0-blue.svg[title="Apache License 2.0", link="https://opensource.org/licenses/Apache-2.0"]
This is a bundle of time utilities for Java 8 Time API. It consists of
- Chronic: parsing natural language to compute time spans (from https://github.com/samtingleff/jchronic)
- Pretty: pretty printing time durations (from https://github.com/ocpsoft/prettytime)
- Format: format time descriptions (from https://github.com/JodaOrg/joda-time)
This project has no dependencies.

9
README.md Normal file
View file

@ -0,0 +1,9 @@
# xbib Time
This is a bundle of time utilities for Java 8 Time API. It consists of
- Chronic: parsing natural language to compute time spans (from https://github.com/samtingleff/jchronic)
- Pretty: pretty printing time durations (from https://github.com/ocpsoft/prettytime)
- Format: format time descriptions (from https://github.com/JodaOrg/joda-time)
This project has no dependencies.

View file

@ -1,38 +1,40 @@
plugins {
id "de.marcphilipp.nexus-publish" version "0.4.0"
id "io.codearte.nexus-staging" version "0.21.1"
id 'maven-publish'
id 'signing'
id "io.github.gradle-nexus.publish-plugin" version "2.0.0-rc-1"
id "org.xbib.gradle.plugin.asciidoctor" version "3.0.0"
}
wrapper {
gradleVersion = "${project.property('gradle.wrapper.version')}"
distributionType = Wrapper.DistributionType.ALL
gradleVersion = libs.versions.gradle.get()
distributionType = Wrapper.DistributionType.BIN
}
ext {
user = 'xbib'
user = 'joerg'
name = 'time'
description = 'A bundle of Chronic, Prettytime, and org.joda.time.format optimized for Java 8 Time API'
inceptionYear = '2016'
url = 'https://github.com/' + user + '/' + name
scmUrl = 'https://github.com/' + user + '/' + name
scmConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git'
scmDeveloperConnection = 'scm:git:ssh://git@github.com:' + user + '/' + name + '.git'
url = 'https://xbib.org/' + user + '/' + name
scmUrl = 'https://xbib.org/' + user + '/' + name
scmConnection = 'scm:git:git://xbib.org/' + user + '/' + name + '.git'
scmDeveloperConnection = 'scm:git:ssh://forgejo@xbib.org:' + user + '/' + name + '.git'
issueManagementSystem = 'Github'
issueManagementUrl = ext.scmUrl + '/issues'
licenseName = 'The Apache License, Version 2.0'
licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
apply plugin: 'java-library'
dependencies {
testImplementation "org.quartz-scheduler:quartz:${project.property('quartz.version')}"
testImplementation "com.google.caliper:caliper:${project.property('caliper.version')}"
}
apply from: rootProject.file('gradle/ide/idea.gradle')
apply from: rootProject.file('gradle/repositories/maven.gradle')
apply from: rootProject.file('gradle/compile/java.gradle')
apply from: rootProject.file('gradle/test/junit5.gradle')
apply from: rootProject.file('gradle/publishing/publication.gradle')
apply from: rootProject.file('gradle/publishing/sonatype.gradle')
apply from: rootProject.file('gradle/publish/maven.gradle')
apply from: rootProject.file('gradle/publish/forgejo.gradle')
apply from: rootProject.file('gradle/publish/sonatype.gradle')
dependencies {
testImplementation testLibs.quartz
testImplementation testLibs.caliper
testImplementation testLibs.guava
}

View file

@ -1,7 +1,3 @@
group = org.xbib
name = time
version = 2.1.1
gradle.wrapper.version = 6.6.1
quartz.version = 2.3.2
caliper.version = 1.0-beta-2
version = 4.0.0

View file

@ -2,17 +2,12 @@
apply plugin: 'java-library'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
modularity.inferModulePath.set(true)
}
compileJava {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
compileTestJava {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
withSourcesJar()
withJavadocJar()
}
jar {
@ -21,15 +16,14 @@ jar {
}
}
task sourcesJar(type: Jar, dependsOn: classes) {
classifier 'sources'
from sourceSets.main.allSource
tasks.withType(JavaCompile) {
options.fork = true
options.forkOptions.jvmArgs += ['-Duser.language=en','-Duser.country=US']
options.compilerArgs << '-Xlint:all'
options.encoding = 'UTF-8'
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier 'javadoc'
javadoc {
options.addStringOption('Xdoclint:none', '-quiet')
options.encoding = 'UTF-8'
}
artifacts {
archives sourcesJar, javadocJar
}

View file

@ -1,14 +1,5 @@
apply plugin: 'org.xbib.gradle.plugin.asciidoctor'
configurations {
asciidoclet
}
dependencies {
asciidoclet "org.asciidoctor:asciidoclet:${project.property('asciidoclet.version')}"
}
asciidoctor {
backends 'html5'
outputDir = file("${rootProject.projectDir}/docs")
@ -26,30 +17,3 @@ asciidoctor {
imagesdir: 'img',
stylesheet: "${projectDir}/src/docs/asciidoc/css/foundation.css"
}
/*javadoc {
options.docletpath = configurations.asciidoclet.files.asType(List)
options.doclet = 'org.asciidoctor.Asciidoclet'
//options.overview = "src/docs/asciidoclet/overview.adoc"
options.addStringOption "-base-dir", "${projectDir}"
options.addStringOption "-attribute",
"name=${project.name},version=${project.version},title-link=https://github.com/xbib/${project.name}"
configure(options) {
noTimestamp = true
}
}*/
/*javadoc {
options.docletpath = configurations.asciidoclet.files.asType(List)
options.doclet = 'org.asciidoctor.Asciidoclet'
options.overview = "${rootProject.projectDir}/src/docs/asciidoclet/overview.adoc"
options.addStringOption "-base-dir", "${projectDir}"
options.addStringOption "-attribute",
"name=${project.name},version=${project.version},title-link=https://github.com/xbib/${project.name}"
options.destinationDirectory(file("${projectDir}/docs/javadoc"))
configure(options) {
noTimestamp = true
}
}*/

View file

@ -6,8 +6,3 @@ idea {
testOutputDir file('build/classes/java/test')
}
}
if (project.convention.findPlugin(JavaPluginConvention)) {
//sourceSets.main.output.classesDirs = file("build/classes/java/main")
//sourceSets.test.output.classesDirs = file("build/classes/java/test")
}

View file

@ -0,0 +1,16 @@
if (project.hasProperty('forgeJoToken')) {
publishing {
repositories {
maven {
url 'https://xbib.org/api/packages/joerg/maven'
credentials(HttpHeaderCredentials) {
name = "Authorization"
value = "token ${project.property('forgeJoToken')}"
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
}
}

27
gradle/publish/ivy.gradle Normal file
View file

@ -0,0 +1,27 @@
apply plugin: 'ivy-publish'
publishing {
repositories {
ivy {
url = "https://xbib.org/repo"
}
}
publications {
ivy(IvyPublication) {
from components.java
descriptor {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
author {
name = 'Jörg Prante'
url = 'https://xbib.org/joerg'
}
descriptor.description {
text = rootProject.ext.description
}
}
}
}
}

View file

@ -1,13 +1,10 @@
apply plugin: "de.marcphilipp.nexus-publish"
publishing {
publications {
mavenJava(MavenPublication) {
"${project.name}"(MavenPublication) {
from components.java
artifact sourcesJar
artifact javadocJar
pom {
artifactId = project.name
name = project.name
description = rootProject.ext.description
url = rootProject.ext.url
@ -19,10 +16,10 @@ publishing {
}
developers {
developer {
id = 'jprante'
id = 'joerg'
name = 'Jörg Prante'
email = 'joergprante@gmail.com'
url = 'https://github.com/jprante'
url = 'https://xbib.org/joerg'
}
}
scm {
@ -49,18 +46,6 @@ publishing {
if (project.hasProperty("signing.keyId")) {
apply plugin: 'signing'
signing {
sign publishing.publications.mavenJava
sign publishing.publications."${project.name}"
}
}
if (project.hasProperty("ossrhUsername")) {
nexusPublishing {
repositories {
sonatype {
username = project.property('ossrhUsername')
password = project.property('ossrhPassword')
packageGroup = "org.xbib"
}
}
}
}

View file

@ -0,0 +1,11 @@
if (project.hasProperty('ossrhUsername') && project.hasProperty('ossrhPassword')) {
nexusPublishing {
repositories {
sonatype {
username = project.property('ossrhUsername')
password = project.property('ossrhPassword')
packageGroup = "org.xbib"
}
}
}
}

View file

@ -1,11 +0,0 @@
if (project.hasProperty('ossrhUsername') && project.hasProperty('ossrhPassword')) {
apply plugin: 'io.codearte.nexus-staging'
nexusStaging {
username = project.property('ossrhUsername')
password = project.property('ossrhPassword')
packageGroup = "org.xbib"
}
}

View file

@ -0,0 +1,19 @@
apply plugin: 'checkstyle'
tasks.withType(Checkstyle) {
ignoreFailures = true
reports {
xml.getRequired().set(true)
html.getRequired().set(true)
}
}
checkstyle {
configFile = rootProject.file('gradle/quality/checkstyle.xml')
ignoreFailures = true
showViolations = true
checkstyleMain {
source = sourceSets.main.allSource
}
}

View file

@ -9,6 +9,10 @@ page at http://checkstyle.sourceforge.net/config.html -->
<module name="Checker">
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value=".*(Example|Test|module-info)(\$.*)?"/>
</module>
<module name="FileTabCharacter">
<!-- Checks that there are no tab characters in the file.
-->
@ -56,10 +60,19 @@ page at http://checkstyle.sourceforge.net/config.html -->
<!-- Checks for out of order import statements. -->
<property name="severity" value="warning"/>
<property name="groups" value="com,junit,net,org,java,javax"/>
<!-- This ensures that static imports go first. -->
<property name="option" value="top"/>
<property name="tokens" value="STATIC_IMPORT, IMPORT"/>
<!-- <property name="tokens" value="IMPORT, STATIC_IMPORT"/> -->
<property name="separated" value="false"/>
<property name="groups" value="*"/>
<!-- <property name="option" value="above"/> -->
<property name="sortStaticImportsAlphabetically" value="true"/>
</module>
<module name="CustomImportOrder">
<!-- <property name="customImportOrderRules" value="THIRD_PARTY_PACKAGE###SPECIAL_IMPORTS###STANDARD_JAVA_PACKAGE###STATIC"/> -->
<!-- <property name="specialImportsRegExp" value="^javax\."/> -->
<!-- <property name="standardPackageRegExp" value="^java\."/> -->
<property name="sortImportsInGroupAlphabetically" value="true"/>
<property name="separateLineBetweenGroups" value="false"/>
</module>
<!--
@ -71,14 +84,10 @@ page at http://checkstyle.sourceforge.net/config.html -->
<!-- Checks for Javadoc comments. -->
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
<module name="JavadocMethod">
<property name="scope" value="protected"/>
<property name="accessModifiers" value="protected"/>
<property name="severity" value="warning"/>
<property name="allowMissingJavadoc" value="true"/>
<property name="allowMissingParamTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/>
<property name="allowMissingThrowsTags" value="true"/>
<property name="allowThrowsTagsForSubclasses" value="true"/>
<property name="allowUndeclaredRTE" value="true"/>
</module>
<module name="JavadocType">
@ -184,21 +193,6 @@ page at http://checkstyle.sourceforge.net/config.html -->
-->
<module name="LineLength">
<!-- Checks if a line is too long. -->
<property name="max" value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.max}" default="128"/>
<property name="severity" value="error"/>
<!--
The default ignore pattern exempts the following elements:
- import statements
- long URLs inside comments
-->
<property name="ignorePattern"
value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
default="^(package .*;\s*)|(import .*;\s*)|( *(\*|//).*https?://.*)$"/>
</module>
<module name="LeftCurly">
<!-- Checks for placement of the left curly brace ('{'). -->
@ -319,5 +313,21 @@ page at http://checkstyle.sourceforge.net/config.html -->
</module>
</module>
<module name="LineLength">
<!-- Checks if a line is too long. -->
<property name="max" value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.max}" default="128"/>
<property name="severity" value="error"/>
<!--
The default ignore pattern exempts the following elements:
- import statements
- long URLs inside comments
-->
<property name="ignorePattern"
value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
default="^(package .*;\s*)|(import .*;\s*)|( *(\*|//).*https?://.*)$"/>
</module>
</module>

View file

@ -0,0 +1,11 @@
cyclonedxBom {
includeConfigs = [ 'runtimeClasspath' ]
skipConfigs = [ 'compileClasspath', 'testCompileClasspath' ]
projectType = "library"
schemaVersion = "1.4"
destination = file("build/reports")
outputName = "bom"
outputFormat = "json"
includeBomSerialNumber = true
componentVersion = "2.0.0"
}

17
gradle/quality/pmd.gradle Normal file
View file

@ -0,0 +1,17 @@
apply plugin: 'pmd'
tasks.withType(Pmd) {
ignoreFailures = true
reports {
xml.getRequired().set(true)
html.getRequired().set(true)
}
}
pmd {
ignoreFailures = true
consoleOutput = false
toolVersion = "6.51.0"
ruleSetFiles = rootProject.files('gradle/quality/pmd/category/java/bestpractices.xml')
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,10 @@
rulesets.filenames=\
category/java/bestpractices.xml,\
category/java/codestyle.xml,\
category/java/design.xml,\
category/java/documentation.xml,\
category/java/errorprone.xml,\
category/java/multithreading.xml,\
category/java/performance.xml,\
category/java/security.xml

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,144 @@
<?xml version="1.0"?>
<ruleset name="Documentation"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<description>
Rules that are related to code documentation.
</description>
<rule name="CommentContent"
since="5.0"
message="Invalid words or phrases found"
class="net.sourceforge.pmd.lang.java.rule.documentation.CommentContentRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_documentation.html#commentcontent">
<description>
A rule for the politically correct... we don't want to offend anyone.
</description>
<priority>3</priority>
<example>
<![CDATA[
//OMG, this is horrible, Bob is an idiot !!!
]]>
</example>
</rule>
<rule name="CommentRequired"
since="5.1"
message="Comment is required"
class="net.sourceforge.pmd.lang.java.rule.documentation.CommentRequiredRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_documentation.html#commentrequired">
<description>
Denotes whether comments are required (or unwanted) for specific language elements.
</description>
<priority>3</priority>
<example>
<![CDATA[
/**
*
*
* @author Jon Doe
*/
]]>
</example>
</rule>
<rule name="CommentSize"
since="5.0"
message="Comment is too large"
class="net.sourceforge.pmd.lang.java.rule.documentation.CommentSizeRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_documentation.html#commentsize">
<description>
Determines whether the dimensions of non-header comments found are within the specified limits.
</description>
<priority>3</priority>
<example>
<![CDATA[
/**
*
* too many lines!
*
*
*
*
*
*
*
*
*
*
*
*
*/
]]>
</example>
</rule>
<rule name="UncommentedEmptyConstructor"
language="java"
since="3.4"
message="Document empty constructor"
class="net.sourceforge.pmd.lang.rule.XPathRule"
typeResolution="true"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_documentation.html#uncommentedemptyconstructor">
<description>
Uncommented Empty Constructor finds instances where a constructor does not
contain statements, but there is no comment. By explicitly commenting empty
constructors it is easier to distinguish between intentional (commented)
and unintentional empty constructors.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//ConstructorDeclaration[@Private='false']
[count(BlockStatement) = 0 and ($ignoreExplicitConstructorInvocation = 'true' or not(ExplicitConstructorInvocation)) and @containsComment = 'false']
[not(../Annotation/MarkerAnnotation/Name[pmd-java:typeIs('javax.inject.Inject')])]
]]>
</value>
</property>
<property name="ignoreExplicitConstructorInvocation" type="Boolean" description="Ignore explicit constructor invocation when deciding whether constructor is empty or not" value="false"/>
</properties>
<example>
<![CDATA[
public Foo() {
// This constructor is intentionally empty. Nothing special is needed here.
}
]]>
</example>
</rule>
<rule name="UncommentedEmptyMethodBody"
language="java"
since="3.4"
message="Document empty method body"
class="net.sourceforge.pmd.lang.rule.XPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_documentation.html#uncommentedemptymethodbody">
<description>
Uncommented Empty Method Body finds instances where a method body does not contain
statements, but there is no comment. By explicitly commenting empty method bodies
it is easier to distinguish between intentional (commented) and unintentional
empty methods.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//MethodDeclaration/Block[count(BlockStatement) = 0 and @containsComment = 'false']
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
public void doSomething() {
}
]]>
</example>
</rule>
</ruleset>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,393 @@
<?xml version="1.0"?>
<ruleset name="Multithreading"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<description>
Rules that flag issues when dealing with multiple threads of execution.
</description>
<rule name="AvoidSynchronizedAtMethodLevel"
language="java"
since="3.0"
message="Use block level rather than method level synchronization"
class="net.sourceforge.pmd.lang.rule.XPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#avoidsynchronizedatmethodlevel">
<description>
Method-level synchronization can cause problems when new code is added to the method.
Block-level synchronization helps to ensure that only the code that needs synchronization
gets it.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>//MethodDeclaration[@Synchronized='true']</value>
</property>
</properties>
<example>
<![CDATA[
public class Foo {
// Try to avoid this:
synchronized void foo() {
}
// Prefer this:
void bar() {
synchronized(this) {
}
}
// Try to avoid this for static methods:
static synchronized void fooStatic() {
}
// Prefer this:
static void barStatic() {
synchronized(Foo.class) {
}
}
}
]]>
</example>
</rule>
<rule name="AvoidThreadGroup"
language="java"
since="3.6"
message="Avoid using java.lang.ThreadGroup; it is not thread safe"
class="net.sourceforge.pmd.lang.rule.XPathRule"
typeResolution="true"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#avoidthreadgroup">
<description>
Avoid using java.lang.ThreadGroup; although it is intended to be used in a threaded environment
it contains methods that are not thread-safe.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//AllocationExpression/ClassOrInterfaceType[pmd-java:typeIs('java.lang.ThreadGroup')]|
//PrimarySuffix[contains(@Image, 'getThreadGroup')]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
public class Bar {
void buz() {
ThreadGroup tg = new ThreadGroup("My threadgroup");
tg = new ThreadGroup(tg, "my thread group");
tg = Thread.currentThread().getThreadGroup();
tg = System.getSecurityManager().getThreadGroup();
}
}
]]>
</example>
</rule>
<rule name="AvoidUsingVolatile"
language="java"
since="4.1"
class="net.sourceforge.pmd.lang.rule.XPathRule"
message="Use of modifier volatile is not recommended."
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#avoidusingvolatile">
<description>
Use of the keyword 'volatile' is generally used to fine tune a Java application, and therefore, requires
a good expertise of the Java Memory Model. Moreover, its range of action is somewhat misknown. Therefore,
the volatile keyword should not be used for maintenance purpose and portability.
</description>
<priority>2</priority>
<properties>
<property name="xpath">
<value>//FieldDeclaration[contains(@Volatile,'true')]</value>
</property>
</properties>
<example>
<![CDATA[
public class ThrDeux {
private volatile String var1; // not suggested
private String var2; // preferred
}
]]>
</example>
</rule>
<rule name="DoNotUseThreads"
language="java"
since="4.1"
class="net.sourceforge.pmd.lang.rule.XPathRule"
message="To be compliant to J2EE, a webapp should not use any thread."
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#donotusethreads">
<description>
The J2EE specification explicitly forbids the use of threads.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>//ClassOrInterfaceType[@Image = 'Thread' or @Image = 'Runnable']</value>
</property>
</properties>
<example>
<![CDATA[
// This is not allowed
public class UsingThread extends Thread {
}
// Neither this,
public class OtherThread implements Runnable {
// Nor this ...
public void methode() {
Runnable thread = new Thread(); thread.run();
}
}
]]>
</example>
</rule>
<rule name="DontCallThreadRun"
language="java"
since="4.3"
message="Don't call Thread.run() explicitly, use Thread.start()"
class="net.sourceforge.pmd.lang.rule.XPathRule"
typeResolution="true"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#dontcallthreadrun">
<description>
Explicitly calling Thread.run() method will execute in the caller's thread of control. Instead, call Thread.start() for the intended behavior.
</description>
<priority>4</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//StatementExpression/PrimaryExpression
[
PrimaryPrefix
[
./Name[ends-with(@Image, '.run') or @Image = 'run']
and substring-before(Name/@Image, '.') =//VariableDeclarator/VariableDeclaratorId/@Image
[../../../Type/ReferenceType/ClassOrInterfaceType[pmd-java:typeIs('java.lang.Thread')]]
or (./AllocationExpression/ClassOrInterfaceType[pmd-java:typeIs('java.lang.Thread')]
and ../PrimarySuffix[@Image = 'run'])
]
]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
Thread t = new Thread();
t.run(); // use t.start() instead
new Thread().run(); // same violation
]]>
</example>
</rule>
<rule name="DoubleCheckedLocking"
language="java"
since="1.04"
message="Double checked locking is not thread safe in Java."
class="net.sourceforge.pmd.lang.java.rule.multithreading.DoubleCheckedLockingRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#doublecheckedlocking">
<description>
Partially created objects can be returned by the Double Checked Locking pattern when used in Java.
An optimizing JRE may assign a reference to the baz variable before it calls the constructor of the object the
reference points to.
Note: With Java 5, you can make Double checked locking work, if you declare the variable to be `volatile`.
For more details refer to: &lt;http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html>
or &lt;http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html>
</description>
<priority>1</priority>
<example>
<![CDATA[
public class Foo {
/*volatile */ Object baz = null; // fix for Java5 and later: volatile
Object bar() {
if (baz == null) { // baz may be non-null yet not fully created
synchronized(this) {
if (baz == null) {
baz = new Object();
}
}
}
return baz;
}
}
]]>
</example>
</rule>
<rule name="NonThreadSafeSingleton"
since="3.4"
message="Singleton is not thread safe"
class="net.sourceforge.pmd.lang.java.rule.multithreading.NonThreadSafeSingletonRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#nonthreadsafesingleton">
<description>
Non-thread safe singletons can result in bad state changes. Eliminate
static singletons if possible by instantiating the object directly. Static
singletons are usually not needed as only a single instance exists anyway.
Other possible fixes are to synchronize the entire method or to use an
[initialize-on-demand holder class](https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom).
Refrain from using the double-checked locking pattern. The Java Memory Model doesn't
guarantee it to work unless the variable is declared as `volatile`, adding an uneeded
performance penalty. [Reference](http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)
See Effective Java, item 48.
</description>
<priority>3</priority>
<example>
<![CDATA[
private static Foo foo = null;
//multiple simultaneous callers may see partially initialized objects
public static Foo getFoo() {
if (foo==null) {
foo = new Foo();
}
return foo;
}
]]>
</example>
</rule>
<rule name="UnsynchronizedStaticDateFormatter"
since="3.6"
deprecated="true"
message="Static DateFormatter objects should be accessed in a synchronized manner"
class="net.sourceforge.pmd.lang.java.rule.multithreading.UnsynchronizedStaticDateFormatterRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#unsynchronizedstaticdateformatter">
<description>
SimpleDateFormat instances are not synchronized. Sun recommends using separate format instances
for each thread. If multiple threads must access a static formatter, the formatter must be
synchronized either on method or block level.
This rule has been deprecated in favor of the rule {% rule UnsynchronizedStaticFormatter %}.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
private static final SimpleDateFormat sdf = new SimpleDateFormat();
void bar() {
sdf.format(); // poor, no thread-safety
}
synchronized void foo() {
sdf.format(); // preferred
}
}
]]>
</example>
</rule>
<rule name="UnsynchronizedStaticFormatter"
since="6.11.0"
message="Static Formatter objects should be accessed in a synchronized manner"
class="net.sourceforge.pmd.lang.java.rule.multithreading.UnsynchronizedStaticFormatterRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#unsynchronizedstaticformatter">
<description>
Instances of `java.text.Format` are generally not synchronized.
Sun recommends using separate format instances for each thread.
If multiple threads must access a static formatter, the formatter must be
synchronized either on method or block level.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
private static final SimpleDateFormat sdf = new SimpleDateFormat();
void bar() {
sdf.format(); // poor, no thread-safety
}
synchronized void foo() {
sdf.format(); // preferred
}
}
]]>
</example>
</rule>
<rule name="UseConcurrentHashMap"
language="java"
minimumLanguageVersion="1.5"
since="4.2.6"
message="If you run in Java5 or newer and have concurrent access, you should use the ConcurrentHashMap implementation"
class="net.sourceforge.pmd.lang.rule.XPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#useconcurrenthashmap">
<description>
Since Java5 brought a new implementation of the Map designed for multi-threaded access, you can
perform efficient map reads without blocking other threads.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//Type[../VariableDeclarator/VariableInitializer//AllocationExpression/ClassOrInterfaceType[@Image != 'ConcurrentHashMap']]
/ReferenceType/ClassOrInterfaceType[@Image = 'Map']
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
public class ConcurrentApp {
public void getMyInstance() {
Map map1 = new HashMap(); // fine for single-threaded access
Map map2 = new ConcurrentHashMap(); // preferred for use with multiple threads
// the following case will be ignored by this rule
Map map3 = someModule.methodThatReturnMap(); // might be OK, if the returned map is already thread-safe
}
}
]]>
</example>
</rule>
<rule name="UseNotifyAllInsteadOfNotify"
language="java"
since="3.0"
message="Call Thread.notifyAll() rather than Thread.notify()"
class="net.sourceforge.pmd.lang.rule.XPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#usenotifyallinsteadofnotify">
<description>
Thread.notify() awakens a thread monitoring the object. If more than one thread is monitoring, then only
one is chosen. The thread chosen is arbitrary; thus its usually safer to call notifyAll() instead.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//StatementExpression/PrimaryExpression
[PrimarySuffix/Arguments[@ArgumentCount = '0']]
[
PrimaryPrefix[
./Name[@Image='notify' or ends-with(@Image,'.notify')]
or ../PrimarySuffix/@Image='notify'
or (./AllocationExpression and ../PrimarySuffix[@Image='notify'])
]
]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
void bar() {
x.notify();
// If many threads are monitoring x, only one (and you won't know which) will be notified.
// use instead:
x.notifyAll();
}
]]>
</example>
</rule>
</ruleset>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,65 @@
<?xml version="1.0"?>
<ruleset name="Security" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<description>
Rules that flag potential security flaws.
</description>
<rule name="HardCodedCryptoKey"
since="6.4.0"
message="Do not use hard coded encryption keys"
class="net.sourceforge.pmd.lang.java.rule.security.HardCodedCryptoKeyRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_security.html#hardcodedcryptokey">
<description>
Do not use hard coded values for cryptographic operations. Please store keys outside of source code.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
void good() {
SecretKeySpec secretKeySpec = new SecretKeySpec(Properties.getKey(), "AES");
}
void bad() {
SecretKeySpec secretKeySpec = new SecretKeySpec("my secret here".getBytes(), "AES");
}
}
]]>
</example>
</rule>
<rule name="InsecureCryptoIv"
since="6.3.0"
message="Do not use hard coded initialization vector in crypto operations"
class="net.sourceforge.pmd.lang.java.rule.security.InsecureCryptoIvRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_security.html#insecurecryptoiv">
<description>
Do not use hard coded initialization vector in cryptographic operations. Please use a randomly generated IV.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
void good() {
SecureRandom random = new SecureRandom();
byte iv[] = new byte[16];
random.nextBytes(bytes);
}
void bad() {
byte[] iv = new byte[] { 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, };
}
void alsoBad() {
byte[] iv = "secret iv in here".getBytes();
}
}
]]>
</example>
</rule>
</ruleset>

View file

@ -0,0 +1,37 @@
subprojects {
sonarqube {
properties {
property "sonar.projectName", "${project.group} ${project.name}"
property "sonar.sourceEncoding", "UTF-8"
property "sonar.tests", "src/test/java"
property "sonar.scm.provider", "git"
property "sonar.junit.reportsPath", "build/test-results/test/"
}
}
tasks.withType(Pmd) {
ignoreFailures = true
reports {
xml.enabled = true
html.enabled = true
}
}
spotbugs {
effort = "max"
reportLevel = "low"
//includeFilter = file("findbugs-exclude.xml")
}
tasks.withType(com.github.spotbugs.SpotBugsTask) {
ignoreFailures = true
reports {
xml.enabled = false
html.enabled = true
}
}
}

View file

@ -0,0 +1,15 @@
apply plugin: 'com.github.spotbugs'
spotbugs {
effort = "max"
reportLevel = "low"
ignoreFailures = true
}
spotbugsMain {
reports {
xml.getRequired().set(false)
html.getRequired().set(true)
}
}

View file

@ -1,12 +1,9 @@
def junitVersion = project.hasProperty('junit.version')?project.property('junit.version'):'5.6.2'
def hamcrestVersion = project.hasProperty('hamcrest.version')?project.property('hamcrest.version'):'2.2'
dependencies {
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitVersion}"
testImplementation "org.junit.jupiter:junit-jupiter-params:${junitVersion}"
testImplementation "org.hamcrest:hamcrest-library:${hamcrestVersion}"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}"
testImplementation testLibs.junit.jupiter.api
testImplementation testLibs.junit.jupiter.params
testImplementation testLibs.hamcrest
testRuntimeOnly testLibs.junit.jupiter.engine
testRuntimeOnly testLibs.junit.jupiter.platform.launcher
}
test {
@ -24,4 +21,16 @@ test {
"${result.skippedTestCount} skipped"
}
}
// for Guava using reflection on JDK classes which JDK17 does not like
jvmArgs '--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED',
'--add-exports=java.base/jdk.internal.ref=ALL-UNNAMED',
'--add-exports=java.base/sun.nio.ch=ALL-UNNAMED',
'--add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED',
'--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED',
'--add-opens=jdk.compiler/com.sun.tools.javac=ALL-UNNAMED',
'--add-opens=java.base/java.lang=ALL-UNNAMED',
'--add-opens=java.base/java.lang.reflect=ALL-UNNAMED',
'--add-opens=java.base/java.io=ALL-UNNAMED',
'--add-opens=java.base/java.util=ALL-UNNAMED'
}

Binary file not shown.

View file

@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

294
gradlew vendored
View file

@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -17,67 +17,99 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@ -87,9 +119,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -98,88 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

35
gradlew.bat vendored
View file

@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

View file

@ -1 +1,33 @@
rootProject.name = name
pluginManagement {
repositories {
mavenLocal()
mavenCentral {
metadataSources {
mavenPom()
artifact()
ignoreGradleMetadataRedirection()
}
}
gradlePluginPortal()
}
}
dependencyResolutionManagement {
versionCatalogs {
libs {
version('gradle', '8.7')
}
testLibs {
version('junit', '5.10.2')
library('junit-jupiter-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit')
library('junit-jupiter-params', 'org.junit.jupiter', 'junit-jupiter-params').versionRef('junit')
library('junit-jupiter-engine', 'org.junit.jupiter', 'junit-jupiter-engine').versionRef('junit')
library('junit-jupiter-platform-launcher', 'org.junit.platform', 'junit-platform-launcher').version('1.10.0')
library('hamcrest', 'org.hamcrest', 'hamcrest-library').version('2.2')
library('junit4', 'junit', 'junit').version('4.13.2')
library('quartz', 'org.quartz-scheduler', 'quartz').version('2.3.2')
library('caliper', 'com.google.caliper', 'caliper').version('1.0-beta-3')
library('guava', 'com.google.guava', 'guava').version('32.1.3-jre')
}
}
}

View file

@ -9,5 +9,4 @@ module org.xbib.time {
exports org.xbib.time.pretty.i18n;
exports org.xbib.time.pretty.units;
exports org.xbib.time.schedule;
exports org.xbib.time.util;
}

View file

@ -1,6 +1,6 @@
package org.xbib.time.chronic;
import org.xbib.time.chronic.tags.Pointer;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZoneId;
import java.time.ZonedDateTime;
@ -9,15 +9,21 @@ import java.time.ZonedDateTime;
*
*/
public class Options {
private ZonedDateTime now;
private ZoneId zoneId;
private Pointer.PointerType context;
private PointerType context;
private boolean guess;
private int ambiguousTimeRange;
private boolean compatibilityMode;
public Options() {
setContext(Pointer.PointerType.FUTURE);
setContext(PointerType.FUTURE);
setNow(ZonedDateTime.now());
setZoneId(ZoneId.of("GMT"));
setGuess(true);
@ -33,11 +39,11 @@ public class Options {
return this;
}
public Pointer.PointerType getContext() {
public PointerType getContext() {
return context;
}
public Options setContext(Pointer.PointerType context) {
public Options setContext(PointerType context) {
this.context = context;
return this;
}

View file

@ -4,8 +4,10 @@ package org.xbib.time.chronic;
*
*/
public class Range {
private Long begin;
private Long end;
private final Long begin;
private final Long end;
public Range(long begin, long end) {
this.begin = begin;

View file

@ -4,8 +4,10 @@ package org.xbib.time.chronic;
*
*/
public class Tick {
private int time;
private boolean ambiguous;
private final boolean ambiguous;
public Tick(int time, boolean ambiguous) {
this.time = time;

View file

@ -10,8 +10,10 @@ import java.util.List;
*
*/
public class Token {
private String word;
private List<Tag<?>> tags;
private final String word;
private final List<Tag<?>> tags;
public Token(String word) {
this.word = word;
@ -35,13 +37,7 @@ public class Token {
* @param tagClass tag class
*/
public void untag(Class<?> tagClass) {
Iterator<Tag<?>> tagIter = tags.iterator();
while (tagIter.hasNext()) {
Tag<?> tag = tagIter.next();
if (tagClass.isInstance(tag)) {
tagIter.remove();
}
}
tags.removeIf(tagClass::isInstance);
}
/**
@ -58,7 +54,6 @@ public class Token {
* @param <T> type parameter
* @return tag
*/
@SuppressWarnings("unchecked")
public <T extends Tag<?>> T getTag(Class<T> tagClass) {
List<T> matches = getTags(tagClass);
T matchingTag = null;

View file

@ -3,6 +3,7 @@ package org.xbib.time.chronic.handlers;
import org.xbib.time.chronic.Options;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.Token;
import org.xbib.time.chronic.repeaters.DayPortion;
import org.xbib.time.chronic.repeaters.EnumRepeaterDayPortion;
import org.xbib.time.chronic.repeaters.IntegerRepeaterDayPortion;
import org.xbib.time.chronic.repeaters.Repeater;
@ -14,7 +15,8 @@ import org.xbib.time.chronic.tags.Grabber;
import org.xbib.time.chronic.tags.Ordinal;
import org.xbib.time.chronic.tags.OrdinalDay;
import org.xbib.time.chronic.tags.Pointer;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import org.xbib.time.chronic.tags.Relative;
import org.xbib.time.chronic.tags.Scalar;
import org.xbib.time.chronic.tags.ScalarDay;
import org.xbib.time.chronic.tags.ScalarMonth;
@ -202,7 +204,7 @@ public class Handler {
}
public static Span getAnchor(List<Token> tokens, Options options) {
Grabber grabber = new Grabber(Grabber.Relative.THIS);
Grabber grabber = new Grabber(Relative.THIS);
PointerType pointer = PointerType.FUTURE;
List<Repeater<?>> repeaters = getRepeaters(tokens);
@ -219,16 +221,16 @@ public class Handler {
head.setNow(options.getNow());
Span outerSpan;
Grabber.Relative grabberType = grabber.getType();
if (grabberType == Grabber.Relative.LAST) {
Relative grabberType = grabber.getType();
if (grabberType == Relative.LAST) {
outerSpan = head.nextSpan(PointerType.PAST);
} else if (grabberType == Grabber.Relative.THIS) {
} else if (grabberType == Relative.THIS) {
if (!repeaters.isEmpty()) {
outerSpan = head.thisSpan(PointerType.NONE);
} else {
outerSpan = head.thisSpan(options.getContext());
}
} else if (grabberType == Grabber.Relative.NEXT) {
} else if (grabberType == Relative.NEXT) {
outerSpan = head.nextSpan(PointerType.FUTURE);
} else {
throw new IllegalArgumentException("Invalid grabber type " + grabberType + ".");
@ -296,14 +298,14 @@ public class Handler {
Tag<RepeaterDayPortion<?>> t1Tag = t1.getTag(RepeaterDayPortion.class);
Object t1TagType = t1Tag.getType();
if (RepeaterDayPortion.DayPortion.MORNING.equals(t1TagType)) {
if (DayPortion.MORNING.equals(t1TagType)) {
t1.untag(RepeaterDayPortion.class);
t1.tag(new EnumRepeaterDayPortion(RepeaterDayPortion.DayPortion.AM));
} else if (RepeaterDayPortion.DayPortion.AFTERNOON.equals(t1TagType) ||
RepeaterDayPortion.DayPortion.EVENING.equals(t1TagType) ||
RepeaterDayPortion.DayPortion.NIGHT.equals(t1TagType)) {
t1.tag(new EnumRepeaterDayPortion(DayPortion.AM));
} else if (DayPortion.AFTERNOON.equals(t1TagType) ||
DayPortion.EVENING.equals(t1TagType) ||
DayPortion.NIGHT.equals(t1TagType)) {
t1.untag(RepeaterDayPortion.class);
t1.tag(new EnumRepeaterDayPortion(RepeaterDayPortion.DayPortion.PM));
t1.tag(new EnumRepeaterDayPortion(DayPortion.PM));
}
}

View file

@ -4,7 +4,8 @@ package org.xbib.time.chronic.handlers;
*
*/
public class HandlerPattern {
private boolean optional;
private final boolean optional;
public HandlerPattern(boolean optional) {
this.optional = optional;

View file

@ -4,7 +4,8 @@ package org.xbib.time.chronic.handlers;
*
*/
public class HandlerTypePattern extends HandlerPattern {
private Handler.HandlerType type;
private final Handler.HandlerType type;
public HandlerTypePattern(Handler.HandlerType type) {
this(type, false);

View file

@ -11,5 +11,6 @@ import java.util.List;
*/
@FunctionalInterface
public interface IHandler {
Span handle(List<Token> tokens, Options options);
}

View file

@ -16,5 +16,4 @@ public class ORGRHandler extends ORRHandler {
Span outerSpan = Handler.getAnchor(tokens.subList(2, 4), options);
return handle(tokens.subList(0, 2), outerSpan, options);
}
}

View file

@ -5,7 +5,7 @@ import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.Token;
import org.xbib.time.chronic.repeaters.Repeater;
import org.xbib.time.chronic.tags.Ordinal;
import org.xbib.time.chronic.tags.Pointer;
import org.xbib.time.chronic.tags.PointerType;
import java.time.temporal.ChronoUnit;
import java.util.List;
@ -21,7 +21,7 @@ public abstract class ORRHandler implements IHandler {
Integer ordinalValue = tokens.get(0).getTag(Ordinal.class).getType();
Span span = null;
for (int i = 0; i < ordinalValue; i++) {
span = repeater.nextSpan(Pointer.PointerType.FUTURE);
span = repeater.nextSpan(PointerType.FUTURE);
if (span.getBegin() > outerSpan.getEnd()) {
span = null;
break;

View file

@ -16,5 +16,4 @@ public class ORSRHandler extends ORRHandler {
Span outerSpan = Handler.getAnchor(tokens.subList(3, 4), options);
return handle(tokens.subList(0, 2), outerSpan, options);
}
}

View file

@ -16,5 +16,4 @@ public class RHandler implements IHandler {
List<Token> ddTokens = Handler.dealiasAndDisambiguateTimes(tokens, options);
return Handler.getAnchor(ddTokens, options);
}
}

View file

@ -30,5 +30,4 @@ public class RmnSdSyHandler implements IHandler {
}
return span;
}
}

View file

@ -29,5 +29,4 @@ public class RmnSyHandler implements IHandler {
}
return span;
}
}

View file

@ -16,5 +16,4 @@ public class SRPAHandler extends SRPHandler {
Span anchorSpan = Handler.getAnchor(tokens.subList(3, tokens.size()), options);
return super.handle(tokens, anchorSpan, options);
}
}

View file

@ -6,6 +6,7 @@ import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.Token;
import org.xbib.time.chronic.repeaters.Repeater;
import org.xbib.time.chronic.tags.Pointer;
import org.xbib.time.chronic.tags.PointerType;
import org.xbib.time.chronic.tags.Scalar;
import java.text.ParseException;
@ -19,7 +20,7 @@ public class SRPHandler implements IHandler {
public Span handle(List<Token> tokens, Span span, Options options) {
int distance = tokens.get(0).getTag(Scalar.class).getType();
Repeater<?> repeater = tokens.get(1).getTag(Repeater.class);
Pointer.PointerType pointer = tokens.get(2).getTag(Pointer.class).getType();
PointerType pointer = tokens.get(2).getTag(Pointer.class).getType();
return repeater.getOffset(span, distance, pointer);
}

View file

@ -21,5 +21,4 @@ public class SdRmnSyHandler extends RmnSdSyHandler {
newTokens.addAll(tokens.subList(3, tokens.size()));
return super.handle(newTokens, options);
}
}

View file

@ -23,5 +23,4 @@ public class SmSdHandler implements IHandler {
ZonedDateTime end = start.plus(1, ChronoUnit.MONTHS);
return new Span(start, end);
}
}

View file

@ -30,5 +30,4 @@ public class SmSdSyHandler implements IHandler {
}
return span;
}
}

View file

@ -29,5 +29,4 @@ public class SmSyHandler implements IHandler {
}
return span;
}
}

View file

@ -7,7 +7,8 @@ import org.xbib.time.chronic.tags.Tag;
*/
@SuppressWarnings("rawtypes")
public class TagPattern extends HandlerPattern {
private Class<? extends Tag> tagClass;
private final Class<? extends Tag> tagClass;
public TagPattern(Class<? extends Tag> tagClass) {
this(tagClass, false);

View file

@ -48,7 +48,7 @@ public class Numerizer {
directNums.add(new DirectNum("nine(\\W|$)", "9$1"));
directNums.add(new DirectNum("ten", "10"));
directNums.add(new DirectNum("\\ba\\b", "1"));
DIRECT_NUMS = directNums.toArray(new DirectNum[directNums.size()]);
DIRECT_NUMS = directNums.toArray(new DirectNum[0]);
List<TenPrefix> tenPrefixes = new LinkedList<>();
tenPrefixes.add(new TenPrefix("twenty", 20));
@ -60,7 +60,7 @@ public class Numerizer {
tenPrefixes.add(new TenPrefix("eighty", 80));
tenPrefixes.add(new TenPrefix("ninety", 90));
tenPrefixes.add(new TenPrefix("ninty", 90));
TEN_PREFIXES = tenPrefixes.toArray(new TenPrefix[tenPrefixes.size()]);
TEN_PREFIXES = tenPrefixes.toArray(new TenPrefix[0]);
List<BigPrefix> bigPrefixes = new LinkedList<>();
bigPrefixes.add(new BigPrefix("hundred", 100L));
@ -68,7 +68,7 @@ public class Numerizer {
bigPrefixes.add(new BigPrefix("million", 1000000L));
bigPrefixes.add(new BigPrefix("billion", 1000000000L));
bigPrefixes.add(new BigPrefix("trillion", 1000000000000L));
BIG_PREFIXES = bigPrefixes.toArray(new BigPrefix[bigPrefixes.size()]);
BIG_PREFIXES = bigPrefixes.toArray(new BigPrefix[0]);
}
public static String numerize(String str) {
@ -81,7 +81,7 @@ public class Numerizer {
for (Prefix tp : Numerizer.TEN_PREFIXES) {
Matcher matcher = tp.getName().matcher(numerizedStr);
if (matcher.find()) {
StringBuffer matcherBuffer = new StringBuffer();
StringBuilder matcherBuffer = new StringBuilder();
do {
if (matcher.group(1) == null) {
matcher.appendReplacement(matcherBuffer, String.valueOf(tp.getNumber()));
@ -97,7 +97,7 @@ public class Numerizer {
for (Prefix bp : Numerizer.BIG_PREFIXES) {
Matcher matcher = bp.getName().matcher(numerizedStr);
if (matcher.find()) {
StringBuffer matcherBuffer = new StringBuffer();
StringBuilder matcherBuffer = new StringBuilder();
do {
if (matcher.group(1) == null) {
matcher.appendReplacement(matcherBuffer, String.valueOf(bp.getNumber()));
@ -113,7 +113,7 @@ public class Numerizer {
}
Matcher matcher = Numerizer.DEHAALFER.matcher(numerizedStr);
if (matcher.find()) {
StringBuffer matcherBuffer = new StringBuffer();
StringBuilder matcherBuffer = new StringBuilder();
do {
matcher.appendReplacement(matcherBuffer,
String.valueOf(Float.parseFloat(matcher.group(1).trim()) + 0.5f));
@ -142,8 +142,10 @@ public class Numerizer {
*
*/
private static class DirectNum {
private Pattern name;
private String number;
private final Pattern name;
private final String number;
DirectNum(String name, String number) {
this.name = Pattern.compile(name, Pattern.CASE_INSENSITIVE);
@ -163,8 +165,10 @@ public class Numerizer {
*
*/
static class Prefix {
private Pattern name;
private long number;
private final Pattern name;
private final long number;
Prefix(Pattern name, long number) {
this.name = name;

View file

@ -0,0 +1,8 @@
package org.xbib.time.chronic.repeaters;
/**
*
*/
public enum DayName {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

View file

@ -0,0 +1,8 @@
package org.xbib.time.chronic.repeaters;
/**
*
*/
public enum DayPortion {
AM, PM, MORNING, AFTERNOON, EVENING, NIGHT
}

View file

@ -5,12 +5,18 @@ import org.xbib.time.chronic.Range;
/**
*
*/
public class EnumRepeaterDayPortion extends RepeaterDayPortion<RepeaterDayPortion.DayPortion> {
public class EnumRepeaterDayPortion extends RepeaterDayPortion<DayPortion> {
private static final Range AM_RANGE = new Range(0, 12 * 60 * 60); // 12am-12pm
private static final Range PM_RANGE = new Range(12 * 60 * 60, 24 * 60 * 60 - 1); // 12pm-12am
private static final Range MORNING_RANGE = new Range(6 * 60 * 60, 12 * 60 * 60); // 6am-12pm
private static final Range AFTERNOON_RANGE = new Range(13 * 60 * 60, 17 * 60 * 60); // 1pm-5pm
private static final Range EVENING_RANGE = new Range(17 * 60 * 60, 20 * 60 * 60); // 5pm-8pm
private static final Range NIGHT_RANGE = new Range(20 * 60 * 60, 24 * 60 * 60); // 8pm-12pm
public EnumRepeaterDayPortion(DayPortion type) {

View file

@ -6,6 +6,7 @@ import org.xbib.time.chronic.Range;
*
*/
public class IntegerRepeaterDayPortion extends RepeaterDayPortion<Integer> {
public IntegerRepeaterDayPortion(Integer type) {
super(type);
}

View file

@ -0,0 +1,9 @@
package org.xbib.time.chronic.repeaters;
/**
*
*/
public enum MonthName {
ZEROMONTH_DO_NOT_REMOVE,
JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER
}

View file

@ -3,7 +3,7 @@ package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Options;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.Token;
import org.xbib.time.chronic.tags.Pointer;
import org.xbib.time.chronic.tags.PointerType;
import org.xbib.time.chronic.tags.Tag;
import java.util.List;
@ -65,25 +65,25 @@ public abstract class Repeater<T> extends Tag<T> implements Comparable<Repeater<
* @param pointer pointer
* @return span
*/
public Span nextSpan(Pointer.PointerType pointer) {
public Span nextSpan(PointerType pointer) {
if (getNow() == null) {
throw new IllegalStateException("Start point must be set before calling #next");
}
return internalNextSpan(pointer);
}
protected abstract Span internalNextSpan(Pointer.PointerType pointer);
protected abstract Span internalNextSpan(PointerType pointer);
public Span thisSpan(Pointer.PointerType pointer) {
public Span thisSpan(PointerType pointer) {
if (getNow() == null) {
throw new IllegalStateException("Start point must be set before calling #this");
}
return internalThisSpan(pointer);
}
protected abstract Span internalThisSpan(Pointer.PointerType pointer);
protected abstract Span internalThisSpan(PointerType pointer);
public abstract Span getOffset(Span span, int amount, Pointer.PointerType pointer);
public abstract Span getOffset(Span span, int amount, PointerType pointer);
@Override
public int hashCode() {

View file

@ -1,7 +1,7 @@
package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

View file

@ -2,7 +2,7 @@ package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.Token;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;
@ -14,18 +14,30 @@ import java.util.regex.Pattern;
/**
*
*/
public class RepeaterDayName extends Repeater<RepeaterDayName.DayName> {
public class RepeaterDayName extends Repeater<DayName> {
private static final int DAY_SECONDS = 86400;
private static final Pattern MON_PATTERN = Pattern.compile("^m[ou]n(day)?$");
private static final Pattern TUE_PATTERN = Pattern.compile("^t(ue|eu|oo|u|)s(day)?$");
private static final Pattern TUE_PATTERN_1 = Pattern.compile("^tue$");
private static final Pattern WED_PATTERN_1 = Pattern.compile("^we(dnes|nds|nns)day$");
private static final Pattern WED_PATTERN_2 = Pattern.compile("^wed$");
private static final Pattern THU_PATTERN_1 = Pattern.compile("^th(urs|ers)day$");
private static final Pattern THU_PATTERN_2 = Pattern.compile("^thu$");
private static final Pattern FRI_PATTERN = Pattern.compile("^fr[iy](day)?$");
private static final Pattern SAT_PATTERN = Pattern.compile("^sat(t?[ue]rday)?$");
private static final Pattern SUN_PATTERN = Pattern.compile("^su[nm](day)?$");
private ZonedDateTime currentDayStart;
public RepeaterDayName(DayName type) {
@ -106,10 +118,4 @@ public class RepeaterDayName extends Repeater<RepeaterDayName.DayName> {
return super.toString() + "-dayname-" + getType();
}
/**
*
*/
public enum DayName {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
}

View file

@ -3,7 +3,7 @@ package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Range;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.Token;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@ -18,14 +18,21 @@ import java.util.regex.Pattern;
public abstract class RepeaterDayPortion<T> extends Repeater<T> {
private static final Pattern AM_PATTERN = Pattern.compile("^ams?$");
private static final Pattern PM_PATTERN = Pattern.compile("^pms?$");
private static final Pattern MORNING_PATTERN = Pattern.compile("^mornings?$");
private static final Pattern AFTERNOON_PATTERN = Pattern.compile("^afternoons?$");
private static final Pattern EVENING_PATTERN = Pattern.compile("^evenings?$");
private static final Pattern NIGHT_PATTERN = Pattern.compile("^(night|nite)s?$");
private static final int FULL_DAY_SECONDS = 60 * 60 * 24;
private Range range;
private final Range range;
private Span currentSpan;
public RepeaterDayPortion(T type) {
@ -149,10 +156,4 @@ public abstract class RepeaterDayPortion<T> extends Repeater<T> {
return super.toString() + "-dayportion-" + getType();
}
/**
*
*/
public enum DayPortion {
AM, PM, MORNING, AFTERNOON, EVENING, NIGHT
}
}

View file

@ -1,7 +1,7 @@
package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@ -10,6 +10,7 @@ import java.time.temporal.ChronoUnit;
*
*/
public class RepeaterFortnight extends RepeaterUnit {
public static final int FORTNIGHT_SECONDS = 1209600; // (14 * 24 * 60 * 60)
private ZonedDateTime currentFortnightStart;
@ -23,12 +24,12 @@ public class RepeaterFortnight extends RepeaterUnit {
protected Span internalNextSpan(PointerType pointer) {
if (currentFortnightStart == null) {
if (pointer == PointerType.FUTURE) {
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY);
RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow());
Span nextSundaySpan = sundayRepeater.nextSpan(PointerType.FUTURE);
currentFortnightStart = nextSundaySpan.getBeginCalendar();
} else if (pointer == PointerType.PAST) {
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY);
RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow().plus(RepeaterDay.DAY_SECONDS, ChronoUnit.SECONDS));
sundayRepeater.nextSpan(PointerType.PAST);
sundayRepeater.nextSpan(PointerType.PAST);
@ -55,7 +56,7 @@ public class RepeaterFortnight extends RepeaterUnit {
Span span;
if (pointer == PointerType.FUTURE) {
ZonedDateTime thisFortnightStart = ymdh(getNow()).plus(RepeaterHour.HOUR_SECONDS, ChronoUnit.SECONDS);
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY);
RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow());
sundayRepeater.thisSpan(PointerType.FUTURE);
Span thisSundaySpan = sundayRepeater.thisSpan(PointerType.FUTURE);
@ -63,7 +64,7 @@ public class RepeaterFortnight extends RepeaterUnit {
span = new Span(thisFortnightStart, thisFortnightEnd);
} else if (pointer == PointerType.PAST) {
ZonedDateTime thisFortnightEnd = ymdh(getNow());
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY);
RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow());
Span lastSundaySpan = sundayRepeater.nextSpan(PointerType.PAST);
ZonedDateTime thisFortnightStart = lastSundaySpan.getBeginCalendar();

View file

@ -1,7 +1,7 @@
package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@ -10,6 +10,7 @@ import java.time.temporal.ChronoUnit;
*
*/
public class RepeaterHour extends RepeaterUnit {
public static final int HOUR_SECONDS = 3600;
private ZonedDateTime currentDayStart;

View file

@ -1,7 +1,7 @@
package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@ -10,6 +10,7 @@ import java.time.temporal.ChronoUnit;
*
*/
public class RepeaterMinute extends RepeaterUnit {
public static final int MINUTE_SECONDS = 60;
private ZonedDateTime currentMinuteStart;

View file

@ -1,7 +1,7 @@
package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@ -10,6 +10,7 @@ import java.time.temporal.ChronoUnit;
*
*/
public class RepeaterMonth extends RepeaterUnit {
private static final int MONTH_SECONDS = 2592000; // 30 * 24 * 60 * 60
private ZonedDateTime currentMonthStart;

View file

@ -2,7 +2,7 @@ package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.Token;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@ -13,21 +13,34 @@ import java.util.regex.Pattern;
/**
*
*/
public class RepeaterMonthName extends Repeater<RepeaterMonthName.MonthName> {
public class RepeaterMonthName extends Repeater<MonthName> {
private static final Pattern JAN_PATTERN = Pattern.compile("^jan\\.?(uary)?$");
private static final Pattern FEB_PATTERN = Pattern.compile("^feb\\.?(ruary)?$");
private static final Pattern MAR_PATTERN = Pattern.compile("^mar\\.?(ch)?$");
private static final Pattern APR_PATTERN = Pattern.compile("^apr\\.?(il)?$");
private static final Pattern MAY_PATTERN = Pattern.compile("^may$");
private static final Pattern JUN_PATTERN = Pattern.compile("^jun\\.?e?$");
private static final Pattern JUL_PATTERN = Pattern.compile("^jul\\.?y?$");
private static final Pattern AUG_PATTERN = Pattern.compile("^aug\\.?(ust)?$");
private static final Pattern SEP_PATTERN = Pattern.compile("^sep\\.?(t\\.?|tember)?$");
private static final Pattern OCT_PATTERN = Pattern.compile("^oct\\.?(ober)?$");
private static final Pattern NOV_PATTERN = Pattern.compile("^nov\\.?(ember)?$");
private static final Pattern DEC_PATTERN = Pattern.compile("^dec\\.?(ember)?$");
private static final int MONTH_SECONDS = 2592000; // 30 * 24 * 60 * 60
private ZonedDateTime currentMonthBegin;
public RepeaterMonthName(MonthName type) {
@ -146,12 +159,4 @@ public class RepeaterMonthName extends Repeater<RepeaterMonthName.MonthName> {
return super.toString() + "-monthname-" + getType();
}
/**
*
*/
public enum MonthName {
ZEROMONTH_DO_NOT_REMOVE,
JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER
}
}

View file

@ -1,7 +1,7 @@
package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@ -10,6 +10,7 @@ import java.time.temporal.ChronoUnit;
*
*/
public class RepeaterSecond extends RepeaterUnit {
private static final int SECOND_SECONDS = 1;
private ZonedDateTime secondStart;
@ -22,7 +23,6 @@ public class RepeaterSecond extends RepeaterUnit {
} else {
secondStart = secondStart.plus(direction, ChronoUnit.SECONDS);
}
return new Span(secondStart, ChronoUnit.SECONDS, 1);
}

View file

@ -4,7 +4,7 @@ import org.xbib.time.chronic.Options;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.Tick;
import org.xbib.time.chronic.Token;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@ -16,13 +16,17 @@ import java.util.regex.Pattern;
*
*/
public class RepeaterTime extends Repeater<Tick> {
private static final Pattern TIME_PATTERN = Pattern.compile("^\\d{1,2}(:?\\d{2})?([\\.:]?\\d{2})?$");
private ZonedDateTime currentTime;
public RepeaterTime(String time) {
super(null);
String t = time.replaceAll(":", "");
Tick type;
boolean ambiguous = time.contains(":") && Integer.parseInt(t.substring(0, 1)) != 0 &&
Integer.parseInt(t.substring(0, 2)) <= 12;
int length = t.length();
if (length <= 2) {
int hours = Integer.parseInt(t);
@ -37,8 +41,6 @@ public class RepeaterTime extends Repeater<Tick> {
int minutesInSeconds = Integer.parseInt(t.substring(1)) * 60;
type = new Tick(hoursInSeconds + minutesInSeconds, true);
} else if (length == 4) {
boolean ambiguous = time.contains(":") && Integer.parseInt(t.substring(0, 1)) != 0 &&
Integer.parseInt(t.substring(0, 2)) <= 12;
int hours = Integer.parseInt(t.substring(0, 2));
int hoursInSeconds = hours * 60 * 60;
int minutesInSeconds = Integer.parseInt(t.substring(2)) * 60;
@ -53,8 +55,6 @@ public class RepeaterTime extends Repeater<Tick> {
int seconds = Integer.parseInt(t.substring(3));
type = new Tick(hoursInSeconds + minutesInSeconds + seconds, true);
} else if (length == 6) {
boolean ambiguous = time.contains(":") && Integer.parseInt(t.substring(0, 1)) != 0 &&
Integer.parseInt(t.substring(0, 2)) <= 12;
int hours = Integer.parseInt(t.substring(0, 2));
int hoursInSeconds = hours * 60 * 60;
int minutesInSeconds = Integer.parseInt(t.substring(2, 4)) * 60;
@ -84,30 +84,31 @@ public class RepeaterTime extends Repeater<Tick> {
private static Integer integerValue(String str) {
if (str != null) {
String s = str.toLowerCase();
if ("one".equals(s)) {
return 1;
} else if ("two".equals(s)) {
return 2;
} else if ("three".equals(s)) {
return 3;
} else if ("four".equals(s)) {
return 4;
} else if ("five".equals(s)) {
return 5;
} else if ("six".equals(s)) {
return 6;
} else if ("seven".equals(s)) {
return 7;
} else if ("eight".equals(s)) {
return 8;
} else if ("nine".equals(s)) {
return 9;
} else if ("ten".equals(s)) {
return 10;
} else if ("eleven".equals(s)) {
return 11;
} else if ("twelve".equals(s)) {
return 12;
switch (s) {
case "one":
return 1;
case "two":
return 2;
case "three":
return 3;
case "four":
return 4;
case "five":
return 5;
case "six":
return 6;
case "seven":
return 7;
case "eight":
return 8;
case "nine":
return 9;
case "ten":
return 10;
case "eleven":
return 11;
case "twelve":
return 12;
}
}
return null;
@ -158,8 +159,8 @@ public class RepeaterTime extends Repeater<Tick> {
}
}
} else {
List<ZonedDateTime> pastDates = new LinkedList<>();
if (tick.isAmbiguous()) {
List<ZonedDateTime> pastDates = new LinkedList<>();
pastDates.add(midnight.plus(halfDay + (long) tick.intValue(), ChronoUnit.SECONDS));
pastDates.add(midnight.plus(tick.intValue(), ChronoUnit.SECONDS));
pastDates.add(yesterdayMidnight.plus(tick.intValue() * 2L, ChronoUnit.SECONDS));
@ -171,7 +172,6 @@ public class RepeaterTime extends Repeater<Tick> {
}
}
} else {
List<ZonedDateTime> pastDates = new LinkedList<>();
pastDates.add(midnight.plus(tick.intValue(), ChronoUnit.SECONDS));
pastDates.add(yesterdayMidnight.plus(tick.intValue(), ChronoUnit.SECONDS));
for (ZonedDateTime pastDate : pastDates) {
@ -183,18 +183,15 @@ public class RepeaterTime extends Repeater<Tick> {
}
}
}
if (!done && currentTime == null) {
throw new IllegalStateException("Current time cannot be null at this point.");
}
}
if (!first) {
int increment = tick.isAmbiguous() ? halfDay : fullDay;
long direction = pointer == PointerType.FUTURE ? 1L : -1L;
currentTime = currentTime.plus(direction * increment, ChronoUnit.SECONDS);
}
return new Span(currentTime, currentTime.plus(getWidth(), ChronoUnit.SECONDS));
}

View file

@ -10,14 +10,23 @@ import java.util.regex.Pattern;
*
*/
public abstract class RepeaterUnit extends Repeater<Object> {
private static final Pattern YEAR_PATTERN = Pattern.compile("^years?$");
private static final Pattern MONTH_PATTERN = Pattern.compile("^months?$");
private static final Pattern FORTNIGHT_PATTERN = Pattern.compile("^fortnights?$");
private static final Pattern WEEK_PATTERN = Pattern.compile("^weeks?$");
private static final Pattern WEEKEND_PATTERN = Pattern.compile("^weekends?$");
private static final Pattern DAY_PATTERN = Pattern.compile("^days?$");
private static final Pattern HOUR_PATTERN = Pattern.compile("^hours?$");
private static final Pattern MINUTE_PATTERN = Pattern.compile("^minutes?$");
private static final Pattern SECOND_PATTERN = Pattern.compile("^seconds?$");
public RepeaterUnit() {
@ -66,10 +75,4 @@ public abstract class RepeaterUnit extends Repeater<Object> {
((Repeater) other).getNow().equals(getNow());
}
/**
*
*/
private enum UnitName {
YEAR, MONTH, FORTNIGHT, WEEK, WEEKEND, DAY, HOUR, MINUTE, SECOND
}
}

View file

@ -1,7 +1,7 @@
package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@ -10,7 +10,9 @@ import java.time.temporal.ChronoUnit;
*
*/
public class RepeaterWeek extends RepeaterUnit {
public static final int WEEK_SECONDS = 604800;
public static final int WEEK_DAYS = 7;
private ZonedDateTime currentWeekStart;
@ -24,12 +26,12 @@ public class RepeaterWeek extends RepeaterUnit {
protected Span internalNextSpan(PointerType pointer) {
if (currentWeekStart == null) {
if (pointer == PointerType.FUTURE) {
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY);
RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow());
Span nextSundaySpan = sundayRepeater.nextSpan(PointerType.FUTURE);
currentWeekStart = nextSundaySpan.getBeginCalendar();
} else if (pointer == PointerType.PAST) {
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY);
RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow().plus(1, ChronoUnit.DAYS));
sundayRepeater.nextSpan(PointerType.PAST);
Span lastSundaySpan = sundayRepeater.nextSpan(PointerType.PAST);
@ -52,20 +54,20 @@ public class RepeaterWeek extends RepeaterUnit {
ZonedDateTime thisWeekEnd;
if (pointer == PointerType.FUTURE) {
thisWeekStart = ymdh(getNow()).plus(1, ChronoUnit.HOURS);
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY);
RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow());
Span thisSundaySpan = sundayRepeater.thisSpan(PointerType.FUTURE);
thisWeekEnd = thisSundaySpan.getBeginCalendar();
thisWeekSpan = new Span(thisWeekStart, thisWeekEnd);
} else if (pointer == PointerType.PAST) {
thisWeekEnd = ymdh(getNow());
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY);
RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow());
Span lastSundaySpan = sundayRepeater.nextSpan(PointerType.PAST);
thisWeekStart = lastSundaySpan.getBeginCalendar();
thisWeekSpan = new Span(thisWeekStart, thisWeekEnd);
} else if (pointer == PointerType.NONE) {
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY);
RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow());
Span lastSundaySpan = sundayRepeater.nextSpan(PointerType.PAST);
thisWeekStart = lastSundaySpan.getBeginCalendar();

View file

@ -1,7 +1,7 @@
package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@ -10,7 +10,8 @@ import java.time.temporal.ChronoUnit;
*
*/
public class RepeaterWeekend extends RepeaterUnit {
public static final long WEEKEND_SECONDS = 172800L; // (2 * 24 * 60 * 60);
private static final long WEEKEND_SECONDS = 172800L; // (2 * 24 * 60 * 60);
private ZonedDateTime currentWeekStart;
@ -25,7 +26,7 @@ public class RepeaterWeekend extends RepeaterUnit {
ZonedDateTime c;
switch (pointer) {
case PAST: {
RepeaterDayName saturdayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SATURDAY);
RepeaterDayName saturdayRepeater = new RepeaterDayName(DayName.SATURDAY);
saturdayRepeater.setNow(getNow().plus(RepeaterDay.DAY_SECONDS, ChronoUnit.SECONDS));
Span lastSaturdaySpan = saturdayRepeater.nextSpan(PointerType.PAST);
currentWeekStart = lastSaturdaySpan.getBeginCalendar();
@ -33,7 +34,7 @@ public class RepeaterWeekend extends RepeaterUnit {
return new Span(currentWeekStart, c);
}
case FUTURE: {
RepeaterDayName saturdayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SATURDAY);
RepeaterDayName saturdayRepeater = new RepeaterDayName(DayName.SATURDAY);
saturdayRepeater.setNow(getNow());
Span nextSaturdaySpan = saturdayRepeater.nextSpan(PointerType.FUTURE);
currentWeekStart = nextSaturdaySpan.getBeginCalendar();
@ -50,13 +51,13 @@ public class RepeaterWeekend extends RepeaterUnit {
protected Span internalThisSpan(PointerType pointer) {
Span thisSpan;
if (pointer == PointerType.FUTURE || pointer == PointerType.NONE) {
RepeaterDayName saturdayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SATURDAY);
RepeaterDayName saturdayRepeater = new RepeaterDayName(DayName.SATURDAY);
saturdayRepeater.setNow(getNow());
Span thisSaturdaySpan = saturdayRepeater.nextSpan(PointerType.FUTURE);
thisSpan = new Span(thisSaturdaySpan.getBeginCalendar(), thisSaturdaySpan.getBeginCalendar()
.plus(RepeaterWeekend.WEEKEND_SECONDS, ChronoUnit.SECONDS));
} else if (pointer == PointerType.PAST) {
RepeaterDayName saturdayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SATURDAY);
RepeaterDayName saturdayRepeater = new RepeaterDayName(DayName.SATURDAY);
saturdayRepeater.setNow(getNow());
Span lastSaturdaySpan = saturdayRepeater.nextSpan(PointerType.PAST);
thisSpan = new Span(lastSaturdaySpan.getBeginCalendar(), lastSaturdaySpan.getBeginCalendar()

View file

@ -1,7 +1,7 @@
package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.tags.Pointer.PointerType;
import org.xbib.time.chronic.tags.PointerType;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@ -10,6 +10,7 @@ import java.time.temporal.ChronoUnit;
*
*/
public class RepeaterYear extends RepeaterUnit {
private ZonedDateTime currentYearStart;
private static ZonedDateTime ymd(ZonedDateTime zonedDateTime) {

View file

@ -0,0 +1,8 @@
package org.xbib.time.chronic.repeaters;
/**
*
*/
enum UnitName {
YEAR, MONTH, FORTNIGHT, WEEK, WEEKEND, DAY, HOUR, MINUTE, SECOND
}

View file

@ -11,9 +11,12 @@ import java.util.regex.Pattern;
/**
*
*/
public class Grabber extends Tag<Grabber.Relative> {
public class Grabber extends Tag<Relative> {
private static final Pattern THIS_PATTERN = Pattern.compile("this");
private static final Pattern NEXT_PATTERN = Pattern.compile("next");
private static final Pattern LAST_PATTERN = Pattern.compile("last");
public Grabber(Relative type) {
@ -49,10 +52,4 @@ public class Grabber extends Tag<Grabber.Relative> {
return "grabber-" + getType();
}
/**
*
*/
public enum Relative {
LAST, NEXT, THIS
}
}

View file

@ -14,7 +14,7 @@ public class Ordinal extends Tag<Integer> {
static final Pattern ORDINAL_PATTERN = Pattern.compile("^(\\d*)(st|nd|rd|th)$");
Ordinal(Integer type) {
protected Ordinal(Integer type) {
super(type);
}

View file

@ -8,7 +8,8 @@ import java.util.regex.Matcher;
*
*/
public class OrdinalDay extends Ordinal {
public OrdinalDay(Integer type) {
private OrdinalDay(Integer type) {
super(type);
}

View file

@ -11,7 +11,7 @@ import java.util.regex.Pattern;
/**
*
*/
public class Pointer extends Tag<Pointer.PointerType> {
public class Pointer extends Tag<PointerType> {
private static final Pattern IN_PATTERN = Pattern.compile("\\bin\\b");
@ -52,10 +52,4 @@ public class Pointer extends Tag<Pointer.PointerType> {
return "pointer-" + getType();
}
/**
*
*/
public enum PointerType {
PAST, FUTURE, NONE
}
}

View file

@ -0,0 +1,8 @@
package org.xbib.time.chronic.tags;
/**
*
*/
public enum PointerType {
PAST, FUTURE, NONE
}

View file

@ -0,0 +1,8 @@
package org.xbib.time.chronic.tags;
/**
*
*/
public enum Relative {
LAST, NEXT, THIS
}

View file

@ -13,8 +13,9 @@ import java.util.regex.Pattern;
*
*/
public class Scalar extends Tag<Integer> {
static final Set<String> TIMES =
new HashSet<>(Arrays.asList("am", "pm", "morning", "afternoon", "evening", "night"));
protected static final Set<String> TIMES = new HashSet<>(Arrays.asList("am", "pm", "morning", "afternoon", "evening", "night"));
private static final Pattern SCALAR_PATTERN = Pattern.compile("^\\d*$");
public Scalar(Integer type) {

View file

@ -9,6 +9,7 @@ import java.util.regex.Pattern;
*
*/
public class ScalarDay extends Scalar {
private static final Pattern DAY_PATTERN = Pattern.compile("^\\d\\d?$");
public ScalarDay(Integer type) {

View file

@ -9,6 +9,7 @@ import java.util.regex.Pattern;
*
*/
public class ScalarMonth extends Scalar {
private static final Pattern MONTH_PATTERN = Pattern.compile("^\\d\\d?$");
public ScalarMonth(Integer type) {

View file

@ -9,6 +9,7 @@ import java.util.regex.Pattern;
*
*/
public class ScalarYear extends Scalar {
private static final Pattern YEAR_PATTERN = Pattern.compile("^([1-9]\\d)?\\d\\d?$");
private ScalarYear(Integer type) {

View file

@ -8,9 +8,9 @@ import java.util.List;
/**
*
*/
public class Separator extends Tag<Separator.SeparatorType> {
public class Separator extends Tag<SeparatorType> {
Separator(SeparatorType type) {
public Separator(SeparatorType type) {
super(type);
}
@ -42,10 +42,4 @@ public class Separator extends Tag<Separator.SeparatorType> {
return "separator";
}
/**
*
*/
enum SeparatorType {
COMMA, DASH, SLASH, AT, IN
}
}

View file

@ -11,6 +11,7 @@ import java.util.regex.Pattern;
*
*/
public class SeparatorAt extends Separator {
private static final Pattern AT_PATTERN = Pattern.compile("^(at|@)$");
private SeparatorAt(SeparatorType type) {

View file

@ -11,6 +11,7 @@ import java.util.regex.Pattern;
*
*/
public class SeparatorComma extends Separator {
private static final Pattern COMMA_PATTERN = Pattern.compile("^,$");
private SeparatorComma(SeparatorType type) {

View file

@ -11,7 +11,9 @@ import java.util.regex.Pattern;
*
*/
public class SeparatorSlashOrDash extends Separator {
private static final Pattern SLASH_PATTERN = Pattern.compile("^/$");
private static final Pattern DASH_PATTERN = Pattern.compile("^-$");
public SeparatorSlashOrDash(SeparatorType type) {

View file

@ -0,0 +1,8 @@
package org.xbib.time.chronic.tags;
/**
*
*/
public enum SeparatorType {
COMMA, DASH, SLASH, AT, IN
}

View file

@ -4,6 +4,7 @@ package org.xbib.time.chronic.tags;
*
*/
public class StringTag extends Tag<String> {
public StringTag(String type) {
super(type);
}

View file

@ -12,6 +12,7 @@ import java.util.regex.Pattern;
*
*/
public class TimeZone extends Tag<Object> {
private static final Pattern TIMEZONE_PATTERN = Pattern.compile("[pmce][ds]t");
private TimeZone() {

View file

@ -11,27 +11,25 @@ import java.util.Locale;
/**
* Composite implementation that merges other fields to create a full pattern.
*/
class Composite implements PeriodPrinter, PeriodParser {
public class Composite implements PeriodPrinter, PeriodParser {
private final PeriodPrinter[] iPrinters;
private final PeriodParser[] iParsers;
Composite(List<Object> elementPairs) {
List<Object> printerList = new ArrayList<>();
List<Object> parserList = new ArrayList<>();
public Composite(List<Object> elementPairs) {
List<PeriodPrinter> printerList = new ArrayList<>();
List<PeriodParser> parserList = new ArrayList<>();
decompose(elementPairs, printerList, parserList);
if (printerList.isEmpty()) {
iPrinters = null;
} else {
iPrinters = printerList.toArray(new PeriodPrinter[printerList.size()]);
iPrinters = printerList.toArray(new PeriodPrinter[0]);
}
if (parserList.isEmpty()) {
iParsers = null;
} else {
iParsers = parserList.toArray(new PeriodParser[parserList.size()]);
iParsers = parserList.toArray(new PeriodParser[0]);
}
}
@ -83,32 +81,31 @@ class Composite implements PeriodPrinter, PeriodParser {
return position;
}
private void decompose(List<Object> elementPairs, List<Object> printerList, List<Object> parserList) {
private void decompose(List<Object> elementPairs, List<PeriodPrinter> printerList, List<PeriodParser> parserList) {
int size = elementPairs.size();
for (int i = 0; i < size; i += 2) {
Object element = elementPairs.get(i);
if (element instanceof PeriodPrinter) {
if (element instanceof Composite) {
addArrayToList(printerList, ((Composite) element).iPrinters);
PeriodPrinter[] periodPrinters = ((Composite) element).iPrinters;
if (periodPrinters != null) {
Collections.addAll(printerList, periodPrinters);
}
} else {
printerList.add(element);
printerList.add((PeriodPrinter) element);
}
}
element = elementPairs.get(i + 1);
if (element instanceof PeriodParser) {
if (element instanceof Composite) {
addArrayToList(parserList, ((Composite) element).iParsers);
PeriodParser[] periodParsers = ((Composite) element).iParsers;
if (periodParsers != null) {
Collections.addAll(parserList, periodParsers);
}
} else {
parserList.add(element);
parserList.add((PeriodParser) element);
}
}
}
}
private void addArrayToList(List<Object> list, Object[] array) {
if (array != null) {
Collections.addAll(list, array);
}
}
}
}

View file

@ -8,30 +8,31 @@ import java.util.Set;
/**
* Builds a composite affix by merging two other affix implementations.
*/
class CompositeAffix extends IgnorableAffix {
public class CompositeAffix extends IgnorableAffix {
private final PeriodFieldAffix iLeft;
private final PeriodFieldAffix iRight;
private final String[] iLeftRightCombinations;
CompositeAffix(PeriodFieldAffix left, PeriodFieldAffix right) {
public CompositeAffix(PeriodFieldAffix left, PeriodFieldAffix right) {
iLeft = left;
iRight = right;
// We need to construct all possible combinations of left and right.
// We are doing it once in constructor so that getAffixes() is quicker.
Set<String> result = new HashSet<String>();
Set<String> result = new HashSet<>();
for (String leftText : iLeft.getAffixes()) {
for (String rightText : iRight.getAffixes()) {
result.add(leftText + rightText);
}
}
iLeftRightCombinations = result.toArray(new String[result.size()]);
iLeftRightCombinations = result.toArray(new String[0]);
}
@Override
public int calculatePrintedLength(int value) {
return iLeft.calculatePrintedLength(value)
+ iRight.calculatePrintedLength(value);
return iLeft.calculatePrintedLength(value) + iRight.calculatePrintedLength(value);
}
@Override

View file

@ -11,10 +11,12 @@ import java.util.Set;
/**
* Formats the numeric value of a field, potentially with prefix/suffix.
*/
class FieldFormatter implements PeriodPrinter, PeriodParser {
public class FieldFormatter implements PeriodPrinter, PeriodParser {
private final int iMinPrintedDigits;
//private final int iPrintZeroSetting;
private final int iMaxParsedDigits;
private final boolean iRejectSignedValues;
/**
@ -30,10 +32,10 @@ class FieldFormatter implements PeriodPrinter, PeriodParser {
private final PeriodFieldAffix iPrefix;
private final PeriodFieldAffix iSuffix;
FieldFormatter(int minPrintedDigits,
int maxParsedDigits, boolean rejectSignedValues,
ChronoUnit chronoUnit,
PeriodFieldAffix prefix, PeriodFieldAffix suffix) {
public FieldFormatter(int minPrintedDigits,
int maxParsedDigits, boolean rejectSignedValues,
ChronoUnit chronoUnit,
PeriodFieldAffix prefix, PeriodFieldAffix suffix) {
iMinPrintedDigits = minPrintedDigits;
iMaxParsedDigits = maxParsedDigits;
iRejectSignedValues = rejectSignedValues;
@ -42,7 +44,7 @@ class FieldFormatter implements PeriodPrinter, PeriodParser {
iSuffix = suffix;
}
FieldFormatter(FieldFormatter field, PeriodFieldAffix periodFieldAffix) {
public FieldFormatter(FieldFormatter field, PeriodFieldAffix periodFieldAffix) {
PeriodFieldAffix suffix = periodFieldAffix;
iMinPrintedDigits = field.iMinPrintedDigits;
iMaxParsedDigits = field.iMaxParsedDigits;
@ -91,17 +93,14 @@ class FieldFormatter implements PeriodPrinter, PeriodParser {
if (valueLong == Long.MAX_VALUE) {
return 0;
}
int sum = Math.max(FormatUtils.calculateDigitCount(valueLong), iMinPrintedDigits);
int value = (int) valueLong;
if (iPrefix != null) {
sum += iPrefix.calculatePrintedLength(value);
}
if (iSuffix != null) {
sum += iSuffix.calculatePrintedLength(value);
}
return sum;
}
@ -152,7 +151,6 @@ class FieldFormatter implements PeriodPrinter, PeriodParser {
if (position >= text.length()) {
return ~position;
}
if (iPrefix != null) {
position = iPrefix.parse(text, position);
if (position < 0) {
@ -187,7 +185,6 @@ class FieldFormatter implements PeriodPrinter, PeriodParser {
}
length++;
}
if (!hasDigits) {
return ~position;
}
@ -236,7 +233,7 @@ class FieldFormatter implements PeriodPrinter, PeriodParser {
/**
* @return Long.MAX_VALUE if nothing to print, otherwise value
*/
long getFieldValue(Period period) {
private long getFieldValue(Period period) {
long value;
switch (unit) {
default:
@ -270,7 +267,7 @@ class FieldFormatter implements PeriodPrinter, PeriodParser {
return value;
}
void setFieldValue(PeriodAmount period, ChronoUnit field, long value) {
private void setFieldValue(PeriodAmount period, ChronoUnit field, long value) {
switch (field) {
default:
break;
@ -300,8 +297,4 @@ class FieldFormatter implements PeriodPrinter, PeriodParser {
break;
}
}
ChronoUnit getFieldType() {
return unit;
}
}

View file

@ -53,7 +53,6 @@ public class FormatUtils {
appenadble.append('0');
}
appenadble.append(Long.toString(Integer.MIN_VALUE));
//.append("" + -(long) Integer.MIN_VALUE)
return;
}
}

View file

@ -6,7 +6,8 @@ import java.util.Set;
/**
* An affix that can be ignored.
*/
abstract class IgnorableAffix implements PeriodFieldAffix {
public abstract class IgnorableAffix implements PeriodFieldAffix {
private volatile String[] iOtherAffixes;
public void finish(Set<PeriodFieldAffix> periodFieldAffixesToIgnore) {
@ -20,7 +21,6 @@ abstract class IgnorableAffix implements PeriodFieldAffix {
shortestAffix = affix;
}
}
// Pick only affixes that are longer than the shortest affix in this instance.
// This will reduce the number of parse operations and thus speed up the PeriodFormatter.
// also need to pick affixes that differ only in case (but not those that are identical)

Some files were not shown because too many files have changed in this diff Show more