Compare commits
2
Commits
release/2.0
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7b572015f | ||
|
|
85dc6cf58b |
No files matched your search
Vendored
+81
-186
@@ -1,186 +1,81 @@
|
|||||||
#!groovy
|
pipeline {
|
||||||
|
agent any
|
||||||
// Required Jenkins plugins:
|
|
||||||
// https://wiki.jenkins-ci.org/display/JENKINS/Timestamper
|
options {
|
||||||
// https://wiki.jenkins-ci.org/display/JENKINS/Static+Code+Analysis+Plug-ins
|
buildDiscarder(logRotator(numToKeepStr: '5'))
|
||||||
// https://wiki.jenkins-ci.org/display/JENKINS/Checkstyle+Plugin ?
|
disableConcurrentBuilds()
|
||||||
// https://wiki.jenkins-ci.org/display/JENKINS/FindBugs+Plugin
|
skipDefaultCheckout(true)
|
||||||
// https://wiki.jenkins-ci.org/display/JENKINS/PMD+Plugin ?
|
timestamps()
|
||||||
// https://wiki.jenkins-ci.org/display/JENKINS/DRY+Plugin ?
|
}
|
||||||
// https://wiki.jenkins-ci.org/display/JENKINS/Task+Scanner+Plugin
|
|
||||||
// https://wiki.jenkins-ci.org/display/JENKINS/Javadoc+Plugin
|
stages {
|
||||||
// https://wiki.jenkins-ci.org/display/JENKINS/JaCoCo+Plugin ?
|
stage('Checkout') {
|
||||||
|
steps { checkout scm }
|
||||||
|
}
|
||||||
init()
|
|
||||||
|
stage('Set version') {
|
||||||
def branch_name
|
steps {
|
||||||
def branch_name_base
|
script {
|
||||||
def build_number
|
String branch = env.BRANCH_NAME
|
||||||
def build_url
|
if (!branch) { error('BRANCH_NAME is unavailable; this pipeline must run as a multibranch job') }
|
||||||
def git_commit
|
env.DEPLOY_BUILD = 'false'
|
||||||
def job_name
|
def releaseMatch = branch =~ /^release\/(\d+\.\d+)$/
|
||||||
def tag
|
if (releaseMatch.matches()) {
|
||||||
def version
|
env.BUILD_VERSION = "${releaseMatch[0][1]}.${env.BUILD_NUMBER}-RELEASE"
|
||||||
def build_type
|
env.DEPLOY_BUILD = 'true'
|
||||||
def display_name
|
} else if (branch == 'develop') {
|
||||||
|
env.BUILD_VERSION = "develop.${env.BUILD_NUMBER}-SNAPSHOT"
|
||||||
def init() {
|
env.DEPLOY_BUILD = 'true'
|
||||||
|
} else {
|
||||||
// Keep the 5 most recent builds
|
String safeBranch = branch.replaceAll(/[^A-Za-z0-9._-]/, '-')
|
||||||
properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', numToKeepStr: '5']]])
|
env.BUILD_VERSION = "0.0.${env.BUILD_NUMBER}-${safeBranch}-SNAPSHOT"
|
||||||
|
}
|
||||||
build_number = env.BUILD_NUMBER
|
currentBuild.displayName = env.BUILD_VERSION
|
||||||
build_url = env.BUILD_URL
|
}
|
||||||
job_name = "${env.JOB_NAME}"
|
withMaven(maven: 'maven-3.9.16', globalMavenSettingsConfig: 'locusworks-settings') {
|
||||||
branch_name = env.BRANCH_NAME
|
sh 'mvn -B org.codehaus.mojo:versions-maven-plugin:2.21.0:set -DgenerateBackupPoms=false -DnewVersion="$BUILD_VERSION"'
|
||||||
branch_name_docker = branch_name.replaceAll(/\//,'.')
|
}
|
||||||
persist = "/var/lib/jenkins/PERSIST/${branch_name_docker}"
|
}
|
||||||
|
}
|
||||||
// execute the branch type specific pipeline code
|
|
||||||
try {
|
stage('Prepare OWASP cache') {
|
||||||
|
steps {
|
||||||
if (branch_name.indexOf('release/')==0) build_type='release'
|
lock(resource: 'owasp-nvd-cache') {
|
||||||
if (branch_name.indexOf('feature/')==0) build_type='feature'
|
withMaven(maven: 'maven-3.9.16', globalMavenSettingsConfig: 'locusworks-settings') {
|
||||||
if (branch_name.indexOf('develop')==0) build_type='develop'
|
sh 'mkdir -p "$HOME/.cache/dependency-check"'
|
||||||
if (branch_name.indexOf('hotfix')==0) build_type='hotfix'
|
sh 'mvn -B org.owasp:dependency-check-maven:13.0.0:update-only -DdataDirectory="$HOME/.cache/dependency-check"'
|
||||||
if (branch_name.indexOf('bugfix')==0) build_type='bugfix'
|
}
|
||||||
if (branch_name.indexOf('master')==0) build_type='master'
|
}
|
||||||
|
}
|
||||||
// common pipeline elements
|
}
|
||||||
node('master') {
|
|
||||||
Initialize()
|
stage('Build and test') {
|
||||||
SetVersion(build_type)
|
steps {
|
||||||
print_vars() // after SetVersion - all variables now defined
|
withMaven(maven: 'maven-3.9.16', globalMavenSettingsConfig: 'locusworks-settings') {
|
||||||
set_result('INPROGRESS')
|
sh 'mvn -B clean verify -DdataDirectory="$HOME/.cache/dependency-check" -DautoUpdate=false -Dbuild.revision="$GIT_COMMIT"'
|
||||||
Build() // builds database via flyway migration
|
}
|
||||||
}
|
}
|
||||||
|
post {
|
||||||
if (branch_name.indexOf('develop')==0) {
|
always { junit allowEmptyResults: true, testResults: '**/target/surefire-reports/*.xml' }
|
||||||
node('master') {
|
success {
|
||||||
Deploy();
|
archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true
|
||||||
}
|
}
|
||||||
} else if (branch_name.indexOf('release/')==0) {
|
}
|
||||||
node('master') {
|
}
|
||||||
Deploy();
|
|
||||||
}
|
stage('Deploy') {
|
||||||
}
|
when { expression { env.DEPLOY_BUILD == 'true' } }
|
||||||
|
steps {
|
||||||
node('master') {
|
withMaven(maven: 'maven-3.9.16', globalMavenSettingsConfig: 'locusworks-settings') {
|
||||||
set_result('SUCCESS')
|
sh 'mvn -B deploy -DskipTests -Ddependency-check.skip=true -Dbuild.number="$BUILD_NUMBER" -Dbuild.revision="$GIT_COMMIT"'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (err) {
|
}
|
||||||
node() {
|
}
|
||||||
set_result('FAILURE')
|
|
||||||
}
|
post {
|
||||||
throw err
|
success { echo "Published build ${env.BUILD_VERSION} successfully" }
|
||||||
}
|
failure { echo "Build ${env.BUILD_VERSION ?: env.BUILD_NUMBER} failed" }
|
||||||
}
|
cleanup { deleteDir() }
|
||||||
|
}
|
||||||
def Build() {
|
}
|
||||||
stage ('build') {
|
|
||||||
mvn "install -DskipTests=true -Dbuild.revision=${git_commit}"
|
|
||||||
step([$class: 'ArtifactArchiver', artifacts: '**/target/*.jar', fingerprint: true])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def Initialize() {
|
|
||||||
stage ('initialize') {
|
|
||||||
|
|
||||||
// get new code
|
|
||||||
checkout scm
|
|
||||||
|
|
||||||
git_commit = getSha1()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def Deploy() {
|
|
||||||
stage ('deploy') {
|
|
||||||
mvn "deploy -DskipTests=true -Dbuild.number=${build_number} -Dbuild.revision=${git_commit}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def getSha1() {
|
|
||||||
sha1 = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
|
|
||||||
echo "sha1 is ${sha1}"
|
|
||||||
return sha1
|
|
||||||
}
|
|
||||||
|
|
||||||
def mvn(args) {
|
|
||||||
withMaven(
|
|
||||||
maven: 'maven-3.9.4',
|
|
||||||
globalMavenSettingsConfig: 'locusworks-settings'
|
|
||||||
) {
|
|
||||||
|
|
||||||
sh "mvn ${args}"
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def mvn_initial(args) {
|
|
||||||
mvn(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
def set_result(status) {
|
|
||||||
if ( status == 'SUCCESS' ) {
|
|
||||||
currentBuild.result = status
|
|
||||||
notify_bitbucket('SUCCESSFUL')
|
|
||||||
} else if ( status == 'FAILURE' ) {
|
|
||||||
currentBuild.result = status
|
|
||||||
notify_bitbucket('FAILED')
|
|
||||||
} else if ( status == 'INPROGRESS' ) {
|
|
||||||
notify_bitbucket('INPROGRESS')
|
|
||||||
} else {
|
|
||||||
error ("unknown status")
|
|
||||||
}
|
|
||||||
|
|
||||||
// save in persistence file for access the status page
|
|
||||||
// make sure the directory exists first
|
|
||||||
sh "mkdir -p $persist && echo $status > $persist/build.result"
|
|
||||||
}
|
|
||||||
|
|
||||||
def notify_bitbucket(state) {
|
|
||||||
}
|
|
||||||
|
|
||||||
def print_vars() {
|
|
||||||
echo "build_number = ${build_number}"
|
|
||||||
echo "build_url = ${build_url}"
|
|
||||||
echo "job_name = ${job_name}"
|
|
||||||
echo "branch_name = ${branch_name}"
|
|
||||||
echo "branch_name_base = ${branch_name_base}"
|
|
||||||
echo "build_type = ${build_type}"
|
|
||||||
echo "display_name = ${currentBuild.displayName}"
|
|
||||||
echo "version = ${version}"
|
|
||||||
echo "git_commit = ${git_commit}"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def SetVersion( v ) {
|
|
||||||
stage ('set version') {
|
|
||||||
echo "set version ${v}"
|
|
||||||
branch_name_base = (branch_name =~ /([^\/]+$)/)[0][0]
|
|
||||||
if ( v == 'release' ) {
|
|
||||||
// for release branches, where the branch is named "release/1.2.3",
|
|
||||||
// derive the version and display name derive from the numeric suffix and append the build number
|
|
||||||
// 3.2.1.100
|
|
||||||
version = branch_name_base + "." + build_number + "-RELEASE";
|
|
||||||
//version = branch_name.substring('release/'.length()) + "." + build_number
|
|
||||||
currentBuild.displayName = version
|
|
||||||
} else if (v == 'develop') {
|
|
||||||
version = branch_name_base + "." + build_number + "-SNAPSHOT";
|
|
||||||
currentBuild.displayName = version
|
|
||||||
} else {
|
|
||||||
// for all other branches the version number is 0 with an appended build number
|
|
||||||
// and for the display name use the jenkins default #n and add the branch name
|
|
||||||
// #101 - feature/user/foo
|
|
||||||
//version = '0.' + build_number
|
|
||||||
version = branch_name_base + "." + build_number
|
|
||||||
currentBuild.displayName = "#" + build_number + " - " + branch_name_base
|
|
||||||
}
|
|
||||||
display_name = currentBuild.displayName
|
|
||||||
mvn_initial "versions:set -DnewVersion=${version}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this
|
|
||||||
@@ -1,17 +1,27 @@
|
|||||||
Locusworks Commons
|
# Locusworks Commons (Deprecated)
|
||||||
=
|
|
||||||
|
> **Deprecated:** Do not add `net.locusworks:locusworks-commons` to new projects.
|
||||||
- Library with common generic functions
|
|
||||||
|
This artifact contains no implementation code. It exists temporarily as a compatibility dependency that brings in all of the replacement libraries below.
|
||||||
Install
|
|
||||||
==
|
| Replacement artifact | Purpose |
|
||||||
|
| --- | --- |
|
||||||
Maven
|
| `locusworks-commons-core` | General utilities, collections, tuples, validation, hashing, I/O, properties, interfaces, and annotations |
|
||||||
===
|
| `locusworks-commons-configuration` | Property-file loading, reconciliation, persistence, and optional value encryption |
|
||||||
```xml
|
| `locusworks-commons-json` | JSON serialization and object mapping |
|
||||||
<dependency>
|
| `locusworks-commons-http` | HTTP client and SSL helpers |
|
||||||
<groupId>net.locusworks</groupId>
|
| `locusworks-commons-migration` | Flyway migration abstractions |
|
||||||
<artifactId>locusworks-commons</artifactId>
|
|
||||||
<version>${latest_version}</version>
|
## Migration
|
||||||
</dependency>
|
|
||||||
```
|
Remove `locusworks-commons` and declare only the libraries the application actually uses:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.locusworks</groupId>
|
||||||
|
<artifactId>locusworks-commons-core</artifactId>
|
||||||
|
<version>${locusworks.commons.version}</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
The Java package names remain unchanged, so source-code changes are generally unnecessary.
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# This is a sample build configuration for Java (Maven).
|
|
||||||
# Check our guides at https://confluence.atlassian.com/x/zd-5Mw for more examples.
|
|
||||||
# Only use spaces to indent your .yml configuration.
|
|
||||||
# -----
|
|
||||||
# You can specify a custom docker image from Docker Hub as your build environment.
|
|
||||||
image: maven:3.3.9
|
|
||||||
|
|
||||||
pipelines:
|
|
||||||
default:
|
|
||||||
- step:
|
|
||||||
caches:
|
|
||||||
- maven
|
|
||||||
script: # Modify the commands below to build your repository.
|
|
||||||
- mvn -B verify # -B batch mode makes Maven less verbose
|
|
||||||
@@ -1,40 +1,67 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>net.locusworks</groupId>
|
<groupId>net.locusworks</groupId>
|
||||||
<artifactId>locusworks-commons</artifactId>
|
<artifactId>locusworks-commons</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<name>locusworks_commons</name>
|
<packaging>jar</packaging>
|
||||||
<description>Common library for locusworks projects</description>
|
<name>Locusworks Commons</name>
|
||||||
|
<description>Convenience dependency that provides all standalone Locusworks commons libraries</description>
|
||||||
<organization>
|
|
||||||
<name>Locusworks</name>
|
|
||||||
<url>http://www.locusworks.net</url>
|
|
||||||
</organization>
|
|
||||||
|
|
||||||
<scm>
|
|
||||||
<connection>locus2k@bitbucket.org:locus2k/commons.git</connection>
|
|
||||||
</scm>
|
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<log4j.version>2.26.1</log4j.version>
|
|
||||||
<slf4j.version>2.0.18</slf4j.version>
|
|
||||||
<jackson.version>2.22.1</jackson.version>
|
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<mockito.version>5.23.0</mockito.version>
|
||||||
<nexus.repo>https://nexus.locusworks.net</nexus.repo>
|
<nexus.repo>https://nexus.locusworks.net</nexus.repo>
|
||||||
</properties>
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.locusworks</groupId>
|
||||||
|
<artifactId>locusworks-commons-core</artifactId>
|
||||||
|
<version>1.0.1-RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.locusworks</groupId>
|
||||||
|
<artifactId>locusworks-commons-configuration</artifactId>
|
||||||
|
<version>1.0.1-RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.locusworks</groupId>
|
||||||
|
<artifactId>locusworks-commons-json</artifactId>
|
||||||
|
<version>1.0.1-RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.locusworks</groupId>
|
||||||
|
<artifactId>locusworks-commons-http</artifactId>
|
||||||
|
<version>1.0.1-RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.locusworks</groupId>
|
||||||
|
<artifactId>locusworks-commons-migration</artifactId>
|
||||||
|
<version>1.0.1-RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.locusworks</groupId>
|
||||||
|
<artifactId>crypto</artifactId>
|
||||||
|
<version>2.0.1-RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<version>${mockito.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>3.5.6</version>
|
<version>3.5.6</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<argLine>@{argLine} --add-exports java.base/sun.security.jca=ALL-UNNAMED</argLine>
|
<argLine>@{argLine} -javaagent:${settings.localRepository}/org/mockito/mockito-core/${mockito.version}/mockito-core-${mockito.version}.jar</argLine>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
@@ -46,15 +73,13 @@
|
|||||||
<failOnError>true</failOnError>
|
<failOnError>true</failOnError>
|
||||||
<compilerArgs>
|
<compilerArgs>
|
||||||
<arg>-Xlint:all</arg>
|
<arg>-Xlint:all</arg>
|
||||||
<arg>--add-exports</arg>
|
|
||||||
<arg>java.base/sun.security.jca=ALL-UNNAMED</arg>
|
|
||||||
</compilerArgs>
|
</compilerArgs>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-maven</artifactId>
|
<artifactId>dependency-check-maven</artifactId>
|
||||||
<version>12.2.2</version>
|
<version>13.0.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<skipProvidedScope>true</skipProvidedScope>
|
<skipProvidedScope>true</skipProvidedScope>
|
||||||
<skipTestScope>true</skipTestScope>
|
<skipTestScope>true</skipTestScope>
|
||||||
@@ -70,143 +95,8 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>org.jacoco</groupId>
|
|
||||||
<artifactId>jacoco-maven-plugin</artifactId>
|
|
||||||
<version>0.8.15</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<goals>
|
|
||||||
<goal>prepare-agent</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>report</id>
|
|
||||||
<phase>prepare-package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>report</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>jacoco-check</id>
|
|
||||||
<goals>
|
|
||||||
<goal>check</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<rules>
|
|
||||||
<rule>
|
|
||||||
<element>PACKAGE</element>
|
|
||||||
<limits>
|
|
||||||
<limit>
|
|
||||||
<counter>LINE</counter>
|
|
||||||
<value>COVEREDRATIO</value>
|
|
||||||
<minimum>1.00</minimum>
|
|
||||||
</limit>
|
|
||||||
<limit>
|
|
||||||
<counter>BRANCH</counter>
|
|
||||||
<value>COVEREDRATIO</value>
|
|
||||||
<minimum>1.00</minimum>
|
|
||||||
</limit>
|
|
||||||
</limits>
|
|
||||||
</rule>
|
|
||||||
</rules>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<!-- Source: https://mvnrepository.com/artifact/commons-codec/commons-codec -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-codec</groupId>
|
|
||||||
<artifactId>commons-codec</artifactId>
|
|
||||||
<version>1.22.0</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
|
||||||
<version>6.1.1</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-params</artifactId>
|
|
||||||
<version>6.1.1</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-core</artifactId>
|
|
||||||
<version>5.23.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.flywaydb</groupId>
|
|
||||||
<artifactId>flyway-core</artifactId>
|
|
||||||
<version>12.10.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
|
||||||
<artifactId>log4j-api</artifactId>
|
|
||||||
<version>${log4j.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
|
||||||
<artifactId>log4j-core</artifactId>
|
|
||||||
<version>${log4j.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
|
||||||
<artifactId>log4j-slf4j-impl</artifactId>
|
|
||||||
<version>${log4j.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-api</artifactId>
|
|
||||||
<version>${slf4j.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>jcl-over-slf4j</artifactId>
|
|
||||||
<version>${slf4j.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
|
||||||
<artifactId>httpclient5</artifactId>
|
|
||||||
<version>5.6.2</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Jackson -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-core</artifactId>
|
|
||||||
<version>${jackson.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-annotations</artifactId>
|
|
||||||
<version>2.22</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-databind</artifactId>
|
|
||||||
<version>${jackson.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.code.gson</groupId>
|
|
||||||
<artifactId>gson</artifactId>
|
|
||||||
<version>2.14.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
<snapshotRepository>
|
<snapshotRepository>
|
||||||
<id>nexus-snapshot</id>
|
<id>nexus-snapshot</id>
|
||||||
@@ -217,7 +107,6 @@
|
|||||||
<url>${nexus.repo}/repository/locusworks-release/</url>
|
<url>${nexus.repo}/repository/locusworks-release/</url>
|
||||||
</repository>
|
</repository>
|
||||||
</distributionManagement>
|
</distributionManagement>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>locusworks-public</id>
|
<id>locusworks-public</id>
|
||||||
@@ -231,7 +120,6 @@
|
|||||||
</snapshots>
|
</snapshots>
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<pluginRepositories>
|
<pluginRepositories>
|
||||||
<pluginRepository>
|
<pluginRepository>
|
||||||
<id>locusworks-public</id>
|
<id>locusworks-public</id>
|
||||||
@@ -244,5 +132,4 @@
|
|||||||
</snapshots>
|
</snapshots>
|
||||||
</pluginRepository>
|
</pluginRepository>
|
||||||
</pluginRepositories>
|
</pluginRepositories>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
Whitespace-only changes.
@@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2007 The Guava Authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.locusworks.common;
|
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains constant definitions for the six standard {@link Charset} instances, which are
|
|
||||||
* guaranteed to be supported by all Java platform implementations.
|
|
||||||
*
|
|
||||||
* <p>Assuming you're free to choose, note that <b>{@link #UTF_8} is widely preferred</b>.
|
|
||||||
*
|
|
||||||
* <p>See the Guava User Guide article on <a
|
|
||||||
* href="https://github.com/google/guava/wiki/StringsExplained#charsets">{@code Charsets}</a>.
|
|
||||||
* <p>
|
|
||||||
* Please do not add new Charset references to this class, unless those character encodings are
|
|
||||||
* part of the set required to be supported by all Java platform implementations! Any Charsets
|
|
||||||
* initialized here may cause unexpected delays when this class is loaded. See the Charset
|
|
||||||
* Javadocs for the list of built-in character encodings.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public final class Charsets {
|
|
||||||
private Charsets() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* US-ASCII: seven-bit ASCII, the Basic Latin block of the Unicode character set (ISO646-US).
|
|
||||||
*/
|
|
||||||
public static final Charset US_ASCII = java.nio.charset.StandardCharsets.US_ASCII;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ISO-8859-1: ISO Latin Alphabet Number 1 (ISO-LATIN-1).
|
|
||||||
*/
|
|
||||||
public static final Charset ISO_8859_1 = java.nio.charset.StandardCharsets.ISO_8859_1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UTF-8: eight-bit UCS Transformation Format.
|
|
||||||
*/
|
|
||||||
public static final Charset UTF_8 = java.nio.charset.StandardCharsets.UTF_8;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UTF-16BE: sixteen-bit UCS Transformation Format, big-endian byte order.
|
|
||||||
*/
|
|
||||||
public static final Charset UTF_16BE = java.nio.charset.StandardCharsets.UTF_16BE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UTF-16LE: sixteen-bit UCS Transformation Format, little-endian byte order.
|
|
||||||
*/
|
|
||||||
public static final Charset UTF_16LE = java.nio.charset.StandardCharsets.UTF_16LE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UTF-16: sixteen-bit UCS Transformation Format, byte order identified by an optional byte-order
|
|
||||||
* mark.
|
|
||||||
*/
|
|
||||||
public static final Charset UTF_16 = java.nio.charset.StandardCharsets.UTF_16;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package net.locusworks.common.annotations;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation that will map a POJO to a map object.
|
|
||||||
* This is at the field level and will map the
|
|
||||||
* filed name as the key and the field value as the value
|
|
||||||
* in the map
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Target({ElementType.FIELD})
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface MapValue {
|
|
||||||
|
|
||||||
String value() default "";
|
|
||||||
|
|
||||||
boolean ignore() default false;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package net.locusworks.common.configuration;
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface ConfigurationCallback {
|
|
||||||
void results(String msg);
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
package net.locusworks.common.configuration;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import net.locusworks.common.Charsets;
|
|
||||||
import net.locusworks.common.crypto.AES;
|
|
||||||
import net.locusworks.common.exceptions.ApplicationException;
|
|
||||||
import net.locusworks.common.interfaces.PersistableRequest;
|
|
||||||
|
|
||||||
import net.locusworks.common.utils.Utils;
|
|
||||||
|
|
||||||
public class ConfigurationManager {
|
|
||||||
|
|
||||||
private Properties configuration;
|
|
||||||
private Properties defaults = null;
|
|
||||||
private Path conf = null;
|
|
||||||
|
|
||||||
protected AES aes;
|
|
||||||
|
|
||||||
private ConfigurationCallback callback;
|
|
||||||
|
|
||||||
protected void init(String baseDir, String propertiesFile, ConfigurationCallback callback) throws IOException {
|
|
||||||
init(baseDir, propertiesFile, this.getClass().getName().getBytes(Charsets.UTF_8), callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void init(String baseDir, String propertiesFile, byte[] aesKey, ConfigurationCallback callback) throws IOException {
|
|
||||||
aes = aesKey.length > 0 ? AES.createInstance(aesKey) : AES.createInstance();
|
|
||||||
this.callback = callback;
|
|
||||||
try {
|
|
||||||
defaults = PropertiesManager.loadConfiguration(this.getClass(), propertiesFile);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
// create patchrepoConf File object
|
|
||||||
conf = Paths.get(baseDir).resolve(propertiesFile);
|
|
||||||
|
|
||||||
loadConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadConfiguration() {
|
|
||||||
// load the active config file
|
|
||||||
// ignore read error, we can continue with an empty configuration map
|
|
||||||
// and all default items will be added below and the file created
|
|
||||||
|
|
||||||
callbackMessage("Loading config file: " + conf);
|
|
||||||
try {
|
|
||||||
configuration = PropertiesManager.loadConfiguration(conf);
|
|
||||||
} catch (Exception e) {
|
|
||||||
callbackMessage("Config file: " + conf + " will be created from template");
|
|
||||||
configuration = new Properties();
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> results = PropertiesManager.addConfiguration(configuration, defaults);
|
|
||||||
boolean changed = !results.isEmpty();
|
|
||||||
if (!results.isEmpty()) {
|
|
||||||
StringBuilder sb = new StringBuilder("Added new configuration items:\n");
|
|
||||||
for (Entry<String, String> entry : results.entrySet()) {
|
|
||||||
sb.append(String.format("%s=%s\n", entry.getKey(), entry.getValue()));
|
|
||||||
}
|
|
||||||
callbackMessage(sb.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
results = PropertiesManager.removeConfiguration(configuration, defaults);
|
|
||||||
changed |= !results.isEmpty();
|
|
||||||
if (!results.isEmpty()) {
|
|
||||||
StringBuilder sb = new StringBuilder("Added new configuration items:\n");
|
|
||||||
for (Entry<String, String> entry : results.entrySet()) {
|
|
||||||
sb.append(String.format("%s=%s\n", entry.getKey(), entry.getValue()));
|
|
||||||
}
|
|
||||||
callbackMessage(sb.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
PropertiesManager.saveConfiguration(configuration, conf, "Patch Repository properties file");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save the configuration values to file
|
|
||||||
*
|
|
||||||
* @param confs Configuration property values to save
|
|
||||||
* @throws Exception general exception
|
|
||||||
*/
|
|
||||||
public void saveToConf(Properties confs) throws Exception {
|
|
||||||
PropertiesManager.saveConfiguration(confs, conf, conf.getFileName().toString());
|
|
||||||
callbackMessage("Saved config file: " + conf + ", " + confs.size() + " entries");
|
|
||||||
loadConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPropertyValue(String key) {
|
|
||||||
return getPropertyValue(key, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPropertyValue(String key, String defaultValue) {
|
|
||||||
return configuration.containsKey(key) ? configuration.getProperty(key) : defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Properties getConfiguration() {
|
|
||||||
return configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void saveConfiguration(PersistableRequest request, Set<String> fieldsToSave, Set<String> excryptedFields) throws Exception {
|
|
||||||
if (fieldsToSave == null || fieldsToSave.isEmpty()) {
|
|
||||||
throw ApplicationException.generic("No fields to save were defined");
|
|
||||||
}
|
|
||||||
if (excryptedFields == null) {
|
|
||||||
excryptedFields = new HashSet<>();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Properties props = new Properties();
|
|
||||||
|
|
||||||
//copy what is current in the configuration settings into the new properties file
|
|
||||||
configuration.entrySet().forEach(item -> props.setProperty(String.valueOf(item.getKey()), String.valueOf(item.getValue())));
|
|
||||||
boolean changed = false;
|
|
||||||
for (Field f : request.getClass().getDeclaredFields()) {
|
|
||||||
f.setAccessible(true);
|
|
||||||
String fieldName = f.getName();
|
|
||||||
String fieldValue = String.valueOf(f.get(request));
|
|
||||||
|
|
||||||
//Ensures we are only saving values that are already configured
|
|
||||||
if (!fieldsToSave.contains(fieldName)) continue;
|
|
||||||
|
|
||||||
//Check to see if the old value changed
|
|
||||||
String oldValue = props.getProperty(fieldName);
|
|
||||||
if (Utils.isNotValid(oldValue, fieldValue) || oldValue.equals(fieldValue)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
changed = true;
|
|
||||||
|
|
||||||
fieldValue = excryptedFields.contains(fieldName) ? aes.encrypt(fieldValue) : fieldValue;
|
|
||||||
|
|
||||||
props.setProperty(fieldName, fieldValue);
|
|
||||||
}
|
|
||||||
if (changed) {
|
|
||||||
saveToConf(props);
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw ApplicationException.actionNotPermitted(ex.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void callbackMessage(String msg) {
|
|
||||||
if (callback != null) callback.results(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
package net.locusworks.common.configuration;
|
|
||||||
|
|
||||||
import static net.locusworks.common.Charsets.UTF_8;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import net.locusworks.common.immutables.Pair;
|
|
||||||
import net.locusworks.common.immutables.Unit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Properties manager class to help load and read properties
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 2.0.0
|
|
||||||
* @date 09/17/2023
|
|
||||||
*/
|
|
||||||
public class PropertiesManager {
|
|
||||||
/**
|
|
||||||
* Load a configuration from a resource
|
|
||||||
*
|
|
||||||
* @param clazz class loader
|
|
||||||
* @param src source of the file
|
|
||||||
* @return properties
|
|
||||||
* @throws IOException Exception thrown the file can't be read
|
|
||||||
*/
|
|
||||||
public static Properties loadConfiguration(Class<?> clazz, String src) throws IOException {
|
|
||||||
InputStream is = clazz.getResourceAsStream(src);
|
|
||||||
if (is == null) {
|
|
||||||
is = clazz.getClassLoader().getResourceAsStream(src);
|
|
||||||
}
|
|
||||||
if (is == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(is, UTF_8));
|
|
||||||
return loadConfiguration(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load configuration from a file. This method has been deprecated and may be removed in
|
|
||||||
* future released. Please use java.nio.Path
|
|
||||||
*
|
|
||||||
* @param file File to load
|
|
||||||
* @return properties
|
|
||||||
* @throws IOException Exception thrown the file can't be read
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static Properties loadConfiguration(File file) throws IOException {
|
|
||||||
return loadConfiguration(file.toPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load configuration from a file.
|
|
||||||
*
|
|
||||||
* @param path the path to the file
|
|
||||||
* @return properties
|
|
||||||
* @throws IOException Exception thrown the file can't be read
|
|
||||||
*/
|
|
||||||
public static Properties loadConfiguration(Path path) throws IOException {
|
|
||||||
if (Files.notExists(path)) {
|
|
||||||
return new Properties();
|
|
||||||
}
|
|
||||||
|
|
||||||
try (BufferedReader br = Files.newBufferedReader(path)) {
|
|
||||||
return loadConfiguration(br);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load configuration from a buffered reader
|
|
||||||
*
|
|
||||||
* @param reader Buffered reader to read the properties values from
|
|
||||||
* @return properties
|
|
||||||
* @throws IOException Exception thrown the file can't be read
|
|
||||||
*/
|
|
||||||
public static Properties loadConfiguration(BufferedReader reader) throws IOException {
|
|
||||||
Properties config = new Properties();
|
|
||||||
config.load(reader);
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add configurations from one properties file to another
|
|
||||||
*
|
|
||||||
* @param to Properties file to copy values to
|
|
||||||
* @param from Properties file to copy values from
|
|
||||||
* @return a map containing the results of the values added
|
|
||||||
*/
|
|
||||||
public static Map<String, String> addConfiguration(Properties to, Properties from) {
|
|
||||||
|
|
||||||
return from.entrySet()
|
|
||||||
.stream()
|
|
||||||
.filter(entry -> !to.containsKey(entry.getKey()))
|
|
||||||
.map(entry -> {
|
|
||||||
String key = entry.getKey().toString();
|
|
||||||
String value = entry.getValue().toString();
|
|
||||||
to.put(key, value);
|
|
||||||
return new Pair<String, String>(key, value);
|
|
||||||
})
|
|
||||||
.collect(Collectors.toMap(Unit::getValue1, Pair::getValue2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes configuration values that are not present in the comparedTo
|
|
||||||
*
|
|
||||||
* @param from Properties file to remove values from
|
|
||||||
* @param comparedTo Properties file to compare to
|
|
||||||
* @return a map containing the results of the values removed
|
|
||||||
*/
|
|
||||||
public static Map<String, String> removeConfiguration(Properties from, Properties comparedTo) {
|
|
||||||
|
|
||||||
return from.keySet()
|
|
||||||
.stream()
|
|
||||||
.filter(key -> !comparedTo.containsKey(key)) //only get the items that are not in the comparedTo properties
|
|
||||||
.map(key -> new Pair<String, String>(String.valueOf(key), String.valueOf(from.get(key))))
|
|
||||||
.toList() //Create a list of paired items (key value) of the items that were filtered
|
|
||||||
.stream()
|
|
||||||
.peek(pair -> { //remove those pairs from the from properties
|
|
||||||
from.remove(pair.getValue1());
|
|
||||||
})
|
|
||||||
.collect(Collectors.toMap(Unit::getValue1, Pair::getValue2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Save the properties file to disk.</p>
|
|
||||||
* <p><b>This method has been depecreated and could be removed in future release.<br/>Please use java.nio.Path</b></p>
|
|
||||||
*
|
|
||||||
* @param props Properties file to save
|
|
||||||
* @param fileToSave File to save to
|
|
||||||
* @param comment Any comments to add
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static void saveConfiguration(Properties props, File fileToSave, String comment) {
|
|
||||||
saveConfiguration(props, fileToSave.toPath(), comment);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Save the properties file to disk.</p>
|
|
||||||
*
|
|
||||||
* @param props Properties file to save
|
|
||||||
* @param fileToSave File to save to
|
|
||||||
* @param comment Any comments to add
|
|
||||||
*/
|
|
||||||
public static void saveConfiguration(Properties props, Path fileToSave, String comment) {
|
|
||||||
try (OutputStream fos = Files.newOutputStream(fileToSave)) {
|
|
||||||
props.store(fos, comment == null ? "" : comment);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new RuntimeException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
package net.locusworks.common.crypto;
|
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
|
||||||
import javax.crypto.KeyGenerator;
|
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
|
|
||||||
import java.security.*;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
import net.locusworks.common.utils.RandomString;
|
|
||||||
import net.locusworks.common.utils.Utils;
|
|
||||||
|
|
||||||
import static net.locusworks.common.Charsets.UTF_8;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AES encryption/decryption class
|
|
||||||
* This class will encrypt/decrypt data. The encryption key is never known.
|
|
||||||
* Instead, it is generated by the provided seed. As long as the seed stays the same
|
|
||||||
* the key will remain the same and the encryption/decryption will work. This
|
|
||||||
* provides and added security.
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
* @date 02/15/2018
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class AES {
|
|
||||||
|
|
||||||
private static final String ENCRYPTION_TYPE = "AES";
|
|
||||||
private static final String ENCRYPTION_ALGORITHM = "AES/CBC/PKCS5Padding";
|
|
||||||
private static final String PROVIDER = "SunJCE";
|
|
||||||
private static final String ALGORITHM = "SHA1PRNG";
|
|
||||||
|
|
||||||
private Cipher cipher;
|
|
||||||
|
|
||||||
private SecretKeySpec secretKeySpec;
|
|
||||||
|
|
||||||
private IvParameterSpec ivParamSpec;
|
|
||||||
|
|
||||||
private String seed;
|
|
||||||
|
|
||||||
private RandomString randomizer;
|
|
||||||
|
|
||||||
private void initSecureKey(String seed) {
|
|
||||||
try {
|
|
||||||
SecureRandom sr = getSecureRandom(seed);
|
|
||||||
KeyGenerator generator = KeyGenerator.getInstance(ENCRYPTION_TYPE);
|
|
||||||
generator.init(128, sr);
|
|
||||||
|
|
||||||
randomizer = RandomString.newInstance(sr);
|
|
||||||
init(generator.generateKey().getEncoded());
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new IllegalArgumentException("Unable to initialize encryption:", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the secure random object to be the same across all platforms
|
|
||||||
* with regard to provider and algorithm used
|
|
||||||
*
|
|
||||||
* @param seed Seed to initialize SecureRandom with
|
|
||||||
* @return SecureRandom object
|
|
||||||
* @throws NoSuchAlgorithmException thrown when algorithm can't be used
|
|
||||||
*/
|
|
||||||
private static SecureRandom getSecureRandom(String seed) throws NoSuchAlgorithmException {
|
|
||||||
SecureRandom sr = SecureRandom.getInstance(ALGORITHM);
|
|
||||||
sr.setSeed(seed.getBytes(UTF_8));
|
|
||||||
return sr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the aes engine
|
|
||||||
*
|
|
||||||
* @param key secret key to use
|
|
||||||
*/
|
|
||||||
private void init(final byte[] key) {
|
|
||||||
try {
|
|
||||||
this.cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM, PROVIDER);
|
|
||||||
this.secretKeySpec = new SecretKeySpec(key, ENCRYPTION_TYPE);
|
|
||||||
this.ivParamSpec = new IvParameterSpec(randomizer.getBytes(16));
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new IllegalArgumentException("Unable to initialize encryption:", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Encrypt a text string
|
|
||||||
* @param plainText String to encrypt
|
|
||||||
* @return encrypted string
|
|
||||||
*/
|
|
||||||
public String encrypt(String plainText) {
|
|
||||||
if (Utils.isEmptyString(plainText)) {
|
|
||||||
plainText = "";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, this.secretKeySpec, this.ivParamSpec);
|
|
||||||
byte[] cypherText = cipher.doFinal(plainText.getBytes(UTF_8));
|
|
||||||
return new String(Base64.getEncoder().encode(cypherText), UTF_8);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new IllegalArgumentException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Decrypt an encrypted string
|
|
||||||
* @param cipherString encrypted string to decrypt
|
|
||||||
* @return unecrypted string
|
|
||||||
*/
|
|
||||||
public String decrypt(String cipherString) {
|
|
||||||
if (Utils.isEmptyString(cipherString)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
byte[] cipherText = Base64.getDecoder().decode(cipherString.getBytes(UTF_8));
|
|
||||||
try {
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, this.secretKeySpec, this.ivParamSpec);
|
|
||||||
return new String(cipher.doFinal(cipherText), UTF_8);
|
|
||||||
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException |
|
|
||||||
InvalidAlgorithmParameterException e) {
|
|
||||||
throw new IllegalArgumentException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public AES withSeed(String seed) {
|
|
||||||
if (this.seed == null || !this.seed.equals(seed)) {
|
|
||||||
initSecureKey(seed);
|
|
||||||
}
|
|
||||||
this.seed = seed;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String getSeed() {
|
|
||||||
return this.seed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AES createInstance() {
|
|
||||||
return createInstance(RandomString.getInstance().getString(16));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AES createInstance(byte[] byteSeed) {
|
|
||||||
String seed = new String(byteSeed, UTF_8);
|
|
||||||
return createInstance(seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AES createInstance(String seed) {
|
|
||||||
return new AES().withSeed(seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws NoSuchAlgorithmException {
|
|
||||||
if (args == null || !(args.length > 0)) {
|
|
||||||
throw new IllegalArgumentException("No args provided. Need password as argument");
|
|
||||||
}
|
|
||||||
if (args.length % 2 == 0) {
|
|
||||||
System.out.println(AES.createInstance(String.valueOf(args[1])).decrypt(String.valueOf(args[0])));
|
|
||||||
} else {
|
|
||||||
System.out.println(AES.createInstance().encrypt(String.valueOf(args[0])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package net.locusworks.common.crypto;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
|
|
||||||
import net.locusworks.common.Charsets;
|
|
||||||
|
|
||||||
public class AESKey implements PrivateKey {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = -8452357427706386362L;
|
|
||||||
private final String seed;
|
|
||||||
|
|
||||||
public AESKey(String seed) {
|
|
||||||
this.seed = seed;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAlgorithm() {
|
|
||||||
return "aes";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFormat() {
|
|
||||||
return "aes-seed";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] getEncoded() {
|
|
||||||
return this.seed.getBytes(Charsets.UTF_8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package net.locusworks.common.crypto;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.security.spec.EncodedKeySpec;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
import net.locusworks.common.Charsets;
|
|
||||||
import net.locusworks.common.io.IOUtils;
|
|
||||||
|
|
||||||
import static net.locusworks.common.utils.Checks.checkArguments;
|
|
||||||
import static net.locusworks.common.utils.Utils.get;
|
|
||||||
import static net.locusworks.common.utils.Utils.size;
|
|
||||||
|
|
||||||
public class AESKeySpec extends EncodedKeySpec {
|
|
||||||
|
|
||||||
private static final String AES_MARKER = "aes-seed";
|
|
||||||
|
|
||||||
public AESKeySpec(byte[] encodedKey) {
|
|
||||||
super(encodedKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AESKey generateKey() throws InvalidKeySpecException {
|
|
||||||
try {
|
|
||||||
byte[] data = this.getEncoded();
|
|
||||||
InputStream stream = new ByteArrayInputStream(data);
|
|
||||||
Iterable<String> parts = Arrays.asList(IOUtils.toString(stream, Charsets.UTF_8).split(" "));
|
|
||||||
|
|
||||||
checkArguments(size(parts) == 2 && AES_MARKER.equals(get(parts, 0)), "Bad format, should be: aes-seed AAB3...");
|
|
||||||
stream = new ByteArrayInputStream(Base64.getDecoder().decode(String.valueOf(get(parts, 1))));
|
|
||||||
String marker = IOUtils.toString(stream, Charsets.UTF_8);
|
|
||||||
return new AESKey(marker);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new InvalidKeySpecException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFormat() {
|
|
||||||
return "aes";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
package net.locusworks.common.crypto;
|
|
||||||
|
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.KeyFactorySpi;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.Provider;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import java.security.spec.KeySpec;
|
|
||||||
|
|
||||||
import sun.security.jca.GetInstance;
|
|
||||||
import sun.security.jca.GetInstance.Instance;
|
|
||||||
|
|
||||||
public class EncryptionKeyFactory extends KeyFactory {
|
|
||||||
|
|
||||||
protected EncryptionKeyFactory(KeyFactorySpi keyFacSpi, Provider provider, String algorithm) {
|
|
||||||
super(keyFacSpi, provider, algorithm);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PrivateKey generatePrivateKey(KeySpec keySpec) throws InvalidKeySpecException {
|
|
||||||
if (keySpec instanceof AESKeySpec) {
|
|
||||||
return ((AESKeySpec) keySpec).generateKey();
|
|
||||||
}
|
|
||||||
return super.generatePrivate(keySpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PublicKey generatePublicKey(KeySpec keySpec) throws InvalidKeySpecException {
|
|
||||||
keySpec = keySpec instanceof SSHEncodedKeySpec ? ((SSHEncodedKeySpec) keySpec).convertToRSAPubKeySpec() : keySpec;
|
|
||||||
return super.generatePublic(keySpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EncryptionKeyFactory getInstance(String algorithm) throws NoSuchAlgorithmException {
|
|
||||||
Instance instance = GetInstance.getInstance("KeyFactory", KeyFactorySpi.class, algorithm);
|
|
||||||
return new EncryptionKeyFactory((KeyFactorySpi) instance.impl, instance.provider, algorithm);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
package net.locusworks.common.crypto;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import javax.crypto.SecretKeyFactory;
|
|
||||||
import javax.crypto.spec.PBEKeySpec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The type Hash salt.
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
* @date 02/15/2018
|
|
||||||
*/
|
|
||||||
public class HashSalt {
|
|
||||||
/**
|
|
||||||
* The constant PBKDF2_ALGORITHM.
|
|
||||||
*/
|
|
||||||
private static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA256";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The constant SALT_BYTE_SIZE.
|
|
||||||
*/
|
|
||||||
private static final int SALT_BYTE_SIZE = 24;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The constant HASH_BYTE_SIZE.
|
|
||||||
*/
|
|
||||||
private static final int HASH_BYTE_SIZE = 24;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The constant PBKDF2_ITERATIONS.
|
|
||||||
*/
|
|
||||||
private static final int PBKDF2_ITERATIONS = 1000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The constant ITERATION_INDEX.
|
|
||||||
*/
|
|
||||||
private static final int ITERATION_INDEX = 0;
|
|
||||||
/**
|
|
||||||
* The constant SALT_INDEX.
|
|
||||||
*/
|
|
||||||
private static final int SALT_INDEX = 1;
|
|
||||||
/**
|
|
||||||
* The constant PBKDF2_INDEX.
|
|
||||||
*/
|
|
||||||
private static final int PBKDF2_INDEX = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a salted PBKDF2 hash of the password.
|
|
||||||
*
|
|
||||||
* @param password the password to hash
|
|
||||||
* @return a salted PBKDF2 hash of the password
|
|
||||||
* @throws NoSuchAlgorithmException the no such algorithm exception
|
|
||||||
* @throws InvalidKeySpecException the invalid key spec exception
|
|
||||||
*/
|
|
||||||
public static String createHash(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
|
||||||
return createHash(password.toCharArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a salted PBKDF2 hash of the password.
|
|
||||||
*
|
|
||||||
* @param password the password to hash
|
|
||||||
* @return a salted PBKDF2 hash of the password
|
|
||||||
* @throws NoSuchAlgorithmException the no such algorithm exception
|
|
||||||
* @throws InvalidKeySpecException the invalid key spec exception
|
|
||||||
*/
|
|
||||||
public static String createHash(char[] password) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
|
||||||
// Generate a random salt
|
|
||||||
SecureRandom random = new SecureRandom();
|
|
||||||
byte[] salt = new byte[SALT_BYTE_SIZE];
|
|
||||||
random.nextBytes(salt);
|
|
||||||
|
|
||||||
// Hash the password
|
|
||||||
byte[] hash = pbkdf2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
|
|
||||||
// format iterations:salt:hash
|
|
||||||
return PBKDF2_ITERATIONS + ":" + toHex(salt) + ":" + toHex(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates a password using a hash.
|
|
||||||
*
|
|
||||||
* @param password the password to check
|
|
||||||
* @param correctHash the hash of the valid password
|
|
||||||
* @return true if the password is correct, false if not
|
|
||||||
* @throws NoSuchAlgorithmException the no such algorithm exception
|
|
||||||
* @throws InvalidKeySpecException the invalid key spec exception
|
|
||||||
*/
|
|
||||||
public static boolean validatePassword(String password, String correctHash) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
|
||||||
return validatePassword(password.toCharArray(), correctHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates a password using a hash.
|
|
||||||
*
|
|
||||||
* @param password the password to check
|
|
||||||
* @param correctHash the hash of the valid password
|
|
||||||
* @return true if the password is correct, false if not
|
|
||||||
* @throws NoSuchAlgorithmException the no such algorithm exception
|
|
||||||
* @throws InvalidKeySpecException the invalid key spec exception
|
|
||||||
*/
|
|
||||||
public static boolean validatePassword(char[] password, String correctHash) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
|
||||||
// Decode the hash into its parameters
|
|
||||||
String[] params = correctHash.split(":");
|
|
||||||
int iterations = Integer.parseInt(params[ITERATION_INDEX]);
|
|
||||||
byte[] salt = fromHex(params[SALT_INDEX]);
|
|
||||||
byte[] hash = fromHex(params[PBKDF2_INDEX]);
|
|
||||||
// Compute the hash of the provided password, using the same salt,
|
|
||||||
// iteration count, and hash length
|
|
||||||
byte[] testHash = pbkdf2(password, salt, iterations, hash.length);
|
|
||||||
// Compare the hashes in constant time. The password is correct if
|
|
||||||
// both hashes match.
|
|
||||||
return slowEquals(hash, testHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares two byte arrays in length-constant time. This comparison method
|
|
||||||
* is used so that password hashes cannot be extracted from an on-line
|
|
||||||
* system using a timing attack and then attacked off-line.
|
|
||||||
*
|
|
||||||
* @param a the first byte array
|
|
||||||
* @param b the second byte array
|
|
||||||
* @return true if both byte arrays are the same, false if not
|
|
||||||
*/
|
|
||||||
private static boolean slowEquals(byte[] a, byte[] b) {
|
|
||||||
int diff = a.length ^ b.length;
|
|
||||||
for (int i = 0; i < a.length && i < b.length; i++)
|
|
||||||
diff |= a[i] ^ b[i];
|
|
||||||
return diff == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes the PBKDF2 hash of a password.
|
|
||||||
*
|
|
||||||
* @param password the password to hash.
|
|
||||||
* @param salt the salt
|
|
||||||
* @param iterations the iteration count (slowness factor)
|
|
||||||
* @param bytes the length of the hash to compute in bytes
|
|
||||||
* @return the PBDKF2 hash of the password
|
|
||||||
*/
|
|
||||||
private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
|
||||||
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8);
|
|
||||||
SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
|
|
||||||
return skf.generateSecret(spec).getEncoded();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a string of hexadecimal characters into a byte array.
|
|
||||||
*
|
|
||||||
* @param hex the hex string
|
|
||||||
* @return the hex string decoded into a byte array
|
|
||||||
*/
|
|
||||||
private static byte[] fromHex(String hex) {
|
|
||||||
byte[] binary = new byte[hex.length() / 2];
|
|
||||||
for (int i = 0; i < binary.length; i++) {
|
|
||||||
binary[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
|
|
||||||
}
|
|
||||||
return binary;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a byte array into a hexadecimal string.
|
|
||||||
*
|
|
||||||
* @param array the byte array to convert
|
|
||||||
* @return a length*2 character string encoding the byte array
|
|
||||||
*/
|
|
||||||
private static String toHex(byte[] array) {
|
|
||||||
BigInteger bi = new BigInteger(1, array);
|
|
||||||
String hex = bi.toString(16);
|
|
||||||
int paddingLength = (array.length * 2) - hex.length();
|
|
||||||
if (paddingLength > 0)
|
|
||||||
return String.format("%0" + paddingLength + "d", 0) + hex;
|
|
||||||
else
|
|
||||||
return hex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
if (args == null || !(args.length > 0)) {
|
|
||||||
throw new IllegalArgumentException("No args provided. Need password as argument");
|
|
||||||
}
|
|
||||||
System.out.println(HashSalt.createHash(String.valueOf(args[0])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,221 +0,0 @@
|
|||||||
package net.locusworks.common.crypto;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.security.Key;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.interfaces.RSAPublicKey;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import java.security.spec.KeySpec;
|
|
||||||
import java.security.spec.PKCS8EncodedKeySpec;
|
|
||||||
import java.security.spec.X509EncodedKeySpec;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import net.locusworks.common.Charsets;
|
|
||||||
import net.locusworks.common.io.IOUtils;
|
|
||||||
import net.locusworks.common.utils.DataOutputStreamHelper;
|
|
||||||
import net.locusworks.common.utils.Utils;
|
|
||||||
|
|
||||||
import static net.locusworks.common.utils.Utils.handleExceptionWrapper;
|
|
||||||
import static net.locusworks.common.utils.Splitter.fixedLengthSplit;
|
|
||||||
import static java.lang.String.join;
|
|
||||||
|
|
||||||
public class KeyFile implements AutoCloseable {
|
|
||||||
|
|
||||||
public enum EncryptionType {
|
|
||||||
RSA,
|
|
||||||
AES,
|
|
||||||
SSH
|
|
||||||
}
|
|
||||||
|
|
||||||
private Key key;
|
|
||||||
private String description;
|
|
||||||
private Writer writer;
|
|
||||||
private EncryptionType encryptionType;
|
|
||||||
|
|
||||||
public KeyFile(Key key) {
|
|
||||||
this(key, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeyFile(Key key, String description) {
|
|
||||||
this(key, description, EncryptionType.valueOf(key.getAlgorithm().toUpperCase()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeyFile(Key key, String description, EncryptionType encryptionType) {
|
|
||||||
this.key = key;
|
|
||||||
this.description = description;
|
|
||||||
this.encryptionType = encryptionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private KeyFile() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadFromFile(String fileName) {
|
|
||||||
if (Utils.isEmptyString(fileName)) return;
|
|
||||||
|
|
||||||
this.key = null;
|
|
||||||
try {
|
|
||||||
File keyFile = new File(fileName);
|
|
||||||
if (!keyFile.exists()) {
|
|
||||||
throw new IllegalArgumentException(String.format("Unable to find file with name %s. Please check path", fileName));
|
|
||||||
}
|
|
||||||
|
|
||||||
String contentStr;
|
|
||||||
try (FileInputStream input = new FileInputStream(keyFile)) {
|
|
||||||
contentStr = IOUtils.toString(input, Charsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean rsaFormat = !contentStr.startsWith("ssh-rsa") && !contentStr.startsWith("aes-seed");
|
|
||||||
if (rsaFormat) {
|
|
||||||
contentStr = contentStr.replaceAll("-----[^-]+-----", "");
|
|
||||||
contentStr = contentStr.replaceAll("\\s", "");
|
|
||||||
} else {
|
|
||||||
contentStr = contentStr.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] content = rsaFormat ? Base64.getDecoder().decode(contentStr) : contentStr.getBytes(Charsets.UTF_8);
|
|
||||||
|
|
||||||
EncryptionKeyFactory kf = EncryptionKeyFactory.getInstance("RSA");
|
|
||||||
|
|
||||||
List<KeySpecHelper> keySpecs = Utils.toList(
|
|
||||||
new KeySpecHelper(new AESKeySpec(content), true, EncryptionType.AES),
|
|
||||||
new KeySpecHelper(new SSHEncodedKeySpec(content), false, EncryptionType.SSH),
|
|
||||||
new KeySpecHelper(new PKCS8EncodedKeySpec(content), true, EncryptionType.RSA),
|
|
||||||
new KeySpecHelper(new X509EncodedKeySpec(content), false, EncryptionType.RSA)
|
|
||||||
);
|
|
||||||
|
|
||||||
for (KeySpecHelper ksh : keySpecs) {
|
|
||||||
try {
|
|
||||||
this.key = ksh.isPrivate() ? kf.generatePrivateKey(ksh.getKeySpec()) : kf.generatePublicKey(ksh.getKeySpec());
|
|
||||||
this.encryptionType = ksh.getEncryptionType();
|
|
||||||
break;
|
|
||||||
} catch (NullPointerException | InvalidKeySpecException ikse) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.key == null) {
|
|
||||||
throw new InvalidKeySpecException(String.format("Unable to determine if file %s is a private or public key. Not type of PKCS8, X509, SSH or AES spec", fileName));
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(String fileName) {
|
|
||||||
try {
|
|
||||||
String data;
|
|
||||||
switch (this.encryptionType) {
|
|
||||||
case AES:
|
|
||||||
data = String.format("%s %s", this.key.getFormat(), Base64.getEncoder().encodeToString(this.key.getEncoded()));
|
|
||||||
IOUtils.writeStringToFile(fileName, data);
|
|
||||||
break;
|
|
||||||
case SSH:
|
|
||||||
try (DataOutputStreamHelper dosh = new DataOutputStreamHelper()) {
|
|
||||||
getSSHPubKeyBytes(this.key)
|
|
||||||
.forEach(handleExceptionWrapper(item -> {
|
|
||||||
dosh.writeInt(item.length);
|
|
||||||
dosh.write(item);
|
|
||||||
}));
|
|
||||||
data = String.format("ssh-rsa %s %s", dosh.base64Encoded(), this.description);
|
|
||||||
IOUtils.writeStringToFile(fileName, data);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
writePem(fileName);
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new IllegalArgumentException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDescription(String description) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
if (Utils.isEmptyString(this.description)) {
|
|
||||||
return this.key instanceof PrivateKey ? "PRIVATE KEY" : "PUBLIC KEY";
|
|
||||||
}
|
|
||||||
return this.description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Key getKey() {
|
|
||||||
return this.key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
try {
|
|
||||||
if (this.writer != null) {
|
|
||||||
this.writer.flush();
|
|
||||||
this.writer.close();
|
|
||||||
this.writer = null;
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static KeyFile read(String fileName) {
|
|
||||||
try (KeyFile kf = new KeyFile()) {
|
|
||||||
kf.loadFromFile(fileName);
|
|
||||||
return kf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writePem(String fileName) {
|
|
||||||
try {
|
|
||||||
String desc = getDescription();
|
|
||||||
this.writer = new OutputStreamWriter(new FileOutputStream(fileName), Charsets.UTF_8);
|
|
||||||
this.writer.write(String.format("-----BEGIN RSA %s-----", desc));
|
|
||||||
|
|
||||||
String encoded = Base64.getEncoder().encodeToString(this.key.getEncoded());
|
|
||||||
String out = join("\n", fixedLengthSplit(60).split(encoded));
|
|
||||||
|
|
||||||
this.writer.write(out);
|
|
||||||
this.writer.write(String.format("-----END RSA %s-----", desc));
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<byte[]> getSSHPubKeyBytes(Key key) {
|
|
||||||
RSAPublicKey rpk = (RSAPublicKey) key;
|
|
||||||
return Arrays.asList("ssh-rsa".getBytes(Charsets.UTF_8),
|
|
||||||
rpk.getPublicExponent().toByteArray(),
|
|
||||||
rpk.getModulus().toByteArray()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class KeySpecHelper {
|
|
||||||
private final KeySpec keySpec;
|
|
||||||
private final boolean isPrivate;
|
|
||||||
private final EncryptionType encryptionType;
|
|
||||||
|
|
||||||
public KeySpecHelper(KeySpec keySpec, boolean isPrivate, EncryptionType encryptionType) {
|
|
||||||
super();
|
|
||||||
this.keySpec = keySpec;
|
|
||||||
this.isPrivate = isPrivate;
|
|
||||||
this.encryptionType = encryptionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized final KeySpec getKeySpec() {
|
|
||||||
return keySpec;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized final boolean isPrivate() {
|
|
||||||
return isPrivate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized final EncryptionType getEncryptionType() {
|
|
||||||
return encryptionType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
package net.locusworks.common.crypto;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.security.Key;
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.KeyPairGenerator;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.security.interfaces.RSAKey;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.CipherInputStream;
|
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
|
||||||
|
|
||||||
import net.locusworks.common.Charsets;
|
|
||||||
import net.locusworks.common.crypto.KeyFile.EncryptionType;
|
|
||||||
import net.locusworks.common.io.IOUtils;
|
|
||||||
|
|
||||||
public class RSA {
|
|
||||||
|
|
||||||
private static final String ENCRYPTION_TYPE = "RSA";
|
|
||||||
private static final String ENCRYPTION_ALGORITHM = "RSA/ECB/PKCS1PADDING";
|
|
||||||
private static final String PROVIDER = "SunJCE";
|
|
||||||
private static final String RANDOM_ALGORITHM = "SHA1PRNG";
|
|
||||||
|
|
||||||
private static final int PADDING_LENGTH = 11;
|
|
||||||
private static final int DEFAULT_KEY_LENGTH = 2048;
|
|
||||||
|
|
||||||
public static KeyPair generateKeyPair() {
|
|
||||||
return generateKeyPair(DEFAULT_KEY_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static KeyPair generateKeyPair(int keyLength) {
|
|
||||||
try {
|
|
||||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance(ENCRYPTION_TYPE);
|
|
||||||
SecureRandom sr = SecureRandom.getInstance(RANDOM_ALGORITHM);
|
|
||||||
kpg.initialize(keyLength, sr);
|
|
||||||
return kpg.genKeyPair();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static KeyPair loadPrivateKey(String privateKeyFileName) {
|
|
||||||
return loadKeyPair(null, privateKeyFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static KeyPair loadPublicKey(String publicKeyFileName) {
|
|
||||||
return loadKeyPair(publicKeyFileName, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static KeyPair loadKeyPair(String publicKey, String privateKey) {
|
|
||||||
KeyFile pubKey = KeyFile.read(publicKey);
|
|
||||||
KeyFile prvKey = KeyFile.read(privateKey);
|
|
||||||
return new KeyPair((PublicKey) pubKey.getKey(), (PrivateKey) prvKey.getKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean generateAndWriteSSHKeys() {
|
|
||||||
KeyPair kp = generateKeyPair();
|
|
||||||
return writePrivateKey(kp) && writePublicKey(kp, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean generateAndWriteKeyPair() {
|
|
||||||
return generateAndWriteKeyPair(DEFAULT_KEY_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean generateAndWriteKeyPair(String keyPairName) {
|
|
||||||
return generateAndWriteKeyPair(keyPairName, DEFAULT_KEY_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean generateAndWriteKeyPair(int keyLength) {
|
|
||||||
return generateAndWriteKeyPair("id_rsa", keyLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean generateAndWriteKeyPair(String keyPairName, int keyLength) {
|
|
||||||
KeyPair kp = generateKeyPair(keyLength);
|
|
||||||
return writePrivateKey(kp, keyPairName, "PRIVATE KEY") && writePublicKey(kp, keyPairName + ".pub", "PUBLIC KEY");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean writePrivateKey(KeyPair kp) {
|
|
||||||
return writePrivateKey(kp, "id_rsa", "PRIVATE KEY");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean writePrivateKey(KeyPair kp, String fileName, String description) {
|
|
||||||
return writePemFile(kp.getPrivate(), fileName, description);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean writePublicKey(KeyPair kp) {
|
|
||||||
return writePublicKey(kp, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean writePublicKey(KeyPair kp, boolean sshFormat) {
|
|
||||||
return writePublicKey(kp, "id_rsa.pub", "PUBLIC KEY", sshFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean writePublicKey(KeyPair kp, String fileName, String description) {
|
|
||||||
return writePemFile(kp.getPublic(), fileName, description, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean writePublicKey(KeyPair kp, String fileName, String description, boolean sshFormat) {
|
|
||||||
return writePemFile(kp.getPublic(), fileName, description, sshFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int calculateRequiredKeyLength(String message) {
|
|
||||||
return (message.getBytes(Charsets.UTF_8).length + PADDING_LENGTH) * 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String encrypt(Key key, String message) {
|
|
||||||
try {
|
|
||||||
calculateKeyLength(key, message);
|
|
||||||
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM, PROVIDER);
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
|
||||||
CipherInputStream cis = new CipherInputStream(new ByteArrayInputStream(message.getBytes(Charsets.UTF_8)), cipher);
|
|
||||||
byte[] encrypted = IOUtils.toByteArray(cis);
|
|
||||||
return Base64.getEncoder().encodeToString(encrypted);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String decrypt(Key key, String message) {
|
|
||||||
try {
|
|
||||||
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM, PROVIDER);
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, key);
|
|
||||||
byte[] decoded = Base64.getDecoder().decode(message);
|
|
||||||
byte[] plainTextArray = cipher.doFinal(decoded);
|
|
||||||
return new String(plainTextArray, Charsets.UTF_8);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean writePemFile(Key key, String fileName, String description) {
|
|
||||||
return writePemFile(key, fileName, description, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean writePemFile(Key key, String fileName, String description, boolean sshFormat) {
|
|
||||||
try (KeyFile kf = sshFormat ? new KeyFile(key, description, EncryptionType.SSH) : new KeyFile(key, description)) {
|
|
||||||
kf.write(fileName);
|
|
||||||
}
|
|
||||||
return Files.exists(Paths.get(fileName));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void calculateKeyLength(Key key, String message) throws IllegalBlockSizeException {
|
|
||||||
int keyLength = ((RSAKey) key).getModulus().bitLength();
|
|
||||||
int requiredKeyLength = calculateRequiredKeyLength(message);
|
|
||||||
if (keyLength < requiredKeyLength) {
|
|
||||||
throw new IllegalBlockSizeException(String.format("RSA key size of %d is not large enough to encrypt message of length %d. "
|
|
||||||
+ "Increase key size to a minimum of %d and re-encrypt with new key", keyLength, message.length(), requiredKeyLength));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
package net.locusworks.common.crypto;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.spec.EncodedKeySpec;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import java.security.spec.RSAPublicKeySpec;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
import net.locusworks.common.Charsets;
|
|
||||||
import net.locusworks.common.io.IOUtils;
|
|
||||||
|
|
||||||
import static net.locusworks.common.utils.Checks.checkArguments;
|
|
||||||
import static net.locusworks.common.utils.Utils.get;
|
|
||||||
import static net.locusworks.common.utils.Utils.size;
|
|
||||||
|
|
||||||
public class SSHEncodedKeySpec extends EncodedKeySpec {
|
|
||||||
|
|
||||||
private static final String SSH_MARKER = "ssh-rsa";
|
|
||||||
|
|
||||||
public SSHEncodedKeySpec(byte[] encodedKey) {
|
|
||||||
super(encodedKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RSAPublicKeySpec convertToRSAPubKeySpec() throws InvalidKeySpecException {
|
|
||||||
try {
|
|
||||||
byte[] data = this.getEncoded();
|
|
||||||
InputStream stream = new ByteArrayInputStream(data);
|
|
||||||
Iterable<String> parts = Arrays.asList(IOUtils.toString(stream, Charsets.UTF_8).split(" "));
|
|
||||||
|
|
||||||
checkArguments(size(parts) >= 2 && SSH_MARKER.equals(get(parts, 0)), "Bad format, should be: ssh-rsa AAB3...");
|
|
||||||
stream = new ByteArrayInputStream(Base64.getDecoder().decode(String.valueOf(get(parts, 1))));
|
|
||||||
String marker = new String(readLengthFirst(stream));
|
|
||||||
checkArguments(SSH_MARKER.equals(marker), "Looking for marker %s but received %s", SSH_MARKER, marker);
|
|
||||||
BigInteger publicExponent = new BigInteger(readLengthFirst(stream));
|
|
||||||
BigInteger modulus = new BigInteger(readLengthFirst(stream));
|
|
||||||
return new RSAPublicKeySpec(modulus, publicExponent);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new InvalidKeySpecException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFormat() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] readLengthFirst(InputStream in) throws IOException {
|
|
||||||
int[] bytes = new int[]{in.read(), in.read(), in.read(), in.read()};
|
|
||||||
int length = 0;
|
|
||||||
int shift = 24;
|
|
||||||
for (int aByte : bytes) {
|
|
||||||
length += aByte << shift;
|
|
||||||
shift -= 8;
|
|
||||||
}
|
|
||||||
byte[] val = new byte[length];
|
|
||||||
in.read(val);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
/**
|
|
||||||
* Package contains classes that help encrypting, decrypting, salting and hashing objects
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
*/
|
|
||||||
package net.locusworks.common.crypto;
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
package net.locusworks.common.exceptions;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Custom exception class for the patch repository
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ApplicationException extends Exception {
|
|
||||||
private final Integer code;
|
|
||||||
boolean success = false;
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public static ApplicationException egregiousServer() {
|
|
||||||
return new ApplicationException(9001, "Something went wrong. Please see logs for details");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException invalidCreds() {
|
|
||||||
return new ApplicationException(9001, "Invalid credentials provided");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException notLoggedIn() {
|
|
||||||
return new ApplicationException(9002, "Not logged in");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException invalidEmailAddress() {
|
|
||||||
return new ApplicationException(9005, "Invalid email address");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException actionNotPermitted() {
|
|
||||||
return new ApplicationException(9007, "Action not permitted");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException actionNotPermitted(String message) {
|
|
||||||
return new ApplicationException(9007, "Action not permitted: " + message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException passwordsNotEqual() {
|
|
||||||
return new ApplicationException(9008, "Passwords do not match");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException unAuthorized() {
|
|
||||||
return new ApplicationException(9009, "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException duplicateEntry(String message) {
|
|
||||||
return new ApplicationException(9100, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException duplicateEntry(String messageFmt, Object... args) {
|
|
||||||
return new ApplicationException(9100, String.format(messageFmt, args));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException noEntryExists(String message) {
|
|
||||||
return new ApplicationException(9101, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException noEntryExists(String messageFmt, Object... items) {
|
|
||||||
return new ApplicationException(9101, String.format(messageFmt, items));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException constraintViolation(String message) {
|
|
||||||
return new ApplicationException(9102, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException constraintViolation(String messageFmt, Object... items) {
|
|
||||||
return new ApplicationException(9102, String.format(messageFmt, items));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException illegalArgument(String message) {
|
|
||||||
return new ApplicationException(9103, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException generic(String message) {
|
|
||||||
return new ApplicationException(9999, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApplicationException fromException(Throwable e) {
|
|
||||||
return new ApplicationException(9999, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApplicationException(int code, Throwable e) {
|
|
||||||
this(code, e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApplicationException(int code, String message) {
|
|
||||||
super(message);
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApplicationException(int code, String message, Throwable e) {
|
|
||||||
super(message, e);
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getSuccess() {
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
return super.getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
package net.locusworks.common.immutables;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class that holds two immutable objects as a pair
|
|
||||||
*
|
|
||||||
* @param <V1> class type of object 1
|
|
||||||
* @param <V2> class type of object 2
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
*/
|
|
||||||
public class Pair<V1, V2> extends Unit<V1> {
|
|
||||||
|
|
||||||
private V2 value2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor with no values
|
|
||||||
*/
|
|
||||||
public Pair() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param value1 Object 1
|
|
||||||
* @param value2 Object 2
|
|
||||||
*/
|
|
||||||
public Pair(V1 value1, V2 value2) {
|
|
||||||
super(value1);
|
|
||||||
this.value2 = value2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set value2
|
|
||||||
*
|
|
||||||
* @param value2 value to set it
|
|
||||||
*/
|
|
||||||
public void setValue2(V2 value2) {
|
|
||||||
if (Objects.nonNull(this.value2)) {
|
|
||||||
throw new IllegalArgumentException("Value2 already set. Cannot change");
|
|
||||||
}
|
|
||||||
this.value2 = value2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get value2
|
|
||||||
*
|
|
||||||
* @return value2
|
|
||||||
*/
|
|
||||||
public V2 getValue2() {
|
|
||||||
return this.value2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object other) {
|
|
||||||
if (other == null) return false;
|
|
||||||
if (!(other instanceof Pair<?, ?> pair)) return false;
|
|
||||||
|
|
||||||
return this.getValue2().equals(pair.getValue2()) &&
|
|
||||||
this.getValue1().equals(pair.getValue1());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
package net.locusworks.common.immutables;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class that holds three immutable objects as triplets
|
|
||||||
*
|
|
||||||
* @param <V1> class type of object 1
|
|
||||||
* @param <V2> class type of object 2
|
|
||||||
* @param <V3> class type of object 3
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
*/
|
|
||||||
public class Triplet<V1, V2, V3> extends Pair<V1, V2> {
|
|
||||||
|
|
||||||
private V3 value3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* default constructor with no values
|
|
||||||
*/
|
|
||||||
public Triplet() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param value1 Object 1
|
|
||||||
* @param value2 Object 2
|
|
||||||
* @param value3 Object 3
|
|
||||||
*/
|
|
||||||
public Triplet(V1 value1, V2 value2, V3 value3) {
|
|
||||||
super(value1, value2);
|
|
||||||
this.value3 = value3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set value 3
|
|
||||||
*
|
|
||||||
* @param value3 value 3
|
|
||||||
*/
|
|
||||||
public void setValue3(V3 value3) {
|
|
||||||
if (Objects.nonNull(this.value3)) {
|
|
||||||
throw new IllegalArgumentException("Value3 already set. Cannot change");
|
|
||||||
}
|
|
||||||
this.value3 = value3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get value 3
|
|
||||||
*
|
|
||||||
* @return value 3
|
|
||||||
*/
|
|
||||||
public V3 getValue3() {
|
|
||||||
return value3;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object other) {
|
|
||||||
if (other == null) return false;
|
|
||||||
if (!(other instanceof Triplet<?, ?, ?> triplet)) return false;
|
|
||||||
|
|
||||||
return this.getValue3().equals(triplet.getValue3()) &&
|
|
||||||
this.getValue2().equals(triplet.getValue2()) &&
|
|
||||||
this.getValue1().equals(triplet.getValue1());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
package net.locusworks.common.immutables;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class that holds three immutable objects as triplets
|
|
||||||
*
|
|
||||||
* @param <V1> class type of object 1
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
*/
|
|
||||||
public class Unit<V1> {
|
|
||||||
|
|
||||||
private V1 value1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor with no values
|
|
||||||
*/
|
|
||||||
public Unit() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param value1 value 1
|
|
||||||
*/
|
|
||||||
public Unit(V1 value1) {
|
|
||||||
this.value1 = value1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set value 1
|
|
||||||
*
|
|
||||||
* @param value1 value 1
|
|
||||||
*/
|
|
||||||
public void setValue1(V1 value1) {
|
|
||||||
if (Objects.nonNull(this.value1)) {
|
|
||||||
throw new IllegalArgumentException("Value1 already set. Cannot change");
|
|
||||||
}
|
|
||||||
this.value1 = value1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get value 1
|
|
||||||
*
|
|
||||||
* @return value1
|
|
||||||
*/
|
|
||||||
public V1 getValue1() {
|
|
||||||
return value1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object other) {
|
|
||||||
if (other == null) return false;
|
|
||||||
if (!(other instanceof Unit<?>)) return false;
|
|
||||||
return this.getValue1().equals(((Unit<?>) other).getValue1());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package net.locusworks.common.interfaces;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
public interface AutoCloseableIterator<T> extends Iterator<T>, AutoCloseable {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void close();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
package net.locusworks.common.interfaces;
|
|
||||||
|
|
||||||
public interface PersistableRequest {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package net.locusworks.common.interfaces;
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface ThrowingConsumer<T, E extends Exception> {
|
|
||||||
void accept(T t) throws E;
|
|
||||||
}
|
|
||||||
@@ -1,359 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package net.locusworks.common.io;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import net.locusworks.common.Charsets;
|
|
||||||
|
|
||||||
public class IOUtils {
|
|
||||||
|
|
||||||
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
|
|
||||||
public static final int EOF = -1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the contents of an <code>InputStream</code> as a list of Strings,
|
|
||||||
* one entry per line, using the specified character encoding.
|
|
||||||
* <p>
|
|
||||||
* This method buffers the input internally, so there is no need to use a
|
|
||||||
* <code>BufferedInputStream</code>.
|
|
||||||
*
|
|
||||||
* @param stream the <code>InputStream</code> to read from, not null
|
|
||||||
* @param charset the encoding to use, null means platform default
|
|
||||||
* @return the list of Strings, never null
|
|
||||||
* @throws NullPointerException if the input is null
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
public static List<String> readLines(final InputStream stream, final Charset charset) throws IOException {
|
|
||||||
final InputStreamReader reader = new InputStreamReader(stream, charset);
|
|
||||||
return readLines(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the contents of a <code>Reader</code> as a list of Strings,
|
|
||||||
* one entry per line.
|
|
||||||
* <p>
|
|
||||||
* This method buffers the input internally, so there is no need to use a
|
|
||||||
* <code>BufferedReader</code>.
|
|
||||||
*
|
|
||||||
* @param input the <code>Reader</code> to read from, not null
|
|
||||||
* @return the list of Strings, never null
|
|
||||||
* @throws NullPointerException if the input is null
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
public static List<String> readLines(final Reader input) throws IOException {
|
|
||||||
final BufferedReader reader = toBufferedReader(input);
|
|
||||||
final List<String> list = new ArrayList<>();
|
|
||||||
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
|
|
||||||
list.add(line);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the given reader if it is a {@link BufferedReader}, otherwise creates a BufferedReader from the given
|
|
||||||
* reader.
|
|
||||||
*
|
|
||||||
* @param reader the reader to wrap or return (not null)
|
|
||||||
* @return the given reader or a new {@link BufferedReader} for the given reader
|
|
||||||
* @throws NullPointerException if the input parameter is null
|
|
||||||
* @see #buffer(Reader)
|
|
||||||
*/
|
|
||||||
public static BufferedReader toBufferedReader(final Reader reader) {
|
|
||||||
return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the contents of an <code>InputStream</code> as a <code>byte[]</code>.
|
|
||||||
* <p>
|
|
||||||
* This method buffers the input internally, so there is no need to use a
|
|
||||||
* <code>BufferedInputStream</code>.
|
|
||||||
*
|
|
||||||
* @param input the <code>InputStream</code> to read from
|
|
||||||
* @return the requested byte array
|
|
||||||
* @throws NullPointerException if the input is null
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
public static byte[] toByteArray(final InputStream input) throws IOException {
|
|
||||||
try (final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
|
||||||
copy(input, output);
|
|
||||||
return output.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies bytes from an <code>InputStream</code> to an
|
|
||||||
* <code>OutputStream</code>.
|
|
||||||
* <p>
|
|
||||||
* This method buffers the input internally, so there is no need to use a
|
|
||||||
* <code>BufferedInputStream</code>.
|
|
||||||
* <p>
|
|
||||||
* Large streams (over 2GB) will return a bytes copied value of
|
|
||||||
* <code>-1</code> after the copy has completed since the correct
|
|
||||||
* number of bytes cannot be returned as an int. For large streams
|
|
||||||
* use the <code>copyLarge(InputStream, OutputStream)</code> method.
|
|
||||||
*
|
|
||||||
* @param input the <code>InputStream</code> to read from
|
|
||||||
* @param output the <code>OutputStream</code> to write to
|
|
||||||
* @return the number of bytes copied, or -1 if > Integer.MAX_VALUE
|
|
||||||
* @throws NullPointerException if the input or output is null
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
public static int copy(final InputStream input, final OutputStream output) throws IOException {
|
|
||||||
final long count = copyLarge(input, output);
|
|
||||||
if (count > Integer.MAX_VALUE) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return (int) count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies bytes from an <code>InputStream</code> to an <code>OutputStream</code> using an internal buffer of the
|
|
||||||
* given size.
|
|
||||||
* <p>
|
|
||||||
* This method buffers the input internally, so there is no need to use a <code>BufferedInputStream</code>.
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* @param input the <code>InputStream</code> to read from
|
|
||||||
* @param output the <code>OutputStream</code> to write to
|
|
||||||
* @param bufferSize the bufferSize used to copy from the input to the output
|
|
||||||
* @return the number of bytes copied
|
|
||||||
* @throws NullPointerException if the input or output is null
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
public static long copy(final InputStream input, final OutputStream output, final int bufferSize)
|
|
||||||
throws IOException {
|
|
||||||
return copyLarge(input, output, new byte[bufferSize]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies bytes from an <code>InputStream</code> to chars on a
|
|
||||||
* <code>Writer</code> using the specified character encoding.
|
|
||||||
* <p>
|
|
||||||
* This method buffers the input internally, so there is no need to use a
|
|
||||||
* <code>BufferedInputStream</code>.
|
|
||||||
* <p>
|
|
||||||
* This method uses {@link InputStreamReader}.
|
|
||||||
*
|
|
||||||
* @param input the <code>InputStream</code> to read from
|
|
||||||
* @param output the <code>Writer</code> to write to
|
|
||||||
* @param inputEncoding the encoding to use for the input stream, null means platform default
|
|
||||||
* @throws NullPointerException if the input or output is null
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
public static void copy(final InputStream input, final Writer output, final Charset inputEncoding)
|
|
||||||
throws IOException {
|
|
||||||
final InputStreamReader in = new InputStreamReader(input, inputEncoding);
|
|
||||||
copy(in, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies chars from a <code>Reader</code> to a <code>Writer</code>.
|
|
||||||
* <p>
|
|
||||||
* This method buffers the input internally, so there is no need to use a
|
|
||||||
* <code>BufferedReader</code>.
|
|
||||||
* <p>
|
|
||||||
* Large streams (over 2GB) will return a chars copied value of
|
|
||||||
* <code>-1</code> after the copy has completed since the correct
|
|
||||||
* number of chars cannot be returned as an int. For large streams
|
|
||||||
* use the <code>copyLarge(Reader, Writer)</code> method.
|
|
||||||
*
|
|
||||||
* @param input the <code>Reader</code> to read from
|
|
||||||
* @param output the <code>Writer</code> to write to
|
|
||||||
* @return the number of characters copied, or -1 if > Integer.MAX_VALUE
|
|
||||||
* @throws NullPointerException if the input or output is null
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
public static int copy(final Reader input, final Writer output) throws IOException {
|
|
||||||
final long count = copyLarge(input, output);
|
|
||||||
if (count > Integer.MAX_VALUE) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return (int) count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
|
|
||||||
* <p>
|
|
||||||
* This method buffers the input internally, so there is no need to use a
|
|
||||||
* <code>BufferedReader</code>.
|
|
||||||
* <p>
|
|
||||||
* The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}.
|
|
||||||
*
|
|
||||||
* @param input the <code>Reader</code> to read from
|
|
||||||
* @param output the <code>Writer</code> to write to
|
|
||||||
* @return the number of characters copied
|
|
||||||
* @throws NullPointerException if the input or output is null
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
public static long copyLarge(final Reader input, final Writer output) throws IOException {
|
|
||||||
return copyLarge(input, output, new char[DEFAULT_BUFFER_SIZE]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies bytes from a large (over 2GB) <code>InputStream</code> to an
|
|
||||||
* <code>OutputStream</code>.
|
|
||||||
* <p>
|
|
||||||
* This method buffers the input internally, so there is no need to use a
|
|
||||||
* <code>BufferedInputStream</code>.
|
|
||||||
* <p>
|
|
||||||
* The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}.
|
|
||||||
*
|
|
||||||
* @param input the <code>InputStream</code> to read from
|
|
||||||
* @param output the <code>OutputStream</code> to write to
|
|
||||||
* @return the number of bytes copied
|
|
||||||
* @throws NullPointerException if the input or output is null
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
public static long copyLarge(final InputStream input, final OutputStream output)
|
|
||||||
throws IOException {
|
|
||||||
return copy(input, output, DEFAULT_BUFFER_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies bytes from a large (over 2GB) <code>InputStream</code> to an
|
|
||||||
* <code>OutputStream</code>.
|
|
||||||
* <p>
|
|
||||||
* This method uses the provided buffer, so there is no need to use a
|
|
||||||
* <code>BufferedInputStream</code>.
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* @param input the <code>InputStream</code> to read from
|
|
||||||
* @param output the <code>OutputStream</code> to write to
|
|
||||||
* @param buffer the buffer to use for the copy
|
|
||||||
* @return the number of bytes copied
|
|
||||||
* @throws NullPointerException if the input or output is null
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
public static long copyLarge(final InputStream input, final OutputStream output, final byte[] buffer)
|
|
||||||
throws IOException {
|
|
||||||
long count = 0;
|
|
||||||
int n;
|
|
||||||
while (EOF != (n = input.read(buffer))) {
|
|
||||||
output.write(buffer, 0, n);
|
|
||||||
count += n;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
|
|
||||||
* <p>
|
|
||||||
* This method uses the provided buffer, so there is no need to use a
|
|
||||||
* <code>BufferedReader</code>.
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* @param input the <code>Reader</code> to read from
|
|
||||||
* @param output the <code>Writer</code> to write to
|
|
||||||
* @param buffer the buffer to be used for the copy
|
|
||||||
* @return the number of characters copied
|
|
||||||
* @throws NullPointerException if the input or output is null
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
public static long copyLarge(final Reader input, final Writer output, final char[] buffer) throws IOException {
|
|
||||||
long count = 0;
|
|
||||||
int n;
|
|
||||||
while (EOF != (n = input.read(buffer))) {
|
|
||||||
output.write(buffer, 0, n);
|
|
||||||
count += n;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the contents of an <code>InputStream</code> as a String
|
|
||||||
* using the specified character encoding.
|
|
||||||
* <p>
|
|
||||||
* This method buffers the input internally, so there is no need to use a
|
|
||||||
* <code>BufferedInputStream</code>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param input the <code>InputStream</code> to read from
|
|
||||||
* @param encoding the encoding to use, null means platform default
|
|
||||||
* @return the requested String
|
|
||||||
* @throws NullPointerException if the input is null
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
public static String toString(final InputStream input, final Charset encoding) throws IOException {
|
|
||||||
try (final StringWriter sw = new StringWriter()) {
|
|
||||||
copy(input, sw, encoding);
|
|
||||||
return sw.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeStringToFile(String fileName, String data) throws IOException {
|
|
||||||
writeStringToFile(Paths.get(fileName), data, Charsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void writeStringToFile(String fileName, String data, Charset charset) throws IOException {
|
|
||||||
writeStringToFile(Paths.get(fileName), data, charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeStringToFile(Path file, String data) throws IOException {
|
|
||||||
writeStringToFile(file, data, Charsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static void writeStringToFile(File file, String data, Charset charset) throws IOException {
|
|
||||||
writeStringToFile(file.toPath(), data, charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeStringToFile(Path file, String data, Charset charset) throws IOException {
|
|
||||||
try (Writer writer = Files.newBufferedWriter(file, charset)) {
|
|
||||||
writer.write(data);
|
|
||||||
writer.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteFile(String fileName) {
|
|
||||||
deleteFile(Paths.get(fileName));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static void deleteFile(File file) {
|
|
||||||
deleteFile(file.toPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteFile(Path file) {
|
|
||||||
try {
|
|
||||||
Files.deleteIfExists(file);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new IllegalArgumentException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteFiles(String... fileNames) {
|
|
||||||
Arrays.asList(fileNames).forEach(file -> deleteFile(file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package net.locusworks.common.migration;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public abstract class BaseMigrationManager {
|
|
||||||
|
|
||||||
protected List<MigrationItem> migrations = new ArrayList<>();
|
|
||||||
|
|
||||||
public abstract void migrate() throws Exception;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package net.locusworks.common.migration;
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface MigrationCallback {
|
|
||||||
void results(String msg);
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
package net.locusworks.common.migration;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.flywaydb.core.Flyway;
|
|
||||||
import org.flywaydb.core.api.MigrationInfo;
|
|
||||||
import org.flywaydb.core.internal.info.MigrationInfoDumper;
|
|
||||||
|
|
||||||
public class MigrationItem {
|
|
||||||
|
|
||||||
protected Flyway flyway = null;
|
|
||||||
protected MigrationInfo[] pendingMigrations;
|
|
||||||
protected MigrationInfo[] allMigrations;
|
|
||||||
private final MigrationCallback callback;
|
|
||||||
|
|
||||||
public MigrationItem(Flyway flyway, MigrationCallback callback) {
|
|
||||||
this.allMigrations = flyway.info().all();
|
|
||||||
this.pendingMigrations = flyway.info().pending();
|
|
||||||
this.flyway = flyway;
|
|
||||||
this.callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MigrationItem(Flyway flyway) {
|
|
||||||
this(flyway, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getSchemas() {
|
|
||||||
return flyway.getConfiguration().getSchemas();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int qtyPending() {
|
|
||||||
return pendingMigrations.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void repair() {
|
|
||||||
// no harm in calling migrate even if none pending, log will contain
|
|
||||||
// assurance that the migrations were verified
|
|
||||||
try {
|
|
||||||
String schemas = Arrays.toString(getSchemas()).replace("[", "").replace("]", "");
|
|
||||||
|
|
||||||
String status = String.format("Repair status for %s:%n%s", schemas, getAllMigrationsLog());
|
|
||||||
|
|
||||||
callback(status);
|
|
||||||
|
|
||||||
flyway.repair();
|
|
||||||
} catch (Exception e) {
|
|
||||||
String message = String.format("%nDatabase migration error:%n %s %nPortal webapp cannot continue.", e.getMessage());
|
|
||||||
throw new RuntimeException(message, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void migrate() {
|
|
||||||
// no harm in calling migrate even if none pending, log will contain
|
|
||||||
// assurance that the migrations were verified
|
|
||||||
try {
|
|
||||||
String schemas = Arrays.toString(getSchemas()).replace("[", "").replace("]", "");
|
|
||||||
String status = String.format("Repair status for %s:%n%s", schemas, getAllMigrationsLog());
|
|
||||||
callback(status);
|
|
||||||
flyway.migrate();
|
|
||||||
} catch (Exception e) {
|
|
||||||
String message = String.format("%nDatabase migration error:%n %s %nPortal webapp cannot continue.", e.getMessage());
|
|
||||||
throw new RuntimeException(message, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAllMigrationsLog() {
|
|
||||||
return MigrationInfoDumper.dumpToAsciiTable(allMigrations);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void callback(String msg) {
|
|
||||||
if (this.callback != null) this.callback.results(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package net.locusworks.common.net;
|
|
||||||
|
|
||||||
|
|
||||||
import net.locusworks.common.net.ssl.SSLManager;
|
|
||||||
import org.apache.hc.client5.http.classic.HttpClient;
|
|
||||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
|
||||||
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
|
||||||
import org.apache.hc.core5.http.HttpEntity;
|
|
||||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
|
||||||
|
|
||||||
public class HttpClientHelper {
|
|
||||||
|
|
||||||
public enum HttpSchema {
|
|
||||||
HTTP,
|
|
||||||
HTTPS;
|
|
||||||
|
|
||||||
public static HttpSchema findEnum(String value) {
|
|
||||||
for (HttpSchema schema : values()) {
|
|
||||||
if (value.equalsIgnoreCase(schema.toString())) {
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String[] TLS = new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"};
|
|
||||||
|
|
||||||
private final HttpClient client;
|
|
||||||
private final String baseUrl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor to handle http connection
|
|
||||||
*
|
|
||||||
* @param protocol protocol to use (http or https)
|
|
||||||
* @param host the host url
|
|
||||||
* @param port the host port
|
|
||||||
* @throws Exception exception
|
|
||||||
*/
|
|
||||||
public HttpClientHelper(String protocol, String host, String port) throws Exception {
|
|
||||||
HttpSchema schema = HttpSchema.findEnum(protocol);
|
|
||||||
if (schema == null) {
|
|
||||||
throw new Exception("Unable to find http schema of " + protocol);
|
|
||||||
}
|
|
||||||
this.baseUrl = String.format("%s://%s:%s", schema.toString().toLowerCase(), host, port);
|
|
||||||
this.client = createClient(schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpClient createClient(HttpSchema schema) throws Exception {
|
|
||||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
|
||||||
|
|
||||||
if (schema == HttpSchema.HTTP) {
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
return SSLManager.getTrustAllTLSClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the http GET response code
|
|
||||||
*
|
|
||||||
* @param endpoint endpoint to get the response from
|
|
||||||
* @return responseCode
|
|
||||||
* @throws Exception general exception
|
|
||||||
*/
|
|
||||||
public Integer getResponseCode(String endpoint) throws Exception {
|
|
||||||
String url = this.baseUrl + endpoint;
|
|
||||||
|
|
||||||
return this.client.execute(new HttpGet(url), response -> {
|
|
||||||
HttpEntity entity = response.getEntity();
|
|
||||||
int responseCode = response.getCode();
|
|
||||||
EntityUtils.consume(entity);
|
|
||||||
return responseCode;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package net.locusworks.common.net.certmanagers;
|
|
||||||
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
|
||||||
|
|
||||||
public class TrustAllCertsManager implements X509TrustManager {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void checkClientTrusted(X509Certificate[] arg0, String arg1) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void checkServerTrusted(X509Certificate[] arg0, String arg1) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public X509Certificate[] getAcceptedIssuers() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TrustManager[] trustAllCerts() {
|
|
||||||
return new TrustManager[]{new TrustAllCertsManager()};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package net.locusworks.common.net.hostverifiers;
|
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
|
||||||
import javax.net.ssl.SSLSession;
|
|
||||||
|
|
||||||
public class AllHostValidVerifier implements HostnameVerifier {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean verify(String arg0, SSLSession arg1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package net.locusworks.common.net.ssl;
|
|
||||||
|
|
||||||
import java.security.KeyManagementException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
|
|
||||||
|
|
||||||
import net.locusworks.common.net.certmanagers.TrustAllCertsManager;
|
|
||||||
import org.apache.hc.client5.http.classic.HttpClient;
|
|
||||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
|
||||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
|
||||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
|
||||||
import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
|
|
||||||
import org.apache.hc.client5.http.ssl.TlsSocketStrategy;
|
|
||||||
|
|
||||||
public class SSLManager {
|
|
||||||
|
|
||||||
public static final String[] TLS = new String[] {"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
|
|
||||||
|
|
||||||
public static HttpClient getTrustAllTLSClient() throws NoSuchAlgorithmException, KeyManagementException {
|
|
||||||
TrustManager[] trustAllCerts = new TrustManager[]{new TrustAllCertsManager()};
|
|
||||||
//Setup the ssl instance using tls
|
|
||||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
|
||||||
sslContext.init(null, trustAllCerts, new SecureRandom());
|
|
||||||
TlsSocketStrategy tlsStrategy = new DefaultClientTlsStrategy(sslContext);
|
|
||||||
|
|
||||||
HttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
|
|
||||||
.setTlsSocketStrategy(tlsStrategy)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
return HttpClients.custom()
|
|
||||||
.setConnectionManager(connectionManager)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private SSLManager() { }
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package net.locusworks.common.objectmapper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error handler for the object mapper class
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
* @date 02/15/2018
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public interface ObjectMapperError {
|
|
||||||
void getError(Throwable e);
|
|
||||||
}
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
package net.locusworks.common.objectmapper;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
|
||||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Object mapper to map to convert objects to json string or
|
|
||||||
* json string back to object
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
* @date 02/15/2018
|
|
||||||
*/
|
|
||||||
public class ObjectMapperHelper {
|
|
||||||
|
|
||||||
private static final ObjectMapper mapper;
|
|
||||||
|
|
||||||
static {
|
|
||||||
mapper = new ObjectMapper();
|
|
||||||
mapper.setDefaultPropertyInclusion(Include.NON_NULL);
|
|
||||||
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write an object out to json
|
|
||||||
*
|
|
||||||
* @param object Object to convert to json
|
|
||||||
* @return return a string representation of the object converted to json
|
|
||||||
*/
|
|
||||||
public static ObjectMapperResults<String> writeValue(Object object) {
|
|
||||||
String results = "";
|
|
||||||
try {
|
|
||||||
results = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
try {
|
|
||||||
GsonBuilder gsonBuilder = new GsonBuilder();
|
|
||||||
gsonBuilder.setPrettyPrinting();
|
|
||||||
Gson gson = gsonBuilder.create();
|
|
||||||
results = gson.toJson(object);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
return new ObjectMapperResults<>(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new ObjectMapperResults<>(results);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert binary data to an object
|
|
||||||
*
|
|
||||||
* @param src Binary data to convert
|
|
||||||
* @param clazz Class to convert the data to
|
|
||||||
* @param <T> The expected class of the value
|
|
||||||
* @return the object populated with the data in the json string
|
|
||||||
*/
|
|
||||||
public static <T> ObjectMapperResults<T> readValue(byte[] src, Class<T> clazz) {
|
|
||||||
try {
|
|
||||||
return new ObjectMapperResults<T>(mapper.readValue(src, clazz));
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return new ObjectMapperResults<T>(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a json string to an object
|
|
||||||
*
|
|
||||||
* @param src Json String
|
|
||||||
* @param clazz Class to convert the json string to
|
|
||||||
* @param <T> The expected class of the value
|
|
||||||
* @return the object populated with the data in the json string
|
|
||||||
*/
|
|
||||||
public static <T> ObjectMapperResults<T> readValue(String src, Class<T> clazz) {
|
|
||||||
try {
|
|
||||||
return new ObjectMapperResults<T>(mapper.readValue(src, clazz));
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return new ObjectMapperResults<T>(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an java object to a class
|
|
||||||
*
|
|
||||||
* @param src Object to convert
|
|
||||||
* @param clazz Class to convert the object to
|
|
||||||
* @param <T> The expected class of the value
|
|
||||||
* @return the object populated with the data in the json string
|
|
||||||
*/
|
|
||||||
public static <T> ObjectMapperResults<T> readValue(Object src, Class<T> clazz) {
|
|
||||||
try {
|
|
||||||
if (src instanceof String) {
|
|
||||||
return readValue((String) src, clazz);
|
|
||||||
}
|
|
||||||
return readValue(mapper.writeValueAsString(src), clazz);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return new ObjectMapperResults<T>(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an object to a list
|
|
||||||
*
|
|
||||||
* @param object Object to convert
|
|
||||||
* @param objectClass Class to convert the object to
|
|
||||||
* @param <T> The expected class of the object
|
|
||||||
* @return the object list populated with the data in the json string
|
|
||||||
*/
|
|
||||||
public static <T, L extends Collection<?>> ObjectMapperListResults<List<T>> readListValue(Object object, Class<T> objectClass) {
|
|
||||||
return readListValue(object, objectClass, ArrayList.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an object to a list
|
|
||||||
*
|
|
||||||
* @param object Object to convert
|
|
||||||
* @param objectClass Class to convert the object to
|
|
||||||
* @param listClass List type to make
|
|
||||||
* @param <T> The expected class of the object
|
|
||||||
* @param <L> The expect class of the list
|
|
||||||
* @return the object list populated with the data in the json string
|
|
||||||
*/
|
|
||||||
public static <T, L extends Collection<?>> ObjectMapperListResults<List<T>> readListValue(Object object, Class<T> objectClass, Class<L> listClass) {
|
|
||||||
try {
|
|
||||||
if (object instanceof String) {
|
|
||||||
return readListValue((String) object, objectClass, listClass);
|
|
||||||
}
|
|
||||||
return readListValue(mapper.writeValueAsString(object), objectClass, listClass);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return new ObjectMapperListResults<>(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an object to a list
|
|
||||||
*
|
|
||||||
* @param src Source to convert
|
|
||||||
* @param objectClass Class to convert the object to
|
|
||||||
* @param listClass List type to make
|
|
||||||
* @param <T> The expected class of the object
|
|
||||||
* @param <L> The expect class of the list
|
|
||||||
* @return the object list populated with the data in the json string
|
|
||||||
*/
|
|
||||||
public static <T, L extends Collection<?>> ObjectMapperListResults<List<T>> readListValue(String src, Class<T> objectClass, Class<L> listClass) {
|
|
||||||
try {
|
|
||||||
List<T> item = mapper.readValue(src, mapper.getTypeFactory().constructCollectionType(listClass, objectClass));
|
|
||||||
return new ObjectMapperListResults<>(item);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return new ObjectMapperListResults<>(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
package net.locusworks.common.objectmapper;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds the results from the object mapper list conversion
|
|
||||||
*
|
|
||||||
* @param <T> class type of the object mapper
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
* @date 02/15/2018
|
|
||||||
*/
|
|
||||||
public class ObjectMapperListResults<T extends Collection<?>> extends ObjectMapperResults<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param results results from the conversion
|
|
||||||
*/
|
|
||||||
public ObjectMapperListResults(T results) {
|
|
||||||
this(results, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param exception exception that was thrown during conversion
|
|
||||||
*/
|
|
||||||
public ObjectMapperListResults(Throwable exception) {
|
|
||||||
this(null, exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param results results from the conversion
|
|
||||||
* @param exception exception that was thrown during conversion
|
|
||||||
*/
|
|
||||||
public ObjectMapperListResults(T results, Throwable exception) {
|
|
||||||
super(results, exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the error handler to the results to retrieve the error that caused
|
|
||||||
* the exception
|
|
||||||
*
|
|
||||||
* @param error the error handler to use
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public ObjectMapperListResults<T> withErrorHandler(ObjectMapperError error) {
|
|
||||||
if (this.hasError() && error != null) {
|
|
||||||
error.getError(this.getException());
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
package net.locusworks.common.objectmapper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds the results from the object mapper list conversion
|
|
||||||
*
|
|
||||||
* @param <T> class type of the object being converted from json to object
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
* @date 02/15/2018
|
|
||||||
*/
|
|
||||||
public class ObjectMapperResults<T> {
|
|
||||||
|
|
||||||
private Throwable exception;
|
|
||||||
private T results;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param results results from the conversion
|
|
||||||
*/
|
|
||||||
public ObjectMapperResults(T results) {
|
|
||||||
this(results, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param exception exception that was thrown during conversion
|
|
||||||
*/
|
|
||||||
public ObjectMapperResults(Throwable exception) {
|
|
||||||
this(null, exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param results results from the conversion
|
|
||||||
* @param exception exception that was thrown during conversion
|
|
||||||
*/
|
|
||||||
public ObjectMapperResults(T results, Throwable exception) {
|
|
||||||
this.results = results;
|
|
||||||
this.exception = exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the exception that happened during conversion
|
|
||||||
*
|
|
||||||
* @return exception
|
|
||||||
*/
|
|
||||||
public Throwable getException() {
|
|
||||||
return exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the exception
|
|
||||||
*
|
|
||||||
* @param exception
|
|
||||||
*/
|
|
||||||
public void setException(Throwable exception) {
|
|
||||||
this.exception = exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the result
|
|
||||||
*
|
|
||||||
* @return the converted results
|
|
||||||
*/
|
|
||||||
public T getResults() {
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set the results
|
|
||||||
*
|
|
||||||
* @param results results to set
|
|
||||||
*/
|
|
||||||
public void setResults(T results) {
|
|
||||||
this.results = results;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check to see if the conversion caused an error
|
|
||||||
*
|
|
||||||
* @return true if there is an error, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean hasError() {
|
|
||||||
return this.exception != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the error handler to the results to retrieve the error that caused
|
|
||||||
* the exception
|
|
||||||
*
|
|
||||||
* @param error the error handler to use
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public ObjectMapperResults<T> withErrorHandler(ObjectMapperError error) {
|
|
||||||
if (this.hasError() && error != null) {
|
|
||||||
error.getError(this.getException());
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package net.locusworks.common.properties;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
public class ImmutableProperties extends Properties {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 65942088008978137L;
|
|
||||||
|
|
||||||
public ImmutableProperties() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImmutableProperties(Properties props) {
|
|
||||||
super();
|
|
||||||
if (props == null || props.isEmpty()) return;
|
|
||||||
|
|
||||||
this.putAll(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized Object setProperty(String key, String value) {
|
|
||||||
return put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized Object put(Object key, Object value) {
|
|
||||||
if (containsKey(key))
|
|
||||||
throw new RuntimeException("Cannot change key value once its set: " + key);
|
|
||||||
return super.put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,977 +0,0 @@
|
|||||||
package net.locusworks.common.properties;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@code Properties} class represents a persistent set of
|
|
||||||
* properties. The {@code Properties} can be saved to a stream
|
|
||||||
* or loaded from a stream. Each key and its corresponding value in
|
|
||||||
* the property list is a string.
|
|
||||||
* <p>
|
|
||||||
* A property list can contain another property list as its
|
|
||||||
* "defaults"; this second property list is searched if
|
|
||||||
* the property key is not found in the original property list.
|
|
||||||
* <p>
|
|
||||||
* Because {@code Properties} inherits from {@code Hashtable}, the
|
|
||||||
* {@code put} and {@code putAll} methods can be applied to a
|
|
||||||
* {@code Properties} object. Their use is strongly discouraged as they
|
|
||||||
* allow the caller to insert entries whose keys or values are not
|
|
||||||
* {@code Strings}. The {@code setProperty} method should be used
|
|
||||||
* instead. If the {@code store} or {@code save} method is called
|
|
||||||
* on a "compromised" {@code Properties} object that contains a
|
|
||||||
* non-{@code String} key or value, the call will fail. Similarly,
|
|
||||||
* the call to the {@code propertyNames} or {@code list} method
|
|
||||||
* will fail if it is called on a "compromised" {@code Properties}
|
|
||||||
* object that contains a non-{@code String} key.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt>
|
|
||||||
* {@link #store(java.io.Writer, java.lang.String) store(Writer, String)}
|
|
||||||
* methods load and store properties from and to a character based stream
|
|
||||||
* in a simple line-oriented format specified below.
|
|
||||||
* <p>
|
|
||||||
* The {@link #load(java.io.InputStream) load(InputStream)} <tt>/</tt>
|
|
||||||
* {@link #store(java.io.OutputStream, java.lang.String) store(OutputStream, String)}
|
|
||||||
* methods work the same way as the load(Reader)/store(Writer, String) pair, except
|
|
||||||
* the input/output stream is encoded in ISO 8859-1 character encoding.
|
|
||||||
* Characters that cannot be directly represented in this encoding can be written using
|
|
||||||
* Unicode escapes as defined in section 3.3 of
|
|
||||||
* <cite>The Java™ Language Specification</cite>;
|
|
||||||
* only a single 'u' character is allowed in an escape
|
|
||||||
* sequence. The native2ascii tool can be used to convert property files to and
|
|
||||||
* from other character encodings.
|
|
||||||
*
|
|
||||||
* <p> The {@link #loadFromXML(InputStream)} and {@link
|
|
||||||
* #storeToXML(OutputStream, String, String)} methods load and store properties
|
|
||||||
* in a simple XML format. By default the UTF-8 character encoding is used,
|
|
||||||
* however a specific encoding may be specified if required. Implementations
|
|
||||||
* are required to support UTF-8 and UTF-16 and may support other encodings.
|
|
||||||
* An XML properties document has the following DOCTYPE declaration:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
|
|
||||||
* </pre>
|
|
||||||
* Note that the system URI (http://java.sun.com/dtd/properties.dtd) is
|
|
||||||
* <i>not</i> accessed when exporting or importing properties; it merely
|
|
||||||
* serves as a string to uniquely identify the DTD, which is:
|
|
||||||
* <pre>
|
|
||||||
* <?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
*
|
|
||||||
* <!-- DTD for properties -->
|
|
||||||
*
|
|
||||||
* <!ELEMENT properties ( comment?, entry* ) >
|
|
||||||
*
|
|
||||||
* <!ATTLIST properties version CDATA #FIXED "1.0">
|
|
||||||
*
|
|
||||||
* <!ELEMENT comment (#PCDATA) >
|
|
||||||
*
|
|
||||||
* <!ELEMENT entry (#PCDATA) >
|
|
||||||
*
|
|
||||||
* <!ATTLIST entry key CDATA #REQUIRED>
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>This class is thread-safe: multiple threads can share a single
|
|
||||||
* <tt>Properties</tt> object without the need for external synchronization.
|
|
||||||
*
|
|
||||||
* @author Arthur van Hoff
|
|
||||||
* @author Michael McCloskey
|
|
||||||
* @author Xueming Shen
|
|
||||||
* @see <a href="../../../technotes/tools/solaris/native2ascii.html">native2ascii tool for Solaris</a>
|
|
||||||
* @see <a href="../../../technotes/tools/windows/native2ascii.html">native2ascii tool for Windows</a>
|
|
||||||
* @since JDK1.0
|
|
||||||
*/
|
|
||||||
public class OrderedProperties extends LinkedHashMap<Object, Object> {
|
|
||||||
/**
|
|
||||||
* use serialVersionUID from JDK 1.1.X for interoperability
|
|
||||||
*/
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 4112578634023874840L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A property list that contains default values for any keys not
|
|
||||||
* found in this property list.
|
|
||||||
*
|
|
||||||
* @serial
|
|
||||||
*/
|
|
||||||
protected OrderedProperties defaults;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty property list with no default values.
|
|
||||||
*/
|
|
||||||
public OrderedProperties() {
|
|
||||||
this(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty property list with the specified defaults.
|
|
||||||
*
|
|
||||||
* @param defaults the defaults.
|
|
||||||
*/
|
|
||||||
public OrderedProperties(OrderedProperties defaults) {
|
|
||||||
this.defaults = defaults;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the <tt>Hashtable</tt> method {@code put}. Provided for
|
|
||||||
* parallelism with the <tt>getProperty</tt> method. Enforces use of
|
|
||||||
* strings for property keys and values. The value returned is the
|
|
||||||
* result of the <tt>Hashtable</tt> call to {@code put}.
|
|
||||||
*
|
|
||||||
* @param key the key to be placed into this property list.
|
|
||||||
* @param value the value corresponding to <tt>key</tt>.
|
|
||||||
* @return the previous value of the specified key in this property
|
|
||||||
* list, or {@code null} if it did not have one.
|
|
||||||
* @see #getProperty
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
public synchronized Object setProperty(String key, String value) {
|
|
||||||
return put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a property list (key and element pairs) from the input
|
|
||||||
* character stream in a simple line-oriented format.
|
|
||||||
* <p>
|
|
||||||
* Properties are processed in terms of lines. There are two
|
|
||||||
* kinds of line, <i>natural lines</i> and <i>logical lines</i>.
|
|
||||||
* A natural line is defined as a line of
|
|
||||||
* characters that is terminated either by a set of line terminator
|
|
||||||
* characters ({@code \n} or {@code \r} or {@code \r\n})
|
|
||||||
* or by the end of the stream. A natural line may be either a blank line,
|
|
||||||
* a comment line, or hold all or some of a key-element pair. A logical
|
|
||||||
* line holds all the data of a key-element pair, which may be spread
|
|
||||||
* out across several adjacent natural lines by escaping
|
|
||||||
* the line terminator sequence with a backslash character
|
|
||||||
* {@code \}. Note that a comment line cannot be extended
|
|
||||||
* in this manner; every natural line that is a comment must have
|
|
||||||
* its own comment indicator, as described below. Lines are read from
|
|
||||||
* input until the end of the stream is reached.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* A natural line that contains only white space characters is
|
|
||||||
* considered blank and is ignored. A comment line has an ASCII
|
|
||||||
* {@code '#'} or {@code '!'} as its first non-white
|
|
||||||
* space character; comment lines are also ignored and do not
|
|
||||||
* encode key-element information. In addition to line
|
|
||||||
* terminators, this format considers the characters space
|
|
||||||
* ({@code ' '}, {@code '\u005Cu0020'}), tab
|
|
||||||
* ({@code '\t'}, {@code '\u005Cu0009'}), and form feed
|
|
||||||
* ({@code '\f'}, {@code '\u005Cu000C'}) to be white
|
|
||||||
* space.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* If a logical line is spread across several natural lines, the
|
|
||||||
* backslash escaping the line terminator sequence, the line
|
|
||||||
* terminator sequence, and any white space at the start of the
|
|
||||||
* following line have no affect on the key or element values.
|
|
||||||
* The remainder of the discussion of key and element parsing
|
|
||||||
* (when loading) will assume all the characters constituting
|
|
||||||
* the key and element appear on a single natural line after
|
|
||||||
* line continuation characters have been removed. Note that
|
|
||||||
* it is <i>not</i> sufficient to only examine the character
|
|
||||||
* preceding a line terminator sequence to decide if the line
|
|
||||||
* terminator is escaped; there must be an odd number of
|
|
||||||
* contiguous backslashes for the line terminator to be escaped.
|
|
||||||
* Since the input is processed from left to right, a
|
|
||||||
* non-zero even number of 2<i>n</i> contiguous backslashes
|
|
||||||
* before a line terminator (or elsewhere) encodes <i>n</i>
|
|
||||||
* backslashes after escape processing.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* The key contains all of the characters in the line starting
|
|
||||||
* with the first non-white space character and up to, but not
|
|
||||||
* including, the first unescaped {@code '='},
|
|
||||||
* {@code ':'}, or white space character other than a line
|
|
||||||
* terminator. All of these key termination characters may be
|
|
||||||
* included in the key by escaping them with a preceding backslash
|
|
||||||
* character; for example,<p>
|
|
||||||
* <p>
|
|
||||||
* {@code \:\=}<p>
|
|
||||||
* <p>
|
|
||||||
* would be the two-character key {@code ":="}. Line
|
|
||||||
* terminator characters can be included using {@code \r} and
|
|
||||||
* {@code \n} escape sequences. Any white space after the
|
|
||||||
* key is skipped; if the first non-white space character after
|
|
||||||
* the key is {@code '='} or {@code ':'}, then it is
|
|
||||||
* ignored and any white space characters after it are also
|
|
||||||
* skipped. All remaining characters on the line become part of
|
|
||||||
* the associated element string; if there are no remaining
|
|
||||||
* characters, the element is the empty string
|
|
||||||
* {@code ""}. Once the raw character sequences
|
|
||||||
* constituting the key and element are identified, escape
|
|
||||||
* processing is performed as described above.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* As an example, each of the following three lines specifies the key
|
|
||||||
* {@code "Truth"} and the associated element value
|
|
||||||
* {@code "Beauty"}:
|
|
||||||
* <pre>
|
|
||||||
* Truth = Beauty
|
|
||||||
* Truth:Beauty
|
|
||||||
* Truth: Beauty
|
|
||||||
* </pre>
|
|
||||||
* As another example, the following three lines specify a single
|
|
||||||
* property:
|
|
||||||
* <pre>
|
|
||||||
* fruits apple, banana, pear, \
|
|
||||||
* cantaloupe, watermelon, \
|
|
||||||
* kiwi, mango
|
|
||||||
* </pre>
|
|
||||||
* The key is {@code "fruits"} and the associated element is:
|
|
||||||
* <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre>
|
|
||||||
* Note that a space appears before each {@code \} so that a space
|
|
||||||
* will appear after each comma in the final result; the {@code \},
|
|
||||||
* line terminator, and leading white space on the continuation line are
|
|
||||||
* merely discarded and are <i>not</i> replaced by one or more other
|
|
||||||
* characters.
|
|
||||||
* <p>
|
|
||||||
* As a third example, the line:
|
|
||||||
* <pre>cheeses
|
|
||||||
* </pre>
|
|
||||||
* specifies that the key is {@code "cheeses"} and the associated
|
|
||||||
* element is the empty string {@code ""}.
|
|
||||||
* <p>
|
|
||||||
* <a name="unicodeescapes"></a>
|
|
||||||
* Characters in keys and elements can be represented in escape
|
|
||||||
* sequences similar to those used for character and string literals
|
|
||||||
* (see sections 3.3 and 3.10.6 of
|
|
||||||
* <cite>The Java™ Language Specification</cite>).
|
|
||||||
* <p>
|
|
||||||
* The differences from the character escape sequences and Unicode
|
|
||||||
* escapes used for characters and strings are:
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li> Octal escapes are not recognized.
|
|
||||||
*
|
|
||||||
* <li> The character sequence {@code \b} does <i>not</i>
|
|
||||||
* represent a backspace character.
|
|
||||||
*
|
|
||||||
* <li> The method does not treat a backslash character,
|
|
||||||
* {@code \}, before a non-valid escape character as an
|
|
||||||
* error; the backslash is silently dropped. For example, in a
|
|
||||||
* Java string the sequence {@code "\z"} would cause a
|
|
||||||
* compile time error. In contrast, this method silently drops
|
|
||||||
* the backslash. Therefore, this method treats the two character
|
|
||||||
* sequence {@code "\b"} as equivalent to the single
|
|
||||||
* character {@code 'b'}.
|
|
||||||
*
|
|
||||||
* <li> Escapes are not necessary for single and double quotes;
|
|
||||||
* however, by the rule above, single and double quote characters
|
|
||||||
* preceded by a backslash still yield single and double quote
|
|
||||||
* characters, respectively.
|
|
||||||
*
|
|
||||||
* <li> Only a single 'u' character is allowed in a Unicode escape
|
|
||||||
* sequence.
|
|
||||||
*
|
|
||||||
* </ul>
|
|
||||||
* <p>
|
|
||||||
* The specified stream remains open after this method returns.
|
|
||||||
*
|
|
||||||
* @param reader the input character stream.
|
|
||||||
* @throws IOException if an error occurred when reading from the
|
|
||||||
* input stream.
|
|
||||||
* @throws IllegalArgumentException if a malformed Unicode escape
|
|
||||||
* appears in the input.
|
|
||||||
* @since 1.6
|
|
||||||
*/
|
|
||||||
public synchronized void load(Reader reader) throws IOException {
|
|
||||||
load0(new LineReader(reader));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a property list (key and element pairs) from the input
|
|
||||||
* byte stream. The input stream is in a simple line-oriented
|
|
||||||
* format as specified in
|
|
||||||
* {@link #load(java.io.Reader) load(Reader)} and is assumed to use
|
|
||||||
* the ISO 8859-1 character encoding; that is each byte is one Latin1
|
|
||||||
* character. Characters not in Latin1, and certain special characters,
|
|
||||||
* are represented in keys and elements using Unicode escapes as defined in
|
|
||||||
* section 3.3 of
|
|
||||||
* <cite>The Java™ Language Specification</cite>.
|
|
||||||
* <p>
|
|
||||||
* The specified stream remains open after this method returns.
|
|
||||||
*
|
|
||||||
* @param inStream the input stream.
|
|
||||||
* @throws IOException if an error occurred when reading from the
|
|
||||||
* input stream.
|
|
||||||
* @throws IllegalArgumentException if the input stream contains a
|
|
||||||
* malformed Unicode escape sequence.
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
public synchronized void load(InputStream inStream) throws IOException {
|
|
||||||
load0(new LineReader(inStream));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void load0(LineReader lr) throws IOException {
|
|
||||||
char[] convtBuf = new char[1024];
|
|
||||||
int limit;
|
|
||||||
int keyLen;
|
|
||||||
int valueStart;
|
|
||||||
char c;
|
|
||||||
boolean hasSep;
|
|
||||||
boolean precedingBackslash;
|
|
||||||
|
|
||||||
while ((limit = lr.readLine()) >= 0) {
|
|
||||||
c = 0;
|
|
||||||
keyLen = 0;
|
|
||||||
valueStart = limit;
|
|
||||||
hasSep = false;
|
|
||||||
|
|
||||||
//System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
|
|
||||||
precedingBackslash = false;
|
|
||||||
while (keyLen < limit) {
|
|
||||||
c = lr.lineBuf[keyLen];
|
|
||||||
//need check if escaped.
|
|
||||||
if ((c == '=' || c == ':') && !precedingBackslash) {
|
|
||||||
valueStart = keyLen + 1;
|
|
||||||
hasSep = true;
|
|
||||||
break;
|
|
||||||
} else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {
|
|
||||||
valueStart = keyLen + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (c == '\\') {
|
|
||||||
precedingBackslash = !precedingBackslash;
|
|
||||||
} else {
|
|
||||||
precedingBackslash = false;
|
|
||||||
}
|
|
||||||
keyLen++;
|
|
||||||
}
|
|
||||||
while (valueStart < limit) {
|
|
||||||
c = lr.lineBuf[valueStart];
|
|
||||||
if (c != ' ' && c != '\t' && c != '\f') {
|
|
||||||
if (!hasSep && (c == '=' || c == ':')) {
|
|
||||||
hasSep = true;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
valueStart++;
|
|
||||||
}
|
|
||||||
String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
|
|
||||||
String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
|
|
||||||
put(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read in a "logical line" from an InputStream/Reader, skip all comment
|
|
||||||
* and blank lines and filter out those leading whitespace characters
|
|
||||||
* (\u0020, \u0009 and \u000c) from the beginning of a "natural line".
|
|
||||||
* Method returns the char length of the "logical line" and stores
|
|
||||||
* the line in "lineBuf".
|
|
||||||
*/
|
|
||||||
static class LineReader {
|
|
||||||
public LineReader(InputStream inStream) {
|
|
||||||
this.inStream = inStream;
|
|
||||||
inByteBuf = new byte[8192];
|
|
||||||
}
|
|
||||||
|
|
||||||
public LineReader(Reader reader) {
|
|
||||||
this.reader = reader;
|
|
||||||
inCharBuf = new char[8192];
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] inByteBuf;
|
|
||||||
char[] inCharBuf;
|
|
||||||
char[] lineBuf = new char[1024];
|
|
||||||
int inLimit = 0;
|
|
||||||
int inOff = 0;
|
|
||||||
InputStream inStream;
|
|
||||||
Reader reader;
|
|
||||||
|
|
||||||
int readLine() throws IOException {
|
|
||||||
int len = 0;
|
|
||||||
char c = 0;
|
|
||||||
|
|
||||||
boolean skipWhiteSpace = true;
|
|
||||||
boolean isCommentLine = false;
|
|
||||||
boolean isNewLine = true;
|
|
||||||
boolean appendedLineBegin = false;
|
|
||||||
boolean precedingBackslash = false;
|
|
||||||
boolean skipLF = false;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (inOff >= inLimit) {
|
|
||||||
inLimit = (inStream == null) ? reader.read(inCharBuf)
|
|
||||||
: inStream.read(inByteBuf);
|
|
||||||
inOff = 0;
|
|
||||||
if (inLimit <= 0) {
|
|
||||||
if (len == 0 || isCommentLine) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (precedingBackslash) {
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (inStream != null) {
|
|
||||||
//The line below is equivalent to calling a
|
|
||||||
//ISO8859-1 decoder.
|
|
||||||
c = (char) (0xff & inByteBuf[inOff++]);
|
|
||||||
} else {
|
|
||||||
c = inCharBuf[inOff++];
|
|
||||||
}
|
|
||||||
if (skipLF) {
|
|
||||||
skipLF = false;
|
|
||||||
if (c == '\n') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (skipWhiteSpace) {
|
|
||||||
if (c == ' ' || c == '\t' || c == '\f') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!appendedLineBegin && (c == '\r' || c == '\n')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
skipWhiteSpace = false;
|
|
||||||
appendedLineBegin = false;
|
|
||||||
}
|
|
||||||
if (isNewLine) {
|
|
||||||
isNewLine = false;
|
|
||||||
if (c == '#' || c == '!') {
|
|
||||||
isCommentLine = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c != '\n' && c != '\r') {
|
|
||||||
lineBuf[len++] = c;
|
|
||||||
if (len == lineBuf.length) {
|
|
||||||
int newLength = lineBuf.length * 2;
|
|
||||||
char[] buf = new char[newLength];
|
|
||||||
System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length);
|
|
||||||
lineBuf = buf;
|
|
||||||
}
|
|
||||||
//flip the preceding backslash flag
|
|
||||||
if (c == '\\') {
|
|
||||||
precedingBackslash = !precedingBackslash;
|
|
||||||
} else {
|
|
||||||
precedingBackslash = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// reached EOL
|
|
||||||
if (isCommentLine) {
|
|
||||||
isCommentLine = false;
|
|
||||||
isNewLine = true;
|
|
||||||
skipWhiteSpace = true;
|
|
||||||
len = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (inOff >= inLimit) {
|
|
||||||
inLimit = (inStream == null)
|
|
||||||
? reader.read(inCharBuf)
|
|
||||||
: inStream.read(inByteBuf);
|
|
||||||
inOff = 0;
|
|
||||||
if (inLimit <= 0) {
|
|
||||||
if (precedingBackslash) {
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (precedingBackslash) {
|
|
||||||
len -= 1;
|
|
||||||
//skip the leading whitespace characters in following line
|
|
||||||
skipWhiteSpace = true;
|
|
||||||
appendedLineBegin = true;
|
|
||||||
precedingBackslash = false;
|
|
||||||
if (c == '\r') {
|
|
||||||
skipLF = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Converts encoded \uxxxx to unicode chars
|
|
||||||
* and changes special saved chars to their original forms
|
|
||||||
*/
|
|
||||||
private String loadConvert(char[] in, int off, int len, char[] convtBuf) {
|
|
||||||
if (convtBuf.length < len) {
|
|
||||||
int newLen = len * 2;
|
|
||||||
convtBuf = new char[newLen];
|
|
||||||
}
|
|
||||||
char aChar;
|
|
||||||
char[] out = convtBuf;
|
|
||||||
int outLen = 0;
|
|
||||||
int end = off + len;
|
|
||||||
|
|
||||||
while (off < end) {
|
|
||||||
aChar = in[off++];
|
|
||||||
if (aChar == '\\') {
|
|
||||||
aChar = in[off++];
|
|
||||||
if (aChar == 'u') {
|
|
||||||
// Read the xxxx
|
|
||||||
int value = 0;
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
aChar = in[off++];
|
|
||||||
value = switch (aChar) {
|
|
||||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> (value << 4) + aChar - '0';
|
|
||||||
case 'a', 'b', 'c', 'd', 'e', 'f' -> (value << 4) + 10 + aChar - 'a';
|
|
||||||
case 'A', 'B', 'C', 'D', 'E', 'F' -> (value << 4) + 10 + aChar - 'A';
|
|
||||||
default -> throw new IllegalArgumentException(
|
|
||||||
"Malformed \\uxxxx encoding.");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
out[outLen++] = (char) value;
|
|
||||||
} else {
|
|
||||||
if (aChar == 't') aChar = '\t';
|
|
||||||
else if (aChar == 'r') aChar = '\r';
|
|
||||||
else if (aChar == 'n') aChar = '\n';
|
|
||||||
else if (aChar == 'f') aChar = '\f';
|
|
||||||
out[outLen++] = aChar;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
out[outLen++] = aChar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new String(out, 0, outLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Converts unicodes to encoded \uxxxx and escapes
|
|
||||||
* special characters with a preceding slash
|
|
||||||
*/
|
|
||||||
private String saveConvert(String theString,
|
|
||||||
boolean escapeSpace,
|
|
||||||
boolean escapeUnicode) {
|
|
||||||
int len = theString.length();
|
|
||||||
int bufLen = len * 2;
|
|
||||||
StringBuffer outBuffer = new StringBuffer(bufLen);
|
|
||||||
|
|
||||||
for (int x = 0; x < len; x++) {
|
|
||||||
char aChar = theString.charAt(x);
|
|
||||||
// Handle common case first, selecting largest block that
|
|
||||||
// avoids the specials below
|
|
||||||
if ((aChar > 61) && (aChar < 127)) {
|
|
||||||
if (aChar == '\\') {
|
|
||||||
outBuffer.append('\\');
|
|
||||||
outBuffer.append('\\');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
outBuffer.append(aChar);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch (aChar) {
|
|
||||||
case ' ':
|
|
||||||
if (x == 0 || escapeSpace)
|
|
||||||
outBuffer.append('\\');
|
|
||||||
outBuffer.append(' ');
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
outBuffer.append('\\');
|
|
||||||
outBuffer.append('t');
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
outBuffer.append('\\');
|
|
||||||
outBuffer.append('n');
|
|
||||||
break;
|
|
||||||
case '\r':
|
|
||||||
outBuffer.append('\\');
|
|
||||||
outBuffer.append('r');
|
|
||||||
break;
|
|
||||||
case '\f':
|
|
||||||
outBuffer.append('\\');
|
|
||||||
outBuffer.append('f');
|
|
||||||
break;
|
|
||||||
case '=': // Fall through
|
|
||||||
case ':': // Fall through
|
|
||||||
case '#': // Fall through
|
|
||||||
case '!':
|
|
||||||
outBuffer.append('\\');
|
|
||||||
outBuffer.append(aChar);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode) {
|
|
||||||
outBuffer.append('\\');
|
|
||||||
outBuffer.append('u');
|
|
||||||
outBuffer.append(toHex((aChar >> 12) & 0xF));
|
|
||||||
outBuffer.append(toHex((aChar >> 8) & 0xF));
|
|
||||||
outBuffer.append(toHex((aChar >> 4) & 0xF));
|
|
||||||
outBuffer.append(toHex(aChar & 0xF));
|
|
||||||
} else {
|
|
||||||
outBuffer.append(aChar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return outBuffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void writeComments(BufferedWriter bw, String comments)
|
|
||||||
throws IOException {
|
|
||||||
bw.write("#");
|
|
||||||
int len = comments.length();
|
|
||||||
int current = 0;
|
|
||||||
int last = 0;
|
|
||||||
char[] uu = new char[6];
|
|
||||||
uu[0] = '\\';
|
|
||||||
uu[1] = 'u';
|
|
||||||
while (current < len) {
|
|
||||||
char c = comments.charAt(current);
|
|
||||||
if (c > 'ÿ' || c == '\n' || c == '\r') {
|
|
||||||
if (last != current)
|
|
||||||
bw.write(comments.substring(last, current));
|
|
||||||
if (c > 'ÿ') {
|
|
||||||
uu[2] = toHex((c >> 12) & 0xf);
|
|
||||||
uu[3] = toHex((c >> 8) & 0xf);
|
|
||||||
uu[4] = toHex((c >> 4) & 0xf);
|
|
||||||
uu[5] = toHex(c & 0xf);
|
|
||||||
bw.write(new String(uu));
|
|
||||||
} else {
|
|
||||||
bw.newLine();
|
|
||||||
if (c == '\r' &&
|
|
||||||
current != len - 1 &&
|
|
||||||
comments.charAt(current + 1) == '\n') {
|
|
||||||
current++;
|
|
||||||
}
|
|
||||||
if (current == len - 1 ||
|
|
||||||
(comments.charAt(current + 1) != '#' &&
|
|
||||||
comments.charAt(current + 1) != '!'))
|
|
||||||
bw.write("#");
|
|
||||||
}
|
|
||||||
last = current + 1;
|
|
||||||
}
|
|
||||||
current++;
|
|
||||||
}
|
|
||||||
if (last != current)
|
|
||||||
bw.write(comments.substring(last, current));
|
|
||||||
bw.newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the {@code store(OutputStream out, String comments)} method
|
|
||||||
* and suppresses IOExceptions that were thrown.
|
|
||||||
*
|
|
||||||
* @param out an output stream.
|
|
||||||
* @throws ClassCastException if this {@code Properties} object
|
|
||||||
* contains any keys or values that are not
|
|
||||||
* {@code Strings}.
|
|
||||||
* @deprecated This method does not throw an IOException if an I/O error
|
|
||||||
* occurs while saving the property list. The preferred way to save a
|
|
||||||
* properties list is via the {@code store(OutputStream out,
|
|
||||||
* String comments)} method or the
|
|
||||||
* {@code storeToXML(OutputStream os, String comment)} method.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void save(OutputStream out, String comments) {
|
|
||||||
try {
|
|
||||||
store(out, comments);
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes this property list (key and element pairs) in this
|
|
||||||
* {@code Properties} table to the output character stream in a
|
|
||||||
* format suitable for using the {@link #load(java.io.Reader) load(Reader)}
|
|
||||||
* method.
|
|
||||||
* <p>
|
|
||||||
* Properties from the defaults table of this {@code Properties}
|
|
||||||
* table (if any) are <i>not</i> written out by this method.
|
|
||||||
* <p>
|
|
||||||
* If the comments argument is not null, then an ASCII {@code #}
|
|
||||||
* character, the comments string, and a line separator are first written
|
|
||||||
* to the output stream. Thus, the {@code comments} can serve as an
|
|
||||||
* identifying comment. Any one of a line feed ('\n'), a carriage
|
|
||||||
* return ('\r'), or a carriage return followed immediately by a line feed
|
|
||||||
* in comments is replaced by a line separator generated by the {@code Writer}
|
|
||||||
* and if the next character in comments is not character {@code #} or
|
|
||||||
* character {@code !} then an ASCII {@code #} is written out
|
|
||||||
* after that line separator.
|
|
||||||
* <p>
|
|
||||||
* Next, a comment line is always written, consisting of an ASCII
|
|
||||||
* {@code #} character, the current date and time (as if produced
|
|
||||||
* by the {@code toString} method of {@code Date} for the
|
|
||||||
* current time), and a line separator as generated by the {@code Writer}.
|
|
||||||
* <p>
|
|
||||||
* Then every entry in this {@code Properties} table is
|
|
||||||
* written out, one per line. For each entry the key string is
|
|
||||||
* written, then an ASCII {@code =}, then the associated
|
|
||||||
* element string. For the key, all space characters are
|
|
||||||
* written with a preceding {@code \} character. For the
|
|
||||||
* element, leading space characters, but not embedded or trailing
|
|
||||||
* space characters, are written with a preceding {@code \}
|
|
||||||
* character. The key and element characters {@code #},
|
|
||||||
* {@code !}, {@code =}, and {@code :} are written
|
|
||||||
* with a preceding backslash to ensure that they are properly loaded.
|
|
||||||
* <p>
|
|
||||||
* After the entries have been written, the output stream is flushed.
|
|
||||||
* The output stream remains open after this method returns.
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* @param writer an output character stream writer.
|
|
||||||
* @param comments a description of the property list.
|
|
||||||
* @throws IOException if writing this property list to the specified
|
|
||||||
* output stream throws an <tt>IOException</tt>.
|
|
||||||
* @throws ClassCastException if this {@code Properties} object
|
|
||||||
* contains any keys or values that are not {@code Strings}.
|
|
||||||
* @throws NullPointerException if {@code writer} is null.
|
|
||||||
* @since 1.6
|
|
||||||
*/
|
|
||||||
public void store(Writer writer, String comments)
|
|
||||||
throws IOException {
|
|
||||||
store0((writer instanceof BufferedWriter) ? (BufferedWriter) writer
|
|
||||||
: new BufferedWriter(writer),
|
|
||||||
comments,
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes this property list (key and element pairs) in this
|
|
||||||
* {@code Properties} table to the output stream in a format suitable
|
|
||||||
* for loading into a {@code Properties} table using the
|
|
||||||
* {@link #load(InputStream) load(InputStream)} method.
|
|
||||||
* <p>
|
|
||||||
* Properties from the defaults table of this {@code Properties}
|
|
||||||
* table (if any) are <i>not</i> written out by this method.
|
|
||||||
* <p>
|
|
||||||
* This method outputs the comments, properties keys and values in
|
|
||||||
* the same format as specified in
|
|
||||||
* {@link #store(java.io.Writer, java.lang.String) store(Writer)},
|
|
||||||
* with the following differences:
|
|
||||||
* <ul>
|
|
||||||
* <li>The stream is written using the ISO 8859-1 character encoding.
|
|
||||||
*
|
|
||||||
* <li>Characters not in Latin-1 in the comments are written as
|
|
||||||
* {@code \u005Cu}<i>xxxx</i> for their appropriate unicode
|
|
||||||
* hexadecimal value <i>xxxx</i>.
|
|
||||||
*
|
|
||||||
* <li>Characters less than {@code \u005Cu0020} and characters greater
|
|
||||||
* than {@code \u005Cu007E} in property keys or values are written
|
|
||||||
* as {@code \u005Cu}<i>xxxx</i> for the appropriate hexadecimal
|
|
||||||
* value <i>xxxx</i>.
|
|
||||||
* </ul>
|
|
||||||
* <p>
|
|
||||||
* After the entries have been written, the output stream is flushed.
|
|
||||||
* The output stream remains open after this method returns.
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* @param out an output stream.
|
|
||||||
* @param comments a description of the property list.
|
|
||||||
* @throws IOException if writing this property list to the specified
|
|
||||||
* output stream throws an <tt>IOException</tt>.
|
|
||||||
* @throws ClassCastException if this {@code Properties} object
|
|
||||||
* contains any keys or values that are not {@code Strings}.
|
|
||||||
* @throws NullPointerException if {@code out} is null.
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
public void store(OutputStream out, String comments)
|
|
||||||
throws IOException {
|
|
||||||
store0(new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.ISO_8859_1)),
|
|
||||||
comments,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void store0(BufferedWriter bw, String comments, boolean escUnicode)
|
|
||||||
throws IOException {
|
|
||||||
if (comments != null) {
|
|
||||||
writeComments(bw, comments);
|
|
||||||
}
|
|
||||||
bw.write("#" + new Date().toString());
|
|
||||||
bw.newLine();
|
|
||||||
synchronized (this) {
|
|
||||||
for (Enumeration<?> e = keys(); e.hasMoreElements(); ) {
|
|
||||||
String key = (String) e.nextElement();
|
|
||||||
String val = (String) get(key);
|
|
||||||
key = saveConvert(key, true, escUnicode);
|
|
||||||
/* No need to escape embedded and trailing spaces for value, hence
|
|
||||||
* pass false to flag.
|
|
||||||
*/
|
|
||||||
val = saveConvert(val, false, escUnicode);
|
|
||||||
bw.write(key + "=" + val);
|
|
||||||
bw.newLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bw.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches for the property with the specified key in this property list.
|
|
||||||
* If the key is not found in this property list, the default property list,
|
|
||||||
* and its defaults, recursively, are then checked. The method returns
|
|
||||||
* {@code null} if the property is not found.
|
|
||||||
*
|
|
||||||
* @param key the property key.
|
|
||||||
* @return the value in this property list with the specified key value.
|
|
||||||
* @see #setProperty
|
|
||||||
* @see #defaults
|
|
||||||
*/
|
|
||||||
public String getProperty(String key) {
|
|
||||||
Object oval = super.get(key);
|
|
||||||
String sval = (oval instanceof String) ? (String) oval : null;
|
|
||||||
return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches for the property with the specified key in this property list.
|
|
||||||
* If the key is not found in this property list, the default property list,
|
|
||||||
* and its defaults, recursively, are then checked. The method returns the
|
|
||||||
* default value argument if the property is not found.
|
|
||||||
*
|
|
||||||
* @param key the hashtable key.
|
|
||||||
* @param defaultValue a default value.
|
|
||||||
* @return the value in this property list with the specified key value.
|
|
||||||
* @see #setProperty
|
|
||||||
* @see #defaults
|
|
||||||
*/
|
|
||||||
public String getProperty(String key, String defaultValue) {
|
|
||||||
String val = getProperty(key);
|
|
||||||
return (val == null) ? defaultValue : val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an enumeration of all the keys in this property list,
|
|
||||||
* including distinct keys in the default property list if a key
|
|
||||||
* of the same name has not already been found from the main
|
|
||||||
* properties list.
|
|
||||||
*
|
|
||||||
* @return an enumeration of all the keys in this property list, including
|
|
||||||
* the keys in the default property list.
|
|
||||||
* @throws ClassCastException if any key in this property list
|
|
||||||
* is not a string.
|
|
||||||
* @see java.util.Enumeration
|
|
||||||
* @see java.util.Properties#defaults
|
|
||||||
* @see #stringPropertyNames
|
|
||||||
*/
|
|
||||||
public Enumeration<?> propertyNames() {
|
|
||||||
LinkedHashMap<String, Object> h = new LinkedHashMap<>();
|
|
||||||
enumerate(h);
|
|
||||||
return Collections.enumeration(h.keySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a set of keys in this property list where
|
|
||||||
* the key and its corresponding value are strings,
|
|
||||||
* including distinct keys in the default property list if a key
|
|
||||||
* of the same name has not already been found from the main
|
|
||||||
* properties list. Properties whose key or value is not
|
|
||||||
* of type <tt>String</tt> are omitted.
|
|
||||||
* <p>
|
|
||||||
* The returned set is not backed by the <tt>Properties</tt> object.
|
|
||||||
* Changes to this <tt>Properties</tt> are not reflected in the set,
|
|
||||||
* or vice versa.
|
|
||||||
*
|
|
||||||
* @return a set of keys in this property list where
|
|
||||||
* the key and its corresponding value are strings,
|
|
||||||
* including the keys in the default property list.
|
|
||||||
* @see java.util.Properties#defaults
|
|
||||||
* @since 1.6
|
|
||||||
*/
|
|
||||||
public Set<String> stringPropertyNames() {
|
|
||||||
LinkedHashMap<String, String> h = new LinkedHashMap<>();
|
|
||||||
enumerateStringProperties(h);
|
|
||||||
return h.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints this property list out to the specified output stream.
|
|
||||||
* This method is useful for debugging.
|
|
||||||
*
|
|
||||||
* @param out an output stream.
|
|
||||||
* @throws ClassCastException if any key in this property list
|
|
||||||
* is not a string.
|
|
||||||
*/
|
|
||||||
public void list(PrintStream out) {
|
|
||||||
PrintWriter writer = new PrintWriter(out);
|
|
||||||
list(writer);
|
|
||||||
writer.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints this property list out to the specified output stream.
|
|
||||||
* This method is useful for debugging.
|
|
||||||
*
|
|
||||||
* @param out an output stream.
|
|
||||||
* @throws ClassCastException if any key in this property list
|
|
||||||
* is not a string.
|
|
||||||
* @since JDK1.1
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Rather than use an anonymous inner class to share common code, this
|
|
||||||
* method is duplicated in order to ensure that a non-1.1 compiler can
|
|
||||||
* compile this file.
|
|
||||||
*/
|
|
||||||
public void list(PrintWriter out) {
|
|
||||||
out.println("-- listing properties --");
|
|
||||||
LinkedHashMap<String, Object> h = new LinkedHashMap<>();
|
|
||||||
enumerate(h);
|
|
||||||
for (Enumeration<String> e = Collections.enumeration(h.keySet()); e.hasMoreElements(); ) {
|
|
||||||
String key = e.nextElement();
|
|
||||||
String val = (String) h.get(key);
|
|
||||||
if (val.length() > 40) {
|
|
||||||
val = val.substring(0, 37) + "...";
|
|
||||||
}
|
|
||||||
out.println(key + "=" + val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lists all key/value pairs in the specified hashtable.
|
|
||||||
*
|
|
||||||
* @param h the hashtable
|
|
||||||
* @throws ClassCastException if any of the property keys
|
|
||||||
* is not of the String type.
|
|
||||||
*/
|
|
||||||
private synchronized void enumerate(LinkedHashMap<String, Object> h) {
|
|
||||||
if (defaults != null) {
|
|
||||||
defaults.enumerate(h);
|
|
||||||
}
|
|
||||||
for (Enumeration<?> e = keys(); e.hasMoreElements(); ) {
|
|
||||||
String key = (String) e.nextElement();
|
|
||||||
h.put(key, get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Enumeration<?> keys() {
|
|
||||||
return Collections.enumeration(keySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enumerates all key/value pairs in the specified hashtable
|
|
||||||
* and omits the property if the key or value is not a string.
|
|
||||||
*
|
|
||||||
* @param h the hashtable
|
|
||||||
*/
|
|
||||||
private synchronized void enumerateStringProperties(Map<String, String> h) {
|
|
||||||
if (defaults != null) {
|
|
||||||
defaults.enumerateStringProperties(h);
|
|
||||||
}
|
|
||||||
for (Enumeration<?> e = keys(); e.hasMoreElements(); ) {
|
|
||||||
Object k = e.nextElement();
|
|
||||||
Object v = get(k);
|
|
||||||
if (k instanceof String && v instanceof String) {
|
|
||||||
h.put((String) k, (String) v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a nibble to a hex character
|
|
||||||
*
|
|
||||||
* @param nibble the nibble to convert.
|
|
||||||
*/
|
|
||||||
private static char toHex(int nibble) {
|
|
||||||
return hexDigit[(nibble & 0xF)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A table of hex digits
|
|
||||||
*/
|
|
||||||
private static final char[] hexDigit = {
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class Checks {
|
|
||||||
|
|
||||||
public static void checkArguments(boolean expression, String error) {
|
|
||||||
checkArguments(expression, "%s", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkArguments(boolean expression, String errorFmt, Object... args) {
|
|
||||||
if (!expression) throw new IllegalArgumentException(String.format(errorFmt, args));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkState(boolean expression, String error) {
|
|
||||||
checkState(expression, "%s", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkState(boolean expression, String errorFmt, Object... args) {
|
|
||||||
if (!expression) throw new IllegalStateException(String.format(errorFmt, args));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkNotNull(Object item, String error) {
|
|
||||||
Objects.requireNonNull(item, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to hold final static constant values used across the system
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
* @date 02/15/2018
|
|
||||||
*/
|
|
||||||
public class Constants {
|
|
||||||
|
|
||||||
public static final short TRUE = (short) 1;
|
|
||||||
public static final short FALSE = (short) 0;
|
|
||||||
|
|
||||||
public static final short EXIT_SUCCESS = (short) 0;
|
|
||||||
public static final short EXIT_FAIL = (short) 1;
|
|
||||||
|
|
||||||
public static final String LOG4J_CONFIG_PROPERTY = "log4j.configurationFile";
|
|
||||||
public static final String JUNIT_TEST_CHECK = "junit.test";
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
import net.locusworks.common.Charsets;
|
|
||||||
|
|
||||||
public class DataOutputStreamHelper extends DataOutputStream implements AutoCloseable {
|
|
||||||
|
|
||||||
public DataOutputStreamHelper() {
|
|
||||||
this(new ByteArrayOutputStream());
|
|
||||||
}
|
|
||||||
|
|
||||||
public DataOutputStreamHelper(OutputStream out) {
|
|
||||||
super(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toByteArray() {
|
|
||||||
if (super.out == null) {
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
if (super.out instanceof ByteArrayOutputStream) {
|
|
||||||
return ((ByteArrayOutputStream) super.out).toByteArray();
|
|
||||||
}
|
|
||||||
return super.out.toString().getBytes(Charsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String base64Encoded() {
|
|
||||||
return Base64.getEncoder().encodeToString(this.toByteArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return new String(this.toByteArray(), Charsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
if (super.out != null) {
|
|
||||||
try {
|
|
||||||
super.out.close();
|
|
||||||
super.out = null;
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
|
||||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to deseralize json data into a Date object back into a class that specifies this deserializer <br>
|
|
||||||
* For example the below code:
|
|
||||||
* <pre>
|
|
||||||
* {@code @JsonDeserialize(using=DateTimeStampDeserializer.class)
|
|
||||||
* private Date purgeEndDate;}
|
|
||||||
* </pre>
|
|
||||||
* Will specify to use this deserializer class when a json field {@code purgeEndDate} is encountered in the json
|
|
||||||
* string and will try to convert the string into a date object and inject the value back into the class
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0
|
|
||||||
* @date 02/15/2018
|
|
||||||
* @see com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
|
||||||
*/
|
|
||||||
public class DateTimeStampDeserializer extends JsonDeserializer<Date> {
|
|
||||||
|
|
||||||
private static final String DEFAULT = "MM/dd/yyyy";
|
|
||||||
private static final String EXPANDED = "MM/dd/yyyy HH:mm:ss z";
|
|
||||||
private static final String EXPANDED_WITH_TIMEZONE = "MMM d, yyyy HH:mm:ss z";
|
|
||||||
private static final String EXPANDED_WITH_AM_PM = "MMM d, yyyy h:mm:ss a";
|
|
||||||
|
|
||||||
private static final String[] formats = new String[]{
|
|
||||||
DEFAULT,
|
|
||||||
EXPANDED,
|
|
||||||
EXPANDED_WITH_TIMEZONE,
|
|
||||||
EXPANDED_WITH_AM_PM,
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final Integer[] styles = new Integer[]{
|
|
||||||
SimpleDateFormat.LONG,
|
|
||||||
SimpleDateFormat.FULL,
|
|
||||||
SimpleDateFormat.MEDIUM,
|
|
||||||
SimpleDateFormat.SHORT
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Date deserialize(JsonParser p, DeserializationContext context) throws IOException {
|
|
||||||
String value = p.getText();
|
|
||||||
|
|
||||||
Date date;
|
|
||||||
//First, try to see if the value can be parsed into along
|
|
||||||
try {
|
|
||||||
date = new Date(Long.parseLong(value));
|
|
||||||
return date;
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
|
|
||||||
//Next, iterate over the built-in styles to see if it can be converted
|
|
||||||
for (Integer style : styles) {
|
|
||||||
date = formatDate(style, value);
|
|
||||||
if (date != null) {
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Lastly, iterate over the custom styles specified in format to see if it can be converted
|
|
||||||
for (String fmt : formats) {
|
|
||||||
date = formatDate(fmt, value);
|
|
||||||
if (date != null) {
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Return null if date format can't be converted
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a string value to a date object
|
|
||||||
*
|
|
||||||
* @param format The format to use in reference to the source
|
|
||||||
* @param source the source to convert
|
|
||||||
* @return Date object if the conversion was success; null otherwise
|
|
||||||
*/
|
|
||||||
private static Date formatDate(String format, String source) {
|
|
||||||
try {
|
|
||||||
return new SimpleDateFormat(format).parse(source);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a string value to a date object using SimpleDateFormats
|
|
||||||
* built in styles
|
|
||||||
*
|
|
||||||
* @param style The style to use
|
|
||||||
* @param source the source to convert
|
|
||||||
* @return Date object if the conversion was success; null otherwise
|
|
||||||
*/
|
|
||||||
private static Date formatDate(Integer style, String source) {
|
|
||||||
try {
|
|
||||||
return SimpleDateFormat.getDateInstance(style).parse(source);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
|
||||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
|
||||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to serialize a date object into a json string value <br>
|
|
||||||
* This serializer will convert date objects to their timestamp representation <br>
|
|
||||||
* For example the below code:
|
|
||||||
* <pre>
|
|
||||||
* {@code @JsonSerialize(using=DateTimeStampSerializer.class)
|
|
||||||
* private Date purgeEndDate;
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
* Will specify to use this serializer class when the {@code purgeEndDate} is encountered when converting to json
|
|
||||||
* and will try to convert the date object to its timestamp equivalent
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0
|
|
||||||
* @date 02/15/2018
|
|
||||||
* @see com.fasterxml.jackson.databind.annotation.JsonSerialize
|
|
||||||
* @see com.fasterxml.jackson.databind.ser.std.StdSerializer
|
|
||||||
*/
|
|
||||||
public class DateTimeStampSerializer extends StdSerializer<Date> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = -4753139740916300831L;
|
|
||||||
|
|
||||||
public DateTimeStampSerializer() {
|
|
||||||
this(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTimeStampSerializer(Class<Date> t) {
|
|
||||||
super(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void serialize(Date date, JsonGenerator generator, SerializerProvider provider) throws IOException {
|
|
||||||
generator.writeNumber(date.getTime());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import static net.locusworks.common.Charsets.UTF_8;
|
|
||||||
import static net.locusworks.common.utils.ObjectUtils.getResourceStream;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import net.locusworks.common.interfaces.AutoCloseableIterator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to read in a file that can be used in the try-with-resource block
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
* @date 02/15/2018
|
|
||||||
*/
|
|
||||||
public class FileReader implements AutoCloseableIterator<FileReader.LineInfo>, Iterable<FileReader.LineInfo>, AutoCloseable {
|
|
||||||
|
|
||||||
private BufferedReader reader;
|
|
||||||
private LineInfo info;
|
|
||||||
private Integer lineNumber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param fileName Name of the file to read
|
|
||||||
*/
|
|
||||||
public FileReader(String fileName) {
|
|
||||||
init(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param file File to read
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public FileReader(File file) {
|
|
||||||
init(file.toPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param file File to read
|
|
||||||
*/
|
|
||||||
public FileReader(Path file) {
|
|
||||||
init(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param reader Buffered reader to read data from
|
|
||||||
*/
|
|
||||||
public FileReader(BufferedReader reader) {
|
|
||||||
init(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialization helper
|
|
||||||
*
|
|
||||||
* @param fileName Name of the file to load
|
|
||||||
* This will look into the resources directory if it cannot
|
|
||||||
* find the file directly.
|
|
||||||
*/
|
|
||||||
private void init(String fileName) {
|
|
||||||
if (fileName == null) {
|
|
||||||
throw new IllegalArgumentException("File name cannot be null");
|
|
||||||
}
|
|
||||||
//check to see if the file exists
|
|
||||||
Path f = Paths.get(fileName);
|
|
||||||
if (Files.exists(f)) {
|
|
||||||
init(f); //If it does. load through the file initializer
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check to see if the file is in the resources directory
|
|
||||||
InputStream is = getResourceStream(fileName);
|
|
||||||
|
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(is, UTF_8));
|
|
||||||
init(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializer helper to load file
|
|
||||||
*
|
|
||||||
* @param file File to load
|
|
||||||
*/
|
|
||||||
private void init(Path file) {
|
|
||||||
if (file == null) throw new IllegalArgumentException("File cannot be null");
|
|
||||||
if (Files.notExists(file)) throw new IllegalArgumentException("File " + file + " does not exist");
|
|
||||||
if (!Files.isRegularFile(file)) throw new IllegalArgumentException("File " + file + " is not a file");
|
|
||||||
try {
|
|
||||||
BufferedReader br = Files.newBufferedReader(file);
|
|
||||||
init(br);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializer helper for buffered reader
|
|
||||||
* This is ultimately where all initializers end as a buffered reader
|
|
||||||
*
|
|
||||||
* @param reader buffered reader to load
|
|
||||||
*/
|
|
||||||
private void init(BufferedReader reader) {
|
|
||||||
if (reader == null) {
|
|
||||||
throw new IllegalArgumentException("Buffered Reader cannot be null");
|
|
||||||
}
|
|
||||||
this.reader = reader;
|
|
||||||
this.lineNumber = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNext() {
|
|
||||||
try {
|
|
||||||
String line = this.reader.readLine();
|
|
||||||
if (line == null) {
|
|
||||||
this.close();
|
|
||||||
this.info = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.lineNumber++;
|
|
||||||
this.info = new LineInfo(this.lineNumber, line);
|
|
||||||
return true;
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LineInfo next() {
|
|
||||||
if (this.info == null) {
|
|
||||||
throw new NoSuchElementException("Call to next was initiated but there are no more elements to read");
|
|
||||||
}
|
|
||||||
return this.info;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<LineInfo> iterator() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
if (this.reader != null) {
|
|
||||||
try {
|
|
||||||
this.reader.close();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class LineInfo {
|
|
||||||
private Integer lineNumber;
|
|
||||||
private Integer lineLength;
|
|
||||||
private String line;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param lineNumber the current line number in the file
|
|
||||||
* @param line the line information from the file
|
|
||||||
*/
|
|
||||||
public LineInfo(Integer lineNumber, String line) {
|
|
||||||
this.lineNumber = lineNumber;
|
|
||||||
this.line = line;
|
|
||||||
this.lineLength = line.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the lineNumber
|
|
||||||
*/
|
|
||||||
public Integer getLineNumber() {
|
|
||||||
return lineNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param lineNumber the lineNumber to set
|
|
||||||
*/
|
|
||||||
public void setLineNumber(Integer lineNumber) {
|
|
||||||
this.lineNumber = lineNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the lineLength
|
|
||||||
*/
|
|
||||||
public Integer getLineLength() {
|
|
||||||
return lineLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param lineLength the lineLength to set
|
|
||||||
*/
|
|
||||||
public void setLineLength(Integer lineLength) {
|
|
||||||
this.lineLength = lineLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the line
|
|
||||||
*/
|
|
||||||
public String getLine() {
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param line the line to set
|
|
||||||
*/
|
|
||||||
public void setLine(String line) {
|
|
||||||
this.line = line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper class that leverages java's MessageDigest to hash files
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class HashUtils {
|
|
||||||
|
|
||||||
private static final Charset UTF_8 = StandardCharsets.UTF_8;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to build output as Hex
|
|
||||||
*/
|
|
||||||
private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to build output as Hex
|
|
||||||
*/
|
|
||||||
private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Size of the streaming buffer
|
|
||||||
*/
|
|
||||||
public static final Integer STREAM_BUFFER_LENGTH = 1024;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash a string literal
|
|
||||||
*
|
|
||||||
* @param hashType Hash types supported by MessageDigest (i.e MD5, SHA-1, SHA-512)
|
|
||||||
* @param data String to hash
|
|
||||||
* @return hash value of the string literal
|
|
||||||
*/
|
|
||||||
public static String hash(String hashType, String data) {
|
|
||||||
return hash(hashType, data, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash a string literal
|
|
||||||
*
|
|
||||||
* @param hashType Hash types supported by MessageDigest (i.e., MD5, SHA-1, SHA-512)
|
|
||||||
* @param data String to hash
|
|
||||||
* @param toLower True to output the hash in lower case. False to output in the upper case
|
|
||||||
* @return hash value of the string literal
|
|
||||||
*/
|
|
||||||
public static String hash(String hashType, String data, boolean toLower) {
|
|
||||||
byte[] stringData = data.getBytes(UTF_8);
|
|
||||||
return hash(hashType, stringData, toLower);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static String hash(String hashType, File data) {
|
|
||||||
return hash(hashType, data.toPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash a file
|
|
||||||
*
|
|
||||||
* @param hashType Hash types supported by MessageDigest (i.e MD5, SHA-1, SHA-512)
|
|
||||||
* @param data File to hash
|
|
||||||
* @return hash value of the file
|
|
||||||
*/
|
|
||||||
public static String hash(String hashType, Path data) {
|
|
||||||
return hash(hashType, data, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static String hash(String hashType, File data, boolean toLower) {
|
|
||||||
return hash(hashType, data.toPath(), toLower);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash a file
|
|
||||||
*
|
|
||||||
* @param hashType Hash types supported by MessageDigest (i.e MD5, SHA-1, SHA-512)
|
|
||||||
* @param data File to hash
|
|
||||||
* @param toLower True to output the hash in lower case. False to output in upper case
|
|
||||||
* @return hash value of the file
|
|
||||||
*/
|
|
||||||
public static String hash(String hashType, Path data, boolean toLower) {
|
|
||||||
try (InputStream stream = Files.newInputStream(data)) {
|
|
||||||
return hash(stream, hashType, toLower);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new IllegalArgumentException(ex.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash a byte array
|
|
||||||
*
|
|
||||||
* @param hashType Hash types supported by MessageDigest (i.e MD5, SHA-1, SHA-512)
|
|
||||||
* @param data data to hash
|
|
||||||
* @return hash value of the data
|
|
||||||
*/
|
|
||||||
public static String hash(String hashType, byte[] data) {
|
|
||||||
return hash(hashType, data, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash a byte array
|
|
||||||
*
|
|
||||||
* @param hashType Hash types supported by MessageDigest (i.e MD5, SHA-1, SHA-512)
|
|
||||||
* @param data data to hash
|
|
||||||
* @param toLower True to output the hash in lower case. False to output in upper case
|
|
||||||
* @return hash value of the data
|
|
||||||
*/
|
|
||||||
public static String hash(String hashType, byte[] data, boolean toLower) {
|
|
||||||
return hash(new BufferedInputStream(new ByteArrayInputStream(data)), hashType, toLower);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash an input stream
|
|
||||||
*
|
|
||||||
* @param stream Stream with the data to hash
|
|
||||||
* @param hashType Hash types supported by MessageDigest (i.e MD5, SHA-1, SHA-512)
|
|
||||||
* @return Hash value of the input stream
|
|
||||||
*/
|
|
||||||
public static String hash(InputStream stream, String hashType) {
|
|
||||||
return hash(stream, hashType, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash an input stream
|
|
||||||
*
|
|
||||||
* @param stream Stream with the data to hash
|
|
||||||
* @param hashType Hash types supported by MessageDigest (i.e MD5, SHA-1, SHA-512)
|
|
||||||
* @param toLower True to output the hash in lower case. False to output in upper case
|
|
||||||
* @return Hash value of the input stream
|
|
||||||
*/
|
|
||||||
public static String hash(InputStream stream, String hashType, boolean toLower) {
|
|
||||||
MessageDigest digest = null;
|
|
||||||
try (InputStream is = stream) {
|
|
||||||
digest = MessageDigest.getInstance(hashType);
|
|
||||||
|
|
||||||
byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
|
|
||||||
int read = is.read(buffer, 0, STREAM_BUFFER_LENGTH);
|
|
||||||
|
|
||||||
while (read > -1) {
|
|
||||||
digest.update(buffer, 0, read);
|
|
||||||
read = is.read(buffer, 0, STREAM_BUFFER_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
return encodeHexString(digest.digest(), toLower);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new IllegalArgumentException(ex.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode the hash data back to a string
|
|
||||||
*
|
|
||||||
* @param data Data to encode
|
|
||||||
* @param toLower output to lower case
|
|
||||||
* @return encoded string
|
|
||||||
*/
|
|
||||||
private static String encodeHexString(byte[] data, boolean toLower) {
|
|
||||||
return new String(encodeHex(data, toLower));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode the hash data to a character array
|
|
||||||
*
|
|
||||||
* @param data Data to encode
|
|
||||||
* @param toLower output to lower case
|
|
||||||
* @return encoded character array
|
|
||||||
*/
|
|
||||||
private static char[] encodeHex(byte[] data, boolean toLower) {
|
|
||||||
return encodeHex(data, toLower ? DIGITS_LOWER : DIGITS_UPPER);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode the hex to a character array
|
|
||||||
*
|
|
||||||
* @param data Data to encode
|
|
||||||
* @param toDigits digits to use
|
|
||||||
* @return encoded character array
|
|
||||||
*/
|
|
||||||
private static char[] encodeHex(byte[] data, char[] toDigits) {
|
|
||||||
int l = data.length;
|
|
||||||
char[] out = new char[l << 1];
|
|
||||||
// two characters form the hex value.
|
|
||||||
for (int i = 0, j = 0; i < l; i++) {
|
|
||||||
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
|
|
||||||
out[j++] = toDigits[0x0F & data[i]];
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Object Utils. Functions to perform on objects
|
|
||||||
*/
|
|
||||||
public class ObjectUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform an action if an object is not null otherwise do nothing.
|
|
||||||
*
|
|
||||||
* @param object the object to test
|
|
||||||
* @param consumer the consumer to perform.
|
|
||||||
* @param <T> the type
|
|
||||||
*/
|
|
||||||
public static <T> void performIfNotNull(T object, Consumer<T> consumer) {
|
|
||||||
if (Objects.isNull(object)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
consumer.accept(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InputStream getResourceStream(String resourceName) {
|
|
||||||
InputStream is = ObjectUtils.class.getResourceAsStream(resourceName);
|
|
||||||
if (is == null) {
|
|
||||||
is = ObjectUtils.class.getClassLoader().getResourceAsStream(resourceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is == null) {
|
|
||||||
throw new NullPointerException("Unable to find resource with name of " + resourceName);
|
|
||||||
}
|
|
||||||
return is;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import static net.locusworks.common.Charsets.UTF_8;
|
|
||||||
|
|
||||||
public class RandomString {
|
|
||||||
|
|
||||||
public static final String LOWER = "abcdefghijklmnopqrstuvwxyz";
|
|
||||||
public static final String UPPER = LOWER.toUpperCase();
|
|
||||||
public static final String DIGITS = "0123456789";
|
|
||||||
|
|
||||||
public static final String ALPHA_NUMERIC = LOWER + UPPER + DIGITS;
|
|
||||||
|
|
||||||
private Random random;
|
|
||||||
|
|
||||||
private char[] symbols;
|
|
||||||
|
|
||||||
private static RandomString instance;
|
|
||||||
|
|
||||||
private RandomString() {
|
|
||||||
Random random;
|
|
||||||
try {
|
|
||||||
random = SecureRandom.getInstance("SHA1PRNG");
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
random = new SecureRandom();
|
|
||||||
}
|
|
||||||
init(random);
|
|
||||||
}
|
|
||||||
|
|
||||||
private RandomString(Random random) {
|
|
||||||
init(random);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init(Random random) {
|
|
||||||
this.random = Objects.requireNonNull(random, "Random generator cannot be null");
|
|
||||||
this.symbols = ALPHA_NUMERIC.toCharArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String nextString(int length) {
|
|
||||||
if (length < 1) throw new IllegalArgumentException("String Length has to be greater than 0");
|
|
||||||
char[] buffer = new char[length];
|
|
||||||
for (int index = 0; index < buffer.length; index++) {
|
|
||||||
buffer[index] = symbols[random.nextInt(symbols.length)];
|
|
||||||
}
|
|
||||||
return new String(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getString(Integer length) {
|
|
||||||
return this.nextString(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes(Integer length) {
|
|
||||||
return getString(length).getBytes(UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RandomString getInstance() {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new RandomString();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RandomString newInstance() {
|
|
||||||
instance = new RandomString();
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RandomString newInstance(Random random) {
|
|
||||||
instance = new RandomString(random);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,195 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static net.locusworks.common.utils.Checks.checkArguments;
|
|
||||||
import static net.locusworks.common.utils.Checks.checkNotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to help split a string in various ways.
|
|
||||||
* By partition (fixed length split) or by sequence (look for a specific string sequence).
|
|
||||||
* it can also split on new line or not.
|
|
||||||
*/
|
|
||||||
public class Splitter {
|
|
||||||
private enum SplitterType {
|
|
||||||
PARTITION,
|
|
||||||
SEQUENCE
|
|
||||||
}
|
|
||||||
|
|
||||||
private String splitSeq;
|
|
||||||
private boolean omitEmptyStrings = false;
|
|
||||||
private int partition;
|
|
||||||
private int limit;
|
|
||||||
private final SplitterType splitterType;
|
|
||||||
private static Splitter splitter;
|
|
||||||
|
|
||||||
private Splitter(String seq) {
|
|
||||||
this.splitSeq = seq;
|
|
||||||
this.splitterType = SplitterType.SEQUENCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Splitter(int partition) {
|
|
||||||
this.partition = partition;
|
|
||||||
this.splitterType = SplitterType.PARTITION;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove empty string from the resulting lists
|
|
||||||
*
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public Splitter omitEmptyStrings() {
|
|
||||||
this.omitEmptyStrings = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a subset of the resulting list
|
|
||||||
*
|
|
||||||
* @param limit how many items to retrieve
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public Splitter withLimit(int limit) {
|
|
||||||
this.limit = limit;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an array instead of a list
|
|
||||||
*
|
|
||||||
* @param sentence the string sentence to split
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public String[] splitToArray(String sentence) {
|
|
||||||
List<String> list = split(sentence);
|
|
||||||
return list.toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Split the string
|
|
||||||
*
|
|
||||||
* @param sentence the string to split
|
|
||||||
* @return the resulting list.
|
|
||||||
*/
|
|
||||||
public List<String> split(String sentence) {
|
|
||||||
checkArguments(!Utils.isEmptyString(sentence), "provided value is null or empty");
|
|
||||||
List<String> list = new ArrayList<>();
|
|
||||||
|
|
||||||
if (splitterType == SplitterType.PARTITION) {
|
|
||||||
populateForFixedWidth(sentence, list);
|
|
||||||
} else {
|
|
||||||
populateForTrimmer(sentence, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
return limit > 0 ? list.subList(0, limit) : list;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void populateForFixedWidth(String sentence, List<String> list) {
|
|
||||||
checkArguments(partition > 0, "Partition should be greater than 0");
|
|
||||||
int strLength = sentence.length();
|
|
||||||
for (int i = 0; i < strLength; i += partition) {
|
|
||||||
list.add(sentence.substring(i, Math.min(strLength, i + partition)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void populateForTrimmer(String sentence, List<String> list) {
|
|
||||||
checkNotNull(splitSeq, "Split value provided was null");
|
|
||||||
for (String s : sentence.split(splitSeq)) {
|
|
||||||
if (omitEmptyStrings && s.trim().isEmpty())
|
|
||||||
continue;
|
|
||||||
list.add(s.trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Split the string on fixed length partitions
|
|
||||||
*
|
|
||||||
* @param partition the length to split the string on
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public static Splitter fixedLengthSplit(int partition) {
|
|
||||||
splitter = new Splitter(partition);
|
|
||||||
return splitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Split the length on a specified string sequence
|
|
||||||
*
|
|
||||||
* @param split the sequence to split
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public static Splitter on(String split) {
|
|
||||||
splitter = new Splitter(split);
|
|
||||||
return splitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Split on new line sequence
|
|
||||||
*
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public static Splitter onNewLine() {
|
|
||||||
return on("\\r?\\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Split on spaces
|
|
||||||
*
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public static Splitter onSpace() {
|
|
||||||
return on(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Separator on what the key value is. return map
|
|
||||||
*
|
|
||||||
* @param separator the separator value
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public MapSplitter withKeyValueSeparator(String separator) {
|
|
||||||
return new MapSplitter(this, separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class MapSplitter {
|
|
||||||
|
|
||||||
private final Splitter splitter;
|
|
||||||
private final String separator;
|
|
||||||
private boolean skipInvalid = false;
|
|
||||||
|
|
||||||
private MapSplitter(Splitter splitter, String separator) {
|
|
||||||
checkNotNull(splitter, "Splitter cannot be null");
|
|
||||||
checkArguments(!Utils.isEmptyString(separator),
|
|
||||||
"Key value separator cannot be empty or null");
|
|
||||||
this.splitter = splitter;
|
|
||||||
this.separator = separator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MapSplitter skipInvalidKeyValues() {
|
|
||||||
this.skipInvalid = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> split(String sentence) {
|
|
||||||
checkArguments(!Utils.isEmptyString(sentence), "provided value is null or empty");
|
|
||||||
Map<String, String> map = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
for (String s : splitter.split(sentence)) {
|
|
||||||
String[] keyValue = s.split(separator);
|
|
||||||
try {
|
|
||||||
checkArguments(keyValue.length == 2, "invalid length found for key value mapping");
|
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
if (!skipInvalid)
|
|
||||||
throw ex;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
map.put(keyValue[0], keyValue[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
import java.util.stream.StreamSupport;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class to make iterators streamable
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
* @date 02/15/2018
|
|
||||||
*/
|
|
||||||
public class StreamUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an iterator to a stream
|
|
||||||
*
|
|
||||||
* @param iterator the iterator to convert
|
|
||||||
* @param <T> the class type
|
|
||||||
* @return stream of the iterator
|
|
||||||
*/
|
|
||||||
public static <T> Stream<T> asStream(Iterator<T> iterator) {
|
|
||||||
return asStream(iterator, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Stream<T> asStream(Iterable<T> iterable) {
|
|
||||||
return asStream(iterable, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an array to a stream
|
|
||||||
*
|
|
||||||
* @param items the items to convert
|
|
||||||
* @param <T> the class type
|
|
||||||
* @return stream of the array
|
|
||||||
*/
|
|
||||||
public static <T> Stream<T> asStream(T[] items) {
|
|
||||||
return asStream(Arrays.asList(items).iterator(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an array to a stream
|
|
||||||
*
|
|
||||||
* @param items the items to convert
|
|
||||||
* @param parallel make the stream parallel if set to true
|
|
||||||
* @param <T> the class type
|
|
||||||
* @return stream of the array
|
|
||||||
*/
|
|
||||||
public static <T> Stream<T> asStream(T[] items, boolean parallel) {
|
|
||||||
return asStream(Arrays.asList(items).iterator(), parallel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Stream<T> asStream(Iterable<T> iterable, boolean parallel) {
|
|
||||||
return StreamSupport.stream(iterable.spliterator(), parallel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an iterator to a stream
|
|
||||||
*
|
|
||||||
* @param iterator iterator to convert
|
|
||||||
* @param parallel make the stream parallel if set to true.
|
|
||||||
* @param <T> the class type
|
|
||||||
* @return stream of the iterator
|
|
||||||
*/
|
|
||||||
public static <T> Stream<T> asStream(Iterator<T> iterator, boolean parallel) {
|
|
||||||
Iterable<T> iterable = () -> iterator;
|
|
||||||
return StreamSupport.stream(iterable.spliterator(), parallel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Success class to return data back to the client
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @version 1.0.0
|
|
||||||
* @date 02/15/2018
|
|
||||||
*/
|
|
||||||
public class Success {
|
|
||||||
private boolean success = true;
|
|
||||||
private final Object body;
|
|
||||||
|
|
||||||
protected Success() {
|
|
||||||
this(true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Success(boolean success) {
|
|
||||||
this(success, success);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Success(boolean success, Object body) {
|
|
||||||
this.success = success;
|
|
||||||
this.body = body;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getBody() {
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getSuccess() {
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Success success() {
|
|
||||||
return new Success();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Success fail() {
|
|
||||||
return new Success(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Configuration status="WARN">
|
|
||||||
<Appenders>
|
|
||||||
<Console name="ConsoleAppender" target="SYSTEM_OUT">
|
|
||||||
<PatternLayout pattern="%d{dd-MMM-yyyy HH:mm:ss.SSS} %m%n" />
|
|
||||||
</Console>
|
|
||||||
<RollingFile name="application" fileName="application.log"
|
|
||||||
filePattern="$${date:yyyy-MM}/${name}-%d{yyyy-MM-dd}-%i.log.gz">
|
|
||||||
<PatternLayout>
|
|
||||||
<pattern>%d{dd-MMM-yyyy HH:mm:ss.SSS} %m%n</pattern>
|
|
||||||
</PatternLayout>
|
|
||||||
<Policies>
|
|
||||||
<TimeBasedTriggeringPolicy />
|
|
||||||
<SizeBasedTriggeringPolicy size="10 MB" />
|
|
||||||
</Policies>
|
|
||||||
</RollingFile>
|
|
||||||
</Appenders>
|
|
||||||
<Loggers>
|
|
||||||
<Root level="INFO">
|
|
||||||
<AppenderRef ref="ConsoleAppender" />
|
|
||||||
<AppenderRef ref="application" />
|
|
||||||
</Root>
|
|
||||||
</Loggers>
|
|
||||||
</Configuration>
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
package net.locusworks.common.configuration;
|
|
||||||
|
|
||||||
import net.locusworks.common.exceptions.ApplicationException;
|
|
||||||
import net.locusworks.common.interfaces.PersistableRequest;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.mockito.Mockito.CALLS_REAL_METHODS;
|
|
||||||
import static org.mockito.Mockito.mockStatic;
|
|
||||||
|
|
||||||
import org.mockito.MockedStatic;
|
|
||||||
|
|
||||||
class ConfigurationCoverageTest {
|
|
||||||
@TempDir
|
|
||||||
Path tempDir;
|
|
||||||
|
|
||||||
static class Manager extends ConfigurationManager {
|
|
||||||
void initialize(Path base, byte[] key, ConfigurationCallback callback) throws Exception {
|
|
||||||
init(base.toString(), "test.properties", key, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initialize(Path base, ConfigurationCallback callback) throws Exception {
|
|
||||||
init(base.toString(), "test.properties", callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class Request implements PersistableRequest {
|
|
||||||
private String dbHost;
|
|
||||||
private String dbPort;
|
|
||||||
private String ignored;
|
|
||||||
|
|
||||||
Request(String dbHost, String dbPort, String ignored) {
|
|
||||||
this.dbHost = dbHost;
|
|
||||||
this.dbPort = dbPort;
|
|
||||||
this.ignored = ignored;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void managerCreatesLoadsReconcilesSavesAndReportsConfiguration() throws Exception {
|
|
||||||
List<String> messages = new ArrayList<>();
|
|
||||||
Manager manager = new Manager();
|
|
||||||
manager.initialize(tempDir, "seed".getBytes(), messages::add);
|
|
||||||
|
|
||||||
assertEquals("localhost", manager.getPropertyValue("dbHost"));
|
|
||||||
assertEquals("fallback", manager.getPropertyValue("missing", "fallback"));
|
|
||||||
assertNull(manager.getPropertyValue("missing"));
|
|
||||||
assertEquals(4, manager.getConfiguration().size());
|
|
||||||
assertTrue(Files.exists(tempDir.resolve("test.properties")));
|
|
||||||
assertTrue(messages.stream().anyMatch(m -> m.contains("Added new configuration")));
|
|
||||||
|
|
||||||
Properties changed = new Properties();
|
|
||||||
changed.putAll(manager.getConfiguration());
|
|
||||||
changed.setProperty("dbHost", "remote");
|
|
||||||
changed.setProperty("obsolete", "remove me");
|
|
||||||
manager.saveToConf(changed);
|
|
||||||
assertEquals("remote", manager.getPropertyValue("dbHost"));
|
|
||||||
assertFalse(manager.getConfiguration().containsKey("obsolete"));
|
|
||||||
assertTrue(messages.stream().anyMatch(m -> m.contains("Saved config file")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void managerPersistsSelectedPlainAndEncryptedFieldsAndSkipsUnchangedOnes() throws Exception {
|
|
||||||
Manager manager = new Manager();
|
|
||||||
manager.initialize(tempDir, new byte[0], null);
|
|
||||||
|
|
||||||
assertThrows(ApplicationException.class,
|
|
||||||
() -> manager.saveConfiguration(new Request("x", "1", "x"), null, null));
|
|
||||||
assertThrows(ApplicationException.class,
|
|
||||||
() -> manager.saveConfiguration(new Request("x", "1", "x"), Set.of(), null));
|
|
||||||
|
|
||||||
manager.saveConfiguration(new Request("new-host", "3306", "ignored"),
|
|
||||||
Set.of("dbHost", "dbPort"), null);
|
|
||||||
assertEquals("new-host", manager.getPropertyValue("dbHost"));
|
|
||||||
assertEquals("3306", manager.getPropertyValue("dbPort"));
|
|
||||||
|
|
||||||
manager.saveConfiguration(new Request("encrypted-host", "3306", "ignored"),
|
|
||||||
Set.of("dbHost", "dbPort", "ignored"), Set.of("dbHost"));
|
|
||||||
assertNotEquals("encrypted-host", manager.getPropertyValue("dbHost"));
|
|
||||||
|
|
||||||
assertThrows(ApplicationException.class,
|
|
||||||
() -> manager.saveConfiguration(null, Set.of("dbHost"), Set.of()));
|
|
||||||
|
|
||||||
assertDoesNotThrow(() -> manager.saveConfiguration(
|
|
||||||
new Request("ignored", "3306", "ignored"), Set.of("dbPort"), Set.of()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void managerConvenienceInitializationAndBothLoadFailuresAreCovered() throws Exception {
|
|
||||||
Path convenience = Files.createDirectory(tempDir.resolve("convenience"));
|
|
||||||
Manager normal = new Manager();
|
|
||||||
normal.initialize(convenience, null);
|
|
||||||
assertNotNull(normal.getConfiguration());
|
|
||||||
|
|
||||||
try (MockedStatic<PropertiesManager> properties = mockStatic(PropertiesManager.class, CALLS_REAL_METHODS)) {
|
|
||||||
properties.when(() -> PropertiesManager.loadConfiguration(Manager.class, "test.properties"))
|
|
||||||
.thenThrow(new java.io.IOException("template failed"));
|
|
||||||
assertThrows(java.io.IOException.class,
|
|
||||||
() -> new Manager().initialize(tempDir, "seed".getBytes(), null));
|
|
||||||
}
|
|
||||||
|
|
||||||
Path activeFailure = Files.createDirectory(tempDir.resolve("active-failure"));
|
|
||||||
try (MockedStatic<PropertiesManager> properties = mockStatic(PropertiesManager.class, CALLS_REAL_METHODS)) {
|
|
||||||
Path activeFile = activeFailure.resolve("test.properties");
|
|
||||||
properties.when(() -> PropertiesManager.loadConfiguration(activeFile))
|
|
||||||
.thenThrow(new java.io.IOException("active failed"));
|
|
||||||
Manager recovered = new Manager();
|
|
||||||
recovered.initialize(activeFailure, "seed".getBytes(), null);
|
|
||||||
assertEquals(4, recovered.getConfiguration().size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Test
|
|
||||||
void propertiesManagerCoversResourcesFilesReadersMergeRemovalAndSaveFailures() throws Exception {
|
|
||||||
assertNotNull(new PropertiesManager());
|
|
||||||
assertNull(PropertiesManager.loadConfiguration(getClass(), "missing.properties"));
|
|
||||||
Properties resource = PropertiesManager.loadConfiguration(getClass(), "/test.properties");
|
|
||||||
assertEquals(4, resource.size());
|
|
||||||
|
|
||||||
Path missing = tempDir.resolve("missing.properties");
|
|
||||||
assertTrue(PropertiesManager.loadConfiguration(missing).isEmpty());
|
|
||||||
|
|
||||||
Properties parsed = PropertiesManager.loadConfiguration(
|
|
||||||
new BufferedReader(new StringReader("one=1\ntwo=2")));
|
|
||||||
assertEquals("1", parsed.getProperty("one"));
|
|
||||||
|
|
||||||
Properties destination = new Properties();
|
|
||||||
destination.setProperty("one", "existing");
|
|
||||||
Properties additions = new Properties();
|
|
||||||
additions.setProperty("one", "replacement");
|
|
||||||
additions.setProperty("two", "2");
|
|
||||||
assertEquals(1, PropertiesManager.addConfiguration(destination, additions).size());
|
|
||||||
assertEquals("existing", destination.getProperty("one"));
|
|
||||||
|
|
||||||
destination.setProperty("obsolete", "old");
|
|
||||||
Properties expected = new Properties();
|
|
||||||
expected.setProperty("one", "existing");
|
|
||||||
assertEquals(2, PropertiesManager.removeConfiguration(destination, expected).size());
|
|
||||||
assertEquals(Set.of("one"), destination.keySet());
|
|
||||||
|
|
||||||
Path saved = tempDir.resolve("saved.properties");
|
|
||||||
PropertiesManager.saveConfiguration(expected, saved.toFile(), null);
|
|
||||||
assertEquals("existing", PropertiesManager.loadConfiguration(saved.toFile()).getProperty("one"));
|
|
||||||
assertThrows(RuntimeException.class,
|
|
||||||
() -> PropertiesManager.saveConfiguration(expected, tempDir, "failure"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
package net.locusworks.common.crypto;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
|
|
||||||
class AESAndHashSaltCoverageTest {
|
|
||||||
@Test
|
|
||||||
void aesFactoriesSeedChangesEmptyValuesAndFailures() throws Exception {
|
|
||||||
AES bytes = AES.createInstance("byte seed".getBytes());
|
|
||||||
assertEquals("byte seed", bytes.getSeed());
|
|
||||||
assertEquals("", bytes.decrypt(bytes.encrypt(null)));
|
|
||||||
assertEquals("", bytes.decrypt(null));
|
|
||||||
|
|
||||||
String encrypted = bytes.encrypt("value");
|
|
||||||
assertSame(bytes, bytes.withSeed("byte seed"));
|
|
||||||
assertEquals("value", bytes.decrypt(encrypted));
|
|
||||||
assertSame(bytes, bytes.withSeed("different seed"));
|
|
||||||
assertEquals("different seed", bytes.getSeed());
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> bytes.decrypt(encrypted));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> bytes.decrypt("AA=="));
|
|
||||||
assertNotNull(AES.createInstance());
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> AES.createInstance((String) null));
|
|
||||||
|
|
||||||
AES uninitialized = new AES();
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> uninitialized.encrypt("value"));
|
|
||||||
Method init = AES.class.getDeclaredMethod("init", byte[].class);
|
|
||||||
init.setAccessible(true);
|
|
||||||
InvocationTargetException initFailure = assertThrows(InvocationTargetException.class,
|
|
||||||
() -> init.invoke(uninitialized, (Object) new byte[16]));
|
|
||||||
assertInstanceOf(IllegalArgumentException.class, initFailure.getCause());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void aesMainValidatesArgumentsAndSupportsEncryptAndDecryptModes() throws Exception {
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> AES.main(null));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> AES.main(new String[0]));
|
|
||||||
assertDoesNotThrow(() -> AES.main(new String[]{"plain"}));
|
|
||||||
|
|
||||||
AES aes = AES.createInstance("seed");
|
|
||||||
assertDoesNotThrow(() -> AES.main(new String[]{aes.encrypt("plain"), "seed"}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void hashSaltSupportsStringAndCharacterPasswordsAndInvalidInputs() throws Exception {
|
|
||||||
assertNotNull(new HashSalt());
|
|
||||||
String hash = HashSalt.createHash("password".toCharArray());
|
|
||||||
assertTrue(HashSalt.validatePassword("password".toCharArray(), hash));
|
|
||||||
assertFalse(HashSalt.validatePassword("wrong", hash));
|
|
||||||
assertFalse(HashSalt.validatePassword("wrong".toCharArray(), hash));
|
|
||||||
assertThrows(RuntimeException.class, () -> HashSalt.validatePassword("password", "bad"));
|
|
||||||
|
|
||||||
Method toHex = HashSalt.class.getDeclaredMethod("toHex", byte[].class);
|
|
||||||
toHex.setAccessible(true);
|
|
||||||
assertEquals("0001", toHex.invoke(null, (Object) new byte[]{0, 1}));
|
|
||||||
|
|
||||||
Method slowEquals = HashSalt.class.getDeclaredMethod("slowEquals", byte[].class, byte[].class);
|
|
||||||
slowEquals.setAccessible(true);
|
|
||||||
assertEquals(false, slowEquals.invoke(null, new byte[]{1}, new byte[]{1, 2}));
|
|
||||||
assertEquals(false, slowEquals.invoke(null, new byte[]{1, 2}, new byte[]{1}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void hashSaltMainValidatesArgumentsAndPrintsHash() {
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> HashSalt.main(null));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> HashSalt.main(new String[0]));
|
|
||||||
assertDoesNotThrow(() -> HashSalt.main(new String[]{"password"}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
package net.locusworks.common.crypto;
|
|
||||||
|
|
||||||
import net.locusworks.common.crypto.KeyFile.EncryptionType;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.mockito.Mockito.CALLS_REAL_METHODS;
|
|
||||||
import static org.mockito.Mockito.mockStatic;
|
|
||||||
|
|
||||||
import org.mockito.MockedStatic;
|
|
||||||
|
|
||||||
class CryptoCoverageTest {
|
|
||||||
@TempDir
|
|
||||||
Path tempDir;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void aesKeyAndSpecRoundTripAndRejectMalformedData() throws Exception {
|
|
||||||
AESKey key = new AESKey("repeatable seed");
|
|
||||||
assertEquals("aes", key.getAlgorithm());
|
|
||||||
assertEquals("aes-seed", key.getFormat());
|
|
||||||
assertArrayEquals("repeatable seed".getBytes(StandardCharsets.UTF_8), key.getEncoded());
|
|
||||||
|
|
||||||
String encoded = "aes-seed " + Base64.getEncoder().encodeToString(key.getEncoded());
|
|
||||||
AESKeySpec spec = new AESKeySpec(encoded.getBytes(StandardCharsets.UTF_8));
|
|
||||||
assertEquals("aes", spec.getFormat());
|
|
||||||
assertArrayEquals(key.getEncoded(), spec.generateKey().getEncoded());
|
|
||||||
assertThrows(InvalidKeySpecException.class,
|
|
||||||
() -> new AESKeySpec("wrong value".getBytes(StandardCharsets.UTF_8)).generateKey());
|
|
||||||
assertThrows(InvalidKeySpecException.class,
|
|
||||||
() -> new AESKeySpec("aes-seed !!!".getBytes(StandardCharsets.UTF_8)).generateKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void encryptionKeyFactoryHandlesAesRsaAndSshSpecs() throws Exception {
|
|
||||||
EncryptionKeyFactory factory = EncryptionKeyFactory.getInstance("RSA");
|
|
||||||
String aes = "aes-seed " + Base64.getEncoder().encodeToString("seed".getBytes(StandardCharsets.UTF_8));
|
|
||||||
assertInstanceOf(AESKey.class, factory.generatePrivateKey(new AESKeySpec(aes.getBytes(StandardCharsets.UTF_8))));
|
|
||||||
|
|
||||||
KeyPair pair = RSA.generateKeyPair(1024);
|
|
||||||
assertEquals(pair.getPrivate(), factory.generatePrivateKey(
|
|
||||||
new java.security.spec.PKCS8EncodedKeySpec(pair.getPrivate().getEncoded())));
|
|
||||||
assertEquals(pair.getPublic(), factory.generatePublicKey(
|
|
||||||
new java.security.spec.X509EncodedKeySpec(pair.getPublic().getEncoded())));
|
|
||||||
|
|
||||||
Path ssh = tempDir.resolve("public.ssh");
|
|
||||||
try (KeyFile file = new KeyFile(pair.getPublic(), "test", EncryptionType.SSH)) {
|
|
||||||
file.write(ssh.toString());
|
|
||||||
}
|
|
||||||
SSHEncodedKeySpec sshSpec = new SSHEncodedKeySpec(Files.readAllBytes(ssh));
|
|
||||||
assertNull(sshSpec.getFormat());
|
|
||||||
assertEquals(pair.getPublic(), factory.generatePublicKey(sshSpec));
|
|
||||||
assertEquals(pair.getPublic(), KeyFile.read(ssh.toString()).getKey());
|
|
||||||
assertThrows(InvalidKeySpecException.class,
|
|
||||||
() -> new SSHEncodedKeySpec("ssh-ed25519 bad".getBytes(StandardCharsets.UTF_8)).convertToRSAPubKeySpec());
|
|
||||||
assertThrows(InvalidKeySpecException.class,
|
|
||||||
() -> new SSHEncodedKeySpec("ssh-rsa !!!".getBytes(StandardCharsets.UTF_8)).convertToRSAPubKeySpec());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void rsaGeneratesCalculatesEncryptsDecryptsAndRejectsOversizedMessages() {
|
|
||||||
assertNotNull(new RSA());
|
|
||||||
KeyPair defaultPair = RSA.generateKeyPair();
|
|
||||||
assertNotNull(defaultPair.getPrivate());
|
|
||||||
KeyPair pair = RSA.generateKeyPair(1024);
|
|
||||||
assertEquals(("hello".getBytes(StandardCharsets.UTF_8).length + 11) * 8,
|
|
||||||
RSA.calculateRequiredKeyLength("hello"));
|
|
||||||
|
|
||||||
String encrypted = RSA.encrypt(pair.getPublic(), "hello RSA");
|
|
||||||
assertEquals("hello RSA", RSA.decrypt(pair.getPrivate(), encrypted));
|
|
||||||
assertThrows(RuntimeException.class, () -> RSA.decrypt(pair.getPrivate(), "not base64"));
|
|
||||||
assertThrows(RuntimeException.class, () -> RSA.encrypt(pair.getPublic(), "x".repeat(200)));
|
|
||||||
assertThrows(RuntimeException.class, () -> RSA.generateKeyPair(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void keyFileWritesAesPemAndSshFormatsAndProvidesDescriptions() throws Exception {
|
|
||||||
AESKey aesKey = new AESKey("seed");
|
|
||||||
Path aesPath = tempDir.resolve("aes.key");
|
|
||||||
try (KeyFile file = new KeyFile(aesKey)) {
|
|
||||||
assertEquals("PRIVATE KEY", file.getDescription());
|
|
||||||
file.setDescription("AES KEY");
|
|
||||||
assertEquals("AES KEY", file.getDescription());
|
|
||||||
assertSame(aesKey, file.getKey());
|
|
||||||
file.write(aesPath.toString());
|
|
||||||
}
|
|
||||||
assertEquals("aes-seed c2VlZA==", Files.readString(aesPath));
|
|
||||||
|
|
||||||
KeyPair pair = RSA.generateKeyPair(1024);
|
|
||||||
Path privatePath = tempDir.resolve("private.pem");
|
|
||||||
try (KeyFile file = new KeyFile(pair.getPrivate())) {
|
|
||||||
file.write(privatePath.toString());
|
|
||||||
}
|
|
||||||
assertTrue(Files.readString(privatePath).contains("BEGIN RSA PRIVATE KEY"));
|
|
||||||
|
|
||||||
Path publicPath = tempDir.resolve("public.pem");
|
|
||||||
try (KeyFile file = new KeyFile(pair.getPublic(), "CUSTOM")) {
|
|
||||||
file.write(publicPath.toString());
|
|
||||||
}
|
|
||||||
assertTrue(Files.readString(publicPath).contains("BEGIN RSA CUSTOM"));
|
|
||||||
assertEquals("PUBLIC KEY", new KeyFile(pair.getPublic()).getDescription());
|
|
||||||
|
|
||||||
Path sshPath = tempDir.resolve("id.pub");
|
|
||||||
try (KeyFile file = new KeyFile(pair.getPublic(), "comment", EncryptionType.SSH)) {
|
|
||||||
file.write(sshPath.toString());
|
|
||||||
}
|
|
||||||
assertTrue(Files.readString(sshPath).startsWith("ssh-rsa "));
|
|
||||||
assertTrue(Files.readString(sshPath).endsWith(" comment"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void keyFileReadHandlesEmptyMissingRecognizedAndInvalidFiles() throws Exception {
|
|
||||||
assertNull(KeyFile.read(null).getKey());
|
|
||||||
RuntimeException missing = assertThrows(RuntimeException.class,
|
|
||||||
() -> KeyFile.read(tempDir.resolve("missing").toString()));
|
|
||||||
assertInstanceOf(IllegalArgumentException.class, missing.getCause());
|
|
||||||
|
|
||||||
Path aesPath = tempDir.resolve("recognized-aes.key");
|
|
||||||
new KeyFile(new AESKey("seed")).write(aesPath.toString());
|
|
||||||
assertArrayEquals("seed".getBytes(StandardCharsets.UTF_8), KeyFile.read(aesPath.toString()).getKey().getEncoded());
|
|
||||||
|
|
||||||
Path invalid = tempDir.resolve("invalid.key");
|
|
||||||
Files.writeString(invalid, "not a key");
|
|
||||||
assertThrows(RuntimeException.class, () -> KeyFile.read(invalid.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void rsaWriteConvenienceOverloadsUseRequestedPaths() {
|
|
||||||
KeyPair pair = RSA.generateKeyPair(1024);
|
|
||||||
Path privatePath = tempDir.resolve("private.key");
|
|
||||||
Path publicPath = tempDir.resolve("public.key");
|
|
||||||
assertTrue(RSA.writePrivateKey(pair, privatePath.toString(), "PRIVATE KEY"));
|
|
||||||
assertTrue(RSA.writePublicKey(pair, publicPath.toString(), "PUBLIC KEY"));
|
|
||||||
assertTrue(Files.exists(privatePath));
|
|
||||||
assertTrue(Files.exists(publicPath));
|
|
||||||
|
|
||||||
Path sshPath = tempDir.resolve("rsa-ssh.pub");
|
|
||||||
assertTrue(RSA.writePublicKey(pair, sshPath.toString(), "comment", true));
|
|
||||||
|
|
||||||
assertTrue(RSA.generateAndWriteKeyPair(tempDir.resolve("generated").toString(), 1024));
|
|
||||||
assertNotNull(RSA.loadKeyPair(publicPath.toString(), privatePath.toString()));
|
|
||||||
assertNotNull(RSA.loadPublicKey(publicPath.toString()).getPublic());
|
|
||||||
assertNotNull(RSA.loadPrivateKey(privatePath.toString()).getPrivate());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void keyFileWrapsWritePemAndCloseFailures() throws Exception {
|
|
||||||
KeyPair pair = RSA.generateKeyPair(1024);
|
|
||||||
KeyFile invalidWrite = new KeyFile(pair.getPrivate());
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> invalidWrite.write(tempDir.toString()));
|
|
||||||
|
|
||||||
KeyFile closeFailure = new KeyFile(pair.getPrivate());
|
|
||||||
Field writerField = KeyFile.class.getDeclaredField("writer");
|
|
||||||
writerField.setAccessible(true);
|
|
||||||
writerField.set(closeFailure, new Writer() {
|
|
||||||
@Override
|
|
||||||
public void write(char[] cbuf, int off, int len) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() throws IOException {
|
|
||||||
throw new IOException("flush failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
assertThrows(RuntimeException.class, closeFailure::close);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void rsaConvenienceDelegatesAndShortCircuitPaths() {
|
|
||||||
KeyPair pair = RSA.generateKeyPair(1024);
|
|
||||||
try (MockedStatic<RSA> rsa = mockStatic(RSA.class, CALLS_REAL_METHODS)) {
|
|
||||||
rsa.when(RSA::generateKeyPair).thenReturn(pair);
|
|
||||||
rsa.when(() -> RSA.writePrivateKey(pair)).thenReturn(true);
|
|
||||||
rsa.when(() -> RSA.writePublicKey(pair, true)).thenReturn(true);
|
|
||||||
assertTrue(RSA.generateAndWriteSSHKeys());
|
|
||||||
rsa.when(() -> RSA.writePrivateKey(pair)).thenReturn(false);
|
|
||||||
assertFalse(RSA.generateAndWriteSSHKeys());
|
|
||||||
rsa.when(() -> RSA.writePrivateKey(pair)).thenReturn(true);
|
|
||||||
rsa.when(() -> RSA.writePublicKey(pair, true)).thenReturn(false);
|
|
||||||
assertFalse(RSA.generateAndWriteSSHKeys());
|
|
||||||
|
|
||||||
rsa.when(() -> RSA.generateAndWriteKeyPair(2048)).thenReturn(true);
|
|
||||||
assertTrue(RSA.generateAndWriteKeyPair());
|
|
||||||
rsa.when(() -> RSA.generateAndWriteKeyPair("named", 2048)).thenReturn(true);
|
|
||||||
assertTrue(RSA.generateAndWriteKeyPair("named"));
|
|
||||||
rsa.when(() -> RSA.generateAndWriteKeyPair("id_rsa", 1024)).thenReturn(true);
|
|
||||||
assertTrue(RSA.generateAndWriteKeyPair(1024));
|
|
||||||
|
|
||||||
rsa.when(() -> RSA.generateKeyPair(512)).thenReturn(pair);
|
|
||||||
rsa.when(() -> RSA.writePrivateKey(pair, "short", "PRIVATE KEY")).thenReturn(false);
|
|
||||||
assertFalse(RSA.generateAndWriteKeyPair("short", 512));
|
|
||||||
rsa.when(() -> RSA.writePrivateKey(pair, "short", "PRIVATE KEY")).thenReturn(true);
|
|
||||||
rsa.when(() -> RSA.writePublicKey(pair, "short.pub", "PUBLIC KEY")).thenReturn(false);
|
|
||||||
assertFalse(RSA.generateAndWriteKeyPair("short", 512));
|
|
||||||
|
|
||||||
rsa.when(() -> RSA.writePrivateKey(pair, "id_rsa", "PRIVATE KEY")).thenReturn(true);
|
|
||||||
assertTrue(RSA.writePrivateKey(pair));
|
|
||||||
rsa.when(() -> RSA.writePublicKey(pair, false)).thenReturn(true);
|
|
||||||
assertTrue(RSA.writePublicKey(pair));
|
|
||||||
rsa.when(() -> RSA.writePublicKey(pair, "id_rsa.pub", "PUBLIC KEY", true)).thenReturn(true);
|
|
||||||
rsa.when(() -> RSA.writePublicKey(pair, true)).thenCallRealMethod();
|
|
||||||
assertTrue(RSA.writePublicKey(pair, true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package net.locusworks.common.exceptions;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
class ApplicationExceptionTest {
|
|
||||||
@Test
|
|
||||||
void factoryMethodsExposeExpectedCodesAndMessages() {
|
|
||||||
List<ApplicationException> exceptions = List.of(
|
|
||||||
ApplicationException.egregiousServer(), ApplicationException.invalidCreds(),
|
|
||||||
ApplicationException.notLoggedIn(), ApplicationException.invalidEmailAddress(),
|
|
||||||
ApplicationException.actionNotPermitted(), ApplicationException.actionNotPermitted("delete"),
|
|
||||||
ApplicationException.passwordsNotEqual(), ApplicationException.unAuthorized(),
|
|
||||||
ApplicationException.duplicateEntry("duplicate"), ApplicationException.duplicateEntry("duplicate %s", "item"),
|
|
||||||
ApplicationException.noEntryExists("missing"), ApplicationException.noEntryExists("missing %s", "item"),
|
|
||||||
ApplicationException.constraintViolation("constraint"), ApplicationException.constraintViolation("constraint %s", "x"),
|
|
||||||
ApplicationException.illegalArgument("illegal"), ApplicationException.generic("generic"));
|
|
||||||
|
|
||||||
assertTrue(exceptions.stream().noneMatch(ApplicationException::getSuccess));
|
|
||||||
assertTrue(exceptions.stream().allMatch(e -> e.getCode() != null && e.getMessage() != null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void constructorsAndThrowableFactoryPreserveCause() {
|
|
||||||
IllegalStateException cause = new IllegalStateException("failure");
|
|
||||||
ApplicationException fromCause = ApplicationException.fromException(cause);
|
|
||||||
assertEquals(9999, fromCause.getCode());
|
|
||||||
assertSame(cause, fromCause.getCause());
|
|
||||||
|
|
||||||
ApplicationException direct = new ApplicationException(42, cause);
|
|
||||||
assertEquals("failure", direct.getMessage());
|
|
||||||
assertSame(cause, direct.getCause());
|
|
||||||
|
|
||||||
ApplicationException explicit = new ApplicationException(43, "message", cause);
|
|
||||||
assertEquals(43, explicit.getCode());
|
|
||||||
assertSame(cause, explicit.getCause());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
package net.locusworks.common.immutables;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
|
|
||||||
class ImmutablesTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testUnit() {
|
|
||||||
Unit<String> unit1 = new Unit<>();
|
|
||||||
unit1.setValue1("123");
|
|
||||||
|
|
||||||
Unit<String> unit2 = new Unit<>("123");
|
|
||||||
Unit<String> unit3 = new Unit<>("1234");
|
|
||||||
|
|
||||||
assertEquals(unit1, unit2);
|
|
||||||
|
|
||||||
assertNotEquals(null, unit1);
|
|
||||||
assertNotEquals(new Object(), unit1);
|
|
||||||
assertNotEquals(unit3, unit1);
|
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> unit1.setValue1("value"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPair() {
|
|
||||||
Pair<String, String> unit1 = new Pair<>();
|
|
||||||
unit1.setValue2("value2");
|
|
||||||
unit1.setValue1("123");
|
|
||||||
|
|
||||||
Pair<String, String> unit2 = new Pair<>("123", "value2");
|
|
||||||
Pair<String, String> unit3 = new Pair<>("1234", "value2");
|
|
||||||
|
|
||||||
assertEquals(unit1, unit2);
|
|
||||||
|
|
||||||
assertNotEquals(null, unit1);
|
|
||||||
assertNotEquals(new Object(), unit1);
|
|
||||||
assertNotEquals(unit3, unit1);
|
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> unit1.setValue1("value"));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> unit1.setValue2("value"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testTriplet() {
|
|
||||||
Triplet<String, String, String> unit1 = new Triplet<>();
|
|
||||||
unit1.setValue3("value3");
|
|
||||||
unit1.setValue2("value2");
|
|
||||||
unit1.setValue1("123");
|
|
||||||
|
|
||||||
Triplet<String, String, String> unit2 = new Triplet<>("123", "value2", "value3");
|
|
||||||
Triplet<String, String, String> unit3 = new Triplet<>("1234", "value2", "value3");
|
|
||||||
|
|
||||||
assertEquals(unit1, unit2);
|
|
||||||
|
|
||||||
assertNotEquals(null, unit1);
|
|
||||||
assertNotEquals(new Object(), unit1);
|
|
||||||
assertNotEquals(unit3, unit1);
|
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> unit1.setValue1("value"));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> unit1.setValue2("value"));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> unit1.setValue3("value"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
package net.locusworks.common.io;
|
|
||||||
|
|
||||||
import net.locusworks.common.Charsets;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
|
||||||
import org.mockito.MockedStatic;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.CALLS_REAL_METHODS;
|
|
||||||
import static org.mockito.Mockito.mockStatic;
|
|
||||||
|
|
||||||
class IOUtilsTest {
|
|
||||||
@TempDir
|
|
||||||
Path tempDir;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void readsLinesFromStreamsAndBothReaderKinds() throws Exception {
|
|
||||||
byte[] text = "first\nsecond\nthird".getBytes(StandardCharsets.UTF_8);
|
|
||||||
assertEquals(List.of("first", "second", "third"),
|
|
||||||
IOUtils.readLines(new ByteArrayInputStream(text), StandardCharsets.UTF_8));
|
|
||||||
assertEquals(List.of("first", "second", "third"), IOUtils.readLines(new StringReader(new String(text))));
|
|
||||||
|
|
||||||
BufferedReader buffered = new BufferedReader(new StringReader("line"));
|
|
||||||
assertSame(buffered, IOUtils.toBufferedReader(buffered));
|
|
||||||
assertNotNull(IOUtils.toBufferedReader(new StringReader("line")));
|
|
||||||
assertThrows(NullPointerException.class, () -> IOUtils.readLines((Reader) null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void convertsStreamsAndCopiesBytesThroughEveryOverload() throws Exception {
|
|
||||||
byte[] source = "some binary data".getBytes(StandardCharsets.UTF_8);
|
|
||||||
assertArrayEquals(source, IOUtils.toByteArray(new ByteArrayInputStream(source)));
|
|
||||||
|
|
||||||
ByteArrayOutputStream defaultCopy = new ByteArrayOutputStream();
|
|
||||||
assertEquals(source.length, IOUtils.copy(new ByteArrayInputStream(source), defaultCopy));
|
|
||||||
assertArrayEquals(source, defaultCopy.toByteArray());
|
|
||||||
|
|
||||||
ByteArrayOutputStream sizedCopy = new ByteArrayOutputStream();
|
|
||||||
assertEquals(source.length, IOUtils.copy(new ByteArrayInputStream(source), sizedCopy, 2));
|
|
||||||
assertArrayEquals(source, sizedCopy.toByteArray());
|
|
||||||
|
|
||||||
ByteArrayOutputStream bufferedCopy = new ByteArrayOutputStream();
|
|
||||||
assertEquals(source.length,
|
|
||||||
IOUtils.copyLarge(new ByteArrayInputStream(source), bufferedCopy, new byte[3]));
|
|
||||||
assertArrayEquals(source, bufferedCopy.toByteArray());
|
|
||||||
|
|
||||||
ByteArrayOutputStream largeCopy = new ByteArrayOutputStream();
|
|
||||||
assertEquals(source.length, IOUtils.copyLarge(new ByteArrayInputStream(source), largeCopy));
|
|
||||||
assertArrayEquals(source, largeCopy.toByteArray());
|
|
||||||
assertEquals(0, IOUtils.copyLarge(new ByteArrayInputStream(new byte[0]), new ByteArrayOutputStream()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void copiesCharactersThroughEveryOverload() throws Exception {
|
|
||||||
String source = "characters-å";
|
|
||||||
StringWriter encoded = new StringWriter();
|
|
||||||
IOUtils.copy(new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)), encoded,
|
|
||||||
StandardCharsets.UTF_8);
|
|
||||||
assertEquals(source, encoded.toString());
|
|
||||||
|
|
||||||
StringWriter regular = new StringWriter();
|
|
||||||
assertEquals(source.length(), IOUtils.copy(new StringReader(source), regular));
|
|
||||||
assertEquals(source, regular.toString());
|
|
||||||
|
|
||||||
StringWriter buffered = new StringWriter();
|
|
||||||
assertEquals(source.length(), IOUtils.copyLarge(new StringReader(source), buffered, new char[2]));
|
|
||||||
assertEquals(source, buffered.toString());
|
|
||||||
|
|
||||||
StringWriter large = new StringWriter();
|
|
||||||
assertEquals(source.length(), IOUtils.copyLarge(new StringReader(source), large));
|
|
||||||
assertEquals(source, large.toString());
|
|
||||||
assertEquals(0, IOUtils.copyLarge(new StringReader(""), new StringWriter()));
|
|
||||||
assertEquals(source, IOUtils.toString(
|
|
||||||
new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void integerCopyMethodsReturnEofMarkerForCountsOverIntegerMaximum() throws Exception {
|
|
||||||
try (MockedStatic<IOUtils> mocked = mockStatic(IOUtils.class, CALLS_REAL_METHODS)) {
|
|
||||||
mocked.when(() -> IOUtils.copyLarge(any(InputStream.class), any(OutputStream.class)))
|
|
||||||
.thenReturn((long) Integer.MAX_VALUE + 1);
|
|
||||||
assertEquals(IOUtils.EOF,
|
|
||||||
IOUtils.copy(new ByteArrayInputStream(new byte[0]), new ByteArrayOutputStream()));
|
|
||||||
|
|
||||||
mocked.when(() -> IOUtils.copyLarge(any(Reader.class), any(Writer.class)))
|
|
||||||
.thenReturn((long) Integer.MAX_VALUE + 1);
|
|
||||||
assertEquals(IOUtils.EOF, IOUtils.copy(new StringReader(""), new StringWriter()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Test
|
|
||||||
void writesFilesUsingEveryOverload() throws Exception {
|
|
||||||
Path byName = tempDir.resolve("name.txt");
|
|
||||||
IOUtils.writeStringToFile(byName.toString(), "default");
|
|
||||||
assertEquals("default", Files.readString(byName));
|
|
||||||
|
|
||||||
Path namedCharset = tempDir.resolve("name-charset.txt");
|
|
||||||
IOUtils.writeStringToFile(namedCharset.toString(), "named", StandardCharsets.UTF_16);
|
|
||||||
assertEquals("named", Files.readString(namedCharset, StandardCharsets.UTF_16));
|
|
||||||
|
|
||||||
Path byPath = tempDir.resolve("path.txt");
|
|
||||||
IOUtils.writeStringToFile(byPath, "path");
|
|
||||||
assertEquals("path", Files.readString(byPath, Charsets.UTF_8));
|
|
||||||
|
|
||||||
Path byFile = tempDir.resolve("file.txt");
|
|
||||||
IOUtils.writeStringToFile(byFile.toFile(), "file", StandardCharsets.UTF_8);
|
|
||||||
assertEquals("file", Files.readString(byFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Test
|
|
||||||
void deletesFilesUsingEveryOverloadAndWrapsIoFailures() throws Exception {
|
|
||||||
Path byName = Files.createFile(tempDir.resolve("name-delete.txt"));
|
|
||||||
IOUtils.deleteFile(byName.toString());
|
|
||||||
assertFalse(Files.exists(byName));
|
|
||||||
|
|
||||||
Path byFile = Files.createFile(tempDir.resolve("file-delete.txt"));
|
|
||||||
IOUtils.deleteFile(byFile.toFile());
|
|
||||||
assertFalse(Files.exists(byFile));
|
|
||||||
|
|
||||||
Path first = Files.createFile(tempDir.resolve("first.txt"));
|
|
||||||
Path second = Files.createFile(tempDir.resolve("second.txt"));
|
|
||||||
IOUtils.deleteFiles(first.toString(), second.toString());
|
|
||||||
assertFalse(Files.exists(first));
|
|
||||||
assertFalse(Files.exists(second));
|
|
||||||
|
|
||||||
Path nonEmptyDirectory = Files.createDirectory(tempDir.resolve("non-empty"));
|
|
||||||
Files.createFile(nonEmptyDirectory.resolve("child"));
|
|
||||||
IllegalArgumentException error = assertThrows(IllegalArgumentException.class,
|
|
||||||
() -> IOUtils.deleteFile(nonEmptyDirectory));
|
|
||||||
assertInstanceOf(IOException.class, error.getCause());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void constructorAndInvalidInputsAreCovered() {
|
|
||||||
assertNotNull(new IOUtils());
|
|
||||||
assertThrows(NullPointerException.class, () -> IOUtils.toByteArray(null));
|
|
||||||
assertThrows(NegativeArraySizeException.class,
|
|
||||||
() -> IOUtils.copy(new ByteArrayInputStream(new byte[0]), new ByteArrayOutputStream(), -1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
package net.locusworks.common.migration;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.mockito.Mockito.doThrow;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import org.flywaydb.core.Flyway;
|
|
||||||
import org.flywaydb.core.api.MigrationInfo;
|
|
||||||
import org.flywaydb.core.api.MigrationInfoService;
|
|
||||||
import org.flywaydb.core.api.configuration.Configuration;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
class MigrationItemTest {
|
|
||||||
private static Flyway flyway(MigrationInfo[] all, MigrationInfo[] pending) {
|
|
||||||
Flyway flyway = mock(Flyway.class);
|
|
||||||
MigrationInfoService info = mock(MigrationInfoService.class);
|
|
||||||
Configuration configuration = mock(Configuration.class);
|
|
||||||
when(flyway.info()).thenReturn(info);
|
|
||||||
when(info.all()).thenReturn(all);
|
|
||||||
when(info.pending()).thenReturn(pending);
|
|
||||||
when(flyway.getConfiguration()).thenReturn(configuration);
|
|
||||||
when(configuration.getSchemas()).thenReturn(new String[]{"first", "second"});
|
|
||||||
return flyway;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void exposesSchemasPendingCountAndMigrationLog() {
|
|
||||||
Flyway flyway = flyway(new MigrationInfo[0], new MigrationInfo[]{mock(MigrationInfo.class)});
|
|
||||||
MigrationItem item = new MigrationItem(flyway);
|
|
||||||
assertArrayEquals(new String[]{"first", "second"}, item.getSchemas());
|
|
||||||
assertEquals(1, item.qtyPending());
|
|
||||||
assertNotNull(item.getAllMigrationsLog());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void repairAndMigrateInvokeCallbackAndFlyway() {
|
|
||||||
Flyway flyway = flyway(new MigrationInfo[0], new MigrationInfo[0]);
|
|
||||||
List<String> messages = new ArrayList<>();
|
|
||||||
MigrationItem item = new MigrationItem(flyway, messages::add);
|
|
||||||
item.repair();
|
|
||||||
item.migrate();
|
|
||||||
verify(flyway).repair();
|
|
||||||
verify(flyway).migrate();
|
|
||||||
assertEquals(2, messages.size());
|
|
||||||
assertTrue(messages.stream().allMatch(s -> s.contains("first, second")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void repairAndMigrateWrapFlywayFailures() {
|
|
||||||
Flyway repairFlyway = flyway(new MigrationInfo[0], new MigrationInfo[0]);
|
|
||||||
doThrow(new IllegalStateException("repair failed")).when(repairFlyway).repair();
|
|
||||||
RuntimeException repair = assertThrows(RuntimeException.class, () -> new MigrationItem(repairFlyway).repair());
|
|
||||||
assertTrue(repair.getMessage().contains("repair failed"));
|
|
||||||
|
|
||||||
Flyway migrateFlyway = flyway(new MigrationInfo[0], new MigrationInfo[0]);
|
|
||||||
doThrow(new IllegalStateException("migrate failed")).when(migrateFlyway).migrate();
|
|
||||||
RuntimeException migrate = assertThrows(RuntimeException.class, () -> new MigrationItem(migrateFlyway).migrate());
|
|
||||||
assertTrue(migrate.getMessage().contains("migrate failed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void baseManagerInitializesMutableMigrationList() {
|
|
||||||
class Manager extends BaseMigrationManager {
|
|
||||||
@Override
|
|
||||||
public void migrate() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Manager manager = new Manager();
|
|
||||||
assertNotNull(manager.migrations);
|
|
||||||
assertDoesNotThrow(manager::migrate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package net.locusworks.common.net;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpServer;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
|
|
||||||
class HttpClientHelperTest {
|
|
||||||
@Test
|
|
||||||
void schemaLookupHandlesBothProtocolsAndUnknownValue() {
|
|
||||||
assertEquals(HttpClientHelper.HttpSchema.HTTP, HttpClientHelper.HttpSchema.findEnum("http"));
|
|
||||||
assertEquals(HttpClientHelper.HttpSchema.HTTPS, HttpClientHelper.HttpSchema.findEnum("HtTpS"));
|
|
||||||
assertNull(HttpClientHelper.HttpSchema.findEnum("ftp"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void constructorRejectsUnknownProtocol() {
|
|
||||||
Exception error = assertThrows(Exception.class, () -> new HttpClientHelper("ftp", "localhost", "21"));
|
|
||||||
assertEquals("Unable to find http schema of ftp", error.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void executesHttpGetAndConsumesResponse() throws Exception {
|
|
||||||
HttpServer server = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
|
|
||||||
server.createContext("/status", exchange -> {
|
|
||||||
byte[] body = "ok".getBytes();
|
|
||||||
exchange.sendResponseHeaders(202, body.length);
|
|
||||||
exchange.getResponseBody().write(body);
|
|
||||||
exchange.close();
|
|
||||||
});
|
|
||||||
server.start();
|
|
||||||
try {
|
|
||||||
HttpClientHelper helper = new HttpClientHelper("http", "localhost", Integer.toString(server.getAddress().getPort()));
|
|
||||||
assertEquals(202, helper.getResponseCode("/status"));
|
|
||||||
assertNotNull(new HttpClientHelper("https", "localhost", "443"));
|
|
||||||
} finally {
|
|
||||||
server.stop(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package net.locusworks.common.net.certmanagers;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
|
|
||||||
|
|
||||||
class TrustAllCertsManagerTest {
|
|
||||||
@Test
|
|
||||||
void trustsClientsAndServersAndBuildsTrustManagerArray() throws Exception {
|
|
||||||
TrustAllCertsManager manager = new TrustAllCertsManager();
|
|
||||||
assertDoesNotThrow(() -> manager.checkClientTrusted(null, null));
|
|
||||||
assertDoesNotThrow(() -> manager.checkServerTrusted(null, null));
|
|
||||||
assertNull(manager.getAcceptedIssuers());
|
|
||||||
|
|
||||||
TrustManager[] managers = TrustAllCertsManager.trustAllCerts();
|
|
||||||
assertEquals(1, managers.length);
|
|
||||||
assertInstanceOf(TrustAllCertsManager.class, managers[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package net.locusworks.common.net.hostverifiers;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
class AllHostValidVerifierTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testVerify() {
|
|
||||||
AllHostValidVerifier verifier = new AllHostValidVerifier();
|
|
||||||
assertTrue(verifier.verify("localhost", null));
|
|
||||||
assertTrue(verifier.verify("127.0.0.1", null));
|
|
||||||
assertTrue(verifier.verify("::1", null));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package net.locusworks.common.net.ssl;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.security.KeyManagementException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
|
|
||||||
|
|
||||||
class SSLManagerTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateSSLContext() throws NoSuchAlgorithmException, KeyManagementException {
|
|
||||||
assertNotNull(SSLManager.getTrustAllTLSClient());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTLS() {
|
|
||||||
assertNotNull(SSLManager.TLS);
|
|
||||||
assertEquals(4, SSLManager.TLS.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
package net.locusworks.common.objectmapper;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
|
|
||||||
class ObjectMapperCoverageTest {
|
|
||||||
static class Value {
|
|
||||||
public String name;
|
|
||||||
|
|
||||||
Value() {
|
|
||||||
}
|
|
||||||
|
|
||||||
Value(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class SelfReference {
|
|
||||||
SelfReference self = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
static class CyclicReference {
|
|
||||||
Object next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ThrowingGetter {
|
|
||||||
String name = "field value";
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
throw new IllegalStateException("Jackson getter failure");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void resultContainersSupportEveryConstructorMutationAndHandlerPath() {
|
|
||||||
RuntimeException error = new RuntimeException("bad json");
|
|
||||||
ObjectMapperResults<String> result = new ObjectMapperResults<>("value", null);
|
|
||||||
assertEquals("value", result.getResults());
|
|
||||||
assertFalse(result.hasError());
|
|
||||||
assertSame(result, result.withErrorHandler(e -> fail("handler must not run")));
|
|
||||||
|
|
||||||
result.setResults("changed");
|
|
||||||
result.setException(error);
|
|
||||||
AtomicReference<Throwable> handled = new AtomicReference<>();
|
|
||||||
assertSame(result, result.withErrorHandler(handled::set));
|
|
||||||
assertSame(error, handled.get());
|
|
||||||
assertSame(result, result.withErrorHandler(null));
|
|
||||||
|
|
||||||
assertEquals("simple", new ObjectMapperResults<>("simple").getResults());
|
|
||||||
assertSame(error, new ObjectMapperResults<String>(error).getException());
|
|
||||||
|
|
||||||
ObjectMapperListResults<List<String>> list = new ObjectMapperListResults<>(List.of("a"), null);
|
|
||||||
assertEquals(List.of("a"), list.getResults());
|
|
||||||
assertFalse(list.hasError());
|
|
||||||
assertSame(list, list.withErrorHandler(e -> fail("handler must not run")));
|
|
||||||
|
|
||||||
ObjectMapperListResults<List<String>> failed = new ObjectMapperListResults<>(error);
|
|
||||||
handled.set(null);
|
|
||||||
assertSame(failed, failed.withErrorHandler(handled::set));
|
|
||||||
assertSame(error, handled.get());
|
|
||||||
assertSame(failed, failed.withErrorHandler(null));
|
|
||||||
assertEquals(List.of("b"), new ObjectMapperListResults<>(List.of("b")).getResults());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void readsBytesStringsObjectsAndCollectionImplementations() {
|
|
||||||
Value fromBytes = ObjectMapperHelper.readValue("{\"name\":\"bytes\"}".getBytes(), Value.class).getResults();
|
|
||||||
assertEquals("bytes", fromBytes.name);
|
|
||||||
assertEquals("string", ObjectMapperHelper.readValue("{\"name\":\"string\"}", Value.class).getResults().name);
|
|
||||||
assertEquals("object", ObjectMapperHelper.readValue(new Value("object"), Value.class).getResults().name);
|
|
||||||
Object delegatedJson = "{\"name\":\"delegated\"}";
|
|
||||||
assertEquals("delegated", ObjectMapperHelper.readValue(delegatedJson, Value.class).getResults().name);
|
|
||||||
|
|
||||||
List<Value> values = List.of(new Value("one"), new Value("two"));
|
|
||||||
assertEquals(2, ObjectMapperHelper.readListValue(values, Value.class).getResults().size());
|
|
||||||
assertEquals(2, ObjectMapperHelper.readListValue("[{\"name\":\"one\"},{\"name\":\"two\"}]", Value.class, LinkedList.class).getResults().size());
|
|
||||||
assertInstanceOf(LinkedList.class,
|
|
||||||
ObjectMapperHelper.readListValue(values, Value.class, LinkedList.class).getResults());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void malformedInputReturnsErrorsForEveryReadOverload() {
|
|
||||||
assertTrue(ObjectMapperHelper.readValue(new byte[]{1, 2}, Value.class).hasError());
|
|
||||||
assertTrue(ObjectMapperHelper.readValue("not-json", Value.class).hasError());
|
|
||||||
assertTrue(ObjectMapperHelper.readValue(new Object(), Thread.class).hasError());
|
|
||||||
assertTrue(ObjectMapperHelper.readListValue("not-json", Value.class, ArrayList.class).hasError());
|
|
||||||
assertTrue(ObjectMapperHelper.readListValue(new Object(), Value.class, List.class).hasError());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void writeFallsBackWhenJacksonAndGsonRejectCircularObject() {
|
|
||||||
CyclicReference first = new CyclicReference();
|
|
||||||
CyclicReference second = new CyclicReference();
|
|
||||||
first.next = second;
|
|
||||||
second.next = first;
|
|
||||||
ObjectMapperResults<String> result = ObjectMapperHelper.writeValue(first);
|
|
||||||
assertTrue(result.hasError());
|
|
||||||
|
|
||||||
ObjectMapperResults<String> fallback = ObjectMapperHelper.writeValue(new ThrowingGetter());
|
|
||||||
assertFalse(fallback.hasError());
|
|
||||||
assertTrue(fallback.getResults().contains("field value"));
|
|
||||||
|
|
||||||
assertNotNull(new ObjectMapperHelper());
|
|
||||||
assertTrue(ObjectMapperHelper.readValue(new SelfReference(), Value.class).hasError());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package net.locusworks.common.properties;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
|
|
||||||
class ImmutablePropertiesTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testImmutableProperties() {
|
|
||||||
assertNotNull(new ImmutableProperties());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testImmutablePropertiesWithEmptyOrNullProperties() {
|
|
||||||
assertNotNull(new ImmutableProperties(new Properties()));
|
|
||||||
assertNotNull(new ImmutableProperties(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testImmutablePropertiesWthProperties() {
|
|
||||||
final Properties properties = new Properties();
|
|
||||||
properties.put("Hello", "World");
|
|
||||||
assertNotNull(new ImmutableProperties(properties));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetProperties() {
|
|
||||||
final ImmutableProperties properties = new ImmutableProperties(new Properties());
|
|
||||||
properties.setProperty("Hello", "World");
|
|
||||||
assertEquals("World", properties.getProperty("Hello"));
|
|
||||||
|
|
||||||
assertThrows(RuntimeException.class, () -> properties.setProperty("Hello", "World"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
package net.locusworks.common.properties;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
class OrderedPropertiesCoverageTest {
|
|
||||||
@Test
|
|
||||||
void loadsAllPropertySyntaxFromReaderAndInputStream() throws Exception {
|
|
||||||
String source = "# comment\n! another\n" +
|
|
||||||
"simple=value\ncolon:value2\nspace value3\n" +
|
|
||||||
"spaced = spaced-value\n" +
|
|
||||||
"tabbed\t:\tvalue5\nform\f=\fvalue6\n" +
|
|
||||||
"slashes\\\\key:value4\n" +
|
|
||||||
"escaped\\:colon=value7\n" +
|
|
||||||
"escaped\\ key=escaped\\ value\n" +
|
|
||||||
"unicode=\\u0041\\tB\\nC\\rD\\fE\n" +
|
|
||||||
"continued=first\\\n second\n" +
|
|
||||||
"emptyKey\n=empty-key-value\n";
|
|
||||||
|
|
||||||
OrderedProperties readerProperties = new OrderedProperties();
|
|
||||||
readerProperties.load(new StringReader(source));
|
|
||||||
assertEquals("value", readerProperties.getProperty("simple"));
|
|
||||||
assertEquals("value2", readerProperties.getProperty("colon"));
|
|
||||||
assertEquals("value3", readerProperties.getProperty("space"));
|
|
||||||
assertEquals("spaced-value", readerProperties.getProperty("spaced"));
|
|
||||||
assertEquals("value4", readerProperties.getProperty("slashes\\key"));
|
|
||||||
assertEquals("value5", readerProperties.getProperty("tabbed"));
|
|
||||||
assertEquals("value6", readerProperties.getProperty("form"));
|
|
||||||
assertEquals("value7", readerProperties.getProperty("escaped:colon"));
|
|
||||||
assertEquals("escaped value", readerProperties.getProperty("escaped key"));
|
|
||||||
assertEquals("A\tB\nC\rD\fE", readerProperties.getProperty("unicode"));
|
|
||||||
assertEquals("firstsecond", readerProperties.getProperty("continued"));
|
|
||||||
assertEquals("", readerProperties.getProperty("emptyKey"));
|
|
||||||
assertEquals("empty-key-value", readerProperties.getProperty(""));
|
|
||||||
|
|
||||||
OrderedProperties streamProperties = new OrderedProperties();
|
|
||||||
streamProperties.load(new ByteArrayInputStream(source.getBytes(StandardCharsets.ISO_8859_1)));
|
|
||||||
assertEquals(readerProperties, streamProperties);
|
|
||||||
assertThrows(IllegalArgumentException.class,
|
|
||||||
() -> streamProperties.load(new StringReader("bad=\\u12G4")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void storesToWriterAndStreamWithCommentsUnicodeAndEscapes() throws Exception {
|
|
||||||
OrderedProperties properties = new OrderedProperties();
|
|
||||||
properties.setProperty(" leading:=#!", " value\t\n\r\f\\é");
|
|
||||||
|
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
properties.store(writer, "first\nsecond\rthird\r\nfourth\u0100");
|
|
||||||
String writerText = writer.toString();
|
|
||||||
assertTrue(writerText.contains("#first"));
|
|
||||||
assertTrue(writerText.contains("#second"));
|
|
||||||
assertTrue(writerText.contains("\\ leading\\:\\=\\#\\!"));
|
|
||||||
assertTrue(writerText.contains("é"));
|
|
||||||
|
|
||||||
StringWriter bufferedTarget = new StringWriter();
|
|
||||||
properties.store(new BufferedWriter(bufferedTarget), "\u0100first\rsolo\n#already\n!also\nlast\r\nend\r");
|
|
||||||
assertTrue(bufferedTarget.toString().contains("#already"));
|
|
||||||
|
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
properties.store(bytes, null);
|
|
||||||
String streamText = bytes.toString(StandardCharsets.ISO_8859_1);
|
|
||||||
assertTrue(streamText.contains("\\u00E9"));
|
|
||||||
|
|
||||||
assertDoesNotThrow(() -> properties.save(new OutputStream() {
|
|
||||||
@Override
|
|
||||||
public void write(int b) throws IOException {
|
|
||||||
throw new IOException("expected");
|
|
||||||
}
|
|
||||||
}, "ignored error"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void defaultsEnumerationListingAndNonStringValuesAreHandled() {
|
|
||||||
OrderedProperties defaults = new OrderedProperties();
|
|
||||||
defaults.setProperty("default", "value");
|
|
||||||
defaults.put("nonStringDefault", 1);
|
|
||||||
OrderedProperties properties = new OrderedProperties(defaults);
|
|
||||||
properties.setProperty("local", "x".repeat(50));
|
|
||||||
properties.put("nonString", 2);
|
|
||||||
|
|
||||||
assertEquals("value", properties.getProperty("default"));
|
|
||||||
assertEquals("fallback", properties.getProperty("missing", "fallback"));
|
|
||||||
assertEquals("value", properties.getProperty("default", "fallback"));
|
|
||||||
Enumeration<?> names = properties.propertyNames();
|
|
||||||
assertTrue(java.util.Collections.list(names).containsAll(List.of("default", "local")));
|
|
||||||
properties.put(3, "nonStringKey");
|
|
||||||
assertTrue(properties.stringPropertyNames().containsAll(java.util.Set.of("default", "local")));
|
|
||||||
|
|
||||||
properties.remove("nonString");
|
|
||||||
properties.remove(3);
|
|
||||||
defaults.remove("nonStringDefault");
|
|
||||||
|
|
||||||
ByteArrayOutputStream printBytes = new ByteArrayOutputStream();
|
|
||||||
properties.list(new PrintStream(printBytes));
|
|
||||||
assertTrue(printBytes.toString().contains("..."));
|
|
||||||
StringWriter output = new StringWriter();
|
|
||||||
properties.list(new PrintWriter(output));
|
|
||||||
assertTrue(output.toString().contains("-- listing properties --"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void lineReaderHandlesCommentsWhitespaceContinuationLongLinesAndEndings() throws Exception {
|
|
||||||
String longValue = "x".repeat(9000);
|
|
||||||
String input = " #comment\r\n\t!comment\n key=value\\\r\n continued\r" + longValue;
|
|
||||||
OrderedProperties.LineReader reader = new OrderedProperties.LineReader(new StringReader(input));
|
|
||||||
int length = reader.readLine();
|
|
||||||
assertEquals("key=valuecontinued", new String(reader.lineBuf, 0, length));
|
|
||||||
assertEquals(9000, reader.readLine());
|
|
||||||
|
|
||||||
OrderedProperties.LineReader stream = new OrderedProperties.LineReader(
|
|
||||||
new ByteArrayInputStream(("a=b\n" + longValue).getBytes(StandardCharsets.ISO_8859_1)));
|
|
||||||
assertEquals(3, stream.readLine());
|
|
||||||
assertEquals(9000, stream.readLine());
|
|
||||||
assertEquals(-1, stream.readLine());
|
|
||||||
|
|
||||||
OrderedProperties.LineReader trailingReader = new OrderedProperties.LineReader(new StringReader("key=value\\"));
|
|
||||||
assertEquals("key=value", new String(trailingReader.lineBuf, 0, trailingReader.readLine()));
|
|
||||||
OrderedProperties.LineReader trailingStream = new OrderedProperties.LineReader(
|
|
||||||
new ByteArrayInputStream("key=value\\\n".getBytes(StandardCharsets.ISO_8859_1)));
|
|
||||||
assertEquals("key=value", new String(trailingStream.lineBuf, 0, trailingStream.readLine()));
|
|
||||||
OrderedProperties.LineReader whiteContinuation = new OrderedProperties.LineReader(
|
|
||||||
new StringReader("key=value\\\n \t\fcontinued\n"));
|
|
||||||
int continuedLength = whiteContinuation.readLine();
|
|
||||||
assertEquals("key=valuecontinued", new String(whiteContinuation.lineBuf, 0, continuedLength));
|
|
||||||
assertEquals(-1, new OrderedProperties.LineReader(new StringReader("#comment without newline")).readLine());
|
|
||||||
|
|
||||||
OrderedProperties.LineReader crWithoutLf = new OrderedProperties.LineReader(new StringReader("a\\\rb\n"));
|
|
||||||
int crLength = crWithoutLf.readLine();
|
|
||||||
assertEquals("ab", new String(crWithoutLf.lineBuf, 0, crLength));
|
|
||||||
|
|
||||||
OrderedProperties.LineReader blankEndings = new OrderedProperties.LineReader(new StringReader("\n\r\nvalue\n"));
|
|
||||||
assertEquals("value", new String(blankEndings.lineBuf, 0, blankEndings.readLine()));
|
|
||||||
|
|
||||||
String boundaryInput = "z".repeat(8191) + "\nnext\n";
|
|
||||||
OrderedProperties.LineReader boundary = new OrderedProperties.LineReader(new StringReader(boundaryInput));
|
|
||||||
assertEquals(8191, boundary.readLine());
|
|
||||||
assertEquals(4, boundary.readLine());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void privateConversionHelpersCoverEveryEscapeAndHexPath() throws Exception {
|
|
||||||
OrderedProperties properties = new OrderedProperties();
|
|
||||||
Method load = OrderedProperties.class.getDeclaredMethod("loadConvert", char[].class, int.class, int.class, char[].class);
|
|
||||||
Method save = OrderedProperties.class.getDeclaredMethod("saveConvert", String.class, boolean.class, boolean.class);
|
|
||||||
Method hex = OrderedProperties.class.getDeclaredMethod("toHex", int.class);
|
|
||||||
load.setAccessible(true);
|
|
||||||
save.setAccessible(true);
|
|
||||||
hex.setAccessible(true);
|
|
||||||
|
|
||||||
String escaped = "a\\tb\\nc\\rd\\fe\\\\f\\ g\\:h\\=i\\#j\\!k\\u0041";
|
|
||||||
assertEquals("a\tb\nc\rd\fe\\f g:h=i#j!kA",
|
|
||||||
load.invoke(properties, escaped.toCharArray(), 0, escaped.length(), new char[1]));
|
|
||||||
String hexCases = "\\u00af\\u00AF";
|
|
||||||
assertEquals("¯¯", load.invoke(properties, hexCases.toCharArray(), 0, hexCases.length(), new char[1]));
|
|
||||||
assertEquals("\\ a\\:\\=\\#\\!\\t\\n\\r\\f\\\\\\u0100",
|
|
||||||
save.invoke(properties, " a:=#!\t\n\r\f\\\u0100", true, true));
|
|
||||||
assertEquals("\\ a\\:\\=\\#\\!\\t\\n\\r\\f\\\\\u0100",
|
|
||||||
save.invoke(properties, " a:=#!\t\n\r\f\\\u0100", false, false));
|
|
||||||
assertEquals("a\\ b", save.invoke(properties, "a b", true, false));
|
|
||||||
assertEquals("a b", save.invoke(properties, "a b", false, false));
|
|
||||||
assertEquals("\\u0001", save.invoke(properties, "\u0001", false, true));
|
|
||||||
assertEquals("\u0001", save.invoke(properties, "\u0001", false, false));
|
|
||||||
assertEquals("0", save.invoke(properties, "0", false, true));
|
|
||||||
assertEquals('0', hex.invoke(null, 0));
|
|
||||||
assertEquals('F', hex.invoke(null, 15));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void immutablePropertiesCopiesValuesAndRejectsReplacement() {
|
|
||||||
Properties source = new Properties();
|
|
||||||
source.setProperty("key", "value");
|
|
||||||
ImmutableProperties immutable = new ImmutableProperties(source);
|
|
||||||
assertEquals("value", immutable.getProperty("key"));
|
|
||||||
assertThrows(RuntimeException.class, () -> immutable.setProperty("key", "changed"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
package net.locusworks.common.properties;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
|
|
||||||
|
|
||||||
class OrderedPropertiesTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetProperty() {
|
|
||||||
OrderedProperties properties = new OrderedProperties();
|
|
||||||
properties.setProperty("Hello", "World");
|
|
||||||
assertEquals("World", properties.getProperty("Hello"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testLoad() throws IOException {
|
|
||||||
OrderedProperties properties = new OrderedProperties();
|
|
||||||
properties.load(new ByteArrayInputStream("Hello=World".getBytes()));
|
|
||||||
assertEquals("World", properties.getProperty("Hello"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSave() {
|
|
||||||
OrderedProperties properties = new OrderedProperties();
|
|
||||||
properties.setProperty("Hello", "World");
|
|
||||||
properties.save(new ByteArrayOutputStream(), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testStore() {
|
|
||||||
OrderedProperties properties = new OrderedProperties();
|
|
||||||
properties.setProperty("Hello", "World");
|
|
||||||
try {
|
|
||||||
properties.store(new ByteArrayOutputStream(), "");
|
|
||||||
} catch (IOException e) {
|
|
||||||
fail("IOException should not be thrown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testGetProperty() {
|
|
||||||
OrderedProperties properties = new OrderedProperties();
|
|
||||||
properties.setProperty("Hello", "World");
|
|
||||||
assertEquals("World", properties.getProperty("Hello"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPropertyNames() {
|
|
||||||
OrderedProperties properties = new OrderedProperties();
|
|
||||||
properties.setProperty("Hello", "World");
|
|
||||||
var propertyNames = properties.stringPropertyNames();
|
|
||||||
assertFalse(propertyNames.isEmpty());
|
|
||||||
assertTrue(propertyNames.contains("Hello"));
|
|
||||||
assertEquals(1, propertyNames.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testList() {
|
|
||||||
PrintStream ps = new PrintStream(new ByteArrayOutputStream());
|
|
||||||
OrderedProperties properties = new OrderedProperties();
|
|
||||||
properties.setProperty("Hello", "World");
|
|
||||||
properties.list(ps);
|
|
||||||
ps.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
|
|
||||||
class ChecksTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testCheckArgument() {
|
|
||||||
Throwable ex = assertThrows(IllegalArgumentException.class, () -> Checks.checkArguments(false, "One does not equal 2"));
|
|
||||||
assertEquals("One does not equal 2", ex.getMessage());
|
|
||||||
|
|
||||||
assertDoesNotThrow(() -> Checks.checkArguments(true, "One does not equal 2"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testCheckState() {
|
|
||||||
Throwable ex = assertThrows(IllegalStateException.class, () -> Checks.checkState(false, "One does not equal 2"));
|
|
||||||
assertEquals("One does not equal 2", ex.getMessage());
|
|
||||||
|
|
||||||
assertDoesNotThrow(() -> Checks.checkState(true, "One does not equal 2"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,286 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
|
|
||||||
import com.fasterxml.jackson.core.Base64Variant;
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
|
||||||
import com.fasterxml.jackson.core.JsonStreamContext;
|
|
||||||
import com.fasterxml.jackson.core.ObjectCodec;
|
|
||||||
import com.fasterxml.jackson.core.SerializableString;
|
|
||||||
import com.fasterxml.jackson.core.TreeNode;
|
|
||||||
import com.fasterxml.jackson.core.Version;
|
|
||||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
|
||||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
|
||||||
import com.fasterxml.jackson.databind.introspect.Annotated;
|
|
||||||
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
|
|
||||||
import com.fasterxml.jackson.databind.ser.impl.WritableObjectId;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
|
|
||||||
class DateTimeStampSerializerTest {
|
|
||||||
|
|
||||||
static AtomicLong atomicLong = new AtomicLong(0);
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSerializer() {
|
|
||||||
DateTimeStampSerializer serializer = new DateTimeStampSerializer();
|
|
||||||
assertDoesNotThrow(() -> serializer.serialize(new Date(), new MyJsonGenerator(), new MySerializerProvider()));
|
|
||||||
assertTrue(atomicLong.get() > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class MyJsonGenerator extends JsonGenerator {
|
|
||||||
@Override
|
|
||||||
public JsonGenerator setCodec(ObjectCodec objectCodec) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ObjectCodec getCodec() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Version version() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonStreamContext getOutputContext() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonGenerator enable(Feature feature) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonGenerator disable(Feature feature) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled(Feature feature) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getFeatureMask() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonGenerator setFeatureMask(int i) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonGenerator useDefaultPrettyPrinter() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeStartArray() {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeEndArray() {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeStartObject() {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeEndObject() {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeFieldName(String s) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeFieldName(SerializableString serializableString) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeString(String s) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeString(char[] chars, int i, int i1) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeString(SerializableString serializableString) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeRawUTF8String(byte[] bytes, int i, int i1) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeUTF8String(byte[] bytes, int i, int i1) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeRaw(String s) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeRaw(String s, int i, int i1) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeRaw(char[] chars, int i, int i1) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeRaw(char c) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeRawValue(String s) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeRawValue(String s, int i, int i1) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeRawValue(char[] chars, int i, int i1) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeBinary(Base64Variant base64Variant, byte[] bytes, int i, int i1) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int writeBinary(Base64Variant base64Variant, InputStream inputStream, int i) {
|
|
||||||
fail();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeNumber(int i) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeNumber(long l) {
|
|
||||||
atomicLong.set(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeNumber(BigInteger bigInteger) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeNumber(double v) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeNumber(float v) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeNumber(BigDecimal bigDecimal) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeNumber(String s) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeBoolean(boolean b) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeNull() {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeObject(Object o) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeTree(TreeNode treeNode) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isClosed() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class MySerializerProvider extends SerializerProvider {
|
|
||||||
@Override
|
|
||||||
public WritableObjectId findObjectId(Object o, ObjectIdGenerator<?> objectIdGenerator) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonSerializer<Object> serializerInstance(Annotated annotated, Object o) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object includeFilterInstance(BeanPropertyDefinition beanPropertyDefinition,
|
|
||||||
Class<?> aClass) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean includeFilterSuppressNulls(Object o) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,275 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import net.locusworks.common.interfaces.AutoCloseableIterator;
|
|
||||||
import net.locusworks.common.utils.FileReader.LineInfo;
|
|
||||||
import org.junit.jupiter.api.AfterAll;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.mockito.MockedStatic;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.Mockito.mockStatic;
|
|
||||||
|
|
||||||
public class FileReaderTest {
|
|
||||||
|
|
||||||
private static final String TEST_FILE = "test_file.txt";
|
|
||||||
private static final Map<Integer, Integer> numLines = new LinkedHashMap<>();
|
|
||||||
private BufferedReader testBufferedReader;
|
|
||||||
|
|
||||||
private static final String[] TEST_CONTENT = new String[]{
|
|
||||||
"Line 1",
|
|
||||||
"Line 2",
|
|
||||||
"Line 3"
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
public static void setUpBeforeClass() throws Exception {
|
|
||||||
File testFile = new File(TEST_FILE);
|
|
||||||
FileOutputStream fos = new FileOutputStream(testFile);
|
|
||||||
|
|
||||||
for (int i = 1; i <= TEST_CONTENT.length; i++) {
|
|
||||||
String randomString = TEST_CONTENT[i - 1] + "\n";
|
|
||||||
numLines.put(i, randomString.length());
|
|
||||||
fos.write(randomString.getBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
fos.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() throws FileNotFoundException {
|
|
||||||
testBufferedReader = new BufferedReader(new java.io.FileReader(TEST_FILE));
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
void tearDown() {
|
|
||||||
try {
|
|
||||||
if (testBufferedReader != null) {
|
|
||||||
testBufferedReader.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
public static void tearDownAfterClass() {
|
|
||||||
File file = new File(TEST_FILE);
|
|
||||||
file.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testForLoop() {
|
|
||||||
int lineCount = 0;
|
|
||||||
try (FileReader fr = new FileReader(Paths.get(TEST_FILE))) {
|
|
||||||
for (LineInfo s : fr) {
|
|
||||||
lineCount++;
|
|
||||||
Integer lineNumber = s.getLineNumber();
|
|
||||||
int lineLength = s.getLine().length();
|
|
||||||
Integer mapLineLength = numLines.get(lineNumber);
|
|
||||||
assertEquals(lineLength, (mapLineLength - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertEquals(lineCount, numLines.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testDeprecatedConstructor() {
|
|
||||||
try (FileReader fr = new FileReader(new File(TEST_FILE))) {
|
|
||||||
assertNotNull(fr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testInit() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIterator() {
|
|
||||||
int lineCount = 0;
|
|
||||||
|
|
||||||
try (AutoCloseableIterator<LineInfo> iter = new FileReader(Paths.get(TEST_FILE))) {
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
lineCount++;
|
|
||||||
LineInfo s = iter.next();
|
|
||||||
Integer lineNumber = s.getLineNumber();
|
|
||||||
int lineLength = s.getLine().length();
|
|
||||||
Integer mapLineLength = numLines.get(lineNumber);
|
|
||||||
assertEquals(lineLength, (mapLineLength - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertEquals(lineCount, numLines.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testForIterator() {
|
|
||||||
int lineCount = 0;
|
|
||||||
try (FileReader fr = new FileReader(Paths.get(TEST_FILE))) {
|
|
||||||
while (((Iterator<LineInfo>) fr).hasNext()) {
|
|
||||||
lineCount++;
|
|
||||||
LineInfo s = ((Iterator<LineInfo>) fr).next();
|
|
||||||
Integer lineNumber = s.getLineNumber();
|
|
||||||
int lineLength = s.getLine().length();
|
|
||||||
Integer mapLineLength = numLines.get(lineNumber);
|
|
||||||
assertEquals(lineLength, (mapLineLength - 1));
|
|
||||||
}
|
|
||||||
assertEquals(lineCount, numLines.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoAlgorithmException() {
|
|
||||||
try (MockedStatic<SecureRandom> mocked = mockStatic(SecureRandom.class)) {
|
|
||||||
mocked.when(() -> SecureRandom.getInstance(anyString())).thenThrow(NoSuchAlgorithmException.class);
|
|
||||||
assertDoesNotThrow(() -> RandomString.newInstance());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFileReaderWithBufferedReader() {
|
|
||||||
try (FileReader fileReader = new FileReader(testBufferedReader)) {
|
|
||||||
Iterator<FileReader.LineInfo> iterator = fileReader.iterator();
|
|
||||||
|
|
||||||
assertTrue(iterator.hasNext());
|
|
||||||
FileReader.LineInfo lineInfo = iterator.next();
|
|
||||||
assertEquals(1, lineInfo.getLineNumber());
|
|
||||||
assertEquals("Line 1", lineInfo.getLine());
|
|
||||||
|
|
||||||
assertTrue(iterator.hasNext());
|
|
||||||
lineInfo = iterator.next();
|
|
||||||
assertEquals(2, lineInfo.getLineNumber());
|
|
||||||
assertEquals("Line 2", lineInfo.getLine());
|
|
||||||
|
|
||||||
assertTrue(iterator.hasNext());
|
|
||||||
lineInfo = iterator.next();
|
|
||||||
assertEquals(3, lineInfo.getLineNumber());
|
|
||||||
assertEquals("Line 3", lineInfo.getLine());
|
|
||||||
|
|
||||||
assertFalse(iterator.hasNext());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFileReaderWithFile() {
|
|
||||||
try (FileReader fileReader = new FileReader(TEST_FILE)) {
|
|
||||||
// Add assertions based on the content of the file
|
|
||||||
Iterator<FileReader.LineInfo> iterator = fileReader.iterator();
|
|
||||||
|
|
||||||
assertTrue(iterator.hasNext());
|
|
||||||
FileReader.LineInfo lineInfo = iterator.next();
|
|
||||||
assertNotNull(lineInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFileReaderWithNonexistentFile() {
|
|
||||||
// Provide the path to a nonexistent file for testing
|
|
||||||
String filePath = "path/to/nonexistent/file.txt";
|
|
||||||
|
|
||||||
// Ensure that the constructor throws an IllegalArgumentException
|
|
||||||
assertThrows(NullPointerException.class, () -> new FileReader(filePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFileReaderInitWithNullFile() {
|
|
||||||
// Ensure that the constructor throws an IllegalArgumentException with a null file
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> new FileReader((String) null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFileReaderInitWithNullBufferedReader() {
|
|
||||||
// Ensure that the constructor throws an IllegalArgumentException with a null BufferedReader
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> new FileReader((BufferedReader) null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFileReaderInitWithNonexistentResource() {
|
|
||||||
// Provide the name of a nonexistent resource for testing
|
|
||||||
String resourceName = "nonexistent_resource.txt";
|
|
||||||
|
|
||||||
// Ensure that the constructor throws an IllegalArgumentException
|
|
||||||
assertThrows(NullPointerException.class, () -> new FileReader(resourceName));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFileReaderInitWithInvalidResource() {
|
|
||||||
// Provide the name of an invalid resource for testing
|
|
||||||
String resourceName = "invalid_resource.txt";
|
|
||||||
|
|
||||||
// Ensure that the constructor throws a RuntimeException
|
|
||||||
assertThrows(RuntimeException.class, () -> new FileReader(resourceName));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFileReaderInitWithNullPath() {
|
|
||||||
// Ensure that the constructor throws an IllegalArgumentException with a null path
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> new FileReader((Path) null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFileReaderInitWithNonexistentPath() {
|
|
||||||
// Provide a nonexistent path for testing
|
|
||||||
Path path = Paths.get("nonexistent_path.txt");
|
|
||||||
|
|
||||||
// Ensure that the constructor throws a RuntimeException
|
|
||||||
assertThrows(RuntimeException.class, () -> new FileReader(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFileReaderInitWithNonRegularFile() {
|
|
||||||
// Provide the path to a non-regular file for testing
|
|
||||||
Path path = Paths.get("path/to/non_regular_file");
|
|
||||||
|
|
||||||
// Ensure that the constructor throws an IllegalArgumentException
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> new FileReader(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFileReaderHasNextIOException() {
|
|
||||||
// Provide a BufferedReader that throws an IOException when reading
|
|
||||||
BufferedReader bufferedReader = new BufferedReader(new StringReader(TEST_FILE)) {
|
|
||||||
@Override
|
|
||||||
public String readLine() throws IOException {
|
|
||||||
throw new IOException("Simulated IOException");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
try (FileReader fileReader = new FileReader(bufferedReader)) {
|
|
||||||
Iterator<FileReader.LineInfo> iterator = fileReader.iterator();
|
|
||||||
|
|
||||||
assertThrows(RuntimeException.class, iterator::hasNext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFileReaderNextNoMoreElements() {
|
|
||||||
// Provide a BufferedReader with no more elements for testing
|
|
||||||
BufferedReader bufferedReader = new BufferedReader(new StringReader(""));
|
|
||||||
|
|
||||||
try (FileReader fileReader = new FileReader(bufferedReader)) {
|
|
||||||
Iterator<FileReader.LineInfo> iterator = fileReader.iterator();
|
|
||||||
|
|
||||||
assertThrows(NoSuchElementException.class, iterator::next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
public class HashUtilsTest {
|
|
||||||
|
|
||||||
private static final String TEST_STRING = "Hello World";
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMD5() {
|
|
||||||
String digestUtilsMD5 = DigestUtils.md5Hex(TEST_STRING.getBytes());
|
|
||||||
String hashUtilsMD5 = HashUtils.hash("MD5", TEST_STRING);
|
|
||||||
|
|
||||||
assertEquals(digestUtilsMD5, hashUtilsMD5);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSHA1() {
|
|
||||||
String digestUtilsMD5 = DigestUtils.sha1Hex(TEST_STRING.getBytes());
|
|
||||||
String hashUtilsMD5 = HashUtils.hash("SHA-1", TEST_STRING);
|
|
||||||
|
|
||||||
assertEquals(digestUtilsMD5, hashUtilsMD5);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSHA512() {
|
|
||||||
String digestUtilsMD5 = DigestUtils.sha512Hex(TEST_STRING.getBytes());
|
|
||||||
String hashUtilsMD5 = HashUtils.hash("SHA-512", TEST_STRING);
|
|
||||||
|
|
||||||
assertEquals(digestUtilsMD5, hashUtilsMD5);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterAll;
|
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static net.locusworks.common.utils.ObjectUtils.performIfNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
class ObjectUtilsTest {
|
|
||||||
|
|
||||||
private static final String TEST_FILE = "object-utils-test.txt";
|
|
||||||
private static Path testFile;
|
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
public static void setUpBeforeClass() throws Exception {
|
|
||||||
Path classpathRoot = Paths.get(Objects.requireNonNull(ObjectUtilsTest.class.getResource("/")).toURI());
|
|
||||||
testFile = classpathRoot.resolve(TEST_FILE);
|
|
||||||
Files.writeString(testFile, "test resource");
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
public static void tearDownAfterClass() throws Exception {
|
|
||||||
Files.deleteIfExists(testFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testNullObject() {
|
|
||||||
performIfNotNull(null, str -> fail());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testNotNullObject() {
|
|
||||||
String str = "hello world";
|
|
||||||
performIfNotNull(str, obj -> assertEquals(str, obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getResourceStream_whenResourceExists_ReturnsInputStream() throws Exception {
|
|
||||||
try (InputStream result = ObjectUtils.getResourceStream("/" + TEST_FILE)) {
|
|
||||||
assertNotNull(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getResourceStream_whenResourceDoesNotExist_ThrowsException() {
|
|
||||||
// Arrange
|
|
||||||
String resourceName = "nonexistent.txt";
|
|
||||||
|
|
||||||
// Act & Assert
|
|
||||||
assertThrows(NullPointerException.class,
|
|
||||||
() -> ObjectUtils.getResourceStream(resourceName));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getResourceStream_whenResourceExistsInClassLoader_ReturnsInputStream() throws Exception {
|
|
||||||
try (InputStream result = ObjectUtils.getResourceStream(TEST_FILE)) {
|
|
||||||
assertNotNull(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getResourceStream_whenResourceDoesNotExistInClassLoader_ThrowsException() {
|
|
||||||
// Arrange
|
|
||||||
String resourceName = "nonexistent.txt";
|
|
||||||
|
|
||||||
// Act & Assert
|
|
||||||
assertThrows(NullPointerException.class,
|
|
||||||
() -> ObjectUtils.getResourceStream(resourceName));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
|
|
||||||
public class RandomStringTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStaticBytes() {
|
|
||||||
for (int length = 3; length < 50; length++) {
|
|
||||||
assertEquals(RandomString.getInstance().getBytes(length).length, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStaticString() {
|
|
||||||
for (int length = 3; length < 50; length++) {
|
|
||||||
String random = RandomString.getInstance().getString(length);
|
|
||||||
assertEquals(random.length(), length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExceptions() {
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> RandomString.newInstance().getString(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
|
|
||||||
class SplitterTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testBasicSplitter() {
|
|
||||||
List<String> split = Splitter.onSpace().split("Hello World");
|
|
||||||
assertNotNull(split);
|
|
||||||
assertEquals(2, split.size());
|
|
||||||
assertEquals("Hello", split.get(0));
|
|
||||||
assertEquals("World", split.get(1));
|
|
||||||
|
|
||||||
split = Splitter.fixedLengthSplit(5).split("HelloWorld");
|
|
||||||
assertNotNull(split);
|
|
||||||
assertEquals(2, split.size());
|
|
||||||
assertEquals("Hello", split.get(0));
|
|
||||||
assertEquals("World", split.get(1));
|
|
||||||
|
|
||||||
split = Splitter.onNewLine().split("Hello\nWorld");
|
|
||||||
assertNotNull(split);
|
|
||||||
assertEquals(2, split.size());
|
|
||||||
assertEquals("Hello", split.get(0));
|
|
||||||
assertEquals("World", split.get(1));
|
|
||||||
|
|
||||||
split = Splitter.onNewLine().split("Hello\r\nWorld");
|
|
||||||
assertNotNull(split);
|
|
||||||
assertEquals(2, split.size());
|
|
||||||
assertEquals("Hello", split.get(0));
|
|
||||||
assertEquals("World", split.get(1));
|
|
||||||
|
|
||||||
String[] array = Splitter.onSpace().splitToArray("Hello World");
|
|
||||||
assertNotNull(array);
|
|
||||||
assertEquals(2, array.length);
|
|
||||||
assertEquals("Hello", array[0]);
|
|
||||||
assertEquals("World", array[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testOmitEmptyStringWithLimits() {
|
|
||||||
List<String> split = Splitter.onSpace().split("Hello World");
|
|
||||||
assertEquals(3, split.size());
|
|
||||||
split = Splitter.onSpace().omitEmptyStrings().withLimit(1).split("Hello World");
|
|
||||||
assertNotNull(split);
|
|
||||||
assertEquals(1, split.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testExceptions() {
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> Splitter.onSpace().split(""));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> Splitter.fixedLengthSplit(0).split("Hello World"));
|
|
||||||
assertThrows(NullPointerException.class, () -> Splitter.on(null).split("Hello World"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testWithKeyValueSeparator() {
|
|
||||||
Map<String, String> map = Splitter.on(";").withKeyValueSeparator("=").split("Hello=World;bubba=hotep");
|
|
||||||
assertEquals(2, map.size());
|
|
||||||
assertEquals("World", map.get("Hello"));
|
|
||||||
assertEquals("hotep", map.get("bubba"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testWithMapSplitterErrors() {
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> Splitter.on(";").withKeyValueSeparator("").split("Hello=;bubba=hotep"));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> Splitter.on(";").withKeyValueSeparator("=").split("Hello=;bubba=hotep"));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> Splitter.on(";").withKeyValueSeparator("=").split(null));
|
|
||||||
Map<String, String> map = Splitter.on(";").withKeyValueSeparator("=").skipInvalidKeyValues().split("Hello=;bubba=hotep");
|
|
||||||
assertEquals(1, map.size());
|
|
||||||
assertEquals("hotep", map.get("bubba"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
class StreamUtilsTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testAsStream() {
|
|
||||||
List<String> list = List.of("Hello", "World");
|
|
||||||
assertEquals(2, StreamUtils.asStream(list).count());
|
|
||||||
assertEquals(2, StreamUtils.asStream(list.iterator()).count());
|
|
||||||
assertEquals(2, StreamUtils.asStream(list.toArray(), false).count());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
class UtilityWrappersTest {
|
|
||||||
@Test
|
|
||||||
void successFactoriesAndConstructorExposeBodyAndStatus() {
|
|
||||||
assertTrue(Success.success().getSuccess());
|
|
||||||
assertEquals(true, Success.success().getBody());
|
|
||||||
assertFalse(Success.fail().getSuccess());
|
|
||||||
assertEquals(false, Success.fail().getBody());
|
|
||||||
Success value = new Success(true, "body");
|
|
||||||
assertEquals("body", value.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void dataOutputStreamConvertsAndClosesByteArrayOutput() throws Exception {
|
|
||||||
DataOutputStreamHelper stream = new DataOutputStreamHelper();
|
|
||||||
stream.write("hello".getBytes(StandardCharsets.UTF_8));
|
|
||||||
assertArrayEquals("hello".getBytes(StandardCharsets.UTF_8), stream.toByteArray());
|
|
||||||
assertEquals("hello", stream.toString());
|
|
||||||
assertEquals("aGVsbG8=", stream.base64Encoded());
|
|
||||||
stream.close();
|
|
||||||
assertArrayEquals(new byte[0], stream.toByteArray());
|
|
||||||
assertDoesNotThrow(stream::close);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void dataOutputStreamSupportsOtherOutputsAndSwallowsCloseFailure() throws Exception {
|
|
||||||
OutputStream custom = new OutputStream() {
|
|
||||||
@Override
|
|
||||||
public void write(int b) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "custom";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
throw new IllegalStateException("expected");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
DataOutputStreamHelper stream = new DataOutputStreamHelper(custom);
|
|
||||||
assertEquals("custom", stream.toString());
|
|
||||||
assertDoesNotThrow(stream::close);
|
|
||||||
|
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
try (DataOutputStreamHelper explicit = new DataOutputStreamHelper(bytes)) {
|
|
||||||
explicit.writeByte(1);
|
|
||||||
assertArrayEquals(new byte[]{1}, explicit.toByteArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.mockStatic;
|
|
||||||
import static org.mockito.Mockito.CALLS_REAL_METHODS;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
import org.mockito.MockedStatic;
|
|
||||||
|
|
||||||
class UtilsPackageCoverageTest {
|
|
||||||
@TempDir
|
|
||||||
Path tempDir;
|
|
||||||
|
|
||||||
private static java.util.Date deserialize(String value) throws Exception {
|
|
||||||
JsonParser parser = mock(JsonParser.class);
|
|
||||||
when(parser.getText()).thenReturn(value);
|
|
||||||
return new DateTimeStampDeserializer().deserialize(parser, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void dateDeserializerHandlesEpochBuiltInCustomAndInvalidFormats() throws Exception {
|
|
||||||
assertEquals(1234L, deserialize("1234").getTime());
|
|
||||||
|
|
||||||
Locale original = Locale.getDefault();
|
|
||||||
Locale.setDefault(Locale.US);
|
|
||||||
try {
|
|
||||||
assertNotNull(deserialize("January 1, 2020"));
|
|
||||||
assertNotNull(deserialize("12/31/2020"));
|
|
||||||
assertNotNull(deserialize("Dec 31, 2020 1:02:03 PM"));
|
|
||||||
assertNull(deserialize("definitely-not-a-date"));
|
|
||||||
|
|
||||||
Field stylesField = DateTimeStampDeserializer.class.getDeclaredField("styles");
|
|
||||||
stylesField.setAccessible(true);
|
|
||||||
Integer[] styles = (Integer[]) stylesField.get(null);
|
|
||||||
Integer[] originalStyles = styles.clone();
|
|
||||||
java.util.Arrays.fill(styles, -1);
|
|
||||||
try {
|
|
||||||
assertNotNull(deserialize("12/31/2020"));
|
|
||||||
} finally {
|
|
||||||
System.arraycopy(originalStyles, 0, styles, 0, styles.length);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
Locale.setDefault(original);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Test
|
|
||||||
void hashUtilsCoversEveryInputOverloadCaseAndFailure() throws Exception {
|
|
||||||
String expected = HashUtils.hash("SHA-256", "content");
|
|
||||||
byte[] bytes = "content".getBytes(StandardCharsets.UTF_8);
|
|
||||||
Path path = tempDir.resolve("hash.txt");
|
|
||||||
Files.write(path, bytes);
|
|
||||||
File file = path.toFile();
|
|
||||||
|
|
||||||
assertEquals(expected, HashUtils.hash("SHA-256", bytes));
|
|
||||||
assertEquals(expected, HashUtils.hash("SHA-256", path));
|
|
||||||
assertEquals(expected, HashUtils.hash("SHA-256", file));
|
|
||||||
assertEquals(expected.toUpperCase(Locale.ROOT), HashUtils.hash("SHA-256", file, false));
|
|
||||||
assertEquals(expected.toUpperCase(Locale.ROOT), HashUtils.hash("SHA-256", path, false));
|
|
||||||
assertEquals(expected, HashUtils.hash(new ByteArrayInputStream(bytes), "SHA-256"));
|
|
||||||
assertEquals(expected.toUpperCase(Locale.ROOT),
|
|
||||||
HashUtils.hash(new ByteArrayInputStream(bytes), "SHA-256", false));
|
|
||||||
assertThrows(IllegalArgumentException.class,
|
|
||||||
() -> HashUtils.hash("SHA-256", tempDir.resolve("missing")));
|
|
||||||
assertThrows(IllegalArgumentException.class,
|
|
||||||
() -> HashUtils.hash(new ByteArrayInputStream(bytes), "not-an-algorithm"));
|
|
||||||
assertThrows(IllegalArgumentException.class,
|
|
||||||
() -> HashUtils.hash(new java.io.InputStream() {
|
|
||||||
@Override public int read() throws IOException { throw new IOException("read failed"); }
|
|
||||||
}, "SHA-256"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void fileReaderCoversResourceValidationIterationMutationAndFailures() throws Exception {
|
|
||||||
try (FileReader resource = new FileReader("test.properties")) {
|
|
||||||
assertTrue(resource.hasNext());
|
|
||||||
assertSame(resource, resource.iterator());
|
|
||||||
assertNotNull(resource.next());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> new FileReader((String) null));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> new FileReader((Path) null));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> new FileReader(tempDir.resolve("missing")));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> new FileReader(tempDir));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> new FileReader((BufferedReader) null));
|
|
||||||
|
|
||||||
BufferedReader readFailure = new BufferedReader(new StringReader("")) {
|
|
||||||
@Override public String readLine() throws IOException { throw new IOException("read failed"); }
|
|
||||||
};
|
|
||||||
assertThrows(RuntimeException.class, () -> new FileReader(readFailure).hasNext());
|
|
||||||
|
|
||||||
BufferedReader closeFailure = new BufferedReader(new StringReader("")) {
|
|
||||||
@Override public void close() throws IOException { throw new IOException("close failed"); }
|
|
||||||
};
|
|
||||||
assertThrows(RuntimeException.class, () -> new FileReader(closeFailure).close());
|
|
||||||
|
|
||||||
FileReader nullReader = new FileReader(new BufferedReader(new StringReader("")));
|
|
||||||
Field readerField = FileReader.class.getDeclaredField("reader");
|
|
||||||
readerField.setAccessible(true);
|
|
||||||
readerField.set(nullReader, null);
|
|
||||||
assertDoesNotThrow(nullReader::close);
|
|
||||||
|
|
||||||
Path simulated = tempDir.resolve("simulated.txt");
|
|
||||||
try (MockedStatic<Files> files = mockStatic(Files.class, CALLS_REAL_METHODS)) {
|
|
||||||
files.when(() -> Files.notExists(simulated)).thenReturn(false);
|
|
||||||
files.when(() -> Files.isRegularFile(simulated)).thenReturn(true);
|
|
||||||
files.when(() -> Files.newBufferedReader(simulated)).thenThrow(new IOException("open failed"));
|
|
||||||
assertThrows(RuntimeException.class, () -> new FileReader(simulated));
|
|
||||||
}
|
|
||||||
|
|
||||||
FileReader.LineInfo info = new FileReader.LineInfo(1, "line");
|
|
||||||
info.setLineNumber(2);
|
|
||||||
info.setLineLength(10);
|
|
||||||
info.setLine("changed");
|
|
||||||
assertEquals(2, info.getLineNumber());
|
|
||||||
assertEquals(10, info.getLineLength());
|
|
||||||
assertEquals("changed", info.getLine());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void singletonAndUtilityClassConstructorsAreCovered() throws Exception {
|
|
||||||
Field instance = RandomString.class.getDeclaredField("instance");
|
|
||||||
instance.setAccessible(true);
|
|
||||||
instance.set(null, null);
|
|
||||||
assertNotNull(RandomString.getInstance());
|
|
||||||
|
|
||||||
assertNotNull(new HashUtils());
|
|
||||||
assertNotNull(new Checks());
|
|
||||||
assertNotNull(new Utils());
|
|
||||||
assertNotNull(new Constants());
|
|
||||||
assertNotNull(new ObjectUtils());
|
|
||||||
assertNotNull(new StreamUtils());
|
|
||||||
assertNotNull(ObjectUtils.getResourceStream("/test.properties"));
|
|
||||||
|
|
||||||
assertEquals(List.of("a", "b"), StreamUtils.asStream(List.of("a", "b"), true).toList());
|
|
||||||
assertTrue(StreamUtils.asStream(new String[]{"a"}, true).isParallel());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,520 +0,0 @@
|
|||||||
package net.locusworks.common.utils;
|
|
||||||
|
|
||||||
import net.locusworks.common.annotations.MapValue;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test cases for the Utils class
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @since 1.0.0-RELEASE
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class UtilsTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSafeString() {
|
|
||||||
assertNotNull(Utils.safeString(null));
|
|
||||||
assertTrue(Utils.safeString(null).isEmpty());
|
|
||||||
assertFalse(Utils.safeString("hello world").isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAreEqual() {
|
|
||||||
String val1 = "H";
|
|
||||||
String val2 = "H";
|
|
||||||
assertTrue(Utils.areEqual(val1, val2));
|
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> Utils.areEqual("1"));
|
|
||||||
}
|
|
||||||
@ParameterizedTest
|
|
||||||
@MethodSource("areEqualParams")
|
|
||||||
public void testAreEqualWithParams(List<Object> objectList, boolean or, boolean equal) {
|
|
||||||
assertEquals(equal, Utils.areEqual(or, objectList.toArray()));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Stream<Arguments> areEqualParams() {
|
|
||||||
return Stream.of(
|
|
||||||
Arguments.of(List.of("Hello", "Hello"), false, true),
|
|
||||||
Arguments.of(List.of("Hello", "World"), false, false),
|
|
||||||
Arguments.of(List.of("Hello", "World", "Hello"), true, true),
|
|
||||||
Arguments.of(List.of("Hello", "World", "Fair"), true, false)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEmptyString() {
|
|
||||||
assertTrue(Utils.isEmptyString(null));
|
|
||||||
assertTrue(Utils.isEmptyString(""));
|
|
||||||
assertTrue(Utils.isEmptyString(" "));
|
|
||||||
assertFalse(Utils.isEmptyString("foo"));
|
|
||||||
assertFalse(Utils.isEmptyString(" bar "));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testToInteger() {
|
|
||||||
assertEquals(2, (int) Utils.toInteger("Hello word", 2));
|
|
||||||
assertEquals(23, (int) Utils.toInteger("23", 5023));
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@MethodSource("validateValueParams")
|
|
||||||
public <V> void testValidateValue(V value, boolean valid) {
|
|
||||||
assertEquals(valid, Utils.validateValue(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Stream<Arguments> validateValueParams() {
|
|
||||||
return Stream.of(
|
|
||||||
Arguments.of(null, false),
|
|
||||||
Arguments.of(Collections.emptyList(), false),
|
|
||||||
Arguments.of(Map.of(), false),
|
|
||||||
Arguments.of(false, false),
|
|
||||||
Arguments.of("", false),
|
|
||||||
Arguments.of("Hello", true),
|
|
||||||
Arguments.of(List.of("Hello"), true),
|
|
||||||
Arguments.of(Map.of("Hello", "World"), true),
|
|
||||||
Arguments.of(true, true)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@MethodSource("areValidParams")
|
|
||||||
public void testValidateValues(List<Object> objects, boolean or, boolean valid) {
|
|
||||||
assertEquals(valid, Utils.areValid(objects.toArray()));
|
|
||||||
assertEquals(!valid, Utils.areNotValid(objects.toArray()));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Stream<Arguments> areValidParams() {
|
|
||||||
return Stream.of(
|
|
||||||
Arguments.of(List.of("Hello", List.of("Hello"), Map.of("Hello", "World"), true), false, true),
|
|
||||||
Arguments.of(List.of(Collections.emptyList(), Map.of(), false), false, false)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBuildMap() {
|
|
||||||
Map<String, String> mymap = Utils.buildMap(TreeMap.class, String.class, String.class, "Hello", "World");
|
|
||||||
assertNotNull(mymap);
|
|
||||||
assertEquals(1, mymap.size());
|
|
||||||
assertEquals("World", mymap.get("Hello"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCloneList() {
|
|
||||||
String[] values = new String[]{
|
|
||||||
"Hello",
|
|
||||||
"world"
|
|
||||||
};
|
|
||||||
List<String> cloned = Utils.cloneList(new ArrayList<>(Arrays.stream(values).toList()));
|
|
||||||
assertEquals(2, cloned.size());
|
|
||||||
assertThrows(UnsupportedOperationException.class, () -> cloned.add("asdf"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCloneObject()
|
|
||||||
throws InvocationTargetException, InstantiationException, IllegalAccessException,
|
|
||||||
NoSuchMethodException {
|
|
||||||
TestClass clazz = new TestClass();
|
|
||||||
clazz.field1 = "hi";
|
|
||||||
clazz.field2 = "low";
|
|
||||||
clazz.field3 = "world";
|
|
||||||
|
|
||||||
TestClass clazz3 = new TestClass();
|
|
||||||
clazz3.field1 = "hi";
|
|
||||||
clazz3.field2 = "smash";
|
|
||||||
clazz3.field3 = "world";
|
|
||||||
|
|
||||||
clazz.testClass = clazz3;
|
|
||||||
|
|
||||||
TestClass clazz2 = Utils.cloneObject(clazz);
|
|
||||||
assertNotNull(clazz2);
|
|
||||||
assertEquals(clazz.field1, clazz2.field1);
|
|
||||||
assertEquals(clazz.field2, clazz2.field2);
|
|
||||||
assertEquals(clazz.field3, clazz2.field3);
|
|
||||||
assertEquals(clazz.field5, clazz2.field5);
|
|
||||||
assertEquals(clazz.number, clazz2.number);
|
|
||||||
assertEquals(clazz.aBoolean, clazz2.aBoolean);
|
|
||||||
assertNotNull(clazz2.field4);
|
|
||||||
assertNull(clazz2.nullField);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCovertToMap() throws Exception {
|
|
||||||
TestClass clazz = new TestClass();
|
|
||||||
clazz.field1 = "hi";
|
|
||||||
clazz.field2 = "low";
|
|
||||||
clazz.field3 = "world";
|
|
||||||
|
|
||||||
TestClass clazz3 = new TestClass();
|
|
||||||
clazz.field1 = "hi";
|
|
||||||
clazz.field2 = "low";
|
|
||||||
clazz.field3 = "world";
|
|
||||||
clazz.testClass = clazz3;
|
|
||||||
|
|
||||||
Map<String, Object> converted = Utils.convertToMap(clazz);
|
|
||||||
|
|
||||||
assertEquals(7, converted.size());
|
|
||||||
assertEquals("hi", converted.get("other_field"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConvertToStringMap() throws Exception {
|
|
||||||
TestClass clazz = new TestClass();
|
|
||||||
clazz.field1 = "hi";
|
|
||||||
clazz.field2 = "low";
|
|
||||||
clazz.field3 = "world";
|
|
||||||
Map<String, String> converted = Utils.convertToStringMap(clazz);
|
|
||||||
assertEquals(6, converted.size());
|
|
||||||
assertEquals("hi", converted.get("other_field"));
|
|
||||||
|
|
||||||
converted = Utils.convertToStringMap(converted);
|
|
||||||
assertEquals(6, converted.size());
|
|
||||||
assertEquals("hi", converted.get("other_field"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBuildStringMap() {
|
|
||||||
Map<String, String> myMap = Utils.buildStringHashMap("hello", "world");
|
|
||||||
assertNotNull(myMap);
|
|
||||||
assertEquals(1, myMap.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExtractFieldToList() {
|
|
||||||
List<TestClass> list = new ArrayList<>();
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
TestClass clazz = new TestClass();
|
|
||||||
clazz.field5 = i;
|
|
||||||
list.add(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Integer> extractedList = Utils.extractFieldToList("field5", list);
|
|
||||||
java.util.Set<Object> extractedSet = Utils.extractFieldToSet("field5", list);
|
|
||||||
|
|
||||||
assertEquals(10, extractedList.size());
|
|
||||||
assertEquals(10, extractedSet.size());
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
assertEquals(i, extractedList.get(i));
|
|
||||||
assertTrue(extractedSet.contains(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> Utils.extractFieldToList("fieldName", list));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> Utils.extractFieldToSet("fieldName", list));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFilterList() {
|
|
||||||
List<TestClass> list = new ArrayList<>();
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
TestClass clazz = new TestClass();
|
|
||||||
clazz.field5 = i;
|
|
||||||
list.add(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
list.get(0).testClass = list.get(1);
|
|
||||||
|
|
||||||
List<TestClass> filteredList = Utils.filterList("field5", 5, list);
|
|
||||||
assertEquals(1, filteredList.size());
|
|
||||||
assertEquals(5, filteredList.get(0).field5);
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> Utils.filterList("fieldName", 5, list));
|
|
||||||
|
|
||||||
int value = Utils.findValue(5, "field5", list);
|
|
||||||
assertEquals(5, value);
|
|
||||||
|
|
||||||
TestClass tc = Utils.findValue(list.get(1), "testClass", list);
|
|
||||||
assertNotNull(tc);
|
|
||||||
assertEquals(1, tc.field5);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindValues() {
|
|
||||||
List<TestClass> list = new ArrayList<>();
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
TestClass clazz = new TestClass();
|
|
||||||
clazz.field5 = i % 2;
|
|
||||||
list.add(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Integer> values = Utils.findValues(0, "field5", list);
|
|
||||||
assertEquals(5, values.size());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBuildMapExceptions() {
|
|
||||||
Throwable ex = assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(String.class, String.class, String.class, "" ));
|
|
||||||
|
|
||||||
assertNotNull(ex);
|
|
||||||
|
|
||||||
ex = assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(TreeMap.class, String.class, String.class, "Hello"));
|
|
||||||
|
|
||||||
assertEquals("Odd number of arguments provided", ex.getMessage());
|
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(TreeMap.class, String.class, String.class, new Object(), "Hello"));
|
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(TreeMap.class, String.class, String.class, "Hello", new Object()));
|
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(TreeMap.class, Object.class, String.class, "Hello", new Object()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBuildSet() {
|
|
||||||
java.util.Set<String> myset = Utils.buildSet(HashSet.class, String.class, "Hello", "World");
|
|
||||||
assertNotNull(myset);
|
|
||||||
assertEquals(2, myset.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFormatString() {
|
|
||||||
String formatted = Utils.formatString("{} {}", "Hi", 1);
|
|
||||||
assertEquals("Hi 1", formatted);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetClassName() {
|
|
||||||
TestClass tc = new TestClass();
|
|
||||||
assertEquals(tc.getClass().getSimpleName(), Utils.getClassName(tc));
|
|
||||||
assertEquals(tc.getClass().getName(), Utils.getClassName(tc, true));
|
|
||||||
assertEquals("Unknown", Utils.getClassName(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetMapValue() {
|
|
||||||
Integer value = Utils.getMapValue(Map.of("hi", 1), "hi");
|
|
||||||
assertEquals(1, value);
|
|
||||||
|
|
||||||
value = Utils.getMapValue(Map.of("hi", 1), "low", 0);
|
|
||||||
|
|
||||||
assertEquals(0, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsNotValid() {
|
|
||||||
assertTrue(Utils.isNotValid(null, null, null));
|
|
||||||
assertFalse(Utils.isNotValid("null", "null", "null"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsValid() {
|
|
||||||
assertFalse(Utils.isValid(null, null, null));
|
|
||||||
assertTrue(Utils.isValid("null", "null", "null"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testListToMap() {
|
|
||||||
List<TestClass> list = new ArrayList<>();
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
TestClass clazz = new TestClass();
|
|
||||||
clazz.field5 = i;
|
|
||||||
list.add(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<Integer, TestClass> values = Utils.listToMap("field5", list);
|
|
||||||
assertEquals(10, values.size());
|
|
||||||
assertEquals(1, values.get(1).field5);
|
|
||||||
|
|
||||||
assertThrows(Throwable.class, () -> Utils.listToMap("fieldasdf5", list));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMakeArray() {
|
|
||||||
List<TestClass> list = new ArrayList<>();
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
TestClass clazz = new TestClass();
|
|
||||||
clazz.field5 = i;
|
|
||||||
list.add(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertNull(Utils.makeArray(null, String.class));
|
|
||||||
|
|
||||||
TestClass[] array = Utils.makeArray(list, TestClass.class);
|
|
||||||
assertEquals(10, array.length);
|
|
||||||
for(int i = 0; i < 10; i++) {
|
|
||||||
assertEquals(list.get(i), array[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertNull(Utils.makeList((Collection<Object>) null));
|
|
||||||
assertNull(Utils.makeList((Iterable<?>) null));
|
|
||||||
assertNull(Utils.makeList((String[]) null));
|
|
||||||
|
|
||||||
List<TestClass> testList = Utils.makeList(list);
|
|
||||||
for(int i = 0; i < 10; i++) {
|
|
||||||
assertEquals(list.get(i), testList.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
TestClassList tcl = new TestClassList();
|
|
||||||
tcl.testClassList = testList;
|
|
||||||
|
|
||||||
List<TestClass> testClassList = Utils.makeList(tcl);
|
|
||||||
for(int i = 0; i < 10; i++) {
|
|
||||||
assertEquals(list.get(i), testClassList.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<TestClass> testArrayList = Utils.makeList(array);
|
|
||||||
for(int i = 0; i < 10; i++) {
|
|
||||||
assertEquals(list.get(i), testArrayList.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<TestClass> testSet = Utils.makeSet(list);
|
|
||||||
assertEquals(10, testSet.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMapToList() {
|
|
||||||
List<Integer> values = Utils.mapToList(Map.of("Hello", 1));
|
|
||||||
assertEquals(1, values.size());
|
|
||||||
assertEquals(1, values.get(0));
|
|
||||||
|
|
||||||
Set<Integer> setValues = Utils.mapToSet(Map.of("Hello", 1));
|
|
||||||
assertEquals(1, setValues.size());
|
|
||||||
assertTrue(setValues.contains(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReverseMap() {
|
|
||||||
Map<Integer, String> map = Utils.reverseMap(Map.of("Hello", 1));
|
|
||||||
assertEquals(1, map.size());
|
|
||||||
assertEquals("Hello", map.get(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSafeList() {
|
|
||||||
assertEquals(0, Utils.safeArray(null).length);
|
|
||||||
assertTrue(Utils.safeList(null).isEmpty());
|
|
||||||
assertFalse(Utils.safeIterable(null).iterator().hasNext());
|
|
||||||
assertTrue(Utils.safeSet(null).isEmpty());
|
|
||||||
|
|
||||||
List<String> list = List.of("Hello", "World");
|
|
||||||
|
|
||||||
String[] stringArray = list.toArray(new String[0]);
|
|
||||||
|
|
||||||
assertEquals(list, Utils.safeList(list));
|
|
||||||
assertEquals(stringArray, Utils.safeArray(stringArray));
|
|
||||||
assertEquals(list, Utils.safeIterable(list));
|
|
||||||
|
|
||||||
Set<String> testSet = Set.of("Hello", "World");
|
|
||||||
|
|
||||||
assertEquals(testSet, Utils.safeSet(testSet));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetToList() {
|
|
||||||
List<String> list = Utils.setToList(Set.of("Hello", "World"));
|
|
||||||
assertEquals(2, list.size());
|
|
||||||
|
|
||||||
list = Utils.toList(Set.of("Hello", "World"));
|
|
||||||
assertEquals(2, list.size());
|
|
||||||
|
|
||||||
Set<String> set = Utils.toSet("Hello", "World");
|
|
||||||
|
|
||||||
assertEquals(2, set.size());
|
|
||||||
|
|
||||||
assertTrue(set.contains("Hello"));
|
|
||||||
assertTrue(set.contains("World"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testToByteList() {
|
|
||||||
byte[] bytes = new byte[10];
|
|
||||||
|
|
||||||
for (int i = 0; i < bytes.length; i++) {
|
|
||||||
bytes[i] = (byte)i;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Byte> byteList = Utils.toByteList(bytes);
|
|
||||||
assertEquals(bytes.length, byteList.size());
|
|
||||||
|
|
||||||
for(int i = 0; i < bytes.length; i++) {
|
|
||||||
assertEquals(bytes[i], byteList.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIterableSize() {
|
|
||||||
List<String> stringList = List.of("Hello", "World");
|
|
||||||
assertEquals(stringList.size(), (int)Utils.size(stringList));
|
|
||||||
assertEquals(stringList.get(1), Utils.get(stringList, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExceptionWrapper() {
|
|
||||||
assertThrows(RuntimeException.class, () -> List.of("Hi", "Low").forEach(Utils.handleExceptionWrapper(o -> {
|
|
||||||
throw new Exception("bleh");
|
|
||||||
})));
|
|
||||||
|
|
||||||
AtomicInteger atomicInteger = new AtomicInteger(0);
|
|
||||||
List.of("Hi", "Low").forEach(Utils.handleExceptionWrapper(o -> {
|
|
||||||
atomicInteger.incrementAndGet();
|
|
||||||
}));
|
|
||||||
|
|
||||||
assertEquals(2, atomicInteger.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testValidateValues() {
|
|
||||||
assertTrue(Utils.validateValues("Hello", "World"));
|
|
||||||
assertTrue(Utils.validateValuesOr("Hello", null));
|
|
||||||
assertTrue(Utils.validateValuesOr(null, "Hello"));
|
|
||||||
assertFalse(Utils.validateValuesOr(null, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsJunitRunning() {
|
|
||||||
assertTrue(Utils.isJUnitRunning());
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TestClassList implements Iterable<TestClass> {
|
|
||||||
private List<TestClass> testClassList;
|
|
||||||
@Override public Iterator<TestClass> iterator() {
|
|
||||||
return testClassList.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TestClass {
|
|
||||||
@MapValue("other_field")
|
|
||||||
private String field1;
|
|
||||||
|
|
||||||
@MapValue(ignore = true)
|
|
||||||
private String field2;
|
|
||||||
|
|
||||||
private String field3;
|
|
||||||
|
|
||||||
private final String field4 = "final";
|
|
||||||
@MapValue
|
|
||||||
private int field5 = 5;
|
|
||||||
|
|
||||||
private Boolean aBoolean = Boolean.valueOf("true");
|
|
||||||
|
|
||||||
private Double number = 1.0d;
|
|
||||||
|
|
||||||
private String nullField = null;
|
|
||||||
|
|
||||||
private TestClass testClass;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package net.locusworks.test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
import net.locusworks.common.crypto.AES;
|
|
||||||
import net.locusworks.common.utils.Utils;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
|
|
||||||
public class AESEncryptionTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEncryption() {
|
|
||||||
try {
|
|
||||||
String encrypted = AES.createInstance().encrypt("hello world");
|
|
||||||
assertFalse(Utils.isEmptyString(encrypted), String.format("Encrypted String is not blank? :%s", encrypted));
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace(System.err);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDecryption() {
|
|
||||||
String testString = "hello world";
|
|
||||||
try {
|
|
||||||
AES aes = AES.createInstance();
|
|
||||||
String encrypted = aes.encrypt(testString);
|
|
||||||
assertFalse(Utils.isEmptyString(encrypted), String.format("Encrypted String is not blank? :%s", encrypted));
|
|
||||||
|
|
||||||
String decrypted = aes.decrypt(encrypted);
|
|
||||||
assertFalse(Utils.isEmptyString(encrypted), String.format("Decrypted String is not blank? :%s", decrypted));
|
|
||||||
|
|
||||||
assertEquals(testString, decrypted, "Test String and Original String the same? :%s");
|
|
||||||
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace(System.err);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package net.locusworks.test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
import net.locusworks.common.crypto.HashSalt;
|
|
||||||
import net.locusworks.common.utils.Utils;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
public class HashSaltTest {
|
|
||||||
|
|
||||||
private static final String samplePassword = "Hello World";
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEncryption() {
|
|
||||||
try {
|
|
||||||
String hashSalt = HashSalt.createHash(samplePassword);
|
|
||||||
assertFalse(Utils.isEmptyString(hashSalt), String.format("Encrypted String is not blank? :%s", hashSalt));
|
|
||||||
} catch (Exception ex) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDecryption() {
|
|
||||||
try {
|
|
||||||
String hashSalt = HashSalt.createHash(samplePassword);
|
|
||||||
boolean decrypted = HashSalt.validatePassword(samplePassword, hashSalt);
|
|
||||||
assertTrue(decrypted, "Test String and Original String the same? :%s");
|
|
||||||
} catch (Exception ex) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
package net.locusworks.test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
|
||||||
|
|
||||||
import net.locusworks.common.immutables.Pair;
|
|
||||||
import net.locusworks.common.immutables.Triplet;
|
|
||||||
import net.locusworks.common.immutables.Unit;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
|
|
||||||
public class ImmutablesTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUnit() {
|
|
||||||
Unit<String> unit1 = new Unit<>("Hello World");
|
|
||||||
Unit<String> unit3 = new Unit<>("Hello World");
|
|
||||||
assertEquals("Hello World", unit1.getValue1());
|
|
||||||
|
|
||||||
Unit<Integer> unit2 = new Unit<>(2);
|
|
||||||
assertEquals(2, (int) unit2.getValue1());
|
|
||||||
|
|
||||||
assertEquals(unit1, unit3);
|
|
||||||
assertNotEquals(unit1, unit2);
|
|
||||||
assertNotEquals(unit1, new Object());
|
|
||||||
assertNotEquals(unit1, null);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testPair() {
|
|
||||||
Pair<String, String> pair1 = new Pair<>("Hello", "World");
|
|
||||||
Pair<String, String> pair2 = new Pair<>("Hello", "World");
|
|
||||||
Pair<String, String> pair3 = new Pair<>("Hello", "World2");
|
|
||||||
assertEquals("Hello", pair1.getValue1());
|
|
||||||
assertEquals("World", pair1.getValue2());
|
|
||||||
assertEquals(pair1, pair2);
|
|
||||||
|
|
||||||
assertNotEquals(pair1, pair3);
|
|
||||||
assertNotEquals(pair1, new Object());
|
|
||||||
assertNotEquals(pair1, null);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTriplet() {
|
|
||||||
Triplet<String, Integer, String> triplet1 = new Triplet<>("Hello", 24, "World");
|
|
||||||
Triplet<String, Integer, String> triplet2 = new Triplet<>("Hello", 25, "World");
|
|
||||||
Triplet<String, Integer, String> triplet3 = new Triplet<>("Hello", 24, "World2");
|
|
||||||
Triplet<String, Integer, String> triplet4 = new Triplet<>("Hello", 24, "World");
|
|
||||||
|
|
||||||
assertEquals("Hello", triplet1.getValue1());
|
|
||||||
assertEquals(24, (int) triplet1.getValue2());
|
|
||||||
assertEquals("World", triplet1.getValue3());
|
|
||||||
assertEquals(triplet1, triplet4);
|
|
||||||
|
|
||||||
assertNotEquals(triplet1, triplet2);
|
|
||||||
assertNotEquals(triplet1, triplet3);
|
|
||||||
assertNotEquals(triplet1, new Object());
|
|
||||||
assertNotEquals(triplet1, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package net.locusworks.test;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import net.locusworks.common.immutables.Triplet;
|
|
||||||
import net.locusworks.common.objectmapper.ObjectMapperHelper;
|
|
||||||
import net.locusworks.common.utils.Utils;
|
|
||||||
import org.junit.jupiter.api.AfterAll;
|
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static net.locusworks.common.utils.Constants.JUNIT_TEST_CHECK;
|
|
||||||
import static net.locusworks.common.utils.Constants.LOG4J_CONFIG_PROPERTY;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test cases to test ObjectMapperHelper.class
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @since 1.0.0-RELEASE
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ObjectMapperHelperTest {
|
|
||||||
|
|
||||||
private static Triplet<String, Integer, String> test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws java.lang.Exception exception
|
|
||||||
*/
|
|
||||||
@BeforeAll
|
|
||||||
public static void setUpBeforeClass() throws Exception {
|
|
||||||
System.setProperty(LOG4J_CONFIG_PROPERTY, "log4j2-test.xml");
|
|
||||||
System.setProperty(JUNIT_TEST_CHECK, "true");
|
|
||||||
test = new Triplet<String, Integer, String>("Hello", 24, "World");
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
public static void tearDownAfterClass() throws Exception {
|
|
||||||
System.clearProperty(LOG4J_CONFIG_PROPERTY);
|
|
||||||
System.clearProperty(JUNIT_TEST_CHECK);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWrite() {
|
|
||||||
String value = ObjectMapperHelper.writeValue(test).getResults();
|
|
||||||
assertTrue(value != null && !value.trim().isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRead() {
|
|
||||||
String value = ObjectMapperHelper.writeValue(test).getResults();
|
|
||||||
assertTrue(value != null && !value.trim().isEmpty());
|
|
||||||
|
|
||||||
Triplet<?, ?, ?> tmp = ObjectMapperHelper.readValue(value, Triplet.class).getResults();
|
|
||||||
assertNotNull(tmp);
|
|
||||||
assertEquals(tmp, test);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
@Test
|
|
||||||
public void testListWriteRead() {
|
|
||||||
List<Triplet<String, Integer, String>> htrList = Utils.toList(test);
|
|
||||||
String value = ObjectMapperHelper.writeValue(htrList).getResults();
|
|
||||||
assertTrue(value != null && !value.trim().isEmpty());
|
|
||||||
List<Triplet> tmpList = ObjectMapperHelper.readListValue(value, Triplet.class).getResults();
|
|
||||||
assertTrue(tmpList != null && !tmpList.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
package net.locusworks.test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import net.locusworks.common.configuration.PropertiesManager;
|
|
||||||
import org.junit.jupiter.api.AfterAll;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test cases for the properties manager class
|
|
||||||
*
|
|
||||||
* @author Isaac Parenteau
|
|
||||||
* @since 1.0.0-RELEASE
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class PropertiesManagerTest {
|
|
||||||
|
|
||||||
private static final String PROPERTIES_FILE = "test.properties";
|
|
||||||
private static final String TMP_PROPS = "temp.properties";
|
|
||||||
private static final int ENTRY_SIZE = 4;
|
|
||||||
|
|
||||||
public enum Configuration {
|
|
||||||
DB_HOST("dbHost"),
|
|
||||||
DB_PORT("dbPort"),
|
|
||||||
USER_EXPIRATION_DAYS("userExpirationDays"),
|
|
||||||
LOG_LEVEL("logLevel");
|
|
||||||
|
|
||||||
private final String value;
|
|
||||||
|
|
||||||
private Configuration(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current value of the enumeration
|
|
||||||
*
|
|
||||||
* @return value
|
|
||||||
*/
|
|
||||||
public String getValue() {
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
public static void removeSavedProps() {
|
|
||||||
File tmp = new File(TMP_PROPS);
|
|
||||||
if (tmp.exists()) {
|
|
||||||
tmp.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testPropertiesLoad() {
|
|
||||||
try {
|
|
||||||
Properties props = PropertiesManager.loadConfiguration(this.getClass(), PROPERTIES_FILE);
|
|
||||||
assertNotNull(props);
|
|
||||||
assertTrue(props.containsKey(Configuration.USER_EXPIRATION_DAYS.toString()));
|
|
||||||
assertTrue(props.containsKey(Configuration.DB_HOST.toString()));
|
|
||||||
assertTrue(props.containsKey(Configuration.DB_PORT.toString()));
|
|
||||||
assertTrue(props.containsKey(Configuration.LOG_LEVEL.toString()));
|
|
||||||
} catch (IOException e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAddConfiguration() {
|
|
||||||
try {
|
|
||||||
Properties props = PropertiesManager.loadConfiguration(this.getClass(), PROPERTIES_FILE);
|
|
||||||
Properties tmp = new Properties();
|
|
||||||
assertEquals(0, tmp.size());
|
|
||||||
PropertiesManager.addConfiguration(tmp, props);
|
|
||||||
assertEquals(ENTRY_SIZE, tmp.size());
|
|
||||||
assertTrue(tmp.containsKey(Configuration.USER_EXPIRATION_DAYS.toString()));
|
|
||||||
assertTrue(tmp.containsKey(Configuration.DB_HOST.toString()));
|
|
||||||
assertTrue(tmp.containsKey(Configuration.DB_PORT.toString()));
|
|
||||||
assertTrue(tmp.containsKey(Configuration.LOG_LEVEL.toString()));
|
|
||||||
} catch (IOException e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRemoveConfiguration() {
|
|
||||||
try {
|
|
||||||
Properties props = PropertiesManager.loadConfiguration(this.getClass(), PROPERTIES_FILE);
|
|
||||||
Properties tmp = new Properties();
|
|
||||||
assert props != null;
|
|
||||||
assertEquals(ENTRY_SIZE, props.size());
|
|
||||||
assertEquals(0, tmp.size());
|
|
||||||
PropertiesManager.removeConfiguration(props, tmp);
|
|
||||||
assertEquals(0, props.size());
|
|
||||||
assertEquals(0, tmp.size());
|
|
||||||
} catch (IOException e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSaveConfiguration() {
|
|
||||||
try {
|
|
||||||
Properties props = PropertiesManager.loadConfiguration(this.getClass(), PROPERTIES_FILE);
|
|
||||||
Path tmpFile = Paths.get(TMP_PROPS);
|
|
||||||
PropertiesManager.saveConfiguration(props, tmpFile, "test propertis");
|
|
||||||
Properties tmp = PropertiesManager.loadConfiguration(tmpFile);
|
|
||||||
assertEquals(ENTRY_SIZE, tmp.size());
|
|
||||||
assertTrue(tmp.containsKey(Configuration.USER_EXPIRATION_DAYS.toString()));
|
|
||||||
assertTrue(tmp.containsKey(Configuration.DB_HOST.toString()));
|
|
||||||
assertTrue(tmp.containsKey(Configuration.DB_PORT.toString()));
|
|
||||||
assertTrue(tmp.containsKey(Configuration.LOG_LEVEL.toString()));
|
|
||||||
} catch (IOException e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Configuration status="WARN">
|
|
||||||
<Appenders>
|
|
||||||
<Console name="ConsoleAppender" target="SYSTEM_OUT">
|
|
||||||
<PatternLayout pattern="%d{dd-MMM-yyyy HH:mm:ss.SSS} [%-5p] %m%n" />
|
|
||||||
</Console>
|
|
||||||
</Appenders>
|
|
||||||
<Loggers>
|
|
||||||
<Root level="TRACE">
|
|
||||||
<AppenderRef ref="ConsoleAppender" level="INFO"/>
|
|
||||||
</Root>
|
|
||||||
</Loggers>
|
|
||||||
</Configuration>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
userExpirationDays=3650
|
|
||||||
dbHost=localhost
|
|
||||||
dbPort=3306
|
|
||||||
logLevel=INFO
|
|
||||||
Reference in new issue
Block a user