├── .gitignore ├── README.md ├── mvn_deploy.bat ├── mvn_eclipse.bat ├── pom.xml └── src ├── main └── java │ ├── org │ └── quartz │ │ └── CronExpression.java │ └── tools │ ├── Action.java │ ├── BeanUtil.java │ ├── CategoryService.java │ ├── CharacterToAlpha.java │ ├── Constant.java │ ├── Context.java │ ├── Convert.java │ ├── Cron.java │ ├── DateTime.java │ ├── FastContains.java │ ├── Global.java │ ├── InitializeOnce.java │ ├── Json.java │ ├── JsonRpcUtil.java │ ├── LightweightException.java │ ├── MapUtil.java │ ├── MySqlFunction.java │ ├── NotSupportedException.java │ ├── ObjectConverter.java │ ├── PagedList.java │ ├── ParamSignature.java │ ├── Predicate.java │ ├── Resource.java │ ├── Result.java │ ├── SpringBeanPostPrcessor.java │ ├── SpringContext.java │ ├── StoreService.java │ ├── StringUtil.java │ ├── User.java │ ├── Validate.java │ ├── ZHCNConvert.java │ ├── ZHCNUtil.java │ ├── cache │ ├── CacheItem.java │ ├── CacheProvider.java │ └── HashMapCacheProvider.java │ ├── code │ └── RunTimer.java │ ├── concurrent │ ├── BatchQueue.java │ └── Parallel.java │ ├── counter │ ├── AtomicKeyedCounter.java │ ├── AtomicLongArrayCounter.java │ ├── MultiKeyedCounter.java │ ├── RedisKeyedCounter.txt │ └── TimedAtomicKeyedCounter.java │ ├── event │ ├── EventArgs.java │ ├── EventContainer.java │ └── EventHandler.java │ ├── generator │ ├── AtomicIdGenerator.java │ ├── DataStore.java │ ├── FileDataStore.java │ ├── IdGenerator.java │ └── ranged │ │ ├── Range.java │ │ ├── RangeGenerator.java │ │ └── RangedIdGenerator.java │ ├── http │ ├── HttpMethod.java │ ├── HttpPostedFile.java │ ├── HttpPostedFileBuilder.java │ ├── HttpRequest.java │ ├── HttpRequestBuilder.java │ ├── HttpResponse.java │ └── HttpUtil.java │ ├── jsonrpc │ ├── InvalidJsonRpcRequestException.java │ ├── InvokeResultList.java │ ├── JsonRpcError.java │ ├── JsonRpcFilter.java │ ├── JsonRpcFilterV2.java │ ├── JsonRpcService.java │ ├── LocalVariableNotFoundException.java │ ├── MethodInfo.java │ ├── MethodNotFoundException.java │ ├── SingleInvokeResult.java │ └── web.txt │ ├── naming.txt │ ├── oauth │ ├── AccessToken.java │ ├── Display.java │ ├── FieldConstant.java │ ├── GrantType.java │ ├── OAuthError.java │ ├── OAuthException.java │ ├── OAuthRequestContext.java │ ├── ProviderDefinition.java │ └── ResponseType.java │ ├── session │ ├── CookieStoreService.java │ └── SessionServiceBase.java │ ├── spring │ ├── AsyncInitBeanFactory.java │ ├── SpringBeanPostPrcessor.java │ └── SpringContext.java │ ├── token │ ├── ArrayHandler.java │ ├── GenericTokenParser.java │ ├── ListHandler.java │ ├── MapHandler.java │ ├── SimpleParser.java │ └── TokenHandler.java │ └── web │ ├── CookieUtil.java │ └── ServletUtil.java ├── temp ├── java │ └── tools │ │ ├── mongodb │ │ ├── DocumentUtil.java │ │ └── builder │ │ │ ├── Builder.java │ │ │ ├── CollectionOptionsBuilder.java │ │ │ ├── FieldsBuilder.java │ │ │ ├── IndexKeysBuilder.java │ │ │ ├── IndexOptionsBuilder.java │ │ │ ├── QueryBuilder.java │ │ │ ├── SortByBuilder.java │ │ │ └── UpdateBuilder.java │ │ ├── quartz │ │ └── JobScheduler.java │ │ └── redis │ │ ├── Executable.java │ │ ├── NotImplementedException.java │ │ ├── RedisMap.java │ │ ├── RedisQueue.java │ │ └── RedisUtil.java └── test │ └── tools │ ├── mongodb │ └── BuilderTest.java │ ├── quartz │ ├── CronTest.java │ ├── HelloJob.java │ └── SimpleExample.java │ └── redis │ ├── MapTest.java │ └── QueueTest.java └── test ├── java └── tools │ └── test │ ├── BeanTest.java │ ├── BitSetTest.java │ ├── Boyer.java │ ├── CategoryTest.java │ ├── ConvertTest.java │ ├── DataProcessing.java │ ├── DateTest.java │ ├── DynamicCompiler.java │ ├── ExecutorServiceTest.java │ ├── FalseSharing.java │ ├── FileTest.java │ ├── FutureTest.java │ ├── GeneratorTest.java │ ├── HttpTest.java │ ├── HttpsTest.java │ ├── ImportTest.java │ ├── IndexOfTest.java │ ├── InlineCompiler.java │ ├── JsonTest.java │ ├── MapGetTest.java │ ├── MapTest.java │ ├── MySqlFunTest.java │ ├── NanoTimeTest.java │ ├── RandomTest.java │ ├── RegexpTest.java │ ├── ReplaceTest.java │ ├── SizeOfTest.java │ ├── StringUtilTest.java │ ├── TokenTest.java │ ├── UnsafeTest.txt │ ├── ValidateTest.java │ ├── ZHCN.java │ ├── cache │ └── CacheTest.java │ ├── concurrent │ ├── AnotherLocal.java │ ├── Local.java │ └── Main.java │ ├── counter │ └── MultiKeyedCounterTest.java │ ├── domain │ └── User.java │ ├── imports │ ├── A1.java │ └── A2.java │ ├── ip │ ├── GeoIpService.java │ └── IPExt.java │ ├── jsonrpc │ ├── ComplexEntity.java │ ├── JsonrpcTest.java │ ├── Obj.java │ └── TestEx.java │ ├── oom │ ├── HeapOOM.java │ ├── JavaMethodAreaOOM.java │ ├── JavaVMStackSOF.java │ ├── RuntimeConstantPoolOOM.java │ ├── StringIntern.java │ └── ThreadStackTrace.java │ ├── session │ ├── MySessionService.java │ └── SessionTest.java │ └── spring │ ├── BeanTest.java │ └── SlowBean.java └── resources ├── applicationContext.xml └── log4j.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Package Files # 4 | *.jar 5 | *.war 6 | *.ear 7 | target 8 | .* 9 | .classpath 10 | .settings -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | tools 2 | ===== 3 | 4 | 我经常用到的一些小工具类:类型验证、转换,http,oauth,job,redis queue,jsonrpc等 -------------------------------------------------------------------------------- /mvn_deploy.bat: -------------------------------------------------------------------------------- 1 | call mvn clean 2 | call mvn deploy -Dmaven.test.skip 3 | @pause -------------------------------------------------------------------------------- /mvn_eclipse.bat: -------------------------------------------------------------------------------- 1 | @cd 2 | call mvn eclipse:clean 3 | call mvn eclipse:eclipse -DdownloadSources=true 4 | @pause -------------------------------------------------------------------------------- /src/main/java/tools/Action.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | /** 4 | * 命名采用c#同名委托:http://msdn.microsoft.com/en-us/library/018hxwa8.aspx 5 | * 6 | * @author liusan.dyf 7 | * @version 1.0 8 | * @since 2012-12-20 9 | */ 10 | public interface Action { 11 | void execute(T t); 12 | } 13 | 14 | // interface Action2 { 15 | // void execute(T1 t1, T2 t2); 16 | // } 17 | -------------------------------------------------------------------------------- /src/main/java/tools/BeanUtil.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | import net.sf.cglib.beans.BeanCopier; 7 | import net.sf.cglib.beans.BeanMap; 8 | 9 | /** 10 | * @author liusan.dyf 11 | * @version 1.0 12 | * @since 2015年4月27日 13 | */ 14 | public class BeanUtil { 15 | private static final Map map = new ConcurrentHashMap(); 16 | 17 | /** 18 | * 2个bean直接相同的属性名之间做copy 19 | * 20 | * @param srcObj 21 | * @param destObj 22 | */ 23 | public static void copy(Object srcObj, Object destObj) { 24 | String key = getKey(srcObj.getClass(), destObj.getClass()); 25 | BeanCopier copier = null; 26 | 27 | if (!map.containsKey(key)) { 28 | synchronized (map) { 29 | if (!map.containsKey(key)) { 30 | copier = BeanCopier.create(srcObj.getClass(), destObj.getClass(), false); 31 | map.put(key, copier); 32 | } 33 | } 34 | } 35 | 36 | if (copier == null) { 37 | copier = map.get(key); 38 | } 39 | 40 | copier.copy(srcObj, destObj, null); 41 | } 42 | 43 | /** 44 | * 把map里的kv赋值到同属性名的bean上 45 | * 46 | * @param destObj 47 | * @param m 48 | */ 49 | public static void fill(Object destObj, Map m) { 50 | if (destObj == null || m == null || m.size() == 0) 51 | return; 52 | 53 | BeanMap bm = BeanMap.create(destObj); 54 | bm.putAll(m); 55 | 56 | // java.util.Set keys = m.keySet(); 57 | // for (String item : keys) { 58 | // bm.put(item, m.get(item));// 类型不匹配时会抛出 java.lang.ClassCastException: 59 | // } 60 | } 61 | 62 | private static String getKey(Class srcClazz, Class destClazz) { 63 | return srcClazz.getName() + destClazz.getName(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/tools/CategoryService.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import org.apache.commons.logging.Log; 8 | import org.apache.commons.logging.LogFactory; 9 | 10 | /** 11 | * 适用于有id、parentId的树状节点判断,约定root节点id为0,小于0的id都不合法 12 | * 13 | * @author liusan.dyf 14 | * @version 1.0 15 | * @since 2013-7-1 16 | */ 17 | public class CategoryService { 18 | private static final Log logger = LogFactory.getLog("system");// 日志 19 | /** 20 | * 最多的层数,map是外面传入的,数据可能出现质量问题(自己指向自己、环状结构)导致死循环 2016-7-22 09:56:51 by liusan.dyf 21 | */ 22 | private static final int MAX_DEPTH = 20; 23 | private static final int MAGIC = -9527; 24 | private static final List EMPTY_LIST = new ArrayList(0); 25 | 26 | private int root = 0; 27 | /** 28 | * key=id,value=parentId 29 | */ 30 | private Map map = MapUtil.create(); 31 | 32 | private String version;// 2016-8-25 16:56:26 by liusan.dyf 33 | 34 | /** 35 | * key=id,value=parentId 36 | * 37 | * @param map 38 | */ 39 | public void init(Map map) { 40 | if (map != null) 41 | this.map = map; 42 | } 43 | 44 | /** 45 | * 改调用init方法,2016-8-31 16:18:58 by liusan.dyf 46 | * 47 | * @param map 48 | */ 49 | @Deprecated 50 | public void loadFrom(Map map) { 51 | init(map); 52 | } 53 | 54 | public Map getData() { 55 | return map; 56 | } 57 | 58 | /** 59 | * 包含自己本身的路径列表 2016-7-22 19:29:01 by liusan.dyf 60 | * 61 | * @param id 62 | * @return 63 | */ 64 | public List getPath(int id) { 65 | if (id <= 0) { 66 | return EMPTY_LIST; 67 | } 68 | 69 | List list = new ArrayList(); 70 | list.add(id); // 先添加自己 71 | 72 | // 开始查找 73 | int childId = id; 74 | Integer parentId; 75 | int count = 0; 76 | 77 | while (true) { 78 | parentId = map.get(childId); 79 | if (parentId == null)// 不存在父节点,数据错误 80 | return EMPTY_LIST; 81 | else if (parentId == childId) { 82 | logger.warn("CategoryService:数据错误,节点指向了自己:" + childId); 83 | return EMPTY_LIST; 84 | } else { 85 | list.add(parentId); 86 | } 87 | 88 | if (parentId == root)// 找到root了,退出 89 | return list; 90 | 91 | childId = parentId;// 继续循环 92 | 93 | // 判断查找的次数,外部数据可能出现环状数据,这里过保护 94 | count++; 95 | if (!canContinue(count, id, null)) { 96 | return EMPTY_LIST;// 数据错误,返回空 97 | } 98 | } 99 | } 100 | 101 | private boolean canContinue(int count, Integer id, Integer pid) { 102 | if (count >= MAX_DEPTH) { 103 | logger.warn("CategoryService:已达最大查找次数:" + MAX_DEPTH + ",入参:id=" + id + ",pid=" + pid); 104 | return false; 105 | } 106 | 107 | return true; 108 | } 109 | 110 | /** 111 | * @param id 112 | * @param pid 0 表示顶级类别 113 | * @return 114 | */ 115 | public boolean isChildOf(int id, int pid) { 116 | if (pid == id || pid == root)// 2个相等或者pid为root 117 | return true; 118 | 119 | if (id == root && pid != root)// id已经是root但pid却不是 120 | return false; 121 | 122 | // 123 | int childId = id; 124 | Integer parentId; 125 | int count = 0; 126 | 127 | while (true) { 128 | parentId = map.get(childId); 129 | if (parentId == null)// 不存在父节点,数据错误 130 | return false; 131 | else if (parentId == pid)// 命中 132 | return true; 133 | else if (parentId == childId) { 134 | logger.warn("CategoryService:数据错误,节点指向了自己:" + childId); 135 | return false; 136 | } 137 | 138 | if (parentId == root) 139 | return false; 140 | 141 | childId = parentId;// 继续循环 142 | 143 | // 判断查找的次数,外部数据可能出现环状数据,这里过保护 144 | count++; 145 | if (!canContinue(count, id, pid)) { 146 | return false; 147 | } 148 | } 149 | } 150 | 151 | /** 152 | * @param child 153 | * @param pidList eg "1,2,3" 154 | * @return 155 | */ 156 | public boolean isChildOfAny(Object child, String pidList) { 157 | int id = Convert.toInt(child, MAGIC); 158 | if (id == MAGIC)// 对于子节点无效值,返回false 159 | return false; 160 | 161 | String[] arr = StringUtil.split(pidList, ","); 162 | 163 | int pid = -1;// -1表示父节点里的无效值 164 | for (String item : arr) { 165 | pid = Convert.toInt(item.trim(), MAGIC);// 注意trim 166 | 167 | if (pid != MAGIC && isChildOf(id, pid)) { 168 | return true; 169 | } 170 | } 171 | 172 | return false; 173 | } 174 | 175 | public static void main(String[] args) { 176 | // 构造树 177 | Map map = MapUtil.create(); 178 | map.put(1, 0); 179 | map.put(2, 1); 180 | map.put(3, 1); 181 | map.put(4, 3); 182 | map.put(5, 3); 183 | map.put(7, 0); 184 | map.put(8, 7); 185 | map.put(9, 8); 186 | 187 | // 错误的干扰数据 2016-7-22 09:45:13 by liusan.dyf 188 | // map.put(-1, -1); 189 | // map.put(0, -1); 190 | map.put(6, 6); 191 | 192 | map.put(1, 5);// 组成环状数据 193 | 194 | // 匹配测试 195 | CategoryService entry = new CategoryService(); 196 | entry.init(map); 197 | 198 | System.out.println(entry.isChildOf(5, 1));// true 199 | System.out.println(entry.getPath(7));// [7, 0] 200 | System.out.println(entry.getPath(9));// [9, 8, 7, 0] 201 | System.out.println(entry.getPath(9527));// [9, 8, 7, 0] 202 | System.out.println(entry.isChildOf(6, 1));// false,节点指向了自己 203 | System.out.println(entry.isChildOfAny(5, "4,2"));// false,环状数据,已达最大查找次数 204 | System.out.println(entry.isChildOfAny(9, "7,2"));// true 205 | System.out.println(entry.isChildOfAny(0, "7,2"));// false 206 | 207 | // 208 | String trim = "trim"; 209 | System.out.println(trim == trim.trim());// true,可以看trim的源码,没有空格时返回本身 210 | } 211 | 212 | public int getRoot() { 213 | return root; 214 | } 215 | 216 | public void setRoot(int root) { 217 | this.root = root; 218 | } 219 | 220 | public String getVersion() { 221 | return version; 222 | } 223 | 224 | public void setVersion(String version) { 225 | this.version = version; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/main/java/tools/CharacterToAlpha.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | public class CharacterToAlpha { 4 | private static final char[] ALPHA_TABLE = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 5 | 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; 6 | /** 7 | * 汉字拼音首字母编码表,可以如下方法得到: 字母Z使用了两个标签,这里有27个值, i, u, v都不做声母, 跟随前面的字母(因为不可以出现,所以可以随便取) private static final char[] 8 | * chartable = { '啊', '芭', '擦', '搭', '蛾', '发', '噶', '哈', '哈', '击', '喀', '垃', '妈', '拿', '哦', '啪', '期', '然', '撒', '塌', 9 | * '塌', '塌', '挖', '昔', '压', '匝', '座' }; private static final int[] table = new int[27]; static { for (int i = 0; i < 10 | * 27; ++i) { table[i] = gbValue(chartable[i]); System.out.print(table[i]+" "); } } 11 | */ 12 | 13 | private static final int[] TABLE = new int[] { 45217, 45253, 45761, 46318, 46826, 47010, 47297, 47614, 47614, 14 | 48119, 49062, 49324, 49896, 50371, 50614, 50622, 50906, 51387, 51446, 52218, 52218, 52218, 52698, 52980, 15 | 53689, 54481, 55289 }; 16 | 17 | private static final int CH = '*'; 18 | private static final int SIZE = 26; 19 | 20 | /** 21 | * 主函数, 输入字符, 得到他的声母, 英文字母返回对应的大写字母 其他非简体汉字返回 '*' 22 | */ 23 | public static char toAlpha(char ch) { 24 | if (ch >= 'a' && ch <= 'z')// 小写字母 25 | return (char) (ch - 'a' + 'A'); 26 | 27 | if (ch >= 'A' && ch <= 'Z')// 大写字母 28 | return ch; 29 | 30 | int idx = getIndex(ch); 31 | if (idx < TABLE[0]) // TABLE是从小到大排列的 32 | return CH; 33 | 34 | for (int i = 0; i < SIZE; ++i) { 35 | if (matches(i, idx)) { 36 | return ALPHA_TABLE[i]; 37 | } 38 | } 39 | return CH; 40 | } 41 | 42 | /** 43 | * 根据一个包含汉字的字符串返回一个汉字拼音首字母的字符串 44 | */ 45 | public static String toAlpha(String v) { 46 | if (v == null) 47 | return null; 48 | 49 | int len = v.length(); 50 | StringBuilder sb = new StringBuilder(len); 51 | for (int i = 0; i < len; i++) { 52 | char ch = toAlpha(v.charAt(i)); 53 | 54 | if (ch != CH) 55 | sb.append(ch); 56 | } 57 | 58 | return sb.toString(); 59 | } 60 | 61 | private static boolean matches(int i, int idx) { 62 | if (idx < TABLE[i]) 63 | return false; 64 | 65 | int j = i + 1; 66 | 67 | // 字母Z使用了两个标签 68 | while (j < SIZE && (TABLE[j] == TABLE[i])) 69 | ++j; 70 | 71 | if (j == SIZE) 72 | return idx <= TABLE[j]; 73 | else 74 | return idx < TABLE[j]; 75 | } 76 | 77 | /** 78 | * 取出传入汉字的编码 79 | */ 80 | private static int getIndex(char ch) { 81 | char[] arr = new char[] { ch }; 82 | String str = new String(arr); 83 | 84 | try { 85 | byte[] bytes = str.getBytes("UTF-8");// 一定要是UTF-8的编码 2015-3-18 19:14:30 by 六三 86 | if (bytes.length < 2)// 英文字符 87 | return 0; 88 | 89 | return (bytes[0] << 8 & 0xff00) + (bytes[1] & 0xff); 90 | } catch (Exception e) { 91 | System.out.println(e); 92 | return CH; 93 | } 94 | } 95 | 96 | /** 97 | * 测试输出 98 | */ 99 | public static void main(String[] args) { 100 | System.out.println(toAlpha("代刷信誉,好评!如有需要,联系qq")); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/tools/Constant.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | public interface Constant { 4 | /** 5 | * 斜线 6 | */ 7 | public static final String OBLIQUE_LINE = "/"; 8 | 9 | /** 10 | * 竖线 11 | */ 12 | public static final String VERTICAL_LINE = "|"; 13 | 14 | /** 15 | * 星号 16 | */ 17 | public static final String POUND = "#"; 18 | 19 | /** 20 | * 冒号 21 | */ 22 | public static final String COLON = ":"; 23 | 24 | /** 25 | * 点号 26 | */ 27 | public static final String DOT = "."; 28 | 29 | /** 30 | * 逗号 31 | */ 32 | public static final String COMMA = ","; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/tools/Context.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | public class Context implements StoreService { 4 | public final ThreadLocal store = new ThreadLocal(); 5 | 6 | public T get() { 7 | return store.get(); 8 | } 9 | 10 | public void set(T t) { 11 | store.set(t); 12 | } 13 | 14 | public void remove() { 15 | store.remove(); 16 | } 17 | 18 | @Override 19 | public void set(T value, int seconds) { 20 | store.set(value); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/tools/Cron.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | 7 | import org.quartz.CronExpression; 8 | 9 | public class Cron { 10 | /** 11 | * 2013-08-01 得到一个cron表达式接下来的若干个执行时间 12 | * 13 | * @param cronExpression 14 | * @param startTimestamp 15 | * @param n 16 | * @return 17 | * @throws Throwable 18 | */ 19 | public static List getNextValidTimes(String cronExpression, long startTimestamp, int n) throws Throwable { 20 | if (n <= 0) 21 | n = 1; 22 | List list = new ArrayList(n); 23 | 24 | // [秒] [分] [小时] [日] [月] [周] [年] 25 | // 实例化表达式类,把字符串转成一个对象 26 | CronExpression cron = new CronExpression(cronExpression); 27 | // cron.setTimeZone(java.util.TimeZone.getTimeZone("Asia/Beijing")); 28 | 29 | Date start = null; 30 | if (startTimestamp <= 0) 31 | start = new Date(); 32 | else 33 | start = new Date(startTimestamp * 1000); 34 | 35 | for (int i = 0; i < n; i++) { 36 | Date d = cron.getNextValidTimeAfter(start); 37 | // System.out.println(tools.Convert.toString(d)); 38 | 39 | start = d; 40 | 41 | list.add(d); 42 | } 43 | 44 | return list; 45 | } 46 | 47 | public static long getNextOccurrenceTimestampBySingleCron(String cron, long ts) { 48 | // 如果cron的秒位是*,那么只要当前时间还和cron的分钟一致,则会返回下一秒的时间 49 | List list = null; 50 | try { 51 | list = getNextValidTimes(cron, ts, 1); 52 | } catch (Throwable e) { 53 | 54 | } 55 | if (list != null && list.size() > 0) 56 | return list.get(0).getTime() / 1000; 57 | 58 | return 0; 59 | } 60 | 61 | /** 62 | * 支持多个cron表达式取值,取时间最早的那个,即最早发生的 2013-09-12 by liusan.dyf 63 | * 64 | * @param crons 65 | * @param ts 66 | * @return 67 | */ 68 | public static long getNextOccurrenceTimestamp(String crons, long ts) { 69 | long min = Long.MAX_VALUE; 70 | 71 | String[] arr = tools.StringUtil.split(crons, '\n'); 72 | 73 | for (String item : arr) { 74 | if (tools.Validate.isBlank(item)) 75 | continue; 76 | 77 | long v = getNextOccurrenceTimestampBySingleCron(item, ts); 78 | if (v != 0 && v < min) { 79 | min = v; 80 | } 81 | } 82 | 83 | if (min == Long.MAX_VALUE) 84 | return 0; 85 | 86 | return min; 87 | } 88 | 89 | public static void main(String[] args) { 90 | String cron = "* 12 18 ? * 2-6\n* 40 11 ? * 2-6"; 91 | System.out.println(tools.Convert.toDate(getNextOccurrenceTimestamp(cron, 0))); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/tools/FastContains.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Random; 6 | 7 | /** 8 | * 字符串精确匹配,要求字符串列表固定。本类使用一维int数组来存储各string的hash值,每个string的hashcode都放入数组的固定的index上。
9 | * 不解决hash碰撞问题。目前没有办法保证hash值均匀的落在某数组内,该类暂不能使用。 10 | * 11 | * @author liusan.dyf 12 | * @version 1.0 13 | * @since 2012-11-26 14 | */ 15 | @Deprecated 16 | public class FastContains { 17 | private int[] table; 18 | 19 | private int size = 0; 20 | private int n = 0; 21 | 22 | public FastContains(List list) { 23 | size = list.size(); 24 | table = new int[size * 2]; 25 | for (String item : list) { 26 | int hc = hashCode(item); 27 | int idx = getIndex(hc, true); 28 | 29 | // System.out.println("hash(" + item + ")=" + hc + ",idx=" + idx); 30 | 31 | if (table[idx] != 0) 32 | n++; 33 | 34 | table[idx] = hc; 35 | } 36 | } 37 | 38 | private int hashCode(String v) { 39 | return v.hashCode(); 40 | } 41 | 42 | private int getIndex(int hc, boolean update) { 43 | int m = hc % size; 44 | return m + size;// hashcode有可能负数,这里用size*2来避免index冲突 45 | 46 | // return new Random(hc).nextInt(size); 47 | 48 | // return (int) (Math.abs(hc) * 1.0 / Integer.MAX_VALUE * size); 49 | 50 | // return hc & size; 51 | } 52 | 53 | public boolean contains(String v) { 54 | int hc = hashCode(v); 55 | int idx = getIndex(hc, false); 56 | 57 | return table[idx] == hc; 58 | } 59 | 60 | public int getN() { 61 | return n; 62 | } 63 | 64 | public static void main(String[] args) { 65 | 66 | // 测试 67 | ArrayList list = new ArrayList(); 68 | list.add("a"); 69 | list.add("b"); 70 | list.add("c"); 71 | list.add("d"); 72 | 73 | FastContains of = new FastContains(list); 74 | System.out.println(of.contains("b")); 75 | 76 | // 77 | Random r = new Random(1); 78 | for (int i = 0; i < 0; i++) 79 | System.out.println(r.nextInt(20)); 80 | 81 | // 82 | int i = (int) (1100 * 1.0 / 2000 * 20); 83 | System.out.println(i); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/tools/Global.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | //import java.lang.reflect.Field; 4 | import java.util.Map; 5 | import java.util.Map.Entry; 6 | import java.util.Set; 7 | 8 | import org.apache.commons.logging.Log; 9 | import org.apache.commons.logging.LogFactory; 10 | 11 | //import sun.misc.Unsafe; 12 | import tools.Context; 13 | import tools.counter.AtomicKeyedCounter; 14 | import tools.counter.MultiKeyedCounter; 15 | 16 | /** 17 | * 使用静态方法,方便使用,spring bean,注意init-method = init 18 | * 19 | * @author liusan.dyf 20 | */ 21 | public class Global extends tools.InitializeOnce { 22 | /** 23 | * 2014-10-22 by liusan.dyf,保存此次发布的版本号 24 | */ 25 | public static int V = 0; 26 | 27 | // private static EventContainer eventContainer = null; 28 | 29 | public static final String LOCAL_IP = tools.StringUtil.getLocalIp();// 本机IP 30 | 31 | private static final Log logger = LogFactory.getLog("system");// 日志 32 | 33 | private static Map settings;// 全局设置 34 | 35 | // /** 36 | // * 哈勃日志,目前供pfp项目使用 37 | // */ 38 | // private static final Log MONITOR_LOGGER = LogFactory.getLog("monitor"); 39 | 40 | /** 41 | * 系统计数器 2012-02-16 42 | */ 43 | private static MultiKeyedCounter counter = createCounters(); 44 | 45 | /** 46 | * 2012-02-28 by liusan.dyf 47 | */ 48 | private static Context contextStore = new Context(); 49 | 50 | public static void destroy() { 51 | ; 52 | } 53 | 54 | // /** 55 | // * 2014-12-13 by 六三,操作堆外内存(off-heap memory),详细说明:http://ifeve.com/sun-misc-unsafe/ 56 | // * 57 | // * @return 58 | // */ 59 | // public static Unsafe getUnsafe() { 60 | // Field f; 61 | // try { 62 | // f = Unsafe.class.getDeclaredField("theUnsafe"); 63 | // f.setAccessible(true); 64 | // return (Unsafe) f.get(null); 65 | // } catch (Exception e) { 66 | // e.printStackTrace(); 67 | // } 68 | // 69 | // // 操作对外内存 http://robaustin.wikidot.com/how-to-write-to-direct-memory-locations-in-java 70 | // 71 | // return null; 72 | // } 73 | 74 | public static Map getSettings() { 75 | if (settings == null) 76 | settings = tools.MapUtil.create();// 2014-01-16 by liusan.dyf 77 | 78 | return settings; 79 | } 80 | 81 | /** 82 | * 2014-03-07 by liusan.dyf 83 | * 84 | * @param v 85 | */ 86 | public static void setSettings(Map v) { 87 | if (v == null) 88 | return; 89 | 90 | settings = v; 91 | } 92 | 93 | /** 94 | * 2014-03-07 by liusan.dyf 95 | * 96 | * @param v 97 | */ 98 | public static void attachSettings(Map v) { 99 | if (v == null) 100 | return; 101 | 102 | getSettings().putAll(v); 103 | } 104 | 105 | /** 106 | * 2012-02-16 by liusan.dyf 107 | * 108 | * @return 109 | */ 110 | public static MultiKeyedCounter getCounter() { 111 | return counter; 112 | } 113 | 114 | /** 115 | * 2013-03-07 by liusan.dyf 合并计数器 116 | * 117 | * @param m 118 | */ 119 | public static void mergeCounters(Map m) { 120 | if (m == null) 121 | return; 122 | 123 | Set> set = m.entrySet(); 124 | 125 | for (Entry item : set) { 126 | counter.increment(item.getKey(), tools.Convert.toLong(item.getValue(), 0)); 127 | } 128 | 129 | logger.warn("mergeCounters:" + m.size()); 130 | } 131 | 132 | /** 133 | * 2013-08-28 by liusan.dyf 134 | * 135 | * @return 136 | */ 137 | public Map getCounterMapAndReset() { 138 | Map m = getCounter().setAll(0); 139 | return m; 140 | } 141 | 142 | public static MultiKeyedCounter createCounters() { 143 | return new AtomicKeyedCounter(); 144 | } 145 | 146 | public static User getCurrentUser() { 147 | return contextStore.get(); 148 | } 149 | 150 | public static void removeCurrentUser() { 151 | contextStore.remove(); 152 | } 153 | 154 | /** 155 | * 2012-02-29 156 | * 157 | * @param u 158 | */ 159 | public static void setCurrentUser(User u) { 160 | contextStore.set(u); 161 | } 162 | 163 | /** 164 | * 动态方法,在spring bean的xml配置里初始化使用 165 | */ 166 | @Override 167 | protected void doInitialize() { 168 | // logger.warn("开始初始化global"); 169 | 170 | // ===初始化工作 171 | // if (eventContainer != null) 172 | // eventContainer.onEvent(this, EventArgs.create(this).setType("global.before-init")); 173 | } 174 | 175 | /** 176 | * 2014-04-20 by liusan.dyf 177 | * 178 | * @param v 179 | */ 180 | public static void println(Object v) { 181 | System.out.println(v); 182 | } 183 | 184 | public static void sleep(long millis) { 185 | try { 186 | Thread.sleep(millis); 187 | } catch (InterruptedException e) { 188 | 189 | } 190 | } 191 | 192 | /** 193 | * 2014-11-20 by 六三,默认是warn的方式打印出来 194 | * 195 | * @param loggerName 196 | * @param content 197 | */ 198 | public static void log(String loggerName, Object content) { 199 | org.apache.commons.logging.LogFactory.getLog(loggerName).warn(content); 200 | } 201 | 202 | // public static EventContainer getEventContainer() { 203 | // return eventContainer; 204 | // } 205 | // 206 | // public static void setEventContainer(EventContainer v) { 207 | // eventContainer = v; 208 | // } 209 | } 210 | -------------------------------------------------------------------------------- /src/main/java/tools/InitializeOnce.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | /** 7 | * 如果类只需要初始化一次,则可继承该类 8 | * 9 | * @author liusan.dyf 10 | * @version 1.0 11 | * @since 2013-8-5 12 | */ 13 | public abstract class InitializeOnce { 14 | private boolean initialized = false; // java 5之后可以不用volatile 15 | private final Lock lock = new ReentrantLock(); 16 | protected final long setupTimeMillis = System.currentTimeMillis();// 2014-12-09 by 六三 17 | 18 | /** 19 | * 是否初始化OK 20 | * 21 | * @return 22 | */ 23 | public boolean isInitialized() { 24 | return initialized; 25 | } 26 | 27 | public final void init() { 28 | if (initialized) { 29 | return; 30 | } 31 | 32 | // 注意和finally对应,防止出错后无法unlock 33 | lock.lock(); 34 | try { 35 | if (initialized)// 双重判断。被lock后,所有变量的值都会重新去内存里取最新的 36 | return; 37 | 38 | doInitialize(); 39 | initialized = true; 40 | } finally { 41 | lock.unlock(); 42 | } 43 | } 44 | 45 | /** 46 | * 不要多次调用 47 | */ 48 | protected abstract void doInitialize(); 49 | } 50 | 51 | // 2013-08-05 20:29:10,250 ERROR ExceptionHandlerImpl - tp_invoke:sfqz.1859 java.lang.NullPointerException 52 | // 2013-08-05 20:29:10,259 WARN ElementChecker - BloomFilter initialized cost : 38 53 | -------------------------------------------------------------------------------- /src/main/java/tools/LightweightException.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | /** 4 | * 用在不需要堆栈信息的地方,性能高,用异常来做流程中断控制 5 | * 6 | * @author liusan.dyf 7 | */ 8 | public class LightweightException extends RuntimeException { 9 | /** 10 | * 11 | */ 12 | private static final long serialVersionUID = 1L; 13 | 14 | public LightweightException() { 15 | } 16 | 17 | public LightweightException(String message) { 18 | super(message); 19 | } 20 | 21 | /** 22 | * 注意,不需要堆栈信息 2012-07-19 23 | */ 24 | @Override 25 | public Throwable fillInStackTrace() { 26 | return this; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/tools/NotSupportedException.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | /** 4 | * 可以用java.lang.UnsupportedOperationException代替 5 | * 6 | * @author 六三 7 | * @version 1.0 8 | * @since 2014年12月12日 9 | */ 10 | public class NotSupportedException extends RuntimeException { 11 | 12 | /** 13 | * 14 | */ 15 | private static final long serialVersionUID = 1L; 16 | 17 | public NotSupportedException() { 18 | } 19 | 20 | public NotSupportedException(String message) { 21 | super(message); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/tools/ObjectConverter.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | /** 4 | * @author liusan.dyf 5 | * @version 1.0 6 | * @since 2013-12-9 7 | */ 8 | public interface ObjectConverter { 9 | TFrom from(TTo v); 10 | 11 | TTo to(TFrom t); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/tools/PagedList.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * 分页辅助类 2011-11-07 7 | * 8 | * @author liusan.dyf 9 | * @param 10 | */ 11 | public class PagedList { 12 | private int count; 13 | private Collection list; 14 | 15 | public int getCount() { 16 | return count; 17 | } 18 | 19 | public void setCount(int count) { 20 | this.count = count; 21 | } 22 | 23 | public Collection getList() { 24 | return list; 25 | } 26 | 27 | public void setList(Collection list) { 28 | this.list = list; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/tools/Predicate.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | public interface Predicate { 4 | boolean execute(T t); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/tools/Resource.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | 8 | /** 9 | * 文件要放到resource目录下面 10 | * 11 | * @author liusan.dyf 12 | */ 13 | public class Resource { 14 | /** 15 | * @param args 16 | */ 17 | public static void main(String[] args) { 18 | ClassLoader c1 = Thread.currentThread().getContextClassLoader(); 19 | ClassLoader c2 = ClassLoader.getSystemClassLoader(); 20 | ClassLoader c3 = Resource.class.getClassLoader(); 21 | 22 | Global.println(c1); 23 | Global.println(c2); 24 | Global.println(c3); 25 | 26 | // c1,c2,c3是同一个对象 2014-05-04 by liusan.dyf 27 | } 28 | 29 | /** 30 | * 2011-11-17 请不要以斜杠开头,ClassLoader已经是根目录了 21:44 做了容错,如果以/开头,自动去掉
31 | * 文件要放到resource目录下面 2012-07-25 32 | * 33 | * @param cl 34 | * @param name 35 | * @return 36 | */ 37 | public static InputStream getResource(ClassLoader cl, String name) { 38 | if (cl == null) 39 | cl = Thread.currentThread().getContextClassLoader(); 40 | if (cl == null) 41 | cl = ClassLoader.getSystemClassLoader(); 42 | 43 | if (Validate.isEmpty(name)) 44 | return null; 45 | 46 | char ch = name.charAt(0); 47 | if (ch == '/' || ch == '\\') 48 | name = name.substring(1); 49 | 50 | return cl.getResourceAsStream(name); 51 | } 52 | 53 | /** 54 | * 请不要以斜杠开头,ClassLoader已经是根目录了
55 | * 文件要放到resource目录下面 2012-07-25 56 | * 57 | * @param cl 58 | * @param name 59 | * @param encoding 60 | * @return 61 | */ 62 | public static String getResourceAsString(ClassLoader cl, String name, String encoding) { 63 | InputStream in = getResource(cl, name); 64 | if (in == null) 65 | return null; 66 | return streamToString(in, encoding); 67 | } 68 | 69 | /** 70 | * 从当前class的路径开始加载Resource,以【/】开头表示路径从根开始;也可以是相对目录,表示以当前class为基准目录 71 | * 72 | * @param clazz 73 | * @param name 74 | * @return 75 | */ 76 | public static InputStream getResourceByClass(Class clazz, String name) { 77 | if (clazz == null) 78 | return null; 79 | return clazz.getResourceAsStream(name); 80 | } 81 | 82 | /** 83 | * 从当前class的路径开始加载Resource,以【/】开头表示路径从根开始;也可以是相对目录,表示以当前class为基准目录 84 | * 85 | * @param clazz 86 | * @param name 87 | * @param encoding 88 | * @return 89 | */ 90 | public static String getResourceAsStringByClass(Class clazz, String name, String encoding) { 91 | InputStream in = getResourceByClass(clazz, name); 92 | if (in == null) 93 | return null; 94 | return streamToString(in, encoding); 95 | } 96 | 97 | /** 98 | * 转换为string 99 | * 100 | * @param in 101 | * @param encoding 102 | * @return 103 | */ 104 | public static String streamToString(InputStream in, String encoding) { 105 | try { 106 | BufferedReader bf = new BufferedReader(new InputStreamReader(in, encoding)); 107 | StringBuffer sb = new StringBuffer(); 108 | String s = null; 109 | boolean first = true; 110 | while ((s = bf.readLine()) != null) { 111 | if (first) 112 | first = false; 113 | else 114 | sb.append("\n"); 115 | 116 | sb.append(s); 117 | } 118 | 119 | bf.close();// 2011-11-18 120 | 121 | return sb.toString(); 122 | } catch (IOException e) { 123 | e.printStackTrace(); 124 | } 125 | 126 | return null; 127 | } 128 | 129 | /** 130 | * 根据文件流判断图片类型 http://www.cnblogs.com/Wendy_Yu/archive/2011/12/27/2303118.html
131 | * 2015-7-20 11:33:28 by liusan.dyf 132 | * 133 | * @param input 134 | * @return jpg/png/gif/bmp 135 | */ 136 | public static String detectImageType(byte[] input) { 137 | // 读取文件的前几个字节来判断图片格式 138 | byte[] b = new byte[4]; 139 | System.arraycopy(input, 0, b, 0, b.length); 140 | String type = Convert.bytesToHexString(b).toUpperCase(); 141 | 142 | if (type.contains("FFD8FF")) { 143 | return "jpg"; 144 | } else if (type.contains("89504E47")) { 145 | return "png"; 146 | } else if (type.contains("47494638")) { 147 | return "gif"; 148 | } else if (type.contains("424D")) { 149 | return "bmp"; 150 | } else { 151 | return "unkown"; 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/tools/Result.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | public class Result { 4 | private int code = -1; // 初始状态2015-4-20 14:42:29 by 六三 5 | private T value; 6 | private String message; // 2015-5-28 10:16:26 by liusan.dyf 7 | 8 | public Result() { 9 | 10 | } 11 | 12 | public Result(int c, T v) { 13 | code = c; 14 | value = v; 15 | } 16 | 17 | public Result(int c, T v, String m) { 18 | code = c; 19 | value = v; 20 | message = m; 21 | } 22 | 23 | public int getCode() { 24 | return code; 25 | } 26 | 27 | public void setCode(int code) { 28 | this.code = code; 29 | } 30 | 31 | public T getValue() { 32 | return value; 33 | } 34 | 35 | public void setValue(T value) { 36 | this.value = value; 37 | } 38 | 39 | public String getMessage() { 40 | return message; 41 | } 42 | 43 | public void setMessage(String message) { 44 | this.message = message; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/tools/SpringBeanPostPrcessor.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | @Deprecated 4 | public class SpringBeanPostPrcessor extends tools.spring.SpringBeanPostPrcessor { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/tools/SpringContext.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | @Deprecated 4 | public class SpringContext extends tools.spring.SpringContext { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/tools/StoreService.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | /** 4 | * 单一存储器,并非KEY-VALUE结构,比如ThreadLocal类似的 5 | * 6 | * @author liusan.dyf 7 | * @version 1.0 8 | * @since 2013-12-9 9 | */ 10 | public interface StoreService { 11 | /** 12 | * 删除 13 | */ 14 | void remove(); 15 | 16 | /** 17 | * 存储介质的存储string,比如cookie里、threadlocal里等 18 | * 19 | * @param value 20 | * @param seconds 21 | */ 22 | void set(T value, int seconds); 23 | 24 | /** 25 | * 从存储介质里获取序列化的string值,比如从cookie里获取 26 | * 27 | * @return 28 | */ 29 | T get(); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/tools/User.java: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 2014-05-17修改id为string类型 7 | * 8 | * @author liusan.dyf 9 | * @version 1.0 10 | * @since 2014年5月17日 11 | */ 12 | public class User { 13 | private long id; 14 | private String name; 15 | private String data; 16 | private Map extra; 17 | 18 | /** 19 | * 是否是空的user对象 2012-08-06 by liusan.dyf 20 | */ 21 | private boolean isEmpty; 22 | 23 | /** 24 | * 时间戳 2015-1-8 18:39:46 by 六三 25 | */ 26 | private long t; 27 | 28 | /** 29 | * 临时设置状态到用户对象上,比如设置已经过期 30 | */ 31 | private int status;// 2015-1-8 18:47:05 by 六三 32 | 33 | /** 34 | * 用户的一些标记 35 | */ 36 | private long tags;// 2015-4-20 20:37:50 by 六三 37 | 38 | public String getData() { 39 | return data; 40 | } 41 | 42 | public void setData(String data) { 43 | this.data = data; 44 | } 45 | 46 | public Map getExtra() { 47 | return extra; 48 | } 49 | 50 | public void setExtra(Map v) { 51 | this.extra = v; 52 | } 53 | 54 | public boolean isEmpty() { 55 | return isEmpty; 56 | } 57 | 58 | public void setEmpty(boolean isEmpty) { 59 | this.isEmpty = isEmpty; 60 | } 61 | 62 | public long getId() { 63 | return id; 64 | } 65 | 66 | public void setId(long id) { 67 | this.id = id; 68 | } 69 | 70 | public String getName() { 71 | return name; 72 | } 73 | 74 | public void setName(String name) { 75 | this.name = name; 76 | } 77 | 78 | public long getT() { 79 | return t; 80 | } 81 | 82 | public void setT(long t) { 83 | this.t = t; 84 | } 85 | 86 | public int getStatus() { 87 | return status; 88 | } 89 | 90 | public void setStatus(int status) { 91 | this.status = status; 92 | } 93 | 94 | public long getTags() { 95 | return tags; 96 | } 97 | 98 | public void setTags(long tags) { 99 | this.tags = tags; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/tools/cache/CacheItem.java: -------------------------------------------------------------------------------- 1 | package tools.cache; 2 | 3 | /** 4 | * 缓存项 http://whirlycache.googlecode.com/svn/trunk/src/java/com/whirlycott/cache/ 有参考价值 5 | * 6 | * @author liusan.dyf 7 | */ 8 | public class CacheItem { 9 | private Object value; 10 | private long cutoffTime; 11 | 12 | public CacheItem(Object value, long ttl) { 13 | this.value = value; 14 | this.cutoffTime = ttl; 15 | } 16 | 17 | public long getCutoffTime() { 18 | return cutoffTime; 19 | } 20 | 21 | public void setCutoffTime(long cutoffTime) { 22 | this.cutoffTime = cutoffTime; 23 | } 24 | 25 | public Object getValue() { 26 | return value; 27 | } 28 | 29 | public void setValue(Object value) { 30 | this.value = value; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/tools/cache/CacheProvider.java: -------------------------------------------------------------------------------- 1 | package tools.cache; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 2012-06-05 7 | * 8 | * @author liusan.dyf 9 | */ 10 | public interface CacheProvider { 11 | /** 12 | * 单位为秒 13 | * 14 | * @param key 15 | * @param value 16 | * @param ttl 17 | */ 18 | void set(String key, Object value, int ttl); 19 | 20 | /** 21 | * 清除key,返回老的结果。不存在或者过期,则返回null 22 | * 23 | * @param key 24 | * @return 25 | */ 26 | Object remove(String key); 27 | 28 | /** 29 | * 获取原始缓存的内容 30 | * 31 | * @param key 32 | * @return 33 | */ 34 | Object get(String key); 35 | 36 | int size(); 37 | 38 | Map getAll(); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/tools/cache/HashMapCacheProvider.java: -------------------------------------------------------------------------------- 1 | package tools.cache; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | import java.util.Set; 9 | import java.util.WeakHashMap; 10 | import java.util.concurrent.locks.Lock; 11 | import java.util.concurrent.locks.ReentrantLock; 12 | 13 | /** 14 | * 如果某个缓存项不被访问,则可能永远都不会被清除,直到被再次调用;否则需要借助第三方程序 2012-06-05
15 | * 默认用WeakHashMap实现 2012-09-26
16 | * 注意使用ConcurrentHashMap 17 | * 18 | * @author liusan.dyf 19 | */ 20 | public class HashMapCacheProvider implements CacheProvider { 21 | 22 | private static final int FOREVER = -1; 23 | 24 | private Map container = null; 25 | private Lock locker = new ReentrantLock(); 26 | 27 | public HashMapCacheProvider(Map container) { 28 | this.container = container; 29 | } 30 | 31 | public HashMapCacheProvider() { 32 | this(new WeakHashMap()); 33 | } 34 | 35 | /** 36 | * 2012-09-26 by liusan.dyf 37 | * 38 | * @return 39 | */ 40 | public List getAllKeys() { 41 | return new ArrayList(container.keySet()); 42 | } 43 | 44 | /** 45 | * 单位为秒,-1表示永不过期 2012-09-26 46 | */ 47 | public void set(String key, Object value, int ttl) { 48 | locker.lock(); 49 | try { 50 | long t = 0; 51 | if (ttl == FOREVER) 52 | t = FOREVER; 53 | else 54 | t = ttl * 1000 + currentTimeMillis(); 55 | 56 | // 溢出保护 2012-09-26 by liusan.dyf 57 | if (t < 0 && t != FOREVER) 58 | t = Long.MAX_VALUE; 59 | 60 | CacheItem entry = new CacheItem(value, t); 61 | getContainer().put(key, entry); 62 | } finally { 63 | locker.unlock(); 64 | } 65 | } 66 | 67 | public Map getAll() { 68 | Map rtn = new HashMap(getContainer().size()); 69 | 70 | // 遍历ConcurrentHashMap,线程安全,如果是普通的hashmap,则线程不安全 2013-11-04 by liusan.dyf 71 | Set> set = getContainer().entrySet(); 72 | 73 | for (Entry item : set) { 74 | CacheItem entry = item.getValue(); 75 | if (!isLive(entry.getCutoffTime()))// 过期的给删除 76 | remove(item.getKey()); 77 | else 78 | rtn.put(item.getKey(), entry.getValue());// 未过期的返回 79 | } 80 | 81 | return rtn; 82 | } 83 | 84 | public Object remove(String key) { 85 | locker.lock(); 86 | try { 87 | CacheItem entry = getContainer().remove(key); 88 | 89 | if (entry != null) 90 | return entry.getValue(); 91 | 92 | return null; 93 | } finally { 94 | locker.unlock(); 95 | } 96 | } 97 | 98 | public int size() { 99 | locker.lock(); 100 | try { 101 | return getContainer().size(); 102 | } finally { 103 | locker.unlock(); 104 | } 105 | } 106 | 107 | public Object get(String key) { 108 | CacheItem item = null; 109 | locker.lock(); 110 | try { 111 | item = getContainer().get(key); 112 | } finally { 113 | locker.unlock(); 114 | } 115 | 116 | if (item == null)// 不包含该key 117 | return null; 118 | else { 119 | if (!isLive(item.getCutoffTime())) { 120 | // 已经过期了,要清除掉 121 | remove(key); 122 | } else 123 | return item.getValue(); 124 | } 125 | 126 | return null; 127 | } 128 | 129 | private long currentTimeMillis() { 130 | return System.currentTimeMillis(); 131 | } 132 | 133 | public Map getContainer() { 134 | return container; 135 | } 136 | 137 | public void setContainer(Map container) { 138 | this.container = container; 139 | } 140 | 141 | private boolean isLive(long t) { 142 | if (t == FOREVER) 143 | return true; 144 | else 145 | return t >= currentTimeMillis(); 146 | } 147 | 148 | public static void main(String[] args) { 149 | System.out.println(Integer.MAX_VALUE); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/tools/code/RunTimer.java: -------------------------------------------------------------------------------- 1 | package tools.code; 2 | 3 | public class RunTimer { 4 | /** 5 | * 运行 6 | * 7 | * @param name 8 | * @param times 9 | * @param job 10 | * @return 11 | */ 12 | public long run(String name, int times, Runnable job) { 13 | if (times <= 0) // fix 2011-11-02 by 63 14 | return 0; 15 | 16 | // long start = System.currentTimeMillis(); 17 | long startNano = System.nanoTime(); 18 | 19 | for (int i = 0; i < times; i++) 20 | job.run(); 21 | 22 | // long rtn = System.currentTimeMillis() - start; 23 | Double rtn = (System.nanoTime() - startNano) * 1e-6; 24 | 25 | System.out.println(name + " for " + times + " times"); 26 | System.out.println("all time: " + rtn); 27 | System.out.println("per time: " + rtn / times + "\n");// 2014-12-23 10:36:26 by 六三 28 | 29 | return rtn.longValue(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/tools/concurrent/BatchQueue.java: -------------------------------------------------------------------------------- 1 | package tools.concurrent; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.BlockingQueue; 6 | import java.util.concurrent.LinkedBlockingQueue; 7 | import java.util.concurrent.TimeUnit; 8 | import org.apache.commons.logging.Log; 9 | import org.apache.commons.logging.LogFactory; 10 | 11 | import tools.Predicate; 12 | 13 | /** 14 | * 延迟、批量队列;一旦队列停止了,就无法再启用,因为负责拉取队列数据的线程已经销毁了 2014-05-21 15 | * 16 | * @author liusan.dyf 17 | * @version 1.0 18 | * @since 2014-3-22 19 | */ 20 | public class BatchQueue extends tools.InitializeOnce { 21 | private static final Log logger = LogFactory.getLog("system"); 22 | 23 | private BlockingQueue q = new LinkedBlockingQueue();// 阻塞队列 24 | private int batchSize = 100;// 批次大小 25 | private int timeout = 10;// 超时时间 26 | private String name = null;// 名称 27 | private Thread workingThread = null;// 执行的线程 28 | private Predicate> callback = null;// 批次的回调 29 | private boolean working = true;// 是否还在工作 2014-04-17 30 | 31 | @Override 32 | protected void doInitialize() { 33 | // 检查参数 34 | if (batchSize <= 0) 35 | throw new IllegalArgumentException("batchSize不能小于等于0"); 36 | 37 | if (getTimeout() <= 0) 38 | throw new IllegalArgumentException("timeout不能小于等于0"); 39 | 40 | if (name == null) 41 | throw new IllegalArgumentException("name不能为null"); 42 | 43 | if (callback == null) 44 | throw new IllegalArgumentException("callback不能为null"); 45 | 46 | // 创建线程 47 | workingThread = new Thread(new Runnable() { 48 | @Override 49 | public void run() { 50 | while (true) { 51 | if (!working) 52 | break;// 2014-04-17 by liusan.dyf 53 | 54 | int nums = 0;// 数 55 | 56 | List list = new ArrayList(batchSize); 57 | 58 | boolean isTimeout = false; 59 | for (int i = 0; i < getBatchSize(); i++) { 60 | try { 61 | T entry = q.poll(getTimeout(), TimeUnit.MILLISECONDS);// 这里有超时 62 | if (entry != null) { 63 | nums++; 64 | list.add(entry); 65 | } else { 66 | // 取不到数据了,立即提交 2014-02-24 by liusan.dyf 67 | break; 68 | } 69 | } catch (InterruptedException e) { 70 | logger.error("poll error", e); 71 | // break;// 等一段时间拉取不到,就提交 2014-01-21 by liusan.dyf 72 | 73 | isTimeout = true; 74 | } 75 | 76 | if (isTimeout) 77 | break;// 跳出for 78 | }// end for 79 | 80 | // 开始提交 81 | if (nums == 0) 82 | continue; 83 | 84 | // 注意try-catch,可能会执行失败 85 | try { 86 | // long startMs = System.currentTimeMillis(); 87 | boolean f = callback.execute(list); 88 | 89 | if (!f) { 90 | // TODO 执行失败了 91 | } else { 92 | // logger.warn("BatchQueueExecute:nums=" + nums + ",left=" + q.size()); // 2014-07-14 93 | } 94 | // logger.warn("成功execute,took=" + (System.currentTimeMillis() - startMs) + ",size=" + nums); 95 | } catch (Throwable e) { 96 | // logger.error("batch execute error", e); 97 | } 98 | 99 | }// end while true 100 | } 101 | }); 102 | 103 | workingThread.setName(getName() + "_working_thread"); 104 | workingThread.setDaemon(true); 105 | workingThread.start(); 106 | } 107 | 108 | public void insert(T entry) { 109 | checkStatus(); 110 | 111 | if (entry == null) 112 | return; 113 | 114 | try { 115 | q.put(entry); 116 | } catch (InterruptedException e) { 117 | throw new RuntimeException(e); 118 | } 119 | } 120 | 121 | public void insert(List list) { 122 | checkStatus(); 123 | 124 | if (list == null) 125 | return; 126 | 127 | for (T item : list) 128 | insert(item); 129 | } 130 | 131 | private void checkStatus() { 132 | if (!this.working) 133 | throw new RuntimeException("队列已经停止了"); 134 | } 135 | 136 | /** 137 | * 2014-05-21 by liusan.dyf 138 | */ 139 | public void stop() { 140 | if (!this.isInitialized()) 141 | throw new RuntimeException("还未初始化,无法停止"); 142 | 143 | checkStatus(); 144 | 145 | this.working = false; 146 | } 147 | 148 | public int size() { 149 | return q.size();// 2014-07-14 by liusan.dyf 150 | } 151 | 152 | public int getBatchSize() { 153 | return batchSize; 154 | } 155 | 156 | public void setBatchSize(int batchSize) { 157 | this.batchSize = batchSize; 158 | } 159 | 160 | public String getName() { 161 | return name; 162 | } 163 | 164 | public void setName(String name) { 165 | this.name = name; 166 | } 167 | 168 | public Predicate> getCallback() { 169 | return callback; 170 | } 171 | 172 | public void setCallback(Predicate> callback) { 173 | this.callback = callback; 174 | } 175 | 176 | public int getTimeout() { 177 | return timeout; 178 | } 179 | 180 | public void setTimeout(int timeout) { 181 | this.timeout = timeout; 182 | } 183 | 184 | public boolean isWorking() { 185 | return working; 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/main/java/tools/counter/AtomicKeyedCounter.java: -------------------------------------------------------------------------------- 1 | package tools.counter; 2 | 3 | import java.util.HashMap; 4 | import java.util.Iterator; 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | import java.util.concurrent.atomic.AtomicLong; 8 | 9 | public class AtomicKeyedCounter implements MultiKeyedCounter { 10 | private Map counters = new ConcurrentHashMap(); 11 | 12 | protected AtomicLong getCounter(String key) { 13 | AtomicLong v = counters.get(key); 14 | if (v == null) { 15 | /* 16 | * 如果你只调用get(),或只调用put()时,ConcurrentHashMap是线程安全的。但是,在你调用完get后,调用put之前,如果有另外一个线程调用了map.put(name, x), 17 | * 你再去执行map.put(name,x),就很可能把前面的操作结果覆盖掉了。所以,即使在线程安全的情况下,你还是有可能违反原子操作的规则。 18 | */ 19 | synchronized (counters) { 20 | if (!counters.containsKey(key)) { 21 | v = new AtomicLong(); 22 | counters.put(key, v); 23 | } else 24 | // 2012-02-27 25 | v = counters.get(key); 26 | } 27 | } 28 | 29 | return v; 30 | } 31 | 32 | @Override 33 | public long get(String key) { 34 | return getCounter(key).get(); 35 | } 36 | 37 | @Override 38 | public long set(String key, long v) { 39 | return getCounter(key).getAndSet(v); 40 | } 41 | 42 | @Override 43 | public long increment(String key) { 44 | return getCounter(key).addAndGet(1); 45 | } 46 | 47 | @Override 48 | public long decrement(String key) { 49 | return getCounter(key).decrementAndGet(); 50 | } 51 | 52 | @Override 53 | public long increment(String key, long v) { 54 | return getCounter(key).addAndGet(v); 55 | } 56 | 57 | @Override 58 | public long decrement(String key, long v) { 59 | return getCounter(key).addAndGet(0 - v); 60 | } 61 | 62 | @Override 63 | public Map getAll() { 64 | Map rtn = new HashMap(counters.size()); 65 | 66 | /** 67 | * 有可能在此时,counters里又增加了新的KV,这样就会有java.util.ConcurrentModificationException 2013-07-17 by liusan.dyf 68 | */ 69 | // Set> set = counters.entrySet(); 70 | // for (Entry item : set) { 71 | // rtn.put(item.getKey(), item.getValue().get()); 72 | // } 73 | 74 | Iterator iterator = counters.keySet().iterator(); 75 | 76 | String key = null; 77 | AtomicLong value = null; 78 | while (iterator.hasNext()) { 79 | key = iterator.next(); 80 | value = counters.get(key); 81 | 82 | if (value != null) 83 | rtn.put(key, value.get()); 84 | } 85 | 86 | return rtn; 87 | } 88 | 89 | /** 90 | * 该方法目前只支持v=0的情况 91 | */ 92 | @Override 93 | public Map setAll(long v) { 94 | // Map rtn = new HashMap(counters.size()); 95 | // 96 | // Set> set = counters.entrySet(); 97 | // for (Entry item : set) { 98 | // rtn.put(item.getKey(), item.getValue().getAndSet(v)); 99 | // } 100 | // 101 | // return rtn; 102 | 103 | // 2012-05-31 by liusan.dyf 104 | // 防止某个时间段,提交的计数太多,内存hash表被撑爆,而且一直得不到清理,这里直接清理掉 105 | 106 | Map rtn = getAll(); 107 | 108 | synchronized (counters) { 109 | counters.clear(); 110 | } 111 | 112 | return rtn; 113 | } 114 | 115 | public static void main(String[] args) { 116 | final MultiKeyedCounter c = new AtomicKeyedCounter(); 117 | String key = "myc"; 118 | long i = 0; 119 | i = c.increment(key, 102); 120 | i = c.decrement(key);// c.decrement(key, 10); 121 | System.out.println(c.get(key)); 122 | 123 | c.setAll(9); 124 | System.out.println(c.increment(key)); 125 | 126 | AtomicLong l = new AtomicLong(Long.MAX_VALUE); 127 | i = l.incrementAndGet(); 128 | System.out.println(i); 129 | 130 | // 性能测试 131 | tools.code.RunTimer run = new tools.code.RunTimer(); 132 | run.run("x", 10000000, new Runnable() { 133 | @Override 134 | public void run() { 135 | c.increment("key");// 511 136 | } 137 | }); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/tools/counter/AtomicLongArrayCounter.java: -------------------------------------------------------------------------------- 1 | package tools.counter; 2 | 3 | import java.util.concurrent.atomic.AtomicLongArray; 4 | 5 | /** 6 | * 初始化一个大小固定为size的AtomicLongArray 7 | * 8 | * @author liusan.dyf 9 | * @version 1.0 10 | * @since 2014年11月7日 11 | */ 12 | public class AtomicLongArrayCounter { 13 | public static final int INVALID_VALUE = -1; 14 | 15 | private int size = 1024; 16 | private AtomicLongArray ala = null;// 计数器的数组 17 | 18 | public AtomicLongArrayCounter(int size) { 19 | if (size <= 0) 20 | throw new IllegalArgumentException("size不能小于等于0"); 21 | 22 | this.size = size; 23 | 24 | ala = new AtomicLongArray(size); 25 | } 26 | 27 | private boolean checkSize(int i) { 28 | return i >= 0 && i < getSize(); 29 | } 30 | 31 | public long get(int i) { 32 | if (checkSize(i)) { 33 | return ala.get(i); 34 | } 35 | 36 | return INVALID_VALUE; 37 | } 38 | 39 | public long addAndGet(int i, int delta) { 40 | if (checkSize(i)) { 41 | return ala.addAndGet(i, delta); 42 | } 43 | 44 | return INVALID_VALUE; 45 | } 46 | 47 | public long getAndAdd(int i, int delta) { 48 | if (checkSize(i)) { 49 | return ala.getAndAdd(i, delta); 50 | } 51 | 52 | return INVALID_VALUE; 53 | } 54 | 55 | public long incrementAndGet(int i) { 56 | if (checkSize(i)) { 57 | return ala.incrementAndGet(i); 58 | } 59 | 60 | return INVALID_VALUE; 61 | } 62 | 63 | public long getAndSet(int i, int newValue) { 64 | if (checkSize(i)) { 65 | return ala.getAndSet(i, newValue); 66 | } 67 | 68 | return INVALID_VALUE; 69 | } 70 | 71 | public int getSize() { 72 | return size; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/tools/counter/MultiKeyedCounter.java: -------------------------------------------------------------------------------- 1 | package tools.counter; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * multivalued,除了get方法外,其他返回int的都表示是操作后的结果 2012-02-16 7 | * 8 | * @author liusan.dyf 9 | */ 10 | public interface MultiKeyedCounter { 11 | /** 12 | * 获取当前的值 13 | * 14 | * @param key 15 | * @return 16 | */ 17 | long get(String key); 18 | 19 | /** 20 | * 获取当前已经存储的所有的计数器 21 | * 22 | * @return 23 | */ 24 | Map getAll(); 25 | 26 | /** 27 | * 设置新值,并返回旧值 28 | * 29 | * @param key 30 | * @param v 31 | * @return 32 | */ 33 | long set(String key, long v); 34 | 35 | /** 36 | * 设置全部的计数器以新值,并返回旧值 37 | * 38 | * @param v 39 | * @return 40 | */ 41 | Map setAll(long v); 42 | 43 | /** 44 | * 计数器加1,返回新值 45 | * 46 | * @param key 47 | * @return 48 | */ 49 | long increment(String key); 50 | 51 | /** 52 | * 计数器减1,返回新值 53 | * 54 | * @param key 55 | * @return 56 | */ 57 | long decrement(String key); 58 | 59 | /** 60 | * 计数器加v,返回新值 61 | * 62 | * @param key 63 | * @param v 64 | * @return 65 | */ 66 | long increment(String key, long v); 67 | 68 | /** 69 | * 计数器减v,返回新值 70 | * 71 | * @param key 72 | * @param v 73 | * @return 74 | */ 75 | long decrement(String key, long v); 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/tools/counter/RedisKeyedCounter.txt: -------------------------------------------------------------------------------- 1 | package tools.counter; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Set; 6 | import java.util.Map.Entry; 7 | import redis.clients.jedis.Jedis; 8 | import redis.clients.jedis.JedisPool; 9 | 10 | public class RedisKeyedCounter implements MultiKeyedCounter { 11 | private String system; 12 | private JedisPool pool; 13 | 14 | public RedisKeyedCounter(String system, JedisPool pool) { 15 | this.system = system; 16 | this.pool = pool; 17 | } 18 | 19 | @Override 20 | public long get(String key) { 21 | Jedis client = pool.getResource(); 22 | try { 23 | return tools.Convert.toLong(client.hget(system, key), 0); 24 | } finally { 25 | pool.returnResource(client); 26 | } 27 | } 28 | 29 | @Override 30 | public long set(String key, long v) { 31 | Jedis client = pool.getResource(); 32 | try { 33 | long i = get(key); 34 | client.hset(system, key, String.valueOf(v)); 35 | return i; 36 | } finally { 37 | pool.returnResource(client); 38 | } 39 | } 40 | 41 | @Override 42 | public long increment(String key) { 43 | return increment(key, 1); 44 | } 45 | 46 | @Override 47 | public long decrement(String key) { 48 | return decrement(key, 1); 49 | } 50 | 51 | @Override 52 | public long increment(String key, long v) { 53 | Jedis client = pool.getResource(); 54 | try { 55 | return tools.Convert.toInt(client.hincrBy(system, key, v), 0); 56 | } finally { 57 | pool.returnResource(client); 58 | } 59 | } 60 | 61 | @Override 62 | public long decrement(String key, long v) { 63 | Jedis client = pool.getResource(); 64 | try { 65 | return tools.Convert.toInt(client.hincrBy(system, key, 0 - v), 0); 66 | } finally { 67 | pool.returnResource(client); 68 | } 69 | } 70 | 71 | @Override 72 | public Map getAll() { 73 | Jedis client = pool.getResource(); 74 | try { 75 | // 从redis里获取 76 | Map r = client.hgetAll(system); 77 | 78 | // 加工数据 79 | Map rtn = new HashMap(); 80 | 81 | Set> set = r.entrySet(); 82 | for (Entry item : set) { 83 | rtn.put(item.getKey(), tools.Convert.toLong(item.getValue(), 0)); 84 | } 85 | 86 | return rtn; 87 | } finally { 88 | pool.returnResource(client); 89 | } 90 | } 91 | 92 | @Override 93 | public Map setAll(long v) { 94 | Jedis client = pool.getResource(); 95 | try { 96 | // 从redis里获取 97 | Map r = client.hgetAll(system); 98 | 99 | // 加工数据 100 | Map rtn = new HashMap(); 101 | 102 | Set> set = r.entrySet(); 103 | for (Entry item : set) { 104 | rtn.put(item.getKey(), tools.Convert.toLong(item.getValue(), 0)); 105 | 106 | // 设置新值 107 | client.hset(system, item.getKey(), String.valueOf(v)); 108 | } 109 | 110 | return rtn; 111 | } finally { 112 | pool.returnResource(client); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/tools/counter/TimedAtomicKeyedCounter.java: -------------------------------------------------------------------------------- 1 | package tools.counter; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | import java.util.concurrent.atomic.AtomicLong; 6 | 7 | /** 8 | * 如果计数器过期了,则重新从0开始计数 9 | * 10 | * @author liusan.dyf 11 | * @version 1.0 12 | * @since 2012-11-29 13 | */ 14 | public class TimedAtomicKeyedCounter extends AtomicKeyedCounter { 15 | private Map cutoffs = new ConcurrentHashMap(); 16 | 17 | private long getTs(int ttl) { 18 | return System.currentTimeMillis() + ttl * 1000; 19 | } 20 | 21 | @Override 22 | protected AtomicLong getCounter(String key) { 23 | AtomicLong v = super.getCounter(key); 24 | 25 | // 判断时间是否过期 26 | if (cutoffs.containsKey(key)) { 27 | Cutoff entry = cutoffs.get(key); 28 | if (System.currentTimeMillis() >= entry.getCurrent()) { 29 | // 重新设置过期时间,并清空计数器 30 | entry.setCurrent(getTs(entry.getTtl())); 31 | v.set(0); 32 | } 33 | } 34 | return v; 35 | } 36 | 37 | public void setTtl(String key, int ttl) { 38 | Cutoff entry = cutoffs.get(key); 39 | if (entry == null || entry.getTtl() != ttl) { 40 | if (entry == null) 41 | entry = new Cutoff(); 42 | 43 | entry.setTtl(ttl); 44 | entry.setCurrent(getTs(ttl)); 45 | cutoffs.put(key, entry); 46 | } // else 47 | // System.out.println("设置ttl无效"); 48 | } 49 | 50 | /** 51 | * 2012-11-30 by liusan.dyf,设置过期时间 52 | * 53 | * @param key 54 | * @param value 55 | */ 56 | public void setCutoff(String key, long value) { 57 | int ttl = (int) ((value - System.currentTimeMillis()) / 1000); 58 | 59 | setTtl(key, ttl); 60 | } 61 | 62 | public static void main(String[] args) { 63 | final TimedAtomicKeyedCounter c = new TimedAtomicKeyedCounter(); 64 | final String key = "myc"; 65 | 66 | c.setTtl(key, 1); 67 | c.setTtl(key, 2); 68 | 69 | for (int i = 0; i < 10; i++) { 70 | System.out.println("got:" + c.increment(key)); 71 | try { 72 | Thread.sleep(100); 73 | } catch (InterruptedException e) { 74 | } 75 | } 76 | 77 | // 多线程测试ranged 78 | int count = 20; 79 | Thread[] array = new Thread[count]; 80 | for (int i = 0; i < count; i++) { 81 | Thread th = new Thread(new Runnable() { 82 | @Override 83 | public void run() { 84 | for (int x = 0; x < 10; x++) { 85 | System.out.println(c.increment(key)); 86 | 87 | try { 88 | Thread.sleep(200); 89 | } catch (InterruptedException e) { 90 | } 91 | } 92 | } 93 | }); 94 | 95 | th.setDaemon(true); 96 | th.setName("thread_" + i); 97 | 98 | th.start(); 99 | 100 | array[i] = th; 101 | } 102 | 103 | // 等待线程关闭 104 | for (int i = 0; i < count; i++) { 105 | try { 106 | array[i].join(); 107 | } catch (InterruptedException e) { 108 | System.out.println(e); 109 | } 110 | } 111 | } 112 | 113 | static class Cutoff { 114 | private long current; 115 | private int ttl; 116 | 117 | public long getCurrent() { 118 | return current; 119 | } 120 | 121 | public void setCurrent(long current) { 122 | this.current = current; 123 | } 124 | 125 | public int getTtl() { 126 | return ttl; 127 | } 128 | 129 | public void setTtl(int ttl) { 130 | this.ttl = ttl; 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/tools/event/EventArgs.java: -------------------------------------------------------------------------------- 1 | package tools.event; 2 | 3 | import java.util.HashMap; 4 | 5 | public class EventArgs { 6 | private final static String MAIN_KEY = "main"; 7 | private final static String TYPE_KEY = "type"; 8 | 9 | private final HashMap data = new HashMap(); 10 | 11 | /** 12 | * event的type,比如hook的名称 2012-06-01 13 | */ 14 | // private String type; 15 | 16 | public static EventArgs create(Object main) { 17 | EventArgs rtn = new EventArgs(); 18 | rtn.set(MAIN_KEY, main); 19 | return rtn; 20 | } 21 | 22 | /* 主对象getter and setter */ 23 | 24 | public Object getMainObject() { 25 | return get(MAIN_KEY); 26 | } 27 | 28 | public EventArgs setMainObject(Object main) { 29 | return set(MAIN_KEY, main); 30 | } 31 | 32 | /* 普通 */ 33 | 34 | public Object get(String key) { 35 | return this.data.get(key); 36 | } 37 | 38 | public EventArgs set(String key, Object value) { 39 | this.data.put(key, value); 40 | return this; 41 | } 42 | 43 | public String getType() { 44 | Object v = get(TYPE_KEY); 45 | if (v == null) 46 | return null; 47 | return v.toString(); 48 | } 49 | 50 | public EventArgs setType(String type) { 51 | return set(TYPE_KEY, type); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/tools/event/EventContainer.java: -------------------------------------------------------------------------------- 1 | package tools.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | public class EventContainer { 8 | private Map> handlers = null; 9 | 10 | /** 11 | * 2012-06-01 by liusan.dyf map的key= hook name 12 | */ 13 | public Map> getHandlers() { 14 | return handlers; 15 | } 16 | 17 | public int size() { 18 | if (handlers != null) 19 | return handlers.size(); 20 | 21 | return 0; 22 | } 23 | 24 | public void clearAll() { 25 | if (handlers != null) 26 | handlers.clear(); 27 | } 28 | 29 | /** 30 | * 清理掉一个hook下的所有的EventHandler 2013-12-16 by liusan.dyf 31 | * 32 | * @param hook 33 | */ 34 | public void clearHandlers(String hook) { 35 | if (handlers != null) 36 | handlers.remove(hook); 37 | } 38 | 39 | /** 40 | * 2013-12-16 by liusan.dyf 41 | * 42 | * @param hook 43 | * @param handler 44 | */ 45 | public void addHandler(String hook, EventHandler handler) { 46 | // 2013-12-16 by liusan.dyf 47 | if (handlers == null) 48 | handlers = tools.MapUtil.create(); 49 | 50 | // 查找事件 51 | List list = handlers.get(hook); 52 | if (list == null) 53 | list = new ArrayList(); 54 | 55 | list.add(handler); 56 | 57 | handlers.put(hook, list); 58 | } 59 | 60 | public void setHandlers(Map> v) { 61 | this.handlers = v; 62 | } 63 | 64 | /** 65 | * 通过EventArgs的type属性来查找注册的事件列表 2012-07-05 66 | * 67 | * @param sender 68 | * @param args 69 | */ 70 | public void onEvent(Object sender, EventArgs args) { 71 | if (args == null || handlers == null) 72 | return; 73 | 74 | // 是否存在type 2012-07-05 75 | String hook = args.getType(); 76 | if (hook == null) 77 | return; 78 | 79 | execute(hook, sender, args); 80 | execute("*", sender, args);// 2012-08-02 81 | } 82 | 83 | private void execute(String hook, Object sender, EventArgs args) { 84 | // 查找事件 85 | List list = handlers.get(hook); 86 | if (list == null) 87 | return; 88 | 89 | // 循环执行 90 | for (EventHandler item : list) 91 | item.fire(sender, args); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/tools/event/EventHandler.java: -------------------------------------------------------------------------------- 1 | package tools.event; 2 | 3 | public interface EventHandler { 4 | /** 5 | * 要设置args.type属性,这是hook点,一来可以在event holder里找到注册的事件列表;二来也表示了事件本身的类型 6 | * 7 | * @param sender 8 | * @param args 9 | */ 10 | void fire(Object sender, EventArgs args); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/tools/generator/AtomicIdGenerator.java: -------------------------------------------------------------------------------- 1 | package tools.generator; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | 5 | /** 6 | * 基于原子计数的id生成器 7 | * 8 | * @author liusan.dyf 9 | * @version 1.0 10 | * @since 2012-11-6 11 | */ 12 | public class AtomicIdGenerator implements IdGenerator { 13 | 14 | /** 15 | * 默认id的存储,是向前存储的;如果向后存储,若buffer还没有消费完,此时系统重启,则下次可能重复 2011-12-28 16 | */ 17 | private boolean storeForward = true; 18 | 19 | private String key; 20 | 21 | /** 22 | * 增量 23 | */ 24 | private int increment = 1;// 2011-02-23 增加 by 杜有发 25 | 26 | /** 27 | * 2010-08-11增加 28 | */ 29 | private int bufferSize = 20; 30 | 31 | /** 32 | * 数据存储 2010-12-23 33 | */ 34 | private DataStore dataStore; 35 | 36 | private AtomicLong atomicId; 37 | 38 | /** 39 | * 操作计数 40 | */ 41 | private AtomicLong counter = new AtomicLong(0); 42 | 43 | public AtomicIdGenerator(String key, DataStore dataStore) { 44 | this(key, dataStore, 0, 0); 45 | } 46 | 47 | public AtomicIdGenerator(String key, DataStore dataStore, int bufferSize, int increment) { 48 | this.dataStore = dataStore; 49 | this.key = key; 50 | 51 | if (bufferSize > 0) 52 | this.bufferSize = bufferSize; 53 | 54 | if (increment != 0) 55 | this.increment = increment; 56 | 57 | init(); 58 | } 59 | 60 | @Override 61 | public long current() { 62 | return atomicId.get(); 63 | } 64 | 65 | @Override 66 | public void init() { 67 | // 初始化atomicId 68 | long currentId = 0; 69 | 70 | if (dataStore != null) 71 | currentId = dataStore.get(key); 72 | 73 | atomicId = new AtomicLong(currentId); 74 | } 75 | 76 | @Override 77 | public long next() { 78 | long v = atomicId.addAndGet(increment); 79 | 80 | // 计数器 81 | long count = counter.incrementAndGet(); 82 | // if (counter.compareAndSet(count, count + 1)) { 83 | if ((count % bufferSize) == 0) { 84 | save(v); 85 | } 86 | // } 87 | 88 | return v; 89 | } 90 | 91 | private void save(long v) { 92 | if (dataStore != null) 93 | dataStore.set(getKey(), storeForward ? (v + (bufferSize - 1) * increment) : v); 94 | } 95 | 96 | @Override 97 | public String next(int count) { 98 | while (true) { 99 | long startId = next(); 100 | long lastId = startId + increment * count; 101 | if (atomicId.compareAndSet(startId, lastId)) { 102 | 103 | // if (count >= bufferSize) 104 | save(lastId); 105 | 106 | return startId + ":" + increment + ":" + count; 107 | } 108 | } 109 | } 110 | 111 | @Override 112 | public String getKey() { 113 | return key; 114 | } 115 | 116 | @Override 117 | public synchronized void setInitialValue(long value) { 118 | long v = 0; 119 | while (true) { 120 | v = atomicId.get(); 121 | if (atomicId.compareAndSet(v, value)) 122 | return; 123 | } 124 | } 125 | 126 | public void setKey(String key) { 127 | this.key = key; 128 | } 129 | 130 | public DataStore getDataStore() { 131 | return dataStore; 132 | } 133 | 134 | public void setDataStore(DataStore dataStore) { 135 | this.dataStore = dataStore; 136 | } 137 | 138 | public int getBufferSize() { 139 | return bufferSize; 140 | } 141 | 142 | public void setBufferSize(int bufferSize) { 143 | this.bufferSize = bufferSize; 144 | } 145 | 146 | public int getIncrement() { 147 | return increment; 148 | } 149 | 150 | public void setIncrement(int increment) { 151 | this.increment = increment; 152 | } 153 | 154 | public static void main(String[] args) { 155 | AtomicIdGenerator g = new AtomicIdGenerator("id", new FileDataStore("d:/data\\temp")); 156 | 157 | for (int i = 0; i < 50; i++) { 158 | long id = g.next(); 159 | System.out.println(id); 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/tools/generator/DataStore.java: -------------------------------------------------------------------------------- 1 | package tools.generator; 2 | 3 | public interface DataStore { 4 | long get(String key); 5 | 6 | boolean set(String key, long value); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/tools/generator/FileDataStore.java: -------------------------------------------------------------------------------- 1 | package tools.generator; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.net.MalformedURLException; 8 | import java.net.URL; 9 | 10 | import org.apache.commons.io.IOUtils; 11 | 12 | import tools.Convert; 13 | import tools.Validate; 14 | 15 | /** 16 | * 依赖于commons-io 2011-11-07 17 | * 18 | * @author liusan.dyf 19 | */ 20 | public class FileDataStore implements DataStore { 21 | 22 | private String baseDirectory; 23 | private static final String ENCODING = "utf-8"; 24 | 25 | public FileDataStore(String baseDirectory) { 26 | // 检查 27 | if (Validate.isEmpty(baseDirectory)) 28 | throw new IllegalArgumentException("baseDirectory属性不能为空"); 29 | baseDirectory = baseDirectory.replace("\\", "/"); 30 | this.baseDirectory = baseDirectory; 31 | 32 | File f = new File(baseDirectory); 33 | if (f.exists()) { 34 | if (!f.isDirectory()) 35 | throw new IllegalArgumentException("baseDirectory必须要是合法的目录"); 36 | } else 37 | // 创建目录 38 | f.mkdirs(); 39 | } 40 | 41 | @Override 42 | public long get(String key) { 43 | String filePath = getFilePath(key); 44 | 45 | File f = new File(filePath); 46 | if (!f.exists()) 47 | return 0; 48 | try { 49 | // 可能不支持unix系统 50 | @SuppressWarnings("deprecation") 51 | String v = IOUtils.toString(new URL("file:///" + filePath)); 52 | return Convert.toLong(v, 0); 53 | } catch (MalformedURLException e) { 54 | e.printStackTrace(); 55 | } catch (IOException e) { 56 | e.printStackTrace(); 57 | } 58 | return 0; 59 | } 60 | 61 | @Override 62 | public boolean set(String key, long value) { 63 | String filePath = getFilePath(key); 64 | File f = new File(filePath); 65 | try { 66 | if (!f.exists()) 67 | f.createNewFile(); 68 | 69 | FileOutputStream s = new FileOutputStream(f); 70 | IOUtils.write(String.valueOf(value), s, ENCODING); 71 | s.flush(); 72 | s.close(); 73 | 74 | // java.io.FileNotFoundException: d:\data\temp\id.txt 75 | // (另一个程序正在使用此文件,进程无法访问。) 76 | 77 | // System.out.println("saved"); 78 | } catch (FileNotFoundException e) { 79 | e.printStackTrace(); 80 | } catch (IOException e) { 81 | e.printStackTrace(); 82 | } 83 | 84 | return true; 85 | } 86 | 87 | private String getFilePath(String key) { 88 | if (baseDirectory.endsWith("/")) 89 | return baseDirectory + key + ".txt"; 90 | else 91 | return baseDirectory + "/" + key + ".txt"; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/tools/generator/IdGenerator.java: -------------------------------------------------------------------------------- 1 | package tools.generator; 2 | 3 | /** 4 | * Numberic 5 | * 6 | * @author liusan.dyf 7 | */ 8 | public interface IdGenerator { 9 | long current(); 10 | 11 | /** 12 | * 会在程序里预先调用,所以提取为接口的一个方法 13 | */ 14 | void init(); 15 | 16 | long next(); 17 | 18 | /** 19 | * 返回【起始id:增量:次数】,包含起始id 适合大批量情况下 20 | * 21 | * @param count 22 | * @return 23 | */ 24 | String next(int count); 25 | 26 | /** 27 | * 2012-02-12 28 | * 29 | * @return 30 | */ 31 | String getKey(); 32 | 33 | /** 34 | * 生成的id从value + increment开始 35 | * 36 | * @param value 37 | */ 38 | void setInitialValue(long value); 39 | 40 | /** 41 | * 得到增长的步长 2012-11-14 by liusan.dyf 42 | * 43 | * @return 44 | */ 45 | int getIncrement(); 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/tools/generator/ranged/Range.java: -------------------------------------------------------------------------------- 1 | package tools.generator.ranged; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * (min,max】 8 | * 9 | * @author liusan.dyf 10 | */ 11 | public class Range { 12 | private long min; 13 | private long max; 14 | 15 | public Range(long min, long max) { 16 | if (min > max) 17 | throw new IllegalArgumentException("min can not greater then max"); 18 | setMin(min); 19 | setMax(max); 20 | } 21 | 22 | public long getMin() { 23 | return min; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return "Range (min=" + min + ", max=" + max + "]"; 29 | } 30 | 31 | public void setMin(long v) { 32 | this.min = v; 33 | } 34 | 35 | public long getMax() { 36 | return max; 37 | } 38 | 39 | public void setMax(long v) { 40 | this.max = v; 41 | } 42 | 43 | public long length() { 44 | return (this.max - this.min + 1); 45 | } 46 | 47 | /** 48 | * 划分区间 49 | * 50 | * @param range 51 | * @param size 52 | * @return 53 | */ 54 | public static List div(Range range, int size) { 55 | if (range == null) 56 | return new ArrayList(0); 57 | if (size < 1) 58 | throw new IllegalArgumentException("size can not be less then 1"); 59 | 60 | long min = range.getMin(); 61 | long max = range.getMax(); 62 | 63 | // 计算会有多少个区间 64 | long d = max - min + 1; 65 | long len = d % size; 66 | if (len == 0) 67 | len = d / size; 68 | else 69 | len = d / size + 1; 70 | 71 | // System.out.println(len); 72 | 73 | ArrayList list = new ArrayList((int) len); 74 | 75 | while (min <= max) {// 注意条件是<= 76 | long mx = min + size - 1; 77 | if (mx > max) { 78 | list.add(new Range(min, max)); 79 | break; 80 | } 81 | 82 | list.add(new Range(min, mx)); 83 | min += size; 84 | } 85 | return list; 86 | } 87 | } 88 | // Range [min=1, max=3] 89 | // Range [min=4, max=6] 90 | // Range [min=7, max=9] 91 | // Range [min=10, max=10] 92 | -------------------------------------------------------------------------------- /src/main/java/tools/generator/ranged/RangeGenerator.java: -------------------------------------------------------------------------------- 1 | package tools.generator.ranged; 2 | 3 | /** 4 | * 根据key来生成一个id范围 5 | * 6 | * @author liusan.dyf 7 | */ 8 | public interface RangeGenerator { 9 | /** 10 | * 确保线程安全,且每次的range都不一样 2012-11-20 by liusan.dyf 11 | * 12 | * @param key 13 | * @return 14 | */ 15 | Range next(String key); 16 | 17 | /** 18 | * 得到当前的range,2012-01-04 19 | * 20 | * @param key 21 | * @return 22 | */ 23 | Range current(String key); 24 | 25 | /** 26 | * 2012-02-12,保存区间,给current使用 27 | * 28 | * @param key 29 | * @return 30 | */ 31 | boolean save(String key, Range g); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/tools/generator/ranged/RangedIdGenerator.java: -------------------------------------------------------------------------------- 1 | package tools.generator.ranged; 2 | 3 | import java.util.concurrent.atomic.AtomicBoolean; 4 | import java.util.concurrent.atomic.AtomicLong; 5 | import java.util.concurrent.locks.Condition; 6 | import java.util.concurrent.locks.ReentrantLock; 7 | 8 | import tools.generator.IdGenerator; 9 | 10 | /** 11 | * 也需要单例运行,生成的值的范围是(start,end】(增量为1时)
12 | * 如果(0,max]表示最大只能为max
13 | * 注意:range只能往大的方向设置,以此来解决并发问题 2012-11-20 14 | * 15 | * @author liusan.dyf 16 | */ 17 | public class RangedIdGenerator implements IdGenerator { 18 | // private long start; 19 | private AtomicLong max = new AtomicLong(0);// 可能为null,所以设置为Long;0也可能是有效的max值 20 | private IdGenerator idGenerator = null; 21 | private RangeGenerator rangeGetter = null; 22 | 23 | private ReentrantLock lock = new ReentrantLock(); 24 | 25 | private Condition waitReadyFlag = lock.newCondition(); 26 | 27 | /** 28 | * 区间是否已经设置,默认为true 2012-11-19 by liusan.dyf 29 | */ 30 | private AtomicBoolean readyFlag = new AtomicBoolean(true); 31 | 32 | public RangedIdGenerator(IdGenerator idGenerator, RangeGenerator rangeGetter) { 33 | this.idGenerator = idGenerator; 34 | this.rangeGetter = rangeGetter; 35 | 36 | if (rangeGetter == null) 37 | throw new IllegalArgumentException("rangeGetter不能为null"); 38 | 39 | init(); 40 | } 41 | 42 | @Override 43 | public long current() { 44 | return idGenerator.current(); 45 | } 46 | 47 | @Override 48 | public void init() { 49 | idGenerator.init(); 50 | 51 | // 设置range 52 | Range r = rangeGetter.current(getKey()); 53 | if (r == null) // 当前range不存在 54 | r = rangeGetter.next(getKey()); 55 | 56 | setRange(r); 57 | } 58 | 59 | /** 60 | * 获取一个新的range,并设置 61 | * 62 | * @param r 63 | */ 64 | private synchronized void setRange(Range r) { 65 | if (r == null) 66 | throw new IllegalArgumentException("range不能为空"); 67 | 68 | // if (max.get() < r.getMax())// 重要,防止由于并发问题引起小区间在大区间后设置 2012-11-20 by liusan.dyf 69 | max.compareAndSet(max.get(), r.getMax()); 70 | 71 | // sleep(20); 72 | 73 | setInitialValue(r.getMin()); 74 | 75 | // 保存 2012-02-12 76 | rangeGetter.save(getKey(), r); 77 | } 78 | 79 | @SuppressWarnings("unused") 80 | private void println(Object obj) { 81 | sleep(0); 82 | System.out.println(System.nanoTime() + " " + Thread.currentThread().getName() + ":" + obj); 83 | } 84 | 85 | private void sleep(int ms) { 86 | try { 87 | Thread.sleep(ms); 88 | } catch (InterruptedException e) { 89 | 90 | } 91 | } 92 | 93 | /* 94 | * 如果返回Long.MIN_VALUE,则表示无效 95 | */ 96 | @Override 97 | public long next() { 98 | while (!readyFlag.get()) { 99 | try { 100 | lock.lock(); 101 | if (!readyFlag.get()) 102 | waitReadyFlag.await(); 103 | } catch (InterruptedException e) { 104 | // IGNORE 105 | } finally { 106 | lock.unlock(); 107 | } 108 | } 109 | 110 | long m = this.max.get(); 111 | long rtn = this.idGenerator.next(); 112 | 113 | if (rtn > m) { 114 | try { 115 | lock.lock(); 116 | // if (readyFlag.get()) { 117 | // return next(); 118 | // } 119 | readyFlag.set(false); 120 | 121 | // do sth... 122 | 123 | Range r = null; 124 | while (true) { 125 | r = rangeGetter.next(getKey()); 126 | 127 | if (r == null) {// 2013-05-06 by liusan.dyf 128 | sleep(100); 129 | continue; 130 | } 131 | 132 | if (max.get() < r.getMax()) 133 | break; 134 | } 135 | 136 | setRange(r); 137 | } finally { 138 | if (!readyFlag.get()) { 139 | readyFlag.set(true); 140 | waitReadyFlag.signalAll(); 141 | } 142 | lock.unlock(); 143 | } 144 | return next(); 145 | } 146 | 147 | return rtn; 148 | } 149 | 150 | @Override 151 | public void setInitialValue(long value) { 152 | idGenerator.setInitialValue(value); 153 | } 154 | 155 | @Override 156 | public String next(int count) { 157 | throw new RuntimeException("NotImplemented"); 158 | } 159 | 160 | @Override 161 | public String getKey() { 162 | return idGenerator.getKey(); 163 | } 164 | 165 | @Override 166 | public int getIncrement() { 167 | return idGenerator.getIncrement(); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/tools/http/HttpMethod.java: -------------------------------------------------------------------------------- 1 | package tools.http; 2 | 3 | public class HttpMethod { 4 | public static final String GET = "GET"; 5 | public static final String POST = "POST"; 6 | /** 7 | * 如果你预先就对响应内容不感兴趣,你可以使用HEAD 请求来代替GET请求。 例如,获取web资源的meta信息或者测试它的有效性,可访问性以及最近的修改。 8 | */ 9 | public static final String HEAD = "HEAD"; 10 | public static final String OPTIONS = "OPTIONS"; 11 | public static final String PUT = "PUT"; 12 | public static final String DELETE = "DELETE"; 13 | public static final String TRACE = "TRACE"; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/tools/http/HttpPostedFile.java: -------------------------------------------------------------------------------- 1 | package tools.http; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | 8 | /** 9 | * 通过HTTP上传的文件类 10 | * 11 | * @author liusan.dyf 12 | */ 13 | public class HttpPostedFile { 14 | private String fieldName; 15 | private String fileName; 16 | private byte[] content; 17 | 18 | public String getFieldName() { 19 | return fieldName; 20 | } 21 | 22 | public void setFieldName(String fieldName) { 23 | this.fieldName = fieldName; 24 | } 25 | 26 | public String getFileName() { 27 | return fileName; 28 | } 29 | 30 | public void setFileName(String fileName) { 31 | this.fileName = fileName; 32 | } 33 | 34 | public byte[] getBytes() { 35 | return content; 36 | } 37 | 38 | /** 39 | * 直接设置文件流 40 | * 41 | * @param bytes 42 | */ 43 | public void setContent(byte[] bytes) { 44 | this.content = bytes; 45 | } 46 | 47 | public void setContent(InputStream content) throws IOException { 48 | this.content = HttpUtil.inputStreamToByte(content); 49 | } 50 | 51 | public void setContent(File file) throws IOException { 52 | this.setContent(new FileInputStream(file)); 53 | } 54 | 55 | /** 56 | * 从http的一个url上下载资源,用于图片、文件等 2012-11-07 by liusan.dyf 57 | * 58 | * @param url 59 | * @throws IOException 60 | */ 61 | public void setContent(String url) throws IOException { 62 | this.content = HttpRequestBuilder.create(url).get().getBytes(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/tools/http/HttpPostedFileBuilder.java: -------------------------------------------------------------------------------- 1 | package tools.http; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | /** 7 | * TODO 类说明 8 | * 9 | * @author liusan.dyf 10 | * @version 1.0 11 | * @since 2012-11-7 12 | */ 13 | public class HttpPostedFileBuilder { 14 | private HttpPostedFile entry = new HttpPostedFile(); 15 | 16 | public static HttpPostedFileBuilder create(String path) { 17 | HttpPostedFileBuilder rtn = new HttpPostedFileBuilder(); 18 | 19 | try { 20 | rtn.entry.setContent(new File(path)); 21 | } catch (IOException e) { 22 | } 23 | 24 | return rtn; 25 | } 26 | 27 | public HttpPostedFileBuilder field(String value) { 28 | entry.setFieldName(value); 29 | return this; 30 | } 31 | 32 | public HttpPostedFileBuilder fileName(String value) { 33 | entry.setFieldName(value); 34 | return this; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/tools/http/HttpUtil.java: -------------------------------------------------------------------------------- 1 | package tools.http; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.UnsupportedEncodingException; 7 | import java.net.URLDecoder; 8 | import java.net.URLEncoder; 9 | import java.util.Map; 10 | import java.util.Map.Entry; 11 | 12 | import tools.StringUtil; 13 | 14 | public class HttpUtil { 15 | public static final String DEFAULT_CHARSET = "utf-8"; 16 | public static final String EMPTY_KEY = "empty_key"; 17 | 18 | public static String decode(final String content, final String encoding) { 19 | if (content == null) { 20 | return null; 21 | } 22 | try { 23 | return URLDecoder.decode(content, encoding); 24 | } catch (UnsupportedEncodingException e) { 25 | throw new IllegalArgumentException(e); 26 | } 27 | } 28 | 29 | public static String encode(final String content, final String encoding) { 30 | if (content == null) { 31 | return null; 32 | } 33 | try { 34 | return URLEncoder.encode(content, encoding); 35 | } catch (UnsupportedEncodingException e) { 36 | throw new IllegalArgumentException(e); 37 | } 38 | } 39 | 40 | /** 41 | * 2016-6-15 14:36:53 by liusan.dyf 42 | * 43 | * @param url 44 | * @param params 45 | * @param charset 46 | * @return 47 | */ 48 | public static String generateUrl(String url, Map params, String charset) { 49 | // 处理url 50 | if (null != params && params.size() > 0) { 51 | if (charset == null) 52 | charset = DEFAULT_CHARSET; 53 | 54 | // 2012-03-06 bugfix 处理直接发送字符串的 55 | if (params.containsKey(EMPTY_KEY)) { 56 | String q = params.get(EMPTY_KEY); 57 | params.remove(EMPTY_KEY); 58 | 59 | params.putAll(StringUtil.parseQueryString(q, charset)); 60 | } 61 | // 特殊字符编码 62 | String encodedParams = toUrlEncodedString(params, charset); 63 | if (-1 == url.indexOf("?")) { 64 | url += "?" + encodedParams; 65 | } else { 66 | url += "&" + encodedParams; 67 | } 68 | } 69 | 70 | return url; 71 | } 72 | 73 | public static String toUrlEncodedString(final Map parameters, final String encoding) { 74 | final StringBuilder result = new StringBuilder(); 75 | boolean willAppendAnd = false; 76 | 77 | for (final Entry item : parameters.entrySet()) { 78 | String key = item.getKey(); 79 | String value = item.getValue(); 80 | 81 | // 2011-12-19如果为blank,这不用追加了 82 | if (key == null || key.length() == 0 || value == null || value.length() == 0) 83 | continue; 84 | 85 | final String encodedName = encode(key, encoding); 86 | final String encodedValue = encode(value, encoding); 87 | 88 | if (willAppendAnd) {// if (result.length() > 0) { 89 | result.append('&'); 90 | } else 91 | willAppendAnd = true; 92 | 93 | // append name value 94 | result.append(encodedName); 95 | result.append('='); 96 | result.append(encodedValue); 97 | } 98 | return result.toString(); 99 | } 100 | 101 | public static byte[] inputStreamToByte(InputStream stream) throws IOException { 102 | ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); 103 | int ch; 104 | while ((ch = stream.read()) != -1) { 105 | byteStream.write(ch); 106 | } 107 | byte data[] = byteStream.toByteArray(); 108 | byteStream.close(); 109 | return data; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/tools/jsonrpc/InvalidJsonRpcRequestException.java: -------------------------------------------------------------------------------- 1 | package tools.jsonrpc; 2 | 3 | @SuppressWarnings("serial") 4 | public class InvalidJsonRpcRequestException extends Exception { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/tools/jsonrpc/InvokeResultList.java: -------------------------------------------------------------------------------- 1 | package tools.jsonrpc; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * 一组调用结果的封装 2011-10-27 by 63 8 | * 9 | * @author liusan.dyf 10 | */ 11 | public class InvokeResultList { 12 | private boolean isBatch; 13 | private List results = new ArrayList(); 14 | 15 | public boolean isBatch() { 16 | return isBatch; 17 | } 18 | 19 | public void setBatch(boolean isBatch) { 20 | this.isBatch = isBatch; 21 | } 22 | 23 | public List getResults() { 24 | return results; 25 | } 26 | 27 | public void setResults(List results) { 28 | this.results = results; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/tools/jsonrpc/JsonRpcError.java: -------------------------------------------------------------------------------- 1 | package tools.jsonrpc; 2 | 3 | import tools.StringUtil; 4 | 5 | /** 6 | * 一个简单的error对象 2012-04-09修改,依赖于StringUtil.jsonEscape 7 | * 8 | * @author liusan.dyf 9 | */ 10 | public class JsonRpcError { 11 | private int id; 12 | private int code; 13 | private String message; 14 | 15 | private static final String TEMPLATE = "{\"jsonrpc\": \"2.0\", \"error\": {\"code\": #code#, \"message\": \"#message#\"}, \"id\": #id#}"; 16 | private static final String[] TAGS = new String[] { "#code#", "#message#", "#id#" }; 17 | 18 | public JsonRpcError(int id, int code, String message) { 19 | this.setId(id); 20 | this.setCode(code); 21 | this.setMessage(message); 22 | } 23 | 24 | public JsonRpcError() { 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | String[] values = new String[] { String.valueOf(code), StringUtil.escapeJSON(message), String.valueOf(id) }; 30 | return StringUtil.replaceAllArray(TEMPLATE, TAGS, values); 31 | } 32 | 33 | public int getId() { 34 | return id; 35 | } 36 | 37 | public void setId(int id) { 38 | this.id = id; 39 | } 40 | 41 | public int getCode() { 42 | return code; 43 | } 44 | 45 | public void setCode(int code) { 46 | this.code = code; 47 | } 48 | 49 | public String getMessage() { 50 | return message; 51 | } 52 | 53 | public void setMessage(String message) { 54 | this.message = message; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/tools/jsonrpc/JsonRpcFilter.java: -------------------------------------------------------------------------------- 1 | package tools.jsonrpc; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.Filter; 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.FilterConfig; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.ServletRequest; 10 | import javax.servlet.ServletResponse; 11 | import javax.servlet.http.HttpServletResponse; 12 | 13 | /** 14 | * 以jsonrpc的方式响应,支持扩展getObject、authenticate、intercept,以及用简单的userName/password做验证
15 | * 执行顺序为:doFilter -》 authenticate -》 intercept -》JsonRpcService.invoke -》 output 16 | * 17 | * @author liusan.dyf 18 | * @version 1.0 19 | * @since 2013-12-17 20 | */ 21 | @Deprecated 22 | public class JsonRpcFilter implements Filter { 23 | 24 | @Override 25 | public void init(FilterConfig filterConfig) throws ServletException { 26 | } 27 | 28 | @Override 29 | public void destroy() { 30 | 31 | } 32 | 33 | /** 34 | * 得到要调用的对象,支持几种形式:spring.xxx和class.com.taobao.xxx静态类方式 35 | * 36 | * @param objKey 37 | * @return 38 | */ 39 | public Object getObject(String objKey) { 40 | if (tools.Validate.isEmpty(objKey)) 41 | return null; 42 | 43 | // 得到调用的对象 44 | Object targetObject = null; 45 | 46 | String clz = "class."; 47 | 48 | if (objKey.startsWith(clz)) {// 调用静态类 2013-12-19 49 | try { 50 | targetObject = Class.forName(objKey.substring(clz.length())); 51 | } catch (ClassNotFoundException e) { 52 | 53 | } 54 | } 55 | return targetObject; 56 | } 57 | 58 | /** 59 | * 看是否有权限调用 2013-12-19 by liusan.dyf 60 | * 61 | * @param request 62 | * @param response 63 | * @return 64 | */ 65 | public boolean authenticate(ServletRequest request, ServletResponse response) { 66 | return true; 67 | } 68 | 69 | /** 70 | * 交给子类,看能否尝试和优先处理 71 | * 72 | * @param objKey 73 | * @param jsonrpc 74 | * @param jsoncallback 75 | * @param request 76 | * @param response 77 | * @return 78 | */ 79 | public boolean intercept(String objKey, String jsonrpc, String jsoncallback, ServletRequest request, 80 | ServletResponse response) { 81 | return false; 82 | } 83 | 84 | @Override 85 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 86 | throws IOException, ServletException { 87 | // jsoncallback 2013-11-01 by liusan.dyf 88 | String jsoncallback = request.getParameter("jsoncallback"); 89 | 90 | // 认证 91 | if (!this.authenticate(request, response)) { 92 | output(response, JsonRpcService.toJsonRpcErrorResult(0, -32602, "权限不足"), jsoncallback); 93 | return; 94 | } 95 | 96 | // invoke.do?obj=spring.xxx&method=getXXX¶ms=... 97 | 98 | // ajax下,Ajax强制将中文内容进行UTF-8编码,这样导致进入后端后使用UTF-8进行解码时发生乱码 99 | // http://www.blogjava.net/xylz/archive/2011/06/10/352073.html 100 | 101 | // input_charset 102 | String inputCharset = request.getParameter("input_charset"); 103 | 104 | // output_charset 105 | String outputCharset = request.getParameter("output_charset"); 106 | if (tools.Validate.isNullOrEmpty(outputCharset)) 107 | outputCharset = "utf-8"; 108 | 109 | // 如果有charset参数,输入和输出都按照这个 2013-12-20 110 | String charset = request.getParameter("charset"); 111 | if (!tools.Validate.isNullOrEmpty(charset)) { 112 | inputCharset = charset; 113 | outputCharset = charset; 114 | 115 | response.setCharacterEncoding(outputCharset);// 显式设置,让CharacterEncodingFilter失效 116 | } 117 | 118 | // 结果 119 | String result = null; 120 | 121 | // http头部,支持jsoncallback参数 122 | if (tools.Validate.isNullOrEmpty(jsoncallback)) { 123 | tools.web.ServletUtil.addJsonContentType((HttpServletResponse) response, outputCharset); 124 | } else { 125 | tools.web.ServletUtil.addContentType((HttpServletResponse) response, "application/x-javascript", 126 | outputCharset); 127 | } 128 | 129 | // key 130 | String objKey = request.getParameter("obj"); 131 | 132 | // jsonrpc的内容 133 | String jsonrpc = request.getParameter("jsonrpc");// 完整的json 134 | if (tools.Validate.isBlank(jsonrpc)) 135 | jsonrpc = request.getParameter("jsonrpcContent"); // 对老版本发起jsonrpc请求的js的兼容 2015-5-25 12:02:32 by liusan.dyf 136 | 137 | // 解码 138 | if (!tools.Validate.isNullOrEmpty(inputCharset)) { 139 | // 解码 140 | if (!tools.Validate.isNullOrEmpty(jsonrpc)) 141 | jsonrpc = java.net.URLDecoder.decode(jsonrpc, inputCharset); 142 | } 143 | 144 | // 尝试处理,这里可以做拦截 2013-12-19 by liusan.dyf 145 | if (this.intercept(objKey, jsonrpc, jsoncallback, request, response)) 146 | return; 147 | 148 | // 得到对象 149 | Object targetObject = getObject(objKey); 150 | 151 | // 调用 152 | if (targetObject != null) 153 | result = JsonRpcService.invokeToString(targetObject, jsonrpc, true); 154 | else 155 | result = JsonRpcService.toJsonRpcErrorResult(0, -32602, "错误的objKey"); 156 | 157 | // 输出 158 | output(response, result, jsoncallback); 159 | 160 | return; 161 | } 162 | 163 | public void output(ServletResponse response, String content, String jsonCallback) throws IOException { 164 | boolean hasJsonCallback = !tools.Validate.isNullOrEmpty(jsonCallback); 165 | 166 | // 2013-11-01 by liusan.dyf 167 | if (hasJsonCallback) 168 | response.getWriter().append(jsonCallback + "("); 169 | 170 | response.getWriter().append(content); 171 | 172 | // 2013-11-01 by liusan.dyf 173 | if (hasJsonCallback) 174 | response.getWriter().append(");"); 175 | 176 | response.getWriter().close(); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/main/java/tools/jsonrpc/LocalVariableNotFoundException.java: -------------------------------------------------------------------------------- 1 | package tools.jsonrpc; 2 | 3 | /** 4 | * 在class中未找到局部变量表信息
5 | * 使用编译器选项 javac -g:{vars}来编译源文件 6 | * 7 | * @author liusan.dyf 8 | */ 9 | public class LocalVariableNotFoundException extends Exception { 10 | /** 11 | * 12 | */ 13 | private static final long serialVersionUID = 1L; 14 | static String msg = "class:%s 不包含局部变量表信息,请使用编译器选项 javac -g:{vars}来编译源文件。"; 15 | 16 | public LocalVariableNotFoundException(String clazzName) { 17 | super(String.format(msg, clazzName)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/tools/jsonrpc/MethodInfo.java: -------------------------------------------------------------------------------- 1 | package tools.jsonrpc; 2 | 3 | import java.lang.reflect.Method; 4 | import java.lang.reflect.Type; 5 | 6 | public class MethodInfo { 7 | private String[] parameterNames; 8 | private Type[] parameterTypes; 9 | private Method method; 10 | 11 | public String[] getParameterNames() { 12 | return parameterNames; 13 | } 14 | 15 | public void setParameterNames(String[] parameterNames) { 16 | this.parameterNames = parameterNames; 17 | } 18 | 19 | public Type[] getParameterTypes() { 20 | return parameterTypes; 21 | } 22 | 23 | public void setParameterTypes(Type[] parameterTypes) { 24 | this.parameterTypes = parameterTypes; 25 | } 26 | 27 | public Method getMethod() { 28 | return method; 29 | } 30 | 31 | public void setMethod(Method method) { 32 | this.method = method; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/tools/jsonrpc/MethodNotFoundException.java: -------------------------------------------------------------------------------- 1 | package tools.jsonrpc; 2 | 3 | public class MethodNotFoundException extends Exception { 4 | 5 | /** 6 | * 7 | */ 8 | private static final long serialVersionUID = -2571099572816268317L; 9 | 10 | public MethodNotFoundException(String message) { 11 | super("不存在的方法名:" + message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/tools/jsonrpc/SingleInvokeResult.java: -------------------------------------------------------------------------------- 1 | package tools.jsonrpc; 2 | 3 | /** 4 | * 对单个返回结果的封装,如果正确,result就是方法的返回值;如果错误,result=JsonRpcError 5 | * 6 | * @author liusan.dyf 7 | */ 8 | public class SingleInvokeResult { 9 | private Object result; 10 | private int id; 11 | 12 | public Object getResult() { 13 | return result; 14 | } 15 | 16 | public void setResult(Object result) { 17 | this.result = result; 18 | } 19 | 20 | public int getId() { 21 | return id; 22 | } 23 | 24 | public void setId(int id) { 25 | this.id = id; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/tools/jsonrpc/web.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | jsonRpcFilter 4 | tools.jsonrpc.JsonRpcFilterV2 5 | 6 | 7 | jsonRpcFilter 8 | /s.do 9 | -------------------------------------------------------------------------------- /src/main/java/tools/naming.txt: -------------------------------------------------------------------------------- 1 | 命名上,如果可以直接是xxx,则无需再加Util后缀,比如StringUtil,MapUtil,因为不能直接命名为String、Map 2 | 而Json是可以的 -------------------------------------------------------------------------------- /src/main/java/tools/oauth/AccessToken.java: -------------------------------------------------------------------------------- 1 | package tools.oauth; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class AccessToken extends HashMap { 7 | private static final long serialVersionUID = -3517561924035633537L; 8 | 9 | // #state=testState&access_token=2.00u3Is_CpmjhRC9787a40fcc0G8lxT&expires_in=86400&uid=2125917932 10 | public String getToken() { 11 | return super.get(FieldConstant.ACCESS_TOKEN) + ""; 12 | } 13 | 14 | public String getState() { 15 | return super.get(FieldConstant.STATE) + ""; 16 | } 17 | 18 | public String getRefreshToken() { 19 | return super.get(FieldConstant.REFRESH_TOKEN) + ""; 20 | } 21 | 22 | public long getExpires() { 23 | Object o = super.get(FieldConstant.EXPIRES_IN); 24 | if (o == null) 25 | return 0; 26 | 27 | // 这样可以兼容long和string类型的字段 28 | return Long.parseLong(super.get(FieldConstant.EXPIRES_IN) + ""); 29 | } 30 | 31 | public AccessToken(Map map) { 32 | super.putAll(map); 33 | } 34 | 35 | public Object get(String key) { 36 | return super.get(key); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/tools/oauth/Display.java: -------------------------------------------------------------------------------- 1 | package tools.oauth; 2 | 3 | public enum Display { 4 | DEFAULT("default"), MOBILE("mobile"), JS("js"), WAP12("wap1.2"), WAP20("wap2.0"); 5 | 6 | private final String value; 7 | 8 | private Display(String value) { 9 | this.value = value; 10 | } 11 | 12 | public String getValue() { 13 | return value; 14 | } 15 | 16 | public static void main(String args[]) { 17 | for (Display item : Display.values()) { 18 | System.out.println(item + "====>" + item.getValue()); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/tools/oauth/FieldConstant.java: -------------------------------------------------------------------------------- 1 | package tools.oauth; 2 | 3 | public class FieldConstant { 4 | public static final String CLIENT_ID = "client_id"; 5 | public static final String CLIENT_SECRET = "client_secret"; 6 | public static final String RESPONSE_TYPE = "response_type"; 7 | public static final String REDIRECT_URI = "redirect_uri"; 8 | public static final String CODE = "code"; 9 | public static final String GRANT_TYPE = "grant_type"; 10 | public static final String USERNAME = "username"; 11 | public static final String PASSWORD = "password"; 12 | 13 | public static final String ACCESS_TOKEN = "access_token"; 14 | public static final String EXPIRES_IN = "expires_in"; 15 | public static final String REFRESH_TOKEN = "refresh_token"; 16 | 17 | public static final String ERROR = "error"; 18 | public static final String ERROR_CODE = "error_code"; 19 | public static final String ERROR_DESCRIPTION = "error_description"; 20 | public static final String ERROR_URL = "error_url"; 21 | 22 | public static final String STATE = "state"; 23 | public static final String DISPLAY = "display"; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/tools/oauth/GrantType.java: -------------------------------------------------------------------------------- 1 | package tools.oauth; 2 | 3 | public enum GrantType { 4 | AUTHORIZATION_CODE("authorization_code"), PASSWORD("password"), REFRESH_TOKEN("refresh_token"); 5 | 6 | private final String value; 7 | 8 | private GrantType(String value) { 9 | this.value = value; 10 | } 11 | 12 | public String getValue() { 13 | return value; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/tools/oauth/OAuthError.java: -------------------------------------------------------------------------------- 1 | package tools.oauth; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * {"request":"/2/oauth2/access_token","error_code":10021,"error": "HTTP METHOD is not suported for this request!"} 8 | * 9 | * @author liusan.dyf 10 | */ 11 | public class OAuthError extends HashMap { 12 | /** 13 | * 14 | */ 15 | private static final long serialVersionUID = -536848467094671187L; 16 | 17 | public static final OAuthError REDIRECT_URI_MISMATCH = new OAuthError(21322, "redirect_uri_mismatch", "重定向地址不匹配", 18 | null); 19 | 20 | public static final OAuthError INVALID_REQUEST = new OAuthError(21323, "invalid_request", "请求不合法", null); 21 | 22 | public static final OAuthError INVALID_CLIENT = new OAuthError(21324, "invalid_client", 23 | "client_id或client_secret参数无效", null); 24 | 25 | public static final OAuthError INVALID_GRANT = new OAuthError(21325, "invalid_grant", 26 | "提供的Access Grant是无效的、过期的或已撤销的", null); 27 | 28 | public static final OAuthError UNAUTHORIZED_CLIENT = new OAuthError(21326, "unauthorized_client ", "客户端没有权限", null); 29 | 30 | public static final OAuthError EXPIRED_TOKEN = new OAuthError(21327, "expired_token", "token过期", null); 31 | 32 | public static final OAuthError UNSUPPORTED_GRANT_TYPE = new OAuthError(21328, "unsupported_grant_type", 33 | "不支持的 GrantType", null); 34 | 35 | public static final OAuthError UNSUPPORTED_RESPONSE_TYPE = new OAuthError(21329, "unsupported_response_type", 36 | "不支持的 ResponseType", null); 37 | 38 | public static final OAuthError ACCESS_DENIED = new OAuthError(21330, "access_denied", "用户或授权服务器拒绝授予数据访问权限", null); 39 | 40 | public static final OAuthError TEMPORARILY_UNAVAILABLE = new OAuthError(21331, "temporarily_unavailable", 41 | "服务暂时无法访问", null); 42 | 43 | public OAuthError(int errorCode, String error, String errorDescription, String errorUrl) { 44 | super.put(FieldConstant.ERROR_CODE, errorCode); 45 | super.put(FieldConstant.ERROR, error); 46 | super.put(FieldConstant.ERROR_DESCRIPTION, errorDescription); 47 | super.put(FieldConstant.ERROR_URL, errorUrl); 48 | } 49 | 50 | public OAuthError(Map map) { 51 | super.putAll(map); 52 | } 53 | 54 | public int getErrorCode() { 55 | if (super.containsKey(FieldConstant.ERROR_CODE)) 56 | return Integer.parseInt(super.get(FieldConstant.ERROR_CODE).toString()); 57 | return 0; 58 | } 59 | 60 | public void setErrorCode(int errorCode) { 61 | super.put(FieldConstant.ERROR_CODE, errorCode); 62 | } 63 | 64 | public String getErrorUrl() { 65 | return super.get(FieldConstant.ERROR_URL) + ""; 66 | } 67 | 68 | public void setErrorUrl(String errorUrl) { 69 | super.put(FieldConstant.ERROR_URL, errorUrl); 70 | } 71 | 72 | public String getErrorDescription() { 73 | return super.get(FieldConstant.ERROR_DESCRIPTION) + ""; 74 | } 75 | 76 | public void setErrorDescription(String errorDescription) { 77 | super.put(FieldConstant.ERROR_DESCRIPTION, errorDescription); 78 | } 79 | 80 | public static void main(String[] args) { 81 | OAuthError error = new OAuthError(21322, "redirect_uri_mismatch", "重定向地址不匹配", null); 82 | System.out.println(error); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/tools/oauth/OAuthException.java: -------------------------------------------------------------------------------- 1 | package tools.oauth; 2 | 3 | public class OAuthException extends Exception { 4 | 5 | /** 6 | * 7 | */ 8 | private static final long serialVersionUID = -4164945653610362059L; 9 | 10 | private OAuthError error; 11 | 12 | public OAuthError getError() { 13 | return error; 14 | } 15 | 16 | public void setError(OAuthError error) { 17 | this.error = error; 18 | } 19 | 20 | public OAuthException(OAuthError error) { 21 | this.error = error; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/tools/oauth/ProviderDefinition.java: -------------------------------------------------------------------------------- 1 | package tools.oauth; 2 | 3 | /** 4 | * @author liusan.dyf 5 | */ 6 | public class ProviderDefinition { 7 | private String url; 8 | private String method; 9 | 10 | public String getUrl() { 11 | return url; 12 | } 13 | 14 | public void setUrl(String url) { 15 | this.url = url; 16 | } 17 | 18 | public String getMethod() { 19 | return method; 20 | } 21 | 22 | public void setMethod(String method) { 23 | this.method = method.toUpperCase(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/tools/oauth/ResponseType.java: -------------------------------------------------------------------------------- 1 | package tools.oauth; 2 | 3 | public enum ResponseType { 4 | CODE("code"), TOKEN("token"); 5 | 6 | private final String value; 7 | 8 | private ResponseType(String value) { 9 | this.value = value; 10 | } 11 | 12 | public String getValue() { 13 | return value; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/tools/session/CookieStoreService.java: -------------------------------------------------------------------------------- 1 | package tools.session; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.net.URLDecoder; 5 | import java.net.URLEncoder; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | 10 | import tools.StoreService; 11 | import tools.web.CookieUtil; 12 | 13 | public class CookieStoreService implements StoreService { 14 | private static final String ENCODING = "UTF-8";// cookie的编码 2012-10-08 15 | private tools.web.CookieUtil cookie = null; 16 | private String name; 17 | private String domain; 18 | 19 | public CookieStoreService(HttpServletRequest request, HttpServletResponse response, String name, String domain){ 20 | this.cookie = new CookieUtil(request, response); 21 | this.name = name; 22 | this.domain = domain; 23 | } 24 | 25 | @Override 26 | public void remove() { 27 | cookie.delete(name, domain, null); 28 | } 29 | 30 | @Override 31 | public void set(String value, int seconds) { 32 | try { 33 | cookie.set(name, URLEncoder.encode(value, ENCODING), domain, null, seconds); 34 | } catch (UnsupportedEncodingException e) { 35 | } 36 | } 37 | 38 | @Override 39 | public String get() { 40 | try { 41 | return URLDecoder.decode(cookie.getValue(name), ENCODING); 42 | } catch (UnsupportedEncodingException e) { 43 | 44 | } 45 | return null; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/tools/session/SessionServiceBase.java: -------------------------------------------------------------------------------- 1 | package tools.session; 2 | 3 | import tools.ObjectConverter; 4 | import tools.StoreService; 5 | import tools.StringUtil; 6 | 7 | /** 8 | * 把session序列化为string,存储到某地方,返回反序列化回来 2012-02-27
9 | * 注意,存储的时候,需要md5签名验证 10 | * 11 | * @author liusan.dyf 12 | * @param 13 | */ 14 | public abstract class SessionServiceBase { 15 | private ObjectConverter converter; 16 | private StoreService storer; 17 | 18 | /** 19 | * salt在编码后的串里不可见 20 | * 21 | * @return 22 | */ 23 | public String getSalt() { 24 | return StringUtil.EMPTY; 25 | } 26 | 27 | public void set(T entry) { 28 | // 写入cookie 29 | set(entry, 3600 * 24 * 30); // 默认30天 30 | } 31 | 32 | public void remove() { 33 | storer.remove(); 34 | } 35 | 36 | public final void set(T entry, int seconds) { 37 | String value = getStringFromEntryInternal(entry); 38 | storer.set(value, seconds); 39 | } 40 | 41 | public T get() { 42 | String v = storer.get(); 43 | if (StringUtil.isNullOrEmpty(v)) { 44 | storer.remove();// 2012-10-08,防止无效的string一直存在 45 | return null; 46 | } 47 | 48 | T r = getEntryFromStringInternal(v); 49 | 50 | if (r == null) { 51 | storer.remove();// 2012-10-08,防止无效的string一直存在 52 | return null; 53 | } 54 | 55 | return r; 56 | } 57 | 58 | String getStringFromEntryInternal(T entry) { 59 | String s = converter.to(entry);// getStringFromEntry(entry); 60 | 61 | return StringUtil.signContent(s, getSalt()); 62 | } 63 | 64 | T getEntryFromStringInternal(String str) { 65 | String raw = StringUtil.getRawContent(str, getSalt()); 66 | // System.out.println("getEntryFromStringInternal:" + str); 67 | if (raw != null) 68 | return converter.from(raw);// getEntryFromString(raw); 69 | else { 70 | return null; 71 | } 72 | } 73 | 74 | public ObjectConverter getConverter() { 75 | return converter; 76 | } 77 | 78 | public void setConverter(ObjectConverter converter) { 79 | this.converter = converter; 80 | } 81 | 82 | public StoreService getStorer() { 83 | return storer; 84 | } 85 | 86 | public void setStorer(StoreService storer) { 87 | this.storer = storer; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/tools/spring/AsyncInitBeanFactory.java: -------------------------------------------------------------------------------- 1 | package tools.spring; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.Future; 8 | 9 | import org.apache.commons.logging.Log; 10 | import org.apache.commons.logging.LogFactory; 11 | import org.springframework.beans.factory.BeanCreationException; 12 | import org.springframework.beans.factory.BeanFactory; 13 | import org.springframework.beans.factory.support.DefaultListableBeanFactory; 14 | import org.springframework.beans.factory.support.RootBeanDefinition; 15 | import org.springframework.context.ApplicationContext; 16 | import org.springframework.context.support.ClassPathXmlApplicationContext; 17 | 18 | /** 19 | * idea和部分代码来自【书全】,耗时统计是通过拦截和注入init-method来实现
20 | * 21 | * @author liusan.dyf 22 | * @version 1.0 23 | * @since 2014年12月9日 24 | */ 25 | public class AsyncInitBeanFactory extends DefaultListableBeanFactory { 26 | protected static final int DEFAULT_POOL_SIZE = 2;// 默认线程池大小 27 | private static final Log logger = LogFactory.getLog("spring");// 日志 28 | 29 | private long setupTimeMillis = 0;// 2014-12-09 by 六三 30 | 31 | private ExecutorService executor = null;// 32 | private List> list = null; 33 | 34 | public AsyncInitBeanFactory() { 35 | this(null, DEFAULT_POOL_SIZE); 36 | } 37 | 38 | /** 39 | * 构造函数 40 | * 41 | * @param parentBeanFactory 42 | * @param poolSize 43 | */ 44 | public AsyncInitBeanFactory(BeanFactory parentBeanFactory, int poolSize) { 45 | super(parentBeanFactory); 46 | 47 | if (poolSize <= 0) 48 | poolSize = DEFAULT_POOL_SIZE; 49 | 50 | // System.out.println(this.getClass()); 51 | 52 | setupTimeMillis = System.currentTimeMillis(); 53 | executor = Executors.newFixedThreadPool(poolSize); 54 | list = new ArrayList>(); 55 | 56 | // http://gitlab.alibaba-inc.com/jhaolee/async-init-spring/blob/master/src/main/java/com/alibaba/trade/async/spring/beans/factory/AsyncInitBeanFactory.java 57 | } 58 | 59 | /** 60 | * 系统启动入口 2014-12-09 by 六三 61 | * 62 | * @param locations 63 | * @param n 64 | * @return 65 | */ 66 | public static ApplicationContext initBeans(String[] locations, final int n) { 67 | ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(locations) { 68 | private AsyncInitBeanFactory beanFactory;// 创建本类的一个实例 69 | 70 | /** 71 | * 这里要重写 createBeanFactory,返回一个自定义的BeanFactory 72 | */ 73 | @Override 74 | protected DefaultListableBeanFactory createBeanFactory() { 75 | beanFactory = new AsyncInitBeanFactory(getParentBeanFactory(), n); 76 | return beanFactory; 77 | } 78 | 79 | @Override 80 | protected void finishRefresh() { 81 | beanFactory.waitToFinish();// 必须 82 | super.finishRefresh(); 83 | 84 | logger.warn(beanFactory + " = " + this.getBeanFactory() + " ?"); 85 | } 86 | }; 87 | 88 | // System.out.println(ctx.getStartupDate()); 89 | // ctx.refresh(); 90 | 91 | return ctx; 92 | } 93 | 94 | @Override 95 | protected void invokeCustomInitMethod(final String beanName, final Object bean, final RootBeanDefinition mbd) 96 | throws Throwable { 97 | // System.out.println("class=" + bean.getClass() + ", method=" + mbd.getInitMethodName()); 98 | 99 | // 原本是要直接去调用super.invokeCustomInitMethod的,这里没有,而是生成任务放到线程池里等待并行完成 2015-12-17 10:50:15 by liusan.dyf 100 | // super.invokeCustomInitMethod(beanName, bean, mbd); 101 | 102 | // 用线程池异步初始化 103 | Future f = executor.submit(new Runnable() { 104 | @Override 105 | public void run() { 106 | try { 107 | doInvokeCustomInitMethod(beanName, bean, mbd); 108 | } catch (Throwable e) { 109 | logger.error(e); 110 | } 111 | } 112 | }); 113 | 114 | list.add(f); 115 | } 116 | 117 | /** 118 | * 真正的去调用super.invokeCustomInitMethod,同时加入了统计耗时的功能 119 | * 120 | * @param beanName 121 | * @param bean 122 | * @param mbd 123 | * @throws Throwable 124 | */ 125 | private void doInvokeCustomInitMethod(final String beanName, final Object bean, final RootBeanDefinition mbd) 126 | throws Throwable { 127 | // long id = Thread.currentThread().getId(); 128 | String info = beanName + "." + mbd.getInitMethodName(); 129 | 130 | // logger.warn("begin to invoke " + info + " by " + id); 131 | 132 | long start = System.currentTimeMillis(); 133 | 134 | // 真正的开始调用 135 | super.invokeCustomInitMethod(beanName, bean, mbd); 136 | 137 | // 调用完毕,统计耗时 138 | logger.warn("invoke " + info + ", cost " + (System.currentTimeMillis() - start)); 139 | } 140 | 141 | /** 142 | * 等待所有的bean的init方法都调用完毕 2015-12-17 11:11:42 by liusan.dyf 143 | * 144 | * @return 145 | */ 146 | public boolean waitToFinish() { 147 | if (list == null || list.size() == 0) // 如果已经调用了这个方法,则要保证再次调用不能出异常 148 | return false; 149 | 150 | try { 151 | for (Future task : list) { 152 | Object result = task.get(); 153 | if (result != null) { 154 | // TODO 155 | } 156 | } 157 | } catch (Throwable e) { 158 | if (e instanceof BeanCreationException) { 159 | throw (BeanCreationException) e; 160 | } else { 161 | throw new BeanCreationException(e.getMessage(), e); 162 | } 163 | } 164 | 165 | // 记录耗时 2014-12-09 by 六三 166 | logger.warn(list.size() + " beans async invoke cost: " + (System.currentTimeMillis() - setupTimeMillis)); 167 | 168 | // 清理 169 | list.clear(); 170 | list = null; 171 | executor.shutdown(); 172 | executor = null; 173 | 174 | return true; 175 | } 176 | 177 | // @Override 178 | // protected void invokeInitMethods(final String beanName, final Object bean, final RootBeanDefinition mbd) 179 | // throws Throwable { 180 | // super.invokeInitMethods(beanName, bean, mbd); 181 | // } 182 | } 183 | -------------------------------------------------------------------------------- /src/main/java/tools/spring/SpringBeanPostPrcessor.java: -------------------------------------------------------------------------------- 1 | package tools.spring; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | import org.apache.commons.logging.Log; 7 | import org.apache.commons.logging.LogFactory; 8 | import org.springframework.beans.BeansException; 9 | import org.springframework.beans.factory.config.BeanPostProcessor; 10 | 11 | /** 12 | * 统计每个bean的创建时间,直接配置即可: 13 | * 14 | *
15 |  * bean class="tools.SpringBeanPostPrcessor"
16 |  * 
17 |  * BeanPostPrcessorImpl beanPostProcessor = new BeanPostPrcessorImpl();
18 |  * Resource resource = new FileSystemResource("applicationContext.xml");
19 |  * ConfigurableBeanFactory factory = new XmlBeanFactory(resource);
20 |  * factory.addBeanPostProcessor(beanPostProcessor);
21 |  * factory.getBean("logic");
22 |  * 
23 | * 24 | * @author liusan.dyf 25 | * @version 1.0 26 | * @since 2014年9月4日 27 | */ 28 | public class SpringBeanPostPrcessor implements BeanPostProcessor { 29 | private static final Log logger = LogFactory.getLog("spring"); 30 | 31 | /** 32 | * 初始状态,value=0-时间戳,为负数;如果初始化OK后,转正,为init耗时情况 33 | */ 34 | private Map map = tools.MapUtil.concurrentHashMap(); 35 | 36 | private AtomicInteger counter = new AtomicInteger(0); 37 | 38 | @Override 39 | public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 40 | counter.incrementAndGet(); 41 | map.put(beanName, 0 - System.currentTimeMillis()); 42 | 43 | logger.warn("______正准备初始化bean: " + beanName); 44 | 45 | return bean; 46 | } 47 | 48 | @Override 49 | public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 50 | counter.incrementAndGet(); 51 | 52 | Long x = map.remove(beanName);// 移除 53 | long v = 0; 54 | 55 | if (x != null) { 56 | if (x < 0) { 57 | v = System.currentTimeMillis() - (0 - x); 58 | 59 | logger.warn("bean=" + beanName + ", counter=" + counter.get() + ", cost=" + v); 60 | } 61 | } else 62 | logger.warn("bean=" + beanName + " time cost not found, counter=" + counter.get()); 63 | 64 | return bean; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/tools/spring/SpringContext.java: -------------------------------------------------------------------------------- 1 | package tools.spring; 2 | 3 | import java.util.Map; 4 | 5 | import org.springframework.beans.BeansException; 6 | import org.springframework.context.ApplicationContext; 7 | import org.springframework.context.ApplicationContextAware; 8 | 9 | /** 10 | * 使用静态方法,方便使用,记得该类要被spring创建一次 11 | * 12 | * @author liusan.dyf 13 | * @version 1.0 14 | * @since 2012-2-28 15 | */ 16 | public class SpringContext implements ApplicationContextAware { 17 | 18 | /** 19 | * 可以存储多个ApplicationContext 2013-02-28 by liusan.dyf 20 | */ 21 | private static Map all = tools.MapUtil.concurrentHashMap(); 22 | private static Map cachedBeans = tools.MapUtil.concurrentHashMap();// 2015-9-11 10:33:32 by 一篑 23 | 24 | /** 25 | * 如果该name没有配置,则返回null;不做containsBean判断则报错:NoSuchBeanDefinitionException 26 | * 27 | * @param name 28 | * @return 29 | */ 30 | public static Object getBean(String name) { 31 | if (cachedBeans.containsKey(name)) {// ApplicationContext.getBean内部有锁,这里做个缓存 2015-9-11 10:33:32 by 一篑 32 | return cachedBeans.get(name); 33 | } 34 | 35 | for (ApplicationContext item : all.values()) { 36 | // if (item.containsBean(name)) 37 | // return item.getBean(name); 38 | 39 | if (item.containsBean(name)) { 40 | Object bean = item.getBean(name); 41 | cachedBeans.put(name, bean);// 放入缓存 2015-9-11 10:31:54 by 一篑 42 | return bean; 43 | } 44 | } 45 | 46 | return null; 47 | } 48 | 49 | /** 50 | * 2012-03-05 by liusan.dyf 51 | * 52 | * @param t 53 | * @param name 54 | * @return 55 | */ 56 | @SuppressWarnings("unchecked") 57 | public static T getBean(Class t, String name) { 58 | Object obj = getBean(name); 59 | if (obj == null) 60 | return null; 61 | return (T) obj; 62 | } 63 | 64 | @Override 65 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 66 | synchronized (all) { 67 | all.put(applicationContext.getId(), applicationContext); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/tools/token/ArrayHandler.java: -------------------------------------------------------------------------------- 1 | package tools.token; 2 | 3 | public class ArrayHandler implements TokenHandler { 4 | private Object[] array; 5 | private int length; 6 | 7 | public ArrayHandler(Object[] array) { 8 | this.array = array; 9 | 10 | if (this.array != null) 11 | length = array.length; 12 | } 13 | 14 | @Override 15 | public String handle(String token) { 16 | if (array == null) 17 | return ""; 18 | 19 | int index = tools.Convert.toInt(token, -1); 20 | if (index == -1 || index >= length) 21 | return ""; 22 | 23 | Object ele = array[index]; 24 | if (ele == null) 25 | return ""; 26 | 27 | return ele.toString(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/tools/token/GenericTokenParser.java: -------------------------------------------------------------------------------- 1 | package tools.token; 2 | 3 | /** 4 | * 取自mybatis框架,转义前面加\即可 2012-04-25
5 | * 来自 https://github.com/mybatis/mybatis-3/blob/master/src/main/java/org/apache/ibatis/parsing/GenericTokenParser.java 6 | * 7 | * @author liusan.dyf 8 | * @author Clinton Begin 9 | */ 10 | public class GenericTokenParser { 11 | private final String openToken; 12 | private final String closeToken; 13 | private final TokenHandler handler; 14 | 15 | public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) { 16 | this.openToken = openToken; 17 | this.closeToken = closeToken; 18 | this.handler = handler; 19 | } 20 | 21 | public String parse(String text) { 22 | StringBuilder builder = new StringBuilder(); 23 | if (text != null && text.length() > 0) { 24 | char[] src = text.toCharArray(); 25 | int offset = 0; 26 | int start = text.indexOf(openToken, offset); 27 | while (start > -1) { 28 | if (start > 0 && src[start - 1] == '\\') { 29 | // the variable is escaped. remove the backslash. 30 | builder.append(src, offset, start - offset - 1).append(openToken); 31 | offset = start + openToken.length(); 32 | } else { 33 | int end = text.indexOf(closeToken, start); 34 | if (end == -1) { 35 | builder.append(src, offset, src.length - offset); 36 | offset = src.length; 37 | } else { 38 | builder.append(src, offset, start - offset); 39 | offset = start + openToken.length(); 40 | String content = new String(src, offset, end - offset); 41 | builder.append(handler.handle(content)); 42 | offset = end + closeToken.length(); 43 | } 44 | } 45 | start = text.indexOf(openToken, offset); 46 | } 47 | if (offset < src.length) { 48 | builder.append(src, offset, src.length - offset); 49 | } 50 | } 51 | return builder.toString(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/tools/token/ListHandler.java: -------------------------------------------------------------------------------- 1 | package tools.token; 2 | 3 | import java.util.List; 4 | 5 | public class ListHandler implements TokenHandler { 6 | private List list; 7 | private int length; 8 | 9 | public ListHandler(List list) { 10 | this.list = list; 11 | 12 | if (this.list != null) 13 | length = list.size(); 14 | } 15 | 16 | @Override 17 | public String handle(String token) { 18 | if (list == null) 19 | return ""; 20 | 21 | int index = tools.Convert.toInt(token, -1); 22 | if (index == -1 || index >= length) 23 | return ""; 24 | 25 | Object ele = list.get(index); 26 | if (ele == null) 27 | return ""; 28 | 29 | return ele.toString(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/tools/token/MapHandler.java: -------------------------------------------------------------------------------- 1 | package tools.token; 2 | 3 | import java.util.Map; 4 | 5 | public class MapHandler implements TokenHandler { 6 | 7 | private Map vars; 8 | 9 | public MapHandler(Map vars) { 10 | this.vars = vars; 11 | } 12 | 13 | @Override 14 | public String handle(String token) { 15 | if (vars == null) 16 | return ""; 17 | 18 | Object obj = vars.get(token); 19 | if (obj == null) 20 | return ""; 21 | 22 | return obj.toString(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/tools/token/SimpleParser.java: -------------------------------------------------------------------------------- 1 | package tools.token; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 2012-05-29 7 | * 8 | * @author liusan.dyf 9 | */ 10 | public class SimpleParser { 11 | public static String execute(String content, String openToken, String closeToken, Map vars) { 12 | TokenHandler handler = new MapHandler(vars); 13 | GenericTokenParser p = new GenericTokenParser(openToken, closeToken, handler); 14 | return p.parse(content); 15 | } 16 | 17 | /** 18 | * like c# string.format("{0},{1}...",1,2,3); 2012-09-28 by liusan.dyf 19 | * 20 | * @param source 21 | * @param args 22 | * @return 23 | */ 24 | public static String format(String source, Object... args) { 25 | TokenHandler handler = new ArrayHandler(args); 26 | GenericTokenParser p = new GenericTokenParser("{", "}", handler); 27 | return p.parse(source); 28 | } 29 | 30 | public static void main(String[] args) { 31 | String text = "
${value}
"; 32 | Map vars = tools.MapUtil.create(); 33 | vars.put("value", "xxx"); 34 | 35 | String output = execute(text, "${", "}", vars); 36 | System.out.println(output); 37 | 38 | // format 2012-09-28 39 | String v = format("{0} {1} {2} {3}", "hello", "world", "!"); 40 | System.out.println(v); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/tools/token/TokenHandler.java: -------------------------------------------------------------------------------- 1 | package tools.token; 2 | 3 | public interface TokenHandler { 4 | String handle(String token); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/tools/web/CookieUtil.java: -------------------------------------------------------------------------------- 1 | package tools.web; 2 | 3 | import javax.servlet.http.Cookie; 4 | import javax.servlet.http.HttpServletRequest; 5 | import javax.servlet.http.HttpServletResponse; 6 | 7 | import org.apache.commons.logging.Log; 8 | import org.apache.commons.logging.LogFactory; 9 | 10 | import tools.StringUtil; 11 | 12 | /** 13 | * 可参见 http://www.tutorialspoint.com/servlets/servlets-cookies-handling.htm
14 | * 要实例化对象才能使用 15 | * 16 | * @author liusan.dyf 17 | */ 18 | public class CookieUtil { 19 | private static final Log logger = LogFactory.getLog(CookieUtil.class); 20 | 21 | private HttpServletRequest request; 22 | private HttpServletResponse response; 23 | 24 | private final static String DEFAULT_PATH = "/"; 25 | private final static String DEFAULT_DOMAIN = "."; 26 | 27 | /** 28 | * @param request HttpServletRequest才有getCookies()的方法 29 | * @param response 30 | */ 31 | public CookieUtil(HttpServletRequest request, HttpServletResponse response) { 32 | this.request = request; 33 | this.response = response; 34 | } 35 | 36 | public void set(String name, String value, String domain, String path, int seconds) { 37 | logger.debug("name=" + name + ",value=" + value + ",seconds=" + seconds); 38 | Cookie c = new Cookie(name, value); 39 | 40 | if (!StringUtil.isNullOrEmpty(domain)) 41 | c.setDomain(domain); 42 | else 43 | c.setDomain(DEFAULT_DOMAIN); 44 | 45 | if (!StringUtil.isNullOrEmpty(path)) 46 | c.setPath(path); 47 | else 48 | c.setPath(DEFAULT_PATH); 49 | 50 | // cookies.setMaxAge(-1);//设置cookie经过多长秒后被删除。如果0,就说明立即删除。如果是负数就表明当浏览器关闭时自动删除。 51 | c.setMaxAge(seconds); 52 | 53 | response.addCookie(c); 54 | } 55 | 56 | public String getValue(String name) { 57 | if (name != null) { 58 | Cookie c = get(name); 59 | if (c != null) { 60 | return c.getValue(); 61 | } 62 | } 63 | return StringUtil.EMPTY; 64 | } 65 | 66 | /** 67 | * 2012-09-28 by liusan.dyf 68 | * 69 | * @return 70 | */ 71 | public String getRequestCookieString() { 72 | Cookie[] coll = request.getCookies(); 73 | if (coll == null || coll.length == 0) 74 | return ""; 75 | 76 | StringBuilder sb = new StringBuilder(); 77 | 78 | for (Cookie item : coll) { 79 | sb.append(item.getName() + "=" + item.getValue() + "; "); 80 | } 81 | 82 | return sb.toString(); 83 | } 84 | 85 | public Cookie get(String n) { 86 | Cookie[] coll = request.getCookies(); 87 | 88 | if (coll == null || coll.length == 0) 89 | return null; 90 | 91 | for (Cookie item : coll) { 92 | if (item.getName().equals(n)) { 93 | return item; 94 | } 95 | } 96 | return null; 97 | } 98 | 99 | public boolean delete(String n, String domain, String path) { 100 | if (!StringUtil.isNullOrEmpty(n)) { 101 | Cookie c = get(n); 102 | if (c != null) { 103 | c.setMaxAge(0);// 如果0,就说明立即删除 104 | 105 | if (!StringUtil.isNullOrEmpty(domain)) 106 | c.setDomain(domain); 107 | else 108 | c.setDomain(DEFAULT_DOMAIN); 109 | 110 | if (!StringUtil.isNullOrEmpty(path)) 111 | c.setPath(path);// 不要漏掉 112 | else 113 | c.setPath(DEFAULT_PATH); 114 | 115 | response.addCookie(c); 116 | return true; 117 | } 118 | } 119 | return false; 120 | } 121 | 122 | public static void main(String[] args) { 123 | // CookieUtil util = new CookieUtil(request,response,-1); 124 | // util.addCookie("name","value"); 125 | // String value = util.getCookieValue("name"); 126 | // System.out.println("value="+value); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/temp/java/tools/mongodb/DocumentUtil.java: -------------------------------------------------------------------------------- 1 | package tools.mongodb; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | import tools.Json; 9 | 10 | import com.mongodb.BasicDBObject; 11 | import com.mongodb.DBObject; 12 | 13 | public class DocumentUtil { 14 | /** 15 | * 把DBObject里的_id映射为class的id属性上 16 | * 17 | * @param dbObject 18 | * @param clz 19 | * @return 20 | */ 21 | public static T toObject(DBObject dbObject, Class clz) { 22 | if (dbObject == null) 23 | return null; 24 | 25 | // 修改id,把_id换为id 26 | Object id = dbObject.get("_id"); 27 | dbObject.put("id", id); 28 | // dbObject.removeField("_id");// 可以不用删除 2012-02-01 29 | 30 | T rtn = Json.toObject(dbObject.toString(), clz); 31 | 32 | return rtn; 33 | } 34 | 35 | /** 36 | * 只把object的id属性当作mongo的object_id,注意Date类型的值要修正下 37 | * 38 | * @param value 39 | * @return 40 | */ 41 | public static DBObject toMongodbObject(Object value) { 42 | Map map = Json.toMap(value); 43 | if (map == null) 44 | return null; 45 | 46 | BasicDBObject document = new BasicDBObject(); 47 | document.putAll(map); 48 | 49 | // 循环下,把value为null的干掉 50 | List keys = new ArrayList(document.size()); 51 | for (Map.Entry item : (Set>) document.entrySet()) { 52 | if (item.getValue() == null) { 53 | keys.add(item.getKey()); 54 | // document.remove(item.getKey()); 55 | // java.util.ConcurrentModificationException 56 | } 57 | } 58 | 59 | for (String item : keys) 60 | document.removeField(item); 61 | 62 | // 修正id的问题 63 | String key = "id"; 64 | Object oid = document.get(key); 65 | if (oid != null) { 66 | document.remove(key); 67 | document.put("_id", oid); 68 | } 69 | 70 | return document; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/temp/java/tools/mongodb/builder/Builder.java: -------------------------------------------------------------------------------- 1 | package tools.mongodb.builder; 2 | 3 | import com.mongodb.BasicDBObject; 4 | import com.mongodb.util.JSON; 5 | 6 | public class Builder { 7 | private BasicDBObject operates; 8 | 9 | /** 10 | * 2011-11-14 11 | * 12 | * @return 13 | */ 14 | public BasicDBObject getResult() { 15 | return operates; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return JSON.serialize(operates); 21 | } 22 | 23 | /** 24 | * Initializes a new instance of the QueryConditionList class. 25 | */ 26 | public Builder() { 27 | operates = new BasicDBObject(); 28 | } 29 | 30 | /** 31 | * 2012-02-21 32 | * 33 | * @param ops 34 | */ 35 | public Builder(BasicDBObject ops) { 36 | operates = ops; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/temp/java/tools/mongodb/builder/CollectionOptionsBuilder.java: -------------------------------------------------------------------------------- 1 | package tools.mongodb.builder; 2 | 3 | public class CollectionOptionsBuilder extends Builder { 4 | public CollectionOptionsBuilder autoIndexId(boolean value) { 5 | if (value) { 6 | super.getResult().put("autoIndexId", value); 7 | } else { 8 | super.getResult().remove("autoIndexId"); 9 | } 10 | return this; 11 | } 12 | 13 | public CollectionOptionsBuilder capped(boolean value) { 14 | if (value) { 15 | super.getResult().put("capped", value); 16 | } else { 17 | super.getResult().remove("capped"); 18 | } 19 | return this; 20 | } 21 | 22 | public CollectionOptionsBuilder maxDocuments(long value) { 23 | super.getResult().put("max", value); 24 | return this; 25 | } 26 | 27 | /** 28 | * 单位是byte 29 | * 30 | * @param value 31 | * @return 32 | */ 33 | public CollectionOptionsBuilder maxSize(long value) { 34 | super.getResult().put("size", value); 35 | return this; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/temp/java/tools/mongodb/builder/FieldsBuilder.java: -------------------------------------------------------------------------------- 1 | package tools.mongodb.builder; 2 | 3 | import com.mongodb.BasicDBObject; 4 | 5 | public class FieldsBuilder extends Builder { 6 | public FieldsBuilder exclude(String... keys) { 7 | BasicDBObject operates = super.getResult(); 8 | for (String item : keys) { 9 | operates.put(item, 0); 10 | } 11 | return this; 12 | } 13 | 14 | public FieldsBuilder include(String... keys) { 15 | BasicDBObject operates = super.getResult(); 16 | for (String item : keys) { 17 | operates.put(item, 1); 18 | } 19 | return this; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/temp/java/tools/mongodb/builder/IndexKeysBuilder.java: -------------------------------------------------------------------------------- 1 | package tools.mongodb.builder; 2 | 3 | import com.mongodb.BasicDBObject; 4 | 5 | public class IndexKeysBuilder extends Builder { 6 | public IndexKeysBuilder asc(String... keys) { 7 | BasicDBObject operates = super.getResult(); 8 | for (String item : keys) { 9 | operates.put(item, 1); 10 | } 11 | return this; 12 | } 13 | 14 | public IndexKeysBuilder desc(String... keys) { 15 | BasicDBObject operates = super.getResult(); 16 | for (String item : keys) { 17 | operates.put(item, -1); 18 | } 19 | return this; 20 | } 21 | 22 | public IndexKeysBuilder GeoSpatial(String name) { 23 | super.getResult().put(name, "2d"); 24 | return this; 25 | } 26 | 27 | public IndexKeysBuilder geoSpatialHaystack(String name) { 28 | return geoSpatialHaystack(name, null); 29 | } 30 | 31 | /** 32 | * Sets the key name and additional field name to create a geospatial haystack index on. 33 | * 34 | * @param name 35 | * @param additionalName 36 | * @return 37 | */ 38 | public IndexKeysBuilder geoSpatialHaystack(String name, String additionalName) { 39 | super.getResult().put(name, "geoHaystack"); 40 | 41 | if (additionalName != null) 42 | super.getResult().put(additionalName, 1); 43 | return this; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/temp/java/tools/mongodb/builder/IndexOptionsBuilder.java: -------------------------------------------------------------------------------- 1 | package tools.mongodb.builder; 2 | 3 | public class IndexOptionsBuilder extends Builder { 4 | public IndexOptionsBuilder background(boolean value) { 5 | super.getResult().put("background", value); 6 | return this; 7 | } 8 | 9 | public IndexOptionsBuilder bucketSize(double value) { 10 | super.getResult().put("bucketSize", value); 11 | return this; 12 | } 13 | 14 | public IndexOptionsBuilder dropDups(boolean value) { 15 | super.getResult().put("dropDups", value); 16 | return this; 17 | } 18 | 19 | public IndexOptionsBuilder geoSpatialRange(double min, double max) { 20 | super.getResult().put("min", min); 21 | super.getResult().put("max", max); 22 | return this; 23 | } 24 | 25 | public IndexOptionsBuilder name(String value) { 26 | super.getResult().put("name", value); 27 | return this; 28 | } 29 | 30 | public IndexOptionsBuilder sparse(boolean value) { 31 | super.getResult().put("sparse", value); 32 | return this; 33 | } 34 | 35 | public IndexOptionsBuilder unique(boolean value) { 36 | super.getResult().put("unique", value); 37 | return this; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/temp/java/tools/mongodb/builder/SortByBuilder.java: -------------------------------------------------------------------------------- 1 | package tools.mongodb.builder; 2 | 3 | import com.mongodb.BasicDBObject; 4 | 5 | public class SortByBuilder extends Builder { 6 | public SortByBuilder asc(String... keys) { 7 | BasicDBObject operates = super.getResult(); 8 | for (String item : keys) { 9 | operates.put(item, 1); 10 | } 11 | return this; 12 | } 13 | 14 | public SortByBuilder desc(String... keys) { 15 | BasicDBObject operates = super.getResult(); 16 | for (String item : keys) { 17 | operates.put(item, -1); 18 | } 19 | return this; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/temp/java/tools/redis/Executable.java: -------------------------------------------------------------------------------- 1 | package tools.redis; 2 | 3 | /** 4 | * 表示是可执行的,用来做回调 5 | * 6 | * @author liusan.dyf 7 | */ 8 | public interface Executable { 9 | void execute(Object value); 10 | } 11 | -------------------------------------------------------------------------------- /src/temp/java/tools/redis/NotImplementedException.java: -------------------------------------------------------------------------------- 1 | package tools.redis; 2 | 3 | public class NotImplementedException extends RuntimeException { 4 | 5 | /** 6 | * 7 | */ 8 | private static final long serialVersionUID = 7519157539998121833L; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/temp/java/tools/redis/RedisMap.java: -------------------------------------------------------------------------------- 1 | package tools.redis; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import redis.clients.jedis.Jedis; 8 | import redis.clients.jedis.JedisPool; 9 | 10 | /** 11 | * 2012-03-06 12 | * 13 | * @author liusan.dyf 14 | */ 15 | public class RedisMap implements Map { 16 | 17 | private JedisPool pool; 18 | private String name; 19 | 20 | public RedisMap(String name, JedisPool pool) { 21 | this.name = name; 22 | this.pool = pool; 23 | } 24 | 25 | public List popAll() { 26 | // 为什么不能getAll()然后再clear,因为在并发情况下,getAll操作完成后,队列里还有可能已经插入了新的元素 27 | 28 | // 1,得到此刻所有的key 29 | Set keys = this.keySet(); 30 | 31 | // 2,根据这些key拉取所有的值 32 | List list = getAll(keys); 33 | 34 | // 3,删除这些key 35 | removeAll(keys); 36 | 37 | // 4,返回结果 38 | return list; 39 | } 40 | 41 | public List getAll(Collection keys) { 42 | Jedis client = pool.getResource(); 43 | try { 44 | String[] arr = (String[]) keys.toArray(new String[0]); 45 | return client.hmget(name, arr); 46 | } finally { 47 | pool.returnResource(client); 48 | } 49 | } 50 | 51 | public int removeAll(Collection keys) { 52 | Jedis client = pool.getResource(); 53 | try { 54 | // 暂时还不支持hmdel命令 55 | // String[] arr = (String[]) keys.toArray(new String[0]); 56 | // return client.hmdel(name, arr); 57 | 58 | int i = 0; 59 | for (String item : keys) 60 | i += client.hdel(name, item); 61 | 62 | return i; 63 | } finally { 64 | pool.returnResource(client); 65 | } 66 | } 67 | 68 | @Override 69 | public int size() { 70 | Jedis client = pool.getResource(); 71 | try { 72 | long i = client.hlen(name); 73 | return (int) i; 74 | } finally { 75 | pool.returnResource(client); 76 | } 77 | } 78 | 79 | @Override 80 | public boolean isEmpty() { 81 | return size() == 0; 82 | } 83 | 84 | @Override 85 | public boolean containsKey(Object key) { 86 | Jedis client = pool.getResource(); 87 | try { 88 | return client.hexists(name, key.toString()); 89 | } finally { 90 | pool.returnResource(client); 91 | } 92 | } 93 | 94 | @Override 95 | public boolean containsValue(Object value) { 96 | throw new NotImplementedException(); 97 | } 98 | 99 | @Override 100 | public String get(Object key) { 101 | Jedis client = pool.getResource(); 102 | try { 103 | return client.hget(name, key.toString()); 104 | } finally { 105 | pool.returnResource(client); 106 | } 107 | } 108 | 109 | @Override 110 | public String put(String key, String value) { 111 | Jedis client = pool.getResource(); 112 | try { 113 | client.hset(name, key, value); 114 | return value; 115 | } finally { 116 | pool.returnResource(client); 117 | } 118 | } 119 | 120 | @Override 121 | public String remove(Object key) { 122 | Jedis client = pool.getResource(); 123 | try { 124 | String rtn = get(key);// 返回被删除的元素 125 | client.hdel(name, key.toString()); 126 | return rtn; 127 | } finally { 128 | pool.returnResource(client); 129 | } 130 | } 131 | 132 | @SuppressWarnings("unchecked") 133 | @Override 134 | public void putAll(Map m) { 135 | Jedis client = pool.getResource(); 136 | try { 137 | // for (String item : m.keySet()) { 138 | // client.hset(name, item, m.get(item)); 139 | // } 140 | 141 | client.hmset(name, (Map) m); 142 | } finally { 143 | pool.returnResource(client); 144 | } 145 | } 146 | 147 | @Override 148 | public void clear() { 149 | Jedis client = pool.getResource(); 150 | try { 151 | client.del(name); 152 | } finally { 153 | pool.returnResource(client); 154 | } 155 | } 156 | 157 | @Override 158 | public Set keySet() { 159 | Jedis client = pool.getResource(); 160 | try { 161 | return client.hkeys(name); 162 | } finally { 163 | pool.returnResource(client); 164 | } 165 | } 166 | 167 | @Override 168 | public Collection values() { 169 | Jedis client = pool.getResource(); 170 | try { 171 | return client.hvals(name); 172 | } finally { 173 | pool.returnResource(client); 174 | } 175 | } 176 | 177 | @Override 178 | public Set> entrySet() { 179 | Jedis client = pool.getResource(); 180 | try { 181 | return client.hgetAll(name).entrySet(); 182 | } finally { 183 | pool.returnResource(client); 184 | } 185 | } 186 | 187 | public JedisPool getPool() { 188 | return pool; 189 | } 190 | 191 | public void setPool(JedisPool pool) { 192 | this.pool = pool; 193 | } 194 | 195 | public String getName() { 196 | return name; 197 | } 198 | 199 | public void setName(String name) { 200 | this.name = name; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/temp/java/tools/redis/RedisUtil.java: -------------------------------------------------------------------------------- 1 | package tools.redis; 2 | 3 | import java.net.URI; 4 | import java.net.URISyntaxException; 5 | import java.util.Map; 6 | 7 | import org.apache.commons.logging.Log; 8 | import org.apache.commons.logging.LogFactory; 9 | 10 | import redis.clients.jedis.JedisPool; 11 | import redis.clients.jedis.JedisPoolConfig; 12 | import tools.StringUtil; 13 | 14 | /** 15 | * 2012-02-21 16 | * 17 | * @author liusan.dyf 18 | */ 19 | public class RedisUtil { 20 | 21 | private static final Log LOGGER = LogFactory.getLog("redis"); 22 | 23 | /** 24 | * 2012-02-14 by liusan.dyf,用于产生redispool
25 | * eg. redis://user:pass@127.0.0.1:6379/?max_active=10&max_idle=20&max_wait= 1000&timeout=5000 26 | * 27 | * @param uriString 28 | * @return 29 | * @throws URISyntaxException 30 | */ 31 | public static JedisPool createRedisPool(String uriString) throws URISyntaxException { 32 | LOGGER.debug("uriString:" + uriString); 33 | 34 | // redis://user:pass@127.0.0.1:6379/?max_active=10&max_idle=20&max_wait=1000&timeout=5000 35 | URI uri = new URI(uriString); 36 | String ip = uri.getHost();// ip 37 | 38 | int port = uri.getPort(); 39 | String auth = uri.getUserInfo();// user:pass 40 | 41 | // 解析密码 42 | String pass = null; 43 | if (!tools.StringUtil.isNullOrEmpty(auth)) { 44 | int index = auth.indexOf(':'); 45 | if (index > -1) 46 | pass = auth.substring(index + 1); 47 | 48 | // 2012-02-15 由于jedis驱动的问题,密码为""也会发送过去,必须为null 49 | if (tools.StringUtil.isNullOrEmpty(pass)) 50 | pass = null; 51 | } 52 | String queryString = uri.getRawQuery();// getRawQuery未解码 53 | 54 | // 选项 55 | Map options = StringUtil.parseQueryString(queryString, "utf-8"); 56 | int max_active = tools.Convert.toInt(options.get("max_active"), 10); 57 | int max_idle = tools.Convert.toInt(options.get("max_idle"), 20); 58 | int max_wait = tools.Convert.toInt(options.get("max_wait"), 1000); 59 | int timeout = tools.Convert.toInt(options.get("timeout"), 2000); 60 | 61 | // 2012-02-14 62 | LOGGER.debug(String.format("redis-pool-config:ip:%s,max_active:%d,max_idle:%d,max_wait:%d,timeout:%d", ip, 63 | max_active, max_idle, max_wait, timeout)); 64 | 65 | JedisPoolConfig config = new JedisPoolConfig(); 66 | config.setMaxActive(max_active); 67 | config.setMaxIdle(max_idle); 68 | config.setMaxWait(max_wait); 69 | config.setTestOnBorrow(true); 70 | 71 | return new JedisPool(config, ip, port, timeout, pass); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/temp/test/tools/quartz/CronTest.java: -------------------------------------------------------------------------------- 1 | package tools.test.quartz; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import org.junit.Test; 7 | import tools.quartz.JobScheduler; 8 | 9 | public class CronTest { 10 | @Test 11 | public void nextTest() throws Throwable { 12 | System.out.println(tools.Convert.toString(new Date())); 13 | 14 | List list = JobScheduler.getNextValidTimes("0 0/1 * * * ? *", -1, 1); 15 | for (Date item : list) { 16 | System.out.println(tools.Convert.toString(item)); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/temp/test/tools/quartz/HelloJob.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2005 - 2009 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy 6 | * of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | * 16 | */ 17 | 18 | package tools.test.quartz; 19 | 20 | import org.quartz.Job; 21 | import org.quartz.JobExecutionContext; 22 | import org.quartz.JobExecutionException; 23 | 24 | /** 25 | *

26 | * This is just a simple job that says "Hello" to the world. 27 | *

28 | * 29 | * @author Bill Kratzer 30 | */ 31 | public class HelloJob implements Job { 32 | 33 | /** 34 | *

35 | * Empty constructor for job initilization 36 | *

37 | *

38 | * Quartz requires a public empty constructor so that the scheduler can instantiate the class whenever it needs. 39 | *

40 | */ 41 | public HelloJob() { 42 | } 43 | 44 | /** 45 | *

46 | * Called by the {@link org.quartz.Scheduler} when a {@link org.quartz.Trigger} fires that 47 | * is associated with the Job. 48 | *

49 | * 50 | * @throws JobExecutionException if there is an exception while executing the job. 51 | */ 52 | public void execute(JobExecutionContext context) throws JobExecutionException { 53 | 54 | // Say Hello to the World and display the date/time 55 | System.out.println("Hello World! - " + context.getJobDetail().getJobDataMap().get("id")); 56 | 57 | // 计数 58 | SimpleExample.atomicInteger.incrementAndGet(); 59 | 60 | // 睡睡 61 | try { 62 | Thread.sleep(200); 63 | } catch (InterruptedException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/temp/test/tools/quartz/SimpleExample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2005 - 2009 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy 6 | * of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | * 16 | */ 17 | 18 | package tools.test.quartz; 19 | 20 | import java.util.Date; 21 | import java.util.HashMap; 22 | import java.util.concurrent.atomic.AtomicInteger; 23 | 24 | import org.quartz.JobDataMap; 25 | import org.quartz.Scheduler; 26 | import org.quartz.SchedulerException; 27 | import org.quartz.SchedulerFactory; 28 | import org.quartz.impl.StdSchedulerFactory; 29 | import tools.quartz.JobScheduler; 30 | 31 | /** 32 | * This Example will demonstrate how to start and shutdown the Quartz scheduler and how to schedule a job to run in 33 | * Quartz. 34 | * 35 | * @author Bill Kratzer 36 | */ 37 | public class SimpleExample { 38 | 39 | public static AtomicInteger atomicInteger = new AtomicInteger(0); 40 | 41 | public void runV2() throws SchedulerException, InterruptedException { 42 | 43 | // 创建工厂 44 | SchedulerFactory sf = new StdSchedulerFactory(); 45 | 46 | Scheduler sched = sf.getScheduler(); 47 | 48 | // 创建JobScheduler,设置调度器 49 | JobScheduler jobScheduler = new JobScheduler(sched); 50 | 51 | // 创建一批job 52 | for (int i = 0; i < 1000; i++) { 53 | HashMap data = new HashMap(); 54 | data.put("id", i); 55 | jobScheduler.addJob(new Date(), HelloJob.class, data, null); 56 | } 57 | 58 | String jobName = "cc"; 59 | 60 | // 创建周期性job 61 | HashMap data = new HashMap(); 62 | data.put("id", -1); 63 | jobScheduler.addJob(new Date(), HelloJob.class, data, jobName, 1, -1); 64 | 65 | // 任务重复了,添加失败 66 | boolean f = jobScheduler.addJob(new Date(), HelloJob.class, null, jobName, 1, -1); 67 | System.out.println(f + ""); 68 | 69 | // 开始做 70 | jobScheduler.start(); 71 | 72 | // 得到任务数据并修改 73 | Thread.sleep(200); 74 | JobDataMap jobData = jobScheduler.getJobData(jobName); 75 | if (jobData != null) { 76 | System.out.println(jobData.get("id").toString()); 77 | jobData.put("id", -2);// 修改是无效的 78 | jobScheduler.setJobData(jobName, jobData); 79 | } 80 | 81 | // jobScheduler.getScheduler().pauseAll(); 82 | 83 | // 删除job 84 | Thread.sleep(600); 85 | jobScheduler.deleteJob(jobName); 86 | 87 | // sleep 88 | Thread.sleep(10L * 1000L); 89 | 90 | // 看看目前还有多少任务还在做 2012-02-17 91 | System.out.println(jobScheduler.getScheduler().getCurrentlyExecutingJobs().size()); 92 | 93 | // 关闭 94 | jobScheduler.shutdown(true); 95 | 96 | // 看看执行了多少job 97 | System.out.println(atomicInteger.get() + ""); 98 | } 99 | 100 | public static void main(String[] args) throws Exception { 101 | SimpleExample example = new SimpleExample(); 102 | example.runV2(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/temp/test/tools/redis/MapTest.java: -------------------------------------------------------------------------------- 1 | package tools.test.redis; 2 | 3 | import java.net.URISyntaxException; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import org.junit.Assert; 10 | 11 | import org.junit.Test; 12 | 13 | import redis.clients.jedis.JedisPool; 14 | import tools.redis.RedisMap; 15 | import tools.redis.RedisUtil; 16 | 17 | public class MapTest { 18 | 19 | private static JedisPool pool; 20 | 21 | static { 22 | try { 23 | pool = createPool(); 24 | } catch (URISyntaxException e) { 25 | e.printStackTrace(); 26 | } 27 | } 28 | 29 | static JedisPool createPool() throws URISyntaxException { 30 | return RedisUtil 31 | .createRedisPool("redis://10.13.42.36:6379/?max_active=10&max_idle=5&max_wait=1000&timeout=1000&testKey=testValue"); 32 | } 33 | 34 | @Test 35 | public void putAllTest() { 36 | RedisMap m = new RedisMap("m", pool); 37 | m.clear(); 38 | 39 | Map to = new HashMap(); 40 | to.put("a", "1"); 41 | 42 | m.putAll(to); 43 | 44 | Assert.assertEquals(m.size(), 1); 45 | } 46 | 47 | @Test 48 | public void toArrayTest() { 49 | List list = new ArrayList(); 50 | list.add("1"); 51 | list.add("2"); 52 | 53 | String[] arr = (String[]) list.toArray(new String[0]); 54 | Assert.assertEquals(list.size(), arr.length); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/temp/test/tools/redis/QueueTest.java: -------------------------------------------------------------------------------- 1 | package tools.test.redis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import redis.clients.jedis.JedisPool; 7 | import redis.clients.jedis.JedisPoolConfig; 8 | import tools.redis.Executable; 9 | import tools.redis.RedisQueue; 10 | 11 | /** 12 | * 依赖commons.pool 13 | * 14 | * @author liusan.dyf 15 | */ 16 | public class QueueTest { 17 | private static JedisPool pool; 18 | 19 | static { 20 | pool = createPool(); 21 | } 22 | 23 | static JedisPool createPool() { 24 | JedisPoolConfig config = new JedisPoolConfig(); 25 | config.setMaxActive(1); 26 | config.setMaxIdle(20); 27 | config.setMaxWait(1000); 28 | config.setTestOnBorrow(true); 29 | 30 | return new JedisPool(config, "127.0.0.1"); 31 | } 32 | 33 | /** 34 | * @param args 35 | * @throws InterruptedException 36 | */ 37 | public static void main(String[] args) throws InterruptedException { 38 | // // 连接断了还可以继续放池里用 39 | // Jedis client = pool.getResource(); 40 | // client.disconnect(); 41 | // pool.returnResource(client); 42 | 43 | // 队列 44 | final RedisQueue q = new RedisQueue(pool, "q"); 45 | // q.add("1"); 46 | // q.add("2"); 47 | // q.remove("2"); 48 | List list = new ArrayList(); 49 | list.add("a"); 50 | list.add("b"); 51 | 52 | q.addAll(list); 53 | System.out.println("size is " + q.size()); 54 | System.out.println("first is " + q.element()); 55 | 56 | // 开个线程,来停止拉取 57 | Thread th = new Thread(new Runnable() { 58 | @Override 59 | public void run() { 60 | try { 61 | Thread.sleep(1000 * 10); 62 | } catch (InterruptedException e) { 63 | e.printStackTrace(); 64 | } 65 | 66 | q.stopBlockingPoll(); 67 | } 68 | }); 69 | th.setDaemon(true); 70 | // th.start(); 71 | 72 | // // 放入队列速度测试 73 | // long start = System.currentTimeMillis(); 74 | // for (int i = 0; i < 100000; i++) { 75 | // q.add("http://..."); 76 | // } 77 | // System.out.println(System.currentTimeMillis() - start); 78 | // 79 | // return; 80 | 81 | // 拉取 82 | q.setCallback(new Executable() { 83 | int i = 0; 84 | 85 | @Override 86 | public void execute(Object value) { 87 | System.out.println(value); 88 | i++; 89 | if ((i % 1000) == 0) 90 | System.out.println(i); 91 | } 92 | }); 93 | 94 | q.setErrorCallback(new Executable() { 95 | @Override 96 | public void execute(Object value) { 97 | // 转换参数 98 | Object[] arr = (Object[]) value; 99 | 100 | // 第一个参数 101 | RedisQueue r = (RedisQueue) arr[0]; 102 | r.getPool().destroy(); 103 | 104 | // 第二个参数是异常信息 105 | // System.out.println(arr[1].getClass().toString()); 106 | 107 | // 服务器突然中断了,down了 2012-02-07 108 | System.out.println("redis server is down,because of " + arr[1].getClass().getName()); 109 | 110 | // 等会儿继续 111 | try { 112 | Thread.sleep(1000 * 5); 113 | } catch (InterruptedException e) { 114 | 115 | } 116 | 117 | // 继续连接 118 | r.setPool(createPool()); 119 | q.startBlockingPoll(); 120 | } 121 | }); 122 | 123 | q.startBlockingPoll(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/test/java/tools/test/BeanTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.Date; 4 | import java.util.Map; 5 | 6 | public class BeanTest { 7 | public static void main(String[] args) { 8 | A a = new A(); 9 | a.setId(10086); 10 | 11 | B b = new B(); 12 | 13 | // copy 14 | tools.BeanUtil.copy(a, b); 15 | 16 | System.out.println(tools.Json.toString(b)); 17 | 18 | // fill 19 | Map map = tools.MapUtil.create(); 20 | map.put("name", "六三"); 21 | map.put("date", new Date()); 22 | tools.BeanUtil.fill(b, map); 23 | 24 | System.out.println(tools.Json.toString(b)); 25 | } 26 | } 27 | 28 | class A { 29 | private long id; 30 | 31 | public long getId() { 32 | return id; 33 | } 34 | 35 | public void setId(long id) { 36 | this.id = id; 37 | } 38 | } 39 | 40 | class B { 41 | private long id; 42 | private String name; 43 | private Date date; 44 | 45 | public long getId() { 46 | return id; 47 | } 48 | 49 | public void setId(long id) { 50 | this.id = id; 51 | } 52 | 53 | public String getName() { 54 | return name; 55 | } 56 | 57 | public void setName(String name) { 58 | this.name = name; 59 | } 60 | 61 | public Date getDate() { 62 | return date; 63 | } 64 | 65 | public void setDate(Date date) { 66 | this.date = date; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/test/java/tools/test/BitSetTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.BitSet; 4 | 5 | public class BitSetTest { 6 | /** 7 | * @param args 8 | */ 9 | public static void main(String[] args) { 10 | BitSet bm1 = new BitSet(7); 11 | System.out.println(bm1.isEmpty() + "--" + bm1.size()); // 64 12 | 13 | BitSet bm2 = new BitSet(63); 14 | System.out.println(bm2.isEmpty() + "--" + bm2.size());// 64 15 | 16 | BitSet bm3 = new BitSet(65); 17 | System.out.println(bm3.isEmpty() + "--" + bm3.size());// 128 18 | 19 | BitSet bm4 = new BitSet(111); 20 | System.out.println(bm4.isEmpty() + "--" + bm4.size());// 128 21 | 22 | System.out.println(bm4.get(1024)); // false 23 | bm4.set(1024, true); // ���Զ����ݣ����Dz����̰߳�ȫ�� 24 | System.out.println(bm4.isEmpty() + "--" + bm4.size());// �Ѿ����ݣ�1088 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/tools/test/CategoryTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.Map; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import tools.CategoryService; 9 | import tools.MapUtil; 10 | 11 | /** 12 | * @author 六三 13 | * @version 1.0 14 | * @since 2014年12月12日 15 | */ 16 | public class CategoryTest { 17 | private CategoryService entry = getService(); 18 | 19 | private CategoryService getService() { 20 | // 构造树 21 | Map map = MapUtil.create(); 22 | map.put(1, 0); 23 | map.put(2, 1); 24 | map.put(3, 1); 25 | map.put(4, 3); 26 | map.put(5, 3); 27 | map.put(7, 0); 28 | map.put(8, 7); 29 | map.put(9, 8); 30 | 31 | // 错误的干扰数据 2016-7-22 09:45:13 by liusan.dyf 32 | // map.put(-1, -1); 33 | // map.put(0, -1); 34 | map.put(6, 6); 35 | 36 | map.put(1, 5);// 组成环状数据 37 | 38 | // 匹配测试 39 | CategoryService entry = new CategoryService(); 40 | entry.init(map); 41 | 42 | return entry; 43 | } 44 | 45 | @Test 46 | public void isChildOfTest() { 47 | Assert.assertEquals(true, entry.isChildOf(5, 1)); 48 | Assert.assertEquals(false, entry.isChildOfAny(5, "4,2")); 49 | Assert.assertEquals(true, entry.isChildOfAny(5, "3")); 50 | Assert.assertEquals(false, entry.isChildOf(5, 20)); 51 | 52 | Assert.assertEquals(false, entry.isChildOf(6, 1));// false,节点指向了自己 53 | Assert.assertEquals(false, entry.isChildOfAny(5, "4,2"));// false,环状数据,已达最大查找次数 54 | Assert.assertEquals(true, entry.isChildOfAny(9, "7,2"));// true 55 | Assert.assertEquals(false, entry.isChildOfAny(0, "7,2"));// false 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/tools/test/DateTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.Date; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | public class DateTest { 9 | final static String DATE_FORMAT = "yyyy-MM-dd"; 10 | 11 | @Test 12 | public void specialTest() { 13 | // getSpecialDate 14 | // System.out.println(tools.DateTime.getSpecialDate(null, -1, -1, 0, 0));// 整点 15 | // System.out.println(tools.DateTime.getSpecialDate(null, -1, 0, 0, 0));// 0点 16 | 17 | System.getProperties(); 18 | } 19 | 20 | @Test 21 | public void dayOfWeekTest() { 22 | Assert.assertEquals("2014-01-13", 23 | tools.DateTime.format(tools.DateTime.getMonday("2014-01-13", DATE_FORMAT), DATE_FORMAT)); 24 | Assert.assertEquals("2014-01-06", 25 | tools.DateTime.format(tools.DateTime.getMonday("2014-01-07", DATE_FORMAT), DATE_FORMAT)); 26 | } 27 | 28 | @Test 29 | public void parseTest() { 30 | final String s = "2013-01-09"; 31 | 32 | Date d = tools.DateTime.parse(s, DATE_FORMAT); 33 | System.out.println(d); 34 | 35 | new tools.code.RunTimer().run("alignTest", 100000, new Runnable() { 36 | @Override 37 | public void run() { 38 | // tools.Convert.toDateTime(s, "yyyy-MM-dd");// 255 39 | // tools.DateTime.parse(s, "yyyy-MM-dd");// 205 40 | tools.MySqlFunction.toDate(s);// 842 - 278 41 | } 42 | }); 43 | } 44 | 45 | @Test 46 | public void formatTest() { 47 | String s = "2013-01-09"; 48 | Date d = tools.DateTime.parse(s, DATE_FORMAT); 49 | Assert.assertEquals(s, tools.DateTime.format(d, DATE_FORMAT)); 50 | Assert.assertEquals(s, tools.DateTime.format(d, 0, DATE_FORMAT)); 51 | Assert.assertEquals("2013-01-08", tools.DateTime.format(d, -1, DATE_FORMAT)); 52 | Assert.assertEquals("2013-01-10", tools.DateTime.format(d, 1, DATE_FORMAT)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/tools/test/ExecutorServiceTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.Future; 6 | 7 | /** 8 | * // from http://my.oschina.net/bairrfhoinn/blog/177639 9 | * 10 | * @author omeweb 11 | * @version 1.0 12 | * @since 2014年12月26日 13 | */ 14 | public class ExecutorServiceTest { 15 | public static void main(String[] args) throws Throwable { 16 | Future f = async(); 17 | System.out.println("begin"); 18 | f.get();// 这里只是确保执行完毕 19 | System.out.println("done"); 20 | } 21 | 22 | public static Future async() { 23 | ExecutorService executorService = Executors.newSingleThreadExecutor(); 24 | 25 | Future f = executorService.submit(new Runnable() { 26 | public void run() { 27 | tools.Global.sleep(10000); 28 | } 29 | }); 30 | 31 | executorService.shutdown(); 32 | 33 | return f; 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/tools/test/FalseSharing.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | /** 4 | * from http://ifeve.com/false-sharing/ 5 | */ 6 | public final class FalseSharing implements Runnable { 7 | public final static int NUM_THREADS = 4; // change 8 | public final static long ITERATIONS = 500L * 1000L * 1000L; 9 | private final int arrayIndex; 10 | 11 | private static VolatileLong[] longs = new VolatileLong[NUM_THREADS]; 12 | 13 | static { 14 | for (int i = 0; i < longs.length; i++) { 15 | longs[i] = new VolatileLong(); 16 | } 17 | } 18 | 19 | public FalseSharing(final int arrayIndex) { 20 | this.arrayIndex = arrayIndex; 21 | } 22 | 23 | public static void main(final String[] args) throws Exception { 24 | final long start = System.nanoTime(); 25 | runTest(); 26 | System.out.println("duration = " + (System.nanoTime() - start)); 27 | } 28 | 29 | private static void runTest() throws InterruptedException { 30 | Thread[] threads = new Thread[NUM_THREADS]; 31 | 32 | for (int i = 0; i < threads.length; i++) { 33 | threads[i] = new Thread(new FalseSharing(i)); 34 | } 35 | 36 | for (Thread t : threads) { 37 | t.start(); 38 | } 39 | 40 | for (Thread t : threads) { 41 | t.join(); 42 | } 43 | } 44 | 45 | public void run() { 46 | long i = ITERATIONS + 1; 47 | while (0 != --i) { 48 | longs[arrayIndex].value = i; 49 | } 50 | } 51 | 52 | public final static class VolatileLong { 53 | public volatile long value = 0L; 54 | // public long p1, p2, p3, p4, p5, p6; // comment out 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/tools/test/FileTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Map.Entry; 9 | import java.util.Set; 10 | 11 | import org.apache.commons.io.IOUtils; 12 | import org.apache.commons.io.LineIterator; 13 | import org.junit.Assert; 14 | import org.junit.Test; 15 | 16 | public class FileTest { 17 | @Test 18 | public void specialTest() { 19 | File f = new File("d:/"); 20 | Assert.assertEquals(false, f.isFile()); 21 | Assert.assertEquals(true, new File("d:/h.txt").isFile()); 22 | 23 | // 如果File不存在,则isFile也会返回false 2014-06-11 by liusan.dyf 24 | 25 | Object obj = null; 26 | List list = new ArrayList(); 27 | for (int i = 0; i < 3; i++) { 28 | obj = new Object(); 29 | list.add(obj); 30 | } 31 | 32 | for (Object item : list) 33 | System.out.println(item); 34 | } 35 | 36 | public static void main___x(String[] args) throws Throwable { 37 | File f = new File("D:/scriptT"); 38 | FileInputStream inputStream = new FileInputStream(f); 39 | LineIterator lineIterator = IOUtils.lineIterator(inputStream, "gbk"); 40 | 41 | Map map = tools.MapUtil.create(); 42 | 43 | // 按行读取 44 | String line = null; 45 | int all = 0; 46 | 47 | while (lineIterator.hasNext()) { 48 | line = lineIterator.next(); 49 | all++; 50 | 51 | String[] arr = tools.StringUtil.split(line, "wwTest:"); 52 | // System.out.println(arr[arr.length - 1]); 53 | String name = arr[arr.length - 1]; 54 | 55 | if (map.containsKey(name)) { 56 | int n = map.get(name); 57 | map.put(name, n + 1); 58 | } else 59 | map.put(name, 1); 60 | } 61 | 62 | inputStream.close(); 63 | 64 | // 65 | Map mapCached = tools.MapUtil.create(); 66 | int x = 0; 67 | 68 | Set> set = map.entrySet(); 69 | for (Entry item : set) { 70 | int c = item.getValue(); 71 | if (c > 1) { 72 | mapCached.put(item.getKey(), c); 73 | x += c; 74 | } 75 | } 76 | 77 | // 78 | System.out.println(all); 79 | System.out.println(map.size()); 80 | System.out.println(x); 81 | System.out.println(mapCached.size()); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/tools/test/FutureTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.*; 6 | 7 | /** 8 | * 试验 Java 的 Future 用法 9 | */ 10 | public class FutureTest { 11 | 12 | public static class Task implements Callable { 13 | @Override 14 | public String call() throws Exception { 15 | String tid = String.valueOf(Thread.currentThread().getId()); 16 | System.out.printf("Thread#%s : in call\n", tid); 17 | return tid; 18 | } 19 | } 20 | 21 | public static void main(String[] args) throws InterruptedException, ExecutionException { 22 | List> results = new ArrayList>(); 23 | ExecutorService es = Executors.newCachedThreadPool(); 24 | for (int i = 0; i < 100; i++) 25 | results.add(es.submit(new Task())); 26 | 27 | for (Future res : results) 28 | System.out.println(res.get()); 29 | 30 | es.shutdown(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/tools/test/GeneratorTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.atomic.AtomicLong; 5 | 6 | import org.junit.Assert; 7 | 8 | import org.junit.Test; 9 | 10 | import tools.generator.AtomicIdGenerator; 11 | import tools.generator.FileDataStore; 12 | import tools.generator.ranged.Range; 13 | import tools.generator.ranged.RangeGenerator; 14 | import tools.generator.ranged.RangedIdGenerator; 15 | 16 | public class GeneratorTest { 17 | // @Test 18 | public void idTest() throws Throwable { 19 | final AtomicIdGenerator g = new AtomicIdGenerator("id", new FileDataStore("d:/data\\temp")); 20 | 21 | final Map map = new java.util.concurrent.ConcurrentHashMap(); 22 | 23 | // 多线程测试ranged 24 | int count = 20; 25 | Thread[] array = new Thread[count]; 26 | for (int i = 0; i < count; i++) { 27 | Thread th = new Thread(new Runnable() { 28 | 29 | @Override 30 | public void run() { 31 | for (int j = 0; j < 5; j++) { 32 | long v = g.next(); 33 | if (!map.containsKey(v)) { 34 | map.put(v, v); 35 | System.out.println(Thread.currentThread().getName() + ":got " + v); 36 | } else 37 | System.out.println(Thread.currentThread().getName() + "------重复了,v=" + v); 38 | } 39 | 40 | } 41 | }); 42 | 43 | th.setDaemon(true); 44 | th.setName("thread_" + i); 45 | 46 | th.start(); 47 | 48 | array[i] = th; 49 | } 50 | 51 | // 等待线程关闭 52 | for (int i = 0; i < count; i++) { 53 | try { 54 | array[i].join(); 55 | } catch (InterruptedException e) { 56 | System.out.println(e); 57 | } 58 | } 59 | 60 | Thread.sleep(1000); 61 | } 62 | 63 | @Test 64 | public void rangeTest() throws Exception { 65 | Assert.assertEquals(1, 1); 66 | 67 | // 原始计数器 68 | AtomicIdGenerator g = new AtomicIdGenerator("id", null); 69 | 70 | final AtomicLong id = new AtomicLong(0); 71 | 72 | // 区间计数器 73 | final RangedIdGenerator ranged = new RangedIdGenerator(g, new RangeGenerator() { 74 | 75 | @Override 76 | public Range next(String key) { 77 | 78 | // System.out.println("获取新的区间"); 79 | long v = id.get(); 80 | long end = v + 1; 81 | 82 | while (id.compareAndSet(v, end)) 83 | return new Range(v, end); 84 | 85 | return null; 86 | } 87 | 88 | @Override 89 | public Range current(String key) { 90 | return null; 91 | } 92 | 93 | @Override 94 | public boolean save(String key, Range g) { 95 | return false; 96 | } 97 | }); 98 | 99 | final Map map = new java.util.concurrent.ConcurrentHashMap(); 100 | 101 | // 多线程测试ranged 102 | int count = 20; 103 | Thread[] array = new Thread[count]; 104 | for (int i = 0; i < count; i++) { 105 | Thread th = new Thread(new Runnable() { 106 | 107 | @Override 108 | public void run() { 109 | for (int j = 0; j < 5; j++) { 110 | 111 | // 取 112 | long v = ranged.next(); 113 | if (!map.containsKey(v)) { 114 | map.put(v, v); 115 | // System.out.println(Thread.currentThread().getName() + ":got " + v); 116 | } else 117 | System.out.println(Thread.currentThread().getName() + "------重复了,v=" + v); 118 | 119 | // sleep 120 | try { 121 | Thread.sleep(8); 122 | } catch (InterruptedException e) { 123 | e.printStackTrace(); 124 | } 125 | } 126 | 127 | } 128 | }); 129 | 130 | th.setDaemon(true); 131 | th.setName("thread_" + i); 132 | 133 | th.start(); 134 | 135 | array[i] = th; 136 | } 137 | 138 | // 等待线程关闭 139 | for (int i = 0; i < count; i++) { 140 | try { 141 | array[i].join(); 142 | } catch (InterruptedException e) { 143 | System.out.println(e); 144 | } 145 | } 146 | 147 | Thread.sleep(1000); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/test/java/tools/test/HttpTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import tools.http.HttpRequestBuilder; 4 | import tools.http.HttpResponse; 5 | 6 | public class HttpTest { 7 | 8 | public static void main(String[] args) { 9 | String url = ""; 10 | url = "http://www.baidu.com"; 11 | 12 | HttpResponse res = HttpRequestBuilder.create(url).head(); 13 | 14 | String rtn = res.setContentCharset("gbk").getString(); 15 | System.out.println("rtn=" + rtn + ", code=" + res.getResponseCode()); 16 | } 17 | 18 | public static void mainx(String[] args) { 19 | String url = "*"; 20 | 21 | HttpResponse res = HttpRequestBuilder 22 | .create(url) 23 | // .proxy("localhost", 8888) 24 | .charset("gbk") 25 | .data("script", 26 | "{\"id\":1,\"method\":\"getPagedList\",\"params\":{\"query\":{\"typeCode\":\"60\",\"keyword\":\"操作\"},\"pageSize\":20,\"pageIndex\":0},\"jsonrpc\":\"2.0\"}") 27 | .post(); 28 | 29 | String rtn = res.setContentCharset("gbk").getString(); 30 | System.out.println(rtn); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/tools/test/HttpsTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStream; 5 | import java.io.InputStreamReader; 6 | import java.net.URL; 7 | 8 | import javax.net.ssl.HostnameVerifier; 9 | import javax.net.ssl.HttpsURLConnection; 10 | import javax.net.ssl.SSLSession; 11 | 12 | public class HttpsTest { 13 | public static void main(String[] args) throws Exception { 14 | URL url = new URL("*"); 15 | HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); 16 | conn.setHostnameVerifier(new TrustAnyHostnameVerifier()); 17 | conn.connect(); 18 | InputStream ip = conn.getInputStream(); 19 | BufferedReader br = new BufferedReader(new InputStreamReader(ip)); 20 | String line; 21 | StringBuffer strb = new StringBuffer(); 22 | while ((line = br.readLine()) != null) { 23 | strb.append(line); 24 | } 25 | String ss = strb.toString(); 26 | System.out.println(ss); 27 | } 28 | } 29 | 30 | class TrustAnyHostnameVerifier implements HostnameVerifier { 31 | public boolean verify(String hostname, SSLSession session) { 32 | // 直接返回true 33 | return true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/tools/test/ImportTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import tools.test.imports.*;// 导入的是这个包下的全部的子类 4 | 5 | /** 6 | * 如果没有用到某个类,这里是不会加载的 7 | * 8 | * @author liusan.dyf 9 | * @version 1.0 10 | * @since 2015年8月3日 11 | */ 12 | public class ImportTest { 13 | public static void main(String[] args) { 14 | A1 a = new A1();// A1类会被加载 15 | System.out.println(a); 16 | 17 | // 这个分支没有走到,那A2类也不会被加载的 2015-8-3 12:07:51 by liusan.dyf 18 | if (System.currentTimeMillis() < 0) 19 | System.out.println(new A2()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/tools/test/IndexOfTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashSet; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Set; 8 | 9 | import org.junit.Assert; 10 | import org.junit.Test; 11 | 12 | import tools.FastContains; 13 | import tools.MapUtil; 14 | import tools.code.RunTimer; 15 | 16 | @SuppressWarnings("deprecation") 17 | public class IndexOfTest { 18 | @Test 19 | public void hashTest() { 20 | // string---------------------------- 21 | final String v = "1234,5687,12356,禁限售"; 22 | 23 | // 测试 24 | new RunTimer().run("indexOfTest", 1000000, new Runnable() { 25 | @Override 26 | public void run() { 27 | // v.indexOf("5687");// 33 28 | v.hashCode();// 13 29 | } 30 | }); 31 | 32 | // set---------------------------- 33 | final Set set = new HashSet(); 34 | set.add("1234"); 35 | set.add("5687"); 36 | set.add("12356"); 37 | set.add("禁限售"); 38 | 39 | Assert.assertEquals(true, set.contains("5687")); 40 | 41 | // 测试 42 | new RunTimer().run("hashTest", 1000000, new Runnable() { 43 | @SuppressWarnings("unused") 44 | int i = 0; 45 | 46 | @Override 47 | public void run() { 48 | // set.contains("5687");// 26 49 | // set.size();//14 50 | i++;// 10 51 | } 52 | }); 53 | 54 | // list---------------------------- 55 | final List list = new ArrayList(); 56 | list.add("1234"); 57 | list.add("5687"); 58 | list.add("12356"); 59 | list.add("禁限售"); 60 | 61 | Assert.assertEquals(true, list.contains("5687")); 62 | 63 | // 测试 64 | new RunTimer().run("listTest", 1000000, new Runnable() { 65 | @Override 66 | public void run() { 67 | list.contains("5687");// 29 68 | } 69 | }); 70 | } 71 | 72 | @Test 73 | public void test() { 74 | // ArrayList 75 | final ArrayList list = new ArrayList(); 76 | list.add("a"); 77 | list.add("b"); 78 | list.add("c"); 79 | list.add("d"); 80 | 81 | for (int i = 0; i < 1000000; i++) 82 | list.add(i + ""); 83 | 84 | // map 85 | final Map map = MapUtil.create(); 86 | for (String item : list) 87 | map.put(item, 1); 88 | 89 | // 90 | final String key = "a"; 91 | 92 | System.out.println("map:" + map.containsKey(key)); 93 | 94 | // 95 | final FastContains of = new FastContains(list); 96 | System.out.println("indexof:" + of.contains(key)); 97 | System.out.println("n:" + of.getN()); 98 | 99 | // 测试 100 | new RunTimer().run("indexOfTest", 1000000, new Runnable() { 101 | @Override 102 | public void run() { 103 | // of.contains(key);// 11 104 | // list.contains(key);// 36 105 | map.containsKey(key);// 22 106 | } 107 | }); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/tools/test/InlineCompiler.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.io.File; 4 | import java.io.FileWriter; 5 | import java.io.Writer; 6 | import java.net.URL; 7 | import java.net.URLClassLoader; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | import javax.tools.Diagnostic; 13 | import javax.tools.DiagnosticCollector; 14 | import javax.tools.JavaCompiler; 15 | import javax.tools.JavaFileObject; 16 | import javax.tools.StandardJavaFileManager; 17 | import javax.tools.ToolProvider; 18 | 19 | public class InlineCompiler { 20 | public static void main(String[] args) throws Throwable { 21 | StringBuilder sb = new StringBuilder(64); 22 | sb.append("package tools.test.compile;\n"); 23 | sb.append("public class HelloWorld implements tools.test.InlineCompiler.DoStuff {\n"); 24 | sb.append(" public void doStuff() {\n"); 25 | sb.append(" System.out.println(\"print:\" + tools.Convert.toString(\"Hello world\"));\n"); 26 | sb.append(" }\n"); 27 | sb.append("}\n"); 28 | 29 | File helloWorldJava = new File("./tools/test/compile/HelloWorld.java");// 注意这里的路径,和包名对应 2014-11-21 by 六三 30 | if (helloWorldJava.getParentFile().exists() || helloWorldJava.getParentFile().mkdirs()) { 31 | // 写文件 32 | Writer writer = null; 33 | try { 34 | writer = new FileWriter(helloWorldJava); 35 | writer.write(sb.toString()); 36 | writer.flush(); 37 | } finally { 38 | try { 39 | writer.close(); 40 | } catch (Exception e) { 41 | ; 42 | } 43 | } 44 | } 45 | 46 | /** Compilation Requirements *********************************************************************************************/ 47 | DiagnosticCollector diagnostics = new DiagnosticCollector(); 48 | JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 49 | StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); 50 | 51 | // This sets up the class path that the compiler will use. 52 | // I've added the .jar file that contains the DoStuff interface within in it... 53 | List optionList = new ArrayList(); 54 | optionList.add("-classpath"); 55 | optionList.add(System.getProperty("java.class.path") + ";"); 56 | 57 | Iterable compilationUnit = fileManager.getJavaFileObjectsFromFiles(Arrays 58 | .asList(helloWorldJava)); 59 | 60 | JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, optionList, null, 61 | compilationUnit); 62 | 63 | /** Compilation Requirements **/ 64 | 65 | if (task.call()) { 66 | /** Load and execute **/ 67 | System.out.println("Yipe"); 68 | // Create a new custom class loader, pointing to the directory that contains the compiled 69 | // classes, this should point to the top of the package structure! 70 | URLClassLoader classLoader = new URLClassLoader(new URL[] { new File("./").toURI().toURL() }); 71 | // Load the class from the classloader by name.... 72 | Class loadedClass = classLoader.loadClass("tools.test.compile.HelloWorld"); 73 | // Create a new instance... 74 | Object obj = loadedClass.newInstance(); 75 | // Santity check 76 | if (obj instanceof DoStuff) { 77 | // Cast to the DoStuff interface 78 | DoStuff stuffToDo = (DoStuff) obj; 79 | // Run it baby 80 | stuffToDo.doStuff(); 81 | } 82 | /** Load and execute **/ 83 | } else { 84 | for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { 85 | System.out.format("Error on line %d in %s%n", diagnostic.getLineNumber(), diagnostic.getSource() 86 | .toUri()); 87 | } 88 | } 89 | fileManager.close(); 90 | } 91 | 92 | public static interface DoStuff { 93 | public void doStuff(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/test/java/tools/test/JsonTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | 5 | public class JsonTest { 6 | public static void main(String[] args) { 7 | // User entry = new User(); 8 | // entry.setUserName("omeweb"); 9 | // 10 | // System.out.println(tools.Json.toString(entry)); 11 | 12 | Entity entry = new Entity(); 13 | entry.setS("string"); 14 | entry.setBody("中国".getBytes()); 15 | 16 | String json = tools.Json.toString(entry); 17 | System.out.println(json); 18 | 19 | Entity another = tools.Json.toObject(json, Entity.class); 20 | 21 | System.out.println(new String(another.getBody())); 22 | } 23 | } 24 | 25 | class Entity { 26 | private String s; 27 | private byte[] body; 28 | 29 | private int age = 10; 30 | 31 | public String getS() { 32 | return s; 33 | } 34 | 35 | public void setS(String s) { 36 | this.s = s; 37 | } 38 | 39 | public byte[] getBody() { 40 | return body; 41 | } 42 | 43 | public void setBody(byte[] body) { 44 | this.body = body; 45 | } 46 | 47 | @JsonIgnore 48 | public int getAge() { 49 | return age; 50 | } 51 | 52 | public void setAge(int age) { 53 | this.age = age; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/tools/test/MapGetTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.Map; 4 | 5 | public class MapGetTest { 6 | public static void main(String[] args) throws Throwable { 7 | final Map m1 = tools.MapUtil.create(); 8 | final Map m2 = tools.MapUtil.concurrentHashMap(); 9 | 10 | final String key = "a"; 11 | 12 | m1.put(key, 1); 13 | m2.put(key, 1); 14 | 15 | int times = 10000000; 16 | new tools.code.RunTimer().run("perf", times, new Runnable() { 17 | @Override 18 | public void run() { 19 | // m1.get(key);//212 20 | m2.get(key);// 350 21 | } 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/tools/test/MapTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.Iterator; 4 | import java.util.Map; 5 | import java.util.Map.Entry; 6 | import java.util.Set; 7 | 8 | import org.junit.Test; 9 | 10 | import tools.code.RunTimer; 11 | 12 | public class MapTest { 13 | public static void main(String[] args) { 14 | final Map map = tools.MapUtil.create(); 15 | map.put("a", "a1"); 16 | map.put("b", "b1"); 17 | 18 | int count = 1000000; 19 | final String key = "a"; 20 | 21 | // 测试 22 | new RunTimer().run("containsKeyTest", count, new Runnable() { 23 | @Override 24 | public void run() { 25 | if (map.containsKey(key))// 有没有这个if的判断,耗时都不变:24ms 26 | map.remove(key); 27 | } 28 | }); 29 | } 30 | 31 | @Test 32 | public void test() { 33 | int count = 1000000; 34 | // 测试 35 | new RunTimer().run("entrySetTest", count, new Runnable() { 36 | @Override 37 | public void run() { 38 | Map map = getMap(); 39 | 40 | String key = null; 41 | for (Entry item : map.entrySet()) { 42 | key = item.getKey(); 43 | if ("a".equals(key)) 44 | map.remove(key); 45 | } 46 | } 47 | }); 48 | 49 | // 测试 50 | new RunTimer().run("iteratorTest", count, new Runnable() { 51 | @Override 52 | public void run() { 53 | Map map = getMap(); 54 | Iterator iterator = map.keySet().iterator(); 55 | 56 | String key = null; 57 | while (iterator.hasNext()) { 58 | key = iterator.next(); 59 | if ("a".equals(key)) 60 | iterator.remove(); 61 | } 62 | } 63 | }); 64 | 65 | // 测试 66 | new RunTimer().run("forTest", count, new Runnable() { 67 | @Override 68 | public void run() { 69 | Map map = getMap(); 70 | Set set = map.keySet(); 71 | 72 | for (String item : set) { 73 | if ("a".equals(item)) 74 | map.remove(item); 75 | } 76 | } 77 | }); 78 | 79 | // 80 | Map map = getMap(); 81 | Set set = map.keySet(); 82 | 83 | for (String item : set) { 84 | if ("a".equals(item)) 85 | map.remove(item); 86 | } 87 | System.out.println(map); 88 | } 89 | 90 | private Map getMap() { 91 | Map map = tools.MapUtil.create(); 92 | map.put("a", "a1"); 93 | map.put("b", "b1"); 94 | 95 | return map; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/test/java/tools/test/MySqlFunTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import org.junit.Assert; 4 | 5 | import org.junit.Test; 6 | 7 | import tools.MySqlFunction; 8 | 9 | public class MySqlFunTest { 10 | @Test 11 | public void substring() { 12 | Assert.assertEquals("ratica", MySqlFunction.substring("Quadratically", 5, 6)); 13 | 14 | Assert.assertEquals("aki", MySqlFunction.substring("Sakila", -5, 3)); 15 | } 16 | 17 | @Test 18 | public void find_in_set() { 19 | String v = "a\nb,c"; 20 | Assert.assertEquals(1, MySqlFunction.find_in_set("a", v)); 21 | Assert.assertEquals(3, MySqlFunction.find_in_set("c", v)); 22 | } 23 | 24 | @Test 25 | public void mod() { 26 | Assert.assertEquals(4, MySqlFunction.mod(234, 10)); 27 | Assert.assertEquals(2, MySqlFunction.mod(29, 9)); 28 | } 29 | 30 | @Test 31 | public void between() { 32 | Assert.assertEquals(true, MySqlFunction.between(15, 234, 10)); 33 | Assert.assertEquals(true, MySqlFunction.between(30, 29, 59)); 34 | } 35 | 36 | @Test 37 | public void floor() { 38 | Assert.assertEquals(1.0, MySqlFunction.floor(1.23), 0); 39 | Assert.assertEquals(-2.0, MySqlFunction.floor(-1.23), 0); 40 | } 41 | 42 | @Test 43 | public void like() { 44 | Assert.assertEquals(1, MySqlFunction.like("abc", "a%")); 45 | Assert.assertEquals(1, MySqlFunction.like("abc", "a_c")); 46 | } 47 | 48 | @Test 49 | public void strcmp() { 50 | Assert.assertEquals(-1, MySqlFunction.strcmp("text", "text2")); 51 | Assert.assertEquals(1, MySqlFunction.strcmp("text2", "text")); 52 | Assert.assertEquals(0, MySqlFunction.strcmp("text", "text")); 53 | } 54 | 55 | @Test 56 | public void truncate() { 57 | Assert.assertEquals(1.23, MySqlFunction.truncate(1.235, 2), 0); 58 | } 59 | 60 | @Test 61 | public void isTime() { 62 | Assert.assertEquals(true, MySqlFunction.isTime("10:12:13")); 63 | Assert.assertEquals(true, MySqlFunction.isTime("10:12:13.456")); 64 | Assert.assertEquals(false, MySqlFunction.isTime("10:12:13a")); 65 | Assert.assertEquals(false, MySqlFunction.isTime("100:12:13")); 66 | } 67 | 68 | @Test 69 | public void hour() { 70 | Assert.assertEquals(10, MySqlFunction.hour("10:12:13")); 71 | Assert.assertEquals(10, MySqlFunction.hour("10:12:13.456")); 72 | Assert.assertEquals(10, MySqlFunction.hour("2012-06-28 10:12:13.456")); 73 | Assert.assertEquals(0, MySqlFunction.hour("10:12:13a")); 74 | Assert.assertEquals(0, MySqlFunction.hour("100:12:13")); 75 | } 76 | 77 | @Test 78 | public void diff() { 79 | Assert.assertEquals(-2, MySqlFunction.second_diff("2012-12-03 10:12:13", "2012-12-03 10:12:15")); 80 | Assert.assertEquals(2, MySqlFunction.abs_second_diff("2012-12-03 10:12:13", "2012-12-03 10:12:15")); 81 | Assert.assertEquals(-1, MySqlFunction.datediff("2012-12-02 10:12:13", "2012-12-03 10:12:15")); 82 | } 83 | 84 | @Test 85 | public void microsecond() { 86 | Assert.assertEquals(0, MySqlFunction.microsecond("10:12:13")); 87 | Assert.assertEquals(455, MySqlFunction.microsecond("10:12:13.456")); 88 | // Assert.assertEquals(455, 89 | // MySqlFunction.microsecond("2012-06-28 10:12:13.456")); 90 | Assert.assertEquals(0, MySqlFunction.microsecond("10:12:13a")); 91 | Assert.assertEquals(0, MySqlFunction.microsecond("100:12:13")); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/test/java/tools/test/NanoTimeTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | public class NanoTimeTest { 4 | @SuppressWarnings("static-access") 5 | public static void main(String[] args) throws Exception { 6 | while (true) { 7 | long start = System.nanoTime(); 8 | for (int i = 0; i < 1; i++) 9 | Thread.currentThread().sleep(200); 10 | 11 | long end = System.nanoTime(); 12 | long cost = end - start; 13 | if (cost < 0) { 14 | System.out.println("start: " + start + ", end: " + end + ", cost: " + cost); 15 | } else 16 | System.out.println(cost / 1000 / 1000); // 换算为毫秒 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/tools/test/RandomTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | 5 | import org.junit.Test; 6 | 7 | import tools.code.RunTimer; 8 | 9 | public class RandomTest { 10 | 11 | volatile int n = 0; 12 | 13 | @Test 14 | public void r() { 15 | System.out.println("jvm 实现版本:\t" + System.getProperty("java.vm.version")); 16 | System.out.println("jvm 规范版本:\t" + System.getProperty("java.vm.specification.version")); 17 | 18 | @SuppressWarnings("unused") 19 | final AtomicLong atomic = new AtomicLong(); 20 | 21 | new RunTimer().run("random", 100000 * 100, new Runnable() { 22 | @Override 23 | public void run() { 24 | // atomic.getAndIncrement();// 3 25 | // atomic.get();// 2 26 | // boolean x = (10 < 10);// 2 27 | // Thread.currentThread().getId();// 2 28 | // tools.StringUtil.RANDOM.nextInt();// 15 29 | // System.currentTimeMillis();// 2 30 | 31 | /** 32 | * 3 33 | */ 34 | // long v = atomic.get(); 35 | // long tid = Thread.currentThread().getId(); 36 | // if(v == 0){ 37 | // atomic.compareAndSet(0, tid); 38 | // }else{ 39 | // boolean y = tid == v; 40 | // } 41 | 42 | // int x = 1322265431 % 4;// 2 43 | 44 | // int x= 1322265431 & 3;//2 45 | 46 | /** 47 | * 48 | */ 49 | // long t = atomic.incrementAndGet() & 7; // 4,100 214 50 | // boolean f = t < 1; 51 | 52 | /** 53 | * 54 | */ 55 | // int t = (n++) & 7; // 4 ,100 170 volatile 56 | // boolean f = t < 1; 57 | } 58 | }); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/tools/test/RegexpTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import jregex.Pattern; 7 | 8 | public class RegexpTest { 9 | @Test 10 | public void t() { 11 | final Pattern p = new Pattern("(\\d)+"); 12 | 13 | final java.util.regex.Pattern jp = java.util.regex.Pattern.compile("(\\d)+", 0); 14 | 15 | Assert.assertEquals(true, p.matcher("123456").matches()); 16 | 17 | new tools.code.RunTimer().run("t", 100000, new Runnable() { 18 | 19 | @Override 20 | public void run() { 21 | // p.matcher("123456").matches();//90 22 | jp.matcher("123456").matches();// 50 23 | } 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/tools/test/ReplaceTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import tools.code.RunTimer; 4 | 5 | public class ReplaceTest { 6 | public static void main(String[] args) { 7 | new RunTimer().run("replace", 100000, new Runnable() { 8 | @Override 9 | public void run() { 10 | tools.StringUtil.replace("abcd", "a", "b");// 42ms 11 | // replaceV2("abcd", "a", "b");// 44ms 12 | // tools.StringUtil.replaceAll("abcd", "a", "b");// 45ms 13 | // StringUtil.replaceAllArrayV1("abcd", new String[] { "a" }, new String[] { "b" });// 48ms/31ms 14 | } 15 | }); 16 | 17 | System.out.println(tools.StringUtil.replace("abcda", "a", "b")); 18 | System.out.println(tools.StringUtil.replace("bbb", "b", "ab")); 19 | } 20 | 21 | public static String replaceV2(String strSource, String strFrom, String strTo) { 22 | if (strFrom == null || strFrom.equals("")) 23 | return strSource; 24 | 25 | String strDest = ""; 26 | int intFromLen = strFrom.length(); 27 | int intPos; 28 | while ((intPos = strSource.indexOf(strFrom)) != -1) { 29 | strDest = strDest + strSource.substring(0, intPos); 30 | strDest = strDest + strTo; 31 | strSource = strSource.substring(intPos + intFromLen); 32 | } 33 | strDest = strDest + strSource; 34 | return strDest; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/tools/test/SizeOfTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.concurrent.atomic.AtomicIntegerArray; 4 | 5 | import com.carrotsearch.sizeof.RamUsageEstimator; 6 | 7 | /** 8 | * https://github.com/dweiss/java-sizeof 9 | * 10 | * @author liusan.dyf 11 | * @version 1.0 12 | * @since 2014年11月12日 13 | */ 14 | public class SizeOfTest { 15 | public static void main(String[] args) { 16 | int[] arr = new int[10000 * 100]; 17 | 18 | long v = RamUsageEstimator.sizeOf(arr); 19 | System.out.println(v);// 4000016 20 | System.out.println(RamUsageEstimator.humanSizeOf(arr));// 3.8 MB 21 | 22 | // 2015-8-14 10:59:54 by liusan.dyf 23 | String[] stringArray = new String[] { "abcdefg", "cd" }; 24 | System.out.println(RamUsageEstimator.sizeOf(stringArray));// 144 25 | 26 | // 2016-7-20 16:02:39 by liusan.dyf 27 | AtomicIntegerArray aia = new AtomicIntegerArray(1024 * 1024); 28 | System.out.println(RamUsageEstimator.humanSizeOf(aia));// 4 MB 29 | 30 | System.out.println(RamUsageEstimator.humanSizeOf(new int[1024 * 20]));// 80K 31 | 32 | } 33 | } 34 | 35 | // from http://mindprod.com/jgloss/sizeof.html 36 | 37 | // overhead ~8 bytes/object 38 | // boolean 1 39 | // byte 1 40 | // char 2 41 | // short 2 42 | // int 4 43 | // long 8 44 | // float 4 45 | // double 8 46 | // reference 4/8 47 | // String length * 2 + 4 48 | -------------------------------------------------------------------------------- /src/test/java/tools/test/TokenTest.java: -------------------------------------------------------------------------------- 1 | package tools.test; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.junit.Assert; 7 | 8 | import org.junit.Test; 9 | 10 | import tools.code.RunTimer; 11 | import tools.token.GenericTokenParser; 12 | import tools.token.SimpleParser; 13 | import tools.token.TokenHandler; 14 | 15 | public class TokenTest { 16 | @Test 17 | public void test() { 18 | final Map map = new HashMap(); 19 | map.put("name", "杜有发"); 20 | 21 | TokenHandler th = new TokenHandler() { 22 | @Override 23 | public String handle(String content) { 24 | return (String) map.get(content); 25 | } 26 | }; 27 | 28 | final String template = "hello ${name}"; 29 | final GenericTokenParser t = new GenericTokenParser("${", "}", th); 30 | 31 | Assert.assertEquals("hello 杜有发", t.parse(template)); 32 | 33 | // 39ms 34 | new RunTimer().run("test", 100000, new Runnable() { 35 | @Override 36 | public void run() { 37 | t.parse(template); 38 | } 39 | }); 40 | } 41 | 42 | @Test 43 | public void formatTest() { 44 | final String source = "{0} {1} {2} {3}"; 45 | 46 | // 200ms 47 | new RunTimer().run("format", 100000, new Runnable() { 48 | @Override 49 | public void run() { 50 | SimpleParser.format(source, "hello", "world", "!"); 51 | } 52 | }); 53 | 54 | // 257ms 55 | new RunTimer().run("java", 100000, new Runnable() { 56 | @Override 57 | public void run() { 58 | java.text.MessageFormat.format(source, "hello", "world", "!"); 59 | } 60 | }); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/tools/test/UnsafeTest.txt: -------------------------------------------------------------------------------- 1 | // package tools.test; 2 | // 3 | // import sun.misc.Unsafe; 4 | // import tools.Global; 5 | // 6 | // public class UnsafeTest { 7 | // private static final Unsafe unsafe = Global.getUnsafe(); 8 | // private static final long stateOffset; 9 | // 10 | // /** 11 | // * The synchronization state. 12 | // */ 13 | // private volatile int state; 14 | // 15 | // static { 16 | // try { 17 | // stateOffset = unsafe.objectFieldOffset(UnsafeTest.class.getDeclaredField("state")); 18 | // } catch (Exception ex) { 19 | // throw new Error(ex); 20 | // } 21 | // } 22 | // 23 | // public final boolean compareAndSetState(int expect, int update) { 24 | // // See below for intrinsics setup to support this 25 | // return unsafe.compareAndSwapInt(this, stateOffset, expect, update); 26 | // } 27 | // 28 | // public int getState() { 29 | // return state; 30 | // } 31 | // 32 | // public static void main(String[] args) { 33 | // UnsafeTest entry = new UnsafeTest(); 34 | // entry.compareAndSetState(0, 10); 35 | // System.out.println(entry.getState()); 36 | // 37 | // // 申请堆外内存 2014-12-15 38 | // long value = 12345; 39 | // byte size = 8; // a long is 64 bits (http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) 40 | // long allocateMemory = unsafe.allocateMemory(size); 41 | // unsafe.putLong(allocateMemory, value); 42 | // long readValue = unsafe.getLong(allocateMemory); 43 | // System.out.println("read value : " + readValue); 44 | // } 45 | // } 46 | -------------------------------------------------------------------------------- /src/test/java/tools/test/cache/CacheTest.java: -------------------------------------------------------------------------------- 1 | package tools.test.cache; 2 | 3 | import org.junit.Assert; 4 | 5 | import org.junit.Test; 6 | 7 | public class CacheTest { 8 | @Test 9 | public void testCache() throws InterruptedException { 10 | String key = "name"; 11 | Catalog value = new Catalog(); 12 | value.setTitle("xxxx"); 13 | 14 | // 创建对象 15 | tools.cache.HashMapCacheProvider c = new tools.cache.HashMapCacheProvider(); 16 | c.set(key, value, 3); 17 | 18 | // 取值 19 | Object s1 = c.get(key); 20 | System.out.println(s1); 21 | 22 | // 等待 23 | Thread.sleep(1000 * 2); 24 | 25 | // 再取 26 | Object s2 = c.get(key); 27 | System.out.println(s2); 28 | 29 | // 验证 30 | Assert.assertEquals(s1, s2); 31 | } 32 | } 33 | 34 | class Catalog { 35 | private String title; 36 | 37 | public String getTitle() { 38 | return title; 39 | } 40 | 41 | public void setTitle(String title) { 42 | this.title = title; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/tools/test/concurrent/AnotherLocal.java: -------------------------------------------------------------------------------- 1 | package tools.test.concurrent; 2 | 3 | public class AnotherLocal { 4 | private static ThreadLocal local = new ThreadLocal() { 5 | 6 | @Override 7 | protected String initialValue() { 8 | return "ThreadLocal"; 9 | } 10 | }; 11 | 12 | public String get() { 13 | return local.get().toString(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/tools/test/concurrent/Local.java: -------------------------------------------------------------------------------- 1 | package tools.test.concurrent; 2 | 3 | public class Local { 4 | private static ThreadLocal local = new ThreadLocal() { 5 | 6 | @Override 7 | protected String initialValue() { 8 | return "Local"; 9 | } 10 | }; 11 | 12 | public String get() { 13 | return local.get().toString(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/tools/test/concurrent/Main.java: -------------------------------------------------------------------------------- 1 | package tools.test.concurrent; 2 | 3 | public class Main { 4 | public static void main(String[] args) { 5 | Local a = new Local(); 6 | AnotherLocal b = new AnotherLocal(); 7 | 8 | System.out.println(a.get()); 9 | System.out.println(b.get()); 10 | 11 | // 同一个线程里可以有多个thradlocal对象 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/tools/test/counter/MultiKeyedCounterTest.java: -------------------------------------------------------------------------------- 1 | package tools.test.counter; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import tools.Action; 9 | import tools.counter.MultiKeyedCounter; 10 | 11 | public class MultiKeyedCounterTest { 12 | static MultiKeyedCounter c = new tools.counter.AtomicKeyedCounter(); 13 | static String key = "myc"; 14 | 15 | @Test 16 | public void perfTest() { 17 | final MultiKeyedCounter c = new tools.counter.AtomicKeyedCounter(); 18 | 19 | // 性能测试 20 | tools.code.RunTimer run = new tools.code.RunTimer(); 21 | run.run("x", 10000000, new Runnable() { 22 | @Override 23 | public void run() { 24 | c.increment("key");// 838 - 557 25 | } 26 | }); 27 | 28 | // 多线程测试 29 | final java.util.Random r = new java.util.Random(); 30 | tools.concurrent.Parallel.loop(100000, new Action() { 31 | @Override 32 | public void execute(Integer t) { 33 | c.increment("key_" + r.nextInt(200)); 34 | } 35 | }, 10); 36 | 37 | try { 38 | Thread.sleep(1000 * 5); 39 | } catch (InterruptedException e) { 40 | 41 | } 42 | 43 | System.out.println(c.getAll()); 44 | } 45 | 46 | @Test 47 | public void hexTest() { 48 | int threadCount = 20; 49 | 50 | final CountDownLatch threadSignal = new CountDownLatch(threadCount * 2);// 初始化countDown 51 | 52 | for (int i = 0; i < threadCount; i++) { 53 | Thread th = new Thread(new Runnable() { 54 | @Override 55 | public void run() { 56 | int x = 10000; 57 | while (x > 0) { 58 | c.increment(key); 59 | x--; 60 | } 61 | 62 | threadSignal.countDown();// 线程结束时计数器减1 63 | } 64 | }); 65 | 66 | th.setDaemon(true); 67 | th.start(); 68 | } 69 | 70 | for (int i = 0; i < threadCount; i++) { 71 | Thread th = new Thread(new Runnable() { 72 | @Override 73 | public void run() { 74 | //System.out.println("running"); 75 | 76 | int x = 10000; 77 | while (x > 0) { 78 | c.decrement(key); 79 | x--; 80 | } 81 | 82 | threadSignal.countDown();// 线程结束时计数器减1 83 | } 84 | }); 85 | 86 | th.setDaemon(true); 87 | th.start(); 88 | } 89 | 90 | try { 91 | threadSignal.await(); 92 | //Thread.sleep(100); 93 | } catch (InterruptedException e) { 94 | e.printStackTrace(); 95 | } 96 | 97 | Assert.assertEquals(c.get(key), 0); 98 | System.out.println(c.get(key)); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/test/java/tools/test/domain/User.java: -------------------------------------------------------------------------------- 1 | package tools.test.domain; 2 | 3 | public class User { 4 | private long userId; 5 | private String userName; 6 | 7 | public long getUserId() { 8 | return userId; 9 | } 10 | 11 | public void setUserId(long userId) { 12 | this.userId = userId; 13 | } 14 | 15 | public String getUserName() { 16 | return userName; 17 | } 18 | 19 | public void setUserName(String userName) { 20 | this.userName = userName; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/tools/test/imports/A1.java: -------------------------------------------------------------------------------- 1 | package tools.test.imports; 2 | 3 | public class A1 { 4 | static { 5 | System.out.println("A1"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/tools/test/imports/A2.java: -------------------------------------------------------------------------------- 1 | package tools.test.imports; 2 | 3 | public class A2 { 4 | static { 5 | System.out.println("A2"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/tools/test/jsonrpc/ComplexEntity.java: -------------------------------------------------------------------------------- 1 | package tools.test.jsonrpc; 2 | 3 | import java.util.Date; 4 | 5 | public class ComplexEntity { 6 | private Date startDate; 7 | private Date endDate; 8 | private int pageSize; 9 | private int pageIndex; 10 | private String where; 11 | 12 | public Date getStartDate() { 13 | return startDate; 14 | } 15 | 16 | public void setStartDate(Date startDate) { 17 | this.startDate = startDate; 18 | } 19 | 20 | public Date getEndDate() { 21 | return endDate; 22 | } 23 | 24 | public void setEndDate(Date endDate) { 25 | this.endDate = endDate; 26 | } 27 | 28 | public int getPageSize() { 29 | return pageSize; 30 | } 31 | 32 | public void setPageSize(int pageSize) { 33 | this.pageSize = pageSize; 34 | } 35 | 36 | public int getPageIndex() { 37 | return pageIndex; 38 | } 39 | 40 | public void setPageIndex(int pageIndex) { 41 | this.pageIndex = pageIndex; 42 | } 43 | 44 | public String getWhere() { 45 | return where; 46 | } 47 | 48 | public void setWhere(String where) { 49 | this.where = where; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/tools/test/jsonrpc/JsonrpcTest.java: -------------------------------------------------------------------------------- 1 | package tools.test.jsonrpc; 2 | 3 | import org.junit.Assert; 4 | 5 | import org.junit.Test; 6 | 7 | import tools.code.RunTimer; 8 | import tools.jsonrpc.JsonRpcError; 9 | import tools.jsonrpc.JsonRpcService; 10 | 11 | public class JsonrpcTest { 12 | public static void main(String[] args) throws Exception { 13 | System.out.println("hello jsonrpc"); 14 | new JsonrpcTest().test(); 15 | } 16 | 17 | @Test 18 | public void test_() throws Exception { 19 | Object r = JsonRpcService.invoke(new Obj(), "add", "{\"b\":10,\"a\":12}", true); 20 | System.out.println("结果是:" + r); 21 | Assert.assertEquals(22, tools.Convert.toInt(r, 0)); 22 | } 23 | 24 | @Test 25 | public void test() throws Exception { 26 | Object r = JsonRpcService.invoke(new Obj(), 27 | "{\"id\":\"100\",\"jsonrpc\":\"2.0\",\"method\":\"add\",\"params\":{\"b\":1,\"a\":2}}", true); 28 | System.out.println("结果是:" + r); 29 | 30 | Assert.assertEquals(3, tools.Convert.toInt(r, 0)); 31 | 32 | final Obj obj = new Obj(); 33 | 34 | // 测试 449ms/471ms 100000 35 | // 1525.731481 100000 * 3 2015-8-19 14:27:05 by liusan.dyf 36 | new RunTimer().run("test", 100000 * 3, new Runnable() { 37 | 38 | @Override 39 | public void run() { 40 | JsonRpcService.invoke(obj, 41 | "{\"id\":\"100\",\"jsonrpc\":\"2.0\",\"method\":\"add\",\"params\":{\"b\":1,\"a\":2}}", true); 42 | } 43 | }); 44 | } 45 | 46 | @Test 47 | public void oneParamTest() throws Exception { 48 | Object r = JsonRpcService.invoke(new Obj(), 49 | "{\"id\":\"100\",\"jsonrpc\":\"2.0\",\"method\":\"incr\",\"params\":{\"a\":1,\"b\":2}}", true); 50 | // System.out.println("结果是:" + r); 51 | 52 | Assert.assertEquals(2, tools.Convert.toInt(r, 0)); 53 | } 54 | 55 | @Test 56 | public void getMethodInfoTest() throws Exception { 57 | Object r = JsonRpcService.invoke(new Obj(), 58 | "{\"id\":\"100\",\"jsonrpc\":\"2.0\",\"method\":\"add\",\"params\":'meta.methodinfo'}", true); 59 | System.out.println("结果是:" + r); 60 | } 61 | 62 | @Test 63 | public void instanceMethodTest() throws Exception { 64 | Object r = JsonRpcService.invoke(new Obj(), 65 | "{\"id\":\"100\",\"jsonrpc\":\"2.0\",\"method\":\"newAdd\",\"params\":{\"a\":1,\"b\":2}}", true); 66 | // System.out.println("结果是:" + r); 67 | 68 | Assert.assertEquals(3, tools.Convert.toInt(r, 0)); 69 | } 70 | 71 | @Test 72 | public void noParamTest() throws Exception { 73 | Object r = JsonRpcService.invoke(new Obj(), 74 | "{\"id\":\"100\",\"jsonrpc\":\"2.0\",\"method\":\"getId\",\"params\":{\"a\":1,\"b\":2}}", true); 75 | // System.out.println("结果是:" + r); 76 | 77 | Assert.assertEquals(1, tools.Convert.toInt(r, 0)); 78 | } 79 | 80 | @Test 81 | public void multiParamTest() throws Exception { 82 | Object r = JsonRpcService.invoke(new Obj(), 83 | "{\"id\":\"100\",\"jsonrpc\":\"2.0\",\"method\":\"addMulti\",\"params\":[1,2,3]}", true); 84 | Assert.assertEquals(6, tools.Convert.toInt(r, 0)); 85 | } 86 | 87 | @Test 88 | public void toStringTest() throws Exception { 89 | String r = JsonRpcService.invokeToString(new Obj(), 90 | "d[{\"id\":99,\"jsonrpc\":\"2.0\",\"method\":\"addMulti\",\"params\":[1,2,3]},{\"id\":100,\"jsonrpc\":\"2.0\",\"method\":\"addMulti\",\"params\":[1,2,3,\"a\"]},{\"id\":102,\"jsonrpc\":\"2.0\",\"method\":\"throwException\",\"params\":null}]", 91 | true); 92 | // Assert.assertEquals(6, tools.Convert.toInt(r, 0)); 93 | System.out.println(r); 94 | } 95 | 96 | @Test 97 | public void entityParamTest() throws Exception { 98 | Object r = JsonRpcService.invoke(new Obj(), 99 | "{\"id\":\"100\",\"jsonrpc\":\"2.0\",\"method\":\"doEntity\",\"params\":{\"error\":{\"message\":\"杜有发-message\"}}}", 100 | true); 101 | 102 | // 注意json的写法 103 | Assert.assertEquals("杜有发-message", ((JsonRpcError) r).getMessage()); 104 | } 105 | 106 | @Test 107 | public void complexEntityParamTest() throws Exception { 108 | String r = JsonRpcService.invokeToString(new Obj(), 109 | "{\"id\":\"100\",\"jsonrpc\":\"2.0\",\"method\":\"doComplexEntity\",\"params\":{\"entry\":{\"startDate\":\"2011-11-02\",\"pageIndex\":10,\"pageSize\":10}}}", 110 | true); 111 | 112 | System.out.println(r); 113 | 114 | // Assert.assertEquals(10, ((ComplexEntity) r).getPageIndex()); 115 | 116 | // 测试 117 | final Obj obj = new Obj(); 118 | new RunTimer().run("complexEntityParamTest", 1, new Runnable() { 119 | 120 | @Override 121 | public void run() { 122 | JsonRpcService.invoke(obj, 123 | "{\"id\":\"100\",\"jsonrpc\":\"2.0\",\"method\":\"doComplexEntity\",\"params\":{\"entry\":{\"startDate\":\"2011-11-02\",\"pageIndex\":10,\"pageSize\":10}}}", 124 | true); 125 | } 126 | }); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/test/java/tools/test/jsonrpc/Obj.java: -------------------------------------------------------------------------------- 1 | package tools.test.jsonrpc; 2 | 3 | import tools.jsonrpc.JsonRpcError; 4 | 5 | public class Obj { 6 | 7 | // 以下是一些方法测试 8 | public static int add(int a, int b) { 9 | return a + b; 10 | } 11 | 12 | public static int addMulti(int[] args) { 13 | int r = 0; 14 | for (int v : args) 15 | r += v; 16 | return r; 17 | } 18 | 19 | public static int incr(int a) { 20 | return a + 1; 21 | } 22 | 23 | public static int getId() { 24 | return 1; 25 | } 26 | 27 | public int newAdd(int a, int b) { 28 | return a + b; 29 | } 30 | 31 | public JsonRpcError doEntity(JsonRpcError error) { 32 | return error; 33 | } 34 | 35 | public ComplexEntity doComplexEntity(ComplexEntity entry) { 36 | if (entry == null) 37 | throw new IllegalArgumentException("实体不能为null"); 38 | 39 | if (entry.getPageSize() <= 0) 40 | throw new IllegalArgumentException("实体pageSize参数不能小于等于0"); 41 | 42 | if (entry.getStartDate() == null) 43 | throw new IllegalArgumentException("实体startDate参数不能为null"); 44 | 45 | return entry; 46 | } 47 | 48 | public int throwException(JsonRpcError error) throws Exception { 49 | // throw new IllegalArgumentException("异常测试"); 50 | throw new Exception("异常测试"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/tools/test/jsonrpc/TestEx.java: -------------------------------------------------------------------------------- 1 | package tools.test.jsonrpc; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import tools.jsonrpc.JsonRpcService; 7 | 8 | public class TestEx { 9 | @Test 10 | public void mainX() { 11 | String expectedResult = "{\"id\":100,\"jsonrpc\":\"2.0\",\"result\":11}"; 12 | // 静态方法 13 | String r = JsonRpcService.invokeToString(Obj.class, 14 | "{\"id\":\"100\",\"jsonrpc\":\"2.0\",\"method\":\"add\",\"params\":{\"a\":1,\"b\":10}}", true); 15 | 16 | System.out.println(r); 17 | 18 | Assert.assertEquals(expectedResult, r); 19 | 20 | // 动态方法 21 | r = JsonRpcService.invokeToString(new Obj(), 22 | "{\"id\":\"100\",\"jsonrpc\":\"2.0\",\"method\":\"add\",\"params\":{\"a\":1,\"b\":10}}", true); 23 | 24 | System.out.println(r); 25 | Assert.assertEquals(expectedResult, r); 26 | } 27 | 28 | public static void main(String[] args) { 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/tools/test/oom/HeapOOM.java: -------------------------------------------------------------------------------- 1 | package tools.test.oom; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author Yong Huang VM args: -Xms20M -Xmx20M 8 | * 9 | *
10 |  * Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
11 |  * 	at java.util.Arrays.copyOf(Arrays.java:2760)
12 |  * 	at java.util.Arrays.copyOf(Arrays.java:2734)
13 |  * 	at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
14 |  * 	at java.util.ArrayList.add(ArrayList.java:351)
15 |  * 	at tools.test.oom.HeapOOM.main(HeapOOM.java:22)
16 |  * 
17 | */ 18 | public class HeapOOM { 19 | 20 | public HeapOOM() { 21 | // TODO Auto-generated constructor stub 22 | } 23 | 24 | static class OOMObject { 25 | 26 | } 27 | 28 | public static void main(String[] args) { 29 | List list = new ArrayList(); 30 | while (true) { 31 | list.add(new OOMObject()); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/tools/test/oom/JavaMethodAreaOOM.java: -------------------------------------------------------------------------------- 1 | package tools.test.oom; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import net.sf.cglib.proxy.Enhancer; 6 | import net.sf.cglib.proxy.MethodInterceptor; 7 | import net.sf.cglib.proxy.MethodProxy; 8 | 9 | /** 10 | * @author Yong Huang VM args: -XX:PermSize=10M -XX:MaxPermSize=10M 11 | */ 12 | public class JavaMethodAreaOOM { 13 | 14 | public JavaMethodAreaOOM() { 15 | // TODO Auto-generated constructor stub 16 | } 17 | 18 | /** 19 | * @param args 20 | */ 21 | public static void main(String[] args) { 22 | // TODO Auto-generated method stub 23 | while (true) { 24 | Enhancer enhancer = new Enhancer(); 25 | enhancer.setSuperclass(OOMObject.class); 26 | enhancer.setUseCache(false);// 设置为true则不会oom 27 | enhancer.setCallback(new MethodInterceptor() { 28 | @Override 29 | public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { 30 | // TODO Auto-generated method stub 31 | return arg3.invokeSuper(arg0, arg2); 32 | } 33 | }); 34 | enhancer.create(); 35 | } 36 | } 37 | 38 | static class OOMObject { 39 | 40 | } 41 | } 42 | 43 | // 44 | // Exception in thread "main" java.lang.OutOfMemoryError: PermGen space 45 | // at java.lang.Class.forName0(Native Method) 46 | // at java.lang.Class.forName(Class.java:247) 47 | // at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:386) 48 | // at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:219) 49 | // at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377) 50 | // at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285) 51 | // at tools.test.oom.JavaMethodAreaOOM.main(JavaMethodAreaOOM.java:35) 52 | 53 | -------------------------------------------------------------------------------- /src/test/java/tools/test/oom/JavaVMStackSOF.java: -------------------------------------------------------------------------------- 1 | package tools.test.oom; 2 | 3 | /** 4 | * @author Yong Huang VM args: -Xss128K 5 | */ 6 | public class JavaVMStackSOF { 7 | 8 | private int stackLength = 1; 9 | 10 | public JavaVMStackSOF() { 11 | // TODO Auto-generated constructor stub 12 | } 13 | 14 | public void stackLeak() { 15 | stackLength++; 16 | stackLeak(); 17 | } 18 | 19 | /** 20 | * @param args 21 | * @throws Throwable 22 | */ 23 | public static void main(String[] args) throws Throwable { 24 | // TODO Auto-generated method stub 25 | JavaVMStackSOF oom = new JavaVMStackSOF(); 26 | try { 27 | oom.stackLeak(); 28 | } catch (Throwable e) { 29 | System.out.println("stack length:" + oom.stackLength); 30 | throw e; 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/tools/test/oom/RuntimeConstantPoolOOM.java: -------------------------------------------------------------------------------- 1 | package tools.test.oom; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author Yong Huang VM args: -XX:PermSize=10M -XX:MaxPermSize=10M 8 | */ 9 | public class RuntimeConstantPoolOOM { 10 | 11 | public RuntimeConstantPoolOOM() { 12 | // TODO Auto-generated constructor stub 13 | } 14 | 15 | /** 16 | * @param args 17 | */ 18 | public static void main(String[] args) { 19 | // TODO Auto-generated method stub 20 | List list = new ArrayList(); 21 | int i = 0; 22 | while (true) { 23 | list.add(String.valueOf(i++).intern()); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/tools/test/oom/StringIntern.java: -------------------------------------------------------------------------------- 1 | package tools.test.oom; 2 | 3 | import java.util.*; 4 | 5 | public class StringIntern { 6 | public static long times = 10000000L; 7 | 8 | public static void main(String[] args) { 9 | testIntern(); 10 | } 11 | 12 | public static void testIntern() { 13 | System.gc(); 14 | 15 | List list = new ArrayList(); 16 | 17 | long l = System.currentTimeMillis(); 18 | 19 | for (int i = 0; i < times; i++) { 20 | list.add(("A" + (i % 1000)).intern()); 21 | } 22 | 23 | long ll = System.currentTimeMillis(); 24 | System.out.println("testIntern time :" + (ll - l)); 25 | 26 | System.gc(); 27 | 28 | System.out.println("testIntern:" + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/tools/test/oom/ThreadStackTrace.java: -------------------------------------------------------------------------------- 1 | package tools.test.oom; 2 | 3 | import java.util.Map; 4 | import java.util.Map.Entry; 5 | 6 | public class ThreadStackTrace { 7 | public static void main(String[] args) { 8 | // 新起一个线程 9 | new Thread(new Runnable() { 10 | @Override 11 | public void run() { 12 | try { 13 | Thread.sleep(1000 * 10); 14 | } catch (InterruptedException e) { 15 | e.printStackTrace(); 16 | } 17 | } 18 | }, "Test-thread").start(); 19 | 20 | // 21 | Map stacktraces = Thread.getAllStackTraces(); 22 | for (Entry stacktrace : stacktraces.entrySet()) { 23 | Thread thread = stacktrace.getKey(); 24 | 25 | // Filter current thread 26 | if (Thread.currentThread().equals(thread)) { 27 | continue; 28 | } 29 | 30 | System.out.println("线程:" + thread.getName()); 31 | StackTraceElement[] elems = stacktrace.getValue(); 32 | 33 | for (StackTraceElement elem : elems) { 34 | System.out.println("\t" + elem); 35 | } 36 | 37 | System.out.println("------------------------------"); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/tools/test/session/MySessionService.java: -------------------------------------------------------------------------------- 1 | package tools.test.session; 2 | 3 | import tools.ObjectConverter; 4 | import tools.session.SessionServiceBase; 5 | import tools.test.domain.User; 6 | 7 | public class MySessionService extends SessionServiceBase { 8 | public MySessionService() { 9 | super.setConverter(new MyConverter()); 10 | super.setStorer(new tools.Context()); 11 | } 12 | } 13 | 14 | class MyConverter implements ObjectConverter { 15 | 16 | @Override 17 | public User from(String v) { 18 | User entry = new User(); 19 | entry.setUserName(v); 20 | return entry; 21 | } 22 | 23 | @Override 24 | public String to(User t) { 25 | return t.getUserName() + "."; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/tools/test/session/SessionTest.java: -------------------------------------------------------------------------------- 1 | package tools.test.session; 2 | 3 | import org.junit.Test; 4 | 5 | import tools.test.domain.User; 6 | 7 | public class SessionTest { 8 | 9 | @Test 10 | public void test() throws InterruptedException { 11 | final MySessionService s = new MySessionService(); 12 | 13 | // 开n个线程 14 | Thread[] arr = new Thread[15]; 15 | for (int i = 0; i < arr.length; i++) { 16 | Thread th = new Thread() { 17 | @Override 18 | public void run() { 19 | long id = Thread.currentThread().getId(); 20 | User entry = new User(); 21 | entry.setUserName(id + ""); 22 | s.set(entry); 23 | 24 | try { 25 | Thread.sleep(1000); 26 | } catch (InterruptedException e) { 27 | 28 | } 29 | 30 | System.out.println(id + ":" + s.get().getUserName()); 31 | } 32 | }; 33 | th.setDaemon(true); 34 | th.start(); 35 | 36 | arr[i] = th; 37 | } 38 | 39 | // 等待线程结束 40 | for (int i = 0; i < arr.length; i++) { 41 | arr[i].join(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/tools/test/spring/BeanTest.java: -------------------------------------------------------------------------------- 1 | package tools.test.spring; 2 | 3 | import tools.spring.AsyncInitBeanFactory; 4 | 5 | public class BeanTest { 6 | static { 7 | // System.out.println("..."); 8 | String[] locations = { "classpath:applicationContext.xml" }; 9 | 10 | AsyncInitBeanFactory.initBeans(locations, 4); 11 | } 12 | 13 | public static void main(String[] args) { 14 | Object bean = tools.spring.SpringContext.getBean("slowBean"); 15 | System.out.println(bean == null); 16 | 17 | bean = tools.spring.SpringContext.getBean("slowBean_2"); 18 | System.out.println(bean == null); 19 | 20 | // tools.Global.sleep(1000 * 2); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/tools/test/spring/SlowBean.java: -------------------------------------------------------------------------------- 1 | package tools.test.spring; 2 | 3 | public class SlowBean { 4 | public void init() { 5 | System.out.println("begin init"); 6 | 7 | tools.Global.sleep(1000 * 10); 8 | 9 | System.out.println("end init"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/test/resources/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/test/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | --------------------------------------------------------------------------------