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 { plugins {
id "de.marcphilipp.nexus-publish" version "0.4.0" id 'maven-publish'
id "io.codearte.nexus-staging" version "0.21.1" 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 { wrapper {
gradleVersion = "${project.property('gradle.wrapper.version')}" gradleVersion = libs.versions.gradle.get()
distributionType = Wrapper.DistributionType.ALL distributionType = Wrapper.DistributionType.BIN
} }
ext { ext {
user = 'xbib' user = 'joerg'
name = 'time' name = 'time'
description = 'A bundle of Chronic, Prettytime, and org.joda.time.format optimized for Java 8 Time API' description = 'A bundle of Chronic, Prettytime, and org.joda.time.format optimized for Java 8 Time API'
inceptionYear = '2016' inceptionYear = '2016'
url = 'https://github.com/' + user + '/' + name url = 'https://xbib.org/' + user + '/' + name
scmUrl = 'https://github.com/' + user + '/' + name scmUrl = 'https://xbib.org/' + user + '/' + name
scmConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git' scmConnection = 'scm:git:git://xbib.org/' + user + '/' + name + '.git'
scmDeveloperConnection = 'scm:git:ssh://git@github.com:' + user + '/' + name + '.git' scmDeveloperConnection = 'scm:git:ssh://forgejo@xbib.org:' + user + '/' + name + '.git'
issueManagementSystem = 'Github' issueManagementSystem = 'Github'
issueManagementUrl = ext.scmUrl + '/issues' issueManagementUrl = ext.scmUrl + '/issues'
licenseName = 'The Apache License, Version 2.0' licenseName = 'The Apache License, Version 2.0'
licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' 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/repositories/maven.gradle')
apply from: rootProject.file('gradle/compile/java.gradle') apply from: rootProject.file('gradle/compile/java.gradle')
apply from: rootProject.file('gradle/test/junit5.gradle') apply from: rootProject.file('gradle/test/junit5.gradle')
apply from: rootProject.file('gradle/publishing/publication.gradle') apply from: rootProject.file('gradle/publish/maven.gradle')
apply from: rootProject.file('gradle/publishing/sonatype.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 group = org.xbib
name = time name = time
version = 2.1.1 version = 4.0.0
gradle.wrapper.version = 6.6.1
quartz.version = 2.3.2
caliper.version = 1.0-beta-2

View file

@ -2,17 +2,12 @@
apply plugin: 'java-library' apply plugin: 'java-library'
java { java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
modularity.inferModulePath.set(true) modularity.inferModulePath.set(true)
} withSourcesJar()
withJavadocJar()
compileJava {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
compileTestJava {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
} }
jar { jar {
@ -21,15 +16,14 @@ jar {
} }
} }
task sourcesJar(type: Jar, dependsOn: classes) { tasks.withType(JavaCompile) {
classifier 'sources' options.fork = true
from sourceSets.main.allSource options.forkOptions.jvmArgs += ['-Duser.language=en','-Duser.country=US']
options.compilerArgs << '-Xlint:all'
options.encoding = 'UTF-8'
} }
task javadocJar(type: Jar, dependsOn: javadoc) { javadoc {
classifier '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' apply plugin: 'org.xbib.gradle.plugin.asciidoctor'
configurations {
asciidoclet
}
dependencies {
asciidoclet "org.asciidoctor:asciidoclet:${project.property('asciidoclet.version')}"
}
asciidoctor { asciidoctor {
backends 'html5' backends 'html5'
outputDir = file("${rootProject.projectDir}/docs") outputDir = file("${rootProject.projectDir}/docs")
@ -26,30 +17,3 @@ asciidoctor {
imagesdir: 'img', imagesdir: 'img',
stylesheet: "${projectDir}/src/docs/asciidoc/css/foundation.css" 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') 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 { publishing {
publications { publications {
mavenJava(MavenPublication) { "${project.name}"(MavenPublication) {
from components.java from components.java
artifact sourcesJar
artifact javadocJar
pom { pom {
artifactId = project.name
name = project.name name = project.name
description = rootProject.ext.description description = rootProject.ext.description
url = rootProject.ext.url url = rootProject.ext.url
@ -19,10 +16,10 @@ publishing {
} }
developers { developers {
developer { developer {
id = 'jprante' id = 'joerg'
name = 'Jörg Prante' name = 'Jörg Prante'
email = 'joergprante@gmail.com' email = 'joergprante@gmail.com'
url = 'https://github.com/jprante' url = 'https://xbib.org/joerg'
} }
} }
scm { scm {
@ -49,18 +46,6 @@ publishing {
if (project.hasProperty("signing.keyId")) { if (project.hasProperty("signing.keyId")) {
apply plugin: 'signing' apply plugin: 'signing'
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="Checker">
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value=".*(Example|Test|module-info)(\$.*)?"/>
</module>
<module name="FileTabCharacter"> <module name="FileTabCharacter">
<!-- Checks that there are no tab characters in the file. <!-- 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. --> <!-- Checks for out of order import statements. -->
<property name="severity" value="warning"/> <property name="severity" value="warning"/>
<property name="groups" value="com,junit,net,org,java,javax"/> <!-- <property name="tokens" value="IMPORT, STATIC_IMPORT"/> -->
<!-- This ensures that static imports go first. --> <property name="separated" value="false"/>
<property name="option" value="top"/> <property name="groups" value="*"/>
<property name="tokens" value="STATIC_IMPORT, IMPORT"/> <!-- <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> </module>
<!-- <!--
@ -71,14 +84,10 @@ page at http://checkstyle.sourceforge.net/config.html -->
<!-- Checks for Javadoc comments. --> <!-- Checks for Javadoc comments. -->
<!-- See http://checkstyle.sf.net/config_javadoc.html --> <!-- See http://checkstyle.sf.net/config_javadoc.html -->
<module name="JavadocMethod"> <module name="JavadocMethod">
<property name="scope" value="protected"/> <property name="accessModifiers" value="protected"/>
<property name="severity" value="warning"/> <property name="severity" value="warning"/>
<property name="allowMissingJavadoc" value="true"/>
<property name="allowMissingParamTags" value="true"/> <property name="allowMissingParamTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/> <property name="allowMissingReturnTag" value="true"/>
<property name="allowMissingThrowsTags" value="true"/>
<property name="allowThrowsTagsForSubclasses" value="true"/>
<property name="allowUndeclaredRTE" value="true"/>
</module> </module>
<module name="JavadocType"> <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"> <module name="LeftCurly">
<!-- Checks for placement of the left curly brace ('{'). --> <!-- Checks for placement of the left curly brace ('{'). -->
@ -319,5 +313,21 @@ page at http://checkstyle.sourceforge.net/config.html -->
</module> </module>
</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> </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 { dependencies {
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitVersion}" testImplementation testLibs.junit.jupiter.api
testImplementation "org.junit.jupiter:junit-jupiter-params:${junitVersion}" testImplementation testLibs.junit.jupiter.params
testImplementation "org.hamcrest:hamcrest-library:${hamcrestVersion}" testImplementation testLibs.hamcrest
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}" testRuntimeOnly testLibs.junit.jupiter.engine
testRuntimeOnly testLibs.junit.jupiter.platform.launcher
} }
test { test {
@ -24,4 +21,16 @@ test {
"${result.skippedTestCount} skipped" "${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 distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists 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 zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists 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"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with 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 # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" # This is normally unused
APP_BASE_NAME=`basename "$0"` # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 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 [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 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." location of your Java installation."
fi fi
else else
JAVACMD="java" 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. 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 Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
MAX_FD="$MAX_FD_LIMIT" # shellcheck disable=SC2039,SC3045
fi MAX_FD=$( ulimit -H -n ) ||
ulimit -n $MAX_FD warn "Could not query maximum file descriptor limit"
if [ $? -ne 0 ] ; then esac
warn "Could not set maximum file descriptor limit: $MAX_FD" case $MAX_FD in #(
fi '' | soft) :;; #(
else *)
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
fi # shellcheck disable=SC2039,SC3045
fi ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
# 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" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=`save "$@"` # * --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 # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 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" "$@" exec "$JAVACMD" "$@"

35
gradlew.bat vendored
View file

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

View file

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

View file

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

View file

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

View file

@ -10,8 +10,10 @@ import java.util.List;
* *
*/ */
public class Token { public class Token {
private String word;
private List<Tag<?>> tags; private final String word;
private final List<Tag<?>> tags;
public Token(String word) { public Token(String word) {
this.word = word; this.word = word;
@ -35,13 +37,7 @@ public class Token {
* @param tagClass tag class * @param tagClass tag class
*/ */
public void untag(Class<?> tagClass) { public void untag(Class<?> tagClass) {
Iterator<Tag<?>> tagIter = tags.iterator(); tags.removeIf(tagClass::isInstance);
while (tagIter.hasNext()) {
Tag<?> tag = tagIter.next();
if (tagClass.isInstance(tag)) {
tagIter.remove();
}
}
} }
/** /**
@ -58,7 +54,6 @@ public class Token {
* @param <T> type parameter * @param <T> type parameter
* @return tag * @return tag
*/ */
@SuppressWarnings("unchecked")
public <T extends Tag<?>> T getTag(Class<T> tagClass) { public <T extends Tag<?>> T getTag(Class<T> tagClass) {
List<T> matches = getTags(tagClass); List<T> matches = getTags(tagClass);
T matchingTag = null; 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.Options;
import org.xbib.time.chronic.Span; import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.Token; 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.EnumRepeaterDayPortion;
import org.xbib.time.chronic.repeaters.IntegerRepeaterDayPortion; import org.xbib.time.chronic.repeaters.IntegerRepeaterDayPortion;
import org.xbib.time.chronic.repeaters.Repeater; 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.Ordinal;
import org.xbib.time.chronic.tags.OrdinalDay; import org.xbib.time.chronic.tags.OrdinalDay;
import org.xbib.time.chronic.tags.Pointer; 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.Scalar;
import org.xbib.time.chronic.tags.ScalarDay; import org.xbib.time.chronic.tags.ScalarDay;
import org.xbib.time.chronic.tags.ScalarMonth; import org.xbib.time.chronic.tags.ScalarMonth;
@ -202,7 +204,7 @@ public class Handler {
} }
public static Span getAnchor(List<Token> tokens, Options options) { 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; PointerType pointer = PointerType.FUTURE;
List<Repeater<?>> repeaters = getRepeaters(tokens); List<Repeater<?>> repeaters = getRepeaters(tokens);
@ -219,16 +221,16 @@ public class Handler {
head.setNow(options.getNow()); head.setNow(options.getNow());
Span outerSpan; Span outerSpan;
Grabber.Relative grabberType = grabber.getType(); Relative grabberType = grabber.getType();
if (grabberType == Grabber.Relative.LAST) { if (grabberType == Relative.LAST) {
outerSpan = head.nextSpan(PointerType.PAST); outerSpan = head.nextSpan(PointerType.PAST);
} else if (grabberType == Grabber.Relative.THIS) { } else if (grabberType == Relative.THIS) {
if (!repeaters.isEmpty()) { if (!repeaters.isEmpty()) {
outerSpan = head.thisSpan(PointerType.NONE); outerSpan = head.thisSpan(PointerType.NONE);
} else { } else {
outerSpan = head.thisSpan(options.getContext()); outerSpan = head.thisSpan(options.getContext());
} }
} else if (grabberType == Grabber.Relative.NEXT) { } else if (grabberType == Relative.NEXT) {
outerSpan = head.nextSpan(PointerType.FUTURE); outerSpan = head.nextSpan(PointerType.FUTURE);
} else { } else {
throw new IllegalArgumentException("Invalid grabber type " + grabberType + "."); throw new IllegalArgumentException("Invalid grabber type " + grabberType + ".");
@ -296,14 +298,14 @@ public class Handler {
Tag<RepeaterDayPortion<?>> t1Tag = t1.getTag(RepeaterDayPortion.class); Tag<RepeaterDayPortion<?>> t1Tag = t1.getTag(RepeaterDayPortion.class);
Object t1TagType = t1Tag.getType(); Object t1TagType = t1Tag.getType();
if (RepeaterDayPortion.DayPortion.MORNING.equals(t1TagType)) { if (DayPortion.MORNING.equals(t1TagType)) {
t1.untag(RepeaterDayPortion.class); t1.untag(RepeaterDayPortion.class);
t1.tag(new EnumRepeaterDayPortion(RepeaterDayPortion.DayPortion.AM)); t1.tag(new EnumRepeaterDayPortion(DayPortion.AM));
} else if (RepeaterDayPortion.DayPortion.AFTERNOON.equals(t1TagType) || } else if (DayPortion.AFTERNOON.equals(t1TagType) ||
RepeaterDayPortion.DayPortion.EVENING.equals(t1TagType) || DayPortion.EVENING.equals(t1TagType) ||
RepeaterDayPortion.DayPortion.NIGHT.equals(t1TagType)) { DayPortion.NIGHT.equals(t1TagType)) {
t1.untag(RepeaterDayPortion.class); 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 { public class HandlerPattern {
private boolean optional;
private final boolean optional;
public HandlerPattern(boolean optional) { public HandlerPattern(boolean optional) {
this.optional = optional; this.optional = optional;

View file

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

View file

@ -11,5 +11,6 @@ import java.util.List;
*/ */
@FunctionalInterface @FunctionalInterface
public interface IHandler { public interface IHandler {
Span handle(List<Token> tokens, Options options); 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); Span outerSpan = Handler.getAnchor(tokens.subList(2, 4), options);
return handle(tokens.subList(0, 2), outerSpan, 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.Token;
import org.xbib.time.chronic.repeaters.Repeater; import org.xbib.time.chronic.repeaters.Repeater;
import org.xbib.time.chronic.tags.Ordinal; 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.time.temporal.ChronoUnit;
import java.util.List; import java.util.List;
@ -21,7 +21,7 @@ public abstract class ORRHandler implements IHandler {
Integer ordinalValue = tokens.get(0).getTag(Ordinal.class).getType(); Integer ordinalValue = tokens.get(0).getTag(Ordinal.class).getType();
Span span = null; Span span = null;
for (int i = 0; i < ordinalValue; i++) { for (int i = 0; i < ordinalValue; i++) {
span = repeater.nextSpan(Pointer.PointerType.FUTURE); span = repeater.nextSpan(PointerType.FUTURE);
if (span.getBegin() > outerSpan.getEnd()) { if (span.getBegin() > outerSpan.getEnd()) {
span = null; span = null;
break; break;

View file

@ -16,5 +16,4 @@ public class ORSRHandler extends ORRHandler {
Span outerSpan = Handler.getAnchor(tokens.subList(3, 4), options); Span outerSpan = Handler.getAnchor(tokens.subList(3, 4), options);
return handle(tokens.subList(0, 2), outerSpan, 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); List<Token> ddTokens = Handler.dealiasAndDisambiguateTimes(tokens, options);
return Handler.getAnchor(ddTokens, options); return Handler.getAnchor(ddTokens, options);
} }
} }

View file

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

View file

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

View file

@ -16,5 +16,4 @@ public class SRPAHandler extends SRPHandler {
Span anchorSpan = Handler.getAnchor(tokens.subList(3, tokens.size()), options); Span anchorSpan = Handler.getAnchor(tokens.subList(3, tokens.size()), options);
return super.handle(tokens, anchorSpan, 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.Token;
import org.xbib.time.chronic.repeaters.Repeater; import org.xbib.time.chronic.repeaters.Repeater;
import org.xbib.time.chronic.tags.Pointer; import org.xbib.time.chronic.tags.Pointer;
import org.xbib.time.chronic.tags.PointerType;
import org.xbib.time.chronic.tags.Scalar; import org.xbib.time.chronic.tags.Scalar;
import java.text.ParseException; import java.text.ParseException;
@ -19,7 +20,7 @@ public class SRPHandler implements IHandler {
public Span handle(List<Token> tokens, Span span, Options options) { public Span handle(List<Token> tokens, Span span, Options options) {
int distance = tokens.get(0).getTag(Scalar.class).getType(); int distance = tokens.get(0).getTag(Scalar.class).getType();
Repeater<?> repeater = tokens.get(1).getTag(Repeater.class); 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); return repeater.getOffset(span, distance, pointer);
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,6 +6,7 @@ import org.xbib.time.chronic.Range;
* *
*/ */
public class IntegerRepeaterDayPortion extends RepeaterDayPortion<Integer> { public class IntegerRepeaterDayPortion extends RepeaterDayPortion<Integer> {
public IntegerRepeaterDayPortion(Integer type) { public IntegerRepeaterDayPortion(Integer type) {
super(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.Options;
import org.xbib.time.chronic.Span; import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.Token; 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 org.xbib.time.chronic.tags.Tag;
import java.util.List; import java.util.List;
@ -65,25 +65,25 @@ public abstract class Repeater<T> extends Tag<T> implements Comparable<Repeater<
* @param pointer pointer * @param pointer pointer
* @return span * @return span
*/ */
public Span nextSpan(Pointer.PointerType pointer) { public Span nextSpan(PointerType pointer) {
if (getNow() == null) { if (getNow() == null) {
throw new IllegalStateException("Start point must be set before calling #next"); throw new IllegalStateException("Start point must be set before calling #next");
} }
return internalNextSpan(pointer); 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) { if (getNow() == null) {
throw new IllegalStateException("Start point must be set before calling #this"); throw new IllegalStateException("Start point must be set before calling #this");
} }
return internalThisSpan(pointer); 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 @Override
public int hashCode() { public int hashCode() {

View file

@ -1,7 +1,7 @@
package org.xbib.time.chronic.repeaters; package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span; 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.ZonedDateTime;
import java.time.temporal.ChronoUnit; 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.Span;
import org.xbib.time.chronic.Token; 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.ZonedDateTime;
import java.time.temporal.ChronoField; 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 int DAY_SECONDS = 86400;
private static final Pattern MON_PATTERN = Pattern.compile("^m[ou]n(day)?$"); 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 = Pattern.compile("^t(ue|eu|oo|u|)s(day)?$");
private static final Pattern TUE_PATTERN_1 = Pattern.compile("^tue$"); 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_1 = Pattern.compile("^we(dnes|nds|nns)day$");
private static final Pattern WED_PATTERN_2 = Pattern.compile("^wed$"); 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_1 = Pattern.compile("^th(urs|ers)day$");
private static final Pattern THU_PATTERN_2 = Pattern.compile("^thu$"); 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 FRI_PATTERN = Pattern.compile("^fr[iy](day)?$");
private static final Pattern SAT_PATTERN = Pattern.compile("^sat(t?[ue]rday)?$"); private static final Pattern SAT_PATTERN = Pattern.compile("^sat(t?[ue]rday)?$");
private static final Pattern SUN_PATTERN = Pattern.compile("^su[nm](day)?$"); private static final Pattern SUN_PATTERN = Pattern.compile("^su[nm](day)?$");
private ZonedDateTime currentDayStart; private ZonedDateTime currentDayStart;
public RepeaterDayName(DayName type) { public RepeaterDayName(DayName type) {
@ -106,10 +118,4 @@ public class RepeaterDayName extends Repeater<RepeaterDayName.DayName> {
return super.toString() + "-dayname-" + getType(); 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.Range;
import org.xbib.time.chronic.Span; import org.xbib.time.chronic.Span;
import org.xbib.time.chronic.Token; 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.ZonedDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
@ -18,14 +18,21 @@ import java.util.regex.Pattern;
public abstract class RepeaterDayPortion<T> extends Repeater<T> { public abstract class RepeaterDayPortion<T> extends Repeater<T> {
private static final Pattern AM_PATTERN = Pattern.compile("^ams?$"); private static final Pattern AM_PATTERN = Pattern.compile("^ams?$");
private static final Pattern PM_PATTERN = Pattern.compile("^pms?$"); private static final Pattern PM_PATTERN = Pattern.compile("^pms?$");
private static final Pattern MORNING_PATTERN = Pattern.compile("^mornings?$"); private static final Pattern MORNING_PATTERN = Pattern.compile("^mornings?$");
private static final Pattern AFTERNOON_PATTERN = Pattern.compile("^afternoons?$"); private static final Pattern AFTERNOON_PATTERN = Pattern.compile("^afternoons?$");
private static final Pattern EVENING_PATTERN = Pattern.compile("^evenings?$"); private static final Pattern EVENING_PATTERN = Pattern.compile("^evenings?$");
private static final Pattern NIGHT_PATTERN = Pattern.compile("^(night|nite)s?$"); private static final Pattern NIGHT_PATTERN = Pattern.compile("^(night|nite)s?$");
private static final int FULL_DAY_SECONDS = 60 * 60 * 24; private static final int FULL_DAY_SECONDS = 60 * 60 * 24;
private Range range;
private final Range range;
private Span currentSpan; private Span currentSpan;
public RepeaterDayPortion(T type) { public RepeaterDayPortion(T type) {
@ -149,10 +156,4 @@ public abstract class RepeaterDayPortion<T> extends Repeater<T> {
return super.toString() + "-dayportion-" + getType(); 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; package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span; 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.ZonedDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
@ -10,6 +10,7 @@ import java.time.temporal.ChronoUnit;
* *
*/ */
public class RepeaterFortnight extends RepeaterUnit { public class RepeaterFortnight extends RepeaterUnit {
public static final int FORTNIGHT_SECONDS = 1209600; // (14 * 24 * 60 * 60) public static final int FORTNIGHT_SECONDS = 1209600; // (14 * 24 * 60 * 60)
private ZonedDateTime currentFortnightStart; private ZonedDateTime currentFortnightStart;
@ -23,12 +24,12 @@ public class RepeaterFortnight extends RepeaterUnit {
protected Span internalNextSpan(PointerType pointer) { protected Span internalNextSpan(PointerType pointer) {
if (currentFortnightStart == null) { if (currentFortnightStart == null) {
if (pointer == PointerType.FUTURE) { if (pointer == PointerType.FUTURE) {
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY); RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow()); sundayRepeater.setNow(getNow());
Span nextSundaySpan = sundayRepeater.nextSpan(PointerType.FUTURE); Span nextSundaySpan = sundayRepeater.nextSpan(PointerType.FUTURE);
currentFortnightStart = nextSundaySpan.getBeginCalendar(); currentFortnightStart = nextSundaySpan.getBeginCalendar();
} else if (pointer == PointerType.PAST) { } 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.setNow(getNow().plus(RepeaterDay.DAY_SECONDS, ChronoUnit.SECONDS));
sundayRepeater.nextSpan(PointerType.PAST); sundayRepeater.nextSpan(PointerType.PAST);
sundayRepeater.nextSpan(PointerType.PAST); sundayRepeater.nextSpan(PointerType.PAST);
@ -55,7 +56,7 @@ public class RepeaterFortnight extends RepeaterUnit {
Span span; Span span;
if (pointer == PointerType.FUTURE) { if (pointer == PointerType.FUTURE) {
ZonedDateTime thisFortnightStart = ymdh(getNow()).plus(RepeaterHour.HOUR_SECONDS, ChronoUnit.SECONDS); 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.setNow(getNow());
sundayRepeater.thisSpan(PointerType.FUTURE); sundayRepeater.thisSpan(PointerType.FUTURE);
Span thisSundaySpan = sundayRepeater.thisSpan(PointerType.FUTURE); Span thisSundaySpan = sundayRepeater.thisSpan(PointerType.FUTURE);
@ -63,7 +64,7 @@ public class RepeaterFortnight extends RepeaterUnit {
span = new Span(thisFortnightStart, thisFortnightEnd); span = new Span(thisFortnightStart, thisFortnightEnd);
} else if (pointer == PointerType.PAST) { } else if (pointer == PointerType.PAST) {
ZonedDateTime thisFortnightEnd = ymdh(getNow()); ZonedDateTime thisFortnightEnd = ymdh(getNow());
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY); RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow()); sundayRepeater.setNow(getNow());
Span lastSundaySpan = sundayRepeater.nextSpan(PointerType.PAST); Span lastSundaySpan = sundayRepeater.nextSpan(PointerType.PAST);
ZonedDateTime thisFortnightStart = lastSundaySpan.getBeginCalendar(); ZonedDateTime thisFortnightStart = lastSundaySpan.getBeginCalendar();

View file

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

View file

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

View file

@ -1,7 +1,7 @@
package org.xbib.time.chronic.repeaters; package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span; 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.ZonedDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
@ -10,6 +10,7 @@ import java.time.temporal.ChronoUnit;
* *
*/ */
public class RepeaterMonth extends RepeaterUnit { public class RepeaterMonth extends RepeaterUnit {
private static final int MONTH_SECONDS = 2592000; // 30 * 24 * 60 * 60 private static final int MONTH_SECONDS = 2592000; // 30 * 24 * 60 * 60
private ZonedDateTime currentMonthStart; 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.Span;
import org.xbib.time.chronic.Token; 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.ZonedDateTime;
import java.time.temporal.ChronoUnit; 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 JAN_PATTERN = Pattern.compile("^jan\\.?(uary)?$");
private static final Pattern FEB_PATTERN = Pattern.compile("^feb\\.?(ruary)?$"); private static final Pattern FEB_PATTERN = Pattern.compile("^feb\\.?(ruary)?$");
private static final Pattern MAR_PATTERN = Pattern.compile("^mar\\.?(ch)?$"); private static final Pattern MAR_PATTERN = Pattern.compile("^mar\\.?(ch)?$");
private static final Pattern APR_PATTERN = Pattern.compile("^apr\\.?(il)?$"); private static final Pattern APR_PATTERN = Pattern.compile("^apr\\.?(il)?$");
private static final Pattern MAY_PATTERN = Pattern.compile("^may$"); private static final Pattern MAY_PATTERN = Pattern.compile("^may$");
private static final Pattern JUN_PATTERN = Pattern.compile("^jun\\.?e?$"); private static final Pattern JUN_PATTERN = Pattern.compile("^jun\\.?e?$");
private static final Pattern JUL_PATTERN = Pattern.compile("^jul\\.?y?$"); private static final Pattern JUL_PATTERN = Pattern.compile("^jul\\.?y?$");
private static final Pattern AUG_PATTERN = Pattern.compile("^aug\\.?(ust)?$"); 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 SEP_PATTERN = Pattern.compile("^sep\\.?(t\\.?|tember)?$");
private static final Pattern OCT_PATTERN = Pattern.compile("^oct\\.?(ober)?$"); private static final Pattern OCT_PATTERN = Pattern.compile("^oct\\.?(ober)?$");
private static final Pattern NOV_PATTERN = Pattern.compile("^nov\\.?(ember)?$"); private static final Pattern NOV_PATTERN = Pattern.compile("^nov\\.?(ember)?$");
private static final Pattern DEC_PATTERN = Pattern.compile("^dec\\.?(ember)?$"); private static final Pattern DEC_PATTERN = Pattern.compile("^dec\\.?(ember)?$");
private static final int MONTH_SECONDS = 2592000; // 30 * 24 * 60 * 60 private static final int MONTH_SECONDS = 2592000; // 30 * 24 * 60 * 60
private ZonedDateTime currentMonthBegin; private ZonedDateTime currentMonthBegin;
public RepeaterMonthName(MonthName type) { public RepeaterMonthName(MonthName type) {
@ -146,12 +159,4 @@ public class RepeaterMonthName extends Repeater<RepeaterMonthName.MonthName> {
return super.toString() + "-monthname-" + getType(); 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; package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span; 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.ZonedDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
@ -10,6 +10,7 @@ import java.time.temporal.ChronoUnit;
* *
*/ */
public class RepeaterSecond extends RepeaterUnit { public class RepeaterSecond extends RepeaterUnit {
private static final int SECOND_SECONDS = 1; private static final int SECOND_SECONDS = 1;
private ZonedDateTime secondStart; private ZonedDateTime secondStart;
@ -22,7 +23,6 @@ public class RepeaterSecond extends RepeaterUnit {
} else { } else {
secondStart = secondStart.plus(direction, ChronoUnit.SECONDS); secondStart = secondStart.plus(direction, ChronoUnit.SECONDS);
} }
return new Span(secondStart, ChronoUnit.SECONDS, 1); 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.Span;
import org.xbib.time.chronic.Tick; import org.xbib.time.chronic.Tick;
import org.xbib.time.chronic.Token; 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.ZonedDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
@ -16,13 +16,17 @@ import java.util.regex.Pattern;
* *
*/ */
public class RepeaterTime extends Repeater<Tick> { public class RepeaterTime extends Repeater<Tick> {
private static final Pattern TIME_PATTERN = Pattern.compile("^\\d{1,2}(:?\\d{2})?([\\.:]?\\d{2})?$"); private static final Pattern TIME_PATTERN = Pattern.compile("^\\d{1,2}(:?\\d{2})?([\\.:]?\\d{2})?$");
private ZonedDateTime currentTime; private ZonedDateTime currentTime;
public RepeaterTime(String time) { public RepeaterTime(String time) {
super(null); super(null);
String t = time.replaceAll(":", ""); String t = time.replaceAll(":", "");
Tick type; Tick type;
boolean ambiguous = time.contains(":") && Integer.parseInt(t.substring(0, 1)) != 0 &&
Integer.parseInt(t.substring(0, 2)) <= 12;
int length = t.length(); int length = t.length();
if (length <= 2) { if (length <= 2) {
int hours = Integer.parseInt(t); int hours = Integer.parseInt(t);
@ -37,8 +41,6 @@ public class RepeaterTime extends Repeater<Tick> {
int minutesInSeconds = Integer.parseInt(t.substring(1)) * 60; int minutesInSeconds = Integer.parseInt(t.substring(1)) * 60;
type = new Tick(hoursInSeconds + minutesInSeconds, true); type = new Tick(hoursInSeconds + minutesInSeconds, true);
} else if (length == 4) { } 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 hours = Integer.parseInt(t.substring(0, 2));
int hoursInSeconds = hours * 60 * 60; int hoursInSeconds = hours * 60 * 60;
int minutesInSeconds = Integer.parseInt(t.substring(2)) * 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)); int seconds = Integer.parseInt(t.substring(3));
type = new Tick(hoursInSeconds + minutesInSeconds + seconds, true); type = new Tick(hoursInSeconds + minutesInSeconds + seconds, true);
} else if (length == 6) { } 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 hours = Integer.parseInt(t.substring(0, 2));
int hoursInSeconds = hours * 60 * 60; int hoursInSeconds = hours * 60 * 60;
int minutesInSeconds = Integer.parseInt(t.substring(2, 4)) * 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) { private static Integer integerValue(String str) {
if (str != null) { if (str != null) {
String s = str.toLowerCase(); String s = str.toLowerCase();
if ("one".equals(s)) { switch (s) {
return 1; case "one":
} else if ("two".equals(s)) { return 1;
return 2; case "two":
} else if ("three".equals(s)) { return 2;
return 3; case "three":
} else if ("four".equals(s)) { return 3;
return 4; case "four":
} else if ("five".equals(s)) { return 4;
return 5; case "five":
} else if ("six".equals(s)) { return 5;
return 6; case "six":
} else if ("seven".equals(s)) { return 6;
return 7; case "seven":
} else if ("eight".equals(s)) { return 7;
return 8; case "eight":
} else if ("nine".equals(s)) { return 8;
return 9; case "nine":
} else if ("ten".equals(s)) { return 9;
return 10; case "ten":
} else if ("eleven".equals(s)) { return 10;
return 11; case "eleven":
} else if ("twelve".equals(s)) { return 11;
return 12; case "twelve":
return 12;
} }
} }
return null; return null;
@ -158,8 +159,8 @@ public class RepeaterTime extends Repeater<Tick> {
} }
} }
} else { } else {
List<ZonedDateTime> pastDates = new LinkedList<>();
if (tick.isAmbiguous()) { if (tick.isAmbiguous()) {
List<ZonedDateTime> pastDates = new LinkedList<>();
pastDates.add(midnight.plus(halfDay + (long) tick.intValue(), ChronoUnit.SECONDS)); pastDates.add(midnight.plus(halfDay + (long) tick.intValue(), ChronoUnit.SECONDS));
pastDates.add(midnight.plus(tick.intValue(), ChronoUnit.SECONDS)); pastDates.add(midnight.plus(tick.intValue(), ChronoUnit.SECONDS));
pastDates.add(yesterdayMidnight.plus(tick.intValue() * 2L, ChronoUnit.SECONDS)); pastDates.add(yesterdayMidnight.plus(tick.intValue() * 2L, ChronoUnit.SECONDS));
@ -171,7 +172,6 @@ public class RepeaterTime extends Repeater<Tick> {
} }
} }
} else { } else {
List<ZonedDateTime> pastDates = new LinkedList<>();
pastDates.add(midnight.plus(tick.intValue(), ChronoUnit.SECONDS)); pastDates.add(midnight.plus(tick.intValue(), ChronoUnit.SECONDS));
pastDates.add(yesterdayMidnight.plus(tick.intValue(), ChronoUnit.SECONDS)); pastDates.add(yesterdayMidnight.plus(tick.intValue(), ChronoUnit.SECONDS));
for (ZonedDateTime pastDate : pastDates) { for (ZonedDateTime pastDate : pastDates) {
@ -183,18 +183,15 @@ public class RepeaterTime extends Repeater<Tick> {
} }
} }
} }
if (!done && currentTime == null) { if (!done && currentTime == null) {
throw new IllegalStateException("Current time cannot be null at this point."); throw new IllegalStateException("Current time cannot be null at this point.");
} }
} }
if (!first) { if (!first) {
int increment = tick.isAmbiguous() ? halfDay : fullDay; int increment = tick.isAmbiguous() ? halfDay : fullDay;
long direction = pointer == PointerType.FUTURE ? 1L : -1L; long direction = pointer == PointerType.FUTURE ? 1L : -1L;
currentTime = currentTime.plus(direction * increment, ChronoUnit.SECONDS); currentTime = currentTime.plus(direction * increment, ChronoUnit.SECONDS);
} }
return new Span(currentTime, currentTime.plus(getWidth(), 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> { public abstract class RepeaterUnit extends Repeater<Object> {
private static final Pattern YEAR_PATTERN = Pattern.compile("^years?$"); private static final Pattern YEAR_PATTERN = Pattern.compile("^years?$");
private static final Pattern MONTH_PATTERN = Pattern.compile("^months?$"); private static final Pattern MONTH_PATTERN = Pattern.compile("^months?$");
private static final Pattern FORTNIGHT_PATTERN = Pattern.compile("^fortnights?$"); private static final Pattern FORTNIGHT_PATTERN = Pattern.compile("^fortnights?$");
private static final Pattern WEEK_PATTERN = Pattern.compile("^weeks?$"); private static final Pattern WEEK_PATTERN = Pattern.compile("^weeks?$");
private static final Pattern WEEKEND_PATTERN = Pattern.compile("^weekends?$"); private static final Pattern WEEKEND_PATTERN = Pattern.compile("^weekends?$");
private static final Pattern DAY_PATTERN = Pattern.compile("^days?$"); private static final Pattern DAY_PATTERN = Pattern.compile("^days?$");
private static final Pattern HOUR_PATTERN = Pattern.compile("^hours?$"); private static final Pattern HOUR_PATTERN = Pattern.compile("^hours?$");
private static final Pattern MINUTE_PATTERN = Pattern.compile("^minutes?$"); private static final Pattern MINUTE_PATTERN = Pattern.compile("^minutes?$");
private static final Pattern SECOND_PATTERN = Pattern.compile("^seconds?$"); private static final Pattern SECOND_PATTERN = Pattern.compile("^seconds?$");
public RepeaterUnit() { public RepeaterUnit() {
@ -66,10 +75,4 @@ public abstract class RepeaterUnit extends Repeater<Object> {
((Repeater) other).getNow().equals(getNow()); ((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; package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span; 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.ZonedDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
@ -10,7 +10,9 @@ import java.time.temporal.ChronoUnit;
* *
*/ */
public class RepeaterWeek extends RepeaterUnit { public class RepeaterWeek extends RepeaterUnit {
public static final int WEEK_SECONDS = 604800; public static final int WEEK_SECONDS = 604800;
public static final int WEEK_DAYS = 7; public static final int WEEK_DAYS = 7;
private ZonedDateTime currentWeekStart; private ZonedDateTime currentWeekStart;
@ -24,12 +26,12 @@ public class RepeaterWeek extends RepeaterUnit {
protected Span internalNextSpan(PointerType pointer) { protected Span internalNextSpan(PointerType pointer) {
if (currentWeekStart == null) { if (currentWeekStart == null) {
if (pointer == PointerType.FUTURE) { if (pointer == PointerType.FUTURE) {
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY); RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow()); sundayRepeater.setNow(getNow());
Span nextSundaySpan = sundayRepeater.nextSpan(PointerType.FUTURE); Span nextSundaySpan = sundayRepeater.nextSpan(PointerType.FUTURE);
currentWeekStart = nextSundaySpan.getBeginCalendar(); currentWeekStart = nextSundaySpan.getBeginCalendar();
} else if (pointer == PointerType.PAST) { } 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.setNow(getNow().plus(1, ChronoUnit.DAYS));
sundayRepeater.nextSpan(PointerType.PAST); sundayRepeater.nextSpan(PointerType.PAST);
Span lastSundaySpan = sundayRepeater.nextSpan(PointerType.PAST); Span lastSundaySpan = sundayRepeater.nextSpan(PointerType.PAST);
@ -52,20 +54,20 @@ public class RepeaterWeek extends RepeaterUnit {
ZonedDateTime thisWeekEnd; ZonedDateTime thisWeekEnd;
if (pointer == PointerType.FUTURE) { if (pointer == PointerType.FUTURE) {
thisWeekStart = ymdh(getNow()).plus(1, ChronoUnit.HOURS); thisWeekStart = ymdh(getNow()).plus(1, ChronoUnit.HOURS);
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY); RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow()); sundayRepeater.setNow(getNow());
Span thisSundaySpan = sundayRepeater.thisSpan(PointerType.FUTURE); Span thisSundaySpan = sundayRepeater.thisSpan(PointerType.FUTURE);
thisWeekEnd = thisSundaySpan.getBeginCalendar(); thisWeekEnd = thisSundaySpan.getBeginCalendar();
thisWeekSpan = new Span(thisWeekStart, thisWeekEnd); thisWeekSpan = new Span(thisWeekStart, thisWeekEnd);
} else if (pointer == PointerType.PAST) { } else if (pointer == PointerType.PAST) {
thisWeekEnd = ymdh(getNow()); thisWeekEnd = ymdh(getNow());
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY); RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow()); sundayRepeater.setNow(getNow());
Span lastSundaySpan = sundayRepeater.nextSpan(PointerType.PAST); Span lastSundaySpan = sundayRepeater.nextSpan(PointerType.PAST);
thisWeekStart = lastSundaySpan.getBeginCalendar(); thisWeekStart = lastSundaySpan.getBeginCalendar();
thisWeekSpan = new Span(thisWeekStart, thisWeekEnd); thisWeekSpan = new Span(thisWeekStart, thisWeekEnd);
} else if (pointer == PointerType.NONE) { } else if (pointer == PointerType.NONE) {
RepeaterDayName sundayRepeater = new RepeaterDayName(RepeaterDayName.DayName.SUNDAY); RepeaterDayName sundayRepeater = new RepeaterDayName(DayName.SUNDAY);
sundayRepeater.setNow(getNow()); sundayRepeater.setNow(getNow());
Span lastSundaySpan = sundayRepeater.nextSpan(PointerType.PAST); Span lastSundaySpan = sundayRepeater.nextSpan(PointerType.PAST);
thisWeekStart = lastSundaySpan.getBeginCalendar(); thisWeekStart = lastSundaySpan.getBeginCalendar();

View file

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

View file

@ -1,7 +1,7 @@
package org.xbib.time.chronic.repeaters; package org.xbib.time.chronic.repeaters;
import org.xbib.time.chronic.Span; 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.ZonedDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
@ -10,6 +10,7 @@ import java.time.temporal.ChronoUnit;
* *
*/ */
public class RepeaterYear extends RepeaterUnit { public class RepeaterYear extends RepeaterUnit {
private ZonedDateTime currentYearStart; private ZonedDateTime currentYearStart;
private static ZonedDateTime ymd(ZonedDateTime zonedDateTime) { 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 THIS_PATTERN = Pattern.compile("this");
private static final Pattern NEXT_PATTERN = Pattern.compile("next"); private static final Pattern NEXT_PATTERN = Pattern.compile("next");
private static final Pattern LAST_PATTERN = Pattern.compile("last"); private static final Pattern LAST_PATTERN = Pattern.compile("last");
public Grabber(Relative type) { public Grabber(Relative type) {
@ -49,10 +52,4 @@ public class Grabber extends Tag<Grabber.Relative> {
return "grabber-" + getType(); 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)$"); static final Pattern ORDINAL_PATTERN = Pattern.compile("^(\\d*)(st|nd|rd|th)$");
Ordinal(Integer type) { protected Ordinal(Integer type) {
super(type); super(type);
} }

View file

@ -8,7 +8,8 @@ import java.util.regex.Matcher;
* *
*/ */
public class OrdinalDay extends Ordinal { public class OrdinalDay extends Ordinal {
public OrdinalDay(Integer type) {
private OrdinalDay(Integer type) {
super(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"); private static final Pattern IN_PATTERN = Pattern.compile("\\bin\\b");
@ -52,10 +52,4 @@ public class Pointer extends Tag<Pointer.PointerType> {
return "pointer-" + getType(); 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> { 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*$"); private static final Pattern SCALAR_PATTERN = Pattern.compile("^\\d*$");
public Scalar(Integer type) { public Scalar(Integer type) {

View file

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

View file

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

View file

@ -9,6 +9,7 @@ import java.util.regex.Pattern;
* *
*/ */
public class ScalarYear extends Scalar { public class ScalarYear extends Scalar {
private static final Pattern YEAR_PATTERN = Pattern.compile("^([1-9]\\d)?\\d\\d?$"); private static final Pattern YEAR_PATTERN = Pattern.compile("^([1-9]\\d)?\\d\\d?$");
private ScalarYear(Integer type) { 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); super(type);
} }
@ -42,10 +42,4 @@ public class Separator extends Tag<Separator.SeparatorType> {
return "separator"; 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 { public class SeparatorAt extends Separator {
private static final Pattern AT_PATTERN = Pattern.compile("^(at|@)$"); private static final Pattern AT_PATTERN = Pattern.compile("^(at|@)$");
private SeparatorAt(SeparatorType type) { private SeparatorAt(SeparatorType type) {

View file

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

View file

@ -11,7 +11,9 @@ import java.util.regex.Pattern;
* *
*/ */
public class SeparatorSlashOrDash extends Separator { public class SeparatorSlashOrDash extends Separator {
private static final Pattern SLASH_PATTERN = Pattern.compile("^/$"); private static final Pattern SLASH_PATTERN = Pattern.compile("^/$");
private static final Pattern DASH_PATTERN = Pattern.compile("^-$"); private static final Pattern DASH_PATTERN = Pattern.compile("^-$");
public SeparatorSlashOrDash(SeparatorType type) { 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 class StringTag extends Tag<String> {
public StringTag(String type) { public StringTag(String type) {
super(type); super(type);
} }

View file

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

View file

@ -11,27 +11,25 @@ import java.util.Locale;
/** /**
* Composite implementation that merges other fields to create a full pattern. * 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 PeriodPrinter[] iPrinters;
private final PeriodParser[] iParsers; private final PeriodParser[] iParsers;
Composite(List<Object> elementPairs) { public Composite(List<Object> elementPairs) {
List<Object> printerList = new ArrayList<>(); List<PeriodPrinter> printerList = new ArrayList<>();
List<Object> parserList = new ArrayList<>(); List<PeriodParser> parserList = new ArrayList<>();
decompose(elementPairs, printerList, parserList); decompose(elementPairs, printerList, parserList);
if (printerList.isEmpty()) { if (printerList.isEmpty()) {
iPrinters = null; iPrinters = null;
} else { } else {
iPrinters = printerList.toArray(new PeriodPrinter[printerList.size()]); iPrinters = printerList.toArray(new PeriodPrinter[0]);
} }
if (parserList.isEmpty()) { if (parserList.isEmpty()) {
iParsers = null; iParsers = null;
} else { } 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; 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(); int size = elementPairs.size();
for (int i = 0; i < size; i += 2) { for (int i = 0; i < size; i += 2) {
Object element = elementPairs.get(i); Object element = elementPairs.get(i);
if (element instanceof PeriodPrinter) { if (element instanceof PeriodPrinter) {
if (element instanceof Composite) { if (element instanceof Composite) {
addArrayToList(printerList, ((Composite) element).iPrinters); PeriodPrinter[] periodPrinters = ((Composite) element).iPrinters;
if (periodPrinters != null) {
Collections.addAll(printerList, periodPrinters);
}
} else { } else {
printerList.add(element); printerList.add((PeriodPrinter) element);
} }
} }
element = elementPairs.get(i + 1); element = elementPairs.get(i + 1);
if (element instanceof PeriodParser) { if (element instanceof PeriodParser) {
if (element instanceof Composite) { if (element instanceof Composite) {
addArrayToList(parserList, ((Composite) element).iParsers); PeriodParser[] periodParsers = ((Composite) element).iParsers;
if (periodParsers != null) {
Collections.addAll(parserList, periodParsers);
}
} else { } 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. * 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 iLeft;
private final PeriodFieldAffix iRight; private final PeriodFieldAffix iRight;
private final String[] iLeftRightCombinations; private final String[] iLeftRightCombinations;
CompositeAffix(PeriodFieldAffix left, PeriodFieldAffix right) { public CompositeAffix(PeriodFieldAffix left, PeriodFieldAffix right) {
iLeft = left; iLeft = left;
iRight = right; iRight = right;
// We need to construct all possible combinations of left and right. // We need to construct all possible combinations of left and right.
// We are doing it once in constructor so that getAffixes() is quicker. // 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 leftText : iLeft.getAffixes()) {
for (String rightText : iRight.getAffixes()) { for (String rightText : iRight.getAffixes()) {
result.add(leftText + rightText); result.add(leftText + rightText);
} }
} }
iLeftRightCombinations = result.toArray(new String[result.size()]); iLeftRightCombinations = result.toArray(new String[0]);
} }
@Override @Override
public int calculatePrintedLength(int value) { public int calculatePrintedLength(int value) {
return iLeft.calculatePrintedLength(value) return iLeft.calculatePrintedLength(value) + iRight.calculatePrintedLength(value);
+ iRight.calculatePrintedLength(value);
} }
@Override @Override

View file

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

View file

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

View file

@ -6,7 +6,8 @@ import java.util.Set;
/** /**
* An affix that can be ignored. * An affix that can be ignored.
*/ */
abstract class IgnorableAffix implements PeriodFieldAffix { public abstract class IgnorableAffix implements PeriodFieldAffix {
private volatile String[] iOtherAffixes; private volatile String[] iOtherAffixes;
public void finish(Set<PeriodFieldAffix> periodFieldAffixesToIgnore) { public void finish(Set<PeriodFieldAffix> periodFieldAffixesToIgnore) {
@ -20,7 +21,6 @@ abstract class IgnorableAffix implements PeriodFieldAffix {
shortestAffix = affix; shortestAffix = affix;
} }
} }
// Pick only affixes that are longer than the shortest affix in this instance. // 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. // 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) // 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