Initial Commit
This commit is contained in:
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
.classpath
|
||||
.idea
|
||||
.project
|
||||
.settings
|
||||
filerepo_client/dist/
|
||||
filerepo_client/nbproject/private/
|
||||
filerepo_client/node/
|
||||
filerepo_client/node_modules/
|
||||
filerepo_client/test_out/
|
||||
filerepo_client/temp/
|
||||
filerepo_client/app/compiled-less
|
||||
filerepo_webapp/.externalToolBuilders/
|
||||
npm-debug.log
|
||||
phantomjs
|
||||
tags
|
||||
*.DS_Store
|
||||
*/bin/
|
||||
**/.classpath
|
||||
**/.settings
|
||||
**/*.swp
|
||||
**/target
|
||||
**/.tern-project
|
||||
**/*.iml
|
||||
**/git.properties
|
177
Jenkinsfile
vendored
Normal file
177
Jenkinsfile
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
#!groovy
|
||||
|
||||
// Required Jenkins plugins:
|
||||
// https://wiki.jenkins-ci.org/display/JENKINS/Timestamper
|
||||
// https://wiki.jenkins-ci.org/display/JENKINS/Static+Code+Analysis+Plug-ins
|
||||
// https://wiki.jenkins-ci.org/display/JENKINS/Checkstyle+Plugin ?
|
||||
// https://wiki.jenkins-ci.org/display/JENKINS/FindBugs+Plugin
|
||||
// https://wiki.jenkins-ci.org/display/JENKINS/PMD+Plugin ?
|
||||
// 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
|
||||
// https://wiki.jenkins-ci.org/display/JENKINS/JaCoCo+Plugin ?
|
||||
|
||||
|
||||
init()
|
||||
|
||||
def branch_name
|
||||
def branch_name_base
|
||||
def build_number
|
||||
def build_url
|
||||
def git_commit
|
||||
def job_name
|
||||
def tag
|
||||
def version
|
||||
def build_type
|
||||
def display_name
|
||||
|
||||
def init() {
|
||||
|
||||
// Keep the 5 most recent builds
|
||||
properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', numToKeepStr: '5']]])
|
||||
|
||||
build_number = env.BUILD_NUMBER
|
||||
build_url = env.BUILD_URL
|
||||
job_name = "${env.JOB_NAME}"
|
||||
branch_name = env.BRANCH_NAME
|
||||
branch_name_docker = branch_name.replaceAll(/\//,'.')
|
||||
|
||||
// execute the branch type specific pipeline code
|
||||
try {
|
||||
|
||||
if (branch_name.indexOf('release/')==0) build_type='release'
|
||||
if (branch_name.indexOf('feature/')==0) build_type='feature'
|
||||
if (branch_name.indexOf('develop')==0) build_type='develop'
|
||||
if (branch_name.indexOf('hotfix')==0) build_type='hotfix'
|
||||
if (branch_name.indexOf('bugfix')==0) build_type='bugfix'
|
||||
|
||||
// common pipeline elements
|
||||
node('master') {
|
||||
Initialize()
|
||||
SetVersion(build_type)
|
||||
print_vars() // after SetVersion - all variables now defined
|
||||
set_result('INPROGRESS')
|
||||
Build() // builds database via flyway migration
|
||||
}
|
||||
|
||||
node('master') {
|
||||
// StopContainers()
|
||||
set_result('SUCCESS')
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
node() {
|
||||
set_result('FAILURE')
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
def Build() {
|
||||
stage ('build') {
|
||||
mvn "install -DskipTests=true -Dbuild.revision=${git_commit}"
|
||||
//mvn "$mvn_cmd"
|
||||
step([$class: 'ArtifactArchiver', artifacts: '**/target/*.jar', fingerprint: true])
|
||||
}
|
||||
}
|
||||
|
||||
def Initialize() {
|
||||
stage ('initialize') {
|
||||
|
||||
// deleteDir()
|
||||
|
||||
// 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) {
|
||||
// add node and maven tools to path before calling maven
|
||||
def mvnHome = tool name: 'maven-3.6.1'
|
||||
env.PATH = "${mvnHome}/bin:${env.PATH}"
|
||||
sh "mvn ${args}"
|
||||
}
|
||||
|
||||
def mvn_initial(args) {
|
||||
// add node and maven tools to path before calling maven
|
||||
def mvnHome = tool name: 'maven-3.6.1'
|
||||
env.PATH = "${mvnHome}/bin:${env.PATH}"
|
||||
sh "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 "branch_name_docker = ${branch_name_docker}"
|
||||
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
|
||||
//version = branch_name.substring('release/'.length()) + "." + build_number
|
||||
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
|
||||
// #900 - develop
|
||||
// #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
|
17
README.md
Normal file
17
README.md
Normal file
@ -0,0 +1,17 @@
|
||||
Locusworks Commons
|
||||
=
|
||||
|
||||
- Library with common generic functions
|
||||
|
||||
Install
|
||||
==
|
||||
|
||||
Maven
|
||||
===
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>net.locusworks</groupId>
|
||||
<artifactId>locusworks-commons</artifactId>
|
||||
<version>1.1.0-RELEASE</version>
|
||||
</dependency>
|
||||
```
|
14
bitbucket-pipelines.yml
Normal file
14
bitbucket-pipelines.yml
Normal file
@ -0,0 +1,14 @@
|
||||
# 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
|
161
pom.xml
Normal file
161
pom.xml
Normal file
@ -0,0 +1,161 @@
|
||||
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>net.locusworks</groupId>
|
||||
<artifactId>locusworks-commons</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>locusworks_commons</name>
|
||||
<description>Common library for locusworks projects</description>
|
||||
|
||||
<organization>
|
||||
<name>Locusworks</name>
|
||||
<url>http://www.locusworks.net</url>
|
||||
</organization>
|
||||
|
||||
<scm>
|
||||
<connection>locus2k@bitbucket.org:locus2k/commons.git</connection>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<log4j.version>2.12.0</log4j.version>
|
||||
<slf4j.version>1.7.26</slf4j.version>
|
||||
<jackson.version>2.9.9</jackson.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.20.1</version>
|
||||
<configuration>
|
||||
<testFailureIgnore>true</testFailureIgnore>
|
||||
<skipTests>true</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
<version>5.1.4</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</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpmime</artifactId>
|
||||
<version>4.5.5</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>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.9.9.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>nexus-proxy-public</id>
|
||||
<url>http://devops.locusworks.net:8081/repository/maven-public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>nexus-proxy-public</id>
|
||||
<url>http://devops.locusworks.net:8081/repository/maven-public/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>nexus-snapshot</id>
|
||||
<url>http://devops.locusworks.net:8081/repository/locusworks-snapshot/</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>nexus-release</id>
|
||||
<url>http://devops.locusworks.net:8081/repository/locusworks-release/</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
</project>
|
68
src/main/java/net/locusworks/common/Charsets.java
Normal file
68
src/main/java/net/locusworks/common/Charsets.java
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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>.
|
||||
*
|
||||
* 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;
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
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, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MapValue {
|
||||
|
||||
String value() default "";
|
||||
|
||||
boolean ignore() default false;
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package net.locusworks.common.configuration;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ConfigurationCallback {
|
||||
void results(String msg);
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
package net.locusworks.common.configuration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
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 File 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 = new File(String.format("%s/%s", baseDir, 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.getName());
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
package net.locusworks.common.configuration;
|
||||
|
||||
import static net.locusworks.common.Charsets.UTF_8;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.locusworks.common.immutables.Pair;
|
||||
/**
|
||||
* Properties manager class to help load and read properties
|
||||
* @author Isaac Parenteau
|
||||
* @version 1.0.0
|
||||
* @date 02/15/2018
|
||||
*/
|
||||
public class PropertiesManager {
|
||||
/**
|
||||
* Load a configuration from 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
|
||||
* @param file File to load
|
||||
* @return properties
|
||||
* @throws IOException Exception thrown the file can't be read
|
||||
*/
|
||||
public static Properties loadConfiguration(File file) throws IOException {
|
||||
if (!file.exists()) {
|
||||
return new Properties();
|
||||
}
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), UTF_8));
|
||||
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) {
|
||||
Map<String, String> results = 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(key -> key.getValue1(), value -> value.getValue2()));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
Map<String, String> results = 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))))
|
||||
.collect(Collectors.toList()) //Create a list of paired items (key value) of the items that were filtered
|
||||
.stream()
|
||||
.map(pair -> { //remove those pairs from the from properties
|
||||
from.remove(pair.getValue1());
|
||||
return pair;
|
||||
})
|
||||
.collect(Collectors.toMap(key -> key.getValue1(), value -> value.getValue2())); //create a map of what was removed
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the properties file to disk
|
||||
* @param props Properties file to save
|
||||
* @param fileToSave File to save to
|
||||
* @param comment Any comments to add
|
||||
*/
|
||||
public static void saveConfiguration(Properties props, File fileToSave, String comment) {
|
||||
try(FileOutputStream fos = new FileOutputStream(fileToSave)) {
|
||||
props.store(fos, comment == null ? "" : comment);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
162
src/main/java/net/locusworks/common/crypto/AES.java
Normal file
162
src/main/java/net/locusworks/common/crypto/AES.java
Normal file
@ -0,0 +1,162 @@
|
||||
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.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
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 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_ALGORITH = "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 void initSecureKey(String seed) {
|
||||
try {
|
||||
SecureRandom sr = getSecureRandom(seed);
|
||||
KeyGenerator generator = KeyGenerator.getInstance(ENCRYPTION_TYPE);
|
||||
generator.init(128, sr);
|
||||
init(generator.generateKey().getEncoded(), sr);
|
||||
} catch (Exception ex) {
|
||||
System.err.println(ex);
|
||||
throw new IllegalArgumentException("Unable to initalize 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
|
||||
* @throws NoSuchProviderException thrown when the provider cant be found
|
||||
*/
|
||||
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
|
||||
* @param sr
|
||||
*/
|
||||
private void init(final byte[] key, SecureRandom sr) {
|
||||
try {
|
||||
this.cipher = Cipher.getInstance(ENCRYPTION_ALGORITH, PROVIDER);
|
||||
this.secretKeySpec = new SecretKeySpec(key, ENCRYPTION_TYPE);
|
||||
this.ivParamSpec = new IvParameterSpec(RandomString.getBytes(16, sr));
|
||||
} catch (Exception ex) {
|
||||
System.err.println(ex);
|
||||
throw new IllegalArgumentException("Unable to initalize 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 setSeed(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.getString(16));
|
||||
}
|
||||
|
||||
public static AES createInstance(byte[] byteSeed) {
|
||||
String seed = new String(byteSeed, UTF_8);
|
||||
return createInstance(seed);
|
||||
}
|
||||
|
||||
public static AES createInstance(String seed) {
|
||||
AES aes = new AES();
|
||||
aes.setSeed(seed);
|
||||
return aes;
|
||||
}
|
||||
|
||||
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])).encrypt(String.valueOf(args[0])));
|
||||
} else {
|
||||
System.out.println(AES.createInstance().encrypt(String.valueOf(args[0])));
|
||||
}
|
||||
}
|
||||
}
|
30
src/main/java/net/locusworks/common/crypto/AESKey.java
Normal file
30
src/main/java/net/locusworks/common/crypto/AESKey.java
Normal file
@ -0,0 +1,30 @@
|
||||
package net.locusworks.common.crypto;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
|
||||
import net.locusworks.common.Charsets;
|
||||
|
||||
public class AESKey implements PrivateKey {
|
||||
|
||||
private static final long serialVersionUID = -8452357427706386362L;
|
||||
private 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);
|
||||
}
|
||||
}
|
45
src/main/java/net/locusworks/common/crypto/AESKeySpec.java
Normal file
45
src/main/java/net/locusworks/common/crypto/AESKeySpec.java
Normal file
@ -0,0 +1,45 @@
|
||||
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";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
189
src/main/java/net/locusworks/common/crypto/HashSalt.java
Normal file
189
src/main/java/net/locusworks/common/crypto/HashSalt.java
Normal file
@ -0,0 +1,189 @@
|
||||
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])));
|
||||
}
|
||||
}
|
213
src/main/java/net/locusworks/common/crypto/KeyFile.java
Normal file
213
src/main/java/net/locusworks/common/crypto/KeyFile.java
Normal file
@ -0,0 +1,213 @@
|
||||
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 = IOUtils.toString(new FileInputStream(keyFile), Charsets.UTF_8);
|
||||
|
||||
boolean rsaFormat = !contentStr.startsWith("ssh-rsa") && !contentStr.startsWith("aes-seed");
|
||||
if (rsaFormat) {
|
||||
contentStr = contentStr.replace("-----.*", "");
|
||||
}
|
||||
|
||||
contentStr = contentStr.replace("\\r?\\n", "");
|
||||
|
||||
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();
|
||||
return;
|
||||
} catch (NullPointerException | InvalidKeySpecException ikse) { continue; }
|
||||
}
|
||||
|
||||
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", 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 KeySpec keySpec;
|
||||
private boolean isPrivate;
|
||||
private 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
156
src/main/java/net/locusworks/common/crypto/RSA.java
Normal file
156
src/main/java/net/locusworks/common/crypto/RSA.java
Normal file
@ -0,0 +1,156 @@
|
||||
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/PKCS10PADDING";
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
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));
|
||||
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
|
||||
return keySpec;
|
||||
} 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 i = 0; i < bytes.length; i++) {
|
||||
length += bytes[i] << shift;
|
||||
shift -= 8;
|
||||
}
|
||||
byte[] val = new byte[length];
|
||||
in.read(val);
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Package contains classes that help encrypting, decrypting, salting and hashing objects
|
||||
* @author Isaac Parenteau
|
||||
*/
|
||||
package net.locusworks.common.crypto;
|
@ -0,0 +1,108 @@
|
||||
package net.locusworks.common.exceptions;
|
||||
|
||||
/***
|
||||
* Custom exception class for the patch repository
|
||||
* @author Isaac Parenteau
|
||||
*
|
||||
*/
|
||||
public class ApplicationException extends Exception {
|
||||
private final Integer code;
|
||||
boolean success = false;
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
55
src/main/java/net/locusworks/common/immutables/Pair.java
Normal file
55
src/main/java/net/locusworks/common/immutables/Pair.java
Normal file
@ -0,0 +1,55 @@
|
||||
package net.locusworks.common.immutables;
|
||||
|
||||
/**
|
||||
* Class that holds two immutable objects as a pair
|
||||
* @author Isaac Parenteau
|
||||
* @version 1.0.0
|
||||
* @param <V1> class type of object 1
|
||||
* @param <V2> class type of object 2
|
||||
*/
|
||||
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) {
|
||||
this.value2 = value2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value2
|
||||
* @return value2
|
||||
*/
|
||||
public V2 getValue2() {
|
||||
return this.value2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof Pair)) return false;
|
||||
|
||||
Pair<?, ?> otherPair = (Pair<?, ?>)other;
|
||||
|
||||
return super.equals(otherPair) && this.getValue2().equals(otherPair.getValue2());
|
||||
}
|
||||
}
|
57
src/main/java/net/locusworks/common/immutables/Triplet.java
Normal file
57
src/main/java/net/locusworks/common/immutables/Triplet.java
Normal file
@ -0,0 +1,57 @@
|
||||
package net.locusworks.common.immutables;
|
||||
|
||||
/**
|
||||
* Class that holds three immutable objects as triplets
|
||||
* @author Isaac Parenteau
|
||||
* @version 1.0.0
|
||||
* @param <V1> class type of object 1
|
||||
* @param <V2> class type of object 2
|
||||
* @param <V3> class type of object 3
|
||||
*/
|
||||
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) {
|
||||
this.value3 = value3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value 3
|
||||
* @return value 3
|
||||
*/
|
||||
public V3 getValue3() {
|
||||
return value3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof Triplet)) return false;
|
||||
|
||||
Triplet<?, ?, ?> otherTriplet = (Triplet<?, ?, ?>)other;
|
||||
|
||||
return super.equals(otherTriplet) && this.getValue3().equals(otherTriplet.getValue3());
|
||||
}
|
||||
}
|
50
src/main/java/net/locusworks/common/immutables/Unit.java
Normal file
50
src/main/java/net/locusworks/common/immutables/Unit.java
Normal file
@ -0,0 +1,50 @@
|
||||
package net.locusworks.common.immutables;
|
||||
|
||||
/**
|
||||
* Class that holds three immutable objects as triplets
|
||||
* @author Isaac Parenteau
|
||||
* @version 1.0.0
|
||||
* @param <V1> class type of object 1
|
||||
*/
|
||||
public class Unit<V1> {
|
||||
|
||||
private V1 value1;
|
||||
|
||||
/**
|
||||
* Default constructor with no values
|
||||
*/
|
||||
public Unit() {}
|
||||
|
||||
/**
|
||||
* Constuctor
|
||||
* @param value1 value 1
|
||||
*/
|
||||
public Unit(V1 value1) {
|
||||
this.value1 = value1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value 1
|
||||
* @param value1 value 1
|
||||
*/
|
||||
public void setValue1(V1 value1) {
|
||||
this.value1 = value1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value 1
|
||||
* @return value1
|
||||
*/
|
||||
public V1 getValue1() {
|
||||
return value1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof Unit)) return false;
|
||||
|
||||
Unit<?> otherUnit = (Unit<?>)other;
|
||||
|
||||
return this.getValue1().equals(otherUnit.getValue1());
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.locusworks.common.interfaces;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public interface AutoCloseableIterator<T> extends Iterator<T>, AutoCloseable {
|
||||
|
||||
@Override
|
||||
public void close();
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package net.locusworks.common.interfaces;
|
||||
|
||||
public interface PersistableRequest {
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package net.locusworks.common.interfaces;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ThrowingConsumer<T, E extends Exception> {
|
||||
void accept(T t) throws E;
|
||||
}
|
346
src/main/java/net/locusworks/common/io/IOUtils.java
Normal file
346
src/main/java/net/locusworks/common/io/IOUtils.java
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* 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.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
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 input the <code>InputStream</code> to read from, not null
|
||||
* @param encoding 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.toString());
|
||||
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(new File(fileName), data, Charsets.UTF_8);
|
||||
}
|
||||
|
||||
|
||||
public static void writeStringToFile(String fileName, String data, Charset charset) throws IOException {
|
||||
writeStringToFile(new File(fileName), data, charset);
|
||||
}
|
||||
|
||||
public static void writeStringToFile(File file, String data) throws IOException {
|
||||
writeStringToFile(file, data, Charsets.UTF_8);
|
||||
}
|
||||
|
||||
public static void writeStringToFile(File file, String data, Charset charset) throws IOException {
|
||||
try(Writer writer = new OutputStreamWriter(new FileOutputStream(file), charset)) {
|
||||
writer.write(data);
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteFile(String fileName) {
|
||||
deleteFile(new File(fileName));
|
||||
}
|
||||
|
||||
public static void deleteFile(File file) {
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
file.deleteOnExit();
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteFiles(String... fileNames) {
|
||||
Arrays.asList(fileNames).forEach(file -> deleteFile(file));
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
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;
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package net.locusworks.common.migration;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface MigrationCallback {
|
||||
void results(String msg);
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
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 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.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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package net.locusworks.common.net;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import net.locusworks.common.net.certmanagers.TrustAllCertsManager;
|
||||
import net.locusworks.common.net.hostverifiers.AllHostValidVerifyer;
|
||||
|
||||
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 HttpClient client;
|
||||
private 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();
|
||||
}
|
||||
|
||||
TrustManager[] trustAllCerts = new TrustManager[] { new TrustAllCertsManager() };
|
||||
//Setup the ssl instance using tls
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(null, trustAllCerts, new SecureRandom());
|
||||
|
||||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, TLS, null, new AllHostValidVerifyer());
|
||||
|
||||
builder = builder.setSSLSocketFactory(sslsf);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the http GET response code
|
||||
* @param endpoint endpoint to get the response from
|
||||
* @return responseCode
|
||||
* @throws Exception general exception
|
||||
*/
|
||||
public Integer getGetResponseCode(String endpoint) throws Exception {
|
||||
String url = this.baseUrl + endpoint;
|
||||
|
||||
HttpResponse response = this.client.execute(new HttpGet(url));
|
||||
|
||||
HttpEntity entity = response.getEntity();
|
||||
|
||||
Integer responseCode = response.getStatusLine().getStatusCode();
|
||||
|
||||
EntityUtils.consume(entity);
|
||||
|
||||
return responseCode;
|
||||
};
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
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) throws CertificateException { }
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { }
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() { return null; }
|
||||
|
||||
public static TrustManager[] trustAllCerts() {
|
||||
return new TrustManager[] { new TrustAllCertsManager() };
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.locusworks.common.net.hostverifiers;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
public class AllHostValidVerifyer implements HostnameVerifier {
|
||||
|
||||
@Override
|
||||
public boolean verify(String arg0, SSLSession arg1) { return true; }
|
||||
|
||||
}
|
30
src/main/java/net/locusworks/common/net/ssl/SSLManager.java
Normal file
30
src/main/java/net/locusworks/common/net/ssl/SSLManager.java
Normal file
@ -0,0 +1,30 @@
|
||||
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 org.apache.http.client.HttpClient;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
|
||||
import net.locusworks.common.net.certmanagers.TrustAllCertsManager;
|
||||
import net.locusworks.common.net.hostverifiers.AllHostValidVerifyer;
|
||||
|
||||
public class SSLManager {
|
||||
|
||||
public static final String[] TLS = new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"};
|
||||
|
||||
public static HttpClient getTrustAllTLSClient() throws NoSuchAlgorithmException, KeyManagementException {
|
||||
SSLContext context = SSLContext.getInstance("TLS");
|
||||
context.init(null, new TrustManager[] { new TrustAllCertsManager() }, new SecureRandom());
|
||||
|
||||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(context, TLS, null, new AllHostValidVerifyer());
|
||||
|
||||
return HttpClientBuilder.create().setSSLSocketFactory(sslsf).build();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
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);
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
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 ObjectMapper mapper;
|
||||
static {
|
||||
mapper = new ObjectMapper();
|
||||
mapper.setSerializationInclusion(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 (Exception e) {
|
||||
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 {
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package net.locusworks.common.objectmapper;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Holds the results from the object mapper list conversion
|
||||
* @author Isaac Parenteau
|
||||
* @version 1.0.0
|
||||
* @date 02/15/2018
|
||||
* @param <T> class type of the object mapper
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package net.locusworks.common.objectmapper;
|
||||
|
||||
/**
|
||||
* Holds the results from the object mapper list conversion
|
||||
* @author Isaac Parenteau
|
||||
* @version 1.0.0
|
||||
* @date 02/15/2018
|
||||
* @param <T> class type of the object being converted from json to object
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.locusworks.common.properties;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class ImmutableProperties extends Properties {
|
||||
|
||||
private static final long serialVersionUID = 65942088008978137L;
|
||||
|
||||
public ImmutableProperties() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ImmutableProperties(Properties props) {
|
||||
super();
|
||||
if (props == null || props.isEmpty()) return;
|
||||
|
||||
props.entrySet().forEach(item -> this.put(item.getKey(), item.getValue()));
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
25
src/main/java/net/locusworks/common/utils/Checks.java
Normal file
25
src/main/java/net/locusworks/common/utils/Checks.java
Normal file
@ -0,0 +1,25 @@
|
||||
package net.locusworks.common.utils;
|
||||
|
||||
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) {
|
||||
if (item == null) throw new IllegalAccessError("Provided item is null");
|
||||
}
|
||||
|
||||
}
|
19
src/main/java/net/locusworks/common/utils/Constants.java
Normal file
19
src/main/java/net/locusworks/common/utils/Constants.java
Normal file
@ -0,0 +1,19 @@
|
||||
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";
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
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 ex) {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
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 ctxt) throws IOException, JsonProcessingException {
|
||||
String value = p.getText();
|
||||
|
||||
Date date = null;
|
||||
//First try to see if the value can be parsed into a long
|
||||
try {
|
||||
date = new Date(Long.parseLong(value));
|
||||
return date;
|
||||
} catch (Exception ex) { }
|
||||
|
||||
//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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package net.locusworks.common.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
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
|
||||
* @date 02/15/2018
|
||||
* @version 1.0
|
||||
* @see com.fasterxml.jackson.databind.annotation.JsonSerialize
|
||||
* @see com.fasterxml.jackson.databind.ser.std.StdSerializer
|
||||
*/
|
||||
public class DateTimeStampSerializer extends StdSerializer<Date> {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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());
|
||||
}
|
||||
}
|
202
src/main/java/net/locusworks/common/utils/FileReader.java
Normal file
202
src/main/java/net/locusworks/common/utils/FileReader.java
Normal file
@ -0,0 +1,202 @@
|
||||
package net.locusworks.common.utils;
|
||||
|
||||
import static net.locusworks.common.Charsets.UTF_8;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
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> {
|
||||
|
||||
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
|
||||
*/
|
||||
public FileReader(File 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) {
|
||||
//check to see if the file exists
|
||||
File f = new File(fileName);
|
||||
if (f.exists()) {
|
||||
init(f); //If it does. load through the file initializer
|
||||
return;
|
||||
}
|
||||
|
||||
//Check to see if the file is in the resources directory
|
||||
InputStream is = this.getClass().getResourceAsStream(fileName);
|
||||
if (is == null) {
|
||||
is = this.getClass().getClassLoader().getResourceAsStream(fileName);
|
||||
}
|
||||
//If it cant be found, throw a runtime exception
|
||||
if (is == null) {
|
||||
throw new IllegalArgumentException("Unable to find resource with name of" + fileName);
|
||||
}
|
||||
|
||||
//Call the buffered reader initializer once the file is found
|
||||
init(new BufferedReader(new InputStreamReader(is, UTF_8)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializer helper to load file
|
||||
* @param file File to load
|
||||
*/
|
||||
private void init(File file) {
|
||||
if (file == null) throw new IllegalArgumentException("File cannot be null");
|
||||
if (!file.exists()) throw new IllegalArgumentException("File " + file + " does not exist");
|
||||
if (!file.isFile()) throw new IllegalArgumentException("File " + file + " is not a file");
|
||||
try {
|
||||
init(new BufferedReader(new InputStreamReader(new FileInputStream(file), UTF_8)));
|
||||
} 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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
179
src/main/java/net/locusworks/common/utils/HashUtils.java
Normal file
179
src/main/java/net/locusworks/common/utils/HashUtils.java
Normal file
@ -0,0 +1,179 @@
|
||||
package net.locusworks.common.utils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
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 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, File data) {
|
||||
return hash(hashType, data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, File data, boolean toLower) {
|
||||
InputStream stream;
|
||||
try {
|
||||
stream = new FileInputStream(data);
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalArgumentException(ex.getMessage());
|
||||
}
|
||||
return hash(stream, hashType, toLower);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
79
src/main/java/net/locusworks/common/utils/RandomString.java
Normal file
79
src/main/java/net/locusworks/common/utils/RandomString.java
Normal file
@ -0,0 +1,79 @@
|
||||
package net.locusworks.common.utils;
|
||||
|
||||
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 int length;
|
||||
|
||||
private static RandomString instance;
|
||||
|
||||
private RandomString(Integer length) {
|
||||
this(length, new SecureRandom());
|
||||
}
|
||||
|
||||
private RandomString(Integer length, Random random) {
|
||||
this(length, random, ALPHA_NUMERIC);
|
||||
}
|
||||
|
||||
private RandomString(Integer length, Random random, String symbols) {
|
||||
if (length < 1) throw new IllegalArgumentException("Length has to be greater than 1");
|
||||
if (symbols.length() < 2) throw new IllegalArgumentException("Symbols need to be greater than 2");
|
||||
this.random = Objects.requireNonNull(random);
|
||||
this.symbols = symbols.toCharArray();
|
||||
}
|
||||
|
||||
private synchronized final void setRandom(Random random) {
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
private synchronized final void setLength(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public String nextString() {
|
||||
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 static String getString(Integer length) {
|
||||
if (instance == null) {
|
||||
instance = new RandomString(length);
|
||||
}
|
||||
instance.setLength(length);
|
||||
return instance.nextString();
|
||||
}
|
||||
|
||||
public static String getString(Integer length, Random random) {
|
||||
if (instance == null) {
|
||||
instance = new RandomString(length);
|
||||
}
|
||||
instance.setLength(length);
|
||||
instance.setRandom(random);
|
||||
return instance.nextString();
|
||||
}
|
||||
|
||||
public static byte[] getBytes(Integer length) {
|
||||
return getString(length).getBytes(UTF_8);
|
||||
}
|
||||
|
||||
public static byte[] getBytes(Integer length, Random random) {
|
||||
return getString(length, random).getBytes(UTF_8);
|
||||
}
|
||||
}
|
130
src/main/java/net/locusworks/common/utils/Splitter.java
Normal file
130
src/main/java/net/locusworks/common/utils/Splitter.java
Normal file
@ -0,0 +1,130 @@
|
||||
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;
|
||||
|
||||
public class Splitter {
|
||||
|
||||
private String splitSeq;
|
||||
private boolean omitEmptyStrings = false;
|
||||
private int partition;
|
||||
private int limit;
|
||||
|
||||
private static Splitter splitter;
|
||||
|
||||
private Splitter(String seq) {
|
||||
this.splitSeq = seq;
|
||||
}
|
||||
|
||||
private Splitter(int partition) {
|
||||
this.partition = partition;
|
||||
}
|
||||
|
||||
public Splitter omitEmptyStrings() {
|
||||
this.omitEmptyStrings = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Splitter withLimit(int limit) {
|
||||
this.limit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MapSplitter withKeyValueSeparator(String separator) {
|
||||
checkArguments(!Utils.isEmptyString(separator), "Key value separator cannot be empty or null");
|
||||
return new MapSplitter(this, separator);
|
||||
}
|
||||
|
||||
public String[] splitToArray(String sentence) {
|
||||
List<String> list = split(sentence);
|
||||
return list.toArray(new String[list.size()]);
|
||||
}
|
||||
|
||||
public List<String> split(String sentence) {
|
||||
checkArguments(!Utils.isEmptyString(sentence), "provided value is null or empty");
|
||||
List<String> list = new ArrayList<>();
|
||||
|
||||
if (!Utils.isEmptyString(splitSeq))
|
||||
populateForTrimmer(sentence, list);
|
||||
else
|
||||
populateForFixedWidth(sentence, list);
|
||||
|
||||
return limit > 0 ? list.subList(0, limit) : list;
|
||||
}
|
||||
|
||||
private void populateForFixedWidth(String sentence, List<String> list) {
|
||||
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) {
|
||||
for (String s : sentence.split(splitSeq)) {
|
||||
if (s == null || (omitEmptyStrings && s.trim().isEmpty())) continue;
|
||||
list.add(s.trim());
|
||||
}
|
||||
}
|
||||
|
||||
public static Splitter fixedLengthSplit(int partition) {
|
||||
checkArguments(partition > 0, "Partition has to be greater than 0");
|
||||
splitter = new Splitter(partition);
|
||||
return splitter;
|
||||
}
|
||||
|
||||
public static Splitter on(String split) {
|
||||
checkNotNull(split, "Split value provided was null");
|
||||
splitter = new Splitter(split);
|
||||
return splitter;
|
||||
}
|
||||
|
||||
public static Splitter onNewLine() {
|
||||
return on("\\r?\\n");
|
||||
}
|
||||
|
||||
public static Splitter onSpace() {
|
||||
return on(" ");
|
||||
}
|
||||
|
||||
public static class MapSplitter {
|
||||
|
||||
private Splitter splitter;
|
||||
private 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;
|
||||
}
|
||||
}
|
||||
}
|
66
src/main/java/net/locusworks/common/utils/StreamUtils.java
Normal file
66
src/main/java/net/locusworks/common/utils/StreamUtils.java
Normal file
@ -0,0 +1,66 @@
|
||||
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 a 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);
|
||||
}
|
||||
}
|
41
src/main/java/net/locusworks/common/utils/Success.java
Normal file
41
src/main/java/net/locusworks/common/utils/Success.java
Normal file
@ -0,0 +1,41 @@
|
||||
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 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);
|
||||
}
|
||||
}
|
1125
src/main/java/net/locusworks/common/utils/Utils.java
Normal file
1125
src/main/java/net/locusworks/common/utils/Utils.java
Normal file
File diff suppressed because it is too large
Load Diff
24
src/main/resources/log4j.xml
Normal file
24
src/main/resources/log4j.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<?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>
|
41
src/test/java/net/locusworks/test/AESEncryptionTest.java
Normal file
41
src/test/java/net/locusworks/test/AESEncryptionTest.java
Normal file
@ -0,0 +1,41 @@
|
||||
package net.locusworks.test;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.locusworks.common.crypto.AES;
|
||||
import net.locusworks.common.utils.Utils;
|
||||
|
||||
public class AESEncryptionTest {
|
||||
|
||||
@Test
|
||||
public void testEncryption() {
|
||||
try {
|
||||
String encrypted = AES.createInstance().encrypt("hello world");
|
||||
Assert.assertTrue(String.format("Encrypted String is not blank? :%s", encrypted), !Utils.isEmptyString(encrypted));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace(System.err);
|
||||
Assert.fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecryption() {
|
||||
String testString ="hello world";
|
||||
try {
|
||||
AES aes = AES.createInstance();
|
||||
String encrypted = aes.encrypt(testString);
|
||||
Assert.assertTrue(String.format("Encrypted String is not blank? :%s", encrypted), !Utils.isEmptyString(encrypted));
|
||||
|
||||
String decrypted = aes.decrypt(encrypted);
|
||||
Assert.assertTrue(String.format("Decrypted String is not blank? :%s", decrypted), !Utils.isEmptyString(encrypted));
|
||||
|
||||
Assert.assertTrue("Test String and Original String the same? :%s", testString.equals(decrypted));
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace(System.err);
|
||||
Assert.fail();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
src/test/java/net/locusworks/test/AllTests.java
Normal file
11
src/test/java/net/locusworks/test/AllTests.java
Normal file
@ -0,0 +1,11 @@
|
||||
package net.locusworks.test;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
import org.junit.runners.Suite.SuiteClasses;
|
||||
|
||||
@RunWith(Suite.class)
|
||||
@SuiteClasses({ AESEncryptionTest.class, FileReaderTest.class, HashSaltTest.class, RandomStringTest.class })
|
||||
public class AllTests {
|
||||
|
||||
}
|
92
src/test/java/net/locusworks/test/FileReaderTest.java
Normal file
92
src/test/java/net/locusworks/test/FileReaderTest.java
Normal file
@ -0,0 +1,92 @@
|
||||
package net.locusworks.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.locusworks.common.interfaces.AutoCloseableIterator;
|
||||
import net.locusworks.common.utils.FileReader;
|
||||
import net.locusworks.common.utils.FileReader.LineInfo;
|
||||
import net.locusworks.common.utils.RandomString;
|
||||
|
||||
public class FileReaderTest {
|
||||
|
||||
private static final String TEST_FILE = "test_file.txt";
|
||||
private static Map<Integer, Integer> numLines = new LinkedHashMap<>();
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpBeforeClass() throws Exception {
|
||||
File testFile = new File(TEST_FILE);
|
||||
FileOutputStream fos = new FileOutputStream(testFile);
|
||||
|
||||
Integer count = ThreadLocalRandom.current().nextInt(100);
|
||||
|
||||
for (int i = 1; i <= count; i++) {
|
||||
String randomString = RandomString.getString(ThreadLocalRandom.current().nextInt(5, 100)) + "\n";
|
||||
numLines.put(i, randomString.length());
|
||||
fos.write(randomString.getBytes());
|
||||
}
|
||||
|
||||
fos.close();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownAfterClass() throws Exception {
|
||||
File file = new File(TEST_FILE);
|
||||
file.delete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForLoop() {
|
||||
Integer lineCount = 0;
|
||||
for(LineInfo s : new FileReader(new File(TEST_FILE))) {
|
||||
lineCount++;
|
||||
Integer lineNumber = s.getLineNumber();
|
||||
Integer lineLength = s.getLine().length();
|
||||
Integer mapLineLength = numLines.get(lineNumber);
|
||||
assertTrue(lineLength == (mapLineLength-1));
|
||||
}
|
||||
assertTrue(lineCount == numLines.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIterator() {
|
||||
Integer lineCount = 0;
|
||||
|
||||
try(AutoCloseableIterator<LineInfo> iter = new FileReader(new File(TEST_FILE))) {
|
||||
while(iter.hasNext()) {
|
||||
lineCount++;
|
||||
LineInfo s = iter.next();
|
||||
Integer lineNumber = s.getLineNumber();
|
||||
Integer lineLength = s.getLine().length();
|
||||
Integer mapLineLength = numLines.get(lineNumber);
|
||||
assertTrue(lineLength == (mapLineLength-1));
|
||||
}
|
||||
}
|
||||
assertTrue(lineCount == numLines.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForIterator() {
|
||||
Integer lineCount = 0;
|
||||
for(Iterator<LineInfo> iter = new FileReader(new File(TEST_FILE)); iter.hasNext();) {
|
||||
lineCount++;
|
||||
LineInfo s = iter.next();
|
||||
Integer lineNumber = s.getLineNumber();
|
||||
Integer lineLength = s.getLine().length();
|
||||
Integer mapLineLength = numLines.get(lineNumber);
|
||||
assertTrue(lineLength == (mapLineLength-1));
|
||||
}
|
||||
assertTrue(lineCount == numLines.size());
|
||||
}
|
||||
|
||||
}
|
34
src/test/java/net/locusworks/test/HashSaltTest.java
Normal file
34
src/test/java/net/locusworks/test/HashSaltTest.java
Normal file
@ -0,0 +1,34 @@
|
||||
package net.locusworks.test;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.locusworks.common.crypto.HashSalt;
|
||||
import net.locusworks.common.utils.Utils;
|
||||
|
||||
public class HashSaltTest {
|
||||
|
||||
private static String samplePassword="Hello World";
|
||||
|
||||
@Test
|
||||
public void testEncryption() {
|
||||
try {
|
||||
String hashSalt = HashSalt.createHash(samplePassword);
|
||||
Assert.assertTrue(String.format("Encrypted String is not blank? :%s", hashSalt), !Utils.isEmptyString(hashSalt));
|
||||
} catch(Exception ex) {
|
||||
Assert.fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecryption() {
|
||||
try {
|
||||
String hashSalt = HashSalt.createHash(samplePassword);
|
||||
boolean decrypted = HashSalt.validatePassword(samplePassword, hashSalt);
|
||||
Assert.assertTrue("Test String and Original String the same? :%s", decrypted);
|
||||
} catch(Exception ex) {
|
||||
Assert.fail();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
38
src/test/java/net/locusworks/test/HashUtilsTest.java
Normal file
38
src/test/java/net/locusworks/test/HashUtilsTest.java
Normal file
@ -0,0 +1,38 @@
|
||||
package net.locusworks.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.locusworks.common.utils.HashUtils;
|
||||
|
||||
public class HashUtilsTest {
|
||||
|
||||
private static final String TEST_STRING = "Hello World";
|
||||
|
||||
@Test
|
||||
public void testMD5() throws Exception {
|
||||
String digestUtilsMD5 = DigestUtils.md5Hex(TEST_STRING.getBytes());
|
||||
String hashUtilsMD5 = HashUtils.hash("MD5", TEST_STRING);
|
||||
|
||||
assertTrue(digestUtilsMD5.equals(hashUtilsMD5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSHA1() throws Exception {
|
||||
String digestUtilsMD5 = DigestUtils.sha1Hex(TEST_STRING.getBytes());
|
||||
String hashUtilsMD5 = HashUtils.hash("SHA-1", TEST_STRING);
|
||||
|
||||
assertTrue(digestUtilsMD5.equals(hashUtilsMD5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSHA512() throws Exception {
|
||||
String digestUtilsMD5 = DigestUtils.sha512Hex(TEST_STRING.getBytes());
|
||||
String hashUtilsMD5 = HashUtils.hash("SHA-512", TEST_STRING);
|
||||
|
||||
assertTrue(digestUtilsMD5.equals(hashUtilsMD5));
|
||||
}
|
||||
|
||||
}
|
45
src/test/java/net/locusworks/test/ImmutablesTest.java
Normal file
45
src/test/java/net/locusworks/test/ImmutablesTest.java
Normal file
@ -0,0 +1,45 @@
|
||||
package net.locusworks.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import net.locusworks.common.immutables.Pair;
|
||||
import net.locusworks.common.immutables.Triplet;
|
||||
import net.locusworks.common.immutables.Unit;
|
||||
|
||||
|
||||
public class ImmutablesTest {
|
||||
|
||||
@Test
|
||||
public void testUnit() {
|
||||
Unit<String> unit = new Unit<>("Hello World");
|
||||
assertTrue(unit.getValue1().equals("Hello World"));
|
||||
Unit<Integer> unit2 = new Unit<>(2);
|
||||
assertTrue(unit2.getValue1().equals(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPair() {
|
||||
Pair<String, String> pair1 = new Pair<>("Hello", "World");
|
||||
assertTrue(pair1.getValue1().equals("Hello"));
|
||||
assertTrue(pair1.getValue2().equals("World"));
|
||||
|
||||
Pair<String, Integer> pair2 = new Pair<>("Foo", 25);
|
||||
assertTrue(pair2.getValue1().equals("Foo"));
|
||||
assertTrue(pair2.getValue2().equals(25));
|
||||
|
||||
Pair<Integer, Integer> pair3 = new Pair<>(1, 23);
|
||||
assertTrue(pair3.getValue1().equals(1));
|
||||
assertTrue(pair3.getValue2().equals(23));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTriplet() {
|
||||
Triplet<String, Integer, String> triplet1 = new Triplet<>("Hello", 24, "World");
|
||||
assertTrue(triplet1.getValue1().equals("Hello"));
|
||||
assertTrue(triplet1.getValue2().equals(24));
|
||||
assertTrue(triplet1.getValue3().equals("World"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package net.locusworks.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.locusworks.common.immutables.Triplet;
|
||||
import net.locusworks.common.objectmapper.ObjectMapperHelper;
|
||||
import net.locusworks.common.utils.Utils;
|
||||
|
||||
import static net.locusworks.common.utils.Constants.JUNIT_TEST_CHECK;
|
||||
import static net.locusworks.common.utils.Constants.LOG4J_CONFIG_PROPERTY;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@BeforeClass
|
||||
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");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
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();
|
||||
assertTrue(tmp != null);
|
||||
assertTrue(tmp.equals(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.size() > 0);
|
||||
}
|
||||
|
||||
}
|
122
src/test/java/net/locusworks/test/PropertiesManagerTest.java
Normal file
122
src/test/java/net/locusworks/test/PropertiesManagerTest.java
Normal file
@ -0,0 +1,122 @@
|
||||
package net.locusworks.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.locusworks.common.configuration.PropertiesManager;
|
||||
|
||||
/**
|
||||
* 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 static enum Configuration {
|
||||
DB_HOST("dbHost"),
|
||||
DB_PORT("dbPort"),
|
||||
USER_EXPIRATION_DAYS("userExpirationDays"),
|
||||
LOG_LEVEL("logLevel");
|
||||
|
||||
private 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;
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
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);
|
||||
assertTrue(props != null);
|
||||
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();
|
||||
assertTrue(tmp.keySet().size() == 0);
|
||||
PropertiesManager.addConfiguration(tmp, props);
|
||||
assertTrue(tmp.keySet().size() == ENTRY_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();
|
||||
assertTrue(props.keySet().size() == ENTRY_SIZE);
|
||||
assertTrue(tmp.keySet().size() == 0);
|
||||
PropertiesManager.removeConfiguration(props, tmp);
|
||||
assertTrue(props.keySet().size() == 0);
|
||||
assertTrue(tmp.keySet().size() == 0);
|
||||
} catch (IOException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveConfiguration() {
|
||||
try {
|
||||
Properties props = PropertiesManager.loadConfiguration(this.getClass(), PROPERTIES_FILE);
|
||||
File tmpFile = new File(TMP_PROPS);
|
||||
PropertiesManager.saveConfiguration(props, tmpFile, "test propertis");
|
||||
Properties tmp = PropertiesManager.loadConfiguration(tmpFile);
|
||||
assertTrue(tmp.keySet().size() == ENTRY_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());
|
||||
}
|
||||
}
|
||||
}
|
26
src/test/java/net/locusworks/test/RandomStringTest.java
Normal file
26
src/test/java/net/locusworks/test/RandomStringTest.java
Normal file
@ -0,0 +1,26 @@
|
||||
package net.locusworks.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import net.locusworks.common.utils.RandomString;
|
||||
|
||||
public class RandomStringTest {
|
||||
|
||||
@Test
|
||||
public void testStaticBytes() {
|
||||
for (Integer length = 3; length < 50; length++) {
|
||||
assertTrue(RandomString.getBytes(length).length == length);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStaticString() {
|
||||
for (Integer length = 3; length < 50; length++) {
|
||||
String random = RandomString.getString(length);
|
||||
assertTrue(random.length() == length);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
39
src/test/java/net/locusworks/test/UtilsTest.java
Normal file
39
src/test/java/net/locusworks/test/UtilsTest.java
Normal file
@ -0,0 +1,39 @@
|
||||
package net.locusworks.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import net.locusworks.common.utils.Utils;
|
||||
|
||||
/**
|
||||
* 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 testEmptyString() {
|
||||
assertTrue(Utils.isEmptyString(null));
|
||||
assertTrue(Utils.isEmptyString(""));
|
||||
assertTrue(Utils.isEmptyString(" "));
|
||||
assertFalse(Utils.isEmptyString("foo"));
|
||||
assertFalse(Utils.isEmptyString(" bar "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToInteger() {
|
||||
assertTrue(Utils.toInteger("Hello word", 2) == 2);
|
||||
assertTrue(Utils.toInteger("23", 5023) == 23);
|
||||
}
|
||||
|
||||
}
|
13
src/test/resources/log4j2-test.xml
Normal file
13
src/test/resources/log4j2-test.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?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>
|
4
src/test/resources/test.properties
Normal file
4
src/test/resources/test.properties
Normal file
@ -0,0 +1,4 @@
|
||||
userExpirationDays=3650
|
||||
dbHost=localhost
|
||||
dbPort=3306
|
||||
logLevel=INFO
|
6
temp.properties
Normal file
6
temp.properties
Normal file
@ -0,0 +1,6 @@
|
||||
#test propertis
|
||||
#Fri Feb 16 09:42:40 EST 2018
|
||||
logLevel=INFO
|
||||
dbPort=3306
|
||||
userExpirationDays=3650
|
||||
dbHost=localhost
|
Reference in New Issue
Block a user