first commit
This commit is contained in:
18
configuration/nb-configuration.xml
Normal file
18
configuration/nb-configuration.xml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project-shared-configuration>
|
||||||
|
<!--
|
||||||
|
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||||
|
The configuration is intended to be shared among all the users of project and
|
||||||
|
therefore it is assumed to be part of version control checkout.
|
||||||
|
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||||
|
-->
|
||||||
|
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||||
|
<!--
|
||||||
|
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||||
|
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||||
|
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||||
|
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||||
|
-->
|
||||||
|
<netbeans.checkstyle.format>true</netbeans.checkstyle.format>
|
||||||
|
</properties>
|
||||||
|
</project-shared-configuration>
|
||||||
44
configuration/pom.xml
Normal file
44
configuration/pom.xml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<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>de.muehlencord.shared</groupId>
|
||||||
|
<artifactId>shared-configuration</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>shared</artifactId>
|
||||||
|
<groupId>de.muehlencord</groupId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<name>shared-configuration</name>
|
||||||
|
<url>http://maven.apache.org</url>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>2.3.2</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
<showDeprecation>true</showDeprecation>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.10</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.configuration.converter.BooleanStringConverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Boolean parameter
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class BooleanParameter extends Parameter<Boolean> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new mandatory parameter object using default string converter
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
*/
|
||||||
|
public BooleanParameter(String name) {
|
||||||
|
super(name, new BooleanStringConverter(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new mandatory parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
*/
|
||||||
|
public BooleanParameter(String name, StringConverter<Boolean> converter) {
|
||||||
|
super(name, converter, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new parameter object using default string converter
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param mandatory detremines if this is a mandatory parameter or not
|
||||||
|
*/
|
||||||
|
public BooleanParameter(String name, boolean mandatory) {
|
||||||
|
super(name, new BooleanStringConverter(), mandatory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
* @param mandatory detremines if this is a mandatory parameter or not
|
||||||
|
*/
|
||||||
|
public BooleanParameter(String name, StringConverter<Boolean> converter, boolean mandatory) {
|
||||||
|
super(name, converter, mandatory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public interface Configuration<T, V extends T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a new parameter to the configuration
|
||||||
|
*
|
||||||
|
* @param p the parameter to add
|
||||||
|
* @throws ConfigurationException if the parameter cannot be added
|
||||||
|
*/
|
||||||
|
public void addParameter(Parameter<T> p) throws ConfigurationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the value of the given parameter
|
||||||
|
*
|
||||||
|
* @param p parameter to set
|
||||||
|
* @param value value to set
|
||||||
|
* @throws ConfigurationException if the parameter is not defined
|
||||||
|
*/
|
||||||
|
public void setParameterValue(Parameter<T> p, V value) throws ConfigurationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the value of parameter with given name
|
||||||
|
*
|
||||||
|
* @param parameterName parameter to set
|
||||||
|
* @param value value to set
|
||||||
|
* @throws ConfigurationException if the parameter is not defined
|
||||||
|
*/
|
||||||
|
public void setParameterValue(String parameterName, V value) throws ConfigurationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the value of the given parameter
|
||||||
|
*
|
||||||
|
* @param p parameter to set
|
||||||
|
* @param value value to set
|
||||||
|
* @throws ConfigurationException if the parameter is not defined
|
||||||
|
*/
|
||||||
|
public void setParameterValueByString(Parameter<T> p, String value) throws ConfigurationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the value of the given parameter
|
||||||
|
*
|
||||||
|
* @param parameterName the name of the parameter to set the value for
|
||||||
|
* @param stringValue the value of the parameter as string
|
||||||
|
* @throws ConfigurationException if the parameter cannot be found or set
|
||||||
|
*/
|
||||||
|
public void setParameterValueByString(String parameterName, String stringValue) throws ConfigurationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the value of the given parameter
|
||||||
|
*
|
||||||
|
* @param p the parameter to return the value for
|
||||||
|
* @return the value of the given parameter; null if not set
|
||||||
|
*
|
||||||
|
* @throws ConfigurationException if the parameter is not defined or if the value is not set
|
||||||
|
*/
|
||||||
|
public V getParameterValue(Parameter<T> p) throws ConfigurationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the value of the given parameter
|
||||||
|
*
|
||||||
|
* @param parameterName the name of the parameter to return the value for
|
||||||
|
* @return the value of the given parameter; null if not set
|
||||||
|
*
|
||||||
|
* @throws ConfigurationException if the parameter is not defined or if the value is not set
|
||||||
|
*/
|
||||||
|
public V getParameterValue(String parameterName) throws ConfigurationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validates the configuration
|
||||||
|
*
|
||||||
|
* @throws ConfigurationException if the configuration is invalid
|
||||||
|
*/
|
||||||
|
public void validateConfiguration() throws ConfigurationException;
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class ConfigurationException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of
|
||||||
|
* <code>ParameterException</code> without detail message.
|
||||||
|
*/
|
||||||
|
public ConfigurationException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>ParameterException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public ConfigurationException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>ParameterException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
* @param th the root cause
|
||||||
|
*/
|
||||||
|
public ConfigurationException(String msg, Throwable th) {
|
||||||
|
super(msg, th);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class ConverterException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of
|
||||||
|
* <code>ConverterException</code> without detail message.
|
||||||
|
*/
|
||||||
|
public ConverterException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>ConverterException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public ConverterException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>ConverterException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
* @param th the causing exception
|
||||||
|
*/
|
||||||
|
public ConverterException(String msg, Throwable th) {
|
||||||
|
super(msg, th);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.configuration.converter.DateStringConverter;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Date parameter
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class DateParameter extends Parameter<Date> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new mandatory parameter object using default string converter
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
*/
|
||||||
|
public DateParameter(String name) {
|
||||||
|
super(name, new DateStringConverter(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new mandatory parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
*/
|
||||||
|
public DateParameter(String name, StringConverter<Date> converter) {
|
||||||
|
super(name, converter, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new parameter object using default string converter
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param mandatory detremines if this is a mandatory parameter or not
|
||||||
|
*/
|
||||||
|
public DateParameter(String name, boolean mandatory) {
|
||||||
|
super(name, new DateStringConverter(), mandatory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
* @param mandatory detremines if this is a mandatory parameter or not
|
||||||
|
*/
|
||||||
|
public DateParameter(String name, StringConverter<Date> converter, boolean mandatory) {
|
||||||
|
super(name, converter, mandatory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,224 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param <T> the type of the parameter
|
||||||
|
* @param <V> the value of the parameter - must be the same class as the type class of the parameter
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class DefaultConfiguration<T, V extends T> implements Configuration<T, V> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the parameter map
|
||||||
|
*/
|
||||||
|
private Map<Parameter<T>, V> parameterMap;
|
||||||
|
/** mapping from name to parameter */
|
||||||
|
private Map<String, Parameter<T>> parameterNameMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new instance of a configuration
|
||||||
|
*/
|
||||||
|
public DefaultConfiguration() {
|
||||||
|
parameterMap = new HashMap<Parameter<T>, V>();
|
||||||
|
parameterNameMap = new HashMap<String, Parameter<T>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the map of parameters and values
|
||||||
|
*
|
||||||
|
* @return the map of parameters and values
|
||||||
|
*/
|
||||||
|
protected Map<Parameter<T>, V> getParameterMap() {
|
||||||
|
return parameterMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a new parameter to the configuration
|
||||||
|
*
|
||||||
|
* @param p the parameter to add
|
||||||
|
* @throws ConfigurationException if the parameter cannot be added
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addParameter(Parameter p) throws ConfigurationException {
|
||||||
|
if (parameterMap.containsKey(p)) {
|
||||||
|
throw new ConfigurationException("Parameter named " + p.getName() + " already defined");
|
||||||
|
} else {
|
||||||
|
parameterMap.put(p, null);
|
||||||
|
parameterNameMap.put(p.getName(), p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validates the configuration
|
||||||
|
*
|
||||||
|
* @throws ConfigurationException if the configuration is invalid
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void validateConfiguration() throws ConfigurationException {
|
||||||
|
List<Parameter> missingMandatoryParameters = new LinkedList<Parameter>();
|
||||||
|
for (Parameter p : parameterMap.keySet()) {
|
||||||
|
if ((!validateParameter(p)) && (!missingMandatoryParameters.contains(p))) {
|
||||||
|
missingMandatoryParameters.add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!missingMandatoryParameters.isEmpty()) {
|
||||||
|
throw new ConfigurationException("Configuration invalid, mandatory parameters missing: " + missingMandatoryParameters.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the value of the given parameter
|
||||||
|
*
|
||||||
|
* @param p parameter to set
|
||||||
|
* @param value value to set
|
||||||
|
* @throws ConfigurationException if the parameter is not defined
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setParameterValue(Parameter<T> p, V value) throws ConfigurationException {
|
||||||
|
if (parameterMap.containsKey(p)) {
|
||||||
|
parameterMap.put(p, value);
|
||||||
|
} else {
|
||||||
|
throw new ConfigurationException("Parameter " + p.getName() + " not defined");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the value of parameter with given name
|
||||||
|
*
|
||||||
|
* @param parameterName parameter to set
|
||||||
|
* @param value value to set
|
||||||
|
* @throws ConfigurationException if the parameter is not defined
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setParameterValue(String parameterName, V value) throws ConfigurationException {
|
||||||
|
if (parameterNameMap.containsKey(parameterName)) {
|
||||||
|
Parameter<T> p = parameterNameMap.get(parameterName);
|
||||||
|
parameterMap.put(p, value);
|
||||||
|
} else {
|
||||||
|
throw new ConfigurationException("Parameter " + parameterName + " not defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the value of the given parameter
|
||||||
|
*
|
||||||
|
* @param p parameter to set
|
||||||
|
* @param stringValue value to set
|
||||||
|
* @throws ConfigurationException if the parameter is not defined
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setParameterValueByString(Parameter<T> p, String stringValue) throws ConfigurationException {
|
||||||
|
if (parameterMap.containsKey(p)) {
|
||||||
|
try {
|
||||||
|
V value = p.getStringConverter().fromString(stringValue);
|
||||||
|
parameterMap.put(p, value);
|
||||||
|
} catch (ConverterException ex) {
|
||||||
|
throw new ConfigurationException("Error while setting parameter value for parameter " + p.getName() + ". Reason:" + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ConfigurationException("Parameter " + p.getName() + " not defined");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the value of the given parameter
|
||||||
|
*
|
||||||
|
* @param parameterName name of parameter to set the value for
|
||||||
|
* @param stringValue value to set
|
||||||
|
* @throws ConfigurationException if the parameter is not defined
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setParameterValueByString(String parameterName, String stringValue) throws ConfigurationException {
|
||||||
|
if (parameterNameMap.containsKey(parameterName)) {
|
||||||
|
Parameter<T> p = parameterNameMap.get(parameterName);
|
||||||
|
|
||||||
|
if (parameterMap.containsKey(p)) {
|
||||||
|
try {
|
||||||
|
V value = p.getStringConverter().fromString(stringValue);
|
||||||
|
parameterMap.put(p, value);
|
||||||
|
} catch (ConverterException ex) {
|
||||||
|
throw new ConfigurationException("Error while setting parameter value for parameter " + p.getName() + ". Reason:" + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ConfigurationException("Parameter " + p.getName() + " not defined");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ConfigurationException("Parameter with name " + parameterName + " not found in configuration");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the value of the given parameter
|
||||||
|
*
|
||||||
|
* @param p the parameter to return the value for
|
||||||
|
* @return the value of the given parameter
|
||||||
|
*
|
||||||
|
* @throws ConfigurationException if the value cannot be determined
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public V getParameterValue(Parameter<T> p) throws ConfigurationException {
|
||||||
|
if (parameterMap.containsKey(p)) {
|
||||||
|
return parameterMap.get(p);
|
||||||
|
} else {
|
||||||
|
throw new ConfigurationException("Parameter " + p.getName() + " not defined");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the value of the given parameter
|
||||||
|
*
|
||||||
|
* @param parameterName the name of the parameter to return the value for
|
||||||
|
* @return the value of the given parameter; null if not set
|
||||||
|
*
|
||||||
|
* @throws ConfigurationException if the parameter is not defined or if the value is not set
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public V getParameterValue(String parameterName) throws ConfigurationException {
|
||||||
|
if (parameterNameMap.containsKey(parameterName)) {
|
||||||
|
Parameter<T> p = parameterNameMap.get(parameterName);
|
||||||
|
return getParameterValue(p);
|
||||||
|
} else {
|
||||||
|
throw new ConfigurationException("Parameter " + parameterName + " not defined");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validates a parameter. Returns true, if the parameter setup is valid; false otherwise
|
||||||
|
*
|
||||||
|
* @param p the parameter to validate
|
||||||
|
* @return true, if the parameter is valid (mandatory parameter set, depending parameters set); false otherwise
|
||||||
|
*
|
||||||
|
* @throws ConfigurationException if a check fails
|
||||||
|
*/
|
||||||
|
private boolean validateParameter(Parameter<T> p) throws ConfigurationException {
|
||||||
|
// check if parameter is mandatory and available
|
||||||
|
if ((p.isMandatory()) && (parameterMap.get(p) == null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if parameter has required parameters and if these are set
|
||||||
|
V parameterValue = getParameterValue(p);
|
||||||
|
if (parameterValue != null) {
|
||||||
|
for (Parameter rp : p.getRequiredParameter()) {
|
||||||
|
if (getParameterValue(rp) == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if parameter has uses value list -if yes ensure only valid value is selected
|
||||||
|
if (!p.isValid(parameterValue)) {
|
||||||
|
throw new ConfigurationException("Value for paramter " + p.getName() + " is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.configuration.converter.IntegerStringConverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Integer parameter
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class IntegerParameter extends Parameter<Integer> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new mandatory parameter object using default string converter
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
*/
|
||||||
|
public IntegerParameter(String name) {
|
||||||
|
super(name, new IntegerStringConverter(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new mandatory parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
*/
|
||||||
|
public IntegerParameter(String name, StringConverter<Integer> converter) {
|
||||||
|
super(name, converter, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new parameter object using default string converter
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param mandatory detremines if this is a mandatory parameter or not
|
||||||
|
*/
|
||||||
|
public IntegerParameter(String name, boolean mandatory) {
|
||||||
|
super(name, new IntegerStringConverter(), mandatory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
* @param mandatory detremines if this is a mandatory parameter or not
|
||||||
|
*/
|
||||||
|
public IntegerParameter(String name, StringConverter<Integer> converter, boolean mandatory) {
|
||||||
|
super(name, converter, mandatory);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,168 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param <T> type of parameter
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public abstract class Parameter<T> {
|
||||||
|
|
||||||
|
/** the name of the parameter */
|
||||||
|
private String name;
|
||||||
|
/** the long description of this parameter */
|
||||||
|
private String description;
|
||||||
|
/** boolean flag if this is a mandatory parameter or not */
|
||||||
|
private boolean mandatory;
|
||||||
|
/** the type of the value object for this paramterer */
|
||||||
|
// private T type;
|
||||||
|
/** the string converter to convert the object to string and back again */
|
||||||
|
private StringConverter<T> stringConverter;
|
||||||
|
/** list of mandatory parameters, if this parameter is active */
|
||||||
|
private List<Parameter<?>> requiredParameters;
|
||||||
|
/** optional validator */
|
||||||
|
private Validator<T> validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new mandatory string parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
*/
|
||||||
|
public Parameter(String name, StringConverter<T> converter) {
|
||||||
|
this.name = name;
|
||||||
|
this.description = name;
|
||||||
|
this.mandatory = true;
|
||||||
|
this.stringConverter = converter;
|
||||||
|
this.requiredParameters = new LinkedList<Parameter<?>>();
|
||||||
|
this.validator = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
* @param mandatory detremines if this is a mandatory parameter or not
|
||||||
|
*/
|
||||||
|
public Parameter(String name, StringConverter<T> converter, boolean mandatory) {
|
||||||
|
this(name, converter);
|
||||||
|
this.mandatory = mandatory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
* @param description the long text description of this parameter
|
||||||
|
* @param mandatory detremines if this is a mandatory parameter or not
|
||||||
|
*/
|
||||||
|
public Parameter(String name, StringConverter<T> converter, String description, boolean mandatory) {
|
||||||
|
this(name, converter);
|
||||||
|
this.description = description;
|
||||||
|
this.mandatory = mandatory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the description
|
||||||
|
*/
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the mandatory
|
||||||
|
*/
|
||||||
|
public boolean isMandatory() {
|
||||||
|
return mandatory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the stringConverter
|
||||||
|
*/
|
||||||
|
public StringConverter<T> getStringConverter() {
|
||||||
|
return stringConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a parameter to the list of required parameters
|
||||||
|
*
|
||||||
|
* @param param the parameter to add
|
||||||
|
*/
|
||||||
|
public void addRequiredParameter(Parameter param) {
|
||||||
|
if (!requiredParameters.contains(param)) {
|
||||||
|
requiredParameters.add(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the list of parameters the given parameter requires
|
||||||
|
*
|
||||||
|
* @return the list of parameters the given parameter requires
|
||||||
|
*/
|
||||||
|
public List<Parameter<?>> getRequiredParameter() {
|
||||||
|
return requiredParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns true, if the given value is part of the possible value list or if the given value list is true
|
||||||
|
*
|
||||||
|
* @param value the value to validate
|
||||||
|
* @return true if no value list is defined or value is part of the value list; false otherwise
|
||||||
|
*/
|
||||||
|
public boolean isValid(T value) {
|
||||||
|
if (validator == null) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
validator.validate(value);
|
||||||
|
return true;
|
||||||
|
} catch (ValidationException ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (o instanceof Parameter) {
|
||||||
|
Parameter param = (Parameter) o;
|
||||||
|
return param.getName().equals(getName());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 7;
|
||||||
|
hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param validator the validator to set
|
||||||
|
*/
|
||||||
|
public void setValidator(Validator<T> validator) {
|
||||||
|
this.validator = validator;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public abstract class ParameterFactory {
|
||||||
|
|
||||||
|
private ParameterFactory() {
|
||||||
|
// hide public constructor to force factory
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parameter getParameterInstance(String name, boolean mandatory, Class clazz) throws ConfigurationException {
|
||||||
|
if (clazz.equals(String.class)) {
|
||||||
|
return new StringParameter(name, mandatory);
|
||||||
|
|
||||||
|
} else if (clazz.equals(Boolean.class)) {
|
||||||
|
return new BooleanParameter(name, mandatory);
|
||||||
|
|
||||||
|
} else if (clazz.equals(Date.class)) {
|
||||||
|
return new DateParameter(name, mandatory);
|
||||||
|
|
||||||
|
} else if (clazz.equals(Integer.class)) {
|
||||||
|
return new IntegerParameter(name, mandatory);
|
||||||
|
|
||||||
|
} else if (clazz.equals(URI.class)) {
|
||||||
|
return new URIParameter(name, mandatory);
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new ConfigurationException("Unsupported type " + clazz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parameter getParameterInstance(String name, boolean mandatory, Object value) throws ConfigurationException {
|
||||||
|
return getParameterInstance(name, mandatory, value.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parameter getParameterInstance(String name) throws ConfigurationException {
|
||||||
|
return getParameterInstance(name, true, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parameter getParameterInstance(String name, boolean mandatory) throws ConfigurationException {
|
||||||
|
return getParameterInstance(name, mandatory, String.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param <T> the class type of the parameter value to convert
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public interface StringConverter<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converter a parameter object to a string representation
|
||||||
|
* @param o the parameter value to convert
|
||||||
|
* @return the parameter value as string
|
||||||
|
* @throws ConverterException if the conversion fails
|
||||||
|
*/
|
||||||
|
public String toString (T o) throws ConverterException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converter a string to a the given type
|
||||||
|
* @param <V> the type of the converter
|
||||||
|
* @param s string representation of a parameter value to convert to an object
|
||||||
|
* @return the parameter value as object
|
||||||
|
* @throws ConverterException if the conversion fails
|
||||||
|
*/
|
||||||
|
public <V> V fromString (String s) throws ConverterException;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.configuration.converter.StringStringConverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A String parameter
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class StringParameter extends Parameter<String> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new mandatory parameter object using default string converter
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
*/
|
||||||
|
public StringParameter(String name) {
|
||||||
|
super(name, new StringStringConverter(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new mandatory parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
*/
|
||||||
|
public StringParameter(String name, StringConverter<String> converter) {
|
||||||
|
super(name, converter, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new parameter object using default string converter
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param mandatory detremines if this is a mandatory parameter or not
|
||||||
|
*/
|
||||||
|
public StringParameter(String name, boolean mandatory) {
|
||||||
|
super(name, new StringStringConverter(), mandatory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
* @param mandatory detremines if this is a mandatory parameter or not
|
||||||
|
*/
|
||||||
|
public StringParameter(String name, StringConverter<String> converter, boolean mandatory) {
|
||||||
|
super(name, converter, mandatory);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.configuration.converter.URIStringConverter;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A URI parameter
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class URIParameter extends Parameter<URI> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new mandatory parameter object using default string converter
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
*/
|
||||||
|
public URIParameter(String name) {
|
||||||
|
super(name, new URIStringConverter(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new mandatory parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
*/
|
||||||
|
public URIParameter(String name, StringConverter<URI> converter) {
|
||||||
|
super(name, converter, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new parameter object using default string converter
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param mandatory detremines if this is a mandatory parameter or not
|
||||||
|
*/
|
||||||
|
public URIParameter(String name, boolean mandatory) {
|
||||||
|
super(name, new URIStringConverter(), mandatory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new parameter object
|
||||||
|
*
|
||||||
|
* @param name the name of the parameter
|
||||||
|
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||||
|
* @param mandatory detremines if this is a mandatory parameter or not
|
||||||
|
*/
|
||||||
|
public URIParameter(String name, StringConverter<URI> converter, boolean mandatory) {
|
||||||
|
super(name, converter, mandatory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class ValidationException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of
|
||||||
|
* <code>ValidationException</code> without detail message.
|
||||||
|
*/
|
||||||
|
public ValidationException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>ValidationException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public ValidationException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>ValidationException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
* @param th the root cause
|
||||||
|
*/
|
||||||
|
public ValidationException(String msg, Throwable th) {
|
||||||
|
super(msg, th);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param <T> the type of the validator
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public interface Validator<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validates the parameter value
|
||||||
|
*
|
||||||
|
* @param value the value of the parameter to validate
|
||||||
|
* @throws ValidationException if the value is not valid according to the validator configuration
|
||||||
|
*/
|
||||||
|
public void validate(T value) throws ValidationException;
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package de.muehlencord.shared.configuration.converter;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.configuration.ConverterException;
|
||||||
|
import de.muehlencord.shared.configuration.StringConverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class BooleanStringConverter implements StringConverter<Boolean> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(Boolean o) throws ConverterException {
|
||||||
|
return o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean fromString(String s) throws ConverterException {
|
||||||
|
return Boolean.parseBoolean(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
package de.muehlencord.shared.configuration.converter;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.configuration.ConverterException;
|
||||||
|
import de.muehlencord.shared.configuration.StringConverter;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class DateStringConverter implements StringConverter<Date> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dateformat to convert from string to date and vice versa
|
||||||
|
*/
|
||||||
|
private static final String format = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converter a parameter object to a string representation
|
||||||
|
*
|
||||||
|
* @param d the parameter value to convert
|
||||||
|
* @return the parameter value as string
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString(Date d) {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US);
|
||||||
|
return sdf.format(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converter a string to date
|
||||||
|
*
|
||||||
|
* @param s string representation of a parameter value to convert to an object
|
||||||
|
* @return the parameter value as date
|
||||||
|
*
|
||||||
|
* @throws ConverterException if the conversion fails
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Date fromString(String s) throws ConverterException {
|
||||||
|
try {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US);
|
||||||
|
return sdf.parse(s);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new ConverterException("Error while converting " + s + "*to date. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package de.muehlencord.shared.configuration.converter;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.configuration.ConverterException;
|
||||||
|
import de.muehlencord.shared.configuration.StringConverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class IntegerStringConverter implements StringConverter<Integer> {
|
||||||
|
|
||||||
|
public String toString(Integer o) throws ConverterException {
|
||||||
|
return o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer fromString(String s) throws ConverterException {
|
||||||
|
return Integer.parseInt(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package de.muehlencord.shared.configuration.converter;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.configuration.ConverterException;
|
||||||
|
import de.muehlencord.shared.configuration.StringConverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class StringStringConverter implements StringConverter<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(String o) throws ConverterException {
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String fromString(String s) throws ConverterException {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package de.muehlencord.shared.configuration.converter;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.configuration.ConverterException;
|
||||||
|
import de.muehlencord.shared.configuration.StringConverter;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class URIStringConverter implements StringConverter<URI> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(URI o) throws ConverterException {
|
||||||
|
return o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URI fromString(String s) throws ConverterException {
|
||||||
|
return URI.create(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package de.muehlencord.shared.configuration.validator;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.configuration.ValidationException;
|
||||||
|
import de.muehlencord.shared.configuration.Validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class IntgerRangeValidator implements Validator<Integer> {
|
||||||
|
|
||||||
|
private Integer lowerBoundary;
|
||||||
|
private Integer upperBoundary;
|
||||||
|
|
||||||
|
public IntgerRangeValidator(Integer lb, Integer ub) {
|
||||||
|
this.lowerBoundary = lb;
|
||||||
|
this.upperBoundary = ub;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate(Integer value) throws ValidationException {
|
||||||
|
if ((value > upperBoundary) || (value < lowerBoundary)) {
|
||||||
|
throw new ValidationException("Value must be between " + lowerBoundary + " and " + upperBoundary + " but is " + value);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package de.muehlencord.shared.configuration.validator;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.configuration.ValidationException;
|
||||||
|
import de.muehlencord.shared.configuration.Validator;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class StringValueListValidator implements Validator<String> {
|
||||||
|
|
||||||
|
private List<String> valueList;
|
||||||
|
|
||||||
|
public StringValueListValidator() {
|
||||||
|
this.valueList = new LinkedList<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringValueListValidator(String... values) {
|
||||||
|
this();
|
||||||
|
valueList.addAll(Arrays.asList(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate(String value) throws ValidationException {
|
||||||
|
if (!valueList.contains(value)) {
|
||||||
|
throw new ValidationException("Value " + value + " not valid. One of " + valueList.toString() + " expected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
package de.muehlencord.shared.configuration;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit test for simple App.
|
||||||
|
*/
|
||||||
|
public class AppTest
|
||||||
|
extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the test case
|
||||||
|
*
|
||||||
|
* @param testName name of the test case
|
||||||
|
*/
|
||||||
|
public AppTest( String testName )
|
||||||
|
{
|
||||||
|
super( testName );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the suite of tests being tested
|
||||||
|
*/
|
||||||
|
public static Test suite()
|
||||||
|
{
|
||||||
|
return new TestSuite( AppTest.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rigourous Test :-)
|
||||||
|
*/
|
||||||
|
public void testApp()
|
||||||
|
{
|
||||||
|
assertTrue( true );
|
||||||
|
}
|
||||||
|
}
|
||||||
81
jeeutil/pom.xml
Normal file
81
jeeutil/pom.xml
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<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>
|
||||||
|
<parent>
|
||||||
|
<artifactId>shared</artifactId>
|
||||||
|
<groupId>de.muehlencord</groupId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>de.muehlencord.app</groupId>
|
||||||
|
<artifactId>shared-jeeutil</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>ejb</packaging>
|
||||||
|
|
||||||
|
<name>shared-jeeutil</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax</groupId>
|
||||||
|
<artifactId>javaee-api</artifactId>
|
||||||
|
<version>6.0</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>2.3.2</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
<compilerArguments>
|
||||||
|
<endorseddirs>${endorsed.dir}</endorseddirs>
|
||||||
|
</compilerArguments>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-ejb-plugin</artifactId>
|
||||||
|
<version>2.3</version>
|
||||||
|
<configuration>
|
||||||
|
<ejbVersion>3.1</ejbVersion>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>validate</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>copy</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<outputDirectory>${endorsed.dir}</outputDirectory>
|
||||||
|
<silent>true</silent>
|
||||||
|
<artifactItems>
|
||||||
|
<artifactItem>
|
||||||
|
<groupId>javax</groupId>
|
||||||
|
<artifactId>javaee-endorsed-api</artifactId>
|
||||||
|
<version>6.0</version>
|
||||||
|
<type>jar</type>
|
||||||
|
</artifactItem>
|
||||||
|
</artifactItems>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package de.muehlencord.app.sharedjeeutil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter to suppress ClickJacking by adding X-FRAME-OPTIONS to header.
|
||||||
|
* see https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet for details
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class ClickJackFIlter implements Filter {
|
||||||
|
|
||||||
|
/** mode to use */
|
||||||
|
private String mode = "DENY";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inits the filter. Checks if a parameter "mode" is available in parameter map tp use instead default "DENY"
|
||||||
|
*
|
||||||
|
* @param filterConfig
|
||||||
|
* @throws ServletException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
String configMode = filterConfig.getInitParameter("mode");
|
||||||
|
if (configMode != null) {
|
||||||
|
mode = configMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add X-FRAME-OPTIONS response header to tell IE8 (and any other browsers who decide to implement) not to display this content in a frame. For details,
|
||||||
|
* please refer to http://blogs.msdn.com/sdl/archive/2009/02/05/clickjacking-defense-in-ie8.aspx.
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @param chain
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ServletException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||||
|
HttpServletResponse res = (HttpServletResponse) response;
|
||||||
|
res.addHeader("X-FRAME-OPTIONS", mode);
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
// nothing todo here
|
||||||
|
}
|
||||||
|
}
|
||||||
2
jeeutil/src/main/resources/META-INF/MANIFEST.MF
Normal file
2
jeeutil/src/main/resources/META-INF/MANIFEST.MF
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Manifest-Version: 1.0
|
||||||
|
|
||||||
30
jmpass/pom.xml
Normal file
30
jmpass/pom.xml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<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>de.muehlencord.shared</groupId>
|
||||||
|
<artifactId>jmpass</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>jmpass</name>
|
||||||
|
<url>http://www.mühlencord.de/</url>
|
||||||
|
|
||||||
|
<issueManagement>
|
||||||
|
<system>Bugzilla</system>
|
||||||
|
<url>https://jomu.timelord.de/bugzilla/</url>
|
||||||
|
</issueManagement>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.10</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.jmpass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class Bcrypt {
|
||||||
|
|
||||||
|
// http://en.wikipedia.org/wiki/Bcrypt
|
||||||
|
|
||||||
|
public String bcrypt(long cost, byte[] salt, String input) {
|
||||||
|
String state = eksBlowfishSetup(cost, salt, input);
|
||||||
|
String cText = "OrpheanBeholderScryDoubt"; // FIXME - what is this string for, 3 64 bit blocks
|
||||||
|
for (int i=0; i<64; i++) { // FIXME - why 64?
|
||||||
|
cText = encryptECB(state, cText);
|
||||||
|
}
|
||||||
|
return concatenate(cost, salt, cText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String eksBlowfishSetup(long cost, String salt, String key) {
|
||||||
|
String state = initState();
|
||||||
|
state = expandKey (state, salt, key);
|
||||||
|
// TODO buffer overflow check, max size of cost
|
||||||
|
long rounds = Math.round(Math.pow(2, cost));
|
||||||
|
for (int i=0; i<rounds; i++) {
|
||||||
|
state = expandKey (state, 0, key);
|
||||||
|
state = expandKey (state, 0, salt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String initState() {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String expandKey(String state, String salt, String input) {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String encryptECB(String state, String cText) {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String concatenate(long cost, byte[] salt, String cText) {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
package de.muehlencord.shared.jmpass;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class Password {
|
||||||
|
|
||||||
|
private final static int SALT_BYTES = 16;
|
||||||
|
private long rounds;
|
||||||
|
private byte[] hash;
|
||||||
|
private byte[] salt;
|
||||||
|
|
||||||
|
public Password(int iterations) {
|
||||||
|
rounds = Math.round(Math.pow(2, iterations));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hashPassword(String password) throws PasswordException {
|
||||||
|
try {
|
||||||
|
salt = createSalt();
|
||||||
|
hash = createHash(password, salt);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new PasswordException("Error while hashing password. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPasswordHashString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("$");
|
||||||
|
sb.append(rounds);
|
||||||
|
sb.append("$");
|
||||||
|
sb.append(salt);
|
||||||
|
sb.append(hash);
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int getIterationsFromString(String hashedPassword) throws PasswordException {
|
||||||
|
if (hashedPassword.length() < 20) {
|
||||||
|
throw new PasswordException("Given string is not a valid hashed password");
|
||||||
|
}
|
||||||
|
|
||||||
|
String roundsString = hashedPassword.substring(0, 3);
|
||||||
|
if ((!roundsString.startsWith("$")) || (!roundsString.endsWith("$"))) {
|
||||||
|
throw new PasswordException("Cannot read iterations value from given string");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int rounds = Integer.parseInt(roundsString.substring(1, 2));
|
||||||
|
return rounds;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new PasswordException("Cannot parse iterations value from given string", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] createSalt() throws NoSuchAlgorithmException {
|
||||||
|
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
|
||||||
|
// Salt generation 64 bits long
|
||||||
|
byte[] bSalt = new byte[SALT_BYTES];
|
||||||
|
random.nextBytes(bSalt);
|
||||||
|
return bSalt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] createHash(String password, byte[] salt) throws UnsupportedEncodingException, NoSuchAlgorithmException {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||||
|
digest.reset();
|
||||||
|
digest.update(salt);
|
||||||
|
|
||||||
|
byte[] input = digest.digest(password.getBytes("UTF-8"));
|
||||||
|
for (int i = 0; i < rounds; i++) {
|
||||||
|
digest.reset();
|
||||||
|
input = digest.digest(input);
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package de.muehlencord.shared.jmpass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
class PasswordException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creats an instance of PasswordException with the given message
|
||||||
|
* @param msg the msg of the exception
|
||||||
|
*/
|
||||||
|
public PasswordException(String msg) {
|
||||||
|
super (msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creats an instance of PasswordException with the given message
|
||||||
|
* @param msg the msg of the exception
|
||||||
|
* @param th the causing exception
|
||||||
|
*/
|
||||||
|
public PasswordException(String msg, Throwable th) {
|
||||||
|
super (msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package de.muehlencord.shared.jmpass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class PasswordValidator {
|
||||||
|
|
||||||
|
public static boolean validatePassword(String plainPassword, String hashedPassword) {
|
||||||
|
Password pw = new Password(8);
|
||||||
|
pw.hashPassword(plainPassword);
|
||||||
|
|
||||||
|
String hash = pw.getPasswordHashString();
|
||||||
|
return hashedPassword.equals(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
package de.muehlencord.shared.jmpass;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit test for simple App.
|
||||||
|
*/
|
||||||
|
public class AppTest
|
||||||
|
extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the test case
|
||||||
|
*
|
||||||
|
* @param testName name of the test case
|
||||||
|
*/
|
||||||
|
public AppTest( String testName )
|
||||||
|
{
|
||||||
|
super( testName );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the suite of tests being tested
|
||||||
|
*/
|
||||||
|
public static Test suite()
|
||||||
|
{
|
||||||
|
return new TestSuite( AppTest.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rigourous Test :-)
|
||||||
|
*/
|
||||||
|
public void testApp()
|
||||||
|
{
|
||||||
|
assertTrue( true );
|
||||||
|
}
|
||||||
|
}
|
||||||
7
network/.settings/org.eclipse.core.resources.prefs
Normal file
7
network/.settings/org.eclipse.core.resources.prefs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#Thu Jul 05 02:27:50 CEST 2012
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding//src/main/java=UTF-8
|
||||||
|
encoding//src/main/resources=UTF-8
|
||||||
|
encoding//src/test/java=UTF-8
|
||||||
|
encoding//src/test/resources=UTF-8
|
||||||
|
encoding/<project>=UTF-8
|
||||||
5
network/.settings/org.eclipse.jdt.core.prefs
Normal file
5
network/.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.6
|
||||||
5
network/.settings/org.eclipse.m2e.core.prefs
Normal file
5
network/.settings/org.eclipse.m2e.core.prefs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#Thu Jul 05 02:27:48 CEST 2012
|
||||||
|
activeProfiles=
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
resolveWorkspaceProjects=true
|
||||||
|
version=1
|
||||||
18
network/nb-configuration.xml
Normal file
18
network/nb-configuration.xml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project-shared-configuration>
|
||||||
|
<!--
|
||||||
|
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||||
|
The configuration is intended to be shared among all the users of project and
|
||||||
|
therefore it is assumed to be part of version control checkout.
|
||||||
|
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||||
|
-->
|
||||||
|
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||||
|
<!--
|
||||||
|
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||||
|
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||||
|
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||||
|
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||||
|
-->
|
||||||
|
<netbeans.compile.on.save>all</netbeans.compile.on.save>
|
||||||
|
</properties>
|
||||||
|
</project-shared-configuration>
|
||||||
78
network/pom.xml
Normal file
78
network/pom.xml
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
<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>de.muehlencord.shared</groupId>
|
||||||
|
<artifactId>shared-network</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<name>shared-network</name>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>shared</artifactId>
|
||||||
|
<groupId>de.muehlencord</groupId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<url>http://maven.apache.org</url>
|
||||||
|
<ciManagement>
|
||||||
|
<system>hudson</system>
|
||||||
|
<url>http://sunrise.muehlencord.intra:8088/jenkins/job/shared-util/</url>
|
||||||
|
</ciManagement>
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>${project.artifactId}</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>2.5.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.10</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.enterprisedt</groupId>
|
||||||
|
<artifactId>edtFTPj</artifactId>
|
||||||
|
<version>1.5.3</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>log4j</groupId>
|
||||||
|
<artifactId>log4j</artifactId>
|
||||||
|
<version>1.2.17</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>de.muehlencord.shared</groupId>
|
||||||
|
<artifactId>shared-util</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<type>jar</type>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.mail</groupId>
|
||||||
|
<artifactId>mail</artifactId>
|
||||||
|
<version>1.4.5</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@ -0,0 +1,241 @@
|
|||||||
|
package de.muehlencord.shared.network.ftp;
|
||||||
|
|
||||||
|
import com.enterprisedt.net.ftp.FTPClient;
|
||||||
|
import com.enterprisedt.net.ftp.FTPConnectMode;
|
||||||
|
import com.enterprisedt.net.ftp.FTPException;
|
||||||
|
import com.enterprisedt.net.ftp.FTPFile;
|
||||||
|
import de.muehlencord.shared.util.StringUtil;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class FTPConnection {
|
||||||
|
|
||||||
|
/** the default timeout in ms */
|
||||||
|
public static final int DEFAULTTIMEOUT = 30000;
|
||||||
|
/** the logger object */
|
||||||
|
private final Logger logger = Logger.getLogger(FTPConnection.class);
|
||||||
|
/** the username to connect with */
|
||||||
|
private String userName;
|
||||||
|
/** the password to connect with */
|
||||||
|
private String password;
|
||||||
|
/** the ftp client to use */
|
||||||
|
private FTPClient client;
|
||||||
|
/** the remote host to connect to */
|
||||||
|
private String remoteHost;
|
||||||
|
/** the locale of the client to use */
|
||||||
|
private Locale clientLocale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new ftp connection
|
||||||
|
*
|
||||||
|
* @param remoteHost the host to connect to
|
||||||
|
* @param userName the user to connect with
|
||||||
|
* @param password the password to connect with
|
||||||
|
*/
|
||||||
|
public FTPConnection(String remoteHost, String userName, String password) {
|
||||||
|
this(remoteHost, userName, password, Locale.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new ftp connection
|
||||||
|
*
|
||||||
|
* @param remoteHost the host to connect to
|
||||||
|
* @param userName the user to connect with
|
||||||
|
* @param password the password to connect with
|
||||||
|
* @param clientLocale the locale to use for the client
|
||||||
|
*/
|
||||||
|
public FTPConnection(String remoteHost, String userName, String password, Locale clientLocale) {
|
||||||
|
this.remoteHost = remoteHost;
|
||||||
|
this.userName = userName;
|
||||||
|
this.password = password;
|
||||||
|
this.clientLocale = clientLocale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* connects the ftp client to the remote host
|
||||||
|
*
|
||||||
|
* @throws FTPConnectionException if the command cannot be executed
|
||||||
|
*/
|
||||||
|
public void connect() throws FTPConnectionException {
|
||||||
|
try {
|
||||||
|
client = new FTPClient();
|
||||||
|
client.setConnectMode(FTPConnectMode.PASV);
|
||||||
|
client.setParserLocale(clientLocale);
|
||||||
|
client.setRemoteHost(remoteHost);
|
||||||
|
client.setTimeout(DEFAULTTIMEOUT);
|
||||||
|
client.connect();
|
||||||
|
client.login(userName, password);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new FTPConnectionException("Error while connecting to ftp client. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** disconnects the ftp client from the remote host */
|
||||||
|
public void disconnect() {
|
||||||
|
try {
|
||||||
|
client.quit();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
} catch (FTPException ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a list of files (as string) found in the given directory
|
||||||
|
*
|
||||||
|
* @param dir the directory to return the list for
|
||||||
|
* @return a list of files (as string) found in the given directory
|
||||||
|
*
|
||||||
|
* @throws FTPConnectionException if the command cannot be executed
|
||||||
|
*/
|
||||||
|
public List<String> list(String dir) throws FTPConnectionException {
|
||||||
|
List<String> returnValue = new LinkedList<String>();
|
||||||
|
try {
|
||||||
|
FTPFile[] files = client.dirDetails(dir);
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
returnValue.add(files[i].getName());
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
throw new FTPConnectionException("Error while getting diretoy listing. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a list of directories contained in given directory
|
||||||
|
*
|
||||||
|
* @param dir the directory to return the subfolders for
|
||||||
|
* @return a list of subfolders of the given directory
|
||||||
|
*
|
||||||
|
* @throws FTPConnectionException if the command cannot be executed
|
||||||
|
*/
|
||||||
|
public List<String> listDirsOnly(String dir) throws FTPConnectionException {
|
||||||
|
List<String> returnValue = new LinkedList<String>();
|
||||||
|
try {
|
||||||
|
FTPFile[] files = client.dirDetails(dir);
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
if (files[i].isDir()) {
|
||||||
|
returnValue.add(files[i].getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
throw new FTPConnectionException("Error while getting diretoy listing. Reason: " + ex.getMessage(), ex);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a list of files contained in the given folder
|
||||||
|
*
|
||||||
|
* @param dir the directory to list
|
||||||
|
* @return a list of files contained in the given folder
|
||||||
|
*
|
||||||
|
* @throws FTPConnectionException if the command cannot be executed
|
||||||
|
*/
|
||||||
|
public List<String> listFilesOnly(String dir) throws FTPConnectionException {
|
||||||
|
List<String> returnValue = new LinkedList<String>();
|
||||||
|
try {
|
||||||
|
FTPFile[] files = client.dirDetails(dir);
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
if (!files[i].isDir()) {
|
||||||
|
returnValue.add(files[i].getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
throw new FTPConnectionException("Error while getting diretoy listing. Reason: " + ex.getMessage(), ex);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a list of links contained in the given folder
|
||||||
|
*
|
||||||
|
* @param dir the directory to list
|
||||||
|
* @return a list of links contained in the given folder
|
||||||
|
*
|
||||||
|
* @throws FTPConnectionException if the command cannot be executed
|
||||||
|
*/
|
||||||
|
public List<String> listLinksOnly(String dir) throws FTPConnectionException {
|
||||||
|
List<String> returnValue = new LinkedList<String>();
|
||||||
|
try {
|
||||||
|
FTPFile[] files = client.dirDetails(dir);
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
if (files[i].isLink()) {
|
||||||
|
returnValue.add(files[i].getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
throw new FTPConnectionException("Error while getting diretoy listing. Reason: " + ex.getMessage(), ex);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uploads the given file and stores it under the given remote filename - including path
|
||||||
|
*
|
||||||
|
* @param localFilename the path and filename of the source file
|
||||||
|
* @param remoteFileName the path and filename of the destination file
|
||||||
|
* @throws FTPConnectionException if the command cannot be executed
|
||||||
|
*/
|
||||||
|
public void uploadFile(String localFilename, String remoteFileName) throws FTPConnectionException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
client.setDetectTransferMode(true);
|
||||||
|
if ((remoteFileName != null) && !remoteFileName.equals("")) {
|
||||||
|
client.put(localFilename, remoteFileName, false);
|
||||||
|
} else {
|
||||||
|
File f = new File(localFilename);
|
||||||
|
String remoteName = f.getName();
|
||||||
|
client.put(localFilename, remoteName, false);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
throw new FTPConnectionException("Error while uploading file. Reason: " + ex.getMessage(), ex);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* renames a file on the remote host
|
||||||
|
*
|
||||||
|
* @param remoteOldName the current file name
|
||||||
|
* @param remoteNewName the new file name
|
||||||
|
* @throws FTPConnectionException if the command cannot be executed
|
||||||
|
*/
|
||||||
|
public void rename(String remoteOldName, String remoteNewName) throws FTPConnectionException {
|
||||||
|
try {
|
||||||
|
client.rename(remoteOldName, remoteNewName);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
throw new FTPConnectionException("Error while renaming file. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.network.ftp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class FTPConnectionException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 4393979078434188521L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of
|
||||||
|
* <code>FTPConnectionException</code> without detail message.
|
||||||
|
*/
|
||||||
|
public FTPConnectionException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>FTPConnectionException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public FTPConnectionException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>FTPConnectionException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
* @param th the causing exception
|
||||||
|
*/
|
||||||
|
public FTPConnectionException(String msg, Throwable th) {
|
||||||
|
super(msg, th);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,263 @@
|
|||||||
|
package de.muehlencord.shared.network.http;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Communication endpoint for posting a messages
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class HttpLayer {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(HttpLayer.class);
|
||||||
|
/** the url to post to */
|
||||||
|
private String destinationUrlString;
|
||||||
|
/** the encoding to use */
|
||||||
|
private String encoding;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new http layer which can communicate with the given url
|
||||||
|
*
|
||||||
|
* @param urlString
|
||||||
|
* the url to communicate with
|
||||||
|
*/
|
||||||
|
public HttpLayer(String urlString) {
|
||||||
|
this.destinationUrlString = urlString;
|
||||||
|
this.encoding = "UTF-8";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* posts the value of message into the varialbe parameter
|
||||||
|
*
|
||||||
|
* @param parameter
|
||||||
|
* the parameter to write the message to
|
||||||
|
* @param message
|
||||||
|
* the message to post
|
||||||
|
* @throws MessageNotSendException
|
||||||
|
* if the message cannot be sent
|
||||||
|
*/
|
||||||
|
public void post(String parameter, String message)
|
||||||
|
throws MessageNotSendException {
|
||||||
|
Map<String, String[]> parameterMap = new HashMap<String, String[]>();
|
||||||
|
String[] valueArray = { message };
|
||||||
|
parameterMap.put(parameter, valueArray);
|
||||||
|
post(parameterMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void post(List<Map<String, String[]>> parameterMap)
|
||||||
|
throws MessageNotSendException {
|
||||||
|
// construct string to post
|
||||||
|
String content = getDataString(parameterMap);
|
||||||
|
post(content);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* posts the parameters and values specified by the parameter map to the
|
||||||
|
* configured url
|
||||||
|
*
|
||||||
|
* @param parameterMap
|
||||||
|
* the parameter map to post
|
||||||
|
* @throws MessageNotSendException
|
||||||
|
* if the http / post request cannot be executed
|
||||||
|
*
|
||||||
|
* TODO add https support
|
||||||
|
*/
|
||||||
|
public void post(Map<String, String[]> parameterMap) throws MessageNotSendException {
|
||||||
|
List<Map<String,String[]>> parameterList = new LinkedList<Map<String,String[]>>();
|
||||||
|
parameterList.add(parameterMap);
|
||||||
|
String content = getDataString(parameterList);
|
||||||
|
post (content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void post(String messageString) throws MessageNotSendException {
|
||||||
|
// check URL string and return URL object if valid; otherwise
|
||||||
|
// MessageNotSendException is thrown
|
||||||
|
URLConnection urlConn = getUrlConnection();
|
||||||
|
|
||||||
|
// post data
|
||||||
|
IOException exceptionDuringPost = null;
|
||||||
|
OutputStream outputStream = null;
|
||||||
|
DataOutputStream printout = null;
|
||||||
|
try {
|
||||||
|
outputStream = urlConn.getOutputStream();
|
||||||
|
printout = new DataOutputStream(outputStream);
|
||||||
|
printout.writeBytes(messageString);
|
||||||
|
printout.flush();
|
||||||
|
logger.info("Message sent successfully");
|
||||||
|
} catch (IOException ioex) {
|
||||||
|
// store received exception but first get output and
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(ioex);
|
||||||
|
}
|
||||||
|
exceptionDuringPost = ioex;
|
||||||
|
} finally {
|
||||||
|
if (outputStream != null) {
|
||||||
|
try {
|
||||||
|
outputStream.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (printout != null) {
|
||||||
|
try {
|
||||||
|
printout.close();
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get response message
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
InputStreamReader inputStreamReader = null;
|
||||||
|
BufferedReader bufferedReader = null;
|
||||||
|
try {
|
||||||
|
inputStreamReader = new InputStreamReader(urlConn.getInputStream());
|
||||||
|
bufferedReader = new BufferedReader(inputStreamReader);
|
||||||
|
while (bufferedReader.ready()) {
|
||||||
|
sb.append(bufferedReader.readLine());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Response from server");
|
||||||
|
logger.debug(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException ioex) {
|
||||||
|
logger.error(ioex);
|
||||||
|
exceptionDuringPost = ioex;
|
||||||
|
} finally {
|
||||||
|
if (bufferedReader != null) {
|
||||||
|
try {
|
||||||
|
bufferedReader.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inputStreamReader != null) {
|
||||||
|
try {
|
||||||
|
inputStreamReader.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exceptionDuringPost != null) {
|
||||||
|
String hint = "Error while sending message. Reason: "
|
||||||
|
+ exceptionDuringPost.getMessage();
|
||||||
|
logger.error(hint);
|
||||||
|
throw new MessageNotSendException(hint, exceptionDuringPost);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param urlString
|
||||||
|
* the url to check
|
||||||
|
* @return a URl object created from the given urlString
|
||||||
|
* @throws MessageNotSendException
|
||||||
|
* if the url is invalid
|
||||||
|
*/
|
||||||
|
private URLConnection getUrlConnection() throws MessageNotSendException {
|
||||||
|
URLConnection urlConn;
|
||||||
|
URL url;
|
||||||
|
try {
|
||||||
|
url = new URL(destinationUrlString);
|
||||||
|
} catch (MalformedURLException ex) {
|
||||||
|
String hint = "Cannot send message to url - invalid url "
|
||||||
|
+ destinationUrlString;
|
||||||
|
logger.error(hint);
|
||||||
|
throw new MessageNotSendException(hint, ex);
|
||||||
|
}
|
||||||
|
String protocol = url.getProtocol().toLowerCase();
|
||||||
|
if (!protocol.equals("http")) {
|
||||||
|
String hint = "protocol " + protocol + " not supported";
|
||||||
|
logger.error(hint);
|
||||||
|
throw new MessageNotSendException(hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup url connection
|
||||||
|
try {
|
||||||
|
// URL connection channel.
|
||||||
|
urlConn = url.openConnection();
|
||||||
|
// Let the run-time system (RTS) know that we want input.
|
||||||
|
urlConn.setDoInput(true);
|
||||||
|
// Let the RTS know that we want to do output.
|
||||||
|
urlConn.setDoOutput(true);
|
||||||
|
// No caching, we want the real thing.
|
||||||
|
urlConn.setUseCaches(false);
|
||||||
|
// Specify the content type.
|
||||||
|
urlConn.setRequestProperty("Content-Type",
|
||||||
|
"application/x-www-form-urlencoded");
|
||||||
|
} catch (IOException ioex) {
|
||||||
|
String hint = "Error while setting up connection. Reason: "
|
||||||
|
+ ioex.getMessage();
|
||||||
|
logger.error(hint);
|
||||||
|
throw new MessageNotSendException(hint, ioex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return urlConn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the data string to post based on the given parameter map
|
||||||
|
*
|
||||||
|
* @param parameterMap
|
||||||
|
* the parameter map to construct the data string from
|
||||||
|
* @return the data string to post
|
||||||
|
* @throws MessageNotSendException
|
||||||
|
* if the datastring cannot be constructed
|
||||||
|
*/
|
||||||
|
private String getDataString(List<Map<String, String[]>> parameterList)
|
||||||
|
throws MessageNotSendException {
|
||||||
|
// perpare data
|
||||||
|
String data = "";
|
||||||
|
for (Map<String,String[]> parameterMap : parameterList) {
|
||||||
|
try {
|
||||||
|
Iterator<String> keyIterator = parameterMap.keySet().iterator();
|
||||||
|
while (keyIterator.hasNext()) {
|
||||||
|
String key = keyIterator.next();
|
||||||
|
String[] valueArray = parameterMap.get(key);
|
||||||
|
for (String currentValue : valueArray) {
|
||||||
|
if (!data.equals("")) {
|
||||||
|
data += "&";
|
||||||
|
}
|
||||||
|
data += key.toLowerCase() + "="
|
||||||
|
+ URLEncoder.encode(currentValue, encoding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (UnsupportedEncodingException ex) {
|
||||||
|
String hint = "Error while preparing data for message. Unknown encoding "
|
||||||
|
+ encoding;
|
||||||
|
logger.error(hint);
|
||||||
|
throw new MessageNotSendException(hint, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
package de.muehlencord.shared.network.http;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This message is thrown if a message cannot be sent
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class MessageNotSendException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -8959773341187046577L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of
|
||||||
|
* <code>MessageNotSendException</code> without detail message.
|
||||||
|
*/
|
||||||
|
public MessageNotSendException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>MessageNotSendException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public MessageNotSendException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>MessageNotSendException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
* @param th the causing exception
|
||||||
|
*/
|
||||||
|
public MessageNotSendException(String msg, Throwable th) {
|
||||||
|
super(msg, th);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,485 @@
|
|||||||
|
package de.muehlencord.shared.network.mail;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.util.StringUtil;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.mail.Flags;
|
||||||
|
import javax.mail.Folder;
|
||||||
|
import javax.mail.Message;
|
||||||
|
import javax.mail.MessagingException;
|
||||||
|
import javax.mail.Session;
|
||||||
|
import javax.mail.Store;
|
||||||
|
import javax.mail.internet.MimeMessage;
|
||||||
|
import javax.mail.search.MessageIDTerm;
|
||||||
|
import javax.mail.search.SearchTerm;
|
||||||
|
import javax.mail.util.SharedByteArrayInputStream;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MailReader to connect and work with IMAP mailboxes. Also works with exchange servers.
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public abstract class DefaultMailReader implements MailReader {
|
||||||
|
|
||||||
|
/** the logging object */
|
||||||
|
private final static Logger logger = Logger.getLogger(DefaultMailReader.class);
|
||||||
|
/** the store to connect with */
|
||||||
|
private Store store = null;
|
||||||
|
/** the smtp host to work with */
|
||||||
|
private final MailReaderConfiguration configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new instance of the DefaultMailReader and updates needed values and settings
|
||||||
|
*
|
||||||
|
* @param config the configuration for the reader
|
||||||
|
*/
|
||||||
|
public DefaultMailReader(MailReaderConfiguration config) {
|
||||||
|
this.configuration = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onnects to the mailbox
|
||||||
|
*
|
||||||
|
* @throws MailReaderConnectionException if the connection cannot be established
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public abstract void connect() throws MailReaderConnectionException;
|
||||||
|
|
||||||
|
/** disconnects from mailbox */
|
||||||
|
@Override
|
||||||
|
public void disconnect() {
|
||||||
|
if (getStore() != null) {
|
||||||
|
try {
|
||||||
|
getStore().close();
|
||||||
|
} catch (MessagingException ex) {
|
||||||
|
logger.error("Cannot disconnect from mailbox");
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
} finally {
|
||||||
|
logger.info("Connection closed");
|
||||||
|
setStore(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** returns the default folder
|
||||||
|
*
|
||||||
|
* @return the default folder
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the default folder cannot be found
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getDefaultFolder() throws MailReaderException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
return getStore().getDefaultFolder().getFullName();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
throw new MailReaderException("Error while retrieving default folder. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the list of subfolders of the specified source folder
|
||||||
|
*
|
||||||
|
* @param sourceFolder the folder to return the folder list for
|
||||||
|
* @return the list of subfolders of the specified source folder
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the folder list cannot be retrieved
|
||||||
|
*/
|
||||||
|
public List<String> getSubFolder(Folder sourceFolder) throws MailReaderException {
|
||||||
|
List<String> returnValue = new LinkedList<String>();
|
||||||
|
try {
|
||||||
|
Folder[] folders = sourceFolder.list();
|
||||||
|
for (Folder folder : folders) {
|
||||||
|
returnValue.add(folder.getFullName());
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
throw new MailReaderException("Cannot retrieve folder list. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the session object to use
|
||||||
|
*
|
||||||
|
* @return the session object to use
|
||||||
|
*/
|
||||||
|
protected Session getDefaultSession() {
|
||||||
|
Properties props = (Properties) System.getProperties().clone();
|
||||||
|
props.put("mail.smtp.host", configuration.getSmtpHost());
|
||||||
|
// TODO - add needed properties - only valid for session, do not overwrite properites
|
||||||
|
// TODO - add chained properties
|
||||||
|
return Session.getInstance(props, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the store
|
||||||
|
*/
|
||||||
|
protected Store getStore() {
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param store the store to set
|
||||||
|
*/
|
||||||
|
protected void setStore(Store store) {
|
||||||
|
this.store = store;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the configuration object
|
||||||
|
*
|
||||||
|
* @return returns the configuration
|
||||||
|
*/
|
||||||
|
protected MailReaderConfiguration getConfiguration() {
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the folder, if folder path is a valid path to an existing folder
|
||||||
|
*
|
||||||
|
* @param folderPath the folder to return
|
||||||
|
* @return the folder, if folder path is a valid path to an existing folder
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the folder cannot be found
|
||||||
|
*/
|
||||||
|
private List<Folder> getFolderPath(String folderPath) throws MailReaderException {
|
||||||
|
List<Folder> returnValue = new LinkedList<Folder>();
|
||||||
|
try {
|
||||||
|
String[] folderPathParts = folderPath.split("/");
|
||||||
|
Folder currentFolder = store.getDefaultFolder();
|
||||||
|
boolean stillExists = true;
|
||||||
|
|
||||||
|
for (int i = 0; ((i < folderPathParts.length) && (stillExists)); i++) {
|
||||||
|
currentFolder = currentFolder.getFolder(folderPathParts[i]);
|
||||||
|
stillExists = currentFolder.exists();
|
||||||
|
returnValue.add(currentFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stillExists) {
|
||||||
|
return returnValue;
|
||||||
|
} else {
|
||||||
|
throw new MailReaderException("Folder " + folderPath + " not found");
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailReaderException("Error while getting older " + folderPath + ". Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the folder object defined by the folder path
|
||||||
|
*
|
||||||
|
* @param sourceFolder the full name of the folder (including path)
|
||||||
|
* @return the folder object if existent
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the folder does not exist
|
||||||
|
*/
|
||||||
|
private Folder getFolderObject(String sourceFolder) throws MailReaderException {
|
||||||
|
List<Folder> folderList = getFolderPath(sourceFolder);
|
||||||
|
return folderList.get(folderList.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the folder, if folder path is a valid path to an existing folder
|
||||||
|
*
|
||||||
|
* @param folderPath the folder to return
|
||||||
|
* @return the folder, if folder path is a valid path to an existing folder
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the folder cannot be found
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getFolder(String folderPath) throws MailReaderException {
|
||||||
|
String returnValue = "";
|
||||||
|
List<Folder> folderList = getFolderPath(folderPath);
|
||||||
|
for (Folder folder : folderList) {
|
||||||
|
returnValue += folder.getName() + "/";
|
||||||
|
}
|
||||||
|
if (returnValue.endsWith("/")) {
|
||||||
|
returnValue = returnValue.substring(0, returnValue.length() - 1);
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the list of subfolders of the specified source folder
|
||||||
|
*
|
||||||
|
* @param sourceFolder the folder to return the folder list for
|
||||||
|
* @return the list of subfolders of the specified source folder
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the folder list cannot be retrieved
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> getSubFolder(String sourceFolder) throws MailReaderException {
|
||||||
|
List<String> returnValue = new LinkedList<String>();
|
||||||
|
Folder folder = getFolderObject(sourceFolder);
|
||||||
|
|
||||||
|
try {
|
||||||
|
folder.open(Folder.READ_ONLY);
|
||||||
|
Folder[] subFolders = folder.list();
|
||||||
|
for (Folder subFolder : subFolders) {
|
||||||
|
returnValue.add(subFolder.getFullName());
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailReaderException("Error while getting subfolders. Reason: " + ex.getMessage(), ex);
|
||||||
|
} finally {
|
||||||
|
if ((folder != null) && folder.isOpen()) {
|
||||||
|
try {
|
||||||
|
folder.close(false);
|
||||||
|
} catch (MessagingException ex) {
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the message count for the given folder
|
||||||
|
*
|
||||||
|
* @param sourceFolder the folder to return the message count for
|
||||||
|
* @return the message count for the given folder
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the amount of messages cannot be determined
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int getMessageCount(String sourceFolder) throws MailReaderException {
|
||||||
|
Folder folder = getFolderObject(sourceFolder);
|
||||||
|
int messageCount;
|
||||||
|
try {
|
||||||
|
|
||||||
|
folder.open(Folder.READ_ONLY);
|
||||||
|
messageCount = folder.getMessageCount();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailReaderException("Error while getting messageCount. Reason:" + ex.getMessage(), ex);
|
||||||
|
} finally {
|
||||||
|
if ((folder != null) && folder.isOpen()) {
|
||||||
|
try {
|
||||||
|
folder.close(false);
|
||||||
|
} catch (MessagingException ex) {
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return messageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retrieves the list of messages stored in the given folder
|
||||||
|
*
|
||||||
|
* @param sourceFolder the folder to search return the emails for
|
||||||
|
* @return list of messages stored in the given folder
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the message list cannot be retrieved
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<MailMessage> getMessages(String sourceFolder) throws MailReaderException {
|
||||||
|
List<MailMessage> returnValue = new LinkedList<MailMessage>();
|
||||||
|
Folder folder = getFolderObject(sourceFolder);
|
||||||
|
try {
|
||||||
|
folder.open(Folder.READ_ONLY);
|
||||||
|
Message[] messages = folder.getMessages();
|
||||||
|
for (Message msg : messages) {
|
||||||
|
returnValue.add(MailMessageUtils.getInstance(getValidMessage(msg)));
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailReaderException("Cannot fetch email from folder " + folder.getFullName() + ". Reason: " + ex.getMessage(), ex);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if ((folder != null) && (folder.isOpen())) {
|
||||||
|
try {
|
||||||
|
folder.close(false);
|
||||||
|
} catch (MessagingException ex) {
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copies the given message from the source folder to the destination folder
|
||||||
|
*
|
||||||
|
* @param mm the message to copy
|
||||||
|
* @param sourceFolder the folder the message currently resists in
|
||||||
|
* @param destFolder the folder the message should be copied to
|
||||||
|
* @throws MailReaderException if the operation fails
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void copyMessage(MailMessage mm, String sourceFolder, String destFolder) throws MailReaderException {
|
||||||
|
copyMessages(mm, sourceFolder, destFolder, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* moves the given message from the source folder to the destination folder
|
||||||
|
*
|
||||||
|
* @param mm the message to move
|
||||||
|
* @param sourceFolder the folder the message currently resists in
|
||||||
|
* @param destFolder the folder the message should be moved to
|
||||||
|
* @throws MailReaderException if the operation fails
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void moveMessage(MailMessage mm, String sourceFolder, String destFolder) throws MailReaderException {
|
||||||
|
copyMessages(mm, sourceFolder, destFolder, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* marks the messages as seen
|
||||||
|
*
|
||||||
|
* @param folderName the folder to search for the email
|
||||||
|
* @param mm the message to mark as seen
|
||||||
|
* @param flagValue if set to true, the seen flag is set; otherwise it is removed (unset)
|
||||||
|
* @throws MailReaderException if the flag cannot be set
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setSeenFlag(String folderName, MailMessage mm, boolean flagValue) throws MailReaderException {
|
||||||
|
Folder folder = getFolderObject(folderName);
|
||||||
|
try {
|
||||||
|
folder.open(Folder.READ_WRITE);
|
||||||
|
Message[] msgs = getMessage(folder, mm.getMessageId());
|
||||||
|
|
||||||
|
for (Message message : msgs) {
|
||||||
|
message.setFlag(Flags.Flag.SEEN, true);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailReaderException("Cannot set seen flag. Reason: " + ex.getMessage(), ex);
|
||||||
|
} finally {
|
||||||
|
if ((folder != null) && (folder.isOpen())) {
|
||||||
|
try {
|
||||||
|
folder.close(false);
|
||||||
|
} catch (MessagingException ex) {
|
||||||
|
logger.debug("Error while closing folder", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns an array with one element of javax.mail.Message with the given messageid
|
||||||
|
*
|
||||||
|
* @param folder the folder to search for the message
|
||||||
|
* @param messageId messageid of the message
|
||||||
|
* @return the javax.mail.Message object for the mail with the givne messageid
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the message cannot be found or if more than one message with the same messageid exists
|
||||||
|
*/
|
||||||
|
private Message[] getMessage(Folder folder, String messageId) throws MailReaderException {
|
||||||
|
try {
|
||||||
|
SearchTerm st = new MessageIDTerm(messageId);
|
||||||
|
Message[] messages = folder.search(st);
|
||||||
|
if (messages.length != 1) {
|
||||||
|
throw new MailReaderException("Cannot find message with messageID = " + messageId);
|
||||||
|
}
|
||||||
|
return messages;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailReaderException("Cannot find message with messageID = " + messageId + ". Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* moves the given message from the source folder to the destination folder
|
||||||
|
*
|
||||||
|
* @param mm the message to move
|
||||||
|
* @param sourceFolder the folder the message currently resists in
|
||||||
|
* @param destFolder the folder the message should be moved to
|
||||||
|
* @param deleteMessage if set to true, the messages are deleted from source folder after deletion
|
||||||
|
* @throws MailReaderException if the operation fails
|
||||||
|
*/
|
||||||
|
private void copyMessages(MailMessage mm, String sourceFolder, String destFolder, boolean deleteMessage) throws MailReaderException {
|
||||||
|
Folder sf = getFolderObject(sourceFolder);
|
||||||
|
Folder df = getFolderObject(destFolder);
|
||||||
|
|
||||||
|
try {
|
||||||
|
sf.open(Folder.READ_WRITE);
|
||||||
|
df.open(Folder.READ_WRITE);
|
||||||
|
|
||||||
|
Message[] messages = getMessage(sf, mm.getMessageId());
|
||||||
|
sf.copyMessages(messages, df);
|
||||||
|
|
||||||
|
if (deleteMessage) {
|
||||||
|
for (Message message : messages) {
|
||||||
|
message.setFlag(Flags.Flag.DELETED, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
} finally {
|
||||||
|
if ((df != null) && (df.isOpen())) {
|
||||||
|
try {
|
||||||
|
df.close(false);
|
||||||
|
} catch (MessagingException ex) {
|
||||||
|
logger.debug("Error while closing destination folder", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sf != null) && (sf.isOpen())) {
|
||||||
|
try {
|
||||||
|
sf.close(true);
|
||||||
|
} catch (MessagingException ex) {
|
||||||
|
logger.debug("Error while closing source folder", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* asures the message can be read even if the underlaying IMAP server does not handle the message correctly. see
|
||||||
|
* http://www.oracle.com/technetwork/java/faq-135477.html for details
|
||||||
|
*
|
||||||
|
* @param msg the message to read
|
||||||
|
* @return the message in a readable format
|
||||||
|
*
|
||||||
|
* @throws MessagingException if the message cannot be processed
|
||||||
|
*/
|
||||||
|
private Message getValidMessage(Message msg) throws MessagingException {
|
||||||
|
|
||||||
|
// assert message can be read
|
||||||
|
// see
|
||||||
|
MessagingException initialException;
|
||||||
|
try {
|
||||||
|
msg.getContentType();
|
||||||
|
return msg;
|
||||||
|
} catch (MessagingException ex) {
|
||||||
|
initialException = ex;
|
||||||
|
logger.debug("Direct access failed - trying workaround copy constructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
MimeMessage copyMsg = (MimeMessage) msg;
|
||||||
|
// Use the MimeMessage copy constructor to make a copy
|
||||||
|
// of the entire message, which will fetch the entire
|
||||||
|
// message from the server and parse it on the client:
|
||||||
|
MimeMessage cmsg = new MimeMessage(copyMsg);
|
||||||
|
cmsg.getContentType();
|
||||||
|
return cmsg;
|
||||||
|
} catch (MessagingException ex) {
|
||||||
|
logger.debug("Access via copy constructor failed, trying byte array constructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Session session = getDefaultSession();
|
||||||
|
|
||||||
|
// Copy the message by writing into an byte array and
|
||||||
|
// creating a new MimeMessage object based on the contents
|
||||||
|
// of the byte array:
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
msg.writeTo(bos);
|
||||||
|
bos.close();
|
||||||
|
SharedByteArrayInputStream bis =
|
||||||
|
new SharedByteArrayInputStream(bos.toByteArray());
|
||||||
|
MimeMessage cmsg = new MimeMessage(session, bis);
|
||||||
|
bis.close();
|
||||||
|
|
||||||
|
return cmsg;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.debug("Also fallback solution did not work");
|
||||||
|
throw initialException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,315 @@
|
|||||||
|
/**
|
||||||
|
* package containing containing acess to mail messages, covering javax.mail api
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.network.mail;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.mail.Address;
|
||||||
|
import javax.mail.internet.InternetAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mail message
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class MailMessage {
|
||||||
|
|
||||||
|
/** the subect of the email */
|
||||||
|
private String subject;
|
||||||
|
/** the content of the message */
|
||||||
|
private List<String> content;
|
||||||
|
/** the html content of the message if avaialble, null else */
|
||||||
|
private List<String> htmlContent;
|
||||||
|
/** true, if content is html message body */
|
||||||
|
private boolean isHtmlMessage;
|
||||||
|
/** the message id if available, null otherwise */
|
||||||
|
private String messageId;
|
||||||
|
/** the size of the message in bytes */
|
||||||
|
private int size;
|
||||||
|
/** the date the message was sent */
|
||||||
|
private Date sentDate;
|
||||||
|
/** the sender of the email */
|
||||||
|
private String sender;
|
||||||
|
/** the list of receivers */
|
||||||
|
private List<String> receiver;
|
||||||
|
/** the list of CC receivers */
|
||||||
|
private List<String> ccReceiver;
|
||||||
|
/** the list of BCCC receivers */
|
||||||
|
private List<String> bccReceiver;
|
||||||
|
|
||||||
|
// TODO add replyTo, add attachmentSupport
|
||||||
|
/**
|
||||||
|
* creates a new instance of a MailMessage
|
||||||
|
*
|
||||||
|
* @param subj the subject of the message
|
||||||
|
* @param contentString the content of the message
|
||||||
|
*/
|
||||||
|
public MailMessage(String subj, String contentString) {
|
||||||
|
this.subject = subj;
|
||||||
|
this.content = new LinkedList<String>();
|
||||||
|
if (contentString != null) {
|
||||||
|
content.add(contentString);
|
||||||
|
}
|
||||||
|
this.htmlContent = new LinkedList<String>();
|
||||||
|
this.isHtmlMessage = false;
|
||||||
|
this.messageId = null;
|
||||||
|
this.sender = null;
|
||||||
|
this.receiver = new LinkedList<String>();
|
||||||
|
this.ccReceiver = new LinkedList<String>();
|
||||||
|
this.bccReceiver = new LinkedList<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** creates a new instance of MaiLmessage
|
||||||
|
*
|
||||||
|
* @param subj the subject of the message
|
||||||
|
* @param contentString the content of the message
|
||||||
|
* @param id the message id the message was sent with
|
||||||
|
*/
|
||||||
|
public MailMessage(String subj, String contentString, String id) {
|
||||||
|
this(subj, contentString);
|
||||||
|
this.messageId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *** getter / setter *** */
|
||||||
|
/**
|
||||||
|
* @return the subject
|
||||||
|
*/
|
||||||
|
public String getSubject() {
|
||||||
|
return subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the content
|
||||||
|
*/
|
||||||
|
public String getContent() {
|
||||||
|
return getContent(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getContent(List<String> contentList) {
|
||||||
|
String returnValue = "";
|
||||||
|
String contentSeparator = "--------";
|
||||||
|
for (String currentContent : contentList) {
|
||||||
|
returnValue += currentContent;
|
||||||
|
returnValue += contentSeparator; // FIXME make configurable
|
||||||
|
}
|
||||||
|
if (returnValue.endsWith(contentSeparator)) {
|
||||||
|
returnValue = returnValue.substring(0, returnValue.length() - contentSeparator.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the content string of the message
|
||||||
|
*
|
||||||
|
* @param c the content to set
|
||||||
|
* @param isHtmlContent if set to true, given content is treated as html content
|
||||||
|
*/
|
||||||
|
public void setContent(String c, boolean isHtmlContent) {
|
||||||
|
if (c != null) {
|
||||||
|
content.add(c);
|
||||||
|
this.isHtmlMessage = isHtmlContent;
|
||||||
|
if (isHtmlContent) {
|
||||||
|
this.htmlContent.add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the html content of the message
|
||||||
|
*
|
||||||
|
* @param c the content to set (html string)
|
||||||
|
*/
|
||||||
|
public void setHtmlContent(String c) {
|
||||||
|
this.htmlContent.add(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the html content string
|
||||||
|
*
|
||||||
|
* @return the html content string
|
||||||
|
*/
|
||||||
|
public String getHtmlContent() {
|
||||||
|
return getContent(htmlContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the isHtmlMessage
|
||||||
|
*/
|
||||||
|
public boolean isHtmlMessage() {
|
||||||
|
return isHtmlMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the messageId
|
||||||
|
*/
|
||||||
|
public String getMessageId() {
|
||||||
|
return messageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the size of the message in bytes
|
||||||
|
*
|
||||||
|
* @param messageSize the size of the message in bytes
|
||||||
|
*/
|
||||||
|
public void setSize(int messageSize) {
|
||||||
|
this.size = messageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the message size in bytes
|
||||||
|
*/
|
||||||
|
public int getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the sentDate
|
||||||
|
*/
|
||||||
|
public Date getSentDate() {
|
||||||
|
return new Date(sentDate.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param date the sentDate to set
|
||||||
|
*/
|
||||||
|
public void setSentDate(Date date) {
|
||||||
|
this.sentDate = new Date(date.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the sender
|
||||||
|
*/
|
||||||
|
public String getSender() {
|
||||||
|
return sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the sender address
|
||||||
|
*
|
||||||
|
* @param sender the sender to set
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setSender(String sender) {
|
||||||
|
this.sender = sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the sender address
|
||||||
|
*
|
||||||
|
* @param sender the sender to set
|
||||||
|
*/
|
||||||
|
public void setSender(Address[] sender) {
|
||||||
|
if (sender.length > 0) {
|
||||||
|
this.sender = getEmailAddress(sender[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the receiver
|
||||||
|
*/
|
||||||
|
public List<String> getReceiver() {
|
||||||
|
return receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param rcv the receiver to set
|
||||||
|
*/
|
||||||
|
public void addReceiver(String rcv) {
|
||||||
|
this.receiver.add(rcv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds the given receiver to the list of receivers
|
||||||
|
*
|
||||||
|
* @param rcvList the receiver to add
|
||||||
|
*/
|
||||||
|
public void addReceiver(List<String> rcvList) {
|
||||||
|
this.receiver.addAll(rcvList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds the give list of addresses to the receiver list
|
||||||
|
*
|
||||||
|
* @param addresses the addresses to add
|
||||||
|
*/
|
||||||
|
public void addReceiver(Address[] addresses) {
|
||||||
|
if (addresses != null) {
|
||||||
|
for (Address currentAddress : addresses) {
|
||||||
|
addReceiver(getEmailAddress(currentAddress));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the ccReceiver
|
||||||
|
*/
|
||||||
|
public List<String> getCcReceiver() {
|
||||||
|
return ccReceiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param rcv the ccReceiver to set
|
||||||
|
*/
|
||||||
|
public void addCcReceiver(String rcv) {
|
||||||
|
this.ccReceiver.add(rcv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds the give list of addresses to the cc receiver list
|
||||||
|
*
|
||||||
|
* @param addresses the addresses to add
|
||||||
|
*/
|
||||||
|
public void addCcReceiver(Address[] addresses) {
|
||||||
|
if (addresses != null) {
|
||||||
|
for (Address currentAddress : addresses) {
|
||||||
|
addCcReceiver(getEmailAddress(currentAddress));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the bccReceiver
|
||||||
|
*/
|
||||||
|
public List<String> getBccReceiver() {
|
||||||
|
return bccReceiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param rcv the bccReceiver to set
|
||||||
|
*/
|
||||||
|
public void addBccReceiver(String rcv) {
|
||||||
|
this.bccReceiver.add(rcv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds the give list of addresses to the bcc receiver list
|
||||||
|
*
|
||||||
|
* @param addresses the addresses to add
|
||||||
|
*/
|
||||||
|
public void addBccReceiver(Address[] addresses) {
|
||||||
|
if (addresses != null) {
|
||||||
|
for (Address currentAddress : addresses) {
|
||||||
|
addBccReceiver(getEmailAddress(currentAddress));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the email adddress of the givne address
|
||||||
|
*
|
||||||
|
* @param currentAddress the address to get
|
||||||
|
* @return the email adddress of the givne address as string
|
||||||
|
*/
|
||||||
|
private String getEmailAddress(Address currentAddress) {
|
||||||
|
if (currentAddress instanceof InternetAddress) {
|
||||||
|
InternetAddress address = (InternetAddress) currentAddress;
|
||||||
|
return address.getAddress();
|
||||||
|
} else {
|
||||||
|
return currentAddress.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
package de.muehlencord.shared.network.mail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception used during mail handling
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class MailMessageException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 6699249884047524285L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of
|
||||||
|
* <code>MailMessageException</code> without detail message.
|
||||||
|
*/
|
||||||
|
public MailMessageException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>MailMessageException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public MailMessageException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>MailMessageException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
* @param th the causing Throwable
|
||||||
|
*/
|
||||||
|
public MailMessageException(String msg, Throwable th) {
|
||||||
|
super(msg,th);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,326 @@
|
|||||||
|
/**
|
||||||
|
* wrapper classes around javax.mail package
|
||||||
|
* written by Joern Muehlencord
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.network.mail;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.util.StringUtil;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import javax.mail.BodyPart;
|
||||||
|
import javax.mail.Message;
|
||||||
|
import javax.mail.MessagingException;
|
||||||
|
import javax.mail.Multipart;
|
||||||
|
import javax.mail.internet.MimeMessage;
|
||||||
|
import javax.mail.internet.MimeMultipart;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Util class to convert between javax.mail.Message and MailMessage objects
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public abstract class MailMessageUtils {
|
||||||
|
|
||||||
|
/** the logging object */
|
||||||
|
private static final Logger logger = Logger.getLogger(MailMessageUtils.class.getName());
|
||||||
|
|
||||||
|
/** content type of mutipart messages - e.g. multipart_alternative or _mixed */
|
||||||
|
private static final String CONTENTTYPE_MULTIPART = "multipart/";
|
||||||
|
/** content type of text messages - like text/plain or text/html */
|
||||||
|
private static final String CONTENTTYPE_TEXT = "text/";
|
||||||
|
/** content type of text/plain messages */
|
||||||
|
private static final String CONTENTTYPE_TEXT_PLAIN = "text/plain";
|
||||||
|
/** content type of text/html messages */
|
||||||
|
private static final String CONTENTTYPE_TEXT_HTML = "text/html";
|
||||||
|
/** content type of application based messages - e.g. application/pdf */
|
||||||
|
private static final String CONTENTTYPE_APPLICATION = "application/";
|
||||||
|
/** content type of application pgp-signature */
|
||||||
|
private static final String CONTENTTYPE_APPLICATION_PGPSIGNATURE = "application/pgp-signature";
|
||||||
|
/** content type of embedded message */
|
||||||
|
private static final String CONTENTTYPE_MESSAGE = "message/";
|
||||||
|
/** content type of attached images */
|
||||||
|
private static final String CONTENTTYPE_IMAGE = "image/";
|
||||||
|
/** content type of attached videos */
|
||||||
|
private static final String CONTENTTYPE_VIDEO = "video/";
|
||||||
|
/** content type of attached audios */
|
||||||
|
private static final String CONTENTTYPE_AUDIO = "audio/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new instance of MailMessage based on the given javax.mail.Message object
|
||||||
|
*
|
||||||
|
* @param message the message object to create the message from
|
||||||
|
* @return the MailMessage object created from the given javax.mail.Message
|
||||||
|
*
|
||||||
|
* @throws MailMessageException if the message cannot be created
|
||||||
|
*/
|
||||||
|
public static MailMessage getInstance(Message message) throws MailMessageException {
|
||||||
|
MailMessage returnMessage = null;
|
||||||
|
|
||||||
|
if (message instanceof MimeMessage) {
|
||||||
|
MimeMessage mm = (MimeMessage) message;
|
||||||
|
String contentType;
|
||||||
|
String subject;
|
||||||
|
String messageId;
|
||||||
|
try {
|
||||||
|
contentType = getContentType(mm.getContentType());
|
||||||
|
subject = mm.getSubject();
|
||||||
|
logger.debug("message subject = " + subject);
|
||||||
|
messageId = getMessageId(message);
|
||||||
|
logger.debug("messageid = " + messageId);
|
||||||
|
logger.debug(mm.getSentDate());
|
||||||
|
|
||||||
|
} catch (MessagingException ex) {
|
||||||
|
throw new MailMessageException("Error while converting mime message. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("messageContentType = " + contentType);
|
||||||
|
|
||||||
|
// handling multipart messages
|
||||||
|
if (contentType.contains(CONTENTTYPE_MULTIPART)) {
|
||||||
|
returnMessage = new MailMessage(subject, null, messageId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Multipart mp = (Multipart) mm.getContent();
|
||||||
|
int partsFound = mp.getCount();
|
||||||
|
logger.debug(partsFound + " parts found");
|
||||||
|
for (int i = 0; i < partsFound; i++) {
|
||||||
|
logger.debug("Working on multiPart " + (i + 1));
|
||||||
|
BodyPart bp = mp.getBodyPart(i);
|
||||||
|
String bodyContentType = getContentType(bp.getContentType());
|
||||||
|
logger.debug("contentType = " + bodyContentType);
|
||||||
|
|
||||||
|
|
||||||
|
if (bodyContentType.contains(CONTENTTYPE_MULTIPART)) {
|
||||||
|
MimeMultipart bodyMultiPart = (MimeMultipart) bp.getContent();
|
||||||
|
int bodyPartCount = bodyMultiPart.getCount();
|
||||||
|
logger.debug(bodyPartCount + " bodyMultiParts found");
|
||||||
|
for (int currentBodyPart = 0; currentBodyPart < bodyPartCount; currentBodyPart++) {
|
||||||
|
|
||||||
|
logger.debug("Working on bodypart " + (currentBodyPart + 1));
|
||||||
|
BodyPart bodyPart = bodyMultiPart.getBodyPart(currentBodyPart);
|
||||||
|
String bodyPartContentType = getContentType(bodyPart.getContentType());
|
||||||
|
logger.debug("bodyPart contentType = " + bodyPartContentType);
|
||||||
|
|
||||||
|
if (bodyPartContentType.contains(CONTENTTYPE_TEXT_PLAIN)) {
|
||||||
|
returnMessage.setContent(getContent(bodyPart), false);
|
||||||
|
} else if (bodyPartContentType.contains(CONTENTTYPE_TEXT_HTML)) {
|
||||||
|
returnMessage.setHtmlContent(getContent(bodyPart));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (bodyContentType.equals(CONTENTTYPE_TEXT_PLAIN)) {
|
||||||
|
|
||||||
|
if (bp.getFileName() == null) {
|
||||||
|
returnMessage.setContent(getContent(bp), false);
|
||||||
|
} else {
|
||||||
|
logger.debug("Found base64 coded attachment - not yet supported, skipping");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (bodyContentType.equals(CONTENTTYPE_TEXT_HTML)) {
|
||||||
|
returnMessage.setHtmlContent(getContent(bp));
|
||||||
|
|
||||||
|
} else if (bodyContentType.equals(CONTENTTYPE_APPLICATION_PGPSIGNATURE)) {
|
||||||
|
logger.debug("Found pgp signature - not yet supported, skipping");
|
||||||
|
// TODO add pgp/signature support
|
||||||
|
|
||||||
|
} else if ((bodyContentType.contains(CONTENTTYPE_APPLICATION) || (bodyContentType.contains(CONTENTTYPE_MESSAGE))
|
||||||
|
|| (bodyContentType.contains(CONTENTTYPE_TEXT)) || (bodyContentType.contains(CONTENTTYPE_IMAGE))
|
||||||
|
|| (bodyContentType.contains(CONTENTTYPE_VIDEO)) || (bodyContentType.contains(CONTENTTYPE_AUDIO)))) {
|
||||||
|
logger.debug("Found attachment - not yet supported, skipping");
|
||||||
|
// TODO add attachment support
|
||||||
|
} else {
|
||||||
|
throw new MailMessageException("Reading bodyContentType " + bodyContentType + " not yet implemented");
|
||||||
|
}
|
||||||
|
} // for all parts
|
||||||
|
|
||||||
|
// asure content is set even if message contains html part only
|
||||||
|
if ((returnMessage.getContent() == null) && (returnMessage.getHtmlContent() != null)) {
|
||||||
|
returnMessage.setContent(returnMessage.getHtmlContent(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((returnMessage.getContent() == null) && (returnMessage.getHtmlContent() == null)) {
|
||||||
|
throw new MailMessageException("Neither plain/text nor text/html content found. Unsupported message format");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailMessageException("Error while converting multipart mime message. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
} else if (contentType.equals(CONTENTTYPE_TEXT_PLAIN)) {
|
||||||
|
// plain/text mimmessage
|
||||||
|
try {
|
||||||
|
returnMessage = new MailMessage(subject, mm.getContent().toString(), messageId);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailMessageException("Error while converting plain/text mime message. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (contentType.equals(CONTENTTYPE_TEXT_HTML)) {
|
||||||
|
// plain/text mimmessage
|
||||||
|
try {
|
||||||
|
String contentString = mm.getContent().toString();
|
||||||
|
returnMessage = new MailMessage(subject, null, messageId);
|
||||||
|
returnMessage.setContent(contentString, true);
|
||||||
|
// returnMessage.setContent(mm.getContent().toString(), false);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailMessageException("Error while converting plain/text mime message. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
} else if (contentType.contains(CONTENTTYPE_MESSAGE)) {
|
||||||
|
try {
|
||||||
|
Message nestedMessage = (Message) mm.getContent();
|
||||||
|
returnMessage = getInstance(nestedMessage);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailMessageException("Error while converting nested message. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
} else if (contentType.contains(CONTENTTYPE_APPLICATION)) {
|
||||||
|
// message with only attachment
|
||||||
|
returnMessage = new MailMessage(subject, "", messageId);
|
||||||
|
logger.debug("Found attachment - not yet supported, skipping"); // TODO add attachment
|
||||||
|
} else if (contentType.contains(CONTENTTYPE_TEXT)) {
|
||||||
|
returnMessage = new MailMessage(subject, "", messageId);
|
||||||
|
logger.debug("Found attachment - not yet supported, skipping"); // TODO add attachment
|
||||||
|
} else {
|
||||||
|
String hint = "Unkonwn message format Converting MimeMessage of contentType " + contentType + " not yet implemented.";
|
||||||
|
|
||||||
|
try {
|
||||||
|
logger.debug(mm.getContent().getClass());
|
||||||
|
logger.debug(mm.getContent());
|
||||||
|
logger.error(hint);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error(hint);
|
||||||
|
}
|
||||||
|
throw new MailMessageException(hint);
|
||||||
|
}
|
||||||
|
} else if (message instanceof Message) {
|
||||||
|
try {
|
||||||
|
String content = message.getContent().toString();
|
||||||
|
String subject = message.getSubject();
|
||||||
|
returnMessage = new MailMessage(subject, content);
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailMessageException("Error whilec converting email. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new MailMessageException("Unsupported messagetype " + message.getClass().toString() + ". Cannot create message");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO add missing parameters
|
||||||
|
// messageid
|
||||||
|
try {
|
||||||
|
returnMessage.addReceiver(message.getRecipients(Message.RecipientType.TO));
|
||||||
|
returnMessage.addCcReceiver(message.getRecipients(Message.RecipientType.CC));
|
||||||
|
returnMessage.addBccReceiver(message.getRecipients(Message.RecipientType.BCC));
|
||||||
|
|
||||||
|
returnMessage.setSender(message.getFrom());
|
||||||
|
returnMessage.setSentDate(message.getSentDate());
|
||||||
|
returnMessage.setSize(message.getSize());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailMessageException("Cannot read email. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
return returnMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the content type based on the content-type header. The messad asures the contentype
|
||||||
|
* is selected correctly from the string, including trim and tolower case
|
||||||
|
* @param contentType the contenttype string read from email header
|
||||||
|
* @return the content type of the email (small letters)
|
||||||
|
*/
|
||||||
|
private static String getContentType(String contentType) {
|
||||||
|
|
||||||
|
if (contentType.contains(";")) {
|
||||||
|
contentType = contentType.substring(0, contentType.indexOf(';'));
|
||||||
|
}
|
||||||
|
contentType = contentType.toLowerCase();
|
||||||
|
contentType = contentType.trim();
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the content of the given bodypart which needs to be a text based bodypart
|
||||||
|
* The method tries to read the messages as it is. In case of an unsupported encoding it reads the message with
|
||||||
|
* the default encoding (accepting "ugly" characters)
|
||||||
|
* @param bp the body part to read the content from
|
||||||
|
* @return the content of the body part
|
||||||
|
* @throws IOException if the content cannot be read
|
||||||
|
* @throws MessagingException if the message cannot be processed
|
||||||
|
*/
|
||||||
|
private static String getContent(BodyPart bp) throws IOException, MessagingException {
|
||||||
|
|
||||||
|
String returnValue = null;
|
||||||
|
try {
|
||||||
|
returnValue = bp.getContent().toString();
|
||||||
|
} catch (java.io.UnsupportedEncodingException ex) {
|
||||||
|
logger.debug(ex.getMessage());
|
||||||
|
} catch (java.io.IOException ioex) {
|
||||||
|
throw new IOException("Cannot read content from bodypart.", ioex);
|
||||||
|
} catch (MessagingException mex) {
|
||||||
|
throw new MessagingException("Cannot read content from bodypart.", mex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnValue == null) {
|
||||||
|
return getContentByStream(bp, "UTF-8"); // TODO make configurable
|
||||||
|
} else {
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the content of the given body part by reading the stream directly. This ommits getting unsupported encoding exceptions, as the content
|
||||||
|
* is read with the given encoding
|
||||||
|
* @param bp the bodypart to read the content from
|
||||||
|
* @param encoding the encoding to force
|
||||||
|
* @return the content string read with the given encoding
|
||||||
|
* @throws IOException if the content cannot be read
|
||||||
|
* @throws MessagingException if the message cannot be processed
|
||||||
|
*/
|
||||||
|
private static String getContentByStream(BodyPart bp, String encoding) throws IOException, MessagingException {
|
||||||
|
String returnValue;
|
||||||
|
Reader input = null;
|
||||||
|
StringWriter output = null;
|
||||||
|
try {
|
||||||
|
input = new BufferedReader(new InputStreamReader(bp.getInputStream(), encoding));
|
||||||
|
output = new StringWriter();
|
||||||
|
char[] b = new char[4096];
|
||||||
|
while (input.read(b) != -1) {
|
||||||
|
output.write(b);
|
||||||
|
}
|
||||||
|
returnValue = output.toString();
|
||||||
|
} catch (IOException ioex) {
|
||||||
|
throw new IOException("Cannot read content from bodypart by reading content stream.", ioex);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
output.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.debug(ex.getMessage());
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
input.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.debug(ex.getMessage());
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the message id from the header of the given message
|
||||||
|
* @param message the message to return the message id from
|
||||||
|
* @return either the message id or null if the message id cannot be read
|
||||||
|
* @throws MessagingException if the message cannot be processed
|
||||||
|
*/
|
||||||
|
private static String getMessageId(Message message) throws MessagingException {
|
||||||
|
String[] messageHeaders = message.getHeader("Message-Id");
|
||||||
|
if ((messageHeaders != null) && (messageHeaders.length > 0)) {
|
||||||
|
return messageHeaders[0];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.network.mail;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.mail.Folder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public interface MailReader {
|
||||||
|
|
||||||
|
/** connects to the mailbox
|
||||||
|
*
|
||||||
|
* @throws MailReaderConnectionException if he connection cannot be established
|
||||||
|
*/
|
||||||
|
void connect() throws MailReaderConnectionException;
|
||||||
|
|
||||||
|
/** disconnects from mailbox */
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
/** returns the default folder
|
||||||
|
*
|
||||||
|
* @return the default folder
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the folder cannot be retrieved
|
||||||
|
*/
|
||||||
|
String getDefaultFolder() throws MailReaderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the list of subfolders of the specified source folder
|
||||||
|
*
|
||||||
|
* @param sourceFolder the folder to return the folder list for
|
||||||
|
* @return the list of subfolders of the specified source folder
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the folder list cannot be retrieved
|
||||||
|
*/
|
||||||
|
List<String> getSubFolder(String sourceFolder) throws MailReaderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the folder, if folder path is a valid path to an existing folder
|
||||||
|
*
|
||||||
|
* @param folderPath the folder to return
|
||||||
|
* @return the folder, if folder path is a valid path to an existing folder
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the folder cannot be found
|
||||||
|
*/
|
||||||
|
String getFolder(String folderPath) throws MailReaderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the amount of message in the given folder
|
||||||
|
*
|
||||||
|
* @param holdFolder the folder to return the amount of messages for
|
||||||
|
* @return the amount of message in the given folder
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the folder cannot be accessed or the amount of messages cannot be determined
|
||||||
|
*/
|
||||||
|
int getMessageCount(String holdFolder) throws MailReaderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retrieves the list of messages stored in the given folder
|
||||||
|
*
|
||||||
|
* @param folder the folder to search return the emails for
|
||||||
|
* @return list of messages stored in the given folder
|
||||||
|
*
|
||||||
|
* @throws MailReaderException if the message list cannot be retrieved
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
List<MailMessage> getMessages(String folder) throws MailReaderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copies the given message from the source folder to the destination folder
|
||||||
|
*
|
||||||
|
* @param mm the message to copy
|
||||||
|
* @param sourceFolder the folder the message currently resists in
|
||||||
|
* @param destFolder the folder the message should be copied to
|
||||||
|
* @throws MailReaderException if the operation fails
|
||||||
|
*/
|
||||||
|
void copyMessage(MailMessage mm, String sourceFolder, String destFolder) throws MailReaderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* moves the given message from the source folder to the destination folder
|
||||||
|
*
|
||||||
|
* @param mm the message to move
|
||||||
|
* @param sourceFolder the folder the message currently resists in
|
||||||
|
* @param destFolder the folder the message should be moved to
|
||||||
|
* @throws MailReaderException if the operation fails
|
||||||
|
*/
|
||||||
|
void moveMessage(MailMessage mm, String sourceFolder, String destFolder) throws MailReaderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* marks the messages as seen
|
||||||
|
*
|
||||||
|
* @param folder the folder to search for the email
|
||||||
|
* @param mm the message to mark as seen
|
||||||
|
* @param flagValue if set to true, the seen flag is set; otherwise it is removed (unset)
|
||||||
|
* @throws MailReaderException if the flag cannot be set
|
||||||
|
*/
|
||||||
|
void setSeenFlag(String folder, MailMessage mm, boolean flagValue) throws MailReaderException;
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
package de.muehlencord.shared.network.mail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Joern Muehlencord
|
||||||
|
*/
|
||||||
|
public class MailReaderConfiguration {
|
||||||
|
/** server for smtp sessions */
|
||||||
|
private String smtpHost = null;
|
||||||
|
/** server for incoming emails - e.g. the imap or pop3 server */
|
||||||
|
private String readerHost = null;
|
||||||
|
/** the username to connect with */
|
||||||
|
private String userName = null;
|
||||||
|
/** the password to connect with */
|
||||||
|
private String password = null;
|
||||||
|
|
||||||
|
// TODO add checkConfig to asure the config is valid for the reader it is attached to
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new config
|
||||||
|
* @param mailHost the smtp host to connect to
|
||||||
|
* @param host the mailreader host (imap, exchange, pop, ...) to connect to
|
||||||
|
* @param user the username to connect with
|
||||||
|
* @param pw the password to connect with
|
||||||
|
*/
|
||||||
|
public MailReaderConfiguration (String mailHost, String host, String user, String pw) {
|
||||||
|
this.smtpHost = mailHost;
|
||||||
|
this.readerHost = host;
|
||||||
|
this.userName = user;
|
||||||
|
this.password = pw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the smtpHost
|
||||||
|
*/
|
||||||
|
public String getSmtpHost() {
|
||||||
|
return smtpHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the readerHost
|
||||||
|
*/
|
||||||
|
public String getReaderHost() {
|
||||||
|
return readerHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the userName
|
||||||
|
*/
|
||||||
|
public String getUserName() {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the password
|
||||||
|
*/
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
package de.muehlencord.shared.network.mail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class MailReaderConfigurationException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 3874572911465653501L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of
|
||||||
|
* <code>MailReaderConfigurationException</code> without detail message.
|
||||||
|
*/
|
||||||
|
public MailReaderConfigurationException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>MailReaderConfigurationException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public MailReaderConfigurationException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>MailReaderConfigurationException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
* @param th the causing exception
|
||||||
|
*/
|
||||||
|
public MailReaderConfigurationException(String msg, Throwable th) {
|
||||||
|
super(msg, th);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
package de.muehlencord.shared.network.mail;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.util.StringUtil;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Properties;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public abstract class MailReaderConfigurationFactory {
|
||||||
|
|
||||||
|
/** the logging object */
|
||||||
|
private final static Logger logger = Logger.getLogger(MailReaderConfigurationFactory.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reads the config file and creates a configured mailreader configuration
|
||||||
|
*
|
||||||
|
* @param configFile the file to read
|
||||||
|
* @return the configured MailReaderConfiguration object
|
||||||
|
*
|
||||||
|
* @throws MailReaderConfigurationException if the file does not exist or the config cannot be created
|
||||||
|
*/
|
||||||
|
public static MailReaderConfiguration getConfiguration(String configFile) throws MailReaderConfigurationException {
|
||||||
|
File f = new File(configFile);
|
||||||
|
if (!f.exists()) {
|
||||||
|
throw new MailReaderConfigurationException("Cannot find configfile " + configFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
Properties p = new Properties();
|
||||||
|
InputStream is = null;
|
||||||
|
try {
|
||||||
|
is = new FileInputStream(f);
|
||||||
|
p.load(is);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MailReaderConfigurationException("Error while reading config file. Reason: " + ex.getMessage(), ex);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error("Error while reading input file.");
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String smtpServer = p.getProperty("smtp.server");
|
||||||
|
if ((smtpServer == null) || (smtpServer.isEmpty())) {
|
||||||
|
throw new MailReaderConfigurationException("property smtp.server not specified. Please check config");
|
||||||
|
}
|
||||||
|
String host = p.getProperty("imap.server");
|
||||||
|
if ((smtpServer == null) || (smtpServer.isEmpty())) {
|
||||||
|
throw new MailReaderConfigurationException("property imap.server not specified. Please check config");
|
||||||
|
}
|
||||||
|
String userName = p.getProperty("imap.username");
|
||||||
|
if ((smtpServer == null) || (smtpServer.isEmpty())) {
|
||||||
|
throw new MailReaderConfigurationException("property imap.username not specified. Please check config");
|
||||||
|
}
|
||||||
|
String password = p.getProperty("imap.password");
|
||||||
|
if ((smtpServer == null) || (smtpServer.isEmpty())) {
|
||||||
|
throw new MailReaderConfigurationException("property imap.password not specified. Please check config");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MailReaderConfiguration(smtpServer, host, userName, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.network.mail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class MailReaderConnectionException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -1593741665654202661L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of
|
||||||
|
* <code>MailReaderConnectionException</code> without detail message.
|
||||||
|
*/
|
||||||
|
public MailReaderConnectionException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>MailReaderConnectionException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public MailReaderConnectionException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>MailReaderConnectionException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
* @param th the causing error
|
||||||
|
*/
|
||||||
|
public MailReaderConnectionException(String msg, Throwable th) {
|
||||||
|
super(msg, th);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.network.mail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class MailReaderException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 4850689622364462635L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of
|
||||||
|
* <code>MailReaderException</code> without detail message.
|
||||||
|
*/
|
||||||
|
public MailReaderException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>MailReaderException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public MailReaderException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>MailReaderException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
* @param th the causing exception
|
||||||
|
*/
|
||||||
|
public MailReaderException(String msg, Throwable th) {
|
||||||
|
super(msg, th);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package de.muehlencord.shared.network.mail.imap;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.network.mail.DefaultMailReader;
|
||||||
|
import de.muehlencord.shared.network.mail.MailReaderConfiguration;
|
||||||
|
import de.muehlencord.shared.network.mail.MailReaderConnectionException;
|
||||||
|
import javax.mail.Session;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of MaiLReader to connect to an IMAP server
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class ImapMailReader extends DefaultMailReader {
|
||||||
|
|
||||||
|
/** the logger object */
|
||||||
|
private final static Logger logger = Logger.getLogger(ImapMailReader.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new instance to connect to an IMAP (or MS Exchange) server
|
||||||
|
*
|
||||||
|
* @param config the configuration of the mail reader
|
||||||
|
*/
|
||||||
|
public ImapMailReader(MailReaderConfiguration config) {
|
||||||
|
super(config);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect() throws MailReaderConnectionException {
|
||||||
|
Session session = getDefaultSession();
|
||||||
|
String hostName = getConfiguration().getReaderHost();
|
||||||
|
String userName = getConfiguration().getUserName();
|
||||||
|
String password = getConfiguration().getPassword();
|
||||||
|
try {
|
||||||
|
setStore(session.getStore("imap")); // TODO add ssl support
|
||||||
|
getStore().connect(hostName, userName, password);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
String hint = "Error while connecting to mailbox " + getConnectionShortCut();
|
||||||
|
hint += ". Reason: " + ex.getMessage();
|
||||||
|
throw new MailReaderConnectionException(hint, ex);
|
||||||
|
}
|
||||||
|
logger.info("Connected to " + getConnectionShortCut());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns userName@hostname
|
||||||
|
*
|
||||||
|
* @return userName@hostname
|
||||||
|
*/
|
||||||
|
private String getConnectionShortCut() {
|
||||||
|
return getConfiguration().getUserName() + "@" + getConfiguration().getReaderHost();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package de.muehlencord.shared.network;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import org.apache.log4j.PropertyConfigurator;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class BaseTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inits logging according to default setup in package
|
||||||
|
*/
|
||||||
|
@BeforeClass
|
||||||
|
public static void initLogging() {
|
||||||
|
URL defaultConfigUrl = BaseTest.class.getResource("/logging.properties");
|
||||||
|
PropertyConfigurator.configure(defaultConfigUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.network.ftp;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class FTPConnectionTest {
|
||||||
|
|
||||||
|
/** the properties loaded from the config file */
|
||||||
|
Properties props = null;
|
||||||
|
/** true, if init is complete to execute test */
|
||||||
|
boolean initDone = false;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void initClass() {
|
||||||
|
System.out.println("\n[FTPConnectionTest]");
|
||||||
|
URL testConfigURL = FTPConnectionTest.class.getResource("/test.properties");
|
||||||
|
FileInputStream fin = null;
|
||||||
|
try {
|
||||||
|
File file = new File(testConfigURL.toURI());
|
||||||
|
props = new Properties();
|
||||||
|
if ((file == null) || (!file.exists())) {
|
||||||
|
initDone = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fin = new FileInputStream(file);
|
||||||
|
props.load(fin);
|
||||||
|
}
|
||||||
|
if ((props.containsKey("ftp.host")) && (props.containsKey("ftp.user")) && (props.containsKey("ftp.password")) && (props.containsKey("ftp.locale"))) {
|
||||||
|
initDone = true;
|
||||||
|
} else {
|
||||||
|
initDone = false;
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
initDone = false;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (fin != null) {
|
||||||
|
fin.close();
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(FTPConnectionTest.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tests connect / disconnect */
|
||||||
|
@Test
|
||||||
|
public void testConnectAndDisconnect() throws FTPConnectionException {
|
||||||
|
System.out.println("testConnectAndDisconnect");
|
||||||
|
if (initDone) {
|
||||||
|
String remoteHost = props.getProperty("ftp.host");
|
||||||
|
String user = props.getProperty("ftp.user");
|
||||||
|
String password = props.getProperty("ftp.password");
|
||||||
|
Locale locale = new Locale(props.getProperty("ftp.locale"));
|
||||||
|
|
||||||
|
FTPConnection con = new FTPConnection(remoteHost, user, password, locale);
|
||||||
|
con.connect();
|
||||||
|
con.disconnect();
|
||||||
|
System.out.println("executed successfully");
|
||||||
|
} else {
|
||||||
|
System.out.println("Skipped because config is not complete");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testList() throws FTPConnectionException {
|
||||||
|
System.out.println("list");
|
||||||
|
String dir = "";
|
||||||
|
FTPConnection instance = null;
|
||||||
|
List expResult = null;
|
||||||
|
List result = instance.list(dir);
|
||||||
|
assertEquals(expResult, result);
|
||||||
|
fail("The test case is a prototype.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testListDirsOnly() throws FTPConnectionException {
|
||||||
|
System.out.println("listDirsOnly");
|
||||||
|
String dir = "";
|
||||||
|
FTPConnection instance = null;
|
||||||
|
List expResult = null;
|
||||||
|
List result = instance.listDirsOnly(dir);
|
||||||
|
assertEquals(expResult, result);
|
||||||
|
fail("The test case is a prototype.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testListFilesOnly() throws FTPConnectionException {
|
||||||
|
System.out.println("listFilesOnly");
|
||||||
|
String dir = "";
|
||||||
|
FTPConnection instance = null;
|
||||||
|
List expResult = null;
|
||||||
|
List result = instance.listFilesOnly(dir);
|
||||||
|
assertEquals(expResult, result);
|
||||||
|
fail("The test case is a prototype.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testListLinksOnly() throws FTPConnectionException {
|
||||||
|
System.out.println("listLinksOnly");
|
||||||
|
String dir = "";
|
||||||
|
FTPConnection instance = null;
|
||||||
|
List expResult = null;
|
||||||
|
List result = instance.listLinksOnly(dir);
|
||||||
|
assertEquals(expResult, result);
|
||||||
|
fail("The test case is a prototype.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testUploadFile() throws FTPConnectionException {
|
||||||
|
System.out.println("uploadFile");
|
||||||
|
String localFilename = "";
|
||||||
|
String remoteFileName = "";
|
||||||
|
FTPConnection instance = null;
|
||||||
|
instance.uploadFile(localFilename, remoteFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testRename() throws FTPConnectionException {
|
||||||
|
System.out.println("rename");
|
||||||
|
String remoteOldName = "";
|
||||||
|
String remoteNewName = "";
|
||||||
|
FTPConnection instance = null;
|
||||||
|
instance.rename(remoteOldName, remoteNewName);
|
||||||
|
fail("The test case is a prototype.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.network.http;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.network.BaseTest;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class HttpLayerTest extends BaseTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testPostByMap() throws Exception {
|
||||||
|
System.out.println("testPostByMap");
|
||||||
|
Map<String, String[]> map = new HashMap<String, String[]>();
|
||||||
|
String[] value = {"Hello World!", "Hello World again"};
|
||||||
|
map.put("message", value);
|
||||||
|
|
||||||
|
HttpLayer httpLayer = new HttpLayer(
|
||||||
|
"http://localhost:8080/HttpPostListener/HttpPostListener");
|
||||||
|
httpLayer.post(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testPostByMapList() throws Exception {
|
||||||
|
System.out.println("testPostByMapList");
|
||||||
|
List<Map<String, String[]>> list = new LinkedList<Map<String, String[]>>();
|
||||||
|
Map<String, String[]> map = new HashMap<String, String[]>();
|
||||||
|
String[] value = {"Hello World!", "Hello World again"};
|
||||||
|
map.put("message", value);
|
||||||
|
list.add(map);
|
||||||
|
map = new HashMap<String, String[]>();
|
||||||
|
String[] urlValue = {"http://localhost:8080/testurl"};
|
||||||
|
map.put("url", urlValue);
|
||||||
|
list.add(map);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
HttpLayer httpLayer = new HttpLayer("http://localhost:8080/HttpPostListener/HttpPostListener");
|
||||||
|
httpLayer.post(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testByValue() throws Exception {
|
||||||
|
System.out.println("testByValue");
|
||||||
|
HttpLayer httpLayer = new HttpLayer(
|
||||||
|
"http://localhost:8080/HttpPostListener/HttpPostListener");
|
||||||
|
httpLayer.post("message", "Hello World by single parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = MessageNotSendException.class)
|
||||||
|
public void testWithUnknownURL() throws MessageNotSendException {
|
||||||
|
System.out.println("testWithUnknownURL");
|
||||||
|
HttpLayer httpLayer = new HttpLayer(
|
||||||
|
"http://localhost/thisURLDoesNotExist");
|
||||||
|
httpLayer.post("message", "Hello World by single parameter");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = MessageNotSendException.class)
|
||||||
|
public void testInvalidURL() throws MessageNotSendException {
|
||||||
|
System.out.println("testInvalidURL");
|
||||||
|
HttpLayer httpLayer = new HttpLayer("joern@muehlencord.de");
|
||||||
|
httpLayer.post("message", "Hello World by single parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = MessageNotSendException.class)
|
||||||
|
public void testUnsupportedURL() throws MessageNotSendException {
|
||||||
|
System.out.println("testUnsupportedURL");
|
||||||
|
HttpLayer httpLayer = new HttpLayer("ftp://localhost");
|
||||||
|
httpLayer.post("message", "Hello World by single parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package de.muehlencord.shared.network.mail;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.network.BaseTest;
|
||||||
|
import de.muehlencord.shared.network.mail.imap.ImapMailReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.List;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class MailMessageUtilsTest extends BaseTest {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
System.out.println ("\n[MailMessageUtilsTest]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetInstance() throws Exception {
|
||||||
|
System.out.println("testGetInstance");
|
||||||
|
URL testConfigURL = MailMessageUtilsTest.class.getResource("/test.properties");
|
||||||
|
File file = new File(testConfigURL.toURI());
|
||||||
|
|
||||||
|
if ((file == null) || (!file.exists())) {
|
||||||
|
return; // Skip test if config file is not available
|
||||||
|
}
|
||||||
|
|
||||||
|
String testConfigFile = file.toString();
|
||||||
|
MailReaderConfiguration config = MailReaderConfigurationFactory.getConfiguration(testConfigFile);
|
||||||
|
MailReader mr = new ImapMailReader(config);
|
||||||
|
mr.connect();
|
||||||
|
List<MailMessage> mm = mr.getMessages("INBOX");
|
||||||
|
mr.disconnect();
|
||||||
|
assertNotNull(mm);
|
||||||
|
assertTrue(mm.size() > 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.network.mail.imap;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.network.BaseTest;
|
||||||
|
import de.muehlencord.shared.network.mail.MailReader;
|
||||||
|
import de.muehlencord.shared.network.mail.MailReaderConfiguration;
|
||||||
|
import de.muehlencord.shared.network.mail.MailReaderConnectionException;
|
||||||
|
import de.muehlencord.shared.network.mail.MailReaderException;
|
||||||
|
import java.util.List;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class ImapMailReaderTest extends BaseTest {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tests the connection of the configured mailbox
|
||||||
|
*
|
||||||
|
* @throws Exception if the tests fails
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testConnect() throws Exception {
|
||||||
|
System.out.println("connect");
|
||||||
|
String meta = "meta.muehlencord.intra";
|
||||||
|
MailReaderConfiguration config = new MailReaderConfiguration(meta, meta, "jomutest", "jomutest");
|
||||||
|
MailReader instance = new ImapMailReader(config);
|
||||||
|
|
||||||
|
instance.connect();
|
||||||
|
instance.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFolder() throws Exception {
|
||||||
|
System.out.println("getFolder");
|
||||||
|
String meta = "meta.muehlencord.intra";
|
||||||
|
MailReaderConfiguration config = new MailReaderConfiguration(meta, meta, "jomutest", "jomutest");
|
||||||
|
MailReader instance = new ImapMailReader(config);
|
||||||
|
instance.connect();
|
||||||
|
String testFolder = "INBOX/test/test1";
|
||||||
|
String foundFolder = instance.getFolder(testFolder);
|
||||||
|
assertEquals(testFolder, foundFolder);
|
||||||
|
instance.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetMessageCount() throws MailReaderConnectionException, MailReaderException {
|
||||||
|
System.out.println("testGetMessageCount");
|
||||||
|
String meta = "meta.muehlencord.intra";
|
||||||
|
MailReaderConfiguration config = new MailReaderConfiguration(meta, meta, "jomutest", "jomutest");
|
||||||
|
MailReader instance = new ImapMailReader(config);
|
||||||
|
instance.connect();
|
||||||
|
int value = instance.getMessageCount("INBOX/test/test1");
|
||||||
|
assertEquals(3, value);
|
||||||
|
instance.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSubFolder() throws MailReaderConnectionException, MailReaderException {
|
||||||
|
System.out.println("getSubFolder");
|
||||||
|
String meta = "meta.muehlencord.intra";
|
||||||
|
MailReaderConfiguration config = new MailReaderConfiguration(meta, meta, "jomutest", "jomutest");
|
||||||
|
MailReader instance = new ImapMailReader(config);
|
||||||
|
instance.connect();
|
||||||
|
List<String> subFolders = instance.getSubFolder("INBOX/test");
|
||||||
|
assertEquals(2, subFolders.size());
|
||||||
|
System.out.println(subFolders.toString());
|
||||||
|
assertTrue(subFolders.contains("INBOX.test.test1"));
|
||||||
|
assertTrue(subFolders.contains("INBOX.test.test2"));
|
||||||
|
instance.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
8
network/src/test/resources/logging.properties
Normal file
8
network/src/test/resources/logging.properties
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
log4j.rootLogger=ALL, ConsoleLogger
|
||||||
|
log4j.debug=false
|
||||||
|
|
||||||
|
# ConsoleAppender
|
||||||
|
log4j.appender.ConsoleLogger=org.apache.log4j.ConsoleAppender
|
||||||
|
log4j.appender.ConsoleLogger.layout=org.apache.log4j.PatternLayout
|
||||||
|
log4j.appender.ConsoleLogger.layout.ConversionPattern= %d - %m (%c)%n
|
||||||
|
log4j.appender.ConsoleLogger.threshold=INFO
|
||||||
13
network/src/test/resources/test.properties
Normal file
13
network/src/test/resources/test.properties
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
## connection to smtp server
|
||||||
|
smtp.server=meta.muehlencord.intra
|
||||||
|
|
||||||
|
## connection to imap server
|
||||||
|
imap.server=meta.muehlencord.intra
|
||||||
|
imap.username=jomutest
|
||||||
|
imap.password=jomutest
|
||||||
|
|
||||||
|
## ftp connection data
|
||||||
|
#ftp.host=
|
||||||
|
#ftp.user=
|
||||||
|
#ftp.password=
|
||||||
|
ftp.locale=en_EN
|
||||||
15
network/src/test/resources/testprod.properties
Normal file
15
network/src/test/resources/testprod.properties
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
## connection to smtp server
|
||||||
|
smtp.server=meta.muehlencord.intra
|
||||||
|
|
||||||
|
## connection to imap server
|
||||||
|
imap.server=meta.muehlencord.intra
|
||||||
|
#imap.username=jomutest
|
||||||
|
#imap.password=jomutest
|
||||||
|
imap.username=jomu
|
||||||
|
imap.password=fR4vbHuL
|
||||||
|
|
||||||
|
## ftp connection data
|
||||||
|
ftp.host=ftp.bytecamp.net
|
||||||
|
ftp.user=asverked
|
||||||
|
ftp.password=76z0fs9Bsx
|
||||||
|
ftp.locale=en_EN
|
||||||
16
pom.xml
Normal file
16
pom.xml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<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>de.muehlencord</groupId>
|
||||||
|
<artifactId>shared</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<name>shared</name>
|
||||||
|
<modules>
|
||||||
|
<module>configuration</module>
|
||||||
|
<module>network</module>
|
||||||
|
<module>security</module>
|
||||||
|
<module>util</module>
|
||||||
|
<module>jeeutil</module>
|
||||||
|
</modules>
|
||||||
|
</project>
|
||||||
6
security/.settings/org.eclipse.core.resources.prefs
Normal file
6
security/.settings/org.eclipse.core.resources.prefs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#Thu Jul 05 02:27:50 CEST 2012
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding//src/main/java=UTF-8
|
||||||
|
encoding//src/main/resources=UTF-8
|
||||||
|
encoding//src/test/java=UTF-8
|
||||||
|
encoding/<project>=UTF-8
|
||||||
6
security/.settings/org.eclipse.jdt.core.prefs
Normal file
6
security/.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#Thu Jul 05 02:27:50 CEST 2012
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.5
|
||||||
5
security/.settings/org.eclipse.m2e.core.prefs
Normal file
5
security/.settings/org.eclipse.m2e.core.prefs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#Thu Jul 05 02:27:48 CEST 2012
|
||||||
|
activeProfiles=
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
resolveWorkspaceProjects=true
|
||||||
|
version=1
|
||||||
40
security/pom.xml
Normal file
40
security/pom.xml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<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>de.muehlencord.shared</groupId>
|
||||||
|
<artifactId>shared-security</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<name>shared-security</name>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>shared</artifactId>
|
||||||
|
<groupId>de.muehlencord</groupId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<url>http://maven.apache.org</url>
|
||||||
|
<ciManagement>
|
||||||
|
<system>hudson</system>
|
||||||
|
<url>http://sunrise.muehlencord.intra:8088/jenkins/job/shared-security/</url>
|
||||||
|
</ciManagement>
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.10</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-codec</groupId>
|
||||||
|
<artifactId>commons-codec</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
<type>jar</type>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.security;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public abstract class PasswordUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns password (pos 0) and the salt (pos 1) of given plaintext password. Both strings are base64 encoded
|
||||||
|
*
|
||||||
|
* @param plainTextPassword he
|
||||||
|
* @param saltLength the length of the salt to use
|
||||||
|
* @return the password (pos 0) and the salt (pos 1) of given plaintext password. Both strings are base64 encoded
|
||||||
|
*
|
||||||
|
* @throws de.muehlencord.shared.security.SecurityException if any error occurs during the password generation
|
||||||
|
*/
|
||||||
|
public static String[] getMD5Password(final String plainTextPassword, final int saltLength) throws SecurityException {
|
||||||
|
byte[] unHashedPassword = getBase64MD5HashedPassword(plainTextPassword);
|
||||||
|
byte[] salt = createSalt(saltLength);
|
||||||
|
byte[] hashedPassword = hashPasswordWithSalt(unHashedPassword, salt);
|
||||||
|
|
||||||
|
// test
|
||||||
|
String saltStr = base64Encode(salt);
|
||||||
|
byte[] salt2 = base64Decode(saltStr);
|
||||||
|
if (!Arrays.equals(salt, salt2)) {
|
||||||
|
throw new SecurityException("Salt conversion failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String[] returnValue = new String[2];
|
||||||
|
returnValue[0] = base64Encode(hashedPassword);
|
||||||
|
returnValue[1] = base64Encode(salt);
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given password (plain text) matches the given crypted password. The crypted password is hashed with the given salt. Both strings, crypted
|
||||||
|
* password and salt, have to be base64 encoded
|
||||||
|
*
|
||||||
|
* @param plainTextPassword the plaintext password to compare to
|
||||||
|
* @param cryptedPasswordStr the crypted password to compare to
|
||||||
|
* @param saltStr the salt needed to hash the plaintext password with to get the correct crypted password if both passwords match
|
||||||
|
* @return true, if and only if the encryption of plainTextPassword (hashed with saltStr) equals to cryptedPasswordStr
|
||||||
|
*
|
||||||
|
* @throws de.muehlencord.shared.security.SecurityException if any error occures during the check
|
||||||
|
*/
|
||||||
|
public static boolean checkPassword(String plainTextPassword, String cryptedPasswordStr, String saltStr) throws SecurityException {
|
||||||
|
byte[] salt = base64Decode(saltStr);
|
||||||
|
byte[] newPassword = getBase64MD5HashedPassword(plainTextPassword);
|
||||||
|
byte[] newHashedPassword = hashPasswordWithSalt(newPassword, salt);
|
||||||
|
byte[] crytepdPassword = base64Decode(cryptedPasswordStr);
|
||||||
|
return Arrays.equals(crytepdPassword, newHashedPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a new salt as a string
|
||||||
|
*
|
||||||
|
* @param saltLength the length of the salt
|
||||||
|
* @return a new salt as a string (base64 encoded)
|
||||||
|
*
|
||||||
|
* @throws SecurityException if the creation of the salt fails
|
||||||
|
*/
|
||||||
|
public static String createSaltString(int saltLength) throws SecurityException {
|
||||||
|
byte[] salt = createSalt(saltLength);
|
||||||
|
return base64Encode(salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* *** private methods *** */
|
||||||
|
/**
|
||||||
|
* creates a salt and returns the value as byte[]
|
||||||
|
*
|
||||||
|
* @param saltLength the length the salt string should have
|
||||||
|
* @return the generated salt as byte[]
|
||||||
|
*
|
||||||
|
* @throws SecurityException if the salt creation fails
|
||||||
|
*/
|
||||||
|
private static byte[] createSalt(int saltLength) throws SecurityException {
|
||||||
|
try {
|
||||||
|
SecureRandom sha1SecureRandom = SecureRandom.getInstance("SHA1PRNG");
|
||||||
|
byte salt[] = new byte[saltLength];
|
||||||
|
synchronized (sha1SecureRandom) {
|
||||||
|
sha1SecureRandom.nextBytes(salt);
|
||||||
|
}
|
||||||
|
return salt;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new SecurityException("Cannot created salt", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hashes the given password (md5 hashed, base64 coded) with the given salt
|
||||||
|
* @param text the text to salt
|
||||||
|
* @param salt the salt to use
|
||||||
|
* @return the input text salted with password
|
||||||
|
* @throws SecurityException
|
||||||
|
*/
|
||||||
|
private static byte[] hashPasswordWithSalt(byte text[], byte salt[]) throws SecurityException {
|
||||||
|
try {
|
||||||
|
MessageDigest sha1Algorithm = MessageDigest.getInstance("SHA-1");
|
||||||
|
byte[] digest;
|
||||||
|
synchronized (sha1Algorithm) {
|
||||||
|
sha1Algorithm.reset();
|
||||||
|
sha1Algorithm.update(salt);
|
||||||
|
digest = sha1Algorithm.digest(text);
|
||||||
|
}
|
||||||
|
return digest;
|
||||||
|
} catch (NoSuchAlgorithmException ex) {
|
||||||
|
throw new SecurityException("Cannot hash password with salt", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the given password as md5 without appliying salt
|
||||||
|
*
|
||||||
|
* @param plainTextPassword the password to convert
|
||||||
|
* @return the given password as md5 without appliying salt
|
||||||
|
*
|
||||||
|
* @throws SecurityException if the passwor cannot be converted
|
||||||
|
*/
|
||||||
|
private static byte[] getBase64MD5HashedPassword(final String plainTextPassword) throws SecurityException {
|
||||||
|
try {
|
||||||
|
MessageDigest algorithm = MessageDigest.getInstance("MD5");
|
||||||
|
algorithm.reset();
|
||||||
|
algorithm.update(plainTextPassword.getBytes());
|
||||||
|
byte[] messageDigest = algorithm.digest();
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
for (int i = 0; i < messageDigest.length; i++) {
|
||||||
|
int halfbyte = (messageDigest[i] >>> 4) & 0x0F;
|
||||||
|
int twoHalfs = 0;
|
||||||
|
do {
|
||||||
|
if ((0 <= halfbyte) && (halfbyte <= 9)) {
|
||||||
|
buf.append((char) ('0' + halfbyte));
|
||||||
|
} else {
|
||||||
|
buf.append((char) ('a' + (halfbyte - 10)));
|
||||||
|
}
|
||||||
|
halfbyte = messageDigest[i] & 0x0F;
|
||||||
|
} while (twoHalfs++ < 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// take password and hash with salt
|
||||||
|
byte[] unHashedPassword = base64Decode(buf.toString());
|
||||||
|
|
||||||
|
return unHashedPassword;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new SecurityException("Cannot created password", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the plain byte[] as base64 coded string
|
||||||
|
*
|
||||||
|
* @param data the data to convert
|
||||||
|
* @return the plain byte[] as base64 coded string
|
||||||
|
*/
|
||||||
|
private static String base64Encode(final byte[] data) {
|
||||||
|
Base64 encoder = new Base64();
|
||||||
|
byte[] result = encoder.encode(data);
|
||||||
|
return new String(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the given base64 coded string as decoded byte[]
|
||||||
|
*
|
||||||
|
* @param data the string to convert
|
||||||
|
* @return the given base64 coded string as decoded byte[]
|
||||||
|
*/
|
||||||
|
private static byte[] base64Decode(final String data) {
|
||||||
|
Base64 decoder = new Base64();
|
||||||
|
return decoder.decode(data.getBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.muehlencord.shared.security;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class SecurityException extends Exception {
|
||||||
|
|
||||||
|
public SecurityException() {
|
||||||
|
super ("An error occured during a security action");
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityException(String msg) {
|
||||||
|
super (msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityException(String msg, Throwable cause) {
|
||||||
|
super(msg, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityException(Throwable cause) {
|
||||||
|
super (cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.muehlencord.shared.security;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class PasswordUtilTest {
|
||||||
|
|
||||||
|
public PasswordUtilTest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpClass() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDownClass() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of createSaltString method, of class PasswordUtil.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void createSaltString() throws Exception {
|
||||||
|
System.out.println("createSaltString");
|
||||||
|
int saltLength = 40;
|
||||||
|
String result = PasswordUtil.createSaltString(saltLength);
|
||||||
|
assertNotNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of getMD5Password method, of class PasswordUtil.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void getMD5Password() throws Exception {
|
||||||
|
System.out.println("getMD5Password");
|
||||||
|
String plainTextPassword = "";
|
||||||
|
int saltLength = 40;
|
||||||
|
String[] result1 = PasswordUtil.getMD5Password(plainTextPassword, saltLength);
|
||||||
|
String password1 = result1[0];
|
||||||
|
String salt1 = result1[1];
|
||||||
|
assertNotNull(result1);
|
||||||
|
assertNotNull(password1);
|
||||||
|
assertNotNull(salt1);
|
||||||
|
|
||||||
|
String[] result2 = PasswordUtil.getMD5Password(plainTextPassword, saltLength);
|
||||||
|
String password2 = result2[0];
|
||||||
|
String salt2 = result2[1];
|
||||||
|
assertNotNull(result2);
|
||||||
|
assertNotNull(password2);
|
||||||
|
assertNotNull(salt2);
|
||||||
|
|
||||||
|
assertNotSame(result1, result2);
|
||||||
|
assertNotSame(password1, password2);
|
||||||
|
assertNotSame(salt1, salt2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of checkPassword method, of class PasswordUtil.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void checkPassword() throws Exception {
|
||||||
|
System.out.println("checkPassword");
|
||||||
|
String plainTextPassword = "welcome";
|
||||||
|
String plainTextPassword2 = "this is not the correct password";
|
||||||
|
|
||||||
|
String[] data = PasswordUtil.getMD5Password(plainTextPassword, 40);
|
||||||
|
String cryptedPassword = data[0];
|
||||||
|
String salt = data[1];
|
||||||
|
|
||||||
|
String salt2 = PasswordUtil.createSaltString(40);
|
||||||
|
String salt3 = PasswordUtil.createSaltString(10);
|
||||||
|
|
||||||
|
boolean expResult = true;
|
||||||
|
boolean result = PasswordUtil.checkPassword(plainTextPassword, cryptedPassword, salt);
|
||||||
|
assertEquals(expResult, result);
|
||||||
|
|
||||||
|
expResult = false;
|
||||||
|
result = PasswordUtil.checkPassword(plainTextPassword2, cryptedPassword, salt);
|
||||||
|
assertEquals(expResult, result);
|
||||||
|
|
||||||
|
expResult = false;
|
||||||
|
result = PasswordUtil.checkPassword(plainTextPassword, cryptedPassword, salt2);
|
||||||
|
assertEquals(expResult, result);
|
||||||
|
|
||||||
|
expResult = false;
|
||||||
|
result = PasswordUtil.checkPassword(plainTextPassword, cryptedPassword, salt3);
|
||||||
|
assertEquals(expResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
7
util/.settings/org.eclipse.core.resources.prefs
Normal file
7
util/.settings/org.eclipse.core.resources.prefs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#Thu Jul 05 02:27:50 CEST 2012
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding//src/main/java=UTF-8
|
||||||
|
encoding//src/main/resources=UTF-8
|
||||||
|
encoding//src/test/java=UTF-8
|
||||||
|
encoding//src/test/resources=UTF-8
|
||||||
|
encoding/<project>=UTF-8
|
||||||
6
util/.settings/org.eclipse.jdt.core.prefs
Normal file
6
util/.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#Thu Jul 05 02:27:50 CEST 2012
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.6
|
||||||
5
util/.settings/org.eclipse.m2e.core.prefs
Normal file
5
util/.settings/org.eclipse.m2e.core.prefs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#Thu Jul 05 02:27:48 CEST 2012
|
||||||
|
activeProfiles=
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
resolveWorkspaceProjects=true
|
||||||
|
version=1
|
||||||
18
util/nb-configuration.xml
Normal file
18
util/nb-configuration.xml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project-shared-configuration>
|
||||||
|
<!--
|
||||||
|
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||||
|
The configuration is intended to be shared among all the users of project and
|
||||||
|
therefore it is assumed to be part of version control checkout.
|
||||||
|
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||||
|
-->
|
||||||
|
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||||
|
<!--
|
||||||
|
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||||
|
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||||
|
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||||
|
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||||
|
-->
|
||||||
|
<netbeans.compile.on.save>all</netbeans.compile.on.save>
|
||||||
|
</properties>
|
||||||
|
</project-shared-configuration>
|
||||||
55
util/pom.xml
Normal file
55
util/pom.xml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
<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>de.muehlencord.shared</groupId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>shared</artifactId>
|
||||||
|
<groupId>de.muehlencord</groupId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
|
||||||
|
<url>http://maven.apache.org</url>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>2.3.2</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.10</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>log4j</groupId>
|
||||||
|
<artifactId>log4j</artifactId>
|
||||||
|
<version>1.2.17</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<name>shared-util</name>
|
||||||
|
<artifactId>shared-util</artifactId>
|
||||||
|
<ciManagement>
|
||||||
|
<system>hudson</system>
|
||||||
|
<url>http://sunrise.muehlencord.intra:8088/jenkins/job/shared-util/</url>
|
||||||
|
</ciManagement>
|
||||||
|
</project>
|
||||||
46
util/src/main/java/de/muehlencord/shared/util/OSUtil.java
Normal file
46
util/src/main/java/de/muehlencord/shared/util/OSUtil.java
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* OSUtil.java
|
||||||
|
*
|
||||||
|
* Created on 10. Dezember 2007, 16:50
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public abstract class OSUtil {
|
||||||
|
|
||||||
|
/** OS unknown */
|
||||||
|
public final static int OS_UNKNOWN = 0;
|
||||||
|
/** OS Linux */
|
||||||
|
public final static int OS_WINDOWS = 1;
|
||||||
|
/** OS Linux */
|
||||||
|
public final static int OS_LINUX = 2;
|
||||||
|
/** OS MacOS X */
|
||||||
|
public final static int OS_MACOS = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the operation system the current JVM is running on
|
||||||
|
*
|
||||||
|
* @return an OS_xxxx constants identifiying the operating system the current JVM is running on;
|
||||||
|
*/
|
||||||
|
public static int getOperationSystem() {
|
||||||
|
String osName = System.getProperties().getProperty("os.name");
|
||||||
|
if (osName != null) {
|
||||||
|
osName = osName.toUpperCase();
|
||||||
|
if (osName.contains("WINDOWS")) {
|
||||||
|
return OS_WINDOWS;
|
||||||
|
} else if (osName.contains("LINUX")) {
|
||||||
|
return OS_LINUX;
|
||||||
|
} else if (osName.contains("MAC")) {
|
||||||
|
return OS_MACOS;
|
||||||
|
} else {
|
||||||
|
return OS_UNKNOWN;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return OS_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class StringEncodingException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of
|
||||||
|
* <code>StringEncodingException</code> without detail message.
|
||||||
|
*/
|
||||||
|
public StringEncodingException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>StringEncodingException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public StringEncodingException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>StringEncodingException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
* @param th the causing exception
|
||||||
|
*/
|
||||||
|
public StringEncodingException(String msg, Throwable th) {
|
||||||
|
super(msg, th);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* StringUtil.java
|
||||||
|
*
|
||||||
|
* Created on 4. Mai 2007, 12:36
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.util;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public abstract class StringUtil {
|
||||||
|
|
||||||
|
/** the logging object */
|
||||||
|
private static final Logger logger = Logger.getLogger(StringUtil.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the given string in ISO-8859-1 encoding
|
||||||
|
*
|
||||||
|
* @param input the input string in UTF-8
|
||||||
|
* @return the converted string in
|
||||||
|
*
|
||||||
|
* @throws StringEncodingException if the string cannot be converted
|
||||||
|
*/
|
||||||
|
public static String getISOString(String input) throws StringEncodingException {
|
||||||
|
try {
|
||||||
|
byte[] b = input.getBytes("UTF-8");
|
||||||
|
return new String(b, "ISO-8859-1");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.debug(getStackTraceString(ex));
|
||||||
|
throw new StringEncodingException("Cannot convert string from UTF-8 to ISO-8859-1. Reason: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the stackstrace as one string
|
||||||
|
*
|
||||||
|
* @param ex the exception to return the string for
|
||||||
|
* @return the stackstrace as one string
|
||||||
|
*/
|
||||||
|
public static String getStackTraceString(Throwable ex) {
|
||||||
|
String logString = ex.toString() + "\n";
|
||||||
|
StackTraceElement[] stack = ex.getStackTrace();
|
||||||
|
for (int i = 0; i < stack.length; i++) {
|
||||||
|
logString += (stack[i].toString()) + "\n";
|
||||||
|
}
|
||||||
|
return logString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fills s with blanks if s < length
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
|
||||||
|
*
|
||||||
|
* @param length the needed length for this field
|
||||||
|
* @param s the field to extend with blanks
|
||||||
|
* @return s extended by trainling blanks. s.length == length
|
||||||
|
*/
|
||||||
|
public static String getBlankedString(int length, String s) {
|
||||||
|
if (s == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
String returnValue = s;
|
||||||
|
while (s.length() < length) {
|
||||||
|
returnValue += " ";
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getValueBetweenKeywords(String content, String keyWord1, String keyWord2) throws ParseException {
|
||||||
|
int pos1 = content.indexOf(keyWord1);
|
||||||
|
if (pos1 == -1) {
|
||||||
|
throw new ParseException("Keyword1=" + keyWord1 + " not found in content string",0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos2 = content.indexOf(keyWord2, pos1);
|
||||||
|
if (pos2 == -1) {
|
||||||
|
throw new ParseException("Keyword2=" + keyWord2 + " not found in content string",0);
|
||||||
|
}
|
||||||
|
String returnValue = content.substring(pos1+keyWord1.length(), pos2);
|
||||||
|
returnValue = returnValue.trim();
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package de.muehlencord.shared.util.file;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class FileHandlingException extends Exception implements Serializable {
|
||||||
|
|
||||||
|
public FileHandlingException (String hint) {
|
||||||
|
super(hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileHandlingException (String hint, Throwable th) {
|
||||||
|
super (hint, th);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
157
util/src/main/java/de/muehlencord/shared/util/file/FileUtil.java
Normal file
157
util/src/main/java/de/muehlencord/shared/util/file/FileUtil.java
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.util.file;
|
||||||
|
|
||||||
|
import de.muehlencord.shared.util.StringUtil;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.Format;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public abstract class FileUtil {
|
||||||
|
|
||||||
|
/** the logging object */
|
||||||
|
private static final Logger logger = Logger.getLogger(FileUtil.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a list of files found by the given regexp in the given folder
|
||||||
|
*
|
||||||
|
* @param directory the folder to search in as a string
|
||||||
|
* @param regEx the regular expression to search with
|
||||||
|
* @return a list of files
|
||||||
|
*
|
||||||
|
* @throws FileHandlingException if the given directory cannot be found
|
||||||
|
*/
|
||||||
|
public static List<File> getFilesFromDirecotry(final String directory, final String regEx) throws FileHandlingException {
|
||||||
|
List<File> returnValue = new LinkedList<File>();
|
||||||
|
File dir = new File(directory);
|
||||||
|
if (!dir.exists()) {
|
||||||
|
throw new FileHandlingException("Directory " + directory + " does not exist");
|
||||||
|
}
|
||||||
|
if (!dir.isDirectory()) {
|
||||||
|
throw new FileHandlingException(directory + " is not a directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
FileFilter ff = new FileFilter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(File pathname) {
|
||||||
|
boolean isFile = pathname.isFile();
|
||||||
|
boolean match = pathname.toString().matches(regEx);
|
||||||
|
return isFile && match;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
File[] files = dir.listFiles(ff);
|
||||||
|
if (files != null) {
|
||||||
|
returnValue.addAll(Arrays.asList(files));
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
} // method getFilesFromDirecotry
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a file handle to a file in the given folder using the given formater and the given number.
|
||||||
|
*
|
||||||
|
* @param outputFolder the folder to link the file to as strnig
|
||||||
|
* @param ft a format object to use to format the filename of the given file
|
||||||
|
* @param number a number used to call the given formater to name the file number
|
||||||
|
* @return a file handle build from formater and number linked to given directory
|
||||||
|
*/
|
||||||
|
public static File getFileName(final String outputFolder, final Format ft, final int number) {
|
||||||
|
String folderName = outputFolder;
|
||||||
|
String fileName = ft.format(number);
|
||||||
|
if (!outputFolder.endsWith(File.separator)) {
|
||||||
|
folderName += File.separator;
|
||||||
|
}
|
||||||
|
fileName = folderName + fileName;
|
||||||
|
return new File(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copies the givn source file to the given destination filename
|
||||||
|
*
|
||||||
|
* @param source the file to copy from
|
||||||
|
* @param destination the destination filename to copy the source file to
|
||||||
|
* @return true, if the vile was copied, false, else
|
||||||
|
*/
|
||||||
|
public static boolean copyFileTo(File source, File destination) {
|
||||||
|
FileInputStream fis = null;
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream(source);
|
||||||
|
fos = new FileOutputStream(destination);
|
||||||
|
|
||||||
|
byte[] buf = new byte[4096];
|
||||||
|
int loaded;
|
||||||
|
while ((loaded = fis.read(buf)) > 0) {
|
||||||
|
fos.write(buf, 0, loaded);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
if (fis != null) {
|
||||||
|
try {
|
||||||
|
fis.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fos != null) {
|
||||||
|
try {
|
||||||
|
fos.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
logger.debug(StringUtil.getStackTraceString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* moves / renames the given file to the new file
|
||||||
|
*
|
||||||
|
* @param source the source file
|
||||||
|
* @param destination the file to rename the source file to
|
||||||
|
* @return true, if move / rename was successfull; false else
|
||||||
|
*/
|
||||||
|
public static boolean moveFileTo(File source, File destination) {
|
||||||
|
boolean isRenamed;
|
||||||
|
if (doesPathExists(destination.getAbsolutePath())) {
|
||||||
|
destination.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
isRenamed = source.renameTo(destination);
|
||||||
|
if (!isRenamed) {
|
||||||
|
copyFileTo(source, destination);
|
||||||
|
source.delete();
|
||||||
|
}
|
||||||
|
return isRenamed;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns true, if the givn path exists; false otherwise
|
||||||
|
*
|
||||||
|
* @param path the path to check
|
||||||
|
* @return true, if the givn path exists; false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean doesPathExists(String path) {
|
||||||
|
File location = new File(path);
|
||||||
|
return location.exists();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package de.muehlencord.shared.util;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class DefaultTest {
|
||||||
|
|
||||||
|
public String readContentFromFile(String name) throws IOException {
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
InputStream is = DefaultTest.class.getResourceAsStream(name);
|
||||||
|
if (is == null) {
|
||||||
|
throw new IOException("File " + name + " not found");
|
||||||
|
}
|
||||||
|
BufferedInputStream bis = new BufferedInputStream(is);
|
||||||
|
|
||||||
|
int bytesRead = 0;
|
||||||
|
while ((bytesRead = bis.read(buffer)) != -1) {
|
||||||
|
sb.append(new String(buffer, 0, bytesRead));
|
||||||
|
}
|
||||||
|
bis.close();
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
package de.muehlencord.shared.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic StringUtilTests
|
||||||
|
* @author joern@muehlencord.de
|
||||||
|
*/
|
||||||
|
public class StringUtilTest extends DefaultTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetValueBetweenKeywords() throws ParseException, IOException {
|
||||||
|
String content = readContentFromFile("/test.txt");
|
||||||
|
|
||||||
|
String ipAddress = StringUtil.getValueBetweenKeywords(content, "The IP", "has just");
|
||||||
|
assertEquals ("ipAddress", "222.184.230.118", ipAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package de.muehlencord.shared.util.file;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jomu
|
||||||
|
*/
|
||||||
|
public class FileUtilTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tests the function getFilesFromDirectory
|
||||||
|
* @throws FileHandlingException if the files could not be listed
|
||||||
|
* @throws URISyntaxException if the testfile specification is wrong
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetFilesFromDirecotry() throws FileHandlingException, URISyntaxException {
|
||||||
|
System.out.println("testGetFilesFromDirectory");
|
||||||
|
|
||||||
|
|
||||||
|
URL url = getClass().getResource("/testfile.txt");
|
||||||
|
File testFile = new File(url.getFile());
|
||||||
|
|
||||||
|
List<File> fileList = FileUtil.getFilesFromDirecotry(testFile.getParent(), ".*.java");
|
||||||
|
Iterator<File> it = fileList.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
System.out.println(it.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
78
util/src/test/resources/test.txt
Normal file
78
util/src/test/resources/test.txt
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
Hi,
|
||||||
|
|
||||||
|
The IP 222.184.230.118 has just been banned by Fail2Ban after
|
||||||
|
4 attempts against ssh.
|
||||||
|
|
||||||
|
|
||||||
|
Here are more information about 222.184.230.118:
|
||||||
|
|
||||||
|
% [whois.apnic.net node-4]
|
||||||
|
% Whois data copyright terms http://www.apnic.net/db/dbcopyright.html
|
||||||
|
|
||||||
|
inetnum: 222.184.0.0 - 222.191.255.255
|
||||||
|
netname: CHINANET-JS
|
||||||
|
descr: CHINANET jiangsu province network
|
||||||
|
descr: China Telecom
|
||||||
|
descr: A12,Xin-Jie-Kou-Wai Street
|
||||||
|
descr: Beijing 100088
|
||||||
|
country: CN
|
||||||
|
admin-c: CH93-AP
|
||||||
|
tech-c: CJ186-AP
|
||||||
|
mnt-by: APNIC-HM
|
||||||
|
mnt-lower: MAINT-CHINANET-JS
|
||||||
|
mnt-routes: MAINT-CHINANET-JS
|
||||||
|
remarks: This object can only modify by APNIC hostmaster
|
||||||
|
remarks: If you wish to modify this object details please
|
||||||
|
remarks: send email to hostmaster@apnic.net with your
|
||||||
|
remarks: organisation account name in the subject line.
|
||||||
|
changed: hm-changed@apnic.net 20040223
|
||||||
|
status: ALLOCATED PORTABLE
|
||||||
|
source: APNIC
|
||||||
|
|
||||||
|
role: CHINANET JIANGSU
|
||||||
|
address: 260 Zhongyang Road,Nanjing 210037
|
||||||
|
country: CN
|
||||||
|
phone: +86-25-86588231
|
||||||
|
phone: +86-25-86588745
|
||||||
|
fax-no: +86-25-86588104
|
||||||
|
e-mail: ip@jsinfo.net
|
||||||
|
remarks: send anti-spam reports to spam@jsinfo.net
|
||||||
|
remarks: send abuse reports to abuse@jsinfo.net
|
||||||
|
remarks: times in GMT+8
|
||||||
|
admin-c: CH360-AP
|
||||||
|
tech-c: CS306-AP
|
||||||
|
tech-c: CN142-AP
|
||||||
|
nic-hdl: CJ186-AP
|
||||||
|
remarks: www.jsinfo.net
|
||||||
|
notify: ip@jsinfo.net
|
||||||
|
mnt-by: MAINT-CHINANET-JS
|
||||||
|
changed: dns@jsinfo.net 20090831
|
||||||
|
changed: ip@jsinfo.net 20090831
|
||||||
|
changed: hm-changed@apnic.net 20090901
|
||||||
|
source: APNIC
|
||||||
|
changed: hm-changed@apnic.net 20111114
|
||||||
|
|
||||||
|
person: Chinanet Hostmaster
|
||||||
|
nic-hdl: CH93-AP
|
||||||
|
e-mail: anti-spam@ns.chinanet.cn.net
|
||||||
|
address: No.31 ,jingrong street,beijing
|
||||||
|
address: 100032
|
||||||
|
phone: +86-10-58501724
|
||||||
|
fax-no: +86-10-58501724
|
||||||
|
country: CN
|
||||||
|
changed: dingsy@cndata.com 20070416
|
||||||
|
mnt-by: MAINT-CHINANET
|
||||||
|
source: APNIC
|
||||||
|
|
||||||
|
|
||||||
|
Lines containing IP:222.184.230.118 in /var/log/auth.log
|
||||||
|
|
||||||
|
Jan 6 23:35:47 localhost sshd[31328]: Invalid user cgi from 222.184.230.118
|
||||||
|
Jan 6 23:35:49 localhost sshd[31330]: Invalid user richie from 222.184.230.118
|
||||||
|
Jan 6 23:35:51 localhost sshd[31332]: Invalid user shirsh from 222.184.230.118
|
||||||
|
Jan 6 23:36:00 localhost sshd[31340]: Invalid user system from 222.184.230.118
|
||||||
|
|
||||||
|
|
||||||
|
Regards,
|
||||||
|
|
||||||
|
Fail2Ban
|
||||||
1
util/src/test/resources/testfile.txt
Normal file
1
util/src/test/resources/testfile.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
||||||
Reference in New Issue
Block a user