com.enterprisemath.utils.DomainUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of em-utils Show documentation
Show all versions of em-utils Show documentation
Collection of utility classes for large scale projects focusing on robust and testable code.
package com.enterprisemath.utils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Contains static method which simplifies the manipulation with domain objects.
*
* @author radek.hecl
*
*/
public class DomainUtils {
/**
* To prevent construction.
*/
private DomainUtils() {
}
/**
* Null safe copy date function.
*
* @param source source date, can be null
* @return copy of the source date or null if source is null
*/
public static Date copyDate(Date source) {
if (source == null) {
return null;
}
return new Date(source.getTime());
}
/**
* Null safe function for creating a soft copy of the list.
* It the source is null, then empty list will be returned.
*
* @param source source object, can be any collection
* @return soft copy of the source object
*/
public static List softCopyList(Collection source) {
if (source == null) {
source = Collections.emptyList();
}
return new ArrayList(source);
}
/**
* Null safe function for creating a soft copy of the set.
* If the source is null, then empty set will be returned.
*
* @param source source object, can be any collection
* @return soft copy of the source object
*/
public static Set softCopySet(Collection source) {
if (source == null) {
source = Collections.emptySet();
}
return new HashSet(source);
}
/**
* Null safe function for creating a soft copy of the sorted set.
* If the source is null, then empty set will be returned.
*
* @param source source object, can be any collection, but elements must
* @return soft copy of the source object
*/
public static > SortedSet softCopySortedSet(Collection source) {
if (source == null) {
source = Collections.emptySet();
}
return new TreeSet(source);
}
/**
* Null safe function for creating a soft copy of the map.
* If the source is null, then empty map will be returned.
*
* @param source source object
* @return soft copy of the source object
*/
public static Map softCopyMap(Map source) {
if (source == null) {
source = Collections.emptyMap();
}
return new HashMap(source);
}
/**
* Make a soft copy of the source map, but without the keys which match the specified regular expression.
* For example if the given map is { "hello" : 1, "world" : 2} and regexp is "hello", then
* result copy will be map { "hello" : 1 }.
*
* @param source source map, must be without null keys
* @param regexp regular expression to filter out the keys from the copy of the map
* @return soft copy of the source map without the keys which are matching the expression
*/
public static Map softCopyMapWithoutMatchedKeys(Map source, String regexp) {
Map res = new HashMap();
for (String key : source.keySet()) {
if (!key.matches(regexp)) {
res.put(key, source.get(key));
}
}
return res;
}
/**
* Merges several maps into one.
* If there is no map to merge, then returns empty map.
* If there is at least one map, then takes elements form the first, then apply from the second
* and so on.
* Examples (in JSON notation):
*
* - {"a" : 1} + {"b" : 2} -> {"a" : 1, "b" : 2}
* - {"a" : 1} + {"a" : 2} -> {"a" : 2}
* - {"a" : 1} + {"b" : 2} + {"a" : "hello"} -> {"a" : "hello", "b" : 2}
*
*
* @param maps maps to merge
* @return merged map
*/
public static Map mergeMaps(Map... maps) {
Map res = new HashMap();
for (int i = 0; i < maps.length; ++i) {
res.putAll(maps[i]);
}
return res;
}
/**
* Creates map where prefix is added to the each key.
* Examples:
*
* - "hello.", {"world" : 1, "baby" : 2} -> {"hello.world" : 1, "hello.baby" : 2}
* - "$", {"world" : 1, "baby" : 2} -> {"$world" : 1, "$baby" : 2}
*
*
* @param prefix prefix which will be used, cannot be null
* @param source source map, cannot be null or have null as a key
* @return map with all keys being prefixed
*/
public static Map createMapPrefixOnKeys(String prefix, Map source) {
ValidationUtils.guardNotNull(prefix, "prefix cannot be null");
ValidationUtils.guardNotNull(source, "source cannot be null");
ValidationUtils.guardNotNullCollection(source.keySet(), "source.keySet() cannot have null element");
Map res = new HashMap();
for (String key : source.keySet()) {
res.put(prefix + key, source.get(key));
}
return res;
}
/**
* Returns the copy of the object. This is not the deep copy.
* Should provide the balance between performance and security.
* If the source is null, then null will be returned.
* If the source is date, then the copy will be returned.
* If the source is list, set or map, then soft copy will be returned.
* If the source is any other type, then source object will be returned.
*
* @param source source object
* @return copy of the given object
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Object copyObject(Object source) {
if (source instanceof Date) {
return copyDate((Date) source);
}
if (source instanceof List) {
return softCopyList((List) source);
}
if (source instanceof Set) {
return softCopySet((Set) source);
}
if (source instanceof Map) {
return softCopyMap((Map) source);
}
return source;
}
/**
* Wrapper function around java.util.Arrays.asList(T... a) to create a set of objects.
*
* @return created set
*/
public static Set createSet(T... a) {
return new HashSet(Arrays.asList(a));
}
/**
* Returns the set which contains all the numbers from the specified interval.
* Borders are included.
* Examples:
*
* - min = 1, max = 3 -> [1, 2, 3]
* - min = 1, max = 1 -> [1]
* - min = 1, max = 0 -> []
*
*
* @param min minimum (included)
* @param max maximum (included)
* @return created interval set
*/
public static Set createLongIntervalSet(long min, long max) {
Set res = new HashSet();
for (long i = min; i <= max; ++i) {
res.add(i);
}
return res;
}
/**
* Takes the collection and splits it into the several lists.
* Every of these lists has maximum number of elements which is less or equal to the max parameters.
* If source collection has some duplicated elements, then all of them stays there.
* If source collection is null or empty, then list with no sub lists will be returned.
* The ordering within the split lists is the same as within the source collection.
*
* @param source source collection
* @param max maximum allowed number of elements per one list, must be positive number
* @return source collection split into lists
*/
public static List> splitIntoLists(Collection source, int max) {
ValidationUtils.guardPositiveInt(max, "max must be positive number");
List sourceCopy = softCopyList(source);
if (sourceCopy.isEmpty()) {
return Collections.emptyList();
}
List> res = new ArrayList>();
List part = new ArrayList();
for (T obj : sourceCopy) {
part.add(obj);
if (part.size() == max) {
res.add(part);
part = new ArrayList();
}
}
if (!part.isEmpty()) {
res.add(part);
}
return res;
}
/**
* Takes the collection and splits it into the several sets.
* Every of these sets has maximum number of elements which is less or equal to the max parameters.
* If source collection has some duplicated elements, then all of them are merged.
* If source collection is null or empty, then list with no sub sets will be returned.
* The ordering within the split sets is not defined.
*
* @param source source collection
* @param max maximum allowed number of elements per one list, must be positive number
* @return source collection split into lists
*/
public static List> splitIntoSets(Collection source, int max) {
ValidationUtils.guardPositiveInt(max, "max must be positive number");
Set sourceCopy = softCopySet(source);
if (sourceCopy.isEmpty()) {
return Collections.emptyList();
}
List> res = new ArrayList>();
Set part = new HashSet();
for (T obj : sourceCopy) {
part.add(obj);
if (part.size() == max) {
res.add(part);
part = new HashSet();
}
}
if (!part.isEmpty()) {
res.add(part);
}
return res;
}
/**
* Creates the document from a given XML file.
*
* @param file file to parse
* @return created DOM document
*/
public static Document createDocumentFromXmlFile(File file) {
InputStream is = null;
try {
is = new FileInputStream(file);
DocumentBuilder docBuilder = DocumentBuilderFactory.
newInstance().
newDocumentBuilder();
Document doc = docBuilder.parse(is);
is.close();
return doc;
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
} catch (SAXException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
IOUtils.closeQuietly(is);
}
}
/**
* Creates the document from a given XML file, specified by bytes.
*
* @param bytes bytes containing file to parse
* @return created DOM document
*/
public static Document createDocumentFromXmlBytes(byte[] bytes) {
InputStream is = null;
try {
is = new ByteArrayInputStream(bytes);
DocumentBuilder docBuilder = DocumentBuilderFactory.
newInstance().
newDocumentBuilder();
Document doc = docBuilder.parse(is);
is.close();
return doc;
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
} catch (SAXException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
IOUtils.closeQuietly(is);
}
}
/**
* Returns object property by the specified enumeration name.
* First searches for getter which starting with "get".
* If this getter is not presented, then search for the one which starting with "is".
* Examples of getters for a specified enumeration:
*
* - ID => getId(), isId()
* - EVENT_TIMESTAMP => getEventTimestamp(), isEventTimestamp()
*
* If getter is presented, then returns the value.
* Note: This method uses reflection, so speed is not great.
*
* @param obj object from which property should be obtained
* @param enm enumeration which will be used to find the property
* @return value of the property
*/
public static Object getPropertyByEnum(Object obj, Enum> enm) {
ValidationUtils.guardNotNull(obj, "obj cannot be null");
ValidationUtils.guardNotNull(enm, "enm cannot be null");
String name = enm.name().toLowerCase();
String getterBase = "";
boolean capital = true;
for (int i = 0; i < name.length(); ++i) {
char c = name.charAt(i);
if (c == '_') {
capital = true;
}
else if (capital) {
getterBase += String.valueOf(c).toUpperCase();
capital = false;
}
else {
getterBase += String.valueOf(c);
}
}
Method method = null;
Class> clazz = obj.getClass();
try {
method = clazz.getMethod("get" + getterBase);
} catch (NoSuchMethodException e) {
try {
method = clazz.getMethod("is" + getterBase);
} catch (NoSuchMethodException e1) {
throw new IllegalArgumentException("getter doesn't exists: Class = " + clazz + "; Enum = " + enm);
} catch (SecurityException e1) {
throw new RuntimeException(e1);
}
} catch (SecurityException e) {
throw new RuntimeException(e);
}
try {
return method.invoke(obj);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
/**
* Null safe equals method. Returns true if both objects are null or equals each other.
* This method expects equals method to be well defined (reflexivity, symetricity, transitivity) in both objects.
*
* @param obj1 first object
* @param obj2 second object
* @return true if both objects are null or if they equals, false otherwise
*/
public static boolean safeEquals(Object obj1, Object obj2) {
if (obj1 == null && obj2 == null) {
return true;
}
if (obj1 == null || obj2 == null) {
return false;
}
return obj1.equals(obj2);
}
/**
* Converts property map into the velocity model.
* This means deep conversion of these property key types is done.
*
* - Properties with key in XX format are converted as they are.
* - Properties with key in XX.YY format are converted into map XX = {YY}
* - Properties with key in XX[NUM] format are converted into list
* - Properties with key in XX[NUM].YY format are converted into list of maps
*
*
* @param properties properties to be converted
* @return velocity model
*/
public static Map convertPropertyMapIntoVelocityModel(Map properties) {
Map res = new HashMap();
Map> maps = new HashMap>();
Map>> arrayMaps = new HashMap>>();
Map> lists = new HashMap>();
for (String key : properties.keySet()) {
if (key.matches("^[^\\.\\[\\]]+$")) {
res.put(key, properties.get(key));
}
else if (key.matches("^[^\\[\\]]+\\..+$")) {
String[] parts = key.split("\\.", 2);
String mapKey = parts[0];
String subKey = parts[1];
if (!maps.containsKey(mapKey)) {
maps.put(mapKey, new HashMap());
}
maps.get(mapKey).put(subKey, properties.get(key));
}
else if (key.matches("^[^\\.]+\\[[0-9]+\\]\\..+$")) {
String[] parts = key.split("[\\[\\]]", 3);
String mapKey = parts[0];
int index = Integer.valueOf(parts[1]);
String subKey = parts[2].substring(1);
if (!arrayMaps.containsKey(mapKey)) {
arrayMaps.put(mapKey, new TreeMap>());
}
if (!arrayMaps.get(mapKey).containsKey(index)) {
arrayMaps.get(mapKey).put(index, new HashMap());
}
arrayMaps.get(mapKey).get(index).put(subKey, properties.get(key));
}
else if (key.matches("^[^\\.]+\\[[0-9]+\\]$")) {
String[] parts = key.split("[\\[\\]]", 3);
String mapKey = parts[0];
int index = Integer.valueOf(parts[1]);
if (!lists.containsKey(mapKey)) {
lists.put(mapKey, new TreeMap());
}
lists.get(mapKey).put(index, properties.get(key));
}
else {
throw new RuntimeException("unsupported property key, please implement me: key = " + key);
}
}
// transform maps and arrays
for (String key : maps.keySet()) {
res.put(key, convertPropertyMapIntoVelocityModel(maps.get(key)));
}
for (String key : arrayMaps.keySet()) {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy