diff --git a/modules/utils/src/main/java/org/springside/modules/utils/base/Platforms.java b/modules/utils/src/main/java/org/springside/modules/utils/base/Platforms.java index 7a5b07009..97636b608 100644 --- a/modules/utils/src/main/java/org/springside/modules/utils/base/Platforms.java +++ b/modules/utils/src/main/java/org/springside/modules/utils/base/Platforms.java @@ -17,6 +17,8 @@ public abstract class Platforms { // 文件路径分隔符 public static final String FILE_PATH_SEPARATOR = File.separator; public static final char FILE_PATH_SEPARATOR_CHAR = File.separatorChar; + public static final char WINDOWS_FILE_PATH_SEPARATOR_CHAR='\\'; + public static final char LINUX_FILE_PATH_SEPARATOR_CHAR='/'; // ClassPath分隔符 public static final String CLASS_PATH_SEPARATOR = File.pathSeparator; diff --git a/modules/utils/src/main/java/org/springside/modules/utils/collection/MapUtil.java b/modules/utils/src/main/java/org/springside/modules/utils/collection/MapUtil.java index f6b446bc0..37b0dba02 100644 --- a/modules/utils/src/main/java/org/springside/modules/utils/collection/MapUtil.java +++ b/modules/utils/src/main/java/org/springside/modules/utils/collection/MapUtil.java @@ -71,7 +71,8 @@ public static boolean isNotEmpty(final Map map) { * * @see org.apache.commons.lang3.concurrent.ConcurrentUtils#putIfAbsent(ConcurrentMap, Object, Object) */ - public static V putIfAbsentWithFinalValue(final ConcurrentMap map, final K key, final V value) { + public static V putIfAbsentWithFinalValue(@NotNull final ConcurrentMap map, final K key, + final V value) { final V result = map.putIfAbsent(key, value); return result != null ? result : value; } @@ -84,12 +85,8 @@ public static V putIfAbsentWithFinalValue(final ConcurrentMap map, * @see org.apache.commons.lang3.concurrent.ConcurrentUtils#createIfAbsent(ConcurrentMap, Object, * org.apache.commons.lang3.concurrent.ConcurrentInitializer) */ - public static V createIfAbsent(final ConcurrentMap map, final K key, - final ValueCreator creator) { - if (map == null || creator == null) { - return null; - } - + public static V createIfAbsent(@NotNull final ConcurrentMap map, final K key, + @NotNull final ValueCreator creator) { final V value = map.get(key); if (value == null) { return putIfAbsentWithFinalValue(map, key, creator.get()); @@ -100,8 +97,6 @@ public static V createIfAbsent(final ConcurrentMap map, final K key /** * 创建Value值的回调函数 * - * from Common Lang - * * @see MapUtil#createIfAbsent(ConcurrentMap, Object, ValueCreator) */ public interface ValueCreator { @@ -212,7 +207,7 @@ public static TreeMap newSortedMap(@Nullable Comparato /** * 相比HashMap,当key是枚举类时, 性能与空间占用俱佳. */ - public static , V> EnumMap newEnumMap(Class type) { + public static , V> EnumMap newEnumMap(@NotNull Class type) { return new EnumMap(Preconditions.checkNotNull(type)); } diff --git a/modules/utils/src/main/java/org/springside/modules/utils/io/FilePathUtil.java b/modules/utils/src/main/java/org/springside/modules/utils/io/FilePathUtil.java index d9b48d1d7..747fc1c48 100644 --- a/modules/utils/src/main/java/org/springside/modules/utils/io/FilePathUtil.java +++ b/modules/utils/src/main/java/org/springside/modules/utils/io/FilePathUtil.java @@ -1,49 +1,36 @@ package org.springside.modules.utils.io; -import java.io.File; - -import org.apache.commons.lang3.Validate; +import org.apache.commons.lang3.StringUtils; import org.springside.modules.utils.base.Platforms; -import org.springside.modules.utils.base.annotation.NotNull; import org.springside.modules.utils.text.MoreStringUtil; import com.google.common.io.Files; /** - * 关于文件名,文件路径的工具集 + * 关于文件路径的工具集 * * @author calvin */ public abstract class FilePathUtil { /** - * 获取文件名(不包含路径) - */ - public static String getFileName(@NotNull String fullName) { - Validate.notEmpty(fullName); - int last = fullName.lastIndexOf(Platforms.FILE_PATH_SEPARATOR_CHAR); - return fullName.substring(last + 1); - } - - /** - * 获取文件名的扩展名部分(不包含.) + * 在Windows环境里,兼容Windows上的路径分割符,将 '/' 转回 '\' */ - public static String getFileExtension(File file) { - return Files.getFileExtension(file.getName()); - } + public static String normalizePath(String path) { + if (Platforms.FILE_PATH_SEPARATOR_CHAR == Platforms.WINDOWS_FILE_PATH_SEPARATOR_CHAR + && StringUtils.indexOf(path, Platforms.LINUX_FILE_PATH_SEPARATOR_CHAR) != -1) { + return StringUtils.replaceChars(path, Platforms.LINUX_FILE_PATH_SEPARATOR_CHAR, + Platforms.WINDOWS_FILE_PATH_SEPARATOR_CHAR); + } + return path; - /** - * 获取文件名的扩展名部分(不包含.) - */ - public static String getFileExtension(String fullName) { - return Files.getFileExtension(fullName); } /** * 将路径整理,如 "a/../b",整理成 "b" */ - public static String simplifyPath(String pathName) { - return Files.simplifyPath(pathName); + public static String simplifyPath(String path) { + return Files.simplifyPath(path); } /** @@ -76,4 +63,5 @@ public static String contact(String baseName, String... appendName) { public static String getJarPath(Class clazz) { return clazz.getProtectionDomain().getCodeSource().getLocation().getFile(); } + } diff --git a/modules/utils/src/main/java/org/springside/modules/utils/io/FileTreeWalker.java b/modules/utils/src/main/java/org/springside/modules/utils/io/FileTreeWalker.java new file mode 100644 index 000000000..b44ae5ab3 --- /dev/null +++ b/modules/utils/src/main/java/org/springside/modules/utils/io/FileTreeWalker.java @@ -0,0 +1,145 @@ +package org.springside.modules.utils.io; + +import java.io.File; +import java.util.List; +import java.util.regex.Pattern; + +import org.springside.modules.utils.text.WildcardMatcher; + +import com.google.common.base.Predicate; +import com.google.common.collect.TreeTraverser; +import com.google.common.io.Files; + +public class FileTreeWalker { + + /** + * 前序递归列出所有文件, 包含文件与目录,及根目录本身. + * + * 前序即先列出父目录,在列出子目录. 如要后序遍历, 直接使用Files.fileTreeTraverser() + */ + public static List listAll(File rootDir) { + return Files.fileTreeTraverser().preOrderTraversal(rootDir).toList(); + } + + /** + * 前序递归列出所有文件, 只包含文件. + */ + public static List listFile(File rootDir) { + return Files.fileTreeTraverser().preOrderTraversal(rootDir).filter(Files.isFile()).toList(); + } + + /** + * 前序递归列出所有文件, 列出后缀名匹配的文件. (后缀名不包含.) + */ + public static List listFileWithExtension(final File rootDir, final String extension) { + return Files.fileTreeTraverser().preOrderTraversal(rootDir).filter(new FileExtensionFilter(extension)).toList(); + } + + /** + * 前序递归列出所有文件, 列出文件名匹配通配符的文件 + * + * 如 ("/a/b/hello.txt", "he*") 将被返回 + */ + public static List listFileWithWildcardFileName(final File rootDir, final String fileNamePattern) { + return Files.fileTreeTraverser().preOrderTraversal(rootDir).filter(new WildcardFileNameFilter(fileNamePattern)) + .toList(); + } + + /** + * 前序递归列出所有文件, 列出文件名匹配正则表达式的文件 + * + * 如 ("/a/b/hello.txt", "he.*\.text") 将被返回 + */ + public static List listFileWithRegexFileName(final File rootDir, final String regexFileNamePattern) { + return Files.fileTreeTraverser().preOrderTraversal(rootDir) + .filter(new RegexFileNameFilter(regexFileNamePattern)).toList(); + } + + /** + * 前序递归列出所有文件, 列出符合ant path风格表达式的文件 + * + * 如 ("/a/b/hello.txt", "he.*\.text") 将被返回 + */ + public static List listFileWithAntPath(final File rootDir, final String antPathPattern) { + return Files.fileTreeTraverser().preOrderTraversal(rootDir).filter(new AntPathFilter(antPathPattern)).toList(); + } + + /** + * 直接使用Guava的TreeTraverser,获得更大的灵活度, 比如加入各类filter,前序/后序的选择,一边遍历一边操作 + * + *
+	 * FileUtil.fileTreeTraverser().preOrderTraversal(root).iterator();
+	 * 
+ */ + public static TreeTraverser fileTreeTraverser() { + return Files.fileTreeTraverser(); + } + + /** + * 以文件名正则表达式为filter,配合fileTreeTraverser使用 + */ + public static final class RegexFileNameFilter implements Predicate { + private final Pattern pattern; + + private RegexFileNameFilter(String pattern) { + this.pattern = Pattern.compile(pattern); + } + + @Override + public boolean apply(File input) { + return input.isFile() && pattern.matcher(input.getName()).matches(); + } + } + + /** + * 以文件名通配符为filter,配合fileTreeTraverser使用. + * + * @param pattern 支持*与?的通配符,如hello*.txt 匹配 helloworld.txt + */ + public static final class WildcardFileNameFilter implements Predicate { + private final String pattern; + + private WildcardFileNameFilter(String pattern) { + this.pattern = pattern; + } + + @Override + public boolean apply(File input) { + return input.isFile() && WildcardMatcher.match(input.getName(), pattern); + } + } + + /** + * 以文件名后缀做filter,配合fileTreeTraverser使用 + */ + public static final class FileExtensionFilter implements Predicate { + private final String extension; + + private FileExtensionFilter(String extension) { + this.extension = extension; + } + + @Override + public boolean apply(File input) { + return input.isFile() && extension.equals(FileUtil.getFileExtension(input)); + } + } + + /** + * 以ant风格的path为filter,配合fileTreeTraverser使用. + * + * @param pattern 支持ant风格的通配符,如/var/?/a?.txt 匹配 /var/b/ab.txt, 其他通配符包括**,* + */ + public static final class AntPathFilter implements Predicate { + private final String pattern; + + private AntPathFilter(String pattern) { + this.pattern = pattern; + } + + @Override + public boolean apply(File input) { + return input.isFile() && WildcardMatcher.matchPath(input.getName(), pattern); + } + } +} diff --git a/modules/utils/src/main/java/org/springside/modules/utils/io/FileUtil.java b/modules/utils/src/main/java/org/springside/modules/utils/io/FileUtil.java index 46ca05cd9..b3ed7ab6f 100644 --- a/modules/utils/src/main/java/org/springside/modules/utils/io/FileUtil.java +++ b/modules/utils/src/main/java/org/springside/modules/utils/io/FileUtil.java @@ -14,12 +14,11 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; +import org.springside.modules.utils.base.Platforms; import org.springside.modules.utils.base.annotation.NotNull; import org.springside.modules.utils.base.annotation.Nullable; import org.springside.modules.utils.text.Charsets; -import com.google.common.base.Predicate; -import com.google.common.collect.TreeTraverser; import com.google.common.io.Files; /** @@ -223,40 +222,6 @@ public static void deleteDir(File dir) { } } - /** - * 前序递归列出所有文件, 包含文件与目录,及根目录本身. - * - * 前序即先列出父目录,在列出子目录. 如要后序遍历, 直接使用Files.fileTreeTraverser() - */ - public static List listAll(File rootDir) { - return Files.fileTreeTraverser().preOrderTraversal(rootDir).toList(); - } - - /** - * 前序递归列出所有文件, 只包含文件. - */ - public static List listFile(File rootDir) { - return Files.fileTreeTraverser().preOrderTraversal(rootDir).filter(Files.isFile()).toList(); - } - - /** - * 前序递归列出所有文件, 只包含后缀名匹配的文件. (后缀名不包含.) - */ - public static List listFileWithExtension(final File rootDir, final String extension) { - return Files.fileTreeTraverser().preOrderTraversal(rootDir).filter(new FileExtensionFilter(extension)).toList(); - } - - /** - * 直接使用Guava的TreeTraverser,获得更大的灵活度, 比如加入各类filter,前序/后序的选择,一边遍历一边操作 - * - *
-	 * FileUtil.fileTreeTraverser().preOrderTraversal(root).iterator();
-	 * 
- */ - public static TreeTraverser fileTreeTraverser() { - return Files.fileTreeTraverser(); - } - /** * 判断目录是否存在, from Jodd */ @@ -349,18 +314,26 @@ private static File getFileByPath(String filePath) { } /** - * 以文件名后缀做filter,配合fileTreeTraverser使用 + * 获取文件名(不包含路径) */ - public static final class FileExtensionFilter implements Predicate { - private final String extension; + public static String getFileName(@NotNull String fullName) { + Validate.notEmpty(fullName); + int last = fullName.lastIndexOf(Platforms.FILE_PATH_SEPARATOR_CHAR); + return fullName.substring(last + 1); + } - private FileExtensionFilter(String extension) { - this.extension = extension; - } + /** + * 获取文件名的扩展名部分(不包含.) + */ + public static String getFileExtension(File file) { + return Files.getFileExtension(file.getName()); + } - @Override - public boolean apply(File input) { - return input.isFile() && extension.equals(FilePathUtil.getFileExtension(input)); - } + /** + * 获取文件名的扩展名部分(不包含.) + */ + public static String getFileExtension(String fullName) { + return Files.getFileExtension(fullName); } + } diff --git a/modules/utils/src/main/java/org/springside/modules/utils/io/ResourceUtil.java b/modules/utils/src/main/java/org/springside/modules/utils/io/ResourceUtil.java index 1e6e6cbf3..011cce976 100644 --- a/modules/utils/src/main/java/org/springside/modules/utils/io/ResourceUtil.java +++ b/modules/utils/src/main/java/org/springside/modules/utils/io/ResourceUtil.java @@ -28,9 +28,10 @@ * * 所以resourceName无需以"/"打头即表示jar file中的根目录,带了"/" 反而导致JarFile.getEntry(resouceName)时没有返回. * - * 指定contextClass时,class.getResource()会先对name进行处理再交给classLoader,打头的"/"的会被去除,不以"/"打头则表示与该contextClass package的相对路径, 会先转为绝对路径. + * 指定contextClass时,class.getResource()会先对name进行处理再交给classLoader,打头的"/"的会被去除,不以"/"打头则表示与该contextClass package的相对路径, + * 会先转为绝对路径. * - * 3.同名资源 + * 3.同名资源 * * 如果有多个同名资源,除非调用getResources()获取全部资源,否则在URLClassLoader中按ClassPath顺序打开第一个命中的Jar文件. */ diff --git a/modules/utils/src/main/java/org/springside/modules/utils/text/WildcardMatcher.java b/modules/utils/src/main/java/org/springside/modules/utils/text/WildcardMatcher.java new file mode 100644 index 000000000..2f92c63b3 --- /dev/null +++ b/modules/utils/src/main/java/org/springside/modules/utils/text/WildcardMatcher.java @@ -0,0 +1,268 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package org.springside.modules.utils.text; + +import org.apache.commons.lang3.StringUtils; +import org.springside.modules.utils.base.Platforms; + +/** + * Checks whether a string or path matches a given wildcard pattern. Possible patterns allow to match single characters + * ('?') or any count of characters ('*'). Wildcard characters can be escaped (by an '\'). When matching path, deep tree + * wildcard also can be used ('**'). + *

+ * This method uses recursive matching, as in linux or windows. regexp works the same. This method is very fast, + * comparing to similar implementations. + */ +public class WildcardMatcher { + + /** + * Checks whether a string matches a given wildcard pattern. + * + * @param string input string + * @param pattern pattern to match + * @return true if string matches the pattern, otherwise false + */ + public static boolean match(CharSequence string, CharSequence pattern) { + return match(string, pattern, 0, 0); + } + + /** + * Internal matching recursive function. + */ + private static boolean match(CharSequence string, CharSequence pattern, int sNdx, int pNdx) { + int pLen = pattern.length(); + if (pLen == 1) { + if (pattern.charAt(0) == '*') { // speed-up + return true; + } + } + int sLen = string.length(); + boolean nextIsNotWildcard = false; + + while (true) { + + // check if end of string and/or pattern occurred + if ((sNdx >= sLen)) { // end of string still may have pending '*' in pattern + while ((pNdx < pLen) && (pattern.charAt(pNdx) == '*')) { + pNdx++; + } + return pNdx >= pLen; + } + if (pNdx >= pLen) { // end of pattern, but not end of the string + return false; + } + char p = pattern.charAt(pNdx); // pattern char + + // perform logic + if (!nextIsNotWildcard) { + + if (p == '\\') { + pNdx++; + nextIsNotWildcard = true; + continue; + } + if (p == '?') { + sNdx++; + pNdx++; + continue; + } + if (p == '*') { + char pNext = 0; // next pattern char + if (pNdx + 1 < pLen) { + pNext = pattern.charAt(pNdx + 1); + } + if (pNext == '*') { // double '*' have the same effect as one '*' + pNdx++; + continue; + } + int i; + pNdx++; + + // find recursively if there is any substring from the end of the + // line that matches the rest of the pattern !!! + for (i = string.length(); i >= sNdx; i--) { + if (match(string, pattern, i, pNdx)) { + return true; + } + } + return false; + } + } else { + nextIsNotWildcard = false; + } + + // check if pattern char and string char are equals + if (p != string.charAt(sNdx)) { + return false; + } + + // everything matches for now, continue + sNdx++; + pNdx++; + } + } + + // ---------------------------------------------------------------- utilities + + /** + * Matches string to at least one pattern. Returns index of matched pattern, or -1 otherwise. + * @see #match(CharSequence, CharSequence) + */ + public static int matchOne(String src, String[] patterns) { + for (int i = 0; i < patterns.length; i++) { + if (match(src, patterns[i])) { + return i; + } + } + return -1; + } + + /** + * Matches path to at least one pattern. Returns index of matched pattern or -1 otherwise. + * @see #matchPath(String, String) + */ + public static int matchPathOne(String path, String[] patterns) { + for (int i = 0; i < patterns.length; i++) { + if (matchPath(path, patterns[i])) { + return i; + } + } + return -1; + } + + // ---------------------------------------------------------------- path + + protected static final String PATH_MATCH = "**"; + protected static final String PATH_SEPARATORS = "/\\"; + + /** + * Matches path against pattern using *, ? and ** wildcards. Both path and the pattern are tokenized on path + * separators (both \ and /). '**' represents deep tree wildcard, as in Ant. + */ + public static boolean matchPath(String path, String pattern) { + String[] pathElements = StringUtils.split(path, Platforms.FILE_PATH_SEPARATOR_CHAR); + String[] patternElements = StringUtils.split(pattern, Platforms.FILE_PATH_SEPARATOR_CHAR); + return matchTokens(pathElements, patternElements); + } + + /** + * Match tokenized string and pattern. + */ + protected static boolean matchTokens(String[] tokens, String[] patterns) { + int patNdxStart = 0; + int patNdxEnd = patterns.length - 1; + int tokNdxStart = 0; + int tokNdxEnd = tokens.length - 1; + + while ((patNdxStart <= patNdxEnd) && (tokNdxStart <= tokNdxEnd)) { // find first ** + String patDir = patterns[patNdxStart]; + if (patDir.equals(PATH_MATCH)) { + break; + } + if (!match(tokens[tokNdxStart], patDir)) { + return false; + } + patNdxStart++; + tokNdxStart++; + } + if (tokNdxStart > tokNdxEnd) { + for (int i = patNdxStart; i <= patNdxEnd; i++) { // string is finished + if (!patterns[i].equals(PATH_MATCH)) { + return false; + } + } + return true; + } + if (patNdxStart > patNdxEnd) { + return false; // string is not finished, but pattern is + } + + while ((patNdxStart <= patNdxEnd) && (tokNdxStart <= tokNdxEnd)) { // to the last ** + String patDir = patterns[patNdxEnd]; + if (patDir.equals(PATH_MATCH)) { + break; + } + if (!match(tokens[tokNdxEnd], patDir)) { + return false; + } + patNdxEnd--; + tokNdxEnd--; + } + if (tokNdxStart > tokNdxEnd) { + for (int i = patNdxStart; i <= patNdxEnd; i++) { // string is finished + if (!patterns[i].equals(PATH_MATCH)) { + return false; + } + } + return true; + } + + while ((patNdxStart != patNdxEnd) && (tokNdxStart <= tokNdxEnd)) { + int patIdxTmp = -1; + for (int i = patNdxStart + 1; i <= patNdxEnd; i++) { + if (patterns[i].equals(PATH_MATCH)) { + patIdxTmp = i; + break; + } + } + if (patIdxTmp == patNdxStart + 1) { + patNdxStart++; // skip **/** situation + continue; + } + // find the pattern between padIdxStart & padIdxTmp in str between strIdxStart & strIdxEnd + int patLength = (patIdxTmp - patNdxStart - 1); + int strLength = (tokNdxEnd - tokNdxStart + 1); + int ndx = -1; + strLoop: for (int i = 0; i <= strLength - patLength; i++) { + for (int j = 0; j < patLength; j++) { + String subPat = patterns[patNdxStart + j + 1]; + String subStr = tokens[tokNdxStart + i + j]; + if (!match(subStr, subPat)) { + continue strLoop; + } + } + + ndx = tokNdxStart + i; + break; + } + + if (ndx == -1) { + return false; + } + + patNdxStart = patIdxTmp; + tokNdxStart = ndx + patLength; + } + + for (int i = patNdxStart; i <= patNdxEnd; i++) { + if (!patterns[i].equals(PATH_MATCH)) { + return false; + } + } + + return true; + } +} diff --git a/modules/utils/src/test/java/org/springside/modules/utils/collection/MapUtilTest.java b/modules/utils/src/test/java/org/springside/modules/utils/collection/MapUtilTest.java index 658fa5993..dee4db8bc 100644 --- a/modules/utils/src/test/java/org/springside/modules/utils/collection/MapUtilTest.java +++ b/modules/utils/src/test/java/org/springside/modules/utils/collection/MapUtilTest.java @@ -108,10 +108,117 @@ public void jdkBuildMap() { } catch (Throwable t) { assertThat(t).isInstanceOf(UnsupportedOperationException.class); } + } + + @Test + public void weakMap() { + ConcurrentMap weakKeyMap = MapUtil.createWeakKeyConcurrentHashMap(10, 1); + initExpireAllMap(weakKeyMap); + System.gc(); + assertThat(weakKeyMap.get(new MyBean("A"))).isNull(); + assertThat(weakKeyMap).hasSize(1); // key仍然在 + + ConcurrentMap weakKeyMap2 = MapUtil.createWeakKeyConcurrentHashMap(10, 1); + MyBean value = new MyBean("B"); + initExpireKeyMap(weakKeyMap2, value); + System.gc(); + assertThat(weakKeyMap2.get(new MyBean("A"))).isNull(); + + ConcurrentMap weakKeyMap3 = MapUtil.createWeakKeyConcurrentHashMap(10, 1); + MyBean key = new MyBean("A"); + initExpireValueMap(weakKeyMap3, key); + System.gc(); + assertThat(weakKeyMap3.get(key)).isEqualTo(new MyBean("B")); + + // weak value + ConcurrentMap weakValueMap = MapUtil.createWeakValueConcurrentHashMap(10, 1); + initExpireAllMap(weakValueMap); + System.gc(); + assertThat(weakValueMap.get(new MyBean("A"))).isNull(); + + ConcurrentMap weakValueMap2 = MapUtil.createWeakValueConcurrentHashMap(10, 1); + MyBean value2 = new MyBean("B"); + initExpireKeyMap(weakValueMap2, value2); + System.gc(); + assertThat(weakValueMap2.get(new MyBean("A"))).isEqualTo(new MyBean("B")); + + ConcurrentMap weakValueMap3 = MapUtil.createWeakValueConcurrentHashMap(10, 1); + MyBean key3 = new MyBean("A"); + initExpireValueMap(weakValueMap3, key3); + System.gc(); + assertThat(weakValueMap3.get(new MyBean("A"))).isNull(); + } + + // 抽出子函数,使得Key/Value的生命周琦过期 + private void initExpireAllMap(ConcurrentMap weakKeyMap) { + MyBean key = new MyBean("A"); + MyBean value = new MyBean("B"); + weakKeyMap.put(key, value); + assertThat(weakKeyMap.get(key)).isEqualTo(value); + } + + // 抽出子函数,使得key过期,value不过期 + private void initExpireKeyMap(ConcurrentMap weakKeyMap, MyBean value) { + MyBean key = new MyBean("A"); + weakKeyMap.put(key, value); + assertThat(weakKeyMap.get(key)).isEqualTo(value); + } + + // 抽出子函数,使得key不过期,value过期 + private void initExpireValueMap(ConcurrentMap weakKeyMap, MyBean key) { + MyBean value = new MyBean("B"); + weakKeyMap.put(key, value); + assertThat(weakKeyMap.get(key)).isEqualTo(value); + } + + // 抽出子函数,使得Key/Value的生命周琦过期 + private void initWeakValue(ConcurrentMap weakKeyMap) { + MyBean key = new MyBean("A"); + MyBean value = new MyBean("B"); + weakKeyMap.put(key, value); + assertThat(weakKeyMap.get(new MyBean("A"))).isEqualTo(value); + } + + public static class MyBean { + String name; + + public MyBean(String name) { + this.name = name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MyBean other = (MyBean) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } } public enum EnumA { A, B, C } + + @Test + public void IntObjectHashMap(){ + + } } diff --git a/modules/utils/src/test/java/org/springside/modules/utils/io/FilePathUtilTest.java b/modules/utils/src/test/java/org/springside/modules/utils/io/FilePathUtilTest.java index efbc9e7a0..a38792ed0 100644 --- a/modules/utils/src/test/java/org/springside/modules/utils/io/FilePathUtilTest.java +++ b/modules/utils/src/test/java/org/springside/modules/utils/io/FilePathUtilTest.java @@ -9,18 +9,7 @@ public class FilePathUtilTest { - private String sep = Platforms.FILE_PATH_SEPARATOR; - - @Test - public void getName() { - assertThat(FilePathUtil.getFileName(sep + "a" + sep + "d" + sep + "b" + sep + "abc.txt")).isEqualTo("abc.txt"); - assertThat(FilePathUtil.getFileName("abc.txt")).isEqualTo("abc.txt"); - - assertThat(FilePathUtil.getFileExtension(sep + "a" + sep + "d" + sep + "b" + sep + "abc.txt")).isEqualTo("txt"); - assertThat(FilePathUtil.getFileExtension(sep + "a" + sep + "d" + sep + "b" + sep + "abc")).isEqualTo(""); - assertThat(FilePathUtil.getFileExtension(sep + "a" + sep + "d" + sep + "b" + sep + "abc.")).isEqualTo(""); - - } + char sep = Platforms.FILE_PATH_SEPARATOR_CHAR; @Test public void pathName() { @@ -40,5 +29,4 @@ public void getJarPath() { System.out.println("the jar file contains Files.class" + FilePathUtil.getJarPath(Files.class)); assertThat(FilePathUtil.getJarPath(Files.class)).endsWith("guava-20.0.jar"); } - } diff --git a/modules/utils/src/test/java/org/springside/modules/utils/io/FileTreeWalkerTest.java b/modules/utils/src/test/java/org/springside/modules/utils/io/FileTreeWalkerTest.java new file mode 100644 index 000000000..d2bc5241b --- /dev/null +++ b/modules/utils/src/test/java/org/springside/modules/utils/io/FileTreeWalkerTest.java @@ -0,0 +1,60 @@ +package org.springside.modules.utils.io; + +import static org.assertj.core.api.Assertions.*; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.junit.Test; +import org.springside.modules.utils.number.RandomUtil; + +public class FileTreeWalkerTest { + + @Test + public void listFile() throws IOException { + File tmpDir = FileUtil.createTempDir(); + + List all = FileTreeWalker.listAll(tmpDir); + assertThat(all).hasSize(1); + + List files = FileTreeWalker.listFile(tmpDir); + assertThat(files).hasSize(0); + + FileUtil.touch(FilePathUtil.contact(tmpDir.getAbsolutePath(), "tmp-" + RandomUtil.nextInt()) + ".tmp"); + FileUtil.touch(FilePathUtil.contact(tmpDir.getAbsolutePath(), "tmp-" + RandomUtil.nextInt()) + ".abc"); + + String childDir = FilePathUtil.contact(tmpDir.getAbsolutePath(), "tmp-" + RandomUtil.nextInt()); + FileUtil.makeSureDirExists(childDir); + + FileUtil.touch(FilePathUtil.contact(childDir, "tmp-" + RandomUtil.nextInt()) + ".tmp"); + + all = FileTreeWalker.listAll(tmpDir); + assertThat(all).hasSize(5); + + files = FileTreeWalker.listFile(tmpDir); + assertThat(files).hasSize(3); + + files = FileTreeWalker.listFileWithExtension(tmpDir, "tmp"); + assertThat(files).hasSize(2); + + files = FileTreeWalker.listFileWithExtension(tmpDir, "tp"); + assertThat(files).hasSize(0); + + files = FileTreeWalker.listFileWithWildcardFileName(tmpDir, "*.tmp"); + assertThat(files).hasSize(2); + files = FileTreeWalker.listFileWithWildcardFileName(tmpDir, "*.tp"); + assertThat(files).hasSize(0); + + files = FileTreeWalker.listFileWithRegexFileName(tmpDir, ".*\\.tmp"); + assertThat(files).hasSize(2); + files = FileTreeWalker.listFileWithRegexFileName(tmpDir, ".*\\.tp"); + assertThat(files).hasSize(0); + + FileUtil.deleteDir(tmpDir); + + assertThat(FileUtil.isDirExists(tmpDir)).isFalse(); + + } + +} diff --git a/modules/utils/src/test/java/org/springside/modules/utils/io/FileUtilTest.java b/modules/utils/src/test/java/org/springside/modules/utils/io/FileUtilTest.java index ab940d96e..10021424c 100644 --- a/modules/utils/src/test/java/org/springside/modules/utils/io/FileUtilTest.java +++ b/modules/utils/src/test/java/org/springside/modules/utils/io/FileUtilTest.java @@ -68,36 +68,17 @@ public void fileExist() throws IOException { } } - @Test - public void listFile() throws IOException { - File tmpDir = FileUtil.createTempDir(); - - List all = FileUtil.listAll(tmpDir); - assertThat(all).hasSize(1); - - List files = FileUtil.listFile(tmpDir); - assertThat(files).hasSize(0); - - FileUtil.touch(FilePathUtil.contact(tmpDir.getAbsolutePath(), "tmp-" + RandomUtil.nextInt()) + ".tmp"); - FileUtil.touch(FilePathUtil.contact(tmpDir.getAbsolutePath(), "tmp-" + RandomUtil.nextInt()) + ".abc"); - - String childDir = FilePathUtil.contact(tmpDir.getAbsolutePath(), "tmp-" + RandomUtil.nextInt()); - FileUtil.makeSureDirExists(childDir); + private String sep = Platforms.FILE_PATH_SEPARATOR; - FileUtil.touch(FilePathUtil.contact(childDir, "tmp-" + RandomUtil.nextInt()) + ".tmp"); - - all = FileUtil.listAll(tmpDir); - assertThat(all).hasSize(5); - - files = FileUtil.listFile(tmpDir); - assertThat(files).hasSize(3); - - files = FileUtil.listFileWithExtension(tmpDir, "tmp"); - assertThat(files).hasSize(2); + @Test + public void getName() { - FileUtil.deleteDir(tmpDir); + assertThat(FileUtil.getFileName(FilePathUtil.normalizePath("/a/d/b/abc.txt"))).isEqualTo("abc.txt"); + assertThat(FileUtil.getFileName("abc.txt")).isEqualTo("abc.txt"); - assertThat(FileUtil.isDirExists(tmpDir)).isFalse(); + assertThat(FileUtil.getFileExtension(FilePathUtil.normalizePath("a/d/b/abc.txt"))).isEqualTo("txt"); + assertThat(FileUtil.getFileExtension(FilePathUtil.normalizePath("/a/d/b/abc"))).isEqualTo(""); + assertThat(FileUtil.getFileExtension(FilePathUtil.normalizePath("/a/d/b/abc."))).isEqualTo(""); } diff --git a/modules/utils/src/test/java/org/springside/modules/utils/reflect/FastMethodInvokerTest.java b/modules/utils/src/test/java/org/springside/modules/utils/reflect/FastMethodInvokerTest.java index 24ba02456..936d24efe 100644 --- a/modules/utils/src/test/java/org/springside/modules/utils/reflect/FastMethodInvokerTest.java +++ b/modules/utils/src/test/java/org/springside/modules/utils/reflect/FastMethodInvokerTest.java @@ -22,10 +22,22 @@ public void test() throws InvocationTargetException { age = fastGetAge.invoke(student2); assertThat(age).isEqualTo(30); + FastMethodInvoker fastGetAge2 = FastMethodInvoker.createGetter(Student.class, "age"); + age = fastGetAge2.invoke(student1); + assertThat(age).isEqualTo(20); + + age = fastGetAge2.invoke(student2); + assertThat(age).isEqualTo(30); + FastMethodInvoker fastSetAge = FastMethodInvoker.create(Student.class, "setAge", int.class); fastSetAge.invoke(student1, 1); assertThat(student1.getAge()).isEqualTo(1); + + FastMethodInvoker fastSetAge2 = FastMethodInvoker.createSetter(Student.class, "age", int.class); + fastSetAge2.invoke(student1, 3); + + assertThat(student1.getAge()).isEqualTo(3); } public static class Student { diff --git a/modules/utils/src/test/java/org/springside/modules/utils/text/WildcardMatcherTest.java b/modules/utils/src/test/java/org/springside/modules/utils/text/WildcardMatcherTest.java new file mode 100644 index 000000000..f7c93fdae --- /dev/null +++ b/modules/utils/src/test/java/org/springside/modules/utils/text/WildcardMatcherTest.java @@ -0,0 +1,48 @@ +package org.springside.modules.utils.text; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.Test; + +public class WildcardMatcherTest { + + @Test + public void matchString() { + assertThat(WildcardMatcher.match("abc", "*")).isTrue(); + assertThat(WildcardMatcher.match("abc", "*c")).isTrue(); + assertThat(WildcardMatcher.match("abc", "a*")).isTrue(); + assertThat(WildcardMatcher.match("abc", "a*c")).isTrue(); + + assertThat(WildcardMatcher.match("abc", "a?c")).isTrue(); + assertThat(WildcardMatcher.match("abcd", "a?c?")).isTrue(); + assertThat(WildcardMatcher.match("abcd", "a??d")).isTrue(); + + assertThat(WildcardMatcher.match("abcde", "a*d?")).isTrue(); + + assertThat(WildcardMatcher.match("abcde", "a*d")).isFalse(); + assertThat(WildcardMatcher.match("abcde", "a*x")).isFalse(); + assertThat(WildcardMatcher.match("abcde", "a*df")).isFalse(); + + assertThat(WildcardMatcher.match("abcde", "?abcd")).isFalse(); + + assertThat(WildcardMatcher.match("ab\\\\*cde", "ab\\\\*c*")).isTrue(); + assertThat(WildcardMatcher.match("ab\\\\*cde", "ab\\\\*?de")).isTrue(); + } + + @Test + public void matchPath() { + assertThat(WildcardMatcher.matchPath("/a/b/dd", "**")).isTrue(); + + assertThat(WildcardMatcher.matchPath("/a/b/dd", "**/dd")).isTrue(); + assertThat(WildcardMatcher.matchPath("/a/b/c/dd", "/a/**/dd")).isTrue(); + assertThat(WildcardMatcher.matchPath("/a/b/dd", "/a/*/dd")).isTrue(); + assertThat(WildcardMatcher.matchPath("/a/b/dd", "/a/*/d?")).isTrue(); + assertThat(WildcardMatcher.matchPath("/a/b/ddxxa", "/a/*/dd*")).isTrue(); + assertThat(WildcardMatcher.matchPath("/a/b/ddxxa", "/a/?/dd*")).isTrue(); + assertThat(WildcardMatcher.matchPath("a/b/ddxxa", "a/?/dd*")).isTrue(); + assertThat(WildcardMatcher.matchPath("a/b/dd", "**/dd")).isTrue(); + + + assertThat(WildcardMatcher.matchPath("/a/b/c/dd", "/a/*/dd")).isFalse(); + } +}