开发用的工具
diff --git a/tools/commons/pom.xml b/tools/commons/pom.xml
new file mode 100755
index 0000000..709d145
--- /dev/null
+++ b/tools/commons/pom.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0"?>
+<project
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.ekingstar.commons</groupId>
+ <artifactId>commons</artifactId>
+ <version>1.0.0</version>
+ <properties>
+ <mockito.version>1.9.5</mockito.version>
+ <testng.version>6.5.2</testng.version>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <downloadJavadocs>true</downloadJavadocs>
+ <logback.version>1.0.7</logback.version>
+ <slf4j.version>1.6.6</slf4j.version>
+ </properties>
+ <distributionManagement>
+ <repository>
+ <id>ekingstar-releases</id>
+ <name>internal release</name>
+ <url>http://app.supwisdom.com:81/artifactory/libs-release-local</url>
+ </repository>
+ <snapshotRepository>
+ <id>ekingstar-snapshots</id>
+ <name>internal Snapshots</name>
+ <url>http://app.supwisdom.com:81/artifactory/libs-snapshot-local</url>
+ </snapshotRepository>
+ <downloadUrl>http://app.supwisdom.com:81/artifactory</downloadUrl>
+ </distributionManagement>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.6.6</version>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.0.7</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.0.7</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>6.5.2</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.6.6</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>6.5.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.0.7</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.0.7</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.0</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <phase>deploy</phase>
+ <goals>
+ <goal>jar-no-fork</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <phase>deploy</phase>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <!-- explicitly define maven-deploy-plugin after other to force exec
+ order -->
+ <artifactId>maven-deploy-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>deploy</id>
+ <phase>deploy</phase>
+ <goals>
+ <goal>deploy</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+
+</project>
\ No newline at end of file
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/Disposable.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/Disposable.java
new file mode 100644
index 0000000..b12af80
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/Disposable.java
@@ -0,0 +1,37 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean;
+
+/**
+ * <p>
+ * Disposable interface.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public interface Disposable {
+
+ /**
+ * <p>
+ * destroy.
+ * </p>
+ */
+ void destroy();
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/Initializing.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/Initializing.java
new file mode 100644
index 0000000..65e4a21
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/Initializing.java
@@ -0,0 +1,38 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean;
+
+/**
+ * <p>
+ * Initializing interface.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public interface Initializing {
+ /**
+ * <p>
+ * init.
+ * </p>
+ *
+ * @throws java.lang.Exception if any.
+ */
+ void init() throws Exception;
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/PropertyNameResolver.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/PropertyNameResolver.java
new file mode 100644
index 0000000..c059513
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/PropertyNameResolver.java
@@ -0,0 +1,215 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean;
+
+/**
+ * Default Property Name Resolver .
+ * <p>
+ * This class assists in resolving property names in the following four formats, with the layout of
+ * an identifying String in parentheses:
+ * <ul>
+ * <li><strong>Simple (<code>name</code>)</strong> - The specified <code>name</code> identifies an
+ * individual property of a particular JavaBean. The name of the actual getter or setter method to
+ * be used is determined using standard JavaBeans instrospection, a property named "xyz" will have a
+ * getter method named <code>getXyz()</code> or (for boolean properties only) <code>isXyz()</code>,
+ * and a setter method named <code>setXyz()</code>.</li>
+ * <li><strong>Indexed (<code>name[index]</code>)</strong> - The underlying property value is
+ * assumed to be an array. The appropriate (zero-relative) entry in the array is selected. <code>List</code>
+ * objects are now also supported for read/write.</li>
+ * <li><strong>Mapped (<code>name(key)</code>)</strong> - The JavaBean is assumed to have an
+ * property getter and setter methods with an additional attribute of type
+ * <code>java.lang.String</code>.</li>
+ * <li><strong>Nested (<code>name1.name2[index].name3(key)</code>)</strong> - Combining mapped,
+ * nested, and indexed references is also supported.</li>
+ * </ul>
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public class PropertyNameResolver {
+
+ private static final char Nested = '.';
+ private static final char MappedStart = '(';
+ private static final char MappedEnd = ')';
+ private static final char IndexedStart = '[';
+ private static final char IndexedEnd = ']';
+
+ /**
+ * Return the index value from the property expression or -1.
+ *
+ * @param expression The property expression
+ * @return The index value or -1 if the property is not indexed
+ * @throws IllegalArgumentException If the indexed property is illegally
+ * formed or has an invalid (non-numeric) value.
+ */
+ public int getIndex(String expression) {
+ if (expression == null || expression.length() == 0) { return -1; }
+ for (int i = 0; i < expression.length(); i++) {
+ char c = expression.charAt(i);
+ if (c == Nested || c == MappedStart) {
+ return -1;
+ } else if (c == IndexedStart) {
+ int end = expression.indexOf(IndexedEnd, i);
+ if (end < 0) { throw new IllegalArgumentException("Missing End Delimiter"); }
+ String value = expression.substring(i + 1, end);
+ if (value.length() == 0) { throw new IllegalArgumentException("No Index Value"); }
+ int index = 0;
+ try {
+ index = Integer.parseInt(value, 10);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Invalid index value '" + value + "'");
+ }
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Return the map key from the property expression or <code>null</code>.
+ *
+ * @param expression The property expression
+ * @return The index value
+ * @throws IllegalArgumentException If the mapped property is illegally formed.
+ */
+ public String getKey(String expression) {
+ if (expression == null || expression.length() == 0) { return null; }
+ for (int i = 0; i < expression.length(); i++) {
+ char c = expression.charAt(i);
+ if (c == Nested || c == IndexedStart) {
+ return null;
+ } else if (c == MappedStart) {
+ int end = expression.indexOf(MappedEnd, i);
+ if (end < 0) { throw new IllegalArgumentException("Missing End Delimiter"); }
+ return expression.substring(i + 1, end);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the property name from the property expression.
+ *
+ * @param expression The property expression
+ * @return The property name
+ */
+ public String getProperty(String expression) {
+ if (expression == null || expression.length() == 0) { return expression; }
+ for (int i = 0; i < expression.length(); i++) {
+ char c = expression.charAt(i);
+ if (c == Nested) {
+ return expression.substring(0, i);
+ } else if (c == MappedStart || c == IndexedStart) { return expression.substring(0, i); }
+ }
+ return expression;
+ }
+
+ /**
+ * Indicates whether or not the expression contains nested property expressions or not.
+ *
+ * @param expression The property expression
+ * @return The next property expression
+ */
+ public boolean hasNested(String expression) {
+ if (expression == null || expression.length() == 0) return false;
+ else return remove(expression) != null;
+
+ }
+
+ /**
+ * Indicate whether the expression is for an indexed property or not.
+ *
+ * @param expression The property expression
+ * @return <code>true</code> if the expresion is indexed,
+ * otherwise <code>false</code>
+ */
+ public boolean isIndexed(String expression) {
+ if (expression == null || expression.length() == 0) { return false; }
+ for (int i = 0; i < expression.length(); i++) {
+ char c = expression.charAt(i);
+ if (c == Nested || c == MappedStart) {
+ return false;
+ } else if (c == IndexedStart) { return true; }
+ }
+ return false;
+ }
+
+ /**
+ * Indicate whether the expression is for a mapped property or not.
+ *
+ * @param expression The property expression
+ * @return <code>true</code> if the expresion is mapped,
+ * otherwise <code>false</code>
+ */
+ public boolean isMapped(String expression) {
+ if (expression == null || expression.length() == 0) { return false; }
+ for (int i = 0; i < expression.length(); i++) {
+ char c = expression.charAt(i);
+ if (c == Nested || c == IndexedStart) {
+ return false;
+ } else if (c == MappedStart) { return true; }
+ }
+ return false;
+ }
+
+ /**
+ * Extract the next property expression from the current expression.
+ *
+ * @param expression The property expression
+ * @return The next property expression
+ */
+ public String next(String expression) {
+ if (expression == null || expression.length() == 0) { return null; }
+ boolean indexed = false;
+ boolean mapped = false;
+ for (int i = 0; i < expression.length(); i++) {
+ char c = expression.charAt(i);
+ if (indexed) {
+ if (c == IndexedEnd) { return expression.substring(0, i + 1); }
+ } else if (mapped) {
+ if (c == MappedEnd) { return expression.substring(0, i + 1); }
+ } else {
+ if (c == Nested) {
+ return expression.substring(0, i);
+ } else if (c == MappedStart) {
+ mapped = true;
+ } else if (c == IndexedStart) {
+ indexed = true;
+ }
+ }
+ }
+ return expression;
+ }
+
+ /**
+ * Remove the last property expresson from the current expression.
+ *
+ * @param expression The property expression
+ * @return The new expression value, with first property
+ * expression removed - null if there are no more expressions
+ */
+ public String remove(String expression) {
+ if (expression == null || expression.length() == 0) { return null; }
+ String property = next(expression);
+ if (expression.length() == property.length()) { return null; }
+ int start = property.length();
+ if (expression.charAt(start) == Nested) start++;
+ return expression.substring(start);
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/PropertyUtils.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/PropertyUtils.java
new file mode 100644
index 0000000..53f7115
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/PropertyUtils.java
@@ -0,0 +1,251 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean;
+
+import java.lang.reflect.Array;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ekingstar.commons.conversion.Conversion;
+import com.ekingstar.commons.conversion.impl.DefaultConversion;
+import com.ekingstar.commons.lang.Strings;
+import com.ekingstar.commons.lang.Throwables;
+import com.ekingstar.commons.lang.reflect.ClassInfo;
+import com.ekingstar.commons.lang.reflect.MethodInfo;
+
+/**
+ * @author chaostone
+ */
+public class PropertyUtils {
+
+ private static final Logger logger = LoggerFactory.getLogger(PropertyUtils.class);
+
+ private static final PropertyNameResolver resolver = new PropertyNameResolver();
+
+ /**
+ * @throws NoSuchMethodException
+ * @param bean
+ * @param name
+ * @param value
+ */
+ public static void setProperty(Object bean, String name, Object value) {
+ copyProperty(bean, name, value, null);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T getProperty(Object bean, String name) {
+ // Resolve nested references
+ while (resolver.hasNested(name)) {
+ String next = resolver.next(name);
+ Object nestedBean = null;
+ if (bean instanceof Map) {
+ nestedBean = getPropertyOfMapBean((Map<?, ?>) bean, next);
+ } else if (resolver.isMapped(next)) {
+ nestedBean = getMappedProperty(bean, next);
+ } else if (resolver.isIndexed(next)) {
+ nestedBean = getIndexedProperty(bean, next);
+ } else {
+ nestedBean = getSimpleProperty(bean, next);
+ }
+ if (nestedBean == null) return null;
+ bean = nestedBean;
+ name = resolver.remove(name);
+ }
+
+ if (bean instanceof Map) {
+ bean = getPropertyOfMapBean((Map<?, ?>) bean, name);
+ } else if (resolver.isMapped(name)) {
+ bean = getMappedProperty(bean, name);
+ } else if (resolver.isIndexed(name)) {
+ bean = getIndexedProperty(bean, name);
+ } else {
+ bean = getSimpleProperty(bean, name);
+ }
+ return (T) bean;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public static Object copyProperty(Object bean, String name, Object value, Conversion conversion) {
+ // Resolve nested references
+ while (resolver.hasNested(name)) {
+ String next = resolver.next(name);
+ Object nestedBean = null;
+ if (bean instanceof Map) {
+ nestedBean = getPropertyOfMapBean((Map) bean, next);
+ } else if (resolver.isMapped(next)) {
+ nestedBean = getMappedProperty(bean, next);
+ } else if (resolver.isIndexed(next)) {
+ nestedBean = getIndexedProperty(bean, next);
+ } else {
+ nestedBean = getSimpleProperty(bean, next);
+ }
+ if (nestedBean == null) { throw new RuntimeException("Null property value for '" + name
+ + "' on bean class '" + bean.getClass() + "'"); }
+ bean = nestedBean;
+ name = resolver.remove(name);
+ }
+
+ if (bean instanceof Map) {
+ setPropertyOfMapBean((Map<Object, Object>) bean, name, value);
+ } else if (resolver.isMapped(name)) {
+ setMappedProperty(bean, name, value);
+ } else if (resolver.isIndexed(name)) {
+ return copyIndexedProperty(bean, name, value, conversion);
+ } else {
+ return copySimpleProperty(bean, name, value, conversion);
+ }
+ return value;
+ }
+
+ public static boolean isWriteable(Object bean, String name) {
+ ClassInfo classInfo = ClassInfo.get(bean.getClass());
+ return null != classInfo.getWriter(name);
+ }
+
+ public static Class<?> getPropertyType(Class<?> clazz, String name) {
+ return ClassInfo.get(clazz).getPropertyType(name);
+ }
+
+ public static Set<String> getWritableProperties(Class<?> clazz) {
+ return ClassInfo.get(clazz).getWritableProperties();
+ }
+
+ private static Object copySimpleProperty(Object bean, String name, Object value, Conversion conversion) {
+ ClassInfo classInfo = ClassInfo.get(bean.getClass());
+ MethodInfo info = classInfo.getWriter(name);
+ if (null == info) {
+ logger.warn("Cannot find set" + Strings.capitalize(name) + " in " + bean.getClass());
+ return null;
+ }
+ Object converted = value;
+ if (null != conversion) converted = conversion.convert(value, classInfo.getPropertyType(name));
+ try {
+ return info.method.invoke(bean, converted);
+ } catch (Exception e) {
+ Throwables.propagate(e);
+ }
+ return converted;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void setMappedProperty(Object bean, String name, Object value) {
+ // Identify the key of the requested individual property
+ String key = null;
+ try {
+ key = resolver.getKey(name);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Invalid mapped property '" + name + "' on bean class '"
+ + bean.getClass() + "'");
+ }
+ if (key == null) { throw new IllegalArgumentException("Invalid mapped property '" + name
+ + "' on bean class '" + bean.getClass() + "'"); }
+
+ // Isolate the name
+ name = resolver.getProperty(name);
+ Object rs = bean;
+ if (name != null && name.length() >= 0) rs = getSimpleProperty(bean, name);
+ if (rs instanceof java.util.Map<?, ?>) ((java.util.Map<Object, Object>) rs).put(key, value);
+ }
+
+ private static void setPropertyOfMapBean(Map<Object, Object> bean, String propertyName, Object value) {
+ if (resolver.isMapped(propertyName)) {
+ String name = resolver.getProperty(propertyName);
+ if (name == null || name.length() == 0) {
+ propertyName = resolver.getKey(propertyName);
+ }
+ }
+ if (resolver.isIndexed(propertyName) || resolver.isMapped(propertyName)) { throw new IllegalArgumentException(
+ "Indexed or mapped properties are not supported on" + " objects of type Map: " + propertyName); }
+
+ bean.put(propertyName, value);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Object copyIndexedProperty(Object bean, String name, Object value, Conversion conversion) {
+ int index = -1;
+ try {
+ index = resolver.getIndex(name);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Invalid indexed property '" + name + "' on bean class '"
+ + bean.getClass() + "'");
+ }
+ if (index < 0) { throw new IllegalArgumentException("Invalid indexed property '" + name
+ + "' on bean class '" + bean.getClass() + "'"); }
+
+ // Isolate the name
+ name = resolver.getProperty(name);
+ Object rs = bean;
+ if (name != null && name.length() >= 0) rs = getSimpleProperty(bean, name);
+
+ Object converted = value;
+ if (rs.getClass().isArray()) {
+ if (null != conversion) converted = conversion.convert(value, rs.getClass().getComponentType());
+ Array.set(rs, index, value);
+ } else if (rs instanceof List) {
+ ((List<Object>) rs).set(index, value);
+ }
+ return converted;
+ }
+
+ public static Object copyProperty(Object bean, String name, Object value) {
+ return copyProperty(bean,name,value,DefaultConversion.Instance);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> T getSimpleProperty(Object bean, String name) {
+ MethodInfo info = ClassInfo.get(bean.getClass()).getReader(name);
+ if (null == info) {
+ logger.warn("Cannot find get" + Strings.capitalize(name) + " in " + bean.getClass());
+ return null;
+ }
+ try {
+ return (T) info.method.invoke(bean);
+ } catch (Exception e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ private static Object getPropertyOfMapBean(Map<?, ?> bean, String propertyName) {
+ String name = resolver.getProperty(propertyName);
+ if (name == null || name.length() == 0) propertyName = resolver.getKey(propertyName);
+ return bean.get(propertyName);
+ }
+
+ private static Object getMappedProperty(Object bean, String name) {
+ String key = resolver.getKey(name);
+ if (key == null) { throw new IllegalArgumentException("Invalid mapped property '" + name + "'"); }
+ Object value = getSimpleProperty(bean, resolver.getProperty(name));
+ if (null == value) return null;
+ return ((Map<?, ?>) value).get(key);
+ }
+
+ private static Object getIndexedProperty(Object bean, String name) {
+ int index = resolver.getIndex(name);
+ if (index < 0) { throw new IllegalArgumentException("Invalid indexed property '" + name + "'"); }
+ Object value = getSimpleProperty(bean, resolver.getProperty(name));
+ if (null == value) return null;
+
+ if (value.getClass().isArray()) return (Array.get(value, index));
+ else return ((List<?>) value).get(index);
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/ChainComparator.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/ChainComparator.java
new file mode 100755
index 0000000..f3a9968
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/ChainComparator.java
@@ -0,0 +1,112 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean.comparators;
+
+import java.util.Comparator;
+import java.util.List;
+
+import com.ekingstar.commons.collection.CollectUtils;
+
+/**
+ * 组合比较器
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class ChainComparator<T> implements Comparator<T> {
+
+ private List<Comparator<T>> comparators;
+
+ /**
+ * <p>
+ * compare.
+ * </p>
+ *
+ * @param first a T object.
+ * @param second a T object.
+ * @return 0 is equals,-1 first < second ,1 first > second
+ */
+ public int compare(final T first, final T second) {
+ int cmpRs = 0;
+ for (final Comparator<T> com : comparators) {
+ cmpRs = com.compare(first, second);
+ if (0 == cmpRs) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ return cmpRs;
+ }
+
+ /**
+ * <p>
+ * Constructor for ChainComparator.
+ * </p>
+ */
+ public ChainComparator() {
+ this.comparators = CollectUtils.newArrayList();
+ }
+
+ /**
+ * <p>
+ * Constructor for ChainComparator.
+ * </p>
+ *
+ * @param comparators a {@link java.util.List} object.
+ */
+ public ChainComparator(final List<Comparator<T>> comparators) {
+ super();
+ this.comparators = comparators;
+ }
+
+ /**
+ * <p>
+ * addComparator.
+ * </p>
+ *
+ * @param com a {@link java.util.Comparator} object.
+ */
+ public void addComparator(final Comparator<T> com) {
+ this.comparators.add(com);
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>comparators</code>.
+ * </p>
+ *
+ * @return a {@link java.util.List} object.
+ */
+ public List<Comparator<T>> getComparators() {
+ return comparators;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>comparators</code>.
+ * </p>
+ *
+ * @param comparators a {@link java.util.List} object.
+ */
+ public void setComparators(final List<Comparator<T>> comparators) {
+ this.comparators = comparators;
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/CollatorStringComparator.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/CollatorStringComparator.java
new file mode 100755
index 0000000..6b3000d
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/CollatorStringComparator.java
@@ -0,0 +1,128 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean.comparators;
+
+import java.text.Collator;
+
+/**
+ * <p>
+ * CollatorStringComparator class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class CollatorStringComparator implements StringComparator {
+ private boolean asc;
+
+ private Collator collator;
+
+ /**
+ * <p>
+ * Constructor for CollatorStringComparator.
+ * </p>
+ */
+ public CollatorStringComparator() {
+ super();
+ collator = Collator.getInstance();
+ }
+
+ /**
+ * <p>
+ * Constructor for CollatorStringComparator.
+ * </p>
+ *
+ * @param asc a boolean.
+ */
+ public CollatorStringComparator(final boolean asc) {
+ this();
+ this.asc = asc;
+ }
+
+ /**
+ * <p>
+ * Constructor for CollatorStringComparator.
+ * </p>
+ *
+ * @param asc a boolean.
+ * @param collator a {@link java.text.Collator} object.
+ */
+ public CollatorStringComparator(final boolean asc, final Collator collator) {
+ this.collator = collator;
+ this.asc = asc;
+ }
+
+ /**
+ * <p>
+ * compare.
+ * </p>
+ *
+ * @param what0 a {@link java.lang.String} object.
+ * @param what1 a {@link java.lang.String} object.
+ * @return a int.
+ */
+ public int compare(final String what0, final String what1) {
+ return (asc ? 1 : -1) * (collator.compare((null == what0) ? "" : what0, (null == what1) ? "" : what1));
+ }
+
+ /**
+ * <p>
+ * isAsc.
+ * </p>
+ *
+ * @return a boolean.
+ */
+ public boolean isAsc() {
+ return asc;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>asc</code>.
+ * </p>
+ *
+ * @param asc a boolean.
+ */
+ public void setAsc(final boolean asc) {
+ this.asc = asc;
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>collator</code>.
+ * </p>
+ *
+ * @return a {@link java.text.Collator} object.
+ */
+ public Collator getCollator() {
+ return collator;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>collator</code>.
+ * </p>
+ *
+ * @param collator a {@link java.text.Collator} object.
+ */
+ public void setCollator(final Collator collator) {
+ this.collator = collator;
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/CollectionSizeComparator.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/CollectionSizeComparator.java
new file mode 100755
index 0000000..99915a8
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/CollectionSizeComparator.java
@@ -0,0 +1,45 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean.comparators;
+
+import java.util.Collection;
+import java.util.Comparator;
+
+/**
+ * 比较两个集合,元素多的大
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class CollectionSizeComparator<T extends Collection<?>> implements Comparator<T> {
+
+ /**
+ * <p>
+ * compare.
+ * </p>
+ *
+ * @param first a T object.
+ * @param second a T object.
+ * @return equals : 0,first less then second : -1 or small , first greate then second : 1 or big
+ */
+ public int compare(final T first, final T second) {
+ if (first.equals(second)) return 0;
+ else return first.size() - second.size();
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/MultiPropertyComparator.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/MultiPropertyComparator.java
new file mode 100755
index 0000000..5e0f5e3
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/MultiPropertyComparator.java
@@ -0,0 +1,46 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean.comparators;
+
+import com.ekingstar.commons.lang.Strings;
+
+/**
+ * 多个属性的比较
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class MultiPropertyComparator extends ChainComparator<Object> {
+
+ /**
+ * <p>
+ * Constructor for MultiPropertyComparator.
+ * </p>
+ *
+ * @param propertyStr a {@link java.lang.String} object.
+ */
+ public MultiPropertyComparator(final String propertyStr) {
+ super();
+ final String[] properties = Strings.split(propertyStr, ',');
+ for (int i = 0; i < properties.length; i++) {
+ addComparator(new PropertyComparator(properties[i].trim()));
+ }
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/PropertyComparator.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/PropertyComparator.java
new file mode 100755
index 0000000..1d28289
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/PropertyComparator.java
@@ -0,0 +1,225 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean.comparators;
+
+import java.util.Comparator;
+
+import com.ekingstar.commons.bean.PropertyUtils;
+import com.ekingstar.commons.lang.Numbers;
+import com.ekingstar.commons.lang.Strings;
+
+/**
+ * 属性比较器。<br>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class PropertyComparator implements Comparator<Object> {
+
+ private String cmpWhat;
+
+ private int index = -1;
+
+ private boolean asc;
+
+ // 升序情况下,null排在前面,降序情况下,null排在后面。
+ private boolean nullFirst = true;
+
+ @SuppressWarnings("rawtypes")
+ private Comparator comparator;
+
+ private StringComparator stringComparator;
+
+ /**
+ * new OrderedBeanComparator("id") or<br>
+ * new OrderedBeanComparator("name desc"); new
+ * OrderedBeanComparator("[0].name desc");
+ *
+ * @param cmpStr a {@link java.lang.String} object.
+ */
+ public PropertyComparator(final String cmpStr) {
+ if (Strings.isEmpty(cmpStr)) { return; }
+
+ if (Strings.contains(cmpStr, ',')) { throw new RuntimeException(
+ "PropertyComparator don't suport comma based order by." + " Use MultiPropertyComparator "); }
+ cmpWhat = cmpStr.trim();
+ // 处理带有[]符号的字符串
+ if ('[' == cmpWhat.charAt(0)) {
+ index = Numbers.toInt(Strings.substringBetween(cmpWhat, "[", "]"));
+ cmpWhat = Strings.substringAfter(cmpWhat, "]");
+ if (cmpWhat.length() > 0 && '.' == cmpWhat.charAt(0)) {
+ cmpWhat = cmpWhat.substring(1);
+ }
+ }
+ // 处理排序
+ asc = true;
+ if (Strings.contains(cmpWhat, ' ')) {
+ if (Strings.contains(cmpWhat, " desc")) {
+ asc = false;
+ }
+ cmpWhat = cmpWhat.substring(0, cmpWhat.indexOf(' '));
+ }
+ stringComparator = new CollatorStringComparator(asc);
+ }
+
+ /**
+ * <p>
+ * Constructor for PropertyComparator.
+ * </p>
+ *
+ * @param cmpWhat a {@link java.lang.String} object.
+ * @param asc a boolean.
+ */
+ public PropertyComparator(final String cmpWhat, final boolean asc) {
+ this(cmpWhat + " " + (asc ? "" : "desc"));
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("unchecked")
+ public int compare(Object arg0, Object arg1) {
+ Object what0 = null;
+ Object what1 = null;
+ // 取出属性
+ if (index > -1) {
+ arg0 = ((Object[]) arg0)[index];
+ arg1 = ((Object[]) arg1)[index];
+ if (Strings.isEmpty(cmpWhat)) {
+ what0 = arg0;
+ what1 = arg1;
+ }
+ }
+ if (Strings.isNotEmpty(cmpWhat)) {
+ what0 = PropertyUtils.getProperty(arg0, cmpWhat);
+ what1 = PropertyUtils.getProperty(arg1, cmpWhat);
+ }
+
+ if (what0 == null && null == what1) { return 0; }
+
+ // 进行比较
+ if (null == comparator) {
+ if (what0 == null && null != what1) { return asc && nullFirst ? -1 : 1; }
+
+ if (what0 != null && null == what1) { return asc && nullFirst ? 1 : -1; }
+ // 进行字符串比较
+ if (what0 instanceof String || what1 instanceof String) {
+ return stringComparator.compare(what0.toString(), what1.toString());
+ } else {
+ if (asc) {
+ return ((Comparable<Object>) what0).compareTo(what1);
+ } else {
+ return ((Comparable<Object>) what1).compareTo(what0);
+ }
+ }
+ } else {
+ // return doCompare(comparator,what0,what1);
+ return comparator.compare(what0, what1);
+ }
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>comparator</code>.
+ * </p>
+ *
+ * @return a {@link java.util.Comparator} object.
+ */
+ @SuppressWarnings("rawtypes")
+ public Comparator getComparator() {
+ return comparator;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>comparator</code>.
+ * </p>
+ *
+ * @param comparator a {@link java.util.Comparator} object.
+ */
+ @SuppressWarnings("rawtypes")
+ public void setComparator(final Comparator comparator) {
+ this.comparator = comparator;
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>stringComparator</code>.
+ * </p>
+ *
+ * @return a {@link com.ekingstar.commons.bean.comparators.StringComparator} object.
+ */
+ public StringComparator getStringComparator() {
+ return stringComparator;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>stringComparator</code>.
+ * </p>
+ *
+ * @param stringComparator a {@link com.ekingstar.commons.bean.comparators.StringComparator} object.
+ */
+ public void setStringComparator(final StringComparator stringComparator) {
+ this.stringComparator = stringComparator;
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>cmpWhat</code>.
+ * </p>
+ *
+ * @return a {@link java.lang.String} object.
+ */
+ public String getCmpWhat() {
+ return cmpWhat;
+ }
+
+ /**
+ * <p>
+ * isAsc.
+ * </p>
+ *
+ * @return a boolean.
+ */
+ public boolean isAsc() {
+ return asc;
+ }
+
+ /**
+ * <p>
+ * isNullFirst.
+ * </p>
+ *
+ * @return a boolean.
+ */
+ public boolean isNullFirst() {
+ return nullFirst;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>nullFirst</code>.
+ * </p>
+ *
+ * @param nullFirst a boolean.
+ */
+ public void setNullFirst(boolean nullFirst) {
+ this.nullFirst = nullFirst;
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/StringComparator.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/StringComparator.java
new file mode 100755
index 0000000..8fef168
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/comparators/StringComparator.java
@@ -0,0 +1,31 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean.comparators;
+
+import java.util.Comparator;
+
+/**
+ * 根据local对两个非空字符串进行比较。
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public interface StringComparator extends Comparator<String> {
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/package-info.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/package-info.java
new file mode 100644
index 0000000..a08c226
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/package-info.java
@@ -0,0 +1,10 @@
+/**
+ * Commons bean interfaces .Some comparator and converters.
+ * It offers
+ * <ul>
+ * <li>Bean lifecyle interface(Initializing,Disposable),it could be integrated with IOC container.
+ * <li>Comparators,PropertyComparator,ChainComparator etc.
+ * <li>Converters,Date,Enum to String and vice versa.
+ * </ul>
+ */
+package com.ekingstar.commons.bean;
\ No newline at end of file
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/predicates/PropertyEqualPredicate.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/predicates/PropertyEqualPredicate.java
new file mode 100755
index 0000000..b6dd241
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/predicates/PropertyEqualPredicate.java
@@ -0,0 +1,62 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean.predicates;
+
+import com.ekingstar.commons.bean.PropertyUtils;
+import com.ekingstar.commons.lang.Assert;
+import com.ekingstar.commons.lang.Objects;
+import com.ekingstar.commons.lang.functor.Predicate;
+
+/**
+ * Property Equals Predicate
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class PropertyEqualPredicate<T> implements Predicate<T> {
+ private String propertyName;
+ private Object propertyValue;
+
+ /**
+ * <p>
+ * Constructor for PropertyEqualPredicate.
+ * </p>
+ *
+ * @param propertyName a {@link java.lang.String} object.
+ * @param propertyValue a {@link java.lang.Object} object.
+ */
+ public PropertyEqualPredicate(String propertyName, Object propertyValue) {
+ Assert.notEmpty(propertyName);
+ this.propertyName = propertyName;
+ this.propertyValue = propertyValue;
+ }
+
+ /**
+ * <p>
+ * evaluate.
+ * </p>
+ *
+ * @param arg0 a {@link java.lang.Object} object.
+ * @return a boolean.
+ */
+ public Boolean apply(T arg0) {
+ return Objects.equals(PropertyUtils.getProperty(arg0, propertyName), propertyValue);
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/bean/transformers/PropertyTransformer.java b/tools/commons/src/main/java/com/ekingstar/commons/bean/transformers/PropertyTransformer.java
new file mode 100755
index 0000000..669b951
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/bean/transformers/PropertyTransformer.java
@@ -0,0 +1,82 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean.transformers;
+
+import com.ekingstar.commons.bean.PropertyUtils;
+import com.ekingstar.commons.lang.functor.Transformer;
+
+/**
+ * bean属性提取器<br>
+ * CollectionUtils.transform(collections,new PropertyTransformer('myAttr'))
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class PropertyTransformer implements Transformer<Object, Object> {
+
+ private String property;
+
+ /**
+ * <p>
+ * Constructor for PropertyTransformer.
+ * </p>
+ *
+ * @param property a {@link java.lang.String} object.
+ */
+ public PropertyTransformer(final String property) {
+ super();
+ this.property = property;
+ }
+
+ /**
+ * <p>
+ * Constructor for PropertyTransformer.
+ * </p>
+ */
+ public PropertyTransformer() {
+ super();
+ }
+
+ public Object apply(final Object arg0) {
+ return PropertyUtils.getProperty(arg0, property);
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>property</code>.
+ * </p>
+ *
+ * @return a {@link java.lang.String} object.
+ */
+ public String getProperty() {
+ return property;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>property</code>.
+ * </p>
+ *
+ * @param property a {@link java.lang.String} object.
+ */
+ public void setProperty(final String property) {
+ this.property = property;
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/collection/CollectUtils.java b/tools/commons/src/main/java/com/ekingstar/commons/collection/CollectUtils.java
new file mode 100755
index 0000000..14ff4c7
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/collection/CollectUtils.java
@@ -0,0 +1,437 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.collection;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+
+import com.ekingstar.commons.bean.PropertyUtils;
+import com.ekingstar.commons.lang.Throwables;
+import com.ekingstar.commons.lang.functor.Predicate;
+import com.ekingstar.commons.lang.functor.Transformer;
+
+/**
+ * <p>
+ * CollectUtils class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public final class CollectUtils {
+
+ /**
+ * <p>
+ * newArrayList.
+ * </p>
+ *
+ * @param <E> a E object.
+ * @return a {@link java.util.List} object.
+ */
+ public static <E> List<E> newArrayList() {
+ return new ArrayList<E>();
+ }
+
+ /**
+ * <p>
+ * newArrayList.
+ * </p>
+ *
+ * @param initialCapacity a int.
+ * @param <E> a E object.
+ * @return a {@link java.util.List} object.
+ */
+ public static <E> List<E> newArrayList(int initialCapacity) {
+ return new ArrayList<E>(initialCapacity);
+ }
+
+ /**
+ * <p>
+ * newArrayList.
+ * </p>
+ *
+ * @param c a {@link java.util.Collection} object.
+ * @param <E> a E object.
+ * @return a {@link java.util.List} object.
+ */
+ public static <E> List<E> newArrayList(Collection<? extends E> c) {
+ return new ArrayList<E>(c);
+ }
+
+ /**
+ * <p>
+ * newArrayList.
+ * </p>
+ *
+ * @param values a E object.
+ * @param <E> a E object.
+ * @return a {@link java.util.List} object.
+ */
+ public static <E> List<E> newArrayList(E... values) {
+ List<E> list = new ArrayList<E>(values.length);
+ for (E e : values) {
+ list.add(e);
+ }
+ return list;
+ }
+
+ /**
+ * 将一个集合按照固定大小查分成若干个集合。
+ *
+ * @param list a {@link java.util.List} object.
+ * @param count a int.
+ * @param <T> a T object.
+ * @return a {@link java.util.List} object.
+ */
+ public static <T> List<List<T>> split(final List<T> list, final int count) {
+ List<List<T>> subIdLists = CollectUtils.newArrayList();
+ if (list.size() < count) {
+ subIdLists.add(list);
+ } else {
+ int i = 0;
+ while (i < list.size()) {
+ int end = i + count;
+ if (end > list.size()) {
+ end = list.size();
+ }
+ subIdLists.add(list.subList(i, end));
+ i += count;
+ }
+ }
+ return subIdLists;
+ }
+
+ /**
+ * <p>
+ * newHashMap.
+ * </p>
+ *
+ * @param <K> a K object.
+ * @param <V> a V object.
+ * @return a {@link java.util.Map} object.
+ */
+ public static <K, V> Map<K, V> newHashMap() {
+ return new HashMap<K, V>();
+ }
+
+ public static <K, V> FastHashMap<K, V> newFastMap() {
+ return new FastHashMap<K, V>();
+ }
+
+ public static <K, V> FastHashMap<K, V> newFastMap(int capacity) {
+ return new FastHashMap<K, V>(capacity);
+ }
+
+ /**
+ * <p>
+ * newConcurrentHashMap.
+ * </p>
+ *
+ * @param <K> a K object.
+ * @param <V> a V object.
+ * @return a {@link java.util.Map} object.
+ */
+ public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap() {
+ return new ConcurrentHashMap<K, V>();
+ }
+
+ /**
+ * <p>
+ * newConcurrentLinkedQueue.
+ * </p>
+ *
+ * @param <E> a E object.
+ * @return a {@link java.util.Queue} object.
+ */
+ public static <E> Queue<E> newConcurrentLinkedQueue() {
+ return new ConcurrentLinkedQueue<E>();
+ }
+
+ /**
+ * <p>
+ * newHashMap.
+ * </p>
+ *
+ * @param m a {@link java.util.Map} object.
+ * @param <K> a K object.
+ * @param <V> a V object.
+ * @return a {@link java.util.Map} object.
+ */
+ public static <K, V> Map<K, V> newHashMap(Map<? extends K, ? extends V> m) {
+ return new HashMap<K, V>(m);
+ }
+
+ /**
+ * <p>
+ * newLinkedHashMap.
+ * </p>
+ *
+ * @param m a {@link java.util.Map} object.
+ * @param <K> a K object.
+ * @param <V> a V object.
+ * @return a {@link java.util.Map} object.
+ */
+ public static <K, V> Map<K, V> newLinkedHashMap(Map<? extends K, ? extends V> m) {
+ return new LinkedHashMap<K, V>(m);
+ }
+
+ /**
+ * <p>
+ * newLinkedHashMap.
+ * </p>
+ *
+ * @param size a int.
+ * @param <K> a K object.
+ * @param <V> a V object.
+ * @return a {@link java.util.Map} object.
+ */
+ public static <K, V> Map<K, V> newLinkedHashMap(int size) {
+ return new LinkedHashMap<K, V>(size);
+ }
+
+ /**
+ * <p>
+ * newHashSet.
+ * </p>
+ *
+ * @param <E> a E object.
+ * @return a {@link java.util.Set} object.
+ */
+ public static <E> Set<E> newHashSet() {
+ return new HashSet<E>();
+ }
+
+ /**
+ * <p>
+ * newHashSet.
+ * </p>
+ *
+ * @param values a E object.
+ * @param <E> a E object.
+ * @return a {@link java.util.Set} object.
+ */
+ public static <E> Set<E> newHashSet(E... values) {
+ Set<E> set = new HashSet<E>(values.length);
+ for (E e : values) {
+ set.add(e);
+ }
+ return set;
+ }
+
+ /**
+ * <p>
+ * newHashSet.
+ * </p>
+ *
+ * @param c a {@link java.util.Collection} object.
+ * @param <E> a E object.
+ * @return a {@link java.util.Set} object.
+ */
+ public static <E> Set<E> newHashSet(Collection<? extends E> c) {
+ return new HashSet<E>(c);
+ }
+
+ /**
+ * <p>
+ * convertToMap.
+ * </p>
+ *
+ * @param coll a {@link java.util.Collection} object.
+ * @param keyProperty a {@link java.lang.String} object.
+ * @return a {@link java.util.Map} object.
+ */
+ public static Map<?, ?> convertToMap(Collection<?> coll, String keyProperty) {
+ Map<Object, Object> map = newHashMap();
+ for (Object obj : coll) {
+ Object key = null;
+ try {
+ key = PropertyUtils.getProperty(obj, keyProperty);
+ } catch (Exception e) {
+ Throwables.propagate(e);
+ }
+ map.put(key, obj);
+ }
+ return map;
+ }
+
+ /**
+ * <p>
+ * convertToMap.
+ * </p>
+ *
+ * @param coll a {@link java.util.Collection} object.
+ * @param keyProperty a {@link java.lang.String} object.
+ * @param valueProperty a {@link java.lang.String} object.
+ * @return a {@link java.util.Map} object.
+ */
+ public static Map<?, ?> convertToMap(Collection<?> coll, String keyProperty, String valueProperty) {
+ Map<Object, Object> map = newHashMap();
+ for (Object obj : coll) {
+ Object key = PropertyUtils.getProperty(obj, keyProperty);
+ Object value = PropertyUtils.getProperty(obj, valueProperty);
+ if (null != key) map.put(key, value);
+ }
+ return map;
+ }
+
+ /**
+ * <p>
+ * toMap.
+ * </p>
+ *
+ * @param wordMappings an array of {@link java.lang.String} objects.
+ * @return a {@link java.util.Map} object.
+ */
+ public static Map<String, String> toMap(String[]... wordMappings) {
+ Map<String, String> mappings = new HashMap<String, String>();
+ for (int i = 0; i < wordMappings.length; i++) {
+ String singular = wordMappings[i][0];
+ String plural = wordMappings[i][1];
+ mappings.put(singular, plural);
+ }
+ return mappings;
+ }
+
+ /**
+ * Null-safe check if the specified collection is empty.
+ * <p>
+ * Null returns true.
+ *
+ * @param coll the collection to check, may be null
+ * @return true if empty or null
+ * @since 3.1
+ */
+ public static boolean isEmpty(Collection<?> coll) {
+ return (coll == null || coll.isEmpty());
+ }
+
+ /**
+ * Null-safe check if the specified collection is not empty.
+ * <p>
+ * Null returns false.
+ *
+ * @param coll the collection to check, may be null
+ * @return true if non-null and non-empty
+ * @since 3.1
+ */
+ public static boolean isNotEmpty(Collection<?> coll) {
+ return null != coll && !coll.isEmpty();
+ }
+
+ public static <T> List<T> union(List<T> first, List<T> second) {
+ Map<T, Integer> mapa = getCardinalityMap(first), mapb = getCardinalityMap(second);
+ Set<T> elts = new HashSet<T>(first);
+ elts.addAll(second);
+ List<T> list = newArrayList();
+ for (T obj : elts)
+ for (int i = 0, m = Math.max(getFreq(obj, mapa), getFreq(obj, mapb)); i < m; i++)
+ list.add(obj);
+ return list;
+
+ }
+
+ public static <T> Map<T, Integer> getCardinalityMap(final List<T> coll) {
+ Map<T, Integer> count = newHashMap();
+ for (Iterator<T> it = coll.iterator(); it.hasNext();) {
+ T obj = it.next();
+ Integer c = (count.get(obj));
+ if (c == null) count.put(obj, Integer.valueOf(1));
+ else count.put(obj, new Integer(c.intValue() + 1));
+ }
+ return count;
+ }
+
+ private static final <T> int getFreq(final T obj, final Map<T, Integer> freqMap) {
+ Integer count = freqMap.get(obj);
+ return (count != null) ? count.intValue() : 0;
+ }
+
+ public static <T> List<T> intersection(List<T> first, List<T> second) {
+ List<T> list = CollectUtils.newArrayList();
+ Map<T, Integer> mapa = getCardinalityMap(first), mapb = getCardinalityMap(second);
+ Set<T> elts = new HashSet<T>(first);
+ elts.addAll(second);
+ for (T obj : elts)
+ for (int i = 0, m = Math.min(getFreq(obj, mapa), getFreq(obj, mapb)); i < m; i++)
+ list.add(obj);
+ return list;
+ }
+
+ public static <T> Set<T> intersection(Set<T> first, Set<T> second) {
+ Set<T> elts = CollectUtils.newHashSet();
+ for (T obj : first)
+ if (second.contains(second)) elts.add(obj);
+ return elts;
+ }
+
+ public static <T> List<T> subtract(List<T> first, List<T> second) {
+ List<T> list = newArrayList(first);
+ for (T t : second)
+ list.remove(t);
+ return list;
+ }
+
+ public static <T> Set<T> subtract(final Set<T> a, final Set<T> b) {
+ Set<T> set = CollectUtils.newHashSet(a);
+ set.removeAll(b);
+ return set;
+ }
+
+ public static <T> void filter(Collection<T> datas, Predicate<T> predicate) {
+ for (Iterator<T> it = datas.iterator(); it.hasNext();)
+ if (!predicate.apply(it.next())) it.remove();
+ }
+
+ public static <T> List<T> select(List<T> datas, Predicate<T> predicate) {
+ List<T> rs = CollectUtils.newArrayList();
+ for (T t : datas)
+ if (predicate.apply(t)) rs.add(t);
+ return rs;
+ }
+
+ public static <T> Set<T> select(Set<T> datas, Predicate<T> predicate) {
+ Set<T> rs = CollectUtils.newHashSet();
+ for (T t : datas)
+ if (predicate.apply(t)) rs.add(t);
+ return rs;
+ }
+
+ public static <R> List<R> collect(Collection<?> datas, Transformer<?, ?> transformer) {
+ @SuppressWarnings("unchecked")
+ Transformer<Object, R> objTransformer = (Transformer<Object, R>) transformer;
+ List<R> rs = new ArrayList<R>();
+ for (Object t : datas) {
+ R value = objTransformer.apply(t);
+ rs.add(value);
+ }
+ return rs;
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/collection/FastHashMap.java b/tools/commons/src/main/java/com/ekingstar/commons/collection/FastHashMap.java
new file mode 100644
index 0000000..2f8c870
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/collection/FastHashMap.java
@@ -0,0 +1,915 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.collection;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.AbstractCollection;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public final class FastHashMap<K, V> implements Map<K, V>, Cloneable, Serializable {
+ private static final long serialVersionUID = -1340573582218930052L;
+
+ /**
+ * Holds the map's hash table.
+ */
+ private transient EntryImpl<K, V>[] _entries;
+
+ /**
+ * Holds the map's current capacity.
+ */
+ private transient int _capacity;
+
+ /**
+ * Holds the hash code mask.
+ */
+ private transient int _mask;
+
+ /**
+ * Holds the first pool entry (linked list).
+ */
+ private transient EntryImpl<K, V> _poolFirst;
+
+ /**
+ * Holds the first map entry (linked list).
+ */
+ private transient EntryImpl<K, V> _mapFirst;
+
+ /**
+ * Holds the last map entry (linked list).
+ */
+ private transient EntryImpl<K, V> _mapLast;
+
+ /**
+ * Holds the current size.
+ */
+ private transient int _size;
+
+ /**
+ * Creates a {@link FastMap} with a capacity of <code>256</code> entries.
+ */
+ public FastHashMap() {
+ initialize(256);
+ }
+
+ /**
+ * Creates a {@link FastMap}, copy of the specified <code>Map</code>.
+ * If the specified map is not an instance of {@link FastMap}, the
+ * newly created map has a capacity set to the specified map's size.
+ * The copy has the same order as the original, regardless of the original
+ * map's implementation:
+ *
+ * <pre>
+ * TreeMap dictionary = ...;
+ * FastMap dictionaryLookup = new FastMap(dictionary);
+ * </pre>
+ *
+ * @param map the map whose mappings are to be placed in this map.
+ */
+ public FastHashMap(Map<K, V> map) {
+ int capacity = (map instanceof FastHashMap) ? ((FastHashMap<K, V>) map).capacity() : map.size();
+ initialize(capacity);
+ putAll(map);
+ }
+
+ /**
+ * Creates a {@link FastMap} with the specified capacity. Unless the
+ * capacity is exceeded, operations on this map do not allocate entries.
+ * For optimum performance, the capacity should be of the same order
+ * of magnitude or larger than the expected map's size.
+ *
+ * @param capacity the number of buckets in the hash table; it also
+ * defines the number of pre-allocated entries.
+ */
+ public FastHashMap(int capacity) {
+ initialize(capacity);
+ }
+
+ /**
+ * Returns the number of key-value mappings in this {@link FastMap}.
+ *
+ * @return this map's size.
+ */
+ public int size() {
+ return _size;
+ }
+
+ /**
+ * Returns the capacity of this {@link FastMap}. The capacity defines
+ * the number of buckets in the hash table, as well as the maximum number
+ * of entries the map may contain without allocating memory.
+ *
+ * @return this map's capacity.
+ */
+ public int capacity() {
+ return _capacity;
+ }
+
+ /**
+ * Indicates if this {@link FastMap} contains no key-value mappings.
+ *
+ * @return <code>true</code> if this map contains no key-value mappings; <code>false</code>
+ * otherwise.
+ */
+ public boolean isEmpty() {
+ return _size == 0;
+ }
+
+ /**
+ * Indicates if this {@link FastMap} contains a mapping for the specified
+ * key.
+ *
+ * @param key the key whose presence in this map is to be tested.
+ * @return <code>true</code> if this map contains a mapping for the
+ * specified key; <code>false</code> otherwise.
+ * @throws NullPointerException if the key is <code>null</code>.
+ */
+ public boolean containsKey(Object key) {
+ EntryImpl<K, V> entry = _entries[keyHash(key) & _mask];
+ while (entry != null) {
+ if (key.equals(entry._key)) { return true; }
+ entry = entry._next;
+ }
+ return false;
+ }
+
+ /**
+ * Indicates if this {@link FastMap} maps one or more keys to the
+ * specified value.
+ *
+ * @param value the value whose presence in this map is to be tested.
+ * @return <code>true</code> if this map maps one or more keys to the
+ * specified value.
+ * @throws NullPointerException if the key is <code>null</code>.
+ */
+ public boolean containsValue(Object value) {
+ EntryImpl<K, V> entry = _mapFirst;
+ while (entry != null) {
+ if (value.equals(entry._value)) { return true; }
+ entry = entry._after;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the value to which this {@link FastMap} maps the specified key.
+ *
+ * @param key the key whose associated value is to be returned.
+ * @return the value to which this map maps the specified key,
+ * or <code>null</code> if there is no mapping for the key.
+ * @throws NullPointerException if key is <code>null</code>.
+ */
+ public V get(Object key) {
+ EntryImpl<K, V> entry = _entries[keyHash(key) & _mask];
+ while (entry != null) {
+ if (key == entry._key || key.equals(entry._key)) return entry._value;
+ entry = entry._next;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the entry with the specified key.
+ *
+ * @param key the key whose associated entry is to be returned.
+ * @return the entry for the specified key or <code>null</code> if none.
+ */
+ public Map.Entry<K, V> getEntry(Object key) {
+ EntryImpl<K, V> entry = _entries[keyHash(key) & _mask];
+ while (entry != null) {
+ if (key.equals(entry._key)) { return entry; }
+ entry = entry._next;
+ }
+ return null;
+ }
+
+ /**
+ * Associates the specified value with the specified key in this {@link FastMap}. If the
+ * {@link FastMap} previously contained a mapping
+ * for this key, the old value is replaced.
+ *
+ * @param key the key with which the specified value is to be associated.
+ * @param value the value to be associated with the specified key.
+ * @return the previous value associated with specified key,
+ * or <code>null</code> if there was no mapping for key.
+ * A <code>null</code> return can also indicate that the map
+ * previously associated <code>null</code> with the specified key.
+ * @throws NullPointerException if the key is <code>null</code>.
+ */
+ public V put(K key, V value) {
+ EntryImpl<K, V> entry = _entries[keyHash(key) & _mask];
+ while (entry != null) {
+ if (key.equals(entry._key)) {
+ V prevValue = entry._value;
+ entry._value = value;
+ return prevValue;
+ }
+ entry = entry._next;
+ }
+ // No previous mapping.
+ addEntry(key, value);
+ return null;
+ }
+
+ /**
+ * Copies all of the mappings from the specified map to this {@link FastMap}.
+ *
+ * @param map the mappings to be stored in this map.
+ * @throws NullPointerException the specified map is <code>null</code>, or
+ * the specified map contains <code>null</code> keys.
+ */
+ public void putAll(Map<? extends K, ? extends V> map) {
+ for (Map.Entry<? extends K, ? extends V> e : map.entrySet()) {
+ addEntry(e.getKey(), e.getValue());
+ }
+ }
+
+ /**
+ * Removes the mapping for this key from this {@link FastMap} if present.
+ *
+ * @param key the key whose mapping is to be removed from the map.
+ * @return previous value associated with specified key,
+ * or <code>null</code> if there was no mapping for key.
+ * A <code>null</code> return can also indicate that the map
+ * previously associated <code>null</code> with the specified key.
+ * @throws NullPointerException if the key is <code>null</code>.
+ */
+ public V remove(Object key) {
+ EntryImpl<K, V> entry = _entries[keyHash(key) & _mask];
+ while (entry != null) {
+ if (key.equals(entry._key)) {
+ V prevValue = entry._value;
+ removeEntry(entry);
+ return prevValue;
+ }
+ entry = entry._next;
+ }
+ return null;
+ }
+
+ /**
+ * Removes all mappings from this {@link FastMap}.
+ */
+ public void clear() {
+ // Clears all keys, values and buckets linked lists.
+ for (EntryImpl<K, V> entry = _mapFirst; entry != null; entry = entry._after) {
+ entry._key = null;
+ entry._value = null;
+ entry._before = null;
+ entry._next = null;
+ if (entry._previous == null) { // First in bucket.
+ _entries[entry._index] = null;
+ } else {
+ entry._previous = null;
+ }
+ }
+
+ // Recycles all entries.
+ if (_mapLast != null) {
+ _mapLast._after = _poolFirst; // Connects to pool.
+ _poolFirst = _mapFirst;
+ _mapFirst = null;
+ _mapLast = null;
+ _size = 0;
+ sizeChanged();
+ }
+ }
+
+ /**
+ * Changes the current capacity of this {@link FastMap}. If the capacity
+ * is increased, new entries are allocated and added to the pool.
+ * If the capacity is decreased, entries from the pool are deallocated
+ * (and are eventually garbage collected). The capacity also determined
+ * the number of buckets for the hash table.
+ *
+ * @param newCapacity the new capacity of this map.
+ */
+ @SuppressWarnings("unchecked")
+ public void setCapacity(int newCapacity) {
+ if (newCapacity > _capacity) { // Capacity increases.
+ for (int i = _capacity; i < newCapacity; i++) {
+ EntryImpl<K, V> entry = new EntryImpl<K, V>();
+ entry._after = _poolFirst;
+ _poolFirst = entry;
+ }
+ } else if (newCapacity < _capacity) { // Capacity decreases.
+ for (int i = newCapacity; (i < _capacity) && (_poolFirst != null); i++) {
+ // Disconnects the entry for gc to do its work.
+ EntryImpl<K, V> entry = _poolFirst;
+ _poolFirst = entry._after;
+ entry._after = null; // All pointers are now null!
+ }
+ }
+ // Find a power of 2 >= capacity
+ int tableLength = 16;
+ while (tableLength < newCapacity) {
+ tableLength <<= 1;
+ }
+ // Checks if the hash table has to be re-sized.
+ if (_entries.length != tableLength) {
+ _entries = new EntryImpl[tableLength];
+ _mask = tableLength - 1;
+
+ // Repopulates the hash table.
+ EntryImpl<K, V> entry = _mapFirst;
+ while (entry != null) {
+ int index = keyHash(entry._key) & _mask;
+ entry._index = index;
+
+ // Connects to bucket.
+ entry._previous = null; // Resets previous.
+ EntryImpl<K, V> next = _entries[index];
+ entry._next = next;
+ if (next != null) {
+ next._previous = entry;
+ }
+ _entries[index] = entry;
+
+ entry = entry._after;
+ }
+ }
+ _capacity = newCapacity;
+ }
+
+ /**
+ * Returns a shallow copy of this {@link FastMap}. The keys and
+ * the values themselves are not cloned.
+ *
+ * @return a shallow copy of this map.
+ */
+ @SuppressWarnings("unchecked")
+ public Object clone() {
+ try {
+ FastHashMap<K, V> clone = (FastHashMap<K, V>) super.clone();
+ clone.initialize(_capacity);
+ clone.putAll(this);
+ return clone;
+ } catch (CloneNotSupportedException e) {
+ // Should not happen, since we are Cloneable.
+ throw new InternalError();
+ }
+ }
+
+ /**
+ * Compares the specified object with this {@link FastMap} for equality.
+ * Returns <code>true</code> if the given object is also a map and the two
+ * maps represent the same mappings (regardless of collection iteration
+ * order).
+ *
+ * @param obj the object to be compared for equality with this map.
+ * @return <code>true</code> if the specified object is equal to this map; <code>false</code>
+ * otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (obj instanceof Map) {
+ @SuppressWarnings("unchecked")
+ Map<K, V> that = (Map<K, V>) obj;
+ if (this.size() == that.size()) {
+ EntryImpl<K, V> entry = _mapFirst;
+ while (entry != null) {
+ if (!that.entrySet().contains(entry)) { return false; }
+ entry = entry._after;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the hash code value for this {@link FastMap}.
+ *
+ * @return the hash code value for this map.
+ */
+ public int hashCode() {
+ int code = 0;
+ EntryImpl<K, V> entry = _mapFirst;
+ while (entry != null) {
+ code += entry.hashCode();
+ entry = entry._after;
+ }
+ return code;
+ }
+
+ /**
+ * Returns a <code>String</code> representation of this {@link FastMap}.
+ *
+ * @return <code>this.entrySet().toString();</code>
+ */
+ public String toString() {
+ return entrySet().toString();
+ }
+
+ /**
+ * Returns a collection view of the values contained in this {@link FastMap}. The collection is
+ * backed by the map, so changes to
+ * the map are reflected in the collection, and vice-versa.
+ * The collection supports element removal, which removes the corresponding
+ * mapping from this map, via the <code>Iterator.remove</code>, <code>Collection.remove</code>,
+ * <code>removeAll</code>, <code>retainAll</code>,
+ * and <code>clear</code> operations. It does not support the <code>add</code> or
+ * <code>addAll</code> operations.
+ *
+ * @return a collection view of the values contained in this map.
+ */
+ public Collection<V> values() {
+ return _values;
+ }
+
+ private transient Values _values;
+
+ private class Values extends AbstractCollection<V> {
+ public Iterator<V> iterator() {
+ return new Iterator<V>() {
+ EntryImpl<K, V> after = _mapFirst;
+ EntryImpl<K, V> before;
+
+ public void remove() {
+ removeEntry(before);
+ }
+
+ public boolean hasNext() {
+ return after != null;
+ }
+
+ public V next() {
+ before = after;
+ after = after._after;
+ return before._value;
+ }
+ };
+ }
+
+ public int size() {
+ return _size;
+ }
+
+ public boolean contains(Object o) {
+ return containsValue(o);
+ }
+
+ public void clear() {
+ FastHashMap.this.clear();
+ }
+ }
+
+ /**
+ * Returns a collection view of the mappings contained in this {@link FastMap}. Each element in
+ * the returned collection is a <code>Map.Entry</code>. The collection is backed by the map,
+ * so changes to the map are reflected in the collection, and vice-versa.
+ * The collection supports element removal, which removes the corresponding
+ * mapping from this map, via the <code>Iterator.remove</code>, <code>Collection.remove</code>,
+ * <code>removeAll</code>, <code>retainAll</code>,
+ * and <code>clear</code> operations. It does not support the <code>add</code> or
+ * <code>addAll</code> operations.
+ *
+ * @return a collection view of the mappings contained in this map.
+ */
+ public Set<Map.Entry<K, V>> entrySet() {
+ return _entrySet;
+ }
+
+ private transient EntrySet _entrySet;
+
+ private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
+ public Iterator<Map.Entry<K, V>> iterator() {
+ return new Iterator<Map.Entry<K, V>>() {
+ EntryImpl<K, V> after = _mapFirst;
+ EntryImpl<K, V> before;
+
+ public void remove() {
+ removeEntry(before);
+ }
+
+ public boolean hasNext() {
+ return after != null;
+ }
+
+ public Map.Entry<K, V> next() {
+ before = after;
+ after = after._after;
+ return before;
+ }
+ };
+ }
+
+ public int size() {
+ return _size;
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean contains(Object obj) { // Optimization.
+ if (obj instanceof Map.Entry) {
+ Map.Entry<K, V> entry = (Map.Entry<K, V>) obj;
+ Map.Entry<K, V> mapEntry = getEntry(entry.getKey());
+ return entry.equals(mapEntry);
+ } else {
+ return false;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean remove(Object obj) { // Optimization.
+ if (obj instanceof Map.Entry) {
+ Map.Entry<K, V> entry = (Map.Entry<K, V>) obj;
+ EntryImpl<K, V> mapEntry = (EntryImpl<K, V>) getEntry(entry.getKey());
+ if ((mapEntry != null) && (entry.getValue()).equals(mapEntry._value)) {
+ removeEntry(mapEntry);
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Returns a set view of the keys contained in this {@link FastMap}.
+ * The set is backed by the map, so changes to the map are reflected
+ * in the set, and vice-versa. The set supports element removal,
+ * which removes the corresponding mapping from this map, via the <code>Iterator.remove</code>,
+ * <code>Collection.remove</code>, <code>removeAll</code>, <code>retainAll</code>,
+ * and <code>clear</code> operations. It does not support the <code>add</code> or
+ * <code>addAll</code> operations.
+ *
+ * @return a set view of the keys contained in this map.
+ */
+ public Set<K> keySet() {
+ return _keySet;
+ }
+
+ private transient KeySet _keySet;
+
+ private class KeySet extends AbstractSet<K> {
+ public Iterator<K> iterator() {
+ return new Iterator<K>() {
+ EntryImpl<K, V> after = _mapFirst;
+ EntryImpl<K, V> before;
+
+ public void remove() {
+ removeEntry(before);
+ }
+
+ public boolean hasNext() {
+ return after != null;
+ }
+
+ public K next() {
+ before = after;
+ after = after._after;
+ return before._key;
+ }
+ };
+ }
+
+ public int size() {
+ return _size;
+ }
+
+ public boolean contains(Object obj) { // Optimization.
+ return FastHashMap.this.containsKey(obj);
+ }
+
+ public boolean remove(Object obj) { // Optimization.
+ return FastHashMap.this.remove(obj) != null;
+ }
+
+ public void clear() { // Optimization.
+ FastHashMap.this.clear();
+ }
+ }
+
+ /**
+ * This methods is being called when the size of this {@link FastMap} has changed. The default
+ * behavior is to double the map's capacity
+ * when the map's size reaches the current map's capacity.
+ * Sub-class may override this method to implement custom resizing
+ * policies or to disable automatic resizing. For example:
+ *
+ * <pre>
+ * Map fixedCapacityMap = new FastMap(256) {
+ * protected sizeChanged() {
+ * // Do nothing, automatic resizing disabled.
+ * }
+ * };
+ * </pre>
+ *
+ * @see #setCapacity
+ */
+ protected void sizeChanged() {
+ if (size() > capacity()) {
+ setCapacity(capacity() * 2);
+ }
+ }
+
+ /**
+ * Returns the the key's hash code.
+ *
+ * @param key the key to calculate the hashcode for.
+ * @return the hash code for the specified key.
+ */
+
+ private static final int keyHash(Object key) {
+ return key.hashCode();
+ }
+
+ /**
+ * Adds a new entry for the specified key and value.
+ *
+ * @param key the entry's key.
+ * @param value the entry's value.
+ */
+ private void addEntry(K key, V value) {
+ EntryImpl<K, V> entry = _poolFirst;
+ if (entry != null) {
+ _poolFirst = entry._after;
+ entry._after = null;
+ } else { // Pool empty.
+ entry = new EntryImpl<K, V>();
+ }
+
+ // Setup entry paramters.
+ entry._key = key;
+ entry._value = value;
+ int index = keyHash(key) & _mask;
+ entry._index = index;
+
+ // Connects to bucket.
+ EntryImpl<K, V> next = _entries[index];
+ entry._next = next;
+ if (next != null) {
+ next._previous = entry;
+ }
+ _entries[index] = entry;
+
+ // Connects to collection.
+ if (_mapLast != null) {
+ entry._before = _mapLast;
+ _mapLast._after = entry;
+ } else {
+ _mapFirst = entry;
+ }
+ _mapLast = entry;
+
+ // Updates size.
+ _size++;
+ sizeChanged();
+ }
+
+ /**
+ * Removes the specified entry from the map.
+ *
+ * @param entry the entry to be removed.
+ */
+ private void removeEntry(EntryImpl<K, V> entry) {
+
+ // Removes from bucket.
+ EntryImpl<K, V> previous = entry._previous;
+ EntryImpl<K, V> next = entry._next;
+ if (previous != null) {
+ previous._next = next;
+ entry._previous = null;
+ } else { // First in bucket.
+ _entries[entry._index] = next;
+ }
+ if (next != null) {
+ next._previous = previous;
+ entry._next = null;
+ } // Else do nothing, no last pointer.
+
+ // Removes from collection.
+ EntryImpl<K, V> before = entry._before;
+ EntryImpl<K, V> after = entry._after;
+ if (before != null) {
+ before._after = after;
+ entry._before = null;
+ } else { // First in collection.
+ _mapFirst = after;
+ }
+ if (after != null) {
+ after._before = before;
+ } else { // Last in collection.
+ _mapLast = before;
+ }
+
+ // Clears value and key.
+ entry._key = null;
+ entry._value = null;
+
+ // Recycles.
+ entry._after = _poolFirst;
+ _poolFirst = entry;
+
+ // Updates size.
+ _size--;
+ sizeChanged();
+ }
+
+ /**
+ * Initializes this instance for the specified capacity.
+ * Once initialized, operations on this map should not create new objects
+ * (unless the map's size exceeds the specified capacity).
+ *
+ * @param capacity the initial capacity.
+ */
+ @SuppressWarnings("unchecked")
+ private void initialize(int capacity) {
+ // Find a power of 2 >= capacity
+ int tableLength = 16;
+ while (tableLength < capacity) {
+ tableLength <<= 1;
+ }
+ // Allocates hash table.
+ _entries = new EntryImpl[tableLength];
+ _mask = tableLength - 1;
+ _capacity = capacity;
+ _size = 0;
+ // Allocates views.
+ _values = new Values();
+ _entrySet = new EntrySet();
+ _keySet = new KeySet();
+ // Resets pointers.
+ _poolFirst = null;
+ _mapFirst = null;
+ _mapLast = null;
+ // Allocates entries.
+ for (int i = 0; i < capacity; i++) {
+ EntryImpl<K, V> entry = new EntryImpl<K, V>();
+ entry._after = _poolFirst;
+ _poolFirst = entry;
+ }
+ }
+
+ /**
+ * Requires special handling during de-serialization process.
+ *
+ * @param stream the object input stream.
+ * @throws IOException if an I/O error occurs.
+ * @throws ClassNotFoundException if the class for the object de-serialized
+ * is not found.
+ */
+ @SuppressWarnings("unchecked")
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ int capacity = stream.readInt();
+ initialize(capacity);
+ int size = stream.readInt();
+ for (int i = 0; i < size; i++) {
+ addEntry((K) stream.readObject(), (V) stream.readObject());
+ }
+ }
+
+ /**
+ * Requires special handling during serialization process.
+ *
+ * @param stream the object output stream.
+ * @throws IOException if an I/O error occurs.
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.writeInt(_capacity);
+ stream.writeInt(_size);
+ int count = 0;
+ EntryImpl<K, V> entry = _mapFirst;
+ while (entry != null) {
+ stream.writeObject(entry._key);
+ stream.writeObject(entry._value);
+ count++;
+ entry = entry._after;
+ }
+ if (count != _size) { throw new IOException("FastMap Corrupted"); }
+ }
+
+ /**
+ * This class represents a {@link FastMap} entry.
+ */
+ private static final class EntryImpl<K, V> implements Map.Entry<K, V> {
+
+ /**
+ * Holds the entry key (null when in pool).
+ */
+ private K _key;
+
+ /**
+ * Holds the entry value (null when in pool).
+ */
+ private V _value;
+
+ /**
+ * Holds the bucket index (undefined when in pool).
+ */
+ private int _index;
+
+ /**
+ * Holds the previous entry in the same bucket (null when in pool).
+ */
+ private EntryImpl<K, V> _previous;
+
+ /**
+ * Holds the next entry in the same bucket (null when in pool).
+ */
+ private EntryImpl<K, V> _next;
+
+ /**
+ * Holds the entry added before this entry (null when in pool).
+ */
+ private EntryImpl<K, V> _before;
+
+ /**
+ * Holds the entry added after this entry
+ * or the next available entry when in pool.
+ */
+ private EntryImpl<K, V> _after;
+
+ /**
+ * Returns the key for this entry.
+ *
+ * @return the entry's key.
+ */
+ public K getKey() {
+ return _key;
+ }
+
+ /**
+ * Returns the value for this entry.
+ *
+ * @return the entry's value.
+ */
+ public V getValue() {
+ return _value;
+ }
+
+ /**
+ * Sets the value for this entry.
+ *
+ * @param value the new value.
+ * @return the previous value.
+ */
+ public V setValue(V value) {
+ V old = _value;
+ _value = value;
+ return old;
+ }
+
+ /**
+ * Indicates if this entry is considered equals to the specified
+ * entry.
+ *
+ * @param that the object to test for equality.
+ * @return <code>true<code> if both entry are considered equal;
+ * <code>false<code> otherwise.
+ */
+ public boolean equals(Object that) {
+ if (that instanceof Map.Entry) {
+ @SuppressWarnings("unchecked")
+ Map.Entry<K, V> entry = (Map.Entry<K, V>) that;
+ return (_key.equals(entry.getKey()))
+ && ((_value != null) ? _value.equals(entry.getValue()) : (entry.getValue() == null));
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the hash code for this entry.
+ *
+ * @return this entry's hash code.
+ */
+ public int hashCode() {
+ return _key.hashCode() ^ ((_value != null) ? _value.hashCode() : 0);
+ }
+
+ /**
+ * Returns the text representation of this entry.
+ *
+ * @return this entry's textual representation.
+ */
+ public String toString() {
+ return _key + "=" + _value;
+ }
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/collection/MapConverter.java b/tools/commons/src/main/java/com/ekingstar/commons/collection/MapConverter.java
new file mode 100755
index 0000000..7d46f04
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/collection/MapConverter.java
@@ -0,0 +1,333 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.collection;
+
+import java.lang.reflect.Array;
+import java.util.Date;
+import java.util.Map;
+import java.util.Set;
+
+import com.ekingstar.commons.conversion.Conversion;
+import com.ekingstar.commons.conversion.impl.DefaultConversion;
+import com.ekingstar.commons.lang.Strings;
+
+/**
+ * <p>
+ * MapConverter class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class MapConverter {
+
+ private final Conversion conversion;
+
+ /**
+ * <p>
+ * Constructor for MapConverter.
+ * </p>
+ */
+ public MapConverter() {
+ this(DefaultConversion.Instance);
+ }
+
+ /**
+ * <p>
+ * Constructor for MapConverter.
+ * </p>
+ */
+ public MapConverter(DefaultConversion conversion) {
+ super();
+ this.conversion = conversion;
+ }
+
+ /**
+ * <p>
+ * getAll.
+ * </p>
+ *
+ * @param data a {@link java.util.Map} object.
+ * @param attr a {@link java.lang.String} object.
+ * @return an array of {@link java.lang.Object} objects.
+ */
+ public Object[] getAll(Map<String, Object> data, String attr) {
+ return (Object[]) data.get(attr);
+ }
+
+ /**
+ * <p>
+ * getAll.
+ * </p>
+ *
+ * @param data a {@link java.util.Map} object.
+ * @param attr a {@link java.lang.String} object.
+ * @param clazz a {@link java.lang.Class} object.
+ * @param <T> a T object.
+ * @return an array of T objects.
+ */
+ public <T> T[] getAll(Map<String, Object> data, String attr, Class<T> clazz) {
+ return convert((Object[]) data.get(attr), clazz);
+ }
+
+ /**
+ * get parameter named attr
+ *
+ * @param attr a {@link java.lang.String} object.
+ * @return single value or multivalue joined with comma
+ * @param data a {@link java.util.Map} object.
+ */
+ public String getString(Map<String, Object> data, String attr) {
+ Object value = data.get(attr);
+ if (null == value) { return null; }
+ if (!value.getClass().isArray()) { return value.toString(); }
+ String[] values = (String[]) value;
+ if (values.length == 1) {
+ return values[0];
+ } else {
+ return Strings.join(values, ",");
+ }
+ }
+
+ /**
+ * get parameter named attr
+ *
+ * @param data a {@link java.util.Map} object.
+ * @param name a {@link java.lang.String} object.
+ * @return a {@link java.lang.Object} object.
+ */
+ public Object get(Map<String, Object> data, String name) {
+ Object value = data.get(name);
+ if (null == value) return null;
+ if (value.getClass().isArray()) {
+ Object[] values = (Object[]) value;
+ if (values.length == 1) { return values[0]; }
+ }
+ return value;
+ }
+
+ /**
+ * <p>
+ * convert.
+ * </p>
+ *
+ * @param value a {@link java.lang.Object} object.
+ * @param clazz a {@link java.lang.Class} object.
+ * @param <T> a T object.
+ * @return a T object.
+ */
+ public <T> T convert(Object value, Class<T> clazz) {
+ if (null == value) return null;
+ if (value instanceof String && Strings.isEmpty((String) value)) { return null; }
+ if (value.getClass().isArray()) {
+ Object[] values = (Object[]) value;
+ if (values.length >= 1) {
+ value = values[0];
+ }
+ }
+ return conversion.convert(value, clazz);
+ }
+
+ /**
+ * <p>
+ * convert.
+ * </p>
+ *
+ * @param datas an array of {@link java.lang.Object} objects.
+ * @param clazz a {@link java.lang.Class} object.
+ * @param <T> a T object.
+ * @return an array of T objects.
+ */
+ public <T> T[] convert(Object[] datas, Class<T> clazz) {
+ if (null == datas) { return null; }
+ @SuppressWarnings("unchecked")
+ T[] newDatas = (T[]) Array.newInstance(clazz, datas.length);
+ for (int i = 0; i < datas.length; i++) {
+ newDatas[i] = convert(datas[i], clazz);
+ }
+ return newDatas;
+ }
+
+ /**
+ * <p>
+ * get.
+ * </p>
+ *
+ * @param data a {@link java.util.Map} object.
+ * @param name a {@link java.lang.String} object.
+ * @param clazz a {@link java.lang.Class} object.
+ * @param <T> a T object.
+ * @return a T object.
+ */
+ public <T> T get(Map<String, Object> data, String name, Class<T> clazz) {
+ return convert(get(data, name), clazz);
+ }
+
+ /**
+ * <p>
+ * getBoolean.
+ * </p>
+ *
+ * @param data a {@link java.util.Map} object.
+ * @param name a {@link java.lang.String} object.
+ * @return a {@link java.lang.Boolean} object.
+ */
+ public Boolean getBoolean(Map<String, Object> data, String name) {
+ return get(data, name, Boolean.class);
+ }
+
+ /**
+ * <p>
+ * getBool.
+ * </p>
+ *
+ * @param data a {@link java.util.Map} object.
+ * @param name a {@link java.lang.String} object.
+ * @return a boolean.
+ */
+ public boolean getBool(Map<String, Object> data, String name) {
+ Boolean value = getBoolean(data, name);
+ return (null == value) ? false : value.booleanValue();
+ }
+
+ /**
+ * <p>
+ * getDate.
+ * </p>
+ *
+ * @param data a {@link java.util.Map} object.
+ * @param name a {@link java.lang.String} object.
+ * @return a {@link java.sql.Date} object.
+ */
+ public java.sql.Date getDate(Map<String, Object> data, String name) {
+ return get(data, name, java.sql.Date.class);
+ }
+
+ /**
+ * <p>
+ * getDateTime.
+ * </p>
+ *
+ * @param data a {@link java.util.Map} object.
+ * @param name a {@link java.lang.String} object.
+ * @return a {@link java.util.Date} object.
+ */
+ public Date getDateTime(Map<String, Object> data, String name) {
+ return get(data, name, Date.class);
+ }
+
+ /**
+ * <p>
+ * getFloat.
+ * </p>
+ *
+ * @param data a {@link java.util.Map} object.
+ * @param name a {@link java.lang.String} object.
+ * @return a {@link java.lang.Float} object.
+ */
+ public Float getFloat(Map<String, Object> data, String name) {
+ return get(data, name, Float.class);
+ }
+
+ /**
+ * <p>
+ * getInteger.
+ * </p>
+ */
+ public Integer getInteger(Map<String, Object> data, String name) {
+ return get(data, name, Integer.class);
+ }
+
+ /**
+ * Get Short.
+ */
+ public Short getShort(Map<String, Object> data, String name) {
+ return get(data, name, Short.class);
+ }
+
+ /**
+ * <p>
+ * getLong.
+ * </p>
+ *
+ * @param data a {@link java.util.Map} object.
+ * @param name a {@link java.lang.String} object.
+ * @return a {@link java.lang.Long} object.
+ */
+ public Long getLong(Map<String, Object> data, String name) {
+ return get(data, name, Long.class);
+ }
+
+ /**
+ * 返回request中以prefix.开头的参数
+ *
+ * @param prefix a {@link java.lang.String} object.
+ * @param exclusiveAttrNames
+ * 要排除的属性串
+ * @param data a {@link java.util.Map} object.
+ * @return a {@link java.util.Map} object.
+ */
+ public Map<String, Object> sub(Map<String, Object> data, String prefix, String exclusiveAttrNames) {
+ return sub(data, prefix, exclusiveAttrNames, true);
+ }
+
+ /**
+ * <p>
+ * sub.
+ * </p>
+ *
+ * @param data a {@link java.util.Map} object.
+ * @param prefix a {@link java.lang.String} object.
+ * @return a {@link java.util.Map} object.
+ */
+ public Map<String, Object> sub(Map<String, Object> data, String prefix) {
+ return sub(data, prefix, null, true);
+ }
+
+ /**
+ * <p>
+ * sub.
+ * </p>
+ *
+ * @param data a {@link java.util.Map} object.
+ * @param prefix a {@link java.lang.String} object.
+ * @param exclusiveAttrNames a {@link java.lang.String} object.
+ * @param stripPrefix a boolean.
+ * @return a {@link java.util.Map} object.
+ */
+ public Map<String, Object> sub(Map<String, Object> data, String prefix, String exclusiveAttrNames,
+ boolean stripPrefix) {
+ Set<String> excludes = CollectUtils.newHashSet();
+ if (Strings.isNotEmpty(exclusiveAttrNames)) {
+ String[] exclusiveAttrs = Strings.split(exclusiveAttrNames, ",");
+ for (int i = 0; i < exclusiveAttrs.length; i++) {
+ excludes.add(exclusiveAttrs[i]);
+ }
+ }
+ Map<String, Object> newParams = CollectUtils.newHashMap();
+ for (final Map.Entry<String, Object> entry : data.entrySet()) {
+ final String attr = entry.getKey();
+ if ((attr.indexOf(prefix + ".") == 0) && (!excludes.contains(attr))) {
+ newParams.put((stripPrefix ? attr.substring(prefix.length() + 1) : attr), get(data, attr));
+ }
+ }
+ return newParams;
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/collection/Order.java b/tools/commons/src/main/java/com/ekingstar/commons/collection/Order.java
new file mode 100755
index 0000000..67b9aed
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/collection/Order.java
@@ -0,0 +1,236 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.collection;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.ekingstar.commons.lang.Strings;
+
+/**
+ * 排序
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class Order {
+
+ /** Constant <code>ORDER_STR="orderBy"</code> */
+ public static final String ORDER_STR = "orderBy";
+
+ private String property;
+
+ private boolean ascending;
+
+ private boolean ignoreCase;
+
+ /**
+ * <p>
+ * Constructor for Order.
+ * </p>
+ */
+ public Order() {
+ super();
+ }
+
+ /**
+ * <p>
+ * Constructor for Order.
+ * </p>
+ *
+ * @param property a {@link java.lang.String} object.
+ * @param ascending a boolean.
+ */
+ public Order(String property, boolean ascending) {
+ this.property = property;
+ this.ascending = ascending;
+ }
+
+ /**
+ * <p>
+ * Constructor for Order.
+ * </p>
+ *
+ * @param property a {@link java.lang.String} object.
+ */
+ public Order(String property) {
+ if (Strings.contains(property, ",")) { throw new RuntimeException("user parser for multiorder"); }
+ if (Strings.contains(property, " desc")) {
+ this.ascending = false;
+ this.property = Strings.substringBefore(property, " desc");
+ } else {
+ if (Strings.contains(property, " asc")) {
+ this.property = Strings.substringBefore(property, " asc");
+ } else {
+ this.property = property;
+ }
+ this.ascending = true;
+ }
+ this.property = this.property.trim();
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>property</code>.
+ * </p>
+ *
+ * @return a {@link java.lang.String} object.
+ */
+ public String getProperty() {
+ return property;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>property</code>.
+ * </p>
+ *
+ * @param property a {@link java.lang.String} object.
+ */
+ public void setProperty(final String property) {
+ this.property = property;
+ }
+
+ /**
+ * <p>
+ * isAscending.
+ * </p>
+ *
+ * @return a boolean.
+ */
+ public boolean isAscending() {
+ return ascending;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>ascending</code>.
+ * </p>
+ *
+ * @param ascending a boolean.
+ */
+ public void setAscending(boolean ascending) {
+ this.ascending = ascending;
+ }
+
+ /**
+ * <p>
+ * ignoreCase.
+ * </p>
+ *
+ * @return a {@link com.ekingstar.commons.collection.Order} object.
+ */
+ public Order ignoreCase() {
+ ignoreCase = true;
+ return this;
+ }
+
+ /**
+ * <p>
+ * asc.
+ * </p>
+ *
+ * @param property a {@link java.lang.String} object.
+ * @return a {@link com.ekingstar.commons.collection.Order} object.
+ */
+ public static Order asc(String property) {
+ return new Order(property, true);
+ }
+
+ /**
+ * <p>
+ * desc.
+ * </p>
+ *
+ * @param property a {@link java.lang.String} object.
+ * @return a {@link com.ekingstar.commons.collection.Order} object.
+ */
+ public static Order desc(String property) {
+ return new Order(property, false);
+ }
+
+ /**
+ * <p>
+ * toSortString.
+ * </p>
+ *
+ * @param orders a {@link java.util.List} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String toSortString(final List<Order> orders) {
+ if (null == orders || orders.isEmpty()) { return ""; }
+ final StringBuilder buf = new StringBuilder("order by ");
+ for (final Order order : orders) {
+ if (order.isAscending()) {
+ buf.append(order.getProperty()).append(',');
+ } else {
+ buf.append(order.getProperty()).append(" desc,");
+ }
+ }
+ return buf.substring(0, buf.length() - 1).toString();
+ }
+
+ /**
+ * <p>
+ * parse.
+ * </p>
+ *
+ * @param orderString a {@link java.lang.String} object.
+ * @return a {@link java.util.List} object.
+ */
+ public static List<Order> parse(final String orderString) {
+ if (Strings.isBlank(orderString)) {
+ return new ArrayList<Order>();
+ } else {
+ final List<Order> orders = new ArrayList<Order>();
+ final String[] orderStrs = Strings.split(orderString, ',');
+ for (int i = 0; i < orderStrs.length; i++) {
+ String order = orderStrs[i].trim();
+ if (Strings.isBlank(order)) {
+ continue;
+ }
+ order = order.toLowerCase().trim();
+ if (order.endsWith(" desc")) {
+ orders.add(new Order(orderStrs[i].substring(0, order.indexOf(" desc")), false));
+ } else if (order.endsWith(" asc")) {
+ orders.add(new Order(orderStrs[i].substring(0, order.indexOf(" asc")), true));
+ } else {
+ orders.add(new Order(orderStrs[i], true));
+ }
+ }
+ return orders;
+ }
+ }
+
+ /**
+ * <p>
+ * toString.
+ * </p>
+ *
+ * @return a {@link java.lang.String} object.
+ */
+ public String toString() {
+ if (ignoreCase) {
+ return "lower(" + getProperty() + ") " + (ascending ? "asc" : "desc");
+ } else {
+ return getProperty() + " " + (ascending ? "asc" : "desc");
+ }
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/Conversion.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/Conversion.java
new file mode 100644
index 0000000..89193e5
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/Conversion.java
@@ -0,0 +1,37 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion;
+
+/**
+ * convert a source to target type.
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public interface Conversion {
+
+ /**
+ * Convert to target type.
+ * <ul>
+ * <li>convert null to null;
+ * <li>convert array to array ,when cannot find converter return targetType[0]
+ * </ul>
+ */
+ <T> T convert(Object source, Class<T> targetType);
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/Converter.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/Converter.java
new file mode 100644
index 0000000..07c9916
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/Converter.java
@@ -0,0 +1,32 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion;
+
+import com.ekingstar.commons.lang.functor.UnaryFunction;
+
+/**
+ * Convert source to target
+ *
+ * @author chaostone
+ * @param <S> source
+ * @param <T> target
+ */
+public interface Converter<S, T> extends UnaryFunction<S, T> {
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/ConverterRegistry.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/ConverterRegistry.java
new file mode 100644
index 0000000..8bf6123
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/ConverterRegistry.java
@@ -0,0 +1,31 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion;
+
+/**
+ * Converter Registry.
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public interface ConverterRegistry {
+
+ void addConverter(Converter<?, ?> converter);
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/Number2NumberConverter.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/Number2NumberConverter.java
new file mode 100644
index 0000000..99f4704
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/Number2NumberConverter.java
@@ -0,0 +1,93 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.converter;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.ekingstar.commons.conversion.Converter;
+import com.ekingstar.commons.conversion.impl.ConverterFactory;
+
+/**
+ * Number Converter Factory
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public class Number2NumberConverter extends ConverterFactory<Number, Number> {
+
+ public Number2NumberConverter() {
+ register(Integer.class, new ShortConverter());
+ register(Integer.class, new IntConverter());
+ register(Long.class, new LongConverter());
+ register(Float.class, new FloatConverter());
+ register(Double.class, new DoubleConverter());
+ register(BigInteger.class, new BigIntegerConverter());
+ register(BigDecimal.class, new BigDecimalConverter());
+ }
+
+ private static class ShortConverter implements Converter<Number, Short> {
+ @Override
+ public Short apply(Number number) {
+ return Short.valueOf(number.shortValue());
+ }
+ }
+
+ private static class IntConverter implements Converter<Number, Integer> {
+ @Override
+ public Integer apply(Number number) {
+ return Integer.valueOf(number.intValue());
+ }
+ }
+
+ private static class LongConverter implements Converter<Number, Long> {
+ @Override
+ public Long apply(Number number) {
+ return Long.valueOf(number.intValue());
+ }
+ }
+
+ private static class FloatConverter implements Converter<Number, Float> {
+ @Override
+ public Float apply(Number number) {
+ return Float.valueOf(number.floatValue());
+ }
+ }
+
+ private static class DoubleConverter implements Converter<Number, Double> {
+ @Override
+ public Double apply(Number number) {
+ return Double.valueOf(number.doubleValue());
+ }
+ }
+
+ private static class BigIntegerConverter implements Converter<Number, BigInteger> {
+ @Override
+ public BigInteger apply(Number number) {
+ return BigInteger.valueOf(number.longValue());
+ }
+ }
+
+ private static class BigDecimalConverter implements Converter<Number, BigDecimal> {
+ @Override
+ public BigDecimal apply(Number number) {
+ return new BigDecimal(number.toString());
+ }
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/Object2StringConverter.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/Object2StringConverter.java
new file mode 100644
index 0000000..be6b19d
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/Object2StringConverter.java
@@ -0,0 +1,40 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.converter;
+
+import com.ekingstar.commons.conversion.Converter;
+import com.ekingstar.commons.lang.Strings;
+
+/**
+ * Convert Object to String
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public class Object2StringConverter implements Converter<Object, String> {
+
+ @Override
+ public String apply(Object input) {
+ if (input == null) return null;
+ if (input.getClass().isArray()) {
+ return Strings.join((Object[]) input,',');
+ } else return input.toString();
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2BooleanConverter.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2BooleanConverter.java
new file mode 100644
index 0000000..fa9ac46
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2BooleanConverter.java
@@ -0,0 +1,65 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.converter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.ekingstar.commons.conversion.Converter;
+import com.ekingstar.commons.lang.Strings;
+
+/**
+ * Convert String to Boolean.
+ * <p>
+ * Convert true,on,yes,Y,1 to Boolean.TRUE.<br>
+ * Convert false,off,no,N,0 to Boolean.FALSE. <br>
+ * Otherwise null.
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public class String2BooleanConverter implements Converter<String, Boolean> {
+ private static final Set<String> trueValues = new HashSet<String>(4);
+
+ private static final Set<String> falseValues = new HashSet<String>(4);
+
+ static {
+ trueValues.add("true");
+ trueValues.add("on");
+ trueValues.add("yes");
+ trueValues.add("Y");
+ trueValues.add("1");
+
+ falseValues.add("false");
+ falseValues.add("off");
+ falseValues.add("no");
+ falseValues.add("N");
+ falseValues.add("0");
+ }
+
+ @Override
+ public Boolean apply(String input) {
+ if(Strings.isEmpty(input))return null;
+ String value = input.toLowerCase();
+ if (trueValues.contains(value)) return Boolean.TRUE;
+ else if (falseValues.contains(value)) return Boolean.FALSE;
+ return null;
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2DateConverter.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2DateConverter.java
new file mode 100755
index 0000000..f54acee
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2DateConverter.java
@@ -0,0 +1,127 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.converter;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import com.ekingstar.commons.conversion.Converter;
+import com.ekingstar.commons.lang.Numbers;
+import com.ekingstar.commons.lang.Strings;
+
+/**
+ * <p>
+ * DateConverter class.
+ * </p>
+ *
+ * @author chaostone
+ * @since 3.2.0
+ * @version $Id: $
+ */
+public class String2DateConverter extends StringConverterFactory<String, Date> {
+
+ public String2DateConverter() {
+ register(Date.class, new DateConverter());
+ register(java.sql.Date.class, new SqlDateConverter());
+ }
+
+ private static class DateConverter implements Converter<String, Date> {
+ @Override
+ public Date apply(String value) {
+ if (Strings.isEmpty((String) value)) { return null; }
+ String dateStr = (String) value;
+ String[] times = Strings.split(dateStr, " ");
+ String[] dateElems = null;
+ if (Strings.contains(times[0], "-")) {
+ dateElems = Strings.split(times[0], "-");
+ } else {
+ dateElems = new String[3];
+ int yearIndex = "yyyy".length();
+ dateElems[0] = Strings.substring(times[0], 0, yearIndex);
+ dateElems[1] = Strings.substring(times[0], yearIndex, yearIndex + 2);
+ dateElems[2] = Strings.substring(times[0], yearIndex + 2, yearIndex + 4);
+ }
+ Calendar gc = GregorianCalendar.getInstance();
+ gc.set(Calendar.YEAR, Numbers.toInt(dateElems[0]));
+ gc.set(Calendar.MONTH, Numbers.toInt(dateElems[1]) - 1);
+ gc.set(Calendar.DAY_OF_MONTH, Numbers.toInt(dateElems[2]));
+ if (times.length > 1 && Strings.isNotBlank(times[1])) {
+ String[] timeElems = Strings.split(times[1], ":");
+ if (timeElems.length > 0) gc.set(Calendar.HOUR_OF_DAY, Numbers.toInt(timeElems[0]));
+ if (timeElems.length > 1) gc.set(Calendar.MINUTE, Numbers.toInt(timeElems[1]));
+ if (timeElems.length > 2) gc.set(Calendar.SECOND, Numbers.toInt(timeElems[2]));
+ }
+ return gc.getTime();
+
+ }
+
+ }
+
+ private static class SqlDateConverter implements Converter<String, java.sql.Date> {
+ @Override
+ public java.sql.Date apply(String input) {
+ // 修复了jdk 1.6_u26 的错误
+ return java.sql.Date.valueOf(normalize(input));
+ }
+
+ }
+
+ /**
+ * <p>
+ * normalize.
+ * </p>
+ *
+ * @param dateStr a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String normalize(String dateStr) {
+ if (!dateStr.contains("-")) {
+ StringBuilder dateBuf = new StringBuilder(dateStr);
+ dateBuf.insert("yyyyMM".length(), '-');
+ dateBuf.insert("yyyy".length(), '-');
+ return dateBuf.toString();
+ } else {
+ if (dateStr.length() >= 10) return dateStr;
+ else if (dateStr.length() < 8) throw new IllegalArgumentException();
+ else {
+ // try 2009-9-1
+ char[] value = dateStr.toCharArray();
+ int dayIndex = -1;
+ if (value[6] == '-') dayIndex = 7;
+ if (value[7] == '-') dayIndex = 8;
+ if (dayIndex < 0) throw new IllegalArgumentException();
+ StringBuilder sb = new StringBuilder(10);
+
+ // append year-
+ sb.append(value, 0, 5);
+
+ // append month-
+ if (dayIndex - 5 < 3) sb.append('0').append(value, 5, 2);
+ else sb.append(value, 5, 3);
+
+ // append day
+ if (value.length - dayIndex < 2) sb.append('0').append(value, dayIndex, 1);
+ else sb.append(value, dayIndex, 2);
+
+ return sb.toString();
+ }
+ }
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2EnumConverter.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2EnumConverter.java
new file mode 100644
index 0000000..0179fc2
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2EnumConverter.java
@@ -0,0 +1,59 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.converter;
+
+import com.ekingstar.commons.conversion.Converter;
+
+/**
+ * Convert String to Enumeration.
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public class String2EnumConverter extends StringConverterFactory<String, Enum<?>> {
+
+ public String2EnumConverter() {
+ super();
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Override
+ public <T extends Enum<?>> Converter<String, T> getConverter(Class<T> targetType) {
+ Converter<String, T> converter = super.getConverter(targetType);
+ if (null == converter) {
+ converter = new EnumConverter(targetType);
+ register(targetType, converter);
+ }
+ return converter;
+ }
+
+ private static class EnumConverter<T extends Enum<T>> implements Converter<String, T> {
+
+ private final Class<T> enumType;
+
+ public EnumConverter(Class<T> enumType) {
+ this.enumType = enumType;
+ }
+
+ @Override
+ public T apply(String input) {
+ return (T) Enum.valueOf(enumType, input);
+ }
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2LocaleConverter.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2LocaleConverter.java
new file mode 100644
index 0000000..3512a58
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2LocaleConverter.java
@@ -0,0 +1,55 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.converter;
+
+import java.util.Locale;
+
+import com.ekingstar.commons.conversion.Converter;
+import com.ekingstar.commons.lang.Strings;
+
+/**
+ * Convert String to Locale.
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public class String2LocaleConverter implements Converter<String, Locale> {
+
+ @Override
+ public Locale apply(String localeStr) {
+ if (Strings.isBlank(localeStr)) return null;
+
+ int index = localeStr.indexOf('_');
+ if (index < 0) return new Locale(localeStr);
+
+ String language = localeStr.substring(0, index);
+ if (index == localeStr.length()) return new Locale(language);
+
+ localeStr = localeStr.substring(index + 1);
+ index = localeStr.indexOf('_');
+ if (index < 0) return new Locale(language, localeStr);
+
+ String country = localeStr.substring(0, index);
+ if (index == localeStr.length()) return new Locale(language, country);
+
+ localeStr = localeStr.substring(index + 1);
+ return new Locale(language, country, localeStr);
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2NumberConverter.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2NumberConverter.java
new file mode 100644
index 0000000..9b47dfc
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/String2NumberConverter.java
@@ -0,0 +1,121 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.converter;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.ekingstar.commons.conversion.Converter;
+
+/**
+ * Convert string to number.
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public class String2NumberConverter extends StringConverterFactory<String, Number> {
+
+ public String2NumberConverter() {
+ register(Short.class, new ShortConverter());
+ register(Integer.class, new IntConverter());
+ register(Long.class, new LongConverter());
+ register(Float.class, new FloatConverter());
+ register(Double.class, new DoubleConverter());
+ register(BigInteger.class, new BigIntegerConverter());
+ register(BigDecimal.class, new BigDecimalConverter());
+ }
+
+ private static class ShortConverter implements Converter<String, Short> {
+ @Override
+ public Short apply(String string) {
+ try {
+ return Short.valueOf(string);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+ }
+
+ private static class IntConverter implements Converter<String, Integer> {
+ @Override
+ public Integer apply(String string) {
+ try {
+ return Integer.valueOf(string);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+ }
+
+ private static class LongConverter implements Converter<String, Long> {
+ @Override
+ public Long apply(String string) {
+ try {
+ return Long.valueOf(string);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+ }
+
+ private static class FloatConverter implements Converter<String, Float> {
+ @Override
+ public Float apply(String string) {
+ try {
+ return Float.valueOf(string);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+ }
+
+ private static class DoubleConverter implements Converter<String, Double> {
+ @Override
+ public Double apply(String string) {
+ try {
+ return Double.valueOf(string);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+ }
+
+ private static class BigIntegerConverter implements Converter<String, BigInteger> {
+ @Override
+ public BigInteger apply(String string) {
+ try {
+ return new BigInteger(string);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+ }
+
+ private static class BigDecimalConverter implements Converter<String, BigDecimal> {
+ @Override
+ public BigDecimal apply(String string) {
+ try {
+ return new BigDecimal(string);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/StringConverterFactory.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/StringConverterFactory.java
new file mode 100644
index 0000000..5a865d2
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/converter/StringConverterFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.converter;
+
+import com.ekingstar.commons.conversion.impl.ConverterFactory;
+import com.ekingstar.commons.lang.Strings;
+
+/**
+ * String to Object
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public class StringConverterFactory<S, R> extends ConverterFactory<S, R> {
+
+ @Override
+ public Object convert(Object input, Class<?> sourceType, Class<?> targetType) {
+ if (Strings.isEmpty((String) input)) return null;
+ return super.convert(input, sourceType, targetType);
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/AbstractGenericConversion.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/AbstractGenericConversion.java
new file mode 100644
index 0000000..710bb0a
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/AbstractGenericConversion.java
@@ -0,0 +1,192 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.impl;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+
+import com.ekingstar.commons.collection.CollectUtils;
+import com.ekingstar.commons.conversion.Conversion;
+import com.ekingstar.commons.conversion.Converter;
+import com.ekingstar.commons.conversion.ConverterRegistry;
+import com.ekingstar.commons.lang.Objects;
+import com.ekingstar.commons.lang.Primitives;
+import com.ekingstar.commons.lang.tuple.Pair;
+
+/**
+ * Generic Conversion Super class
+ * It provider converter registry and converter search machanism.
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public abstract class AbstractGenericConversion implements Conversion, ConverterRegistry {
+
+ Map<Class<?>, Map<Class<?>, GenericConverter>> converters = CollectUtils.newHashMap();
+
+ Map<Pair<Class<?>, Class<?>>, GenericConverter> cache = CollectUtils.newConcurrentHashMap();
+
+ protected void addConverter(GenericConverter converter) {
+ Pair<?, ?> key = converter.getTypeinfo();
+ getOrCreateConverters((Class<?>) key.getLeft()).put((Class<?>) key.getRight(), converter);
+ cache.clear();
+ }
+
+ @Override
+ public void addConverter(Converter<?, ?> converter) {
+ Pair<Class<?>, Class<?>> key = null;
+ Pair<Class<Object>, Class<Object>> defaultKey = Pair.of(Object.class, Object.class);
+ for (Method m : converter.getClass().getMethods()) {
+ if (m.getName().equals("apply") && Modifier.isPublic(m.getModifiers())) {
+ key = Pair.<Class<?>, Class<?>> of(m.getParameterTypes()[0], m.getReturnType());
+ if (!key.equals(defaultKey)) break;
+ }
+ }
+ if (null == key) throw new IllegalArgumentException("Cannot find convert type pair "
+ + converter.getClass());
+
+ getOrCreateConverters((Class<?>) key.getLeft()).put((Class<?>) key.getRight(),
+ new ConverterAdapter(converter, key));
+ cache.clear();
+ }
+
+ private Map<Class<?>, GenericConverter> getOrCreateConverters(Class<?> sourceType) {
+ Map<Class<?>, GenericConverter> exists = converters.get(sourceType);
+ if (null == exists) {
+ exists = CollectUtils.newHashMap();
+ converters.put(sourceType, exists);
+ }
+ return exists;
+ }
+
+ private Map<Class<?>, GenericConverter> getConverters(Class<?> sourceType) {
+ Map<Class<?>, GenericConverter> exists = converters.get(sourceType);
+ if (null == exists) return Collections.emptyMap();
+ else return exists;
+ }
+
+ private GenericConverter getConverter(Class<?> targetType, Map<Class<?>, GenericConverter> converters) {
+ Set<Class<?>> interfaces = new LinkedHashSet<Class<?>>();
+ LinkedList<Class<?>> queue = new LinkedList<Class<?>>();
+ queue.addFirst(targetType);
+ while (!queue.isEmpty()) {
+ Class<?> cur = queue.removeLast();
+ GenericConverter converter = converters.get(cur);
+ if (converter != null) return converter;
+
+ Class<?> superClass = cur.getSuperclass();
+ if (superClass != null && superClass != Object.class) queue.addFirst(superClass);
+
+ for (Class<?> interfaceType : cur.getInterfaces())
+ addInterfaces(interfaceType, interfaces);
+ }
+
+ for (Class<?> interfaceType : interfaces) {
+ GenericConverter converter = converters.get(interfaceType);
+ if (converter != null) return converter;
+ }
+
+ return null;
+ }
+
+ private void addInterfaces(Class<?> interfaceType, Set<Class<?>> interfaces) {
+ interfaces.add(interfaceType);
+ for (Class<?> inheritedInterface : interfaceType.getInterfaces())
+ addInterfaces(inheritedInterface, interfaces);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected GenericConverter findConverter(Class<?> sourceType, Class<?> targetType) {
+ // Get cache
+ Pair<?, ?> key = Pair.of(sourceType, targetType);
+ GenericConverter converter = cache.get(key);
+ if (null == converter) converter = searchConverter(sourceType, targetType);
+ else return converter;
+
+ if (null == converter) converter = NoneConverter.Instance;
+ else cache.put((Pair<Class<?>, Class<?>>) key, converter);
+ return converter;
+ }
+
+ protected GenericConverter searchConverter(Class<?> sourceType, Class<?> targetType) {
+ HashSet<Class<?>> interfaces = new LinkedHashSet<Class<?>>();
+ LinkedList<Class<?>> classQueue = new LinkedList<Class<?>>();
+ classQueue.addFirst(sourceType);
+ // Search Class hierarchy
+ while (!classQueue.isEmpty()) {
+ Class<?> currentClass = classQueue.removeLast();
+ GenericConverter converter = getConverter(targetType, getConverters(currentClass));
+ if (converter != null) return converter;
+
+ Class<?> superClass = currentClass.getSuperclass();
+ if (superClass != null && superClass != Object.class) classQueue.addFirst(superClass);
+
+ for (Class<?> interfaceType : currentClass.getInterfaces())
+ addInterfaces(interfaceType, interfaces);
+ }
+ // Search interface
+ for (Class<?> interfaceType : interfaces) {
+ GenericConverter converter = getConverter(targetType, getConverters(interfaceType));
+ if (converter != null) return converter;
+ }
+ return getConverter(targetType, getConverters(Object.class));
+ }
+
+ /**
+ * Convert to target type.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T convert(Object source, Class<T> targetType) {
+ if (null == source) return (T) Objects.defaultValue(targetType);
+
+ Class<?> sourceType = Primitives.wrap(source.getClass());
+ Class<?> targetClazz = Primitives.wrap(targetType);
+
+ if (targetClazz.isAssignableFrom(sourceType)) return (T) source;
+
+ if (sourceType.isArray() && targetClazz.isArray()) {
+ Class<?> sourceObjType = Primitives.wrap(sourceType.getComponentType());
+ Class<?> targetObjType = Primitives.wrap(targetClazz.getComponentType());
+ GenericConverter converter = findConverter(sourceObjType, targetObjType);
+ if (null == converter) return (T) Array.newInstance(targetClazz.getComponentType(), 0);
+ else {
+ int length = Array.getLength(source);
+ T result = (T) Array.newInstance(targetClazz.getComponentType(), length);
+ for (int i = 0; i < length; i++)
+ Array.set(result, i, converter.convert(Array.get(source, i), sourceObjType, targetObjType));
+ return result;
+ }
+ } else {
+ Object rs = null;
+ GenericConverter converter = findConverter(sourceType, targetClazz);
+ if (null != converter) rs = converter.convert(source, sourceType, targetClazz);
+ if (null == rs && targetType.isPrimitive()) rs = Objects.defaultValue(targetType);
+ return (T) rs;
+ }
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/ConvertUtils.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/ConvertUtils.java
new file mode 100644
index 0000000..72a9c7d
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/ConvertUtils.java
@@ -0,0 +1,26 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.impl;
+
+public final class ConvertUtils {
+
+ public static final <T> T convert(Object value, Class<T> targetType) {
+ return DefaultConversion.Instance.convert(value, targetType);
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/ConverterAdapter.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/ConverterAdapter.java
new file mode 100644
index 0000000..10dadb7
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/ConverterAdapter.java
@@ -0,0 +1,53 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.impl;
+
+import com.ekingstar.commons.conversion.Converter;
+import com.ekingstar.commons.lang.tuple.Pair;
+
+/**
+ * Adapte a Converter to GenericConverter
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public class ConverterAdapter implements GenericConverter {
+
+ final Converter<Object, Object> converter;
+
+ final Pair<Class<?>, Class<?>> typeinfo;
+
+ @SuppressWarnings("unchecked")
+ public ConverterAdapter(Converter<?, ?> converter, Pair<Class<?>, Class<?>> typeinfo) {
+ super();
+ this.converter = (Converter<Object, Object>) converter;
+ this.typeinfo = typeinfo;
+ }
+
+ @Override
+ public Object convert(Object input, Class<?> sourceType, Class<?> targetType) {
+ return converter.apply(input);
+ }
+
+ @Override
+ public Pair<Class<?>, Class<?>> getTypeinfo() {
+ return typeinfo;
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/ConverterFactory.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/ConverterFactory.java
new file mode 100644
index 0000000..9bcfbc4
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/ConverterFactory.java
@@ -0,0 +1,77 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.impl;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Map;
+
+import com.ekingstar.commons.collection.CollectUtils;
+import com.ekingstar.commons.conversion.Converter;
+import com.ekingstar.commons.lang.tuple.Pair;
+
+/**
+ * A converter factory that can convert objects from S to subtypes of R.
+ *
+ * @author chaostone
+ * @since 3.2.0
+ * @param <S>
+ * @param <R> The target base
+ */
+public abstract class ConverterFactory<S, R> implements GenericConverter {
+ protected Map<Class<?>, Converter<S, ? extends R>> converters = CollectUtils.newHashMap();
+
+ /**
+ * Return convert from S to T
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends R> Converter<S, T> getConverter(Class<T> targetType) {
+ return (Converter<S, T>) converters.get(targetType);
+ }
+
+ private Class<?> classof(Type type) {
+ if (type instanceof Class<?>) {
+ return (Class<?>) type;
+ } else if (type instanceof ParameterizedType) { return (Class<?>) ((ParameterizedType) type).getRawType(); }
+ return null;
+ }
+
+ @Override
+ public Pair<Class<?>, Class<?>> getTypeinfo() {
+ Type superType = getClass().getGenericSuperclass();
+ if ((superType instanceof ParameterizedType)) {
+ ParameterizedType ptype = (ParameterizedType) superType;
+ return Pair.<Class<?>, Class<?>> of(classof(ptype.getActualTypeArguments()[0]),
+ classof(ptype.getActualTypeArguments()[1]));
+ } else {
+ throw new RuntimeException("Cannot identify type of " + getClass());
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object convert(Object input, Class<?> sourceType, Class<?> targetType) {
+ Converter<S, R> converter = getConverter((Class<R>) targetType);
+ return (null == converter) ? null : converter.apply((S) input);
+ }
+
+ protected void register(Class<?> targetType, Converter<S, ? extends R> converter) {
+ converters.put(targetType, converter);
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/DefaultConversion.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/DefaultConversion.java
new file mode 100644
index 0000000..0d131f6
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/DefaultConversion.java
@@ -0,0 +1,57 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.impl;
+
+import com.ekingstar.commons.conversion.Converter;
+import com.ekingstar.commons.conversion.converter.Number2NumberConverter;
+import com.ekingstar.commons.conversion.converter.Object2StringConverter;
+import com.ekingstar.commons.conversion.converter.String2BooleanConverter;
+import com.ekingstar.commons.conversion.converter.String2DateConverter;
+import com.ekingstar.commons.conversion.converter.String2EnumConverter;
+import com.ekingstar.commons.conversion.converter.String2LocaleConverter;
+import com.ekingstar.commons.conversion.converter.String2NumberConverter;
+
+/**
+ * Default Conversion implementation.
+ * <p>
+ * It register String to Boolean/Number/Date/Locale, Number to Number and Object to String buildin
+ * converters.
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public class DefaultConversion extends AbstractGenericConversion {
+
+ static final public DefaultConversion Instance = new DefaultConversion();
+
+ public DefaultConversion() {
+ addConverter(new String2BooleanConverter());
+ addConverter(new String2NumberConverter());
+ addConverter(new String2DateConverter());
+ addConverter(new String2EnumConverter());
+ addConverter(new String2LocaleConverter());
+ addConverter(new Number2NumberConverter());
+ addConverter(new Object2StringConverter());
+ }
+
+ public DefaultConversion(Converter<?, ?>... converters) {
+ for (Converter<?, ?> converter : converters)
+ addConverter(converter);
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/GenericConverter.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/GenericConverter.java
new file mode 100644
index 0000000..a7f3bba
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/GenericConverter.java
@@ -0,0 +1,36 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.impl;
+
+import com.ekingstar.commons.lang.tuple.Pair;
+
+/**
+ * Generic Converter using in DefaultConversion
+ * <p>
+ * It's a SPI interface.
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public interface GenericConverter {
+
+ Pair<Class<?>, Class<?>> getTypeinfo();
+
+ Object convert(Object input, Class<?> sourceType, Class<?> targetType);
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/NoneConverter.java b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/NoneConverter.java
new file mode 100644
index 0000000..1af26a6
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/conversion/impl/NoneConverter.java
@@ -0,0 +1,43 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.impl;
+
+import com.ekingstar.commons.lang.tuple.Pair;
+
+/**
+ * Convert anything to null.
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public class NoneConverter implements GenericConverter {
+
+ public final static NoneConverter Instance = new NoneConverter();
+
+ @Override
+ public Object convert(Object input, Class<?> sourceType, Class<?> targetType) {
+ return null;
+ }
+
+ @Override
+ public Pair<Class<?>, Class<?>> getTypeinfo() {
+ return Pair.<Class<?>, Class<?>> of(Object.class, Object.class);
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/io/Files.java b/tools/commons/src/main/java/com/ekingstar/commons/io/Files.java
new file mode 100644
index 0000000..cac833c
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/io/Files.java
@@ -0,0 +1,236 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.io;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
+import java.util.List;
+
+import com.ekingstar.commons.lang.Assert;
+
+/**
+ * File Operation Utility
+ *
+ * @author chaostone
+ * @since 3.1
+ */
+public class Files {
+
+ public static final long CopyBufferSize = 1024 * 1024 * 30;// 30MB
+
+ /**
+ * Reads the contents of a file into a String using the default encoding for the VM.
+ * The file is always closed.
+ */
+ public static String readFileToString(File file) throws IOException {
+ return readFileToString(file, null);
+ }
+
+ /**
+ * Reads the contents of a file into a String.
+ * The file is always closed.
+ */
+ public static String readFileToString(File file, Charset charset) throws IOException {
+ InputStream in = null;
+ try {
+ in = new FileInputStream(file);
+ StringBuilderWriter sw = new StringBuilderWriter();
+
+ if (null == charset) IOs.copy(new InputStreamReader(in), sw);
+ else IOs.copy(new InputStreamReader(in, charset.name()), sw);
+
+ return sw.toString();
+ } finally {
+ IOs.close(in);
+ }
+ }
+
+ /**
+ * Reads the contents of a file line by line to a List of Strings.
+ * The file is always closed.
+ */
+ public static List<String> readLines(File file, Charset charset) throws IOException {
+ InputStream in = null;
+ try {
+ in = new FileInputStream(file);
+ if (null == charset) {
+ return IOs.readLines(new InputStreamReader(in));
+ } else {
+ InputStreamReader reader = new InputStreamReader(in, charset.name());
+ return IOs.readLines(reader);
+ }
+ } finally {
+ IOs.close(in);
+ }
+ }
+
+ public static List<String> readLines(File file) throws IOException {
+ return readLines(file, null);
+ }
+
+ /**
+ * Copies a file to a new location preserving the file date.
+ * <p>
+ * This method copies the contents of the specified source file to the specified destination file.
+ * The directory holding the destination file is created if it does not exist. If the destination
+ * file exists, then this method will overwrite it.
+ * <p>
+ * <strong>Note:</strong> This method tries to preserve the file's last modified date/times using
+ * {@link File#setLastModified(long)}, however it is not guaranteed that the operation will
+ * succeed. If the modification operation fails, no indication is provided.
+ *
+ * @param srcFile an existing file to copy, must not be <code>null</code>
+ * @param destFile the new file, must not be <code>null</code>
+ * @throws NullPointerException if source or destination is <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @see #copyFileToDirectory(File, File)
+ */
+ public static void copyFile(File srcFile, File destFile) throws IOException {
+ Assert.isTrue(null != srcFile, "Source must not be null");
+ Assert.isTrue(null != destFile, "Destination must not be null");
+ if (srcFile.exists() == false) { throw new FileNotFoundException("Source '" + srcFile
+ + "' does not exist"); }
+ if (srcFile.isDirectory()) { throw new IOException("Source '" + srcFile + "' exists but is a directory"); }
+ if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) { throw new IOException("Source '"
+ + srcFile + "' and destination '" + destFile + "' are the same"); }
+ File parentFile = destFile.getParentFile();
+ if (parentFile != null) {
+ if (!parentFile.mkdirs() && !parentFile.isDirectory()) { throw new IOException("Destination '"
+ + parentFile + "' directory cannot be created"); }
+ }
+ if (destFile.exists()) {
+ if (destFile.isDirectory()) { throw new IOException("Destination '" + destFile
+ + "' exists but is a directory"); }
+ if (!destFile.canWrite()) throw new IOException("Destination '" + destFile
+ + "' exists but is read-only");
+ }
+ doCopyFile(srcFile, destFile, true);
+ }
+
+ private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
+ FileInputStream fis = null;
+ FileOutputStream fos = null;
+ FileChannel input = null;
+ FileChannel output = null;
+ try {
+ fis = new FileInputStream(srcFile);
+ fos = new FileOutputStream(destFile);
+ input = fis.getChannel();
+ output = fos.getChannel();
+ long size = input.size();
+ long pos = 0;
+ long count = 0;
+ while (pos < size) {
+ count = size - pos > CopyBufferSize ? CopyBufferSize : size - pos;
+ pos += output.transferFrom(input, pos, count);
+ }
+ } finally {
+ IOs.close(output);
+ IOs.close(fos);
+ IOs.close(input);
+ IOs.close(fis);
+ }
+
+ if (srcFile.length() != destFile.length()) { throw new IOException("Failed to copy full contents from '"
+ + srcFile + "' to '" + destFile + "'"); }
+ if (preserveFileDate) {
+ destFile.setLastModified(srcFile.lastModified());
+ }
+ }
+
+ public static void deleteDirectory(File directory) throws IOException {
+ if (!directory.exists()) return;
+ if (!isSymlink(directory)) cleanDirectory(directory);
+ if (!directory.delete()) throw new IOException("Unable to delete directory " + directory + ".");
+ }
+
+ public static void cleanDirectory(File directory) throws IOException {
+ if (!directory.exists()) throw new IllegalArgumentException(directory + " does not exist");
+ if (!directory.isDirectory()) throw new IllegalArgumentException(directory + " is not a directory");
+
+ File[] files = directory.listFiles();
+ if (files == null) { // null if security restricted
+ throw new IOException("Failed to list contents of " + directory);
+ }
+ IOException exception = null;
+ for (File file : files) {
+ try {
+ forceDelete(file);
+ } catch (IOException ioe) {
+ exception = ioe;
+ }
+ }
+ if (null != exception) throw exception;
+ }
+
+ public static void forceDelete(File file) throws IOException {
+ if (file.isDirectory()) {
+ deleteDirectory(file);
+ } else {
+ if (file.exists()) {
+ if (!file.delete()) throw new IOException("Unable to delete file: " + file);
+ }
+ }
+ }
+
+ public static boolean isSymlink(File file) throws IOException {
+ if (file == null) throw new NullPointerException("File must not be null");
+ // windows
+ if (File.separatorChar == '\\') { return false; }
+ File fileInCanonicalDir = null;
+ if (file.getParent() == null) {
+ fileInCanonicalDir = file;
+ } else {
+ File canonicalDir = file.getParentFile().getCanonicalFile();
+ fileInCanonicalDir = new File(canonicalDir, file.getName());
+ }
+
+ if (fileInCanonicalDir.getCanonicalFile().equals(fileInCanonicalDir.getAbsoluteFile())) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public static void writeStringToFile(File file, String data, Charset charset) throws IOException {
+ writeStringToFile(file, data, charset, false);
+ }
+
+ public static void writeStringToFile(File file, String data, Charset charset, boolean append)
+ throws IOException {
+ OutputStream out = null;
+ try {
+ out = new FileOutputStream(file, append);
+ IOs.write(data, out, charset);
+ out.close();
+ } finally {
+ IOs.close(out);
+ }
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/io/IOs.java b/tools/commons/src/main/java/com/ekingstar/commons/io/IOs.java
new file mode 100644
index 0000000..351eb0f
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/io/IOs.java
@@ -0,0 +1,133 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.io;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Simple IO Utility
+ *
+ * @author chaostone
+ * @since 3.1
+ */
+public class IOs {
+ private static final int DefaultBufferSize = 1024 * 4;
+ private static final int Eof = -1;
+
+ /**
+ * Copy bytes from a <code>InputStream</code> to an <code>OutputStream</code>.
+ *
+ * @param input the <code>InputStream</code> to read from
+ * @param output the <code>OutputStream</code> to write to
+ * @return the number of bytes copied
+ * @throws NullPointerException if the input or output is null
+ * @throws IOException if an I/O error occurs
+ * @since 3.1
+ */
+ public static long copy(InputStream input, OutputStream output) throws IOException {
+ byte[] buffer = new byte[DefaultBufferSize];
+ long count = 0;
+ int n = 0;
+ while (Eof != (n = input.read(buffer))) {
+ output.write(buffer, 0, n);
+ count += n;
+ }
+ return count;
+ }
+
+ /**
+ * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
+ *
+ * @param input the <code>Reader</code> to read from
+ * @param output the <code>Writer</code> to write to
+ * @return the number of characters copied
+ * @throws NullPointerException if the input or output is null
+ * @throws IOException if an I/O error occurs
+ * @since 3.1
+ */
+ public static long copy(Reader input, Writer output) throws IOException {
+ char[] buffer = new char[DefaultBufferSize];
+ long count = 0;
+ int n = 0;
+ while (Eof != (n = input.read(buffer))) {
+ output.write(buffer, 0, n);
+ count += n;
+ }
+ return count;
+ }
+
+ /**
+ * Get the contents of a <code>Reader</code> as a list of Strings,
+ * one entry per line.
+ * <p>
+ *
+ * @param input the <code>Reader</code> to read from, not null
+ * @return the list of Strings, never null
+ * @throws IOException if an I/O error occurs
+ * @since 1.1
+ */
+ public static List<String> readLines(Reader input) throws IOException {
+ BufferedReader reader = toBufferedReader(input);
+ List<String> list = new ArrayList<String>();
+ String line = reader.readLine();
+ while (line != null) {
+ list.add(line);
+ line = reader.readLine();
+ }
+ return list;
+ }
+
+ public static List<String> readLines(InputStream input) throws IOException {
+ return readLines(new InputStreamReader(input));
+ }
+
+ public static void write(String data, OutputStream output, Charset encoding) throws IOException {
+ if (data != null) {
+ if (encoding == null) {
+ output.write(data.getBytes());
+ } else {
+ output.write(data.getBytes(encoding));
+ }
+ }
+ }
+
+ public static void close(Closeable closeable) {
+ try {
+ if (closeable != null) {
+ closeable.close();
+ }
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+
+ private static BufferedReader toBufferedReader(Reader reader) {
+ return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader);
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/io/StringBuilderWriter.java b/tools/commons/src/main/java/com/ekingstar/commons/io/StringBuilderWriter.java
new file mode 100644
index 0000000..c3298c5
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/io/StringBuilderWriter.java
@@ -0,0 +1,139 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.io;
+
+import java.io.Serializable;
+import java.io.Writer;
+
+/**
+ * {@link Writer} implementation that outputs to a {@link StringBuilder}.
+ * <p>
+ * <strong>NOTE:</strong> This implementation, as an alternative to
+ * <code>java.io.StringWriter</code>, provides an <i>un-synchronized</i> (i.e. for use in a single
+ * thread) implementation for better performance. For safe usage with multiple {@link Thread}s then
+ * <code>java.io.StringWriter</code> should be used.
+ *
+ * @author chaostone
+ * @since 3.1
+ */
+public class StringBuilderWriter extends Writer implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final StringBuilder builder;
+
+ /**
+ * Construct a new {@link StringBuilder} instance with default capacity.
+ */
+ public StringBuilderWriter() {
+ this.builder = new StringBuilder();
+ }
+
+ /**
+ * Construct a new {@link StringBuilder} instance with the specified capacity.
+ *
+ * @param capacity The initial capacity of the underlying {@link StringBuilder}
+ */
+ public StringBuilderWriter(int capacity) {
+ this.builder = new StringBuilder(capacity);
+ }
+
+ /**
+ * Construct a new instance with the specified {@link StringBuilder}.
+ *
+ * @param builder The String builder
+ */
+ public StringBuilderWriter(StringBuilder builder) {
+ this.builder = builder != null ? builder : new StringBuilder();
+ }
+
+ /**
+ * Append a single character to this Writer.
+ */
+ @Override
+ public Writer append(char value) {
+ builder.append(value);
+ return this;
+ }
+
+ /**
+ * Append a character sequence to this Writer.
+ */
+ @Override
+ public Writer append(CharSequence value) {
+ builder.append(value);
+ return this;
+ }
+
+ /**
+ * Append a portion of a character sequence to the {@link StringBuilder}.
+ */
+ @Override
+ public Writer append(CharSequence value, int start, int end) {
+ builder.append(value, start, end);
+ return this;
+ }
+
+ /**
+ * Closing this writer has no effect.
+ */
+ @Override
+ public void close() {
+ }
+
+ /**
+ * Flushing this writer has no effect.
+ */
+ @Override
+ public void flush() {
+ }
+
+ /**
+ * Write a String to the {@link StringBuilder}.
+ *
+ * @param value The value to write
+ */
+ @Override
+ public void write(String value) {
+ if (value != null) builder.append(value);
+ }
+
+ /**
+ * Write a portion of a character array to the {@link StringBuilder}.
+ */
+ @Override
+ public void write(char[] value, int offset, int length) {
+ if (value != null) builder.append(value, offset, length);
+ }
+
+ /**
+ * Return the underlying builder.
+ */
+ public StringBuilder getBuilder() {
+ return builder;
+ }
+
+ /**
+ * Returns {@link StringBuilder#toString()}.
+ */
+ @Override
+ public String toString() {
+ return builder.toString();
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/Arrays.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/Arrays.java
new file mode 100644
index 0000000..8f0dc6e
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/Arrays.java
@@ -0,0 +1,142 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import java.lang.reflect.Array;
+import java.util.List;
+
+/**
+ * <p>
+ * Operations on arrays, primitive arrays (like {@code int[]}) and primitive wrapper arrays (like
+ * {@code Integer[]}).
+ * </p>
+ * <p>
+ * This class tries to handle {@code null} input gracefully. An exception will not be thrown for a
+ * {@code null} array input.
+ * </p>
+ *
+ * @author chaostone
+ * @since 3.0.0
+ */
+public final class Arrays {
+
+ /**
+ * <p>
+ * Checks if an array of Objects is empty or {@code null}.
+ * </p>
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is empty or {@code null}
+ */
+ public static boolean isEmpty(Object[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
+ * <p>
+ * Produces a new array containing the elements between the start and end indices.
+ * </p>
+ * <p>
+ * The start index is inclusive, the end index exclusive. Null array input produces null output.
+ * </p>
+ * <p>
+ * The component type of the subarray is always the same as that of the input array. Thus, if the
+ * input is an array of type {@code Date}, the following usage is envisaged:
+ * </p>
+ *
+ * <pre>
+ * Date[] someDates = (Date[]) Arrays.subarray(allDates, 2, 5);
+ * </pre>
+ *
+ * @param <T> the component type of the array
+ * @param array the array
+ * @param startIndexInclusive the starting index. Undervalue (<0)
+ * is promoted to 0, overvalue (>array.length) results
+ * in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the
+ * returned subarray. Undervalue (< startIndex) produces
+ * empty array, overvalue (>array.length) is demoted to
+ * array length.
+ * @return a new array containing the elements between
+ * the start and end indices.
+ */
+ public static <T> T[] subarray(T[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) { return null; }
+ if (startIndexInclusive < 0) {
+ startIndexInclusive = 0;
+ }
+ if (endIndexExclusive > array.length) {
+ endIndexExclusive = array.length;
+ }
+ int newSize = endIndexExclusive - startIndexInclusive;
+ Class<?> type = array.getClass().getComponentType();
+ if (newSize <= 0) {
+ @SuppressWarnings("unchecked")
+ // OK, because array is of type T
+ final T[] emptyArray = (T[]) Array.newInstance(type, 0);
+ return emptyArray;
+ }
+ @SuppressWarnings("unchecked")
+ // OK, because array is of type T
+ T[] subarray = (T[]) Array.newInstance(type, newSize);
+ System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
+ return subarray;
+ }
+
+ /**
+ * join multi array
+ *
+ * @param arrays
+ * @return
+ */
+ public static byte[] join(List<byte[]> arrays) {
+ int maxlength = 0;
+ for (byte[] array : arrays) {
+ maxlength += array.length;
+ }
+ byte[] rs = new byte[maxlength];
+ int pos = 0;
+ for (byte[] array : arrays) {
+ System.arraycopy(array, 0, rs, pos, array.length);
+ pos += array.length;
+ }
+ return rs;
+ }
+
+ /**
+ * join two array
+ *
+ * @param array1
+ * @param array2
+ * @return
+ */
+ public static byte[] join(byte[] array1, byte[] array2) {
+ if (array1 == null) return clone(array2);
+ else if (array2 == null) return clone(array1);
+ byte[] joinedArray = new byte[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ private static byte[] clone(byte[] array) {
+ if (array == null) return null;
+ return (byte[]) array.clone();
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/Assert.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/Assert.java
new file mode 100644
index 0000000..5ee2a29
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/Assert.java
@@ -0,0 +1,207 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import java.util.Iterator;
+
+/**
+ * Assertion tool class
+ *
+ * @author chaostone
+ * @since 3.0.0
+ */
+public class Assert {
+ private static final String NotEmptyCharSeqMsg = "The validated character sequence is empty";
+ private static final String IsNullMsg = "The validated object is null";
+ private static final String IsTrueMsg = "The validated expression is false";
+
+ /**
+ * <p>
+ * Validate that the argument condition is {@code true}; otherwise throwing an exception. This
+ * method is useful when validating according to an arbitrary boolean expression, such as
+ * validating a primitive number or using your own custom validation expression.
+ * </p>
+ *
+ * <pre>
+ * Assert.isTrue(i > 0);
+ * Assert.isTrue(myObject.isOk());
+ * </pre>
+ * <p>
+ * The message of the exception is "The validated expression is false".
+ * </p>
+ *
+ * @param expression the boolean expression to check
+ * @throws IllegalArgumentException if expression is {@code false}
+ * @see #isTrue(boolean, String, Object...)
+ */
+ public static void isTrue(boolean expression) {
+ if (expression == false) { throw new IllegalArgumentException(IsTrueMsg); }
+ }
+
+ /**
+ * <p>
+ * Validate that the argument condition is {@code true}; otherwise throwing an exception with the
+ * specified message. This method is useful when validating according to an arbitrary boolean
+ * expression, such as validating a primitive number or using your own custom validation
+ * expression.
+ * </p>
+ *
+ * <pre>
+ * Assert.isTrue(i >= min && i <= max, "The value must be between %d and %d", min, max);
+ * Assert.isTrue(myObject.isOk(), "The object is not okay");
+ * </pre>
+ *
+ * @param expression the boolean expression to check
+ * @param message the {@link String#format(String, Object...)} exception message if invalid, not
+ * null
+ * @param values the optional values for the formatted exception message, null array not
+ * recommended
+ * @throws IllegalArgumentException if expression is {@code false}
+ * @see #isTrue(boolean)
+ */
+ public static void isTrue(boolean expression, String message, Object... values) {
+ if (!expression) { throw new IllegalArgumentException(String.format(message, values)); }
+ }
+
+ /**
+ * <p>
+ * Validate that the specified argument is not {@code null}; otherwise throwing an exception.
+ *
+ * <pre>
+ * Assert.notNull(myObject, "The object must not be null");
+ * </pre>
+ * <p>
+ * The message of the exception is "The validated object is null".
+ * </p>
+ *
+ * @param <T> the object type
+ * @param object the object to check
+ * @return the validated object (never {@code null} for method chaining)
+ * @throws NullPointerException if the object is {@code null}
+ * @see #notNull(Object, String, Object...)
+ */
+ public static <T> T notNull(T object) {
+ return notNull(object, IsNullMsg);
+ }
+
+ /**
+ * <p>
+ * Validate that the specified argument is not {@code null}; otherwise throwing an exception with
+ * the specified message.
+ *
+ * <pre>
+ * Assert.notNull(myObject, "The object must not be null");
+ * </pre>
+ *
+ * @param <T> the object type
+ * @param object the object to check
+ * @param message the {@link String#format(String, Object...)} exception message if invalid, not
+ * null
+ * @param values the optional values for the formatted exception message
+ * @return the validated object (never {@code null} for method chaining)
+ * @throws NullPointerException if the object is {@code null}
+ * @see #notNull(Object)
+ */
+ public static <T> T notNull(T object, String message, Object... values) {
+ if (object == null) { throw new NullPointerException(String.format(message, values)); }
+ return object;
+ }
+
+ /**
+ * <p>
+ * Validate that the specified argument array is neither {@code null} nor a length of zero (no
+ * elements); otherwise throwing an exception.
+ *
+ * <pre>
+ * Assert.notEmpty(myArray);
+ * </pre>
+ * <p>
+ * The message in the exception is "The validated array is empty".
+ *
+ * @param <T> the array type
+ * @return the validated array (never {@code null} method for chaining)
+ * @throws NullPointerException if the array is {@code null}
+ * @throws IllegalArgumentException if the array is empty
+ */
+ public static <T extends CharSequence> T notEmpty(T chars) {
+ if (chars == null) { throw new NullPointerException(NotEmptyCharSeqMsg); }
+ if (chars.length() == 0) { throw new IllegalArgumentException(NotEmptyCharSeqMsg); }
+ return chars;
+ }
+
+ /**
+ * <p>
+ * Validate that the specified argument character sequence is neither {@code null} nor a length of
+ * zero (no characters); otherwise throwing an exception with the specified message.
+ *
+ * <pre>
+ * Assert.notEmpty(myString);
+ * </pre>
+ * <p>
+ * The message in the exception is "The validated character sequence is empty".
+ * </p>
+ *
+ * @param <T> the character sequence type
+ * @param chars the character sequence to check, validated not null by this method
+ * @return the validated character sequence (never {@code null} method for chaining)
+ * @throws NullPointerException if the character sequence is {@code null}
+ * @throws IllegalArgumentException if the character sequence is empty
+ */
+ public static <T extends CharSequence> T notEmpty(T chars, String message, Object... values) {
+ if (chars == null) { throw new NullPointerException(String.format(message, values)); }
+ if (chars.length() == 0) { throw new IllegalArgumentException(String.format(message, values)); }
+ return chars;
+ }
+
+ /**
+ * <p>
+ * Validate that the specified argument iterable is neither {@code null} nor contains any elements
+ * that are {@code null}; otherwise throwing an exception with the specified message.
+ *
+ * <pre>
+ * Assert.noNullElements(myCollection, "The collection contains null at position %d");
+ * </pre>
+ * <p>
+ * If the iterable is {@code null}, then the message in the exception is "The validated
+ * object is null".
+ * </p>
+ * <p>
+ * If the iterable has a {@code null} element, then the iteration index of the invalid element is
+ * appended to the {@code values} argument.
+ * </p>
+ *
+ * @param <T> the iterable type
+ * @param iterable the iterable to check, validated not null by this method
+ * @param message the {@link String#format(String, Object...)} exception message if invalid, not
+ * null
+ * @param values the optional values for the formatted exception message, null array not
+ * recommended
+ * @return the validated iterable (never {@code null} method for chaining)
+ * @throws NullPointerException if the array is {@code null}
+ * @throws IllegalArgumentException if an element is {@code null}
+ */
+ public static <T extends Iterable<?>> T noNullElements(T iterable, String message, Object... values) {
+ notNull(iterable);
+ int i = 0;
+ for (Iterator<?> it = iterable.iterator(); it.hasNext(); i++) {
+ if (it.next() == null) { throw new IllegalArgumentException(String.format(message, Integer.valueOf(i))); }
+ }
+ return iterable;
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/BitStrings.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/BitStrings.java
new file mode 100755
index 0000000..c01305e
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/BitStrings.java
@@ -0,0 +1,152 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+/**
+ * <p>
+ * BitStrings class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class BitStrings {
+
+ BitStrings() {
+ }
+
+ /**
+ * 比较两个等长字符串的每一位,若都大于0,则返回结果的相应位为1,否则为0;
+ *
+ * @param first a {@link java.lang.String} object.
+ * @param second a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String and(final String first, final String second) {
+ final StringBuilder buffer = new StringBuilder();
+ for (int i = 0; i < first.length(); i++) {
+ if ('0' == first.charAt(i) || '0' == second.charAt(i)) {
+ buffer.append('0');
+ } else {
+ buffer.append('1');
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * 比较两个等长字符串的每一位,相或<br>
+ * 适用于仅含有1和0的字符串.
+ *
+ * @param first a {@link java.lang.String} object.
+ * @param second a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String or(final String first, final String second) {
+ final StringBuilder buffer = new StringBuilder();
+ for (int i = 0; i < first.length(); i++) {
+ if ('0' == first.charAt(i) && '0' == second.charAt(i)) {
+ buffer.append('0');
+ } else {
+ buffer.append('1');
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * 将一个字符串,按照boolString的形式进行变化. 如果boolString[i]!=0则保留str[i],否则置0
+ *
+ * @param str a {@link java.lang.String} object.
+ * @param boolString a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String andWith(final String str, final String boolString) {
+ if (Strings.isEmpty(str)) { return null; }
+ if (Strings.isEmpty(boolString)) { return str; }
+ if (str.length() < boolString.length()) { return str; }
+ final StringBuilder buffer = new StringBuilder(str);
+ for (int i = 0; i < buffer.length(); i++) {
+ if (boolString.charAt(i) == '0') {
+ buffer.setCharAt(i, '0');
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * 将"314213421340asdf"转换成"1111111111101111"
+ *
+ * @param first a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String convertToBoolStr(final String first) {
+ final StringBuilder occupyBuffer = new StringBuilder(first.length());
+ for (int i = 0; i < first.length(); i++) {
+ if ('0' == first.charAt(i)) {
+ occupyBuffer.append('0');
+ } else {
+ occupyBuffer.append('1');
+ }
+
+ }
+ return occupyBuffer.toString();
+ }
+
+ /**
+ * 返回零一串的整型值
+ *
+ * @param binaryStr a {@link java.lang.String} object.
+ * @return a long.
+ */
+ public static long binValueOf(final String binaryStr) {
+ if (Strings.isEmpty(binaryStr)) { return 0; }
+ long value = 0;
+ long height = 1;
+
+ for (int i = binaryStr.length() - 1; i >= 0; i--) {
+ if ('1' == binaryStr.charAt(i)) {
+ value += height;
+ }
+ height *= 2;
+ }
+ return value;
+ }
+
+ /**
+ * <p>
+ * reverse.
+ * </p>
+ *
+ * @param binaryStr a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String reverse(final String binaryStr) {
+ final StringBuilder occupyBuffer = new StringBuilder(binaryStr.length());
+ for (int i = 0; i < binaryStr.length(); i++) {
+ if ('0' == binaryStr.charAt(i)) {
+ occupyBuffer.append('1');
+ } else {
+ occupyBuffer.append('0');
+ }
+ }
+ return occupyBuffer.toString();
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/Chars.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/Chars.java
new file mode 100644
index 0000000..a6c1ee0
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/Chars.java
@@ -0,0 +1,44 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+public final class Chars {
+
+ /**
+ * <p>
+ * Checks whether the character is ASCII 7 bit alphabetic.
+ * </p>
+ *
+ * <pre>
+ * isAsciiAlpha('a') = true
+ * isAsciiAlpha('A') = true
+ * isAsciiAlpha('3') = false
+ * isAsciiAlpha('-') = false
+ * isAsciiAlpha('\n') = false
+ * isAsciiAlpha('©') = false
+ * </pre>
+ *
+ * @param ch the character to check
+ * @return true if between 65 and 90 or 97 and 122 inclusive
+ * @since 3.0
+ */
+ public static boolean isAsciiAlpha(char ch) {
+ return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/Charsets.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/Charsets.java
new file mode 100644
index 0000000..6b2a43e
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/Charsets.java
@@ -0,0 +1,65 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import java.nio.charset.Charset;
+
+/**
+ * Contains constant definitions for the six standard {@link Charset} instances, which are
+ * guaranteed to be supported by all Java platform implementations.
+ *
+ * @author chaostone
+ * @since 3.1
+ */
+public final class Charsets {
+
+ private Charsets() {
+ }
+
+ /**
+ * US-ASCII: seven-bit ASCII, the Basic Latin block of the Unicode character set (ISO646-US).
+ */
+ public static final Charset US_ASCII = Charset.forName("US-ASCII");
+
+ /**
+ * ISO-8859-1: ISO Latin Alphabet Number 1 (ISO-LATIN-1).
+ */
+ public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+
+ /**
+ * UTF-8: eight-bit UCS Transformation Format.
+ */
+ public static final Charset UTF_8 = Charset.forName("UTF-8");
+
+ /**
+ * UTF-16BE: sixteen-bit UCS Transformation Format, big-endian byte order.
+ */
+ public static final Charset UTF_16BE = Charset.forName("UTF-16BE");
+
+ /**
+ * UTF-16LE: sixteen-bit UCS Transformation Format, little-endian byte order.
+ */
+ public static final Charset UTF_16LE = Charset.forName("UTF-16LE");
+
+ /**
+ * UTF-16: sixteen-bit UCS Transformation Format, byte order identified by an optional
+ * byte-order-mark.
+ */
+ public static final Charset UTF_16 = Charset.forName("UTF-16");
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/Dates.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/Dates.java
new file mode 100644
index 0000000..7ec3759
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/Dates.java
@@ -0,0 +1,46 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * Dates class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: DateUtils.java Jul 26, 2011 4:22:37 PM chaostone $
+ */
+public final class Dates {
+
+ /**
+ * <p>
+ * rollMinutes.
+ * </p>
+ *
+ * @param date a {@link java.util.Date} object.
+ * @param mount a int.
+ * @return a {@link java.util.Date} object.
+ */
+ public static Date rollMinutes(Date date, int mount) {
+ // Do not user calendar.roll. it will never modify hour
+ return new Date(date.getTime() + mount * 60 * 1000);
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/Numbers.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/Numbers.java
new file mode 100644
index 0000000..253edbf
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/Numbers.java
@@ -0,0 +1,119 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import java.math.BigDecimal;
+
+public final class Numbers {
+
+ /**
+ * <p>
+ * Convert a <code>String</code> to an <code>int</code>, returning <code>zero</code> if the
+ * conversion fails.
+ * </p>
+ * <p>
+ * If the string is <code>null</code>, <code>zero</code> is returned.
+ * </p>
+ *
+ * <pre>
+ * toInt(null) = 0
+ * toInt("") = 0
+ * toInt("1") = 1
+ * </pre>
+ *
+ * @param str the string to convert, may be null
+ * @return the int represented by the string, or <code>zero</code> if
+ * conversion fails
+ * @since 3.0
+ */
+ public static int toInt(String str) {
+ return toInt(str, 0);
+ }
+
+ /**
+ * <p>
+ * Convert a <code>String</code> to an <code>int</code>, returning a default value if the
+ * conversion fails.
+ * </p>
+ * <p>
+ * If the string is <code>null</code>, the default value is returned.
+ * </p>
+ *
+ * <pre>
+ * toInt(null, 1) = 1
+ * toInt("", 1) = 1
+ * toInt("1", 0) = 1
+ * </pre>
+ *
+ * @param str the string to convert, may be null
+ * @param defaultValue the default value
+ * @return the int represented by the string, or the default if conversion fails
+ * @since 3.0
+ */
+ public static int toInt(String str, int defaultValue) {
+ if (str == null) { return defaultValue; }
+ try {
+ return Integer.parseInt(str);
+ } catch (NumberFormatException nfe) {
+ return defaultValue;
+ }
+ }
+
+ public static float toFloat(String str) {
+ return toFloat(str, 0.0f);
+ }
+
+ public static float toFloat(String str, float defaultValue) {
+ if (str == null) return defaultValue;
+ try {
+ return Float.parseFloat(str);
+ } catch (NumberFormatException nfe) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * <p>
+ * Checks whether the <code>String</code> contains only digit characters.
+ * </p>
+ * <p>
+ * <code>Null</code> and empty String will return <code>false</code>.
+ * </p>
+ *
+ * @param str the <code>String</code> to check
+ * @return <code>true</code> if str contains only Unicode numeric
+ */
+ public static boolean isDigits(String str) {
+ if (Strings.isEmpty(str)) return false;
+ for (int i = 0; i < str.length(); i++) {
+ if (!Character.isDigit(str.charAt(i))) return false;
+ }
+ return true;
+ }
+
+ public static boolean isNumber(String str) {
+ if (Strings.isEmpty(str)) return false;
+ try {
+ new BigDecimal(str);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/Objects.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/Objects.java
new file mode 100644
index 0000000..e1fda44
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/Objects.java
@@ -0,0 +1,663 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+
+public final class Objects {
+
+ /**
+ * <p>
+ * Compares two objects for equality, where either one or both objects may be {@code null}.
+ * </p>
+ *
+ * <pre>
+ * equals(null, null) = true
+ * equals(null, "") = false
+ * equals("", null) = false
+ * equals("", "") = true
+ * equals(Boolean.TRUE, null) = false
+ * equals(Boolean.TRUE, "true") = false
+ * equals(Boolean.TRUE, Boolean.TRUE) = true
+ * equals(Boolean.TRUE, Boolean.FALSE) = false
+ * </pre>
+ *
+ * @param a the first object, may be {@code null}
+ * @param b the second object, may be {@code null}
+ * @return {@code true} if the values of both objects are the same
+ * @since 3.0
+ */
+ public static boolean equals(Object a, Object b) {
+ return (a == b) || (a != null && a.equals(b));
+ }
+
+ /**
+ * <p>
+ * Compares two object array for equality, where either one or both objects may be {@code null}.
+ * </p>
+ */
+ public static boolean equals(Object[] a, Object b[]) {
+ if (a == b) return true;
+ if (null == a || null == b) return false;
+
+ if (a.length != b.length) return false;
+ for (int i = 0; i < a.length; ++i) {
+ if (!Objects.equals(a[i], b[i])) return false;
+ }
+ return true;
+ }
+
+ /**
+ * <p>
+ * Gets the {@code toString} of an {@code Object} returning an empty string ("") if {@code null}
+ * input.
+ * </p>
+ *
+ * <pre>
+ * toString(null) = ""
+ * toString("") = ""
+ * toString("bat") = "bat"
+ * toString(Boolean.TRUE) = "true"
+ * </pre>
+ *
+ * @see String#valueOf(Object)
+ * @param obj the Object to {@code toString}, may be null
+ * @return the passed in Object's toString, or nullStr if {@code null} input
+ * @since 3.0
+ */
+ public static String toString(Object obj) {
+ return obj == null ? "" : obj.toString();
+ }
+
+ // -----------------------------------------------------------------------
+ /**
+ * <p>
+ * Returns a default value if the object passed is {@code null}.
+ * </p>
+ *
+ * <pre>
+ * defaultIfNull(null, null) = null
+ * defaultIfNull(null, "") = ""
+ * defaultIfNull(null, "zz") = "zz"
+ * defaultIfNull("abc", *) = "abc"
+ * defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
+ * </pre>
+ *
+ * @param <T> the type of the object
+ * @param object the {@code Object} to test, may be {@code null}
+ * @param defaultValue the default value to return, may be {@code null}
+ * @return {@code object} if it is not {@code null}, defaultValue otherwise
+ * @since 3.0
+ */
+ public static <T> T defaultIfNull(T object, T defaultValue) {
+ return object != null ? object : defaultValue;
+ }
+
+ public static Object defaultValue(Class<?> clazz) {
+ if (clazz.equals(boolean.class)) return false;
+ if (clazz.equals(int.class)) return 0;
+ if (clazz.equals(short.class)) return (short) 0;
+ if (clazz.equals(long.class)) return 0L;
+ if (clazz.equals(float.class)) return 0.0f;
+ if (clazz.equals(double.class)) return 0.0d;
+ if (clazz.equals(char.class)) return (char) 0;
+ if (clazz.equals(byte.class)) return (byte) 0;
+ return null;
+ }
+
+ /**
+ * Return a hex String form of an object's identity hash code.
+ *
+ * @param obj the object
+ * @return the object's identity code in hex notation
+ */
+ public static String getIdentityHexString(Object obj) {
+ return Integer.toHexString(System.identityHashCode(obj));
+ }
+
+ public static CompareBuilder compareBuilder() {
+ return new CompareBuilder();
+ }
+
+ public static EqualsBuilder equalsBuilder() {
+ return new EqualsBuilder();
+ }
+
+ /**
+ * Creates an instance of {@link ToStringBuilder}.
+ * <p>
+ * This is helpful for implementing {@link Object#toString()}. Specification by example:
+ *
+ * <pre>
+ * {@code
+ * // Returns "ClassName{}"
+ * Objects.toStringBuilder(this)
+ * .toString();
+ *
+ * // Returns "ClassName{x=1}"
+ * Objects.toStringBuilder(this)
+ * .add("x", 1)
+ * .toString();
+ *
+ * // Returns "MyObject{x=1}"
+ * Objects.toStringBuilder("MyObject")
+ * .add("x", 1)
+ * .toString();
+ *
+ * // Returns "ClassName{x=1, y=foo}"
+ * Objects.toStringBuilder(this)
+ * .add("x", 1)
+ * .add("y", "foo")
+ * .toString();
+ * }}
+ *
+ * // Returns "ClassName{x=1}"
+ * Objects.toStringBuilder(this)
+ * .omitNullValues()
+ * .add("x", 1)
+ * .add("y", null)
+ * .toString();
+ * }}
+ * </pre>
+ *
+ * @param self the object to generate the string for (typically {@code this}),
+ * used only for its class name
+ * @since 3.1
+ */
+ public static ToStringBuilder toStringBuilder(Object self) {
+ return new ToStringBuilder(simpleName(self.getClass()));
+ }
+
+ /**
+ * Creates an instance of {@link ToStringBuilder} in the same manner as
+ * {@link Objects#toStringBuilder(Object)}, but using the name of {@code clazz} instead of using
+ * an
+ * instance's {@link Object#getClass()}.
+ * <p>
+ *
+ * @param clazz the {@link Class} of the instance
+ */
+ public static ToStringBuilder toStringBuilder(Class<?> clazz) {
+ return new ToStringBuilder(simpleName(clazz));
+ }
+
+ /**
+ * Creates an instance of {@link ToStringBuilder} in the same manner as
+ * {@link Objects#toStringBuilder(Object)}, but using {@code className} instead
+ * of using an instance's {@link Object#getClass()}.
+ *
+ * @param className the name of the instance type
+ */
+ public static ToStringBuilder toStringBuilder(String className) {
+ return new ToStringBuilder(className);
+ }
+
+ /**
+ * More readable than {@link Class#getSimpleName()}
+ */
+ private static String simpleName(Class<?> clazz) {
+ String name = clazz.getName();
+
+ // the nth anonymous class has a class name ending in "Outer$n"
+ // and local inner classes have names ending in "Outer.$1Inner"
+ name = name.replaceAll("\\$[0-9]+", "\\$");
+
+ // we want the name of the inner class all by its lonesome
+ int start = name.lastIndexOf('$');
+
+ // if this isn't an inner class, just find the start of the
+ // top level class name.
+ if (start == -1) start = name.lastIndexOf('.');
+ return name.substring(start + 1);
+ }
+
+ /**
+ * Support class for {@link Objects#toStringBuilder}.
+ */
+ public static final class ToStringBuilder {
+ private final String className;
+ private final List<ValueHolder> valueHolders = new LinkedList<ValueHolder>();
+ private boolean omitNull = false;
+
+ /**
+ * Use {@link Objects#toStringBuilder(Object)} to create an instance.
+ */
+ private ToStringBuilder(String className) {
+ this.className = className;
+ }
+
+ /**
+ * When called, the formatted output returned by {@link #toString()} will
+ * ignore {@code null} values.
+ */
+ public ToStringBuilder omitNull() {
+ omitNull = true;
+ return this;
+ }
+
+ /**
+ * Adds a name/value pair to the formatted output in {@code name=value} format. If {@code value}
+ * is {@code null}, the string {@code "null"} is used, unless {@link #omitNull()} is
+ * called, in which case this
+ * name/value pair will not be added.
+ */
+ public ToStringBuilder add(String name, Object value) {
+ addHolder(value).builder.append(name).append('=').append(value);
+ return this;
+ }
+
+ /**
+ * Returns a string in the format specified by {@link Objects#toStringBuilder(Object)}.
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder(32).append(className).append('{');
+ boolean needsSeparator = false;
+ for (ValueHolder valueHolder : valueHolders) {
+ if (!omitNull || !valueHolder.isNull) {
+ if (needsSeparator) builder.append(", ");
+ else needsSeparator = true;
+ builder.append(valueHolder.builder);
+ }
+ }
+ return builder.append('}').toString();
+ }
+
+ private ValueHolder addHolder() {
+ ValueHolder valueHolder = new ValueHolder();
+ valueHolders.add(valueHolder);
+ return valueHolder;
+ }
+
+ private ValueHolder addHolder(Object value) {
+ ValueHolder valueHolder = addHolder();
+ valueHolder.isNull = (value == null);
+ return valueHolder;
+ }
+
+ private static final class ValueHolder {
+ final StringBuilder builder = new StringBuilder();
+ boolean isNull;
+ }
+ }
+
+ public static final class CompareBuilder {
+ private int comparison = 0;
+
+ public CompareBuilder add(Object lhs, Object rhs) {
+ return add(lhs, rhs, null);
+
+ }
+
+ public CompareBuilder add(Object lhs, Object rhs, Comparator<?> comparator) {
+ if (comparison != 0) return this;
+ if (lhs == rhs) return this;
+ if (lhs == null) {
+ comparison = -1;
+ return this;
+ }
+ if (rhs == null) {
+ comparison = +1;
+ return this;
+ }
+ if (lhs.getClass().isArray()) {
+ // switch on type of array, to dispatch to the correct handler
+ // handles multi dimensional arrays
+ // throws a ClassCastException if rhs is not the correct array type
+ if (lhs instanceof long[]) {
+ add((long[]) lhs, (long[]) rhs);
+ } else if (lhs instanceof int[]) {
+ add((int[]) lhs, (int[]) rhs);
+ } else if (lhs instanceof short[]) {
+ add((short[]) lhs, (short[]) rhs);
+ } else if (lhs instanceof char[]) {
+ add((char[]) lhs, (char[]) rhs);
+ } else if (lhs instanceof byte[]) {
+ add((byte[]) lhs, (byte[]) rhs);
+ } else if (lhs instanceof double[]) {
+ add((double[]) lhs, (double[]) rhs);
+ } else if (lhs instanceof float[]) {
+ add((float[]) lhs, (float[]) rhs);
+ } else if (lhs instanceof boolean[]) {
+ add((boolean[]) lhs, (boolean[]) rhs);
+ } else {
+ // not an array of primitives
+ // throws a ClassCastException if rhs is not an array
+ add((Object[]) lhs, (Object[]) rhs, comparator);
+ }
+ } else {
+ // the simple case, not an array, just test the element
+ if (comparator == null) {
+ @SuppressWarnings("unchecked")
+ final Comparable<Object> comparable = (Comparable<Object>) lhs;
+ comparison = comparable.compareTo(rhs);
+ } else {
+ @SuppressWarnings("unchecked")
+ final Comparator<Object> comparator2 = (Comparator<Object>) comparator;
+ comparison = comparator2.compare(lhs, rhs);
+ }
+ }
+ return this;
+ }
+
+ public CompareBuilder add(long lhs, long rhs) {
+ if (comparison != 0) return this;
+ comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
+ return this;
+ }
+
+ public CompareBuilder add(int lhs, int rhs) {
+ if (comparison != 0) return this;
+ comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
+ return this;
+ }
+
+ public CompareBuilder add(short lhs, short rhs) {
+ if (comparison != 0) return this;
+ comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
+ return this;
+ }
+
+ public CompareBuilder add(char lhs, char rhs) {
+ if (comparison != 0) return this;
+ comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
+ return this;
+ }
+
+ public CompareBuilder add(byte lhs, byte rhs) {
+ if (comparison != 0) return this;
+ comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
+ return this;
+ }
+
+ public CompareBuilder add(double lhs, double rhs) {
+ if (comparison != 0) return this;
+ comparison = Double.compare(lhs, rhs);
+ return this;
+ }
+
+ public CompareBuilder add(float lhs, float rhs) {
+ if (comparison != 0) return this;
+ comparison = Float.compare(lhs, rhs);
+ return this;
+ }
+
+ public CompareBuilder add(boolean lhs, boolean rhs) {
+ if (comparison != 0) return this;
+ if (lhs == rhs) return this;
+ if (lhs == false) comparison = -1;
+ else comparison = +1;
+ return this;
+ }
+
+ public CompareBuilder add(Object[] lhs, Object[] rhs) {
+ return add(lhs, rhs, null);
+ }
+
+ public CompareBuilder add(Object[] lhs, Object[] rhs, Comparator<?> comparator) {
+ if (comparison != 0) return this;
+ if (lhs == rhs) return this;
+ if (lhs == null) {
+ comparison = -1;
+ return this;
+ }
+ if (rhs == null) {
+ comparison = +1;
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ comparison = (lhs.length < rhs.length) ? -1 : +1;
+ return this;
+ }
+ for (int i = 0; i < lhs.length && comparison == 0; i++) {
+ add(lhs[i], rhs[i], comparator);
+ }
+ return this;
+ }
+
+ public CompareBuilder add(long[] lhs, long[] rhs) {
+ if (comparison != 0) return this;
+ if (lhs == rhs) return this;
+ if (lhs == null) {
+ comparison = -1;
+ return this;
+ }
+ if (rhs == null) {
+ comparison = +1;
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ comparison = (lhs.length < rhs.length) ? -1 : +1;
+ return this;
+ }
+ for (int i = 0; i < lhs.length && comparison == 0; i++) {
+ add(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ public CompareBuilder add(int[] lhs, int[] rhs) {
+ if (comparison != 0) return this;
+ if (lhs == rhs) return this;
+ if (lhs == null) {
+ comparison = -1;
+ return this;
+ }
+ if (rhs == null) {
+ comparison = +1;
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ comparison = (lhs.length < rhs.length) ? -1 : +1;
+ return this;
+ }
+ for (int i = 0; i < lhs.length && comparison == 0; i++) {
+ add(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ public CompareBuilder add(short[] lhs, short[] rhs) {
+ if (comparison != 0) return this;
+ if (lhs == rhs) return this;
+ if (lhs == null) {
+ comparison = -1;
+ return this;
+ }
+ if (rhs == null) {
+ comparison = +1;
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ comparison = (lhs.length < rhs.length) ? -1 : +1;
+ return this;
+ }
+ for (int i = 0; i < lhs.length && comparison == 0; i++) {
+ add(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ public CompareBuilder add(char[] lhs, char[] rhs) {
+ if (comparison != 0) return this;
+ if (lhs == rhs) return this;
+ if (lhs == null) {
+ comparison = -1;
+ return this;
+ }
+ if (rhs == null) {
+ comparison = +1;
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ comparison = (lhs.length < rhs.length) ? -1 : +1;
+ return this;
+ }
+ for (int i = 0; i < lhs.length && comparison == 0; i++) {
+ add(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ public CompareBuilder add(byte[] lhs, byte[] rhs) {
+ if (comparison != 0) return this;
+ if (lhs == rhs) return this;
+ if (lhs == null) {
+ comparison = -1;
+ return this;
+ }
+ if (rhs == null) {
+ comparison = +1;
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ comparison = (lhs.length < rhs.length) ? -1 : +1;
+ return this;
+ }
+ for (int i = 0; i < lhs.length && comparison == 0; i++) {
+ add(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ public CompareBuilder add(double[] lhs, double[] rhs) {
+ if (comparison != 0) return this;
+ if (lhs == rhs) return this;
+ if (lhs == null) {
+ comparison = -1;
+ return this;
+ }
+ if (rhs == null) {
+ comparison = +1;
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ comparison = (lhs.length < rhs.length) ? -1 : +1;
+ return this;
+ }
+ for (int i = 0; i < lhs.length && comparison == 0; i++) {
+ add(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ public CompareBuilder add(float[] lhs, float[] rhs) {
+ if (comparison != 0) return this;
+ if (lhs == rhs) return this;
+ if (lhs == null) {
+ comparison = -1;
+ return this;
+ }
+ if (rhs == null) {
+ comparison = +1;
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ comparison = (lhs.length < rhs.length) ? -1 : +1;
+ return this;
+ }
+ for (int i = 0; i < lhs.length && comparison == 0; i++) {
+ add(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ public CompareBuilder add(boolean[] lhs, boolean[] rhs) {
+ if (comparison != 0) return this;
+ if (lhs == rhs) return this;
+ if (lhs == null) {
+ comparison = -1;
+ return this;
+ }
+ if (rhs == null) {
+ comparison = +1;
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ comparison = (lhs.length < rhs.length) ? -1 : +1;
+ return this;
+ }
+ for (int i = 0; i < lhs.length && comparison == 0; i++) {
+ add(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ public int toComparison() {
+ return comparison;
+ }
+ }
+
+ /**
+ * Equals Builder
+ *
+ * @author chaostone
+ * @since 3.1.0
+ */
+ public static final class EqualsBuilder {
+ private boolean equals = true;
+
+ public EqualsBuilder add(Object lhs, Object rhs) {
+ if (!equals) return this;
+ equals &= Objects.equals(lhs, rhs);
+ return this;
+ }
+
+ public EqualsBuilder add(Object[] lhs, Object[] rhs) {
+ if (!equals) return this;
+ equals &= Objects.equals(lhs, rhs);
+ return this;
+ }
+
+ public EqualsBuilder add(int lhs, int rhs) {
+ if (!equals) return this;
+ equals &= (lhs == rhs);
+ return this;
+ }
+
+ public EqualsBuilder add(long lhs, long rhs) {
+ if (!equals) return this;
+ equals &= (lhs == rhs);
+ return this;
+ }
+
+ public EqualsBuilder add(short lhs, short rhs) {
+ if (!equals) return this;
+ equals &= (lhs == rhs);
+ return this;
+ }
+
+ public EqualsBuilder add(boolean lhs, boolean rhs) {
+ if (!equals) return this;
+ equals &= (lhs == rhs);
+ return this;
+ }
+
+ public boolean isEquals() {
+ return equals;
+ }
+ }
+
+ public static boolean isArray(Object obj) {
+ if (null == obj) return false;
+ return obj.getClass().isArray();
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/Primitives.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/Primitives.java
new file mode 100644
index 0000000..5e019b4
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/Primitives.java
@@ -0,0 +1,98 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import java.util.Map;
+
+import com.ekingstar.commons.collection.CollectUtils;
+
+/**
+ * Wrap or Unwrap primitive
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public final class Primitives {
+ private Primitives() {
+ }
+
+ /** Primitive types to their corresponding wrapper types. */
+ private static final Map<Class<?>, Class<?>> PrimitiveToWrappers = CollectUtils.newFastMap(16);
+
+ /** Wrapper types to their corresponding primitive types. */
+ private static final Map<Class<?>, Class<?>> WrapperToPrimitives = CollectUtils.newFastMap(16);
+
+ static {
+ add(boolean.class, Boolean.class);
+ add(byte.class, Byte.class);
+ add(char.class, Character.class);
+ add(double.class, Double.class);
+ add(float.class, Float.class);
+ add(int.class, Integer.class);
+ add(long.class, Long.class);
+ add(short.class, Short.class);
+ add(void.class, Void.class);
+ }
+
+ private static void add(Class<?> key, Class<?> value) {
+ PrimitiveToWrappers.put(key, value);
+ WrapperToPrimitives.put(value, key);
+ }
+
+ /**
+ * Returns {@code true} if {@code type} is one of the nine
+ * primitive-wrapper types, such as {@link Integer}.
+ *
+ * @see Class#isPrimitive
+ */
+ public static boolean isWrapperType(Class<?> type) {
+ return WrapperToPrimitives.containsKey(type);
+ }
+
+ /**
+ * Returns the corresponding wrapper type of {@code type} if it is a primitive
+ * type; otherwise returns {@code type} itself. Idempotent.
+ *
+ * <pre>
+ * wrap(int.class) == Integer.class
+ * wrap(Integer.class) == Integer.class
+ * wrap(String.class) == String.class
+ * </pre>
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Class<T> wrap(Class<T> type) {
+ return (type.isPrimitive() || type == void.class) ? (Class<T>) PrimitiveToWrappers.get(type) : type;
+ }
+
+ /**
+ * Returns the corresponding primitive type of {@code type} if it is a
+ * wrapper type; otherwise returns {@code type} itself. Idempotent.
+ *
+ * <pre>
+ * unwrap(Integer.class) == int.class
+ * unwrap(int.class) == int.class
+ * unwrap(String.class) == String.class
+ * </pre>
+ */
+ public static <T> Class<T> unwrap(Class<T> type) {
+ @SuppressWarnings("unchecked")
+ Class<T> unwrapped = (Class<T>) WrapperToPrimitives.get(type);
+ return (unwrapped == null) ? type : unwrapped;
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/Strings.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/Strings.java
new file mode 100755
index 0000000..ba0e90c
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/Strings.java
@@ -0,0 +1,1460 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import static java.lang.Character.isLowerCase;
+import static java.lang.Character.isUpperCase;
+import static java.lang.Character.toLowerCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import com.ekingstar.commons.collection.CollectUtils;
+
+/**
+ * <p>
+ * Operations on {@link java.lang.String} that are {@code null} safe.
+ * </p>
+ *
+ * @author chaostone 2005-11-15
+ * @version $Id: $
+ * @since 3.0
+ */
+public class Strings {
+
+ /** Constant <code>DELIMITER=","</code> */
+ public static final String DELIMITER = ",";
+
+ private static final String Empty = "";
+
+ private static final int Index_not_found = -1;
+
+ Strings() {
+ }
+
+ /**
+ * <p>
+ * Capitalizes a String changing the first letter to title case as per
+ * {@link Character#toTitleCase(char)}. No other letters are changed.
+ * </p>
+ * <p>
+ * For a word based algorithm, see returns {@code null}.
+ * </p>
+ *
+ * <pre>
+ * capitalize(null) = null
+ * capitalize("") = ""
+ * capitalize("cat") = "Cat"
+ * capitalize("cAt") = "CAt"
+ * </pre>
+ *
+ * @param str the String to capitalize, may be null
+ * @return the capitalized String, {@code null} if null String input
+ * @see #uncapitalize(String)
+ * @since 2.0
+ */
+ public static String capitalize(String str) {
+ int strLen;
+ if (str == null || (strLen = str.length()) == 0) { return str; }
+ return new StringBuilder(strLen).append(Character.toTitleCase(str.charAt(0))).append(str.substring(1))
+ .toString();
+ }
+
+ /**
+ * <p>
+ * concat.
+ * </p>
+ *
+ * @param seq
+ * a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String concat(final String... seq) {
+ return join(seq, "");
+ }
+
+ /**
+ * <p>
+ * Checks if CharSequence contains a search CharSequence, handling {@code null}. This method uses
+ * {@link String#indexOf(String)} if possible.
+ * </p>
+ * <p>
+ * A {@code null} CharSequence will return {@code false}.
+ * </p>
+ *
+ * <pre>
+ * contains(null, *) = false
+ * contains(*, null) = false
+ * contains("", "") = true
+ * contains("abc", "") = true
+ * contains("abc", "a") = true
+ * contains("abc", "z") = false
+ * </pre>
+ *
+ * @param seq the CharSequence to check, may be null
+ * @param searchSeq the CharSequence to find, may be null
+ * @return true if the CharSequence contains the search CharSequence,
+ * false if not or {@code null} string input
+ */
+ public static boolean contains(CharSequence seq, CharSequence searchSeq) {
+ if (seq == null || searchSeq == null) { return false; }
+ return indexOf(seq, searchSeq, 0) >= 0;
+ }
+
+ /**
+ * <p>
+ * Checks if CharSequence contains a search character, handling {@code null}. This method uses
+ * {@link String#indexOf(int)} if possible.
+ * </p>
+ * <p>
+ * A {@code null} or empty ("") CharSequence will return {@code false}.
+ * </p>
+ *
+ * <pre>
+ * contains(null, *) = false
+ * contains("", *) = false
+ * contains("abc", 'a') = true
+ * contains("abc", 'z') = false
+ * </pre>
+ *
+ * @param seq
+ * the CharSequence to check, may be null
+ * @param searchChar
+ * the character to find
+ * @return true if the CharSequence contains the search character,
+ * false if not or {@code null} string input
+ * @since 2.0
+ * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
+ */
+ public static boolean contains(CharSequence seq, int searchChar) {
+ if (isEmpty(seq)) { return false; }
+ return indexOf(seq, searchChar, 0) >= 0;
+ }
+
+ /**
+ * count char in host string
+ *
+ * @param host
+ * a {@link java.lang.String} object.
+ * @param charactor
+ * a char.
+ * @return a int.
+ */
+ public static int count(final String host, final char charactor) {
+ int count = 0;
+ for (int i = 0; i < host.length(); i++) {
+ if (host.charAt(i) == charactor) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * count inner string in host string
+ *
+ * @param host
+ * a {@link java.lang.String} object.
+ * @param searchStr
+ * a {@link java.lang.String} object.
+ * @return a int.
+ */
+ public static int count(final String host, final String searchStr) {
+ int count = 0;
+ for (int startIndex = 0; startIndex < host.length(); startIndex++) {
+ int findLoc = host.indexOf(searchStr, startIndex);
+ if (findLoc == -1) {
+ break;
+ } else {
+ count++;
+ startIndex = findLoc + searchStr.length() - 1;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Returns index of searchChar in cs with begin index {@code start}
+ *
+ * @param searchChar
+ * @param start
+ */
+ private static int indexOf(CharSequence cs, CharSequence searchChar, int start) {
+ return cs.toString().indexOf(searchChar.toString(), start);
+ }
+
+ /**
+ * <p>
+ * Finds the first index in the {@code CharSequence} that matches the specified character.
+ * </p>
+ *
+ * @param cs the {@code CharSequence} to be processed, not null
+ * @param searchChar the char to be searched for
+ * @param start the start index, negative starts at the string start
+ * @return the index where the search char was found, -1 if not found
+ */
+ private static int indexOf(CharSequence cs, int searchChar, int start) {
+ if (cs instanceof String) {
+ return ((String) cs).indexOf(searchChar, start);
+ } else {
+ int sz = cs.length();
+ if (start < 0) {
+ start = 0;
+ }
+ for (int i = start; i < sz; i++) {
+ if (cs.charAt(i) == searchChar) { return i; }
+ }
+ return -1;
+ }
+ }
+
+ /**
+ * <p>
+ * insert.
+ * </p>
+ *
+ * @param str a {@link java.lang.String} object.
+ * @param c a {@link java.lang.String} object.
+ * @param pos a int.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String insert(final String str, final String c, final int pos) {
+ if (str.length() < pos) { return str; }
+ return str.substring(0, pos - 1) + c + str.substring(pos);
+ }
+
+ /**
+ * replace [bigen,end] [1...end] with givenStr
+ * 可以使用StringBuilder的replace方法替换该方法
+ *
+ * @param str a {@link java.lang.String} object.
+ * @param begin a int.
+ * @param end a int.
+ * @param given a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String insert(final String str, final String given, final int begin, final int end) {
+ if (begin < 1 || end > str.length() || end < begin) { return str; }
+ return str.substring(0, begin - 1) + given + str.substring(end);
+ }
+
+ /**
+ * <p>
+ * intersectSeq.
+ * </p>
+ *
+ * @param first
+ * a {@link java.lang.String} object.
+ * @param second
+ * a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String intersectSeq(final String first, final String second) {
+ return intersectSeq(first, second, DELIMITER);
+ }
+
+ /**
+ * 返回一个新的逗号相隔字符串,实现其中的单词a-b的功能
+ *
+ * @param first a {@link java.lang.String} object.
+ * @param second a {@link java.lang.String} object.
+ * @param delimiter a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String intersectSeq(final String first, final String second, final String delimiter) {
+ if (isEmpty(first) || isEmpty(second)) { return ""; }
+ List<String> firstSeq = Arrays.asList(split(first, ','));
+ List<String> secondSeq = Arrays.asList(split(second, ','));
+ Collection<String> rs = CollectUtils.intersection(firstSeq, secondSeq);
+ StringBuilder buf = new StringBuilder();
+ for (final String ele : rs) {
+ buf.append(delimiter).append(ele);
+ }
+ if (buf.length() > 0) {
+ buf.append(delimiter);
+ }
+ return buf.toString();
+ }
+
+ /**
+ * <p>
+ * Checks if a CharSequence is whitespace, empty ("") or null.
+ * </p>
+ *
+ * <pre>
+ * isBlank(null) = true
+ * isBlank("") = true
+ * isBlank(" ") = true
+ * isBlank("bob") = false
+ * isBlank(" bob ") = false
+ * </pre>
+ *
+ * @param cs
+ * the CharSequence to check, may be null
+ * @return {@code true} if the CharSequence is null, empty or whitespace
+ * @since 3.0
+ */
+ public static boolean isBlank(CharSequence cs) {
+ int strLen;
+ if (cs == null || (strLen = cs.length()) == 0) { return true; }
+ for (int i = 0; i < strLen; i++) {
+ if (Character.isWhitespace(cs.charAt(i)) == false) { return false; }
+ }
+ return true;
+ }
+
+ /**
+ * Returns true is cs is null or cs.length equals 0.
+ */
+ public static boolean isEmpty(CharSequence cs) {
+ return cs == null || cs.length() == 0;
+ }
+
+ /**
+ * <p>
+ * isEqualSeq.
+ * </p>
+ *
+ * @param first not null
+ * @param second not null
+ * @return a boolean.
+ */
+ public static boolean isEqualSeq(final String first, final String second) {
+ return isEqualSeq(first, second, DELIMITER);
+ }
+
+ /**
+ * 判断两个","逗号相隔的字符串中的单词是否完全等同.
+ *
+ * @param first
+ * a {@link java.lang.String} object.
+ * @param second
+ * a {@link java.lang.String} object.
+ * @param delimiter
+ * a {@link java.lang.String} object.
+ * @return a boolean.
+ */
+ public static boolean isEqualSeq(final String first, final String second, final String delimiter) {
+ if (isNotEmpty(first) && isNotEmpty(second)) {
+ String[] firstWords = split(first, delimiter);
+ Set<String> firstSet = CollectUtils.newHashSet();
+ for (int i = 0; i < firstWords.length; i++) {
+ firstSet.add(firstWords[i]);
+ }
+ String[] secondWords = split(second, delimiter);
+ Set<String> secondSet = CollectUtils.newHashSet();
+ for (int i = 0; i < secondWords.length; i++) {
+ secondSet.add(secondWords[i]);
+ }
+ return firstSet.equals(secondSet);
+ } else {
+ return isEmpty(first) & isEmpty(second);
+ }
+ }
+
+ /**
+ * <p>
+ * Checks if a CharSequence is not empty (""), not null and not whitespace only.
+ * </p>
+ *
+ * <pre>
+ * isNotBlank(null) = false
+ * isNotBlank("") = false
+ * isNotBlank(" ") = false
+ * isNotBlank("bob") = true
+ * isNotBlank(" bob ") = true
+ * </pre>
+ *
+ * @param cs
+ * the CharSequence to check, may be null
+ * @return {@code true} if the CharSequence is
+ * not empty and not null and not whitespace
+ * @since 3.0
+ */
+ public static boolean isNotBlank(CharSequence cs) {
+ return !isBlank(cs);
+ }
+
+ /**
+ * Return true if cs not null and cs has length.
+ */
+ public static boolean isNotEmpty(CharSequence cs) {
+ return !isEmpty(cs);
+ }
+
+ /**
+ * <p>
+ * join.
+ * </p>
+ *
+ * @param seq
+ * a {@link java.util.Collection} object.
+ * @param delimiter
+ * a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String join(final Collection<String> seq, final String delimiter) {
+ if (null == seq || seq.size() < 1) {
+ return "";
+ } else {
+ StringBuilder aim = new StringBuilder();
+ for (String one : seq) {
+ if (null != delimiter && aim.length() > 0) {
+ aim.append(delimiter);
+ }
+ aim.append(one);
+ }
+ return aim.toString();
+ }
+ }
+
+ /**
+ * <p>
+ * join.
+ * </p>
+ *
+ * @param seq
+ * a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String join(final String... seq) {
+ return join(seq, DELIMITER);
+ }
+
+ public static String join(final Object[] seq, final char delimiter) {
+ if (null == seq || seq.length < 1) return "";
+ StringBuilder aim = new StringBuilder();
+ for (int i = 0; i < seq.length; i++) {
+ if (aim.length() > 0) aim.append(delimiter);
+ aim.append(seq[i]);
+ }
+ return aim.toString();
+ }
+
+ /**
+ * 将数组中的字符串,用delimiter串接起来.<br>
+ * 首尾不加delimiter
+ *
+ * @param seq an array of {@link java.lang.String} objects.
+ * @param delimiter a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String join(final String[] seq, final String delimiter) {
+ if (null == seq || seq.length < 1) return "";
+ Assert.notNull(delimiter);
+ StringBuilder aim = new StringBuilder();
+ for (int i = 0; i < seq.length; i++) {
+ if (aim.length() > 0) aim.append(delimiter);
+ aim.append(seq[i]);
+ }
+ return aim.toString();
+ }
+
+ /**
+ * 保持逗号分隔的各个单词都是唯一的。并且按照原来的顺序存放。
+ *
+ * @param keys
+ * a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String keepSeqUnique(final String keys) {
+ String[] keysArray = split(keys, ",");
+ List<String> keyList = CollectUtils.newArrayList();
+ for (int i = 0; i < keysArray.length; i++) {
+ if (!keyList.contains(keysArray[i])) {
+ keyList.add(keysArray[i]);
+ }
+ }
+ StringBuilder keyBuf = new StringBuilder();
+ for (Iterator<String> iter = keyList.iterator(); iter.hasNext();) {
+ keyBuf.append(iter.next());
+ if (iter.hasNext()) {
+ keyBuf.append(",");
+ }
+ }
+ return keyBuf.toString();
+ }
+
+ /**
+ * <p>
+ * Left pad a String with a specified character.
+ * </p>
+ * <p>
+ * Pad to a size of {@code size}.
+ * </p>
+ *
+ * <pre>
+ * leftPad(null, *, *) = null
+ * leftPad("", 3, 'z') = "zzz"
+ * leftPad("bat", 3, 'z') = "bat"
+ * leftPad("bat", 5, 'z') = "zzbat"
+ * leftPad("bat", 1, 'z') = "bat"
+ * leftPad("bat", -1, 'z') = "bat"
+ * </pre>
+ *
+ * @param str the String to pad out, may be null
+ * @param size the size to pad to
+ * @param padChar the character to pad with
+ * @return left padded String or original String if no padding is necessary, {@code null} if null
+ * String input
+ * @since 3.0
+ */
+ public static String leftPad(String str, int size, char padChar) {
+ if (str == null) { return null; }
+ int pads = size - str.length();
+ if (pads <= 0) { return str; // returns original String when possible
+ }
+ return repeat(padChar, pads).concat(str);
+ }
+
+ /**
+ * <p>
+ * Right pad a String with a specified character.
+ * </p>
+ * <p>
+ * The String is padded to the size of {@code size}.
+ * </p>
+ *
+ * <pre>
+ * rightPad(null, *, *) = null
+ * rightPad("", 3, 'z') = "zzz"
+ * rightPad("bat", 3, 'z') = "bat"
+ * rightPad("bat", 5, 'z') = "batzz"
+ * rightPad("bat", 1, 'z') = "bat"
+ * rightPad("bat", -1, 'z') = "bat"
+ * </pre>
+ *
+ * @param str the String to pad out, may be null
+ * @param size the size to pad to
+ * @param padChar the character to pad with
+ * @return right padded String or original String if no padding is necessary, {@code null} if null
+ * String input
+ * @since 3.0
+ */
+ public static String rightPad(String str, int size, char padChar) {
+ if (str == null) { return null; }
+ int pads = size - str.length();
+ if (pads <= 0) { return str; // returns original String when possible
+ }
+ return str.concat(repeat(padChar, pads));
+ }
+
+ /**
+ * <p>
+ * mergeSeq.
+ * </p>
+ *
+ * @param first
+ * a {@link java.lang.String} object.
+ * @param second
+ * a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String mergeSeq(final String first, final String second) {
+ return mergeSeq(first, second, DELIMITER);
+ }
+
+ /**
+ * 将两个用delimiter串起来的字符串,合并成新的串,重复的"单词"只出现一次.
+ * 如果第一个字符串以delimiter开头,第二个字符串以delimiter结尾,<br>
+ * 合并后的字符串仍以delimiter开头和结尾.<br>
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * mergeSeq(",1,2,", "") = ",1,2,";
+ * mergeSeq(",1,2,", null) = ",1,2,";
+ * mergeSeq("1,2", "3") = "1,2,3";
+ * mergeSeq("1,2", "3,") = "1,2,3,";
+ * mergeSeq(",1,2", "3,") = ",1,2,3,";
+ * mergeSeq(",1,2,", ",3,") = ",1,2,3,";
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @param first
+ * a {@link java.lang.String} object.
+ * @param second
+ * a {@link java.lang.String} object.
+ * @param delimiter
+ * a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String mergeSeq(final String first, final String second, final String delimiter) {
+ if (isNotEmpty(second) && isNotEmpty(first)) {
+ List<String> firstSeq = Arrays.asList(split(first, delimiter));
+ List<String> secondSeq = Arrays.asList(split(second, delimiter));
+ Collection<String> rs = CollectUtils.union(firstSeq, secondSeq);
+ StringBuilder buf = new StringBuilder();
+ for (final String ele : rs)
+ buf.append(delimiter).append(ele);
+ if (buf.length() > 0) buf.append(delimiter);
+ return buf.toString();
+ } else {
+ return ((first == null) ? "" : first) + ((second == null) ? "" : second);
+ }
+ }
+
+ /**
+ * <p>
+ * removeWord.
+ * </p>
+ *
+ * @param host
+ * a {@link java.lang.String} object.
+ * @param word
+ * a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String removeWord(final String host, final String word) {
+ return removeWord(host, word, DELIMITER);
+
+ }
+
+ /**
+ * <p>
+ * removeWord.
+ * </p>
+ *
+ * @param host
+ * a {@link java.lang.String} object.
+ * @param word
+ * a {@link java.lang.String} object.
+ * @param delimiter
+ * a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String removeWord(final String host, final String word, final String delimiter) {
+ if (host.indexOf(word) == -1) {
+ return host;
+ } else {
+ int beginIndex = host.indexOf(word);
+ int endIndex = beginIndex + word.length();
+ if (beginIndex == 0) { return host.substring(endIndex + 1); }
+ if (endIndex == host.length()) {
+ return host.substring(0, beginIndex - delimiter.length());
+ } else {
+ String before = host.substring(0, beginIndex);
+ String after = host.substring(endIndex + 1);
+ return before + after;
+ }
+ }
+ }
+
+ /**
+ * <p>
+ * Returns padding using the specified delimiter repeated to a given length.
+ * </p>
+ *
+ * <pre>
+ * repeat(0, 'e') = ""
+ * repeat(3, 'e') = "eee"
+ * repeat(-2, 'e') = ""
+ * </pre>
+ *
+ * @param ch character to repeat
+ * @param repeat number of times to repeat char, negative treated as zero
+ * @return String with repeated character
+ * @see #repeat(String, int)
+ */
+ public static String repeat(char ch, int repeat) {
+ if (repeat <= 0) return Empty;
+ char[] buf = new char[repeat];
+ for (int i = repeat - 1; i >= 0; i--) {
+ buf[i] = ch;
+ }
+ return new String(buf);
+ }
+
+ /**
+ * <p>
+ * Repeat a String {@code repeat} times to form a new String.
+ * </p>
+ *
+ * <pre>
+ * repeat(null, 2) = null
+ * repeat("", 0) = ""
+ * repeat("", 2) = ""
+ * repeat("a", 3) = "aaa"
+ * repeat("ab", 2) = "abab"
+ * repeat("a", -2) = ""
+ * </pre>
+ *
+ * @param str the String to repeat, may be null
+ * @param repeat number of times to repeat str, negative treated as zero
+ * @return a new String consisting of the original String repeated, {@code null} if null String
+ * input
+ * @since 3.0
+ */
+ public static String repeat(String str, int repeat) {
+ if (str == null) return null;
+ if (repeat <= 0) return Empty;
+ if (repeat == 1) return str;
+ final int len = str.length();
+ final long longSize = (long) len * (long) repeat;
+ final int size = (int) longSize;
+ if (size != longSize) { throw new ArrayIndexOutOfBoundsException("Required array size too large: "
+ + String.valueOf(longSize)); }
+
+ final char[] array = new char[size];
+ str.getChars(0, len, array, 0);
+ int n;
+ for (n = len; n < size - n; n <<= 1) {
+ System.arraycopy(array, 0, array, n, n);
+ }
+ System.arraycopy(array, 0, array, n, size - n);
+ return new String(array);
+
+ }
+
+ /**
+ * <p>
+ * Replaces all occurrences of a String within another String.
+ * </p>
+ * <p>
+ * A {@code null} reference passed to this method is a no-op.
+ * </p>
+ *
+ * <pre>
+ * replace(null, *, *) = null
+ * replace("", *, *) = ""
+ * replace("any", null, *) = "any"
+ * replace("any", *, null) = "any"
+ * replace("any", "", *) = "any"
+ * replace("aba", "a", null) = "aba"
+ * replace("aba", "a", "") = "b"
+ * replace("aba", "a", "z") = "zbz"
+ * </pre>
+ *
+ * @param text text to search and replace in, may be null
+ * @param searchString the String to search for, may be null
+ * @param replacement the String to replace it with, may be null
+ * @return the text with any replacements processed, {@code null} if null String input
+ */
+ public static String replace(String text, String searchString, String replacement) {
+ if (isEmpty(text) || isEmpty(searchString) || replacement == null) { return text; }
+ int start = 0;
+ int end = text.indexOf(searchString, start);
+ if (end == -1) { return text; }
+ int replLength = searchString.length();
+ int increase = replacement.length() - replLength;
+ increase = increase < 0 ? 0 : increase;
+ increase *= 16;
+ StringBuilder buf = new StringBuilder(text.length() + increase);
+ while (end != -1) {
+ buf.append(text.substring(start, end)).append(replacement);
+ start = end + replLength;
+ end = text.indexOf(searchString, start);
+ }
+ buf.append(text.substring(start));
+ return buf.toString();
+ }
+
+ /**
+ * <p>
+ * split.
+ * </p>
+ *
+ * @param target
+ * a {@link java.lang.String} object.
+ * @return an array of {@link java.lang.String} objects.
+ */
+ public static String[] split(String target) {
+ return split(target, new char[] { ',', ';', '\r', '\n', ' ' });
+ }
+
+ /**
+ * <p>
+ * Splits the provided text into an array, separator specified. This is an alternative to using
+ * StringTokenizer.
+ * </p>
+ * A {@code null} input String returns {@code null}.
+ * </p>
+ *
+ * <pre>
+ * split(null, *) = null
+ * split("", *) = []
+ * split("a.b.c", '.') = ["a", "b", "c"]
+ * split("a..b.c", '.') = ["a", "b", "c"]
+ * split("a:b:c", '.') = ["a:b:c"]
+ * split("a b c", ' ') = ["a", "b", "c"]
+ * </pre>
+ */
+ public static String[] split(String str, char separatorChar) {
+ if (str == null) { return null; }
+ int len = str.length();
+ if (len == 0) return new String[0];
+ List<String> list = new ArrayList<String>();
+ int i = 0, start = 0;
+ boolean match = false;
+ while (i < len) {
+ if (str.charAt(i) == separatorChar) {
+ if (match) {
+ list.add(str.substring(start, i));
+ match = false;
+ }
+ start = ++i;
+ continue;
+ }
+ match = true;
+ i++;
+ }
+ if (match) list.add(str.substring(start, i));
+ return list.toArray(new String[list.size()]);
+
+ }
+
+ /**
+ * <p>
+ * split.
+ * </p>
+ *
+ * @param target
+ * a {@link java.lang.String} object.
+ * @param separatorChars
+ * an array of char.
+ * @return an array of {@link java.lang.String} objects.
+ */
+ public static String[] split(String target, char[] separatorChars) {
+ if (null == target) { return new String[0]; }
+ char[] sb = target.toCharArray();
+ for (char separator : separatorChars) {
+ if (separator != ',') {
+ for (int i = 0; i < sb.length; i++)
+ if (sb[i] == separator) sb[i] = ',';
+ }
+ }
+ String[] targets = split(new String(sb), ',');
+ List<String> list = CollectUtils.newArrayList();
+ for (String one : targets) {
+ if (isNotBlank(one)) list.add(one.trim());
+ }
+ String[] rs = new String[list.size()];
+ list.toArray(rs);
+ return rs;
+ }
+
+ /**
+ * *
+ * <p>
+ * Splits the provided text into an array, separators specified. This is an alternative to using
+ * StringTokenizer.
+ * </p>
+ * <p>
+ * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on
+ * whitespace.
+ * </p>
+ *
+ * <pre>
+ * split(null, *) = null
+ * split("", *) = []
+ * split("abc def", null) = ["abc", "def"]
+ * split("abc def", " ") = ["abc", "def"]
+ * split("abc def", " ") = ["abc", "def"]
+ * split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
+ * </pre>
+ */
+ public static String[] split(String str, String separatorChars) {
+ if (str == null) { return null; }
+ int len = str.length();
+ if (len == 0) return new String[0];
+ List<String> list = new ArrayList<String>();
+ int i = 0, start = 0;
+ boolean match = false;
+ if (null == separatorChars) separatorChars = " ";
+ while (i < len) {
+ if (separatorChars.indexOf(str.charAt(i)) >= 0) {
+ if (match) {
+ list.add(str.substring(start, i));
+ match = false;
+ }
+ start = ++i;
+ continue;
+ }
+ match = true;
+ i++;
+ }
+ if (match) list.add(str.substring(start, i));
+ return list.toArray(new String[list.size()]);
+ }
+
+ /**
+ * 将1-2,3,4-9之类的序列拆分成数组
+ *
+ * @param numSeq
+ * a {@link java.lang.String} object.
+ * @return an array of {@link java.lang.Integer} objects.
+ */
+ public static Integer[] splitNumSeq(final String numSeq) {
+ if (isEmpty(numSeq)) { return null; }
+ String[] numArray = split(numSeq, ',');
+ Set<Integer> numSet = CollectUtils.newHashSet();
+ for (int i = 0; i < numArray.length; i++) {
+ String num = numArray[i];
+ if (num.contains("-")) {
+ String[] termFromTo = split(num, '-');
+ int from = Numbers.toInt(termFromTo[0]);
+ int to = Numbers.toInt(termFromTo[1]);
+ for (int j = from; j <= to; j++) {
+ numSet.add(Integer.valueOf(j));
+ }
+ } else {
+ numSet.add(new Integer(num));
+ }
+ }
+ Integer[] nums = new Integer[numSet.size()];
+ numSet.toArray(nums);
+ return nums;
+ }
+
+ /**
+ * <p>
+ * splitToInt.
+ * </p>
+ *
+ * @param ids
+ * a {@link java.lang.String} object.
+ * @return an array of {@link java.lang.Integer} objects.
+ */
+ public static Integer[] splitToInt(final String ids) {
+ if (isEmpty(ids)) return new Integer[0];
+ else return transformToInt(split(ids, ','));
+ }
+
+ /**
+ * <p>
+ * splitToLong.
+ * </p>
+ *
+ * @param ids
+ * a {@link java.lang.String} object.
+ * @return an array of {@link java.lang.Long} objects.
+ */
+ public static Long[] splitToLong(final String ids) {
+ if (isEmpty(ids)) {
+ return new Long[0];
+ } else {
+ return transformToLong(split(ids, ','));
+ }
+ }
+
+ /**
+ * <p>
+ * Gets a substring from the specified String avoiding exceptions.
+ * </p>
+ * <p>
+ * A negative start position can be used to start/end {@code n} characters from the end of the
+ * String.
+ * </p>
+ * <p>
+ * The returned substring starts with the character in the {@code start} position and ends before
+ * the {@code end} position. All position counting is zero-based -- i.e., to start at the
+ * beginning of the string use {@code start = 0}. Negative start and end positions can be used to
+ * specify offsets relative to the end of the String.
+ * </p>
+ * <p>
+ * If {@code start} is not strictly to the left of {@code end}, "" is returned.
+ * </p>
+ *
+ * <pre>
+ * substring(null, *, *) = null
+ * substring("", * , *) = "";
+ * substring("abc", 0, 2) = "ab"
+ * substring("abc", 2, 0) = ""
+ * substring("abc", 2, 4) = "c"
+ * substring("abc", 4, 6) = ""
+ * substring("abc", 2, 2) = ""
+ * substring("abc", -2, -1) = "b"
+ * substring("abc", -4, 2) = "ab"
+ * </pre>
+ *
+ * @param str
+ * the String to get the substring from, may be null
+ * @param start
+ * the position to start from, negative means
+ * count back from the end of the String by this many characters
+ * @param end
+ * the position to end at (exclusive), negative means
+ * count back from the end of the String by this many characters
+ * @return substring from start position to end position, {@code null} if null String input
+ */
+ public static String substring(String str, int start, int end) {
+ if (str == null) return null;
+ // handle negatives
+ if (end < 0) end = str.length() + end; // remember end is negative
+ if (start < 0) start = str.length() + start; // remember start is negative
+ // check length next
+ if (end > str.length()) end = str.length();
+ // if start is greater than end, return ""
+ if (start > end) return "";
+ if (start < 0) start = 0;
+ if (end < 0) end = 0;
+ return str.substring(start, end);
+ }
+
+ /**
+ * <p>
+ * subtractSeq.
+ * </p>
+ *
+ * @param first
+ * a {@link java.lang.String} object.
+ * @param second
+ * a {@link java.lang.String} object.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String subtractSeq(final String first, final String second) {
+ return subtractSeq(first, second, DELIMITER);
+ }
+
+ /**
+ * 返回一个新的逗号相隔字符串,实现其中的单词a-b的功能. 新的字符串将以,开始,结束<br>
+ */
+ public static String subtractSeq(String first, String second, String delimiter) {
+ if (isEmpty(first)) { return ""; }
+ if (isEmpty(second)) {
+ StringBuilder builder = new StringBuilder();
+ if (!first.startsWith(delimiter)) builder.append(delimiter).append(first);
+ if (!first.endsWith(delimiter)) builder.append(first).append(delimiter);
+ return builder.toString();
+ }
+ List<String> firstSeq = Arrays.asList(split(first, delimiter));
+ List<String> secondSeq = Arrays.asList(split(second, delimiter));
+ Collection<String> rs = CollectUtils.subtract(firstSeq, secondSeq);
+ StringBuilder buf = new StringBuilder();
+ for (final String ele : rs)
+ buf.append(delimiter).append(ele);
+ if (buf.length() > 0) buf.append(delimiter);
+ return buf.toString();
+ }
+
+ /**
+ * <p>
+ * transformToInt.
+ * </p>
+ *
+ * @param ids
+ * an array of {@link java.lang.String} objects.
+ * @return an array of {@link java.lang.Integer} objects.
+ */
+ public static Integer[] transformToInt(final String[] ids) {
+ Integer[] idsOfInteger = new Integer[ids.length];
+ for (int i = 0; i < ids.length; i++) {
+ idsOfInteger[i] = new Integer(ids[i]);
+ }
+ return idsOfInteger;
+ }
+
+ /**
+ * <p>
+ * transformToLong.
+ * </p>
+ *
+ * @param ids
+ * an array of {@link java.lang.String} objects.
+ * @return an array of {@link java.lang.Long} objects.
+ */
+ public static Long[] transformToLong(final String[] ids) {
+ if (null == ids) { return null; }
+ Long[] idsOfLong = new Long[ids.length];
+ for (int i = 0; i < ids.length; i++) {
+ idsOfLong[i] = new Long(ids[i]);
+ }
+ return idsOfLong;
+ }
+
+ /**
+ * <p>
+ * unCamel.
+ * </p>
+ */
+ public static String unCamel(String str) {
+ return unCamel(str, '-', true);
+ }
+
+ /**
+ * <p>
+ * unCamel.
+ * </p>
+ *
+ * @param str
+ * a {@link java.lang.String} object.
+ * @param seperator
+ * a char.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String unCamel(String str, char seperator) {
+ return unCamel(str, seperator, true);
+ }
+
+ /**
+ * 将驼峰表示法转换为下划线小写表示
+ *
+ * @param str
+ * a {@link java.lang.String} object.
+ * @param seperator
+ * a char.
+ * @param lowercase
+ * a boolean.
+ * @return a {@link java.lang.String} object.
+ */
+ public static String unCamel(String str, char seperator, boolean lowercase) {
+ char[] ca = str.toCharArray();
+ if (3 > ca.length) { return lowercase ? str.toLowerCase() : str; }
+ // about five seperator
+ StringBuilder build = new StringBuilder(ca.length + 5);
+ build.append(lowercase ? toLowerCase(ca[0]) : ca[0]);
+
+ boolean lower1 = isLowerCase(ca[0]);
+ int i = 1;
+ while (i < ca.length - 1) {
+ char cur = ca[i];
+ char next = ca[i + 1];
+ boolean upper2 = isUpperCase(cur);
+ boolean lower3 = isLowerCase(next);
+ if (lower1 && upper2 && lower3) {
+ build.append(seperator);
+ build.append(lowercase ? toLowerCase(cur) : cur);
+ build.append(next);
+ i += 2;
+ } else {
+ if (lowercase && upper2) {
+ build.append(toLowerCase(cur));
+ } else {
+ build.append(cur);
+ }
+ lower1 = !upper2;
+ i++;
+ }
+ }
+ if (i == ca.length - 1) {
+ build.append(lowercase ? toLowerCase(ca[i]) : ca[i]);
+ }
+ return build.toString();
+ }
+
+ /**
+ * <p>
+ * Gets the substring before the first occurrence of a separator. The separator is not returned.
+ * </p>
+ * <p>
+ * A {@code null} string input will return {@code null}. An empty ("") string input will return
+ * the empty string. A {@code null} separator will return the input string.
+ * </p>
+ * <p>
+ * If nothing is found, the string input is returned.
+ * </p>
+ *
+ * <pre>
+ * substringBefore(null, *) = null
+ * substringBefore("", *) = ""
+ * substringBefore("abc", "a") = ""
+ * substringBefore("abcba", "b") = "a"
+ * substringBefore("abc", "c") = "ab"
+ * substringBefore("abc", "d") = "abc"
+ * substringBefore("abc", "") = ""
+ * substringBefore("abc", null) = "abc"
+ * </pre>
+ *
+ * @param str the String to get a substring from, may be null
+ * @param separator the String to search for, may be null
+ * @return the substring before the first occurrence of the separator, {@code null} if null String
+ * input
+ * @since 2.0
+ */
+ public static String substringBefore(String str, String separator) {
+ if (isEmpty(str) || separator == null) { return str; }
+ if (separator.length() == 0) { return Empty; }
+ int pos = str.indexOf(separator);
+ if (pos == Index_not_found) { return str; }
+ return str.substring(0, pos);
+ }
+
+ /**
+ * <p>
+ * Gets the substring after the first occurrence of a separator. The separator is not returned.
+ * </p>
+ * <p>
+ * A {@code null} string input will return {@code null}. An empty ("") string input will return
+ * the empty string. A {@code null} separator will return the empty string if the input string is
+ * not {@code null}.
+ * </p>
+ * <p>
+ * If nothing is found, the empty string is returned.
+ * </p>
+ *
+ * <pre>
+ * substringAfter(null, *) = null
+ * substringAfter("", *) = ""
+ * substringAfter(*, null) = ""
+ * substringAfter("abc", "a") = "bc"
+ * substringAfter("abcba", "b") = "cba"
+ * substringAfter("abc", "c") = ""
+ * substringAfter("abc", "d") = ""
+ * substringAfter("abc", "") = "abc"
+ * </pre>
+ *
+ * @param str the String to get a substring from, may be null
+ * @param separator the String to search for, may be null
+ * @return the substring after the first occurrence of the separator, {@code null} if null String
+ * input
+ * @since 2.0
+ */
+ public static String substringAfter(String str, String separator) {
+ if (isEmpty(str)) { return str; }
+ if (separator == null) { return Empty; }
+ int pos = str.indexOf(separator);
+ if (pos == Index_not_found) { return Empty; }
+ return str.substring(pos + separator.length());
+ }
+
+ /**
+ * <p>
+ * Gets the String that is nested in between two Strings. Only the first match is returned.
+ * </p>
+ * <p>
+ * A {@code null} input String returns {@code null}. A {@code null} open/close returns
+ * {@code null} (no match). An empty ("") open and close returns an empty string.
+ * </p>
+ *
+ * <pre>
+ * substringBetween("wx[b]yz", "[", "]") = "b"
+ * substringBetween(null, *, *) = null
+ * substringBetween(*, null, *) = null
+ * substringBetween(*, *, null) = null
+ * substringBetween("", "", "") = ""
+ * substringBetween("", "", "]") = null
+ * substringBetween("", "[", "]") = null
+ * substringBetween("yabcz", "", "") = ""
+ * substringBetween("yabcz", "y", "z") = "abc"
+ * substringBetween("yabczyabcz", "y", "z") = "abc"
+ * </pre>
+ *
+ * @param str the String containing the substring, may be null
+ * @param open the String before the substring, may be null
+ * @param close the String after the substring, may be null
+ * @return the substring, {@code null} if no match
+ * @since 3.0
+ */
+ public static String substringBetween(String str, String open, String close) {
+ if (str == null || open == null || close == null) { return null; }
+ int start = str.indexOf(open);
+ if (start != Index_not_found) {
+ int end = str.indexOf(close, start + open.length());
+ if (end != Index_not_found) { return str.substring(start + open.length(), end); }
+ }
+ return null;
+ }
+
+ /**
+ * <p>
+ * Gets the substring before the last occurrence of a separator. The separator is not returned.
+ * </p>
+ * <p>
+ * A {@code null} string input will return {@code null}. An empty ("") string input will return
+ * the empty string. An empty or {@code null} separator will return the input string.
+ * </p>
+ * <p>
+ * If nothing is found, the string input is returned.
+ * </p>
+ *
+ * <pre>
+ * substringBeforeLast(null, *) = null
+ * substringBeforeLast("", *) = ""
+ * substringBeforeLast("abcba", "b") = "abc"
+ * substringBeforeLast("abc", "c") = "ab"
+ * substringBeforeLast("a", "a") = ""
+ * substringBeforeLast("a", "z") = "a"
+ * substringBeforeLast("a", null) = "a"
+ * substringBeforeLast("a", "") = "a"
+ * </pre>
+ *
+ * @param str the String to get a substring from, may be null
+ * @param separator the String to search for, may be null
+ * @return the substring before the last occurrence of the separator, {@code null} if null String
+ * input
+ * @since 3.0
+ */
+ public static String substringBeforeLast(String str, String separator) {
+ if (isEmpty(str) || isEmpty(separator)) { return str; }
+ int pos = str.lastIndexOf(separator);
+ if (pos == Index_not_found) { return str; }
+ return str.substring(0, pos);
+ }
+
+ /**
+ * <p>
+ * Gets the substring after the last occurrence of a separator. The separator is not returned.
+ * </p>
+ * <p>
+ * A {@code null} string input will return {@code null}. An empty ("") string input will return
+ * the empty string. An empty or {@code null} separator will return the empty string if the input
+ * string is not {@code null}.
+ * </p>
+ * <p>
+ * If nothing is found, the empty string is returned.
+ * </p>
+ *
+ * <pre>
+ * substringAfterLast(null, *) = null
+ * substringAfterLast("", *) = ""
+ * substringAfterLast(*, "") = ""
+ * substringAfterLast(*, null) = ""
+ * substringAfterLast("abc", "a") = "bc"
+ * substringAfterLast("abcba", "b") = "a"
+ * substringAfterLast("abc", "c") = ""
+ * substringAfterLast("a", "a") = ""
+ * substringAfterLast("a", "z") = ""
+ * </pre>
+ *
+ * @param str the String to get a substring from, may be null
+ * @param separator the String to search for, may be null
+ * @return the substring after the last occurrence of the separator, {@code null} if null String
+ * input
+ * @since 3.0
+ */
+ public static String substringAfterLast(String str, String separator) {
+ if (isEmpty(str)) { return str; }
+ if (isEmpty(separator)) { return Empty; }
+ int pos = str.lastIndexOf(separator);
+ if (pos == Index_not_found || pos == str.length() - separator.length()) { return Empty; }
+ return str.substring(pos + separator.length());
+ }
+
+ /**
+ * <p>
+ * Removes control characters (char <= 32) from both ends of this String, handling {@code null}
+ * by returning {@code null}.
+ * </p>
+ * <p>
+ * The String is trimmed using {@link String#trim()}. Trim removes start and end characters <=
+ * 32.
+ * </p>
+ *
+ * <pre>
+ * trim(null) = null
+ * trim("") = ""
+ * trim(" ") = ""
+ * trim("abc") = "abc"
+ * trim(" abc ") = "abc"
+ * </pre>
+ *
+ * @param str the String to be trimmed, may be null
+ * @return the trimmed string, {@code null} if null String input
+ * @since 3.0
+ */
+ public static String trim(String str) {
+ return str == null ? null : str.trim();
+ }
+
+ /**
+ * <p>
+ * Uncapitalizes a String changing the first letter to title case as per
+ * {@link Character#toLowerCase(char)}. No other letters are changed.
+ * </p>
+ * <p>
+ * For a word based algorithm, see String returns {@code null}.
+ * </p>
+ *
+ * <pre>
+ * uncapitalize(null) = null
+ * uncapitalize("") = ""
+ * uncapitalize("Cat") = "cat"
+ * uncapitalize("CAT") = "cAT"
+ * </pre>
+ *
+ * @param str the String to uncapitalize, may be null
+ * @return the uncapitalized String, {@code null} if null String input
+ * @see #capitalize(String)
+ * @since 3.0
+ */
+ public static String uncapitalize(String str) {
+ int strLen;
+ if (str == null || (strLen = str.length()) == 0) { return str; }
+ return new StringBuilder(strLen).append(Character.toLowerCase(str.charAt(0))).append(str.substring(1))
+ .toString();
+ }
+
+ /**
+ * <p>
+ * Returns either the passed in CharSequence, or if the CharSequence is whitespace, empty ("") or
+ * {@code null}, the value of {@code defaultStr}.
+ * </p>
+ *
+ * @param str
+ * @param defaultStr
+ */
+ public static <T extends CharSequence> T defaultIfBlank(T str, T defaultStr) {
+ return isBlank(str) ? defaultStr : str;
+ }
+
+ public static String abbreviate(String str, int maxWidth) {
+ return abbreviate(str, 0, maxWidth);
+ }
+
+ public static String abbreviate(String str, int offset, int maxWidth) {
+ if (str == null) return null;
+ if (maxWidth < 4) throw new IllegalArgumentException("Minimum abbreviation width is 4");
+ if (str.length() <= maxWidth) return str;
+ if (offset > str.length()) offset = str.length();
+
+ if (str.length() - offset < maxWidth - 3) offset = str.length() - (maxWidth - 3);
+ final String abrevMarker = "...";
+ if (offset <= 4) return str.substring(0, maxWidth - 3) + abrevMarker;
+ if (maxWidth < 7) throw new IllegalArgumentException("Minimum abbreviation width with offset is 7");
+ if (offset + maxWidth - 3 < str.length()) { return abrevMarker
+ + abbreviate(str.substring(offset), maxWidth - 3); }
+ return abrevMarker + str.substring(str.length() - (maxWidth - 3));
+ }
+
+ /**
+ * <p>
+ * Removes all occurrences of a character from within the source string.
+ * </p>
+ * <p>
+ * A {@code null} source string will return {@code null}. An empty ("") source string will return
+ * the empty string.
+ * </p>
+ *
+ * <pre>
+ * StringUtils.remove(null, *) = null
+ * StringUtils.remove("", *) = ""
+ * StringUtils.remove("queued", 'u') = "qeed"
+ * StringUtils.remove("queued", 'z') = "queued"
+ * </pre>
+ *
+ * @param str the source String to search, may be null
+ * @param remove the char to search for and remove, may be null
+ * @return the substring with the char removed if found, {@code null} if null String input
+ */
+ public static String remove(String str, char remove) {
+ if (isEmpty(str) || str.indexOf(remove) == -1) { return str; }
+ char[] chars = str.toCharArray();
+ int pos = 0;
+ for (int i = 0; i < chars.length; i++) {
+ if (chars[i] != remove) chars[pos++] = chars[i];
+ }
+ return new String(chars, 0, pos);
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/Throwables.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/Throwables.java
new file mode 100644
index 0000000..a23d504
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/Throwables.java
@@ -0,0 +1,99 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Static utility methods pertaining to instances of {@link Throwable}.
+ *
+ * @author chaostone
+ * @since 3.0
+ */
+public final class Throwables {
+ private Throwables() {
+ }
+
+ /**
+ * Propagates {@code throwable} exactly as-is, if and only if it is an
+ * instance of {@code declaredType}. Example usage:
+ *
+ * <pre>
+ * try {
+ * someMethodThatCouldThrowAnything();
+ * } catch (IKnowWhatToDoWithThisException e) {
+ * handle(e);
+ * } catch (Throwable t) {
+ * Throwables.propagateIfInstanceOf(t, IOException.class);
+ * Throwables.propagateIfInstanceOf(t, SQLException.class);
+ * throw Throwables.propagate(t);
+ * }
+ * </pre>
+ */
+ public static <X extends Throwable> void propagateIfInstanceOf(Throwable throwable, Class<X> declaredType)
+ throws X {
+ // Check for null is needed to avoid frequent JNI calls to isInstance().
+ if (throwable != null && declaredType.isInstance(throwable)) { throw declaredType.cast(throwable); }
+ }
+
+ /**
+ * Propagates {@code throwable} as-is if it is an instance of {@link RuntimeException} or
+ * {@link Error}, or else as a last resort, wraps
+ * it in a {@code RuntimeException} then propagates.
+ * <p>
+ * This method always throws an exception. The {@code RuntimeException} return type is only for
+ * client code to make Java type system happy in case a return value is required by the enclosing
+ * method. Example usage:
+ *
+ * <pre>
+ * T doSomething() {
+ * try {
+ * return someMethodThatCouldThrowAnything();
+ * } catch (IKnowWhatToDoWithThisException e) {
+ * return handle(e);
+ * } catch (Throwable t) {
+ * throw Throwables.propagate(t);
+ * }
+ * }
+ * </pre>
+ *
+ * @param throwable the Throwable to propagate
+ * @return nothing will ever be returned; this return type is only for your
+ * convenience, as illustrated in the example above
+ */
+ public static RuntimeException propagate(Throwable throwable) {
+ propagateIfInstanceOf(throwable, Error.class);
+ propagateIfInstanceOf(throwable, RuntimeException.class);
+ throw new RuntimeException(throwable);
+ }
+
+ /**
+ * Returns a string containing the result of {@link Throwable#toString() toString()}, followed by
+ * the full, recursive
+ * stack trace of {@code throwable}. Note that you probably should not be
+ * parsing the resulting string; if you need programmatic access to the stack
+ * frames, you can call {@link Throwable#getStackTrace()}.
+ */
+ public static String getStackTrace(Throwable throwable) {
+ StringWriter sw = new StringWriter();
+ throwable.printStackTrace(new PrintWriter(sw));
+ return sw.toString();
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/BinaryFunction.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/BinaryFunction.java
new file mode 100644
index 0000000..0701e8d
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/BinaryFunction.java
@@ -0,0 +1,46 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.functor;
+
+import com.ekingstar.commons.lang.Objects;
+
+/**
+ * Binary Function Object
+ *
+ * @author chaostone
+ * @since 3.2.0
+ * @param <I1> first input type
+ * @param <I2> second input type
+ * @param <R> returned output type
+ */
+public interface BinaryFunction<I1, I2, R> {
+ /**
+ * Returns the result of applying this function to {@code input}. This method is <i>generally
+ * expected</i>, but not absolutely required, to have the following properties:
+ * <ul>
+ * <li>Its execution does not cause any observable side effects.
+ * <li>The computation is <i>consistent with equals</i>; that is, {@link Objects#equal
+ * Objects.equal}{@code (a, b)} implies that {@code Objects.equal(function.apply(a),
+ * function.apply(b))}.
+ * </ul>
+ *
+ * @throws NullPointerException if {@code input} is null
+ */
+ R apply(I1 arg1, I2 arg2);
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/CollectionHasUpto1ElementPredicate.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/CollectionHasUpto1ElementPredicate.java
new file mode 100755
index 0000000..e636768
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/CollectionHasUpto1ElementPredicate.java
@@ -0,0 +1,37 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.functor;
+
+import java.util.Collection;
+
+/**
+ * <p>
+ * CollectionHasUpto1ElementPredicate class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class CollectionHasUpto1ElementPredicate implements Predicate<Collection<?>> {
+
+ public Boolean apply(final Collection<?> object) {
+ return object.size() < 2;
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/ContainsPredicate.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/ContainsPredicate.java
new file mode 100755
index 0000000..72eefef
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/ContainsPredicate.java
@@ -0,0 +1,51 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.functor;
+
+import java.util.Collection;
+
+/**
+ * <p>
+ * ContainsPredicate class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class ContainsPredicate<T> implements Predicate<T> {
+
+ private final Collection<? extends T> objs;
+
+ /**
+ * <p>
+ * Constructor for ContainsPredicate.
+ * </p>
+ *
+ * @param objs a {@link java.util.Collection} object.
+ */
+ public ContainsPredicate(Collection<? extends T> objs) {
+ super();
+ this.objs = objs;
+ }
+
+ public Boolean apply(T arg0) {
+ return objs.contains(arg0);
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/InStrPredicate.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/InStrPredicate.java
new file mode 100755
index 0000000..01a2c55
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/InStrPredicate.java
@@ -0,0 +1,49 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.functor;
+
+/**
+ * <p>
+ * InStrPredicate class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class InStrPredicate implements Predicate<String> {
+
+ private final String str;
+
+ /**
+ * <p>
+ * Constructor for InStrPredicate.
+ * </p>
+ *
+ * @param str a {@link java.lang.String} object.
+ */
+ public InStrPredicate(final String str) {
+ this.str = str;
+ }
+
+ public Boolean apply(final String arg0) {
+ String target = arg0.toString();
+ return -1 != str.indexOf(target);
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/NotEmptyStringPredicate.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/NotEmptyStringPredicate.java
new file mode 100755
index 0000000..ad221f1
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/NotEmptyStringPredicate.java
@@ -0,0 +1,39 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.functor;
+
+import com.ekingstar.commons.lang.Strings;
+
+/**
+ * <p>
+ * NotEmptyStringPredicate class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class NotEmptyStringPredicate implements Predicate<String> {
+ /** Constant <code>INSTANCE</code> */
+ public static final NotEmptyStringPredicate Instance = new NotEmptyStringPredicate();
+
+ public Boolean apply(final String value) {
+ return (null != value) && (value instanceof String) && Strings.isNotEmpty((String) value);
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/NotZeroNumberPredicate.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/NotZeroNumberPredicate.java
new file mode 100755
index 0000000..2b7b852
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/NotZeroNumberPredicate.java
@@ -0,0 +1,49 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.functor;
+
+
+/**
+ * <p>
+ * NotZeroNumberPredicate class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class NotZeroNumberPredicate implements Predicate<Number> {
+
+ public Boolean apply(final Number value) {
+ return 0 != ((Number) value).intValue();
+ }
+
+ /** Constant <code>INSTANCE</code> */
+ public static final NotZeroNumberPredicate Instance = new NotZeroNumberPredicate();
+
+ /**
+ * <p>
+ * getInstance.
+ * </p>
+ *
+ * @return a {@link com.ekingstar.commons.lang.functor.NotZeroNumberPredicate} object.
+ */
+ public static NotZeroNumberPredicate getInstance() {
+ return Instance;
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/NumRangePredicate.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/NumRangePredicate.java
new file mode 100755
index 0000000..e3eb23c
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/NumRangePredicate.java
@@ -0,0 +1,53 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.functor;
+
+/**
+ * 有效整型判断谓词
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class NumRangePredicate implements Predicate<Number> {
+
+ private final int floor, upper;
+
+ /**
+ * <p>
+ * Constructor for NumRangePredicate.
+ * </p>
+ *
+ * @param floor a int.
+ * @param upper a int.
+ */
+ public NumRangePredicate(final int floor, final int upper) {
+ this.floor = floor;
+ this.upper = upper;
+ }
+
+ public Boolean apply(final Number value) {
+ if (null == value) {
+ return false;
+ } else {
+ int valueInt = value.intValue();
+ return valueInt <= upper && valueInt >= floor;
+ }
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/Predicate.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/Predicate.java
new file mode 100644
index 0000000..8af4bc3
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/Predicate.java
@@ -0,0 +1,29 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.functor;
+
+/**
+ * Prediate
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public interface Predicate<T> extends UnaryFunction<T, Boolean> {
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/Transformer.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/Transformer.java
new file mode 100644
index 0000000..7baff61
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/Transformer.java
@@ -0,0 +1,31 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.functor;
+
+/**
+ * Transform object to another
+ *
+ * @author chaostone
+ * @since 3.2.0
+ * @param <I>
+ * @param <R>
+ */
+public interface Transformer<I, R> extends UnaryFunction<I, R> {
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/UnaryFunction.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/UnaryFunction.java
new file mode 100644
index 0000000..be374eb
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/functor/UnaryFunction.java
@@ -0,0 +1,46 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.functor;
+
+import com.ekingstar.commons.lang.Objects;
+
+/**
+ * Unary Function Object
+ *
+ * @param <I> input type
+ * @param <R> returned output type
+ * @author chaostone
+ * @since 3.2.0
+ */
+public interface UnaryFunction<I, R> {
+
+ /**
+ * Returns the result of applying this function to {@code input}. This method is <i>generally
+ * expected</i>, but not absolutely required, to have the following properties:
+ * <ul>
+ * <li>Its execution does not cause any observable side effects.
+ * <li>The computation is <i>consistent with equals</i>; that is, {@link Objects#equal
+ * Objects.equal}{@code (a, b)} implies that {@code Objects.equal(function.apply(a),
+ * function.apply(b))}.
+ * </ul>
+ *
+ * @throws NullPointerException if {@code input} is null
+ */
+ R apply(I input);
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/reflect/ClassInfo.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/reflect/ClassInfo.java
new file mode 100644
index 0000000..7fd05c0
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/reflect/ClassInfo.java
@@ -0,0 +1,247 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.reflect;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.ekingstar.commons.collection.CollectUtils;
+import com.ekingstar.commons.collection.FastHashMap;
+import com.ekingstar.commons.lang.tuple.Pair;
+
+/**
+ * Class meta information.It contains method signature,property names
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public final class ClassInfo {
+
+ /** class info cache */
+ public static Map<Class<?>, ClassInfo> cache = CollectUtils.newHashMap();
+
+ /** unqiue method indexes,without any override */
+ private final FastHashMap<String, Integer> methodIndexs = CollectUtils.newFastMap(64);
+
+ /** all method indexes */
+ private final FastHashMap<String, List<MethodInfo>> methods = CollectUtils.newFastMap(64);
+
+ /** property read method indexes */
+ private final FastHashMap<String, MethodInfo> propertyReadMethods = CollectUtils.newFastMap(64);
+
+ /** property write method indexes */
+ private final FastHashMap<String, MethodInfo> propertyWriteMethods = CollectUtils.newFastMap(64);
+
+ /**
+ * Construct Classinfo by method list.
+ */
+ public ClassInfo(Collection<MethodInfo> methodinfos) {
+ super();
+ for (MethodInfo info : methodinfos) {
+ List<MethodInfo> named = methods.get(info.method.getName());
+ if (null == named) {
+ named = CollectUtils.newArrayList();
+ methods.put(info.method.getName(), named);
+ }
+ named.add(info);
+ // true is get,false is set.
+ Pair<Boolean, String> propertyInfo = info.property();
+ if (null != propertyInfo) {
+ if (propertyInfo.getLeft()) {
+ MethodInfo old = propertyReadMethods.put(propertyInfo.getRight(), info);
+ // old return type is subtype
+ if (null != old && info.method.getReturnType().isAssignableFrom(old.method.getReturnType())) propertyReadMethods
+ .put(propertyInfo.getRight(), old);
+ } else propertyWriteMethods.put(propertyInfo.getRight(), info);
+ }
+ }
+ for (Map.Entry<String, List<MethodInfo>> entry : methods.entrySet()) {
+ if (entry.getValue().size() == 1) methodIndexs.put(entry.getKey(),
+ Integer.valueOf(entry.getValue().get(0).index));
+ }
+ }
+
+ /**
+ * Return property read index,return -1 when not found.
+ */
+ public final int getReadIndex(String property) {
+ MethodInfo method = propertyReadMethods.get(property);
+ return (null == method) ? -1 : method.index;
+ }
+
+ /**
+ * Return property read index,return -1 when not found.
+ */
+ public final MethodInfo getReader(String property) {
+ return propertyReadMethods.get(property);
+ }
+
+ /**
+ * Return property type,return null when not found.
+ */
+ public final Class<?> getPropertyType(String property) {
+ MethodInfo info = propertyWriteMethods.get(property);
+ if (null == info) return null;
+ else return info.parameterTypes[0];
+ }
+
+ /**
+ * Return property write index,return -1 if not found.
+ */
+ public final int getWriteIndex(String property) {
+ MethodInfo method = propertyWriteMethods.get(property);
+ return (null == method) ? -1 : method.index;
+ }
+
+ /**
+ * Return property write method,return null if not found.
+ */
+ public final MethodInfo getWriter(String property) {
+ return propertyWriteMethods.get(property);
+ }
+
+ /**
+ * Return method index,return -1 if not found.
+ */
+ public final int getIndex(String name, Object... args) {
+ Integer defaultIndex = methodIndexs.get(name);
+ if (null != defaultIndex) return defaultIndex.intValue();
+ else {
+ final List<MethodInfo> exists = methods.get(name);
+ if (null != exists) {
+ for (MethodInfo info : exists)
+ if (info.matches(args)) return info.index;
+ }
+ return -1;
+ }
+ }
+
+ /**
+ * Return public metheds according to given name
+ */
+ public final List<MethodInfo> getMethods(String name) {
+ List<MethodInfo> namedMethod = methods.get(name);
+ if (null == namedMethod) return Collections.emptyList();
+ else return namedMethod;
+ }
+
+ /**
+ * Return all public methods.
+ */
+ public final List<MethodInfo> getMethods() {
+ List<MethodInfo> methodInfos = CollectUtils.newArrayList();
+ for (Map.Entry<String, List<MethodInfo>> entry : methods.entrySet()) {
+ for (MethodInfo info : entry.getValue())
+ methodInfos.add(info);
+ }
+ Collections.sort(methodInfos);
+ return methodInfos;
+ }
+
+ /**
+ * Return true when Method is public and not static and not volatile.
+ * <p>
+ * javassist.util.proxy.ProxyFactory.getMethods has error due to bridge method.
+ */
+ private static boolean goodMethod(Method method) {
+ int modifiers = method.getModifiers();
+ if (Modifier.isStatic(modifiers) || Modifier.isPrivate(modifiers)) return false;
+ // Skip bridge methods generated method by compiler
+ // For example. CompareTo(Some) and CompareTo(Object).
+ if (method.isBridge()) return false;
+ // Skip method in Object
+ String methodName = method.getName();
+ if (method.getParameterTypes().length == 0
+ && (methodName.equals("hashCode") || methodName.equals("toString"))) return false;
+ if (method.getParameterTypes().length == 1 & methodName.equals("equals")) return false;
+ return true;
+ }
+
+ /**
+ * Get ClassInfo by type.
+ * It search from cache, when failure build it and put it into cache.
+ */
+ public static final ClassInfo get(Class<?> type) {
+ ClassInfo exist = cache.get(type);
+ if (null != exist) return exist;
+ synchronized (cache) {
+ exist = cache.get(type);
+ if (null != exist) return exist;
+
+ Set<MethodInfo> methods = CollectUtils.newHashSet();
+ Class<?> nextClass = type;
+ int index = 0;
+ Map<String, Class<?>> nextParamTypes = null;
+ while (null != nextClass && Object.class != nextClass) {
+ Method[] declaredMethods = nextClass.getDeclaredMethods();
+ for (int i = 0, n = declaredMethods.length; i < n; i++) {
+ Method method = declaredMethods[i];
+ if (!goodMethod(method)) continue;
+ Type[] types = method.getGenericParameterTypes();
+ Class<?>[] paramsTypes = new Class<?>[types.length];
+ for (int j = 0; j < types.length; j++) {
+ Type t = types[j];
+ if (t instanceof ParameterizedType) {
+ paramsTypes[j] = (Class<?>) ((ParameterizedType) t).getRawType();
+ } else if (t instanceof TypeVariable) {
+ paramsTypes[j] = nextParamTypes.get(((TypeVariable<?>) t).getName());
+ } else {
+ paramsTypes[j] = (Class<?>) t;
+ }
+ if (null == paramsTypes[j]) paramsTypes[j] = Object.class;
+ }
+ if (!methods.add(new MethodInfo(index++, method, paramsTypes))) index--;
+ }
+
+ Type nextType = nextClass.getGenericSuperclass();
+ nextClass = nextClass.getSuperclass();
+ if (nextType instanceof ParameterizedType) {
+ Map<String, Class<?>> tmp = CollectUtils.newHashMap();
+ Type[] ps = ((ParameterizedType) nextType).getActualTypeArguments();
+ TypeVariable<?>[] tvs = nextClass.getTypeParameters();
+ for (int k = 0; k < ps.length; k++) {
+ if (ps[k] instanceof Class<?>) {
+ tmp.put(tvs[k].getName(), (Class<?>) ps[k]);
+ } else if (ps[k] instanceof TypeVariable) {
+ tmp.put(tvs[k].getName(), nextParamTypes.get(((TypeVariable<?>) ps[k]).getName()));
+ }
+ }
+ nextParamTypes = tmp;
+ } else {
+ nextParamTypes = Collections.emptyMap();
+ }
+ }
+ exist = new ClassInfo(methods);
+ cache.put(type, exist);
+ return exist;
+ }
+ }
+
+ public Set<String> getWritableProperties() {
+ return CollectUtils.newHashSet(propertyWriteMethods.keySet());
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/reflect/MethodInfo.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/reflect/MethodInfo.java
new file mode 100644
index 0000000..87bcd7e
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/reflect/MethodInfo.java
@@ -0,0 +1,117 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.reflect;
+
+import static com.ekingstar.commons.lang.Strings.substringAfter;
+import static com.ekingstar.commons.lang.Strings.uncapitalize;
+import static java.lang.Character.isUpperCase;
+
+import java.lang.reflect.Method;
+
+import com.ekingstar.commons.lang.Objects;
+import com.ekingstar.commons.lang.tuple.Pair;
+
+/**
+ * Method name and return type and parameters type
+ *
+ * @author chaostone
+ * @since 3.2.0
+ */
+public final class MethodInfo implements Comparable<MethodInfo> {
+
+ public final int index;
+ public final Method method;
+ public final Class<?>[] parameterTypes;
+
+ public MethodInfo(int index, Method method, Class<?>[] parameterTypes) {
+ super();
+ this.index = index;
+ this.method = method;
+ this.parameterTypes = parameterTypes;
+ }
+
+ /**
+ * Return thid method is property read method (0) or write method(1) or none(-1).
+ */
+ public Pair<Boolean, String> property() {
+ String name = method.getName();
+ if (name.length() > 3 && name.startsWith("get") && isUpperCase(name.charAt(3))
+ && parameterTypes.length == 0) {
+ return Pair.of(Boolean.TRUE, uncapitalize(substringAfter(name, "get")));
+ } else if (name.length() > 2 && name.startsWith("is") && isUpperCase(name.charAt(2))
+ && parameterTypes.length == 0) {
+ return Pair.of(Boolean.TRUE, uncapitalize(substringAfter(name, "is")));
+ } else if (name.length() > 3 && name.startsWith("set") && isUpperCase(name.charAt(3))
+ && parameterTypes.length == 1) { return Pair.of(Boolean.FALSE,
+ uncapitalize(substringAfter(name, "set"))); }
+ return null;
+ }
+
+ @Override
+ public int compareTo(MethodInfo o) {
+ return this.index - o.index;
+ }
+
+ public boolean matches(Object[] args) {
+ if (parameterTypes.length != args.length) return false;
+ for (int i = 0; i < args.length; i++) {
+ if (null != args[i] && !parameterTypes[i].isInstance(args[i])) return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final Class<?> returnType = method.getReturnType();
+ StringBuilder sb = new StringBuilder();
+ sb.append((null == returnType) ? "void" : returnType.getSimpleName());
+ sb.append(' ').append(method.getName());
+ if (parameterTypes.length == 0) {
+ sb.append("()");
+ } else {
+ sb.append('(');
+ for (Class<?> type : parameterTypes) {
+ sb.append(type.getSimpleName()).append(",");
+ }
+ sb.deleteCharAt(sb.length() - 1);
+ sb.append(')');
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ for (Class<?> t : parameterTypes)
+ hash += t.hashCode();
+ return method.getName().hashCode() + hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof MethodInfo) {
+ MethodInfo other = (MethodInfo) obj;
+ return Objects.equalsBuilder().add(method.getName(), other.method.getName())
+ .add(parameterTypes, other.parameterTypes).isEquals();
+ } else {
+ return false;
+ }
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/time/Stopwatch.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/time/Stopwatch.java
new file mode 100644
index 0000000..c7c445e
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/time/Stopwatch.java
@@ -0,0 +1,181 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.time;
+
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.concurrent.TimeUnit;
+
+import com.ekingstar.commons.lang.Assert;
+
+/**
+ * @author chaostone
+ * @since 3.0.0
+ */
+public final class Stopwatch {
+ private final Ticker ticker;
+ private boolean isRunning;
+ private long elapsedNanos;
+ private long startTick;
+
+ /**
+ * Creates (but does not start) a new stopwatch using {@link System#nanoTime} as its time source.
+ */
+ public Stopwatch() {
+ this(Ticker.systemTicker(), false);
+ }
+
+ public Stopwatch(boolean start) {
+ this(Ticker.systemTicker(), true);
+ }
+
+ /**
+ * Creates (but does not start) a new stopwatch, using the specified time
+ * source.
+ */
+ public Stopwatch(Ticker ticker, boolean start) {
+ this.ticker = ticker;
+ if (start) {
+ isRunning = true;
+ startTick = ticker.read();
+ }
+ }
+
+ /**
+ * Returns {@code true} if {@link #start()} has been called on this stopwatch,
+ * and {@link #stop()} has not been called since the last call to {@code start()}.
+ */
+ public boolean isRunning() {
+ return isRunning;
+ }
+
+ /**
+ * Starts the stopwatch.
+ *
+ * @return this {@code Stopwatch} instance
+ * @throws IllegalStateException if the stopwatch is already running.
+ */
+ public Stopwatch start() {
+ Assert.isTrue(!isRunning);
+ isRunning = true;
+ startTick = ticker.read();
+ return this;
+ }
+
+ /**
+ * Stops the stopwatch. Future reads will return the fixed duration that had
+ * elapsed up to this point.
+ *
+ * @return this {@code Stopwatch} instance
+ * @throws IllegalStateException if the stopwatch is already stopped.
+ */
+ public Stopwatch stop() {
+ long tick = ticker.read();
+ Assert.isTrue(isRunning);
+ isRunning = false;
+ elapsedNanos += tick - startTick;
+ return this;
+ }
+
+ /**
+ * Sets the elapsed time for this stopwatch to zero,
+ * and places it in a stopped state.
+ *
+ * @return this {@code Stopwatch} instance
+ */
+ public Stopwatch reset() {
+ elapsedNanos = 0;
+ isRunning = false;
+ return this;
+ }
+
+ private long elapsedNanos() {
+ return isRunning ? ticker.read() - startTick + elapsedNanos : elapsedNanos;
+ }
+
+ /**
+ * Returns the current elapsed time shown on this stopwatch, expressed
+ * in the desired time unit, with any fraction rounded down.
+ * <p>
+ * Note that the overhead of measurement can be more than a microsecond, so it is generally not
+ * useful to specify {@link TimeUnit#NANOSECONDS} precision here.
+ */
+ public long elapsedTime(TimeUnit desiredUnit) {
+ return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
+ }
+
+ /**
+ * Returns the current elapsed time shown on this stopwatch, expressed
+ * in milliseconds, with any fraction rounded down. This is identical to
+ * {@code elapsedTime(TimeUnit.MILLISECONDS}.
+ */
+ public long elapsedMillis() {
+ return elapsedTime(MILLISECONDS);
+ }
+
+ /**
+ * Returns a string representation of the current elapsed time; equivalent to {@code toString(4)}
+ * (four significant figures).
+ */
+ @Override
+ public String toString() {
+ return toString(4);
+ }
+
+ /**
+ * Returns a string representation of the current elapsed time, choosing an
+ * appropriate unit and using the specified number of significant figures.
+ * For example, at the instant when {@code elapsedTime(NANOSECONDS)} would
+ * return {1234567}, {@code toString(4)} returns {@code "1.235 ms"}.
+ */
+ public String toString(int significantDigits) {
+ long nanos = elapsedNanos();
+
+ TimeUnit unit = chooseUnit(nanos);
+ double value = (double) nanos / NANOSECONDS.convert(1, unit);
+
+ // Too bad this functionality is not exposed as a regular method call
+ return String.format("%." + significantDigits + "g %s", value, abbreviate(unit));
+ }
+
+ private static TimeUnit chooseUnit(long nanos) {
+ if (SECONDS.convert(nanos, NANOSECONDS) > 0) { return SECONDS; }
+ if (MILLISECONDS.convert(nanos, NANOSECONDS) > 0) { return MILLISECONDS; }
+ if (MICROSECONDS.convert(nanos, NANOSECONDS) > 0) { return MICROSECONDS; }
+ return NANOSECONDS;
+ }
+
+ private static String abbreviate(TimeUnit unit) {
+ switch (unit) {
+ case NANOSECONDS:
+ return "ns";
+ case MICROSECONDS:
+ return "\u03bcs"; // μs
+ case MILLISECONDS:
+ return "ms";
+ case SECONDS:
+ return "s";
+ default:
+ throw new AssertionError();
+ }
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/time/Ticker.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/time/Ticker.java
new file mode 100644
index 0000000..b569ade
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/time/Ticker.java
@@ -0,0 +1,50 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.time;
+
+/**
+ * Time source generator
+ *
+ * @author chaostone
+ * @since 3.0.0
+ */
+public abstract class Ticker {
+
+ protected Ticker() {
+ }
+
+ /**
+ * Returns the number of nanoseconds elapsed
+ */
+ public abstract long read();
+
+ /**
+ * A ticker that reads the current time using {@link System#nanoTime}.
+ */
+ public static Ticker systemTicker() {
+ return SYSTEM_TICKER;
+ }
+
+ private static final Ticker SYSTEM_TICKER = new Ticker() {
+ @Override
+ public long read() {
+ return System.nanoTime();
+ }
+ };
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/time/TimerNode.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/time/TimerNode.java
new file mode 100644
index 0000000..68cbb62
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/time/TimerNode.java
@@ -0,0 +1,78 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.time;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Timer Node in stack
+ *
+ * @author chaostone
+ * @since 3.0.0
+ */
+public class TimerNode implements java.io.Serializable {
+
+ private static final long serialVersionUID = -6180672043920208784L;
+
+ List<TimerNode> children = new ArrayList<TimerNode>();
+
+ String resource;
+
+ long startTime;
+
+ long totalTime;
+
+ public TimerNode(String resource, long startTime) {
+ this.resource = resource;
+ this.startTime = startTime;
+ }
+
+ public void start(long startTime) {
+ this.startTime = startTime;
+ }
+
+ public long end() {
+ this.totalTime = System.currentTimeMillis() - startTime;
+ return this.totalTime;
+ }
+
+ public String getResource() {
+ return resource;
+ }
+
+ /**
+ * Get a formatted string representing all the methods that took longer than a specified time.
+ */
+ public String getPrintable() {
+ return getPrintable("");
+ }
+
+ protected String getPrintable(String indent) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(indent);
+ buffer.append("[" + totalTime + "ms] - " + resource);
+
+ for (TimerNode child : children) {
+ buffer.append('\n').append(child.getPrintable(indent + " "));
+ }
+ return buffer.toString();
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/time/TimerStack.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/time/TimerStack.java
new file mode 100644
index 0000000..8b2c3e4
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/time/TimerStack.java
@@ -0,0 +1,70 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.time;
+
+import java.util.Arrays;
+
+/**
+ * Record timer nodes
+ *
+ * @author chaostone
+ * @since 3.0.0
+ */
+public class TimerStack {
+
+ int index = -1;
+
+ TimerNode[] nodes;
+
+ public TimerStack(TimerNode root, int initCapacity) {
+ super();
+ nodes = new TimerNode[initCapacity];
+ push(root);
+ }
+
+ public TimerStack(TimerNode root) {
+ this(root, 15);
+ }
+
+ private void ensureCapacity() {
+ if (index >= nodes.length) {
+ int newCapacity = nodes.length * 2;
+ nodes = Arrays.copyOf(nodes, newCapacity);
+ }
+ }
+
+ public void push(TimerNode node) {
+ ensureCapacity();
+ nodes[++index] = node;
+ }
+
+ public TimerNode pop() {
+ if (index < 0) return null;
+ TimerNode top = nodes[index];
+ nodes[index] = null;
+ index--;
+ return top;
+ }
+
+ public TimerNode peek() {
+ if (index < 0) return null;
+ return nodes[index];
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/time/TimerTrace.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/time/TimerTrace.java
new file mode 100644
index 0000000..78e694b
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/time/TimerTrace.java
@@ -0,0 +1,161 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.time;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author chaostone
+ * @since 3.0.0
+ */
+public final class TimerTrace {
+
+ private static final Logger logger = LoggerFactory.getLogger(TimerTrace.class);
+
+ // A reference to the current TimerNode
+ protected static ThreadLocal<TimerStack> curStack = new ThreadLocal<TimerStack>();
+
+ /**
+ * System property that controls whether this timer should be used or not. Set to "true" activates
+ * the timer. Set to "false" to disactivate.
+ */
+ public static final String ACTIVATE_PROPERTY = "beangle.profile.activate";
+
+ /**
+ * System property that controls the min time, that if exceeded will cause a log (at INFO level)
+ * to be created.
+ */
+ public static final String MIN_TIME = "beangle.profile.mintime";
+
+ /**
+ * Initialized in a static block, it can be changed at runtime by calling setActive(...)
+ */
+ private static boolean active;
+
+ /**
+ * Get the min time for this profiling, it searches for a System property
+ * 'beangle.profile.mintime' and default to 0.
+ */
+ private static int mintime;
+
+ static {
+ active = "true".equalsIgnoreCase(System.getProperty(ACTIVATE_PROPERTY));
+ try {
+ mintime = Integer.parseInt(System.getProperty(MIN_TIME, "0"));
+ } catch (NumberFormatException e) {
+ }
+ }
+
+ /**
+ * Create and start a performance profiling with the <code>name</code> given. Deal with
+ * profile hierarchy automatically, so caller don't have to be concern about it.
+ *
+ * @param name profile name
+ */
+ public static void start(String name) {
+ if (!active) return;
+
+ TimerNode root = new TimerNode(name, System.currentTimeMillis());
+ TimerStack stack = (TimerStack) curStack.get();
+ if (null == stack) curStack.set(new TimerStack(root));
+ else stack.push(root);
+ }
+
+ /**
+ * End a preformance profiling with the <code>name</code> given. Deal with
+ * profile hierarchy automatically, so caller don't have to be concern about it.
+ */
+ public static void end() {
+ if (!active) return;
+
+ TimerStack stack = curStack.get();
+ if (null == stack) return;
+
+ TimerNode currentNode = stack.pop();
+
+ if (currentNode != null) {
+ TimerNode parent = stack.peek();
+ long total = currentNode.end();
+ // if we are the root timer, then print out the times
+ if (parent == null) {
+ printTimes(currentNode);
+ curStack.set(null); // for those servers that use thread pooling
+ } else {
+ if (total > mintime) parent.children.add(currentNode);
+ }
+ }
+ }
+
+ public void clear() {
+ curStack.set(null);
+ }
+
+ /**
+ * Do a log (at INFO level) of the time taken for this particular profiling.
+ *
+ * @param currentTimer profiling timer bean
+ */
+ private static void printTimes(TimerNode currentTimer) {
+ if (logger.isInfoEnabled()) logger.info(currentTimer.getPrintable());
+
+ }
+
+ /**
+ * Get the min time for this profiling, it searches for a System property
+ * 'beangle.profile.mintime' and default to 0.
+ *
+ * @return long
+ */
+ public static int getMinTime() {
+ return mintime;
+ }
+
+ /**
+ * Change mintime
+ *
+ * @param mintime
+ */
+ public static void setMinTime(int mintime) {
+ System.setProperty(MIN_TIME, String.valueOf(mintime));
+ TimerTrace.mintime = mintime;
+ }
+
+ /**
+ * Determine if profiling is being activated, by searching for a system property
+ * 'beangle.profile.activate', default to false (profiling is off).
+ *
+ * @return <tt>true</tt>, if active, <tt>false</tt> otherwise.
+ */
+ public static boolean isActive() {
+ return active;
+ }
+
+ /**
+ * Turn profiling on or off.
+ *
+ * @param active
+ */
+ public static void setActive(boolean active) {
+ if (active) System.setProperty(ACTIVATE_PROPERTY, "true");
+ else System.clearProperty(ACTIVATE_PROPERTY);
+ TimerTrace.active = active;
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/tuple/Pair.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/tuple/Pair.java
new file mode 100644
index 0000000..01ef701
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/tuple/Pair.java
@@ -0,0 +1,172 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.tuple;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import com.ekingstar.commons.lang.Objects;
+
+/**
+ * <p>
+ * A immutable pair consisting of two elements.
+ * </p>
+ *
+ * @author chaostone
+ * @param <L> the left element type
+ * @param <R> the right element type
+ */
+public class Pair<L, R> implements Map.Entry<L, R>, Serializable {
+
+ private static final long serialVersionUID = -7643900124010501814L;
+
+ /** Left object */
+ public final L _1;
+ /** Right object */
+ public final R _2;
+
+ /**
+ * <p>
+ * Obtains an immutable pair of from two objects inferring the generic types.
+ * </p>
+ * <p>
+ * This factory allows the pair to be created using inference to obtain the generic types.
+ * </p>
+ *
+ * @param <L> the left element type
+ * @param <R> the right element type
+ * @param left the left element, may be null
+ * @param right the right element, may be null
+ * @return a pair formed from the two parameters, not null
+ */
+ public static <L, R> Pair<L, R> of(L left, R right) {
+ return new Pair<L, R>(left, right);
+ }
+
+ /**
+ * Create a new pair instance.
+ *
+ * @param left the left value, may be null
+ * @param right the right value, may be null
+ */
+ public Pair(L left, R right) {
+ super();
+ this._1 = left;
+ this._2 = right;
+ }
+
+ public L getLeft() {
+ return _1;
+ }
+
+ public R getRight() {
+ return _2;
+ }
+
+ /**
+ * <p>
+ * Throws {@code UnsupportedOperationException}.
+ * </p>
+ * <p>
+ * This pair is immutable, so this operation is not supported.
+ * </p>
+ *
+ * @param value the value to set
+ * @return never
+ * @throws UnsupportedOperationException as this operation is not supported
+ */
+ public R setValue(R value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public L get_1() {
+ return _1;
+ }
+
+ public R get_2() {
+ return _2;
+ }
+
+ /**
+ * <p>
+ * Gets the key from this pair.
+ * </p>
+ * <p>
+ * This method implements the {@code Map.Entry} interface returning the left element as the key.
+ * </p>
+ *
+ * @return the left element as the key, may be null
+ */
+ public final L getKey() {
+ return _1;
+ }
+
+ /**
+ * <p>
+ * Gets the value from this pair.
+ * </p>
+ * <p>
+ * This method implements the {@code Map.Entry} interface returning the right element as the
+ * value.
+ * </p>
+ *
+ * @return the right element as the value, may be null
+ */
+ public R getValue() {
+ return _2;
+ }
+
+ /**
+ * <p>
+ * Compares this pair to another based on the two elements.
+ * </p>
+ *
+ * @param obj the object to compare to, null returns false
+ * @return true if the elements of the pair are equal
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) { return true; }
+ if (obj instanceof Map.Entry<?, ?>) {
+ Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
+ return Objects.equals(getKey(), other.getKey()) && Objects.equals(getValue(), other.getValue());
+ }
+ return false;
+ }
+
+ /**
+ * <p>
+ * Returns a suitable hash code. The hash code follows the definition in {@code Map.Entry}.
+ * </p>
+ *
+ * @return the hash code
+ */
+ @Override
+ public int hashCode() {
+ // see Map.Entry API specification
+ return (getKey() == null ? 0 : getKey().hashCode()) ^ (getValue() == null ? 0 : getValue().hashCode());
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder().append('(').append(getLeft()).append(',').append(getRight()).append(')')
+ .toString();
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/lang/tuple/Triple.java b/tools/commons/src/main/java/com/ekingstar/commons/lang/tuple/Triple.java
new file mode 100644
index 0000000..3f6b11d
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/lang/tuple/Triple.java
@@ -0,0 +1,70 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.tuple;
+
+import com.ekingstar.commons.lang.Objects;
+
+public class Triple<X, Y, Z> {
+
+ public final X _1;
+ public final Y _2;
+ public final Z _3;
+
+ public Triple(X e1, Y e2, Z e3) {
+ this._1 = e1;
+ this._2 = e2;
+ this._3 = e3;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((_1 == null) ? 0 : _1.hashCode());
+ result = prime * result + ((_2 == null) ? 0 : _2.hashCode());
+ result = prime * result + ((_3 == null) ? 0 : _3.hashCode());
+ return result;
+ }
+
+
+ public X get_1() {
+ return _1;
+ }
+
+ public Y get_2() {
+ return _2;
+ }
+
+ public Z get_3() {
+ return _3;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ Triple<?, ?, ?> other = (Triple<?, ?, ?>) obj;
+ return Objects.equalsBuilder().add(_1, other._1).add(_2, other._2).add(_3, other._3).isEquals();
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringBuilder(this).add("_1", _1).add("_2", _2).add("_3", _3).toString();
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/page/Limit.java b/tools/commons/src/main/java/com/ekingstar/commons/page/Limit.java
new file mode 100755
index 0000000..f2d03a8
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/page/Limit.java
@@ -0,0 +1,29 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.page;
+
+/**
+ * 查询中的数目限制
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public interface Limit {
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/page/Page.java b/tools/commons/src/main/java/com/ekingstar/commons/page/Page.java
new file mode 100755
index 0000000..5813e17
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/page/Page.java
@@ -0,0 +1,130 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.page;
+
+import java.util.List;
+
+/**
+ * 分页对象
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public interface Page<E> extends List<E> {
+ /** Constant <code>DEFAULT_PAGE_NUM=1</code> */
+ public static final int DEFAULT_PAGE_NUM = 1;
+
+ /** Constant <code>DEFAULT_PAGE_SIZE=20</code> */
+ public static final int DEFAULT_PAGE_SIZE = 20;
+
+ /**
+ * 第一页.
+ *
+ * @return 1
+ */
+ int getFirstPageNo();
+
+ /**
+ * 最大页码
+ *
+ * @return a int.
+ */
+ int getMaxPageNo();
+
+ /**
+ * 下一页页码
+ *
+ * @return a int.
+ */
+ int getNextPageNo();
+
+ /**
+ * 上一页页码
+ *
+ * @return a int.
+ */
+ int getPreviousPageNo();
+
+ /**
+ * 当前页码
+ *
+ * @return a int.
+ */
+ int getPageNo();
+
+ /**
+ * 每页大小
+ *
+ * @return a int.
+ */
+ int getPageSize();
+
+ /**
+ * 数据总量
+ *
+ * @return a int.
+ */
+ int getTotal();
+
+ /**
+ * 下一页
+ *
+ * @return a {@link com.ekingstar.commons.collection.page.Page} object.
+ */
+ Page<E> next();
+
+ /**
+ * 是否还有下一页
+ *
+ * @return a boolean.
+ */
+ boolean hasNext();
+
+ /**
+ * 上一页
+ *
+ * @return a {@link com.ekingstar.commons.collection.page.Page} object.
+ */
+ Page<E> previous();
+
+ /**
+ * 是否还有上一页
+ *
+ * @return a boolean.
+ */
+ boolean hasPrevious();
+
+ /**
+ * 调转到指定页
+ *
+ * @param pageNo a int.
+ * @return a {@link com.ekingstar.commons.collection.page.Page} object.
+ */
+ Page<E> moveTo(int pageNo);
+
+ /**
+ * <p>
+ * getItems.
+ * </p>
+ *
+ * @return a {@link java.util.List} object.
+ */
+ List<E> getItems();
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/page/PageLimit.java b/tools/commons/src/main/java/com/ekingstar/commons/page/PageLimit.java
new file mode 100755
index 0000000..a59476c
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/page/PageLimit.java
@@ -0,0 +1,128 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.page;
+
+
+/**
+ * 查询分页限制
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class PageLimit implements Limit {
+
+ private int pageNo;
+
+ private int pageSize;
+
+ /**
+ * <p>
+ * Constructor for PageLimit.
+ * </p>
+ */
+ public PageLimit() {
+ super();
+ }
+
+ /**
+ * <p>
+ * Constructor for PageLimit.
+ * </p>
+ *
+ * @param pageNo
+ * a int.
+ * @param pageSize
+ * a int.
+ */
+ public PageLimit(final int pageNo, final int pageSize) {
+ this.pageNo = pageNo;
+ this.pageSize = pageSize;
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>pageSize</code>.
+ * </p>
+ *
+ * @return a int.
+ */
+ public int getPageSize() {
+ return pageSize;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>pageSize</code>.
+ * </p>
+ *
+ * @param pageSize
+ * a int.
+ */
+ public void setPageSize(final int pageSize) {
+ this.pageSize = pageSize;
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>pageNo</code>.
+ * </p>
+ *
+ * @return a int.
+ */
+ public int getPageNo() {
+ return pageNo;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>pageNo</code>.
+ * </p>
+ *
+ * @param pageNo
+ * a int.
+ */
+ public void setPageNo(final int pageNo) {
+ this.pageNo = pageNo;
+ }
+
+ /**
+ * <p>
+ * isValid.
+ * </p>
+ *
+ * @return a boolean.
+ */
+ public boolean isValid() {
+ return pageNo > 0 && pageSize > 0;
+ }
+
+ /**
+ * <p>
+ * toString.
+ * </p>
+ *
+ * @see java.lang.Object#toString()
+ * @return a {@link java.lang.String} object.
+ */
+ public String toString() {
+ return new StringBuilder().append("pageNo:").append(pageNo).append(" pageSize:").append(pageSize)
+ .toString();
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/page/PageWapper.java b/tools/commons/src/main/java/com/ekingstar/commons/page/PageWapper.java
new file mode 100755
index 0000000..0c25f11
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/page/PageWapper.java
@@ -0,0 +1,267 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.page;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * <p>
+ * Abstract PageWapper class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public abstract class PageWapper<E> implements Page<E> {
+
+ private Page<E> page;
+
+ /**
+ * <p>
+ * getFirstPageNo.
+ * </p>
+ *
+ * @return a int.
+ */
+ public int getFirstPageNo() {
+ return 1;
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>page</code>.
+ * </p>
+ *
+ * @return a {@link com.ekingstar.commons.collection.page.Page} object.
+ */
+ public Page<E> getPage() {
+ return page;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>page</code>.
+ * </p>
+ *
+ * @param page a {@link com.ekingstar.commons.collection.page.Page} object.
+ */
+ public void setPage(Page<E> page) {
+ this.page = page;
+ }
+
+ /**
+ * <p>
+ * getItems.
+ * </p>
+ *
+ * @return a {@link java.util.List} object.
+ */
+ public List<E> getItems() {
+ return page.getItems();
+ }
+
+ /**
+ * <p>
+ * iterator.
+ * </p>
+ *
+ * @return a {@link java.util.Iterator} object.
+ */
+ public Iterator<E> iterator() {
+ return page.iterator();
+ }
+
+ /**
+ * <p>
+ * add.
+ * </p>
+ *
+ * @param obj a E object.
+ * @return a boolean.
+ */
+ public boolean add(E obj) {
+ return page.add(obj);
+ }
+
+ /** {@inheritDoc} */
+ public boolean addAll(Collection<? extends E> datas) {
+ return page.addAll(datas);
+ }
+
+ /**
+ * <p>
+ * clear.
+ * </p>
+ */
+ public void clear() {
+ page.clear();
+ }
+
+ /** {@inheritDoc} */
+ public boolean contains(Object obj) {
+ return page.contains(obj);
+ }
+
+ /** {@inheritDoc} */
+ public boolean containsAll(Collection<?> datas) {
+ return page.containsAll(datas);
+ }
+
+ /**
+ * <p>
+ * isEmpty.
+ * </p>
+ *
+ * @return a boolean.
+ */
+ public boolean isEmpty() {
+ return page.isEmpty();
+ }
+
+ /**
+ * <p>
+ * size.
+ * </p>
+ *
+ * @return a int.
+ */
+ public int size() {
+ return page.size();
+ }
+
+ /**
+ * <p>
+ * toArray.
+ * </p>
+ *
+ * @return an array of {@link java.lang.Object} objects.
+ */
+ public Object[] toArray() {
+ return page.toArray();
+ }
+
+ /**
+ * <p>
+ * toArray.
+ * </p>
+ *
+ * @param datas an array of T objects.
+ * @param <T> a T object.
+ * @return an array of T objects.
+ */
+ public <T> T[] toArray(T[] datas) {
+ return page.toArray(datas);
+ }
+
+ /** {@inheritDoc} */
+ public boolean remove(Object obj) {
+ return page.remove(obj);
+ }
+
+ /** {@inheritDoc} */
+ public boolean removeAll(Collection<?> datas) {
+ return page.removeAll(datas);
+ }
+
+ /** {@inheritDoc} */
+ public boolean retainAll(Collection<?> datas) {
+ return page.retainAll(datas);
+ }
+
+ /**
+ * <p>
+ * add.
+ * </p>
+ *
+ * @param index a int.
+ * @param arg1 a E object.
+ */
+ public void add(int index, E arg1) {
+ page.add(index, arg1);
+ }
+
+ /** {@inheritDoc} */
+ public boolean addAll(int index, Collection<? extends E> arg1) {
+ return page.addAll(index, arg1);
+ }
+
+ /** {@inheritDoc} */
+ public E get(int index) {
+ return page.get(index);
+ }
+
+ /** {@inheritDoc} */
+ public int lastIndexOf(Object o) {
+ return page.lastIndexOf(o);
+ }
+
+ /**
+ * <p>
+ * listIterator.
+ * </p>
+ *
+ * @return a {@link java.util.ListIterator} object.
+ */
+ public ListIterator<E> listIterator() {
+ return page.listIterator();
+ }
+
+ /** {@inheritDoc} */
+ public ListIterator<E> listIterator(int index) {
+ return page.listIterator(index);
+ }
+
+ /**
+ * <p>
+ * remove.
+ * </p>
+ *
+ * @param index a int.
+ * @return a E object.
+ */
+ public E remove(int index) {
+ return page.remove(index);
+ }
+
+ /**
+ * <p>
+ * set.
+ * </p>
+ *
+ * @param index a int.
+ * @param arg1 a E object.
+ * @return a E object.
+ */
+ public E set(int index, E arg1) {
+ return page.set(index, arg1);
+ }
+
+ /** {@inheritDoc} */
+ public List<E> subList(int fromIndex, int toIndex) {
+ return page.subList(fromIndex, toIndex);
+ }
+
+ /** {@inheritDoc} */
+ public int indexOf(Object o) {
+ return page.indexOf(o);
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/page/PagedList.java b/tools/commons/src/main/java/com/ekingstar/commons/page/PagedList.java
new file mode 100755
index 0000000..f4f496b
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/page/PagedList.java
@@ -0,0 +1,197 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.page;
+
+import java.util.List;
+
+/**
+ * <p>
+ * PagedList class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class PagedList<E> extends PageWapper<E> {
+
+ private final List<E> datas;
+
+ private int pageNo = 0;
+
+ private int maxPageNo;
+
+ private int pageSize;
+
+ /**
+ * <p>
+ * Constructor for PagedList.
+ * </p>
+ *
+ * @param datas a {@link java.util.List} object.
+ * @param pageSize a int.
+ */
+ public PagedList(List<E> datas, int pageSize) {
+ this(datas, new PageLimit(1, pageSize));
+ }
+
+ /**
+ * <p>
+ * Constructor for PagedList.
+ * </p>
+ *
+ * @param datas a {@link java.util.List} object.
+ * @param limit a {@link com.ekingstar.commons.page.PageLimit} object.
+ */
+ public PagedList(List<E> datas, PageLimit limit) {
+ super();
+ this.datas = datas;
+ this.pageSize = limit.getPageSize();
+ this.pageNo = limit.getPageNo() - 1;
+ if (datas.size() <= pageSize) {
+ this.maxPageNo = 1;
+ } else {
+ final int remainder = datas.size() % pageSize;
+ final int quotient = datas.size() / pageSize;
+ this.maxPageNo = (0 == remainder) ? quotient : (quotient + 1);
+ }
+ this.next();
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>maxPageNo</code>.
+ * </p>
+ *
+ * @return a int.
+ */
+ public int getMaxPageNo() {
+ return maxPageNo;
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>pageNo</code>.
+ * </p>
+ *
+ * @return a int.
+ */
+ public int getPageNo() {
+ return pageNo;
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>pageSize</code>.
+ * </p>
+ *
+ * @return a int.
+ */
+ public int getPageSize() {
+ return pageSize;
+ }
+
+ /**
+ * <p>
+ * getTotal.
+ * </p>
+ *
+ * @return a int.
+ */
+ public int getTotal() {
+ return datas.size();
+ }
+
+ /**
+ * <p>
+ * getNextPageNo.
+ * </p>
+ *
+ * @return a int.
+ */
+ public final int getNextPageNo() {
+ return getPage().getNextPageNo();
+ }
+
+ /**
+ * <p>
+ * getPreviousPageNo.
+ * </p>
+ *
+ * @return a int.
+ */
+ public final int getPreviousPageNo() {
+ return getPage().getPreviousPageNo();
+ }
+
+ /**
+ * <p>
+ * hasNext.
+ * </p>
+ *
+ * @return a boolean.
+ */
+ public boolean hasNext() {
+ return getPageNo() < getMaxPageNo();
+ }
+
+ /**
+ * <p>
+ * hasPrevious.
+ * </p>
+ *
+ * @return a boolean.
+ */
+ public boolean hasPrevious() {
+ return getPageNo() > 1;
+ }
+
+ /**
+ * <p>
+ * next.
+ * </p>
+ *
+ * @return a {@link com.ekingstar.commons.collection.page.Page} object.
+ */
+ public Page<E> next() {
+ return moveTo(pageNo + 1);
+ }
+
+ /**
+ * <p>
+ * previous.
+ * </p>
+ *
+ * @return a {@link com.ekingstar.commons.collection.page.Page} object.
+ */
+ public Page<E> previous() {
+ return moveTo(pageNo - 1);
+ }
+
+ /** {@inheritDoc} */
+ public Page<E> moveTo(int pageNo) {
+ if (pageNo < 1) { throw new RuntimeException("error pageNo:" + pageNo); }
+ this.pageNo = pageNo;
+ int toIndex = pageNo * pageSize;
+ SinglePage<E> newPage = new SinglePage<E>(pageNo, pageSize, datas.size(), datas.subList((pageNo - 1)
+ * pageSize, (toIndex < datas.size()) ? toIndex : datas.size()));
+ setPage(newPage);
+ return this;
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/page/Pages.java b/tools/commons/src/main/java/com/ekingstar/commons/page/Pages.java
new file mode 100755
index 0000000..67a64b4
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/page/Pages.java
@@ -0,0 +1,114 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.page;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>
+ * Pages class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class Pages {
+
+ private static final Page<Object> EMPTY_PAGE = new EmptyPage<Object>();
+
+ /**
+ * <p>
+ * emptyPage.
+ * </p>
+ *
+ * @param <T> a T object.
+ * @return a {@link com.ekingstar.commons.collection.page.Page} object.
+ */
+ @SuppressWarnings("unchecked")
+ public static final <T> Page<T> emptyPage() {
+ return (Page<T>) EMPTY_PAGE;
+ }
+
+ private static class EmptyPage<E> extends AbstractList<E> implements Page<E> {
+
+ public int getFirstPageNo() {
+ return 0;
+ }
+
+ public int getMaxPageNo() {
+ return 0;
+ }
+
+ public int getNextPageNo() {
+ return 0;
+ }
+
+ public int getPageNo() {
+ return 0;
+ }
+
+ public int getPageSize() {
+ return 0;
+ }
+
+ public int getPreviousPageNo() {
+ return 0;
+ }
+
+ public int getTotal() {
+ return 0;
+ }
+
+ public boolean hasNext() {
+ return false;
+ }
+
+ public boolean hasPrevious() {
+ return false;
+ }
+
+ public Page<E> next() {
+ return this;
+ }
+
+ public Page<E> previous() {
+ return this;
+ }
+
+ public E get(int index) {
+ return null;
+ }
+
+ public int size() {
+ return 0;
+ }
+
+ public Page<E> moveTo(int pageNo) {
+ return this;
+ }
+
+ public List<E> getItems() {
+ return new ArrayList<E>(0);
+ }
+
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/page/SinglePage.java b/tools/commons/src/main/java/com/ekingstar/commons/page/SinglePage.java
new file mode 100755
index 0000000..aaa948f
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/page/SinglePage.java
@@ -0,0 +1,451 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.page;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * 分页对象
+ *
+ * @author chaostone
+ * @version $Id: $
+ */
+public class SinglePage<E> implements Page<E> {
+
+ private int pageNo;
+
+ private int pageSize;
+
+ private int total;
+
+ private List<E> items;
+
+ /**
+ * <p>
+ * Constructor for SinglePage.
+ * </p>
+ */
+ public SinglePage() {
+ super();
+ }
+
+ /**
+ * <p>
+ * Constructor for SinglePage.
+ * </p>
+ *
+ * @param pageNo a int.
+ * @param pageSize a int.
+ * @param total a int.
+ * @param dataItems a {@link java.util.List} object.
+ */
+ public SinglePage(int pageNo, int pageSize, int total, List<E> dataItems) {
+ this.items = dataItems;
+ if (pageSize < 1) {
+ this.pageSize = 2;
+ } else {
+ this.pageSize = pageSize;
+ }
+ if (pageNo < 1) {
+ this.pageNo = 1;
+ } else {
+ this.pageNo = pageNo;
+ }
+ this.total = total;
+ }
+
+ /**
+ * <p>
+ * getFirstPageNo.
+ * </p>
+ *
+ * @return a int.
+ */
+ public final int getFirstPageNo() {
+ return 1;
+ }
+
+ /**
+ * <p>
+ * getMaxPageNo.
+ * </p>
+ *
+ * @return a int.
+ */
+ public final int getMaxPageNo() {
+ if (getTotal() < getPageSize()) {
+ return 1;
+ } else {
+ final int remainder = getTotal() % getPageSize();
+ final int quotient = getTotal() / getPageSize();
+ return (0 == remainder) ? quotient : (quotient + 1);
+ }
+ }
+
+ /**
+ * <p>
+ * getNextPageNo.
+ * </p>
+ *
+ * @return a int.
+ */
+ public final int getNextPageNo() {
+ if (getPageNo() == getMaxPageNo()) {
+ return getMaxPageNo();
+ } else {
+ return getPageNo() + 1;
+ }
+ }
+
+ /**
+ * <p>
+ * getPreviousPageNo.
+ * </p>
+ *
+ * @return a int.
+ */
+ public final int getPreviousPageNo() {
+ if (getPageNo() == 1) {
+ return getPageNo();
+ } else {
+ return getPageNo() - 1;
+ }
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>pageNo</code>.
+ * </p>
+ *
+ * @return a int.
+ */
+ public final int getPageNo() {
+ return pageNo;
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>pageSize</code>.
+ * </p>
+ *
+ * @return a int.
+ */
+ public final int getPageSize() {
+ return pageSize;
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>items</code>.
+ * </p>
+ *
+ * @return a {@link java.util.List} object.
+ */
+ public final List<E> getItems() {
+ return items;
+ }
+
+ /**
+ * <p>
+ * Getter for the field <code>total</code>.
+ * </p>
+ *
+ * @return a int.
+ */
+ public final int getTotal() {
+ return total;
+ }
+
+ /** {@inheritDoc} */
+ public boolean add(final Object obj) {
+ throw new RuntimeException("unsupported add");
+ }
+
+ /** {@inheritDoc} */
+ public boolean addAll(final Collection<? extends E> datas) {
+ throw new RuntimeException("unsupported addAll");
+ }
+
+ /**
+ * <p>
+ * clear.
+ * </p>
+ */
+ public void clear() {
+ throw new RuntimeException("unsupported clear");
+ }
+
+ /** {@inheritDoc} */
+ public boolean contains(final Object obj) {
+ return items.contains(obj);
+ }
+
+ /** {@inheritDoc} */
+ public boolean containsAll(final Collection<?> datas) {
+ return items.containsAll(datas);
+ }
+
+ /**
+ * <p>
+ * isEmpty.
+ * </p>
+ *
+ * @return a boolean.
+ */
+ public boolean isEmpty() {
+ return items.isEmpty();
+ }
+
+ /**
+ * <p>
+ * iterator.
+ * </p>
+ *
+ * @return a {@link java.util.Iterator} object.
+ */
+ public Iterator<E> iterator() {
+ return items.iterator();
+ }
+
+ /** {@inheritDoc} */
+ public boolean remove(final Object obj) {
+ throw new RuntimeException("unsupported removeAll");
+ }
+
+ /** {@inheritDoc} */
+ public boolean removeAll(final Collection<?> datas) {
+ throw new RuntimeException("unsupported removeAll");
+ }
+
+ /** {@inheritDoc} */
+ public boolean retainAll(final Collection<?> datas) {
+ throw new RuntimeException("unsupported retailAll");
+ }
+
+ /**
+ * <p>
+ * size.
+ * </p>
+ *
+ * @return a int.
+ */
+ public int size() {
+ return items.size();
+ }
+
+ /**
+ * <p>
+ * toArray.
+ * </p>
+ *
+ * @return an array of {@link java.lang.Object} objects.
+ */
+ public Object[] toArray() {
+ return items.toArray();
+ }
+
+ /**
+ * <p>
+ * toArray.
+ * </p>
+ *
+ * @param datas an array of T objects.
+ * @param <T> a T object.
+ * @return an array of T objects.
+ */
+ public <T> T[] toArray(final T[] datas) {
+ return items.toArray(datas);
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>pageNo</code>.
+ * </p>
+ *
+ * @param pageNo a int.
+ */
+ public void setPageNo(final int pageNo) {
+ this.pageNo = pageNo;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>pageSize</code>.
+ * </p>
+ *
+ * @param pageSize a int.
+ */
+ public void setPageSize(final int pageSize) {
+ this.pageSize = pageSize;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>total</code>.
+ * </p>
+ *
+ * @param total a int.
+ */
+ public void setTotal(final int total) {
+ this.total = total;
+ }
+
+ /**
+ * <p>
+ * Setter for the field <code>items</code>.
+ * </p>
+ *
+ * @param dataItems a {@link java.util.List} object.
+ */
+ public void setItems(final List<E> dataItems) {
+ this.items = dataItems;
+ }
+
+ // dummy method
+ /**
+ * <p>
+ * hasNext.
+ * </p>
+ *
+ * @return a boolean.
+ */
+ public boolean hasNext() {
+ return getMaxPageNo() > pageNo;
+ }
+
+ /**
+ * <p>
+ * hasPrevious.
+ * </p>
+ *
+ * @return a boolean.
+ */
+ public boolean hasPrevious() {
+ return pageNo > 1;
+ }
+
+ /**
+ * <p>
+ * next.
+ * </p>
+ *
+ * @return a {@link com.ekingstar.commons.collection.page.Page} object.
+ */
+ public Page<E> next() {
+ return this;
+ }
+
+ /**
+ * <p>
+ * previous.
+ * </p>
+ *
+ * @return a {@link com.ekingstar.commons.collection.page.Page} object.
+ */
+ public Page<E> previous() {
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ public Page<E> moveTo(int pageNo) {
+ return this;
+ }
+
+ /**
+ * <p>
+ * add.
+ * </p>
+ *
+ * @param arg0 a int.
+ * @param arg1 a E object.
+ */
+ public void add(int arg0, E arg1) {
+ items.add(arg0, arg1);
+ }
+
+ /** {@inheritDoc} */
+ public E get(int index) {
+ return items.get(index);
+ }
+
+ /** {@inheritDoc} */
+ public int indexOf(Object o) {
+ return items.indexOf(o);
+ }
+
+ /** {@inheritDoc} */
+ public int lastIndexOf(Object o) {
+ return items.lastIndexOf(o);
+ }
+
+ /**
+ * <p>
+ * listIterator.
+ * </p>
+ *
+ * @return a {@link java.util.ListIterator} object.
+ */
+ public ListIterator<E> listIterator() {
+ return items.listIterator();
+ }
+
+ /** {@inheritDoc} */
+ public ListIterator<E> listIterator(int index) {
+ return items.listIterator(index);
+ }
+
+ /**
+ * <p>
+ * remove.
+ * </p>
+ *
+ * @param index a int.
+ * @return a E object.
+ */
+ public E remove(int index) {
+ return items.remove(index);
+ }
+
+ /** {@inheritDoc} */
+ public boolean addAll(int arg0, Collection<? extends E> arg1) {
+ return items.addAll(arg0, arg1);
+ }
+
+ /**
+ * <p>
+ * set.
+ * </p>
+ *
+ * @param arg0 a int.
+ * @param arg1 a E object.
+ * @return a E object.
+ */
+ public E set(int arg0, E arg1) {
+ return items.set(arg0, arg1);
+ }
+
+ /** {@inheritDoc} */
+ public List<E> subList(int fromIndex, int toIndex) {
+ return items.subList(fromIndex, toIndex);
+ }
+
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/script/EvaluationException.java b/tools/commons/src/main/java/com/ekingstar/commons/script/EvaluationException.java
new file mode 100644
index 0000000..d572948
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/script/EvaluationException.java
@@ -0,0 +1,53 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.script;
+
+/**
+ * <p>
+ * EvaluationException class.
+ * </p>
+ *
+ * @author chaostone
+ * @version $Id: EvaluationException.java Mar 5, 2012 12:13:41 AM chaostone $
+ */
+public class EvaluationException extends RuntimeException {
+
+ private static final long serialVersionUID = 7366966661039007890L;
+
+ /**
+ * <p>
+ * Constructor for EvaluationException.
+ * </p>
+ *
+ * @param cause a {@link java.lang.Throwable} object.
+ */
+ public EvaluationException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructs the exception using a message and cause.
+ *
+ * @param message the message to use
+ * @param cause the underlying cause
+ */
+ public EvaluationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/tools/commons/src/main/java/com/ekingstar/commons/script/ExpressionEvaluator.java b/tools/commons/src/main/java/com/ekingstar/commons/script/ExpressionEvaluator.java
new file mode 100644
index 0000000..a3b3782
--- /dev/null
+++ b/tools/commons/src/main/java/com/ekingstar/commons/script/ExpressionEvaluator.java
@@ -0,0 +1,60 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.script;
+
+
+
+/**
+ * 表达式执行器
+ *
+ * @author chaostone
+ * @version $Id: ExpressionEvaluator.java Mar 5, 2012 12:13:41 AM chaostone $
+ * @since 2012-03-05
+ */
+public interface ExpressionEvaluator {
+ /**
+ * Parse the expression
+ * @param exp
+ * @throws EvaluationException
+ */
+ void parse(String exp) throws EvaluationException;
+ /**
+ * <p>
+ * Eval a expression within context
+ * </p>
+ *
+ * @param exp a java's expression
+ * @param root params.
+ * @return evaluate result
+ */
+ Object eval(String exp, Object root);
+
+ /**
+ * <p>
+ * Eval a expression within context,Return the given type
+ * </p>
+ *
+ * @param exp a java's expression
+ * @param root params.
+ * @param resultType What type of the result
+ * @return evaluate result
+ */
+ <T> T eval(String exp, Object root, Class<T> resultType);
+
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/bean/PropertyUtilsTest.java b/tools/commons/src/test/java/com/ekingstar/commons/bean/PropertyUtilsTest.java
new file mode 100644
index 0000000..918b16c
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/bean/PropertyUtilsTest.java
@@ -0,0 +1,52 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.ekingstar.commons.bean.PropertyUtils;
+import com.ekingstar.commons.lang.Assert;
+import com.ekingstar.commons.lang.testbean.TestBean;
+
+@Test
+public class PropertyUtilsTest {
+
+ public void testSet() {
+ TestBean bean = new TestBean();
+ PropertyUtils.setProperty(bean, "intValue", 2);
+ assertEquals(bean.getIntValue(), 2);
+
+ PropertyUtils.setProperty(bean, "nested.datas(key)", "value");
+ assertEquals(PropertyUtils.getProperty(bean, "nested.datas(key)"), "value");
+
+ PropertyUtils.setProperty(bean, "nested.id", 4L);
+ assertEquals(PropertyUtils.getProperty(bean, "nested.id"), 4L);
+ }
+
+ public static void main(String[] args) {
+ TestBean bean = new TestBean();
+ PropertyUtils.setProperty(bean, "nested.datas(key)", "value");
+ Assert.isTrue("value".equals(PropertyUtils.getProperty(bean, "nested.datas(key)")));
+
+ PropertyUtils.setProperty(bean, "nested.id", 4L);
+ Assert.isTrue(PropertyUtils.getProperty(bean, "nested.id").equals(4L));
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/bean/comparators/PropertyComparatorTest.java b/tools/commons/src/test/java/com/ekingstar/commons/bean/comparators/PropertyComparatorTest.java
new file mode 100755
index 0000000..d7bacf9
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/bean/comparators/PropertyComparatorTest.java
@@ -0,0 +1,32 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.bean.comparators;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+@Test
+public class PropertyComparatorTest {
+
+ public void testSingleProperty() {
+ Logger logger = LoggerFactory.getLogger(PropertyComparatorTest.class);
+ logger.info("dd");
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/collection/MapConverterTest.java b/tools/commons/src/test/java/com/ekingstar/commons/collection/MapConverterTest.java
new file mode 100755
index 0000000..a554e83
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/collection/MapConverterTest.java
@@ -0,0 +1,93 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.collection;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import java.sql.Date;
+import java.util.Calendar;
+import java.util.Map;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.ekingstar.commons.collection.CollectUtils;
+import com.ekingstar.commons.collection.MapConverter;
+
+@Test
+public class MapConverterTest {
+
+ Map<String, Object> datas = CollectUtils.newHashMap();
+ MapConverter converter = new MapConverter();
+
+ @BeforeClass
+ public void setUp() {
+ datas.put("empty1", "");
+ datas.put("empty2", null);
+ datas.put("empty3", new String[] { "" });
+ }
+
+ public void testGetDate() {
+ int year = 2010;
+ int month = 9;
+ int day = 1;
+ datas.put("birthday", year + "-" + month + "-" + day);
+
+ Date birthday = converter.get(datas, "birthday", Date.class);
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(birthday);
+ assertEquals(calendar.get(Calendar.YEAR), year);
+ assertEquals(calendar.get(Calendar.MONTH), month - 1);
+ assertEquals(calendar.get(Calendar.DAY_OF_MONTH), day);
+
+ datas.put("birthday", new Date[] { birthday });
+ Date birthday2 = converter.get(datas, "birthday", Date.class);
+ assertEquals(birthday, birthday2);
+ }
+
+ public void testGetArray() {
+ datas.put("name", new String[] { "me" });
+ Object name = converter.get(datas, "name");
+ assertNotNull(name);
+ assertEquals(name, "me");
+
+ }
+
+ public void testGetNull() {
+ boolean empty1 = converter.getBool(datas, "empty1");
+ assertFalse(empty1);
+ empty1 = converter.getBool(datas, "empty2");
+ assertFalse(empty1);
+ Boolean emptyB1 = converter.getBoolean(datas, "empty1");
+ assertNull(emptyB1);
+ emptyB1 = converter.getBoolean(datas, "empty2");
+ assertNull(emptyB1);
+
+ Long id = converter.getLong(datas, "empty1");
+ assertNull(id);
+ id = converter.getLong(datas, "empty2");
+ assertNull(id);
+
+ id = converter.getLong(datas, "empty3");
+ assertNull(id);
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/collection/OrderTest.java b/tools/commons/src/test/java/com/ekingstar/commons/collection/OrderTest.java
new file mode 100755
index 0000000..b6d07ae
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/collection/OrderTest.java
@@ -0,0 +1,84 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.collection;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+import com.ekingstar.commons.collection.CollectUtils;
+import com.ekingstar.commons.collection.Order;
+
+public class OrderTest {
+ @Test
+ public void testToString1() throws Exception {
+ List<Order> sorts = Order.parse(null);
+ if (sorts.isEmpty()) {
+ sorts.add(new Order(" teachPlan.grade desc "));
+ sorts.add(new Order(" teachPlan.major.code "));
+ // sorts.add(new Order("teachPlan.stdType"));
+ }
+ assertEquals(Order.toSortString(sorts), "order by teachPlan.grade desc,teachPlan.major.code");
+ }
+
+ @Test
+ public void testToString() throws Exception {
+ List<Order> sorts = CollectUtils.newArrayList();
+ sorts.add(new Order("id", false));
+ sorts.add(Order.asc("name"));
+ assertEquals(Order.toSortString(sorts), "order by id desc,name");
+ }
+
+ public void testParserOrder() throws Exception {
+ List<Order> orders = Order.parse("std.code asc");
+ for (final Order order : orders) {
+ assertTrue(order.isAscending());
+ assertEquals(order.getProperty(), "std.code");
+ }
+ }
+
+ @Test
+ public void testParserMutiOrder() throws Exception {
+ List<Order> sorts = Order
+ .parse("activity.time.year desc,activity.time.validWeeksNum,activity.time.weekId desc");
+ assertEquals(sorts.size(), 3);
+ Order order = (Order) sorts.get(0);
+ assertEquals(order.getProperty(), "activity.time.year");
+ assertFalse(order.isAscending());
+ order = (Order) sorts.get(1);
+ assertEquals(order.getProperty(), "activity.time.validWeeksNum");
+ assertTrue(order.isAscending());
+ order = (Order) sorts.get(2);
+ assertEquals(order.getProperty(), "activity.time.weekId");
+ assertFalse(order.isAscending());
+ }
+
+ @Test
+ public void testParserComplexOrder() {
+ List<Order> sorts = Order.parse("(case when ware.price is null then 0 else ware.price end) desc");
+ assertEquals(sorts.size(), 1);
+ Order order = (Order) sorts.get(0);
+ assertEquals(order.getProperty(), "(case when ware.price is null then 0 else ware.price end)");
+ assertFalse(order.isAscending());
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/conversion/ConversionTest.java b/tools/commons/src/test/java/com/ekingstar/commons/conversion/ConversionTest.java
new file mode 100644
index 0000000..3adef6f
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/conversion/ConversionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ekingstar.commons.conversion.impl.DefaultConversion;
+
+@Test
+public class ConversionTest {
+
+ public void testConvert() {
+ DefaultConversion con = new DefaultConversion();
+ Assert.assertEquals(con.convert(2.5f, Integer.class), new Integer(2));
+ Assert.assertEquals(con.convert("", Boolean.class),null);
+ Assert.assertEquals((boolean)con.convert(null, boolean.class),false);
+ }
+
+ public void testConvertArray() {
+ DefaultConversion con = new DefaultConversion();
+ Assert.assertEquals(con.convert(new String[] { "2", "3" }, Integer[].class), new Integer[] { 2, 3 });
+ }
+
+ public void testConvertPrimitive() {
+ DefaultConversion con = new DefaultConversion();
+ Assert.assertEquals((int) con.convert("2", int.class), 2);
+
+ Assert.assertEquals(con.convert(3, Integer.class), new Integer(3));
+ }
+
+ public void testConvertPrimitiveArray() {
+ DefaultConversion con = new DefaultConversion();
+ Assert.assertEquals((float[]) con.convert(new String[] { "2", "3.4" }, float[].class), new float[] { 2f,
+ 3.4f });
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/conversion/converter/DateConverterTest.java b/tools/commons/src/test/java/com/ekingstar/commons/conversion/converter/DateConverterTest.java
new file mode 100755
index 0000000..c492d6b
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/conversion/converter/DateConverterTest.java
@@ -0,0 +1,57 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.converter;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import org.testng.annotations.Test;
+
+import com.ekingstar.commons.conversion.Converter;
+import com.ekingstar.commons.conversion.converter.String2DateConverter;
+
+public class DateConverterTest {
+ @Test
+ public void testConvertoDate() throws Exception {
+ String date1 = "19800909";
+ converToDate(date1, 1980, 8, 9);
+ date1 = "1980-09-09";
+ converToDate(date1, 1980, 8, 9);
+ }
+
+ private void converToDate(String dateStr, int year, int month, int day) {
+ Converter<String, Date> c = new String2DateConverter().getConverter(Date.class);
+ Date date = c.apply(dateStr);
+ Calendar calendar = new GregorianCalendar();
+ calendar.setTime(date);
+ assertEquals(calendar.get(Calendar.YEAR), year);
+ assertEquals(calendar.get(Calendar.MONTH), month);
+ assertEquals(calendar.get(Calendar.DAY_OF_MONTH), day);
+ }
+
+ public void testNormalize() {
+ assertEquals("1980-09-01", String2DateConverter.normalize("1980-9-1"));
+ assertEquals("1980-09-01", String2DateConverter.normalize("1980-09-1"));
+ assertEquals("1980-09-01", String2DateConverter.normalize("1980-9-01"));
+ assertEquals("1980-09-01", String2DateConverter.normalize("1980-09-01"));
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/conversion/converter/DefaultConverterTest.java b/tools/commons/src/test/java/com/ekingstar/commons/conversion/converter/DefaultConverterTest.java
new file mode 100644
index 0000000..aa2980e
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/conversion/converter/DefaultConverterTest.java
@@ -0,0 +1,38 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.converter;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ekingstar.commons.conversion.Conversion;
+import com.ekingstar.commons.conversion.impl.DefaultConversion;
+
+@Test
+public class DefaultConverterTest {
+
+ public void testConvertNull() {
+ Conversion conversion = DefaultConversion.Instance;
+ Assert.assertNull(conversion.convert("", Long.class));
+ Assert.assertNull(conversion.convert((String) null, Long.class));
+ Assert.assertNull(conversion.convert("abc", Long.class));
+ Assert.assertEquals((Object) conversion.convert("1", Long.class), (Object) 1L);
+ Assert.assertEquals((Object) conversion.convert(1L, Long.class), (Object) 1L);
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/conversion/converter/EnumConverterTest.java b/tools/commons/src/test/java/com/ekingstar/commons/conversion/converter/EnumConverterTest.java
new file mode 100644
index 0000000..c8df788
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/conversion/converter/EnumConverterTest.java
@@ -0,0 +1,39 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.converter;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ekingstar.commons.conversion.impl.DefaultConversion;
+import com.ekingstar.commons.lang.testbean.TestEnum;
+
+/**
+ * @author chaostone
+ * @since 3.0.0
+ */
+@Test
+public class EnumConverterTest {
+
+ public void testConvertEnum() throws IllegalAccessException, InvocationTargetException {
+ Assert.assertEquals(DefaultConversion.Instance.convert("Private", TestEnum.class), TestEnum.Private);
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/conversion/converter/Object2StringConverterTest.java b/tools/commons/src/test/java/com/ekingstar/commons/conversion/converter/Object2StringConverterTest.java
new file mode 100644
index 0000000..891b762
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/conversion/converter/Object2StringConverterTest.java
@@ -0,0 +1,42 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.conversion.converter;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import org.testng.annotations.Test;
+
+import com.ekingstar.commons.conversion.converter.Object2StringConverter;
+
+/**
+ * @author chaostone
+ * @since 3.3.7
+ */
+@Test
+public class Object2StringConverterTest {
+
+ public void testConvert() {
+ Object2StringConverter converter = new Object2StringConverter();
+ assertNull(converter.apply(null), null);
+ assertEquals(converter.apply("abc"), "abc");
+ assertEquals(converter.apply(new Object[] { 1, 3, "abc" }), "1,3,abc");
+ assertEquals(converter.apply(new Object[] { 1, }), "1");
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/lang/BitStringsTest.java b/tools/commons/src/test/java/com/ekingstar/commons/lang/BitStringsTest.java
new file mode 100755
index 0000000..aff268e
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/lang/BitStringsTest.java
@@ -0,0 +1,35 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.ekingstar.commons.lang.BitStrings;
+
+public class BitStringsTest {
+
+ @Test
+ public void binValueOf() {
+ assertEquals(BitStrings.binValueOf("00000000000000000000000000000000011111111111111111111"), 1048575);
+
+ assertEquals(BitStrings.binValueOf("00000000000000000000000000000000000011100000000000000"), 114688);
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/lang/CalendarTest.java b/tools/commons/src/test/java/com/ekingstar/commons/lang/CalendarTest.java
new file mode 100644
index 0000000..4d5ff6f
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/lang/CalendarTest.java
@@ -0,0 +1,42 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import org.testng.annotations.Test;
+
+import com.ekingstar.commons.lang.Dates;
+
+/**
+ * @author chaostone
+ * @version $Id: CalendarTest.java Jul 26, 2011 4:12:17 PM chaostone $
+ */
+@Test
+public class CalendarTest {
+
+ public void testRoll() {
+ Calendar calendar = Calendar.getInstance();
+ Date ajusted = Dates.rollMinutes(calendar.getTime(), -30);
+ assertTrue(ajusted.before(calendar.getTime()));
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/lang/MapTest.java b/tools/commons/src/test/java/com/ekingstar/commons/lang/MapTest.java
new file mode 100644
index 0000000..dcc02c6
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/lang/MapTest.java
@@ -0,0 +1,41 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+import com.ekingstar.commons.collection.CollectUtils;
+
+@Test
+public class MapTest {
+
+ /**
+ * test map's key set
+ */
+ public void testRemove() {
+ Map<String, String> favorates = CollectUtils.newHashMap();
+ favorates.put("john", "sports,music");
+ favorates.put("mack", "food");
+ favorates.keySet().remove("john");
+ org.testng.Assert.assertTrue(favorates.size() == 1);
+ }
+
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/lang/ObjectsTest.java b/tools/commons/src/test/java/com/ekingstar/commons/lang/ObjectsTest.java
new file mode 100755
index 0000000..3ca0bde
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/lang/ObjectsTest.java
@@ -0,0 +1,33 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.Test;
+
+import com.ekingstar.commons.lang.Objects;
+
+@Test
+public class ObjectsTest {
+
+ public void testNullEquals() {
+ assertTrue(Objects.equals(null, null));
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/lang/StringsTest.java b/tools/commons/src/test/java/com/ekingstar/commons/lang/StringsTest.java
new file mode 100755
index 0000000..6e9a1ea
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/lang/StringsTest.java
@@ -0,0 +1,107 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang;
+
+import static com.ekingstar.commons.lang.Strings.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.Test;
+
+@Test
+public class StringsTest {
+
+ public void testCount() {
+ String targetStr = "11001101101111";
+ String searchStr = "11";
+ assertEquals(count(targetStr, searchStr), 5);
+ }
+
+ public void testUnCamel() {
+ assertEquals(unCamel("MyCountInI_cbc", '-'), "my-count-ini_cbc");
+ assertEquals(unCamel("MyCounT", '_'), "my_count");
+ assertEquals(unCamel("MYCOUNT", '-'), "mycount");
+ assertEquals(unCamel("parent_id", '_'), "parent_id");
+ assertEquals(unCamel("parentId", '_'), "parent_id");
+ }
+
+ public void testSplit2() {
+ String target = " abc ,; def ,;; ghi\r\n opq";
+ String[] codes = split(target);
+ assertEquals(codes.length, 4);
+ assertEquals(codes[3], "opq");
+ }
+
+ public void testIsEqualSeq() {
+ String first = "123,4546,";
+ String second = ",4546,123";
+ assertTrue(isEqualSeq(first, second));
+ assertTrue(isEqualSeq(first, second, ","));
+ }
+
+ public void testMergeSeq() {
+ String first = ",1,2,";
+ String second = "3,";
+ String third = "";
+ String forth = null;
+ assertTrue(isEqualSeq(mergeSeq(first, second), ",1,2,3,"));
+ assertTrue(isEqualSeq(mergeSeq(first, second), ",1,2,3,"));
+ assertTrue(isEqualSeq(mergeSeq(first, third), ",1,2,"));
+ assertTrue(isEqualSeq(mergeSeq(first, forth), ",1,2,"));
+ }
+
+ public void testSplitNumSeq() throws Exception {
+ String a = "1-2,3,5-9,3,";
+ Integer[] nums = splitNumSeq(a);
+ assertEquals(nums.length, 8);
+ }
+
+ public void testMisc() {
+ assertEquals(",2,", subtractSeq("1,2", "1"));
+ assertFalse(isEqualSeq(",2005-9,", ",2005-9,2006-9,"));
+ }
+
+ public void testRepeat() {
+ assertEquals("", repeat("ad", 0));
+ assertEquals("adadad", repeat("ad", 3));
+ }
+
+ public void testSplit() {
+ assertEquals(new String[] { "a", "b", "c" }, split("a.b.c.", '.'));
+ assertEquals(new String[] { "a", "b", "c" }, split(".a..b.c", '.'));
+ assertEquals(new String[] { "a:b:c" }, split("a:b:c", '.'));
+ assertEquals(new String[] {}, split("", (String)null));
+ assertEquals(new String[] { "abc", "def" }, split("abc def", (String)null));
+ assertEquals(new String[] { "abc", "def" }, split("abc def", " "));
+ assertEquals(new String[] { "ab", "cd", "ef" }, split("ab:cd:ef", ":"));
+ }
+
+ public void testReplace() {
+ assertEquals(replace(null, "x", null), null);
+ assertEquals(replace("", "dd", "xx"), "");
+ assertEquals(replace("any", null, "xx"), "any");
+ assertEquals(replace("any", "d", null), "any");
+ assertEquals(replace("any", "", "dd"), "any");
+ assertEquals(replace("aba", "a", null), "aba");
+ assertEquals(replace("aba", "a", ""), "b");
+ assertEquals(replace("aba", "a", "z"), "zbz");
+
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/lang/reflect/BridgeMethodTest.java b/tools/commons/src/test/java/com/ekingstar/commons/lang/reflect/BridgeMethodTest.java
new file mode 100644
index 0000000..8a81c5e
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/lang/reflect/BridgeMethodTest.java
@@ -0,0 +1,52 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.reflect;
+
+import java.lang.reflect.Method;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+@Test
+public class BridgeMethodTest {
+
+ public void testBridgeMethods() {
+
+ for (Method m : Dog.class.getMethods()) {
+ if (m.getName().equals("getAge") && null == m.getReturnType()) {
+ if (m.getReturnType().equals(Integer.class)) Assert.assertFalse(m.isBridge());
+
+ else if (m.getReturnType().equals(Number.class)) {
+ Assert.assertTrue(m.isBridge());
+ Assert.assertEquals(m.getDeclaringClass(), Dog.class);
+ }
+ }
+ }
+ }
+}
+
+interface Animal {
+ Number getAge();
+}
+
+class Dog implements Animal {
+ public Integer getAge() {
+ return 0;
+ }
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/lang/testbean/NestedBean.java b/tools/commons/src/test/java/com/ekingstar/commons/lang/testbean/NestedBean.java
new file mode 100644
index 0000000..8bde946
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/lang/testbean/NestedBean.java
@@ -0,0 +1,48 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.testbean;
+
+import java.util.Map;
+
+import com.ekingstar.commons.collection.CollectUtils;
+
+public class NestedBean {
+
+ Long id;
+
+ Map<Object,Object> datas=CollectUtils.newHashMap();
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Map<Object, Object> getDatas() {
+ return datas;
+ }
+
+ public void setDatas(Map<Object, Object> datas) {
+ this.datas = datas;
+ }
+
+
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/lang/testbean/TestBean.java b/tools/commons/src/test/java/com/ekingstar/commons/lang/testbean/TestBean.java
new file mode 100644
index 0000000..3deb866
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/lang/testbean/TestBean.java
@@ -0,0 +1,74 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.testbean;
+
+public class TestBean {
+ private Integer id;
+ private String name;
+ private int intValue;
+ TestEnum testEnum;
+
+ private NestedBean nested= new NestedBean();
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public TestEnum getTestEnum() {
+ return testEnum;
+ }
+
+ public void setTestEnum(TestEnum testEnum) {
+ this.testEnum = testEnum;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getIntValue() {
+ return intValue;
+ }
+
+ public void setIntValue(int intValue) {
+ this.intValue = intValue;
+ }
+
+ public String methodWithManyArguments(int i, float f, Integer I, Float F, TestBean c, TestBean c1,
+ TestBean c2) {
+ return "test";
+ }
+
+ public NestedBean getNested() {
+ return nested;
+ }
+
+ public void setNested(NestedBean nested) {
+ this.nested = nested;
+ }
+
+}
diff --git a/tools/commons/src/test/java/com/ekingstar/commons/lang/testbean/TestEnum.java b/tools/commons/src/test/java/com/ekingstar/commons/lang/testbean/TestEnum.java
new file mode 100644
index 0000000..f71122f
--- /dev/null
+++ b/tools/commons/src/test/java/com/ekingstar/commons/lang/testbean/TestEnum.java
@@ -0,0 +1,24 @@
+/*
+ * Beangle, Agile Java/Scala Development Scaffold and Toolkit
+ *
+ * Copyright (c) 2005-2013, Beangle Software.
+ *
+ * Beangle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Beangle is distributed in the hope that it will be useful.
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Beangle. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.ekingstar.commons.lang.testbean;
+
+public enum TestEnum {
+
+ Public, Protected, Private;
+}