/** @author haiqing.zhuhq 2011-6-15 */ public class CobarAccesser implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(CobarAccesser.class); private AdapterDelegate cobarAdapterDelegate; private XmlAccesser xmlAccesser; public AdapterDelegate getCobarAdapterDelegate() { return cobarAdapterDelegate; } public void setCobarAdapterDelegate(AdapterDelegate cobarAdapterDelegate) { this.cobarAdapterDelegate = cobarAdapterDelegate; } public XmlAccesser getXmlAccesser() { return xmlAccesser; } public void setXmlAccesser(XmlAccesser xmlAccesser) { this.xmlAccesser = xmlAccesser; } @Override public void afterPropertiesSet() throws Exception { if (cobarAdapterDelegate == null) { throw new IllegalArgumentException("property 'cobarAdapterDelegate' is null!"); } if (xmlAccesser == null) { throw new IllegalArgumentException("property 'xmlAccesser' is null!"); } } public CobarAdapterDAO getAccesser(long cobarId) { final CobarDO cobar = xmlAccesser.getCobarDAO().getCobarById(cobarId); if (cobar == null) { logger.error( new StringBuilder("Fail to get cobar information which id = ") .append(cobarId) .toString()); } CobarAdapterDAO accesser = cobarAdapterDelegate.getCobarNodeAccesser( cobar.getHost(), cobar.getPort(), cobar.getUser(), cobar.getPassword()); return accesser; } public CobarAdapterDAO getAccesser(CobarDO cobar) { CobarAdapterDAO accesser = cobarAdapterDelegate.getCobarNodeAccesser( cobar.getHost(), cobar.getPort(), cobar.getUser(), cobar.getPassword()); return accesser; } }
public class TestCobarAdapter { public static CobarAdapter cobarAdapter = null; public static SimpleCobarNode sCobarNode = null; private static final Logger logger = LoggerFactory.getLogger(TestCobarAdapter.class); @BeforeClass public static void init() { try { cobarAdapter = CobarFactory.getCobarAdapter("cobar"); sCobarNode = CobarFactory.getSimpleCobarNode("cobar"); } catch (Exception e) { logger.error(e.getMessage(), e); Assert.fail(); } } @Before public void initData() { if (null != cobarAdapter && null != cobarAdapter.getDataSource()) { try { cobarAdapter.destroy(); } catch (Exception e) { logger.error("destroy adpter error"); Assert.fail(); } } } @After public void end() { try { if (null != cobarAdapter && null != cobarAdapter.getDataSource()) { cobarAdapter.destroy(); } } catch (Exception e) { logger.error("destroy adpter error"); Assert.fail(); } } }
/** * 加载一个appname对应的资源,比如用户密码/tddl数据源等 * * @author jianghang 2014-5-28 下午5:09:41 * @since 5.1.0 */ public final class AppLoader extends AbstractLifecycle implements Lifecycle { private static final Logger logger = LoggerFactory.getLogger(AppLoader.class); private static final String DATAID_PREFIX = "com.taobao.corona."; private static final String DATAID_SUFFIX = ".passwd"; private static final String QUARANTINE_SURFIX = ".quarantine"; private ConfigDataHandlerFactory cdhf = ConfigDataHandlerCity.getFactory(null, null); private Cache<String, ConfigDataHandler> cdhs = CacheBuilder.newBuilder().build(); private String cluster; private Map<String /* app */, UserConfig> users; private Map<String, SchemaConfig> schemas; private QuarantineConfig quarantine; public AppLoader(String cluster) { this.cluster = cluster; } @Override protected void doInit() throws TddlException { this.users = new HashMap<String, UserConfig>(); this.schemas = new HashMap<String, SchemaConfig>(); this.quarantine = QuarantineConfig.getInstance(); } /** 装载app */ public void loadApp(final String app) { try { logger.info("start loading app:" + app); this.loadUser(app); this.loadSchema(app); this.loadQuarantine(app); logger.info("finish loading app:" + app); } catch (Throwable e) { throw new TddlNestableRuntimeException(e); } } /** * Do not add cluster to keep compatible with old tddl * * @param app * @throws ExecutionException * @throws TddlException */ private void loadQuarantine(String app) throws ExecutionException, TddlException { String dataId = DATAID_PREFIX + app + QUARANTINE_SURFIX; ConfigDataHandler cdh = getQuarantineDataHandler(app, dataId); String config = cdh.getData(); this.parseQuarantineConfig(dataId, app, config); } /** 卸载app */ public void unLoadApp(final String app) { try { logger.info("start unLoading app:" + app); this.unLoadUser(app); this.unLoadSchema(app); logger.info("finish unLoading app:" + app); } catch (Throwable e) { throw new TddlNestableRuntimeException(e); } } private synchronized void loadUser(final String app) throws ExecutionException, TddlException { String dataId = DATAID_PREFIX + this.cluster + "." + app + DATAID_SUFFIX; ConfigDataHandler cdh = getConfigDataHandler(app, dataId); String config = cdh.getData(); if (StringUtil.isEmpty(config)) { cdhs.invalidate(dataId); cdh.destroy(); // 重新拿一下新的dataId String newDataId = DATAID_PREFIX + app + DATAID_SUFFIX; cdh = getConfigDataHandler(app, newDataId); config = cdh.getData(); } this.parseConfig(dataId, app, config); } private synchronized void unLoadUser(final String app) throws TddlException { String dataId = DATAID_PREFIX + this.cluster + "." + app + DATAID_SUFFIX; ConfigDataHandler cdh = cdhs.getIfPresent(dataId); if (cdh != null) { cdh.destroy(); cdhs.invalidate(dataId); } String newDataId = DATAID_PREFIX + app + DATAID_SUFFIX; cdh = cdhs.getIfPresent(newDataId); if (cdh != null) { cdh.destroy(); cdhs.invalidate(dataId); } users.remove(app); } private synchronized void loadSchema(final String app) { SchemaConfig schema = schemas.get(app); if (schema != null) { return; } // MDC.put("app", app); TDataSource ds = new TDataSource(); ds.putConnectionProperties(ConnectionProperties.CHOOSE_STREAMING, true); ds.putConnectionProperties(ConnectionProperties.PROCESS_AUTO_INCREMENT_BY_SEQUENCE, true); ds.putConnectionProperties(ConnectionProperties.INIT_CONCURRENT_POOL_EVERY_CONNECTION, false); // 共享一个链接池 ds.setGlobalExecutorService(CobarServer.getInstance().getServerExectuor()); // ds.putConnectionProperties(ConnectionProperties.MERGE_CONCURRENT, // true); // ds.putConnectionProperties(ConnectionProperties.CONCURRENT_THREAD_SIZE, // CobarServer.getInstance() // .getConfig() // .getSystem() // .getServerExecutor()); ds.setSharding(false); // 允许非sharding启动 ds.setAppName(app); // try { // ds.init(); // } catch (TddlException e) { // // 启动时出错不往上抛 // logger.error(e); // } finally { // MDC.remove("app"); // } schema = new SchemaConfig(app); schema.setDataSource(ds); schemas.put(app, schema); } private synchronized void unLoadSchema(final String app) throws TddlException { SchemaConfig schema = schemas.remove(app); if (schema != null) { TDataSource dataSource = schema.getDataSource(); if (dataSource != null) { dataSource.destroy(); } } } private ConfigDataHandler getQuarantineDataHandler(final String app, final String dataId) throws ExecutionException { return cdhs.get( dataId, new Callable<ConfigDataHandler>() { @Override public ConfigDataHandler call() throws Exception { return cdhf.getConfigDataHandler( dataId, new ConfigDataListener() { @Override public void onDataRecieved(String dataId, String data) { parseQuarantineConfig(dataId, app, data); } }); } }); } private ConfigDataHandler getConfigDataHandler(final String app, final String dataId) throws ExecutionException { return cdhs.get( dataId, new Callable<ConfigDataHandler>() { @Override public ConfigDataHandler call() throws Exception { return cdhf.getConfigDataHandler( dataId, new ConfigDataListener() { @Override public void onDataRecieved(String dataId, String data) { parseConfig(dataId, app, data); } }); } }); } private synchronized void parseConfig(String dataId, String app, String config) { if (StringUtil.isEmpty(config)) { logger.info("password data is empty, so use default passwd, dataId:" + dataId); config = app; } UserConfig user = this.users.get(app); if (user == null) { user = new UserConfig(); this.users.put(app, user); } user.setName(app); user.setPassword(config); user.setSchemas(this.buildSchema(app)); } private void parseQuarantineConfig(String dataId, String app, String config) { /* Must clear existing whitelist first always */ cleanHostByApp(app); if (StringUtil.isEmpty(config)) { return; } parseQuarantine(app, dataId, config); } private synchronized void parseQuarantine(String app, String dataId, String config) { quarantine.resetHosts(app, config); } private void cleanHostByApp(String app) { quarantine.cleanHostByApp(app); } private Set<String> buildSchema(String app) { Set<String> result = new HashSet<String>(); result.add(app); return result; } public Map<String, SchemaConfig> getSchemas() { return schemas; } public Map<String, UserConfig> getUsers() { return users; } @Override protected void doDestroy() throws TddlException { for (ConfigDataHandler cdh : cdhs.asMap().values()) { try { cdh.destroy(); } catch (Exception e) { // ignore } } for (SchemaConfig schema : schemas.values()) { TDataSource dataSource = schema.getDataSource(); try { if (dataSource != null) { dataSource.destroy(); } } catch (Exception e) { // ignore } } } public QuarantineConfig getQuarantine() { return quarantine; } }
/** * 一组{@linkplain TableRule}的集合 * * @author junyu * @author <a href="*****@*****.**">jianghang</a> */ public class VirtualTableRoot extends AbstractLifecycle implements Lifecycle, ApplicationContextAware { private static final Logger logger = LoggerFactory.getLogger(VirtualTableRoot.class); protected String dbType = "MYSQL"; protected Map<String /* 大写key */, TableRule> virtualTableMap; protected Map<String /* 大写key */, String> dbIndexMap; protected String defaultDbIndex; protected boolean needIdInGroup = false; protected boolean completeDistinct = false; protected boolean lazyInit = false; protected ApplicationContext context; public void init() throws TddlException { if (virtualTableMap == null || virtualTableMap.isEmpty()) { // 如果为空,采用自动查找的方式,将bean name做为逻辑表名 Map<String, TableRule> vts = new HashMap<String, TableRule>(); String[] tbeanNames = context.getBeanNamesForType(TableRule.class); for (String name : tbeanNames) { Object obj = context.getBean(name); vts.put(name, (TableRule) obj); } setTableRules(vts); } for (Map.Entry<String, TableRule> entry : virtualTableMap.entrySet()) { if (!lazyInit) { initTableRule(entry.getKey(), entry.getValue()); } } } /** * 此处有个问题是Map中key对应的VirtualTableRule为null; * * @param virtualTableName * @return */ public TableRule getVirtualTable(String virtualTableName) { RuleUtils.notNull(virtualTableName, "virtual table name is null"); TableRule tablRule = virtualTableMap.get(virtualTableName.toUpperCase()); if (tablRule != null && lazyInit && !tablRule.isInited()) { try { initTableRule(virtualTableName, tablRule); } catch (TddlException e) { throw new TddlRuleException(e); } } return tablRule; } public void setTableRules(Map<String, TableRule> virtualTableMap) { Map<String, TableRule> logicTableMap = new HashMap<String, TableRule>(virtualTableMap.size()); for (Entry<String, TableRule> entry : virtualTableMap.entrySet()) { logicTableMap.put(entry.getKey().toUpperCase(), entry.getValue()); // 转化大写 } this.virtualTableMap = logicTableMap; } public void setDbIndexMap(Map<String, String> dbIndexMap) { Map<String, String> logicTableMap = new HashMap<String, String>(dbIndexMap.size()); for (Entry<String, String> entry : dbIndexMap.entrySet()) { logicTableMap.put(entry.getKey().toUpperCase(), entry.getValue()); // 转化大写 } this.dbIndexMap = logicTableMap; } private void initTableRule(String tableNameKey, TableRule tableRule) throws TddlException { tableNameKey = tableNameKey.toUpperCase(); logger.warn("virtual table start to init :" + tableNameKey); if (tableRule.getDbType() == null) { // 如果虚拟表中dbType为null,那指定全局dbType tableRule.setDbType(this.getDbTypeEnumObj()); } if (tableRule.getVirtualTbName() == null) { tableRule.setVirtualTbName(tableNameKey); } tableRule.init(); logger.warn("virtual table inited :" + tableNameKey); } public String getDefaultDbIndex() { return defaultDbIndex; } public void setDefaultDbIndex(String defaultDbIndex) { this.defaultDbIndex = defaultDbIndex; } public Map<String, String> getDbIndexMap() { return dbIndexMap; } public DBType getDbTypeEnumObj() { return DBType.valueOf(this.dbType); } public String getDbType() { return this.dbType; } public void setDbType(String dbType) { this.dbType = dbType; } public boolean isNeedIdInGroup() { return needIdInGroup; } public void setNeedIdInGroup(boolean needIdInGroup) { this.needIdInGroup = needIdInGroup; } public boolean isCompleteDistinct() { return completeDistinct; } public void setCompleteDistinct(boolean completeDistinct) { this.completeDistinct = completeDistinct; } public void setLazyInit(boolean lazyInit) { this.lazyInit = lazyInit; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context = applicationContext; } }
/** * 序列DAO默认实现,JDBC方式 * * @author nianbing */ public class DefaultSequenceDao extends AbstractLifecycle implements SequenceDao { private static final Logger logger = LoggerFactory.getLogger(DefaultSequenceDao.class); private static final int MIN_STEP = 1; private static final int MAX_STEP = 100000; private static final int DEFAULT_STEP = 1000; private static final int DEFAULT_RETRY_TIMES = 150; private static final String DEFAULT_TABLE_NAME = "sequence"; private static final String DEFAULT_NAME_COLUMN_NAME = "name"; private static final String DEFAULT_VALUE_COLUMN_NAME = "value"; private static final String DEFAULT_GMT_MODIFIED_COLUMN_NAME = "gmt_modified"; private static final long DELTA = 100000000L; private DataSource dataSource; /** 重试次数 */ private int retryTimes = DEFAULT_RETRY_TIMES; /** 步长 */ private int step = DEFAULT_STEP; /** 序列所在的表名 */ private String tableName = DEFAULT_TABLE_NAME; /** 存储序列名称的列名 */ private String nameColumnName = DEFAULT_NAME_COLUMN_NAME; /** 存储序列值的列名 */ private String valueColumnName = DEFAULT_VALUE_COLUMN_NAME; /** 存储序列最后更新时间的列名 */ private String gmtModifiedColumnName = DEFAULT_GMT_MODIFIED_COLUMN_NAME; private volatile String selectSql; private volatile String updateSql; public SequenceRange nextRange(String name) throws SequenceException { if (name == null) { throw new IllegalArgumentException("序列名称不能为空"); } long oldValue; long newValue; Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; for (int i = 0; i < retryTimes + 1; ++i) { try { conn = dataSource.getConnection(); stmt = conn.prepareStatement(getSelectSql()); stmt.setString(1, name); rs = stmt.executeQuery(); rs.next(); oldValue = rs.getLong(1); if (oldValue < 0) { StringBuilder message = new StringBuilder(); message.append("Sequence value cannot be less than zero, value = ").append(oldValue); message.append(", please check table ").append(getTableName()); throw new SequenceException(message.toString()); } if (oldValue > Long.MAX_VALUE - DELTA) { StringBuilder message = new StringBuilder(); message.append("Sequence value overflow, value = ").append(oldValue); message.append(", please check table ").append(getTableName()); throw new SequenceException(message.toString()); } newValue = oldValue + getStep(); } catch (SQLException e) { throw new SequenceException(e); } finally { closeResultSet(rs); rs = null; closeStatement(stmt); stmt = null; closeConnection(conn); conn = null; } try { conn = dataSource.getConnection(); stmt = conn.prepareStatement(getUpdateSql()); stmt.setLong(1, newValue); stmt.setTimestamp(2, new Timestamp(System.currentTimeMillis())); stmt.setString(3, name); stmt.setLong(4, oldValue); int affectedRows = stmt.executeUpdate(); if (affectedRows == 0) { // retry continue; } return new SequenceRange(oldValue + 1, newValue); } catch (SQLException e) { throw new SequenceException(e); } finally { closeStatement(stmt); stmt = null; closeConnection(conn); conn = null; } } throw new SequenceException("Retried too many times, retryTimes = " + retryTimes); } private String getSelectSql() { if (selectSql == null) { synchronized (this) { if (selectSql == null) { StringBuilder buffer = new StringBuilder(); buffer.append("select ").append(getValueColumnName()); buffer.append(" from ").append(getTableName()); buffer.append(" where ").append(getNameColumnName()).append(" = ?"); selectSql = buffer.toString(); } } } return selectSql; } private String getUpdateSql() { if (updateSql == null) { synchronized (this) { if (updateSql == null) { StringBuilder buffer = new StringBuilder(); buffer.append("update ").append(getTableName()); buffer.append(" set ").append(getValueColumnName()).append(" = ?, "); buffer.append(getGmtModifiedColumnName()).append(" = ? where "); buffer.append(getNameColumnName()).append(" = ? and "); buffer.append(getValueColumnName()).append(" = ?"); updateSql = buffer.toString(); } } } return updateSql; } private static void closeResultSet(ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException e) { logger.debug("Could not close JDBC ResultSet", e); } catch (Throwable e) { logger.debug("Unexpected exception on closing JDBC ResultSet", e); } } } private static void closeStatement(Statement stmt) { if (stmt != null) { try { stmt.close(); } catch (SQLException e) { logger.debug("Could not close JDBC Statement", e); } catch (Throwable e) { logger.debug("Unexpected exception on closing JDBC Statement", e); } } } private static void closeConnection(Connection conn) { if (conn != null) { try { conn.close(); } catch (SQLException e) { logger.debug("Could not close JDBC Connection", e); } catch (Throwable e) { logger.debug("Unexpected exception on closing JDBC Connection", e); } } } public DataSource getDataSource() { return dataSource; } public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public int getRetryTimes() { return retryTimes; } public void setRetryTimes(int retryTimes) { if (retryTimes < 0) { throw new IllegalArgumentException( "Property retryTimes cannot be less than zero, retryTimes = " + retryTimes); } this.retryTimes = retryTimes; } public int getStep() { return step; } public void setStep(int step) { if (step < MIN_STEP || step > MAX_STEP) { StringBuilder message = new StringBuilder(); message.append("Property step out of range [").append(MIN_STEP); message.append(",").append(MAX_STEP).append("], step = ").append(step); throw new IllegalArgumentException(message.toString()); } this.step = step; } public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } public String getNameColumnName() { return nameColumnName; } public void setNameColumnName(String nameColumnName) { this.nameColumnName = nameColumnName; } public String getValueColumnName() { return valueColumnName; } public void setValueColumnName(String valueColumnName) { this.valueColumnName = valueColumnName; } public String getGmtModifiedColumnName() { return gmtModifiedColumnName; } public void setGmtModifiedColumnName(String gmtModifiedColumnName) { this.gmtModifiedColumnName = gmtModifiedColumnName; } }
/** @author haiqing.zhuhq 2012-2-21 */ public class EncryptUtil { private static final Logger logger = LoggerFactory.getLogger(EncryptUtil.class); /** 密钥,长度必须大于8 */ private static final String PASSWORD_CRYPT_KEY = "cobar-manager"; private static final String DES = "DES"; /** * 加密 * * @param src 数据源 * @param key 密钥,长度必须大于8 * @return 返回加密后的数据 * @throws Exception */ public static byte[] encrypt(byte[] src, byte[] key) throws Exception { // DES算法要求有一个可信任的随机数源 SecureRandom sr = new SecureRandom(); // 从原始密匙数据创建DESKeySpec对象 DESKeySpec dks = new DESKeySpec(key); // 创建一个密匙工厂,然后用它把DESKeySpec转换成 // 一个SecretKey对象 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); SecretKey securekey = keyFactory.generateSecret(dks); // Cipher对象实际完成加密操作 Cipher cipher = Cipher.getInstance(DES); // 用密匙初始化Cipher对象 cipher.init(Cipher.ENCRYPT_MODE, securekey, sr); // 现在,获取数据并加密 // 正式执行加密操作 return cipher.doFinal(src); } /** * 解密 * * @param src 数据源 * @param key 密钥,长度必须是8的倍数 * @return 返回解密后的原始数据 * @throws Exception */ public static byte[] decrypt(byte[] src, byte[] key) throws Exception { // DES算法要求有一个可信任的随机数源 SecureRandom sr = new SecureRandom(); // 从原始密匙数据创建一个DESKeySpec对象 DESKeySpec dks = new DESKeySpec(key); // 创建一个密匙工厂,然后用它把DESKeySpec对象转换成 // 一个SecretKey对象 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); SecretKey securekey = keyFactory.generateSecret(dks); // Cipher对象实际完成解密操作 Cipher cipher = Cipher.getInstance(DES); // 用密匙初始化Cipher对象 cipher.init(Cipher.DECRYPT_MODE, securekey, sr); // 现在,获取数据并解密 // 正式执行解密操作 return cipher.doFinal(src); } /** * 密码解密 * * @param data * @return * @throws Exception */ public static final String decrypt(String data) { try { return new String(decrypt(hex2byte(data.getBytes()), PASSWORD_CRYPT_KEY.getBytes())); } catch (Exception e) { logger.error("decrypt error!!"); logger.error(e.getMessage(), e); } return null; } /** * 密码加密 * * @param password * @return * @throws Exception */ public static final String encrypt(String password) { try { return byte2hex(encrypt(password.getBytes(), PASSWORD_CRYPT_KEY.getBytes())); } catch (Exception e) { logger.error("encrypt error!!"); logger.error(e.getMessage(), e); } return null; } /** * 二行制转字符串 * * @param b * @return */ public static String byte2hex(byte[] b) { String hs = ""; String stmp = ""; for (int n = 0; n < b.length; n++) { stmp = (java.lang.Integer.toHexString(b[n] & 0XFF)); if (stmp.length() == 1) hs = hs + "0" + stmp; else hs = hs + stmp; } return hs.toUpperCase(); } public static byte[] hex2byte(byte[] b) { if ((b.length % 2) != 0) throw new IllegalArgumentException("长度不是偶数"); byte[] b2 = new byte[b.length / 2]; for (int n = 0; n < b.length; n += 2) { String item = new String(b, n, 2); b2[n / 2] = (byte) Integer.parseInt(item, 16); } return b2; } }