Java tutorial
/** * (C) 2011-2012 Alibaba Group Holding Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * */ /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.taobao.common.tedis.group; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.juhuasuan.osprey.OspreyManager; import com.juhuasuan.osprey.OspreyProcessor; import com.juhuasuan.osprey.Result; import com.taobao.common.tedis.Group; import com.taobao.common.tedis.Single; import com.taobao.common.tedis.TedisConnectionException; import com.taobao.common.tedis.TedisException; import com.taobao.common.tedis.binary.RedisCommands; import com.taobao.common.tedis.config.ConfigManager; import com.taobao.common.tedis.config.Process; import com.taobao.common.tedis.config.Process.Policy; import com.taobao.common.tedis.config.Router; import com.taobao.common.tedis.monitor.BufferedStatLogWriter; /** * , * * @author juxin.zj E-mail:juxin.zj@taobao.com * @since 2012-3-26 10:37:19 * @version 1.0 */ public class ReliableAsynTedisGroup implements Group { static final Log logger = LogFactory.getLog(ReliableAsynTedisGroup.class); private ConfigManager cm; private RedisCommands tedis; private String appName; private String version; private volatile boolean inited = false; private OspreyManager ospreyManager; public ReliableAsynTedisGroup(String appName, String version) { this.appName = appName; this.version = version; } public void init() { if (!inited) { try { if (this.cm == null) { this.cm = new DiamondConfigManager(appName, version); } this.ospreyManager = new OspreyManager("tedis-" + appName + "-" + version); this.ospreyManager.registerProcessor(new OspreyProcessor<ReliableAsynMessage>() { @Override public Class<ReliableAsynMessage> interest() { return ReliableAsynMessage.class; } @Override public Result process(ReliableAsynMessage message) { Result result = new Result(); long time = System.currentTimeMillis(); Single single = cm.getRouter().getAtomic(message.getSingleKey()); if (single == null) { result.setSuccess(false); result.setErrorMessage("Current atomic is null"); return result; } try { message.getMethod().invoke(single.getTedis(), message.getArgs()); } catch (Throwable t) { logger.warn("write exception:" + single.getProperties(), t); try { statLog(message.getMethod().getName(), false, time); // InvocationTargetException ite = (InvocationTargetException) t; UndeclaredThrowableException ute = (UndeclaredThrowableException) ite .getTargetException(); if (ute.getUndeclaredThrowable() instanceof TimeoutException) { result.setSuccess(false); result.setErrorMessage("TimeoutException"); result.setRuntimeException(ute); return result; } else { ExecutionException ee = (ExecutionException) ute.getUndeclaredThrowable(); InvocationTargetException ite_1 = (InvocationTargetException) ee.getCause(); TedisException te = (TedisException) ite_1.getTargetException(); if (te.getCause() instanceof TedisConnectionException) { result.setSuccess(false); result.setErrorMessage("JedisConnectionException"); result.setRuntimeException(te); return result; } } } catch (Throwable tt) { logger.warn(":", tt); } } return result; } }); this.ospreyManager.init(); tedis = (RedisCommands) Proxy.newProxyInstance(RedisCommands.class.getClassLoader(), new Class[] { RedisCommands.class }, new TedisGroupInvocationHandler()); } catch (Exception e) { throw new TedisException("init failed", e); } inited = true; } } public RedisCommands getTedis() { if (tedis == null) { throw new TedisException("please invoke the init method first."); } return tedis; } public class TedisGroupInvocationHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long time = System.currentTimeMillis(); String name = method.getName(); Router rr = cm.getRouter(); Process annotation = method.getAnnotation(Process.class); Throwable exception = null; if (annotation.value() == Policy.READ) { while (rr.getRouteData().props.size() > 0) { Single s = rr.route(); try { Object result = method.invoke(s.getTedis(), args); statLog(name, true, time); return result; } catch (Throwable t) { statLog(name, false, time); exception = t; logger.warn("read exception:" + s.getProperties(), t); boolean connectionError = false; try { if (t instanceof InvocationTargetException) {// InvocationTargetException ite = (InvocationTargetException) t; UndeclaredThrowableException ute = (UndeclaredThrowableException) ite .getTargetException(); if (ute.getUndeclaredThrowable() instanceof TimeoutException) { connectionError = true; rr.onError(s); } else { ExecutionException ee = (ExecutionException) ute.getUndeclaredThrowable(); InvocationTargetException ite_1 = (InvocationTargetException) ee.getCause(); TedisException te = (TedisException) ite_1.getTargetException(); if (te.getCause() instanceof TedisConnectionException) { connectionError = true; rr.onError(s); } } } } catch (Throwable tt) { logger.warn(":", tt); // ,,,connection error // } if (!connectionError) { throw t; } } } throw new Exception("read RouteData is empty," + rr, exception); } else if (annotation.value() == Policy.WRITE) { Single[] ss = rr.getAllRouteData().group; if (ss == null || ss.length == 0) { throw new Exception("write RouteData is empty," + rr, exception); } Object result = null; int e = 0; List<ReliableAsynMessage> messages = null; for (Single s : ss) { try { result = method.invoke(s.getTedis(), args); } catch (Throwable t) { e++; statLog(name, false, time); logger.warn("write exception:" + s.getProperties(), t); exception = t; try { // InvocationTargetException ite = (InvocationTargetException) t; UndeclaredThrowableException ute = (UndeclaredThrowableException) ite .getTargetException(); if (ute.getUndeclaredThrowable() instanceof TimeoutException) { messages = onError(args, name, rr, messages, s); } else { ExecutionException ee = (ExecutionException) ute.getUndeclaredThrowable(); InvocationTargetException ite_1 = (InvocationTargetException) ee.getCause(); TedisException te = (TedisException) ite_1.getTargetException(); if (te.getCause() instanceof TedisConnectionException) { messages = onError(args, name, rr, messages, s); } } } catch (Throwable tt) { logger.warn(":", tt); } } } if (e >= 2) {// , throw exception; } if (messages != null && messages.size() > 0) { for (ReliableAsynMessage m : messages) { ospreyManager.addMessage(m, true); } messages.clear(); } statLog(name, true, time); return result; } else if ("toString".equals(name)) { return ""; } else if ("hashCode".equals(name)) { Single s = rr.route(); if (s != null) { return s.hashCode(); } else { return 0; } } else if ("equals".equals(name)) { Single s = rr.route(); if (args.length == 1) { return s.equals(args[0]); } } statLog(name, false, time); throw new Exception("method don't match:" + name); } private List<ReliableAsynMessage> onError(Object[] args, String name, Router rr, List<ReliableAsynMessage> messages, Single s) { if (rr.getAtomic(s.getProperties().generateKey()) != null) { rr.onError(s); } if (messages == null) { messages = new ArrayList<ReliableAsynMessage>(); } String[] types = new String[args.length]; for (int n = 0; n < args.length; n++) { types[n] = args[n].getClass().getName(); } messages.add(new ReliableAsynMessage(s.getProperties().generateKey(), args, RedisCommands.class.getName(), name, types)); return messages; } } private void statLog(String methodName, Boolean flag, long time) { BufferedStatLogWriter.add(appName, methodName, flag, 1, System.currentTimeMillis() - time); } public void destroy() { Router rr = cm.getRouter(); rr.destroy(); // ConfigMananger.destroy(); } public String getAppName() { return appName; } public void setAppName(String appName) { this.appName = appName; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public ConfigManager getConfigManager() { return this.cm; } @Override public void setConfigManager(ConfigManager cm) { this.cm = cm; } }