├── .gitignore ├── LICENSE.txt ├── README.md ├── clover.license ├── create_table.sql ├── diamond-client ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── taobao │ │ └── diamond │ │ ├── client │ │ ├── DiamondClientSub.java │ │ ├── DiamondConfigure.java │ │ ├── DiamondSubscriber.java │ │ ├── SubscriberListener.java │ │ ├── impl │ │ │ ├── DefaultDiamondSubscriber.java │ │ │ ├── DefaultSubscriberListener.java │ │ │ └── DiamondClientFactory.java │ │ └── processor │ │ │ ├── LocalConfigInfoProcessor.java │ │ │ ├── ServerAddressProcessor.java │ │ │ └── SnapshotConfigInfoProcessor.java │ │ ├── configinfo │ │ ├── CacheData.java │ │ └── ConfigureInfomation.java │ │ ├── manager │ │ ├── DiamondManager.java │ │ ├── ManagerListener.java │ │ ├── ManagerListenerAdapter.java │ │ └── impl │ │ │ ├── DefaultDiamondManager.java │ │ │ └── PropertiesListener.java │ │ └── mockserver │ │ └── MockServer.java │ └── test │ ├── java │ └── ClientTest.java │ └── resources │ └── diamond.properties ├── diamond-sdk ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── taobao │ └── diamond │ ├── domain │ ├── BatchContextResult.java │ ├── ContextResult.java │ ├── DiamondConf.java │ ├── DiamondSDKConf.java │ └── PageContextResult.java │ ├── sdkapi │ ├── DiamondSDKManager.java │ └── impl │ │ └── DiamondSDKManagerImpl.java │ └── util │ ├── DiamondUtils.java │ ├── PatternUtils.java │ ├── RandomDiamondUtils.java │ └── ResourceUtils.java ├── diamond-server ├── pom.xml ├── release.xml └── src │ └── main │ ├── java │ └── com │ │ └── taobao │ │ └── diamond │ │ └── server │ │ ├── controller │ │ ├── AdminController.java │ │ ├── ConfigController.java │ │ ├── ConfigServlet.java │ │ ├── LoginController.java │ │ ├── NotifyController.java │ │ └── ServerAddressController.java │ │ ├── exception │ │ └── ConfigServiceException.java │ │ ├── listener │ │ └── AuthorizationFilter.java │ │ ├── service │ │ ├── AdminService.java │ │ ├── ConfigService.java │ │ ├── DiskService.java │ │ ├── DumpConfigInfoTask.java │ │ ├── NotifyService.java │ │ ├── PersistService.java │ │ └── TimerTaskService.java │ │ └── utils │ │ ├── DiamondUtils.java │ │ ├── GlobalCounter.java │ │ ├── PaginationHelper.java │ │ ├── SessionHolder.java │ │ └── SystemConfig.java │ ├── resources │ ├── jdbc.properties │ ├── log4j.properties │ ├── node.properties │ ├── system.properties │ └── user.properties │ └── webapp │ ├── META-INF │ └── MANIFEST.MF │ ├── WEB-INF │ ├── applicationContext.xml │ ├── diamond-servlet.xml │ └── web.xml │ ├── js │ ├── effects.js │ ├── fabtabulous.js │ ├── jquery-1.2.6.min.js │ ├── prototype.js │ ├── prototype_for_validation.js │ ├── tooltips.js │ ├── unittest.js │ └── validation_cn.js │ └── jsp │ ├── 200.jsp │ ├── 400.jsp │ ├── 500.jsp │ ├── 503.jsp │ ├── admin │ ├── admin.jsp │ ├── config │ │ ├── batch_result.jsp │ │ ├── edit.jsp │ │ ├── list.jsp │ │ ├── list_json.jsp │ │ ├── new.jsp │ │ └── upload.jsp │ ├── count.jsp │ ├── menu.jsp │ ├── user │ │ ├── list.jsp │ │ └── new.jsp │ └── welcome.jsp │ ├── common │ └── message.jsp │ └── login.jsp ├── diamond-utils ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── taobao │ └── diamond │ ├── common │ └── Constants.java │ ├── domain │ ├── ConfigInfo.java │ ├── ConfigInfoEx.java │ └── Page.java │ ├── io │ ├── FileSystem.java │ ├── Path.java │ └── watch │ │ ├── StandardWatchEventKind.java │ │ ├── WatchEvent.java │ │ ├── WatchKey.java │ │ ├── WatchService.java │ │ ├── Watchable.java │ │ └── util │ │ └── PathNode.java │ ├── md5 │ └── MD5.java │ └── utils │ ├── FileUtils.java │ ├── JSONUtils.java │ ├── LoggerInit.java │ ├── ResourceUtils.java │ ├── SimpleCache.java │ └── TimeUtils.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .svn 3 | .idea 4 | *.iml 5 | target/ 6 | *.log -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Diamond -- 分布式配置中心 2 | ======================== 3 | 4 | # 一、简介 5 | * Diamond是淘宝研发的分布式配置管理系统。使用Diamond可以让集群中的服务进程动态感知数据的变化,无需重启服务就可以实现配置数据的更新。 6 | * 具有简单、可靠、易用等特点 7 | 8 | # 二、使用方法 9 | ## 服务端搭建 10 | ## 1 准备工作 11 | * 安装jdk 12 | * 安装maven 13 | * 安装tomcat 14 | * 安装mysql 15 | ## 2 启动mysql并创建数据库和表 16 | 17 | ``` 18 | -- 创建Diamond数据库 19 | CREATE DATABASE IF NOT EXISTS `diamond` /*!40100 DEFAULT CHARACTER SET utf8 */; 20 | USE `diamond`; 21 | 22 | 23 | -- 配置表 24 | CREATE TABLE IF NOT EXISTS `config_info` ( 25 | `id` bigint(64) unsigned NOT NULL AUTO_INCREMENT, 26 | `data_id` varchar(255) NOT NULL DEFAULT '', 27 | `group_id` varchar(128) NOT NULL DEFAULT '', 28 | `content` longtext NOT NULL, 29 | `md5` varchar(32) NOT NULL DEFAULT '', 30 | `src_ip` varchar(20) DEFAULT NULL, 31 | `src_user` varchar(20) DEFAULT NULL, 32 | `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00', 33 | `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00', 34 | PRIMARY KEY (`id`), 35 | UNIQUE KEY `uk_config_datagroup` (`data_id`) 36 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 37 | 38 | -- 数据导出被取消选择。 39 | 40 | 41 | -- 组表 42 | CREATE TABLE IF NOT EXISTS `group_info` ( 43 | `id` bigint(64) unsigned NOT NULL AUTO_INCREMENT, 44 | `address` varchar(70) NOT NULL DEFAULT '', 45 | `data_id` varchar(255) NOT NULL DEFAULT '', 46 | `group_id` varchar(128) NOT NULL DEFAULT '', 47 | `src_ip` varchar(20) DEFAULT NULL, 48 | `src_user` varchar(20) DEFAULT NULL, 49 | `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00', 50 | `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00', 51 | PRIMARY KEY (`id`), 52 | UNIQUE KEY `uk_group_address` (`address`,`data_id`) 53 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 54 | ``` 55 | ## 3 下载源码 56 | ``` 57 | git clone https://github.com/gzllol/diamond.git 58 | ``` 59 | ## 4 打包 60 | 1. 修改diamond-server/src/main/resources/system.properties文件,将diamond.server.addr的值换成Diamond服务器所在机器的ip地址 61 | 2. 修改diamond-server/src/main/resources/jdbc.properties文件,配置mysql服务器的url,用户名和密码 62 | 2. 在根目录执行打包命令 63 | 64 | ``` 65 | mvn clean package -Dmaven.test.skip=true 66 | ``` 67 | 68 | ## 5 用tomcat加载diamond-server/target/diamond-server.war 69 | 70 | ## 客户端使用 71 | ## 1 将diamond-client jar包发布到maven仓库 72 | ``` 73 | mvn clean deploy -Dmaven.test.skip=true 74 | ``` 75 | ## 2 在工程中引入jar包 76 | 77 | ``` 78 | 79 | com.taobao.diamond 80 | diamond-client 81 | 2.0.5.4.taocode-SNAPSHOT 82 | 83 | ``` 84 | ## 3 使用例子 85 | 86 | ``` 87 | DiamondManager manager = new DefaultDiamondManager("${your_config_data_id}", new ManagerListener() { 88 | @Override 89 | public Executor getExecutor() { 90 | return null; 91 | } 92 | 93 | @Override 94 | public void receiveConfigInfo(String configInfo) { 95 | System.out.println("receive config: " + configInfo); 96 | } 97 | }); 98 | ``` 99 | 100 | ## 4 在配置中心界面添加一个配置 101 | 1. 登陆配置中心(本机是127.0.0.1:8080),用户名abc,密码123 102 | 2. 点击左侧“配置信息管理” 103 | 3. 点击添加配置信息 104 | 4. 输入data_id(就是配置的id,3中的${your_config_data_id})和配置内容 105 | 5. 点击“提交” 106 | 6. 在更新配置时,客户端会调用ManagerListener的回调函数receiveConfigInfo,参数就是最新的配置内容 107 | -------------------------------------------------------------------------------- /clover.license: -------------------------------------------------------------------------------- 1 | ooOPSrijRSMpkBwoEAQSTuiIrMxGWnLOtfdENlSCmVniQk 2 | mi2KTt8nwsN0xZ0yQ>773SoN2KN>MUkQEpTg>kY2ykbpJ> 3 | QOppsSpRNrMoNpqMQROSxqqQRMRPRmNOrrUVWSVStvmXXU 4 | wURnmpmUUnoumopvommmmmUUnoumopvommmmmUUvvplcqk 5 | ZljUUn 6 | -------------------------------------------------------------------------------- /create_table.sql: -------------------------------------------------------------------------------- 1 | -- 导出 diamond 的数据库结构 2 | CREATE DATABASE IF NOT EXISTS `diamond` /*!40100 DEFAULT CHARACTER SET utf8 */; 3 | USE `diamond`; 4 | 5 | 6 | -- 导出 表 diamond.config_info 结构 7 | CREATE TABLE IF NOT EXISTS `config_info` ( 8 | `id` bigint(64) unsigned NOT NULL AUTO_INCREMENT, 9 | `data_id` varchar(255) NOT NULL DEFAULT '', 10 | `group_id` varchar(128) NOT NULL DEFAULT '', 11 | `content` longtext NOT NULL, 12 | `md5` varchar(32) NOT NULL DEFAULT '', 13 | `src_ip` varchar(20) DEFAULT NULL, 14 | `src_user` varchar(20) DEFAULT NULL, 15 | `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00', 16 | `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00', 17 | PRIMARY KEY (`id`), 18 | UNIQUE KEY `uk_config_datagroup` (`data_id`) 19 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 20 | 21 | -- 数据导出被取消选择。 22 | 23 | 24 | -- 导出 表 diamond.group_info 结构 25 | CREATE TABLE IF NOT EXISTS `group_info` ( 26 | `id` bigint(64) unsigned NOT NULL AUTO_INCREMENT, 27 | `address` varchar(70) NOT NULL DEFAULT '', 28 | `data_id` varchar(255) NOT NULL DEFAULT '', 29 | `group_id` varchar(128) NOT NULL DEFAULT '', 30 | `src_ip` varchar(20) DEFAULT NULL, 31 | `src_user` varchar(20) DEFAULT NULL, 32 | `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00', 33 | `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00', 34 | PRIMARY KEY (`id`), 35 | UNIQUE KEY `uk_group_address` (`address`,`data_id`) 36 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -------------------------------------------------------------------------------- /diamond-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | diamond-all 5 | com.taobao.diamond 6 | 2.0.5.4.taocode-SNAPSHOT 7 | 8 | 9 | 4.0.0 10 | diamond-client 11 | diamond-client v${project.version} 12 | 13 | 14 | 15 | com.taobao.diamond 16 | diamond-utils 17 | 18 | 19 | commons-logging 20 | commons-logging 21 | 22 | 23 | commons-httpclient 24 | commons-httpclient 25 | 26 | 27 | commons-io 28 | commons-io 29 | 30 | 31 | commons-lang 32 | commons-lang 33 | 34 | 35 | junit 36 | junit 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/client/DiamondClientSub.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.client; 11 | 12 | /** 13 | * Diamond是一个支持持久的可靠的文本配置信息管理中心,用于文本配置信息的订阅。
14 | * Diamond目前是使用ops发布持久配置信息。
15 | * Diamond由于使用集中的数据库保存持久的配置信息,配置信息十分安全,并且,Diamond能够使客户永远获取最新的订阅信息。
16 | * 目前Diamond客户端拥有如下几种方式:
17 | * 1.主动获取
18 | * 2.定时获取
19 | * Diamond客户端还支持相对远程配置信息而言,优先级更高的本地配置配置信息的获取(使用Properties或者xml) 20 | * 21 | * @author aoqiong 22 | * 23 | */ 24 | public interface DiamondClientSub { 25 | 26 | public void setDiamondConfigure(DiamondConfigure diamondConfigure); 27 | 28 | 29 | public DiamondConfigure getDiamondConfigure(); 30 | 31 | 32 | public void start(); 33 | 34 | 35 | public void close(); 36 | } 37 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/client/DiamondSubscriber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.client; 11 | 12 | import java.util.Set; 13 | import java.util.concurrent.ConcurrentHashMap; 14 | 15 | import com.taobao.diamond.configinfo.CacheData; 16 | 17 | 18 | /** 19 | * DiamondSubscriber用于订阅持久的文本配置信息。
20 | * 21 | * @author aoqiong 22 | * 23 | */ 24 | public interface DiamondSubscriber extends DiamondClientSub { 25 | /** 26 | * 设置异步订阅的Listener,可以动态替换 27 | * 28 | * @param subscriberListener 29 | */ 30 | public void setSubscriberListener(SubscriberListener subscriberListener); 31 | 32 | 33 | /** 34 | * 获取异步订阅的Listener 35 | * 36 | * @return 37 | */ 38 | public SubscriberListener getSubscriberListener(); 39 | 40 | 41 | /** 42 | * 获取group组DataID为dataId的ConfigureInfomation,必须在start()方法后调用,,此方法优先从${user. 43 | * home}/diamond/data下获取配置文件,如果没有,则从diamond server获取配置信息 44 | * 45 | * @param dataId 46 | * @param group 47 | * @param timeout 48 | * @return 49 | */ 50 | public String getConfigureInfomation(String dataId, String group, long timeout); 51 | 52 | 53 | /** 54 | * 获取缺省组的DataID为dataId的ConfigureInfomation,必须在start()方法后调用,此方法优先从${user.home 55 | * }/diamond/data下获取配置文件,如果没有,则从diamond server获取配置信息 56 | * 57 | * @param dataId 58 | * @param timeout 59 | * @return 60 | */ 61 | public String getConfigureInfomation(String dataId, long timeout); 62 | 63 | 64 | /** 65 | * 获取一份可用的配置信息,按照本地文件->diamond服务器->本地上一次保存的snapshot 66 | * 的优先顺序获取一份有效的配置信息,如果所有途径都无法获取一份有效配置信息 , 则返回null 67 | * 68 | * @param dataId 69 | * @param group 70 | * @param timeout 71 | * @return 72 | */ 73 | public String getAvailableConfigureInfomation(String dataId, String group, long timeout); 74 | 75 | 76 | /** 77 | * 添加一个DataID,如果原来有此DataID和Group,将替换它们 78 | * 79 | * @param dataId 80 | * @param group 81 | * 组名,可为null,代表使用缺省的组名 82 | */ 83 | public void addDataId(String dataId, String group); 84 | 85 | 86 | /** 87 | * 添加一个DataID,使用缺省的组名。如果原来有此DataID和Group,将替换它们 88 | * 89 | * @param dataId 90 | */ 91 | public void addDataId(String dataId); 92 | 93 | 94 | /** 95 | * 目前是否支持对DataID对应的ConfigInfo 96 | * 97 | * @param dataId 98 | * @return 99 | */ 100 | public boolean containDataId(String dataId); 101 | 102 | 103 | /** 104 | * 105 | * @param dataId 106 | * @param group 107 | * @return 108 | */ 109 | public boolean containDataId(String dataId, String group); 110 | 111 | 112 | /** 113 | * 114 | * @param dataId 115 | */ 116 | public void removeDataId(String dataId); 117 | 118 | 119 | /** 120 | * 121 | * @param dataId 122 | * @param group 123 | */ 124 | public void removeDataId(String dataId, String group); 125 | 126 | 127 | /** 128 | * 清空所有的DataID 129 | */ 130 | public void clearAllDataIds(); 131 | 132 | 133 | /** 134 | * 获取支持的所有的DataID 135 | * 136 | * @return 137 | */ 138 | public Set getDataIds(); 139 | 140 | 141 | /** 142 | * 获取客户端cache 143 | * 144 | * @return 145 | */ 146 | public ConcurrentHashMap> getCache(); 147 | 148 | 149 | /** 150 | * 获取一份可用的配置信息,按照本地snapshot -> 本地文件 -> server的顺序 151 | * 152 | * @param dataId 153 | * @param group 154 | * @param timeout 155 | * @return 156 | */ 157 | public String getAvailableConfigureInfomationFromSnapshot(String dataId, String group, long timeout); 158 | 159 | } 160 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/client/SubscriberListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.client; 11 | 12 | import java.util.concurrent.Executor; 13 | 14 | import com.taobao.diamond.configinfo.ConfigureInfomation; 15 | 16 | 17 | /** 18 | * Diamond订阅者的配置信息监听器 19 | * 20 | * @author aoqiong 21 | * 22 | */ 23 | public interface SubscriberListener { 24 | 25 | public Executor getExecutor(); 26 | 27 | 28 | /** 29 | * 接收到一次配置信息 30 | * 31 | * @param configureInfomation 32 | */ 33 | public void receiveConfigInfo(final ConfigureInfomation configureInfomation); 34 | } 35 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/client/impl/DefaultSubscriberListener.java: -------------------------------------------------------------------------------- 1 | package com.taobao.diamond.client.impl; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.ConcurrentHashMap; 6 | import java.util.concurrent.ConcurrentMap; 7 | import java.util.concurrent.CopyOnWriteArrayList; 8 | import java.util.concurrent.Executor; 9 | 10 | import org.apache.commons.lang.StringUtils; 11 | import org.apache.commons.logging.Log; 12 | import org.apache.commons.logging.LogFactory; 13 | 14 | import com.taobao.diamond.client.SubscriberListener; 15 | import com.taobao.diamond.common.Constants; 16 | import com.taobao.diamond.configinfo.ConfigureInfomation; 17 | import com.taobao.diamond.manager.ManagerListener; 18 | import com.taobao.diamond.utils.LoggerInit; 19 | 20 | 21 | /** 22 | * 业务监听器的聚集。 23 | * 24 | * @author leiwen.zh 25 | * 26 | */ 27 | public class DefaultSubscriberListener implements SubscriberListener { 28 | 29 | // 回调日志单独记录 30 | private static final Log dataLog = LogFactory.getLog(LoggerInit.LOG_NAME_CONFIG_DATA); 31 | 32 | private final ConcurrentMap/* listeners */> allListeners = 33 | new ConcurrentHashMap>(); 34 | 35 | 36 | public Executor getExecutor() { 37 | return null; 38 | } 39 | 40 | 41 | public void receiveConfigInfo(final ConfigureInfomation configureInfomation) { 42 | String dataId = configureInfomation.getDataId(); 43 | String group = configureInfomation.getGroup(); 44 | if (null == dataId) { 45 | dataLog.error("[receiveConfigInfo] dataId is null"); 46 | return; 47 | } 48 | 49 | String key = makeKey(dataId, group); 50 | CopyOnWriteArrayList listeners = allListeners.get(key); 51 | if (listeners == null || listeners.isEmpty()) { 52 | dataLog.warn("[notify-listener] no listener for dataId=" + dataId + ", group=" + group); 53 | return; 54 | } 55 | 56 | for (ManagerListener listener : listeners) { 57 | try { 58 | notifyListener(configureInfomation, listener); 59 | } 60 | catch (Throwable t) { 61 | dataLog.error("call listener error, dataId=" + dataId + ", group=" + group, t); 62 | } 63 | } 64 | } 65 | 66 | 67 | private void notifyListener(final ConfigureInfomation configureInfomation, final ManagerListener listener) { 68 | if (listener == null) { 69 | return; 70 | } 71 | 72 | final String dataId = configureInfomation.getDataId(); 73 | final String group = configureInfomation.getGroup(); 74 | final String content = configureInfomation.getConfigureInfomation(); 75 | 76 | dataLog.info("[notify-listener] call listener " + listener.getClass().getName() + ", for " + dataId + ", " 77 | + group + ", " + content); 78 | 79 | Runnable job = new Runnable() { 80 | public void run() { 81 | try { 82 | listener.receiveConfigInfo(content); 83 | } 84 | catch (Throwable t) { 85 | dataLog.error(t.getMessage(), t); 86 | } 87 | } 88 | }; 89 | 90 | if (null != listener.getExecutor()) { 91 | listener.getExecutor().execute(job); 92 | } 93 | else { 94 | job.run(); 95 | } 96 | } 97 | 98 | 99 | /** 100 | * 添加一个DataID对应的ManagerListener 101 | */ 102 | public void addManagerListener(String dataId, String group, ManagerListener listener) { 103 | List list = new ArrayList(); 104 | list.add(listener); 105 | addManagerListeners(dataId, group, list); 106 | } 107 | 108 | 109 | public List getManagerListenerList(String dataId, String group) { 110 | if (null == dataId) { 111 | return null; 112 | } 113 | 114 | String key = makeKey(dataId, group); 115 | return new ArrayList(allListeners.get(key)); 116 | } 117 | 118 | 119 | /** 120 | * 删除一个DataID对应的所有的ManagerListeners 121 | * 122 | * @param dataId 123 | */ 124 | public void removeManagerListeners(String dataId, String group) { 125 | if (null == dataId) { 126 | return; 127 | } 128 | 129 | String key = makeKey(dataId, group); 130 | allListeners.remove(key); 131 | } 132 | 133 | 134 | /** 135 | * 添加一个DataID对应的一些ManagerListener 136 | * 137 | * @param dataId 138 | * @param addListeners 139 | */ 140 | public void addManagerListeners(String dataId, String group, List addListeners) { 141 | if (null == dataId || null == addListeners) { 142 | return; 143 | } 144 | if (addListeners.size() == 0) { 145 | return; 146 | } 147 | 148 | String key = makeKey(dataId, group); 149 | CopyOnWriteArrayList listenerList = allListeners.get(key); 150 | if (listenerList == null) { 151 | listenerList = new CopyOnWriteArrayList(); 152 | CopyOnWriteArrayList oldList = allListeners.putIfAbsent(key, listenerList); 153 | if (oldList != null) { 154 | listenerList = oldList; 155 | } 156 | } 157 | listenerList.addAll(addListeners); 158 | } 159 | 160 | 161 | private String makeKey(String dataId, String group) { 162 | if (StringUtils.isBlank(group)) { 163 | group = Constants.DEFAULT_GROUP; 164 | } 165 | return dataId + "_" + group; 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/client/impl/DiamondClientFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.client.impl; 11 | 12 | import com.taobao.diamond.client.DiamondSubscriber; 13 | 14 | 15 | /** 16 | * Diamond客户端工厂类,可以产生一个单例的DiamondSubscriber,供所有的DiamondManager共用 不同的集群对应不同的单例 17 | * 18 | * @author aoqiong 19 | * 20 | */ 21 | public class DiamondClientFactory { 22 | 23 | private static DiamondSubscriber diamondSubscriber = new DefaultDiamondSubscriber(new DefaultSubscriberListener()); 24 | 25 | 26 | public static DiamondSubscriber getSingletonDiamondSubscriber() { 27 | return diamondSubscriber; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/client/processor/LocalConfigInfoProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.client.processor; 11 | 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.util.HashMap; 15 | import java.util.HashSet; 16 | import java.util.Map; 17 | import java.util.Set; 18 | import java.util.concurrent.Executors; 19 | import java.util.concurrent.ScheduledExecutorService; 20 | 21 | import org.apache.commons.logging.Log; 22 | import org.apache.commons.logging.LogFactory; 23 | 24 | import com.taobao.diamond.common.Constants; 25 | import com.taobao.diamond.configinfo.CacheData; 26 | import com.taobao.diamond.io.FileSystem; 27 | import com.taobao.diamond.io.Path; 28 | import com.taobao.diamond.io.watch.StandardWatchEventKind; 29 | import com.taobao.diamond.io.watch.WatchEvent; 30 | import com.taobao.diamond.io.watch.WatchKey; 31 | import com.taobao.diamond.io.watch.WatchService; 32 | import com.taobao.diamond.utils.FileUtils; 33 | 34 | 35 | public class LocalConfigInfoProcessor { 36 | private static final Log log = LogFactory.getLog(LocalConfigInfoProcessor.class); 37 | private ScheduledExecutorService singleExecutor = Executors.newSingleThreadScheduledExecutor();; 38 | 39 | private final Map existFiles = new HashMap(); 40 | 41 | private volatile boolean isRun; 42 | private String rootPath = null; 43 | 44 | 45 | /** 46 | * 获取本地配置 47 | * 48 | * @param cacheData 49 | * @param force 50 | * 强制获取,在没有变更的时候不返回null 51 | * @return 52 | * @throws IOException 53 | */ 54 | public String getLocalConfigureInfomation(CacheData cacheData, boolean force) throws IOException { 55 | String filePath = getFilePath(cacheData.getDataId(), cacheData.getGroup()); 56 | if (!existFiles.containsKey(filePath)) { 57 | if (cacheData.isUseLocalConfigInfo()) { 58 | cacheData.setLastModifiedHeader(Constants.NULL); 59 | cacheData.setMd5(Constants.NULL); 60 | cacheData.setLocalConfigInfoFile(null); 61 | cacheData.setLocalConfigInfoVersion(0L); 62 | cacheData.setUseLocalConfigInfo(false); 63 | } 64 | return null; 65 | } 66 | if (force) { 67 | log.info("主动从本地获取配置数据, dataId:" + cacheData.getDataId() + ", group:" + cacheData.getGroup()); 68 | 69 | String content = FileUtils.getFileContent(filePath); 70 | return content; 71 | } 72 | // 判断是否变更,没有变更,返回null 73 | if (!filePath.equals(cacheData.getLocalConfigInfoFile()) 74 | || existFiles.get(filePath) != cacheData.getLocalConfigInfoVersion()) { 75 | String content = FileUtils.getFileContent(filePath); 76 | cacheData.setLocalConfigInfoFile(filePath); 77 | cacheData.setLocalConfigInfoVersion(existFiles.get(filePath)); 78 | cacheData.setUseLocalConfigInfo(true); 79 | 80 | if (log.isInfoEnabled()) { 81 | log.info("本地配置数据发生变化, dataId:" + cacheData.getDataId() + ", group:" + cacheData.getGroup()); 82 | } 83 | 84 | return content; 85 | } 86 | else { 87 | cacheData.setUseLocalConfigInfo(true); 88 | 89 | if (log.isInfoEnabled()) { 90 | log.debug("本地配置数据没有发生变化, dataId:" + cacheData.getDataId() + ", group:" + cacheData.getGroup()); 91 | } 92 | 93 | return null; 94 | } 95 | } 96 | 97 | 98 | String getFilePath(String dataId, String group) { 99 | StringBuilder filePathBuilder = new StringBuilder(); 100 | filePathBuilder.append(rootPath).append("/").append(Constants.BASE_DIR).append("/").append(group).append("/") 101 | .append(dataId); 102 | File file = new File(filePathBuilder.toString()); 103 | return file.getAbsolutePath(); 104 | } 105 | 106 | 107 | public synchronized void start(String rootPath) { 108 | if (this.isRun) { 109 | return; 110 | } 111 | this.rootPath = rootPath; 112 | this.isRun = true; 113 | if (this.singleExecutor == null || singleExecutor.isTerminated()) { 114 | singleExecutor = Executors.newSingleThreadScheduledExecutor(); 115 | } 116 | initDataDir(rootPath); 117 | startCheckLocalDir(rootPath); 118 | } 119 | 120 | 121 | private void initDataDir(String rootPath) { 122 | try { 123 | File flie = new File(rootPath); 124 | flie.mkdir(); 125 | } 126 | catch (Exception e) { 127 | } 128 | } 129 | 130 | 131 | public synchronized void stop() { 132 | if (!this.isRun) { 133 | return; 134 | } 135 | this.isRun = false; 136 | this.singleExecutor.shutdownNow(); 137 | this.singleExecutor = null; 138 | } 139 | 140 | 141 | private void startCheckLocalDir(final String filePath) { 142 | final WatchService watcher = FileSystem.getDefault().newWatchService(); 143 | 144 | Path path = new Path(new File(filePath)); 145 | // 注册事件 146 | watcher.register(path, true, StandardWatchEventKind.ENTRY_CREATE, StandardWatchEventKind.ENTRY_DELETE, 147 | StandardWatchEventKind.ENTRY_MODIFY); 148 | // 第一次运行,主动check 149 | checkAtFirst(watcher); 150 | singleExecutor.execute(new Runnable() { 151 | public void run() { 152 | log.debug(">>>>>>已经开始监控目录<<<<<<"); 153 | // 无限循环等待事件 154 | while (isRun) { 155 | // 凭证 156 | WatchKey key; 157 | try { 158 | key = watcher.take(); 159 | } 160 | catch (InterruptedException x) { 161 | continue; 162 | } 163 | // reset,如果无效,跳出循环,无效可能是监听的目录被删除 164 | if (!processEvents(key)) { 165 | log.error("reset unvalid,监控服务失效"); 166 | break; 167 | } 168 | } 169 | log.debug(">>>>>>退出监控目录<<<<<<"); 170 | watcher.close(); 171 | 172 | } 173 | 174 | }); 175 | } 176 | 177 | 178 | private void checkAtFirst(final WatchService watcher) { 179 | watcher.check(); 180 | WatchKey key = null; 181 | while ((key = watcher.poll()) != null) { 182 | processEvents(key); 183 | } 184 | } 185 | 186 | 187 | /** 188 | * 处理触发的事件 189 | * 190 | * @param key 191 | * @return 192 | */ 193 | @SuppressWarnings({ "unchecked" }) 194 | private boolean processEvents(WatchKey key) { 195 | /** 196 | * 获取事件集合 197 | */ 198 | for (WatchEvent event : key.pollEvents()) { 199 | // 事件的类型 200 | // WatchEvent.Kind kind = event.kind(); 201 | 202 | // 通过context方法得到发生事件的path 203 | WatchEvent ev = (WatchEvent) event; 204 | Path eventPath = ev.context(); 205 | 206 | String realPath = eventPath.getAbsolutePath(); 207 | if (ev.kind() == StandardWatchEventKind.ENTRY_CREATE || ev.kind() == StandardWatchEventKind.ENTRY_MODIFY) { 208 | 209 | String grandpaDir = null; 210 | try { 211 | grandpaDir = FileUtils.getGrandpaDir(realPath); 212 | } 213 | catch (Exception e1) { 214 | 215 | } 216 | if (!Constants.BASE_DIR.equals(grandpaDir)) { 217 | log.error("无效的文件进入监控目录: " + realPath); 218 | continue; 219 | } 220 | existFiles.put(realPath, System.currentTimeMillis()); 221 | if (log.isInfoEnabled()) { 222 | log.info(realPath + "文件被添加或更新"); 223 | } 224 | } 225 | else if (ev.kind() == StandardWatchEventKind.ENTRY_DELETE) { 226 | String grandpaDir = null; 227 | try { 228 | grandpaDir = FileUtils.getGrandpaDir(realPath); 229 | } 230 | catch (Exception e1) { 231 | 232 | } 233 | if (Constants.BASE_DIR.equals(grandpaDir)) { 234 | // 删除的是文件 235 | existFiles.remove(realPath); 236 | if (log.isInfoEnabled()) { 237 | log.info(realPath + "文件被被删除"); 238 | } 239 | } 240 | else { 241 | // 删除的是目录 242 | Set keySet = new HashSet(existFiles.keySet()); 243 | for (String filePath : keySet) { 244 | if (filePath.startsWith(realPath)) { 245 | existFiles.remove(filePath); 246 | if (log.isInfoEnabled()) { 247 | log.info(filePath + "文件被删除"); 248 | } 249 | } 250 | } 251 | 252 | } 253 | } 254 | } 255 | return key.reset(); 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/client/processor/ServerAddressProcessor.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-client/src/main/java/com/taobao/diamond/client/processor/ServerAddressProcessor.java -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/client/processor/SnapshotConfigInfoProcessor.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-client/src/main/java/com/taobao/diamond/client/processor/SnapshotConfigInfoProcessor.java -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/configinfo/CacheData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.configinfo; 11 | 12 | import java.util.concurrent.atomic.AtomicInteger; 13 | import java.util.concurrent.atomic.AtomicLong; 14 | 15 | import com.taobao.diamond.common.Constants; 16 | 17 | 18 | public class CacheData { 19 | 20 | private String dataId; 21 | private String group; 22 | private volatile String lastModifiedHeader = Constants.NULL; 23 | private volatile String md5 = Constants.NULL; 24 | private AtomicInteger domainNamePos = new AtomicInteger(0); 25 | private volatile String localConfigInfoFile = null; 26 | private volatile long localConfigInfoVersion; 27 | private volatile boolean useLocalConfigInfo = false; 28 | /** 29 | * 统计成功获取配置信息的次数 30 | */ 31 | private final AtomicLong fetchCounter = new AtomicLong(0); 32 | 33 | 34 | public CacheData(String dataId, String group) { 35 | this.dataId = dataId; 36 | this.group = group; 37 | } 38 | 39 | 40 | public String getDataId() { 41 | return dataId; 42 | } 43 | 44 | 45 | public long getFetchCount() { 46 | return this.fetchCounter.get(); 47 | } 48 | 49 | 50 | public long incrementFetchCountAndGet() { 51 | return this.fetchCounter.incrementAndGet(); 52 | } 53 | 54 | 55 | public void setDataId(String dataId) { 56 | this.dataId = dataId; 57 | } 58 | 59 | 60 | public String getGroup() { 61 | return group; 62 | } 63 | 64 | 65 | public void setGroup(String group) { 66 | this.group = group; 67 | } 68 | 69 | 70 | public String getLocalConfigInfoFile() { 71 | return localConfigInfoFile; 72 | } 73 | 74 | 75 | public void setLocalConfigInfoFile(String localConfigInfoFile) { 76 | this.localConfigInfoFile = localConfigInfoFile; 77 | } 78 | 79 | 80 | public long getLocalConfigInfoVersion() { 81 | return localConfigInfoVersion; 82 | } 83 | 84 | 85 | public void setLocalConfigInfoVersion(long localConfigInfoVersion) { 86 | this.localConfigInfoVersion = localConfigInfoVersion; 87 | } 88 | 89 | 90 | public boolean isUseLocalConfigInfo() { 91 | return useLocalConfigInfo; 92 | } 93 | 94 | 95 | public void setUseLocalConfigInfo(boolean useLocalConfigInfo) { 96 | this.useLocalConfigInfo = useLocalConfigInfo; 97 | } 98 | 99 | 100 | public String getLastModifiedHeader() { 101 | return lastModifiedHeader; 102 | } 103 | 104 | 105 | public void setLastModifiedHeader(String lastModifiedHeader) { 106 | this.lastModifiedHeader = lastModifiedHeader; 107 | } 108 | 109 | 110 | public AtomicInteger getDomainNamePos() { 111 | return domainNamePos; 112 | } 113 | 114 | 115 | public void setDomainNamePos(int domainNamePos) { 116 | this.domainNamePos.set(domainNamePos); 117 | } 118 | 119 | 120 | public String getMd5() { 121 | return md5; 122 | } 123 | 124 | 125 | public void setMd5(String md5) { 126 | this.md5 = md5; 127 | } 128 | 129 | 130 | @Override 131 | public int hashCode() { 132 | final int prime = 31; 133 | int result = 1; 134 | result = prime * result + ((dataId == null) ? 0 : dataId.hashCode()); 135 | result = prime * result + ((group == null) ? 0 : group.hashCode()); 136 | return result; 137 | } 138 | 139 | 140 | @Override 141 | public boolean equals(Object obj) { 142 | if (this == obj) 143 | return true; 144 | if (obj == null) 145 | return false; 146 | if (getClass() != obj.getClass()) 147 | return false; 148 | CacheData other = (CacheData) obj; 149 | if (dataId == null) { 150 | if (other.dataId != null) 151 | return false; 152 | } 153 | else if (!dataId.equals(other.dataId)) 154 | return false; 155 | if (group == null) { 156 | if (other.group != null) 157 | return false; 158 | } 159 | else if (!group.equals(other.group)) 160 | return false; 161 | return true; 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/configinfo/ConfigureInfomation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.configinfo; 11 | 12 | import java.io.Serializable; 13 | 14 | 15 | /** 16 | * 配置信息的类 17 | * 18 | * @author aoqiong 19 | * 20 | */ 21 | public class ConfigureInfomation implements Serializable { 22 | 23 | /** 24 | * 25 | */ 26 | private static final long serialVersionUID = 6684264073344815420L; 27 | 28 | private String dataId; 29 | private String group; 30 | private String ConfigureInfomation; 31 | 32 | 33 | public String getDataId() { 34 | return dataId; 35 | } 36 | 37 | 38 | public void setDataId(String dataId) { 39 | this.dataId = dataId; 40 | } 41 | 42 | 43 | public String getGroup() { 44 | return group; 45 | } 46 | 47 | 48 | public void setGroup(String group) { 49 | this.group = group; 50 | } 51 | 52 | 53 | public String getConfigureInfomation() { 54 | return ConfigureInfomation; 55 | } 56 | 57 | 58 | public void setConfigureInfomation(String configureInfomation) { 59 | ConfigureInfomation = configureInfomation; 60 | } 61 | 62 | 63 | @Override 64 | public int hashCode() { 65 | final int prime = 31; 66 | int result = 1; 67 | result = prime * result + ((ConfigureInfomation == null) ? 0 : ConfigureInfomation.hashCode()); 68 | result = prime * result + ((dataId == null) ? 0 : dataId.hashCode()); 69 | result = prime * result + ((group == null) ? 0 : group.hashCode()); 70 | return result; 71 | } 72 | 73 | 74 | @Override 75 | public boolean equals(Object obj) { 76 | if (this == obj) 77 | return true; 78 | if (obj == null) 79 | return false; 80 | if (getClass() != obj.getClass()) 81 | return false; 82 | ConfigureInfomation other = (ConfigureInfomation) obj; 83 | if (ConfigureInfomation == null) { 84 | if (other.ConfigureInfomation != null) 85 | return false; 86 | } 87 | else if (!ConfigureInfomation.equals(other.ConfigureInfomation)) 88 | return false; 89 | if (dataId == null) { 90 | if (other.dataId != null) 91 | return false; 92 | } 93 | else if (!dataId.equals(other.dataId)) 94 | return false; 95 | if (group == null) { 96 | if (other.group != null) 97 | return false; 98 | } 99 | else if (!group.equals(other.group)) 100 | return false; 101 | return true; 102 | } 103 | 104 | 105 | @Override 106 | public String toString() { 107 | StringBuilder sb = new StringBuilder(); 108 | sb.append("DataId: ").append(dataId); 109 | sb.append(", Group: ").append(group); 110 | sb.append(", ConfigureInfomation: ").append(ConfigureInfomation); 111 | return sb.toString(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/manager/DiamondManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.manager; 11 | 12 | import java.util.List; 13 | import java.util.Properties; 14 | 15 | import com.taobao.diamond.client.DiamondConfigure; 16 | 17 | 18 | /** 19 | * DiamondManager用于订阅一个且仅有一个DataID对应的配置信息 20 | * 21 | * @author aoqiong 22 | * 23 | */ 24 | public interface DiamondManager { 25 | 26 | /** 27 | * 设置ManagerListener,每当收到一个DataID对应的配置信息,则客户设置的ManagerListener会接收到这个配置信息 28 | * 29 | * @param managerListener 30 | */ 31 | public void setManagerListener(ManagerListener managerListener); 32 | 33 | 34 | /** 35 | * 设置DataID对应的多个ManagerListener,每当收到一个DataID对应的配置信息, 36 | * 则客户设置的多个ManagerListener会接收到这个配置信息 37 | * 38 | * @param managerListenerList 39 | */ 40 | public void setManagerListeners(List managerListenerList); 41 | 42 | 43 | /** 44 | * 返回该DiamondManager设置的listener列表 45 | * 46 | * @return 47 | */ 48 | public List getManagerListeners(); 49 | 50 | 51 | /** 52 | * 同步获取配置信息,,此方法优先从${user.home 53 | * }/diamond/data/config-data/${group}/${dataId}下获取配置文件,如果没有,则从diamond 54 | * server获取配置信息 55 | * 56 | * @param timeout 57 | * 从网络获取配置信息的超时,单位毫秒 58 | * @return 59 | */ 60 | public String getConfigureInfomation(long timeout); 61 | 62 | 63 | /** 64 | * 同步获取一份有效的配置信息,按照本地文件->diamond服务器->上一次正确配置的snapshot 65 | * 的优先顺序获取, 如果这些途径都无效,则返回null 66 | * 67 | * @param timeout 68 | * 从网络获取配置信息的超时,单位毫秒 69 | * @return 70 | */ 71 | public String getAvailableConfigureInfomation(long timeout); 72 | 73 | 74 | /** 75 | * 同步获取一份有效的配置信息,按照上一次正确配置的snapshot->本地文件->diamond服务器 76 | * 的优先顺序获取, 如果这些途径都无效,则返回null 77 | * 78 | * @param timeout 79 | * 从网络获取配置信息的超时,单位毫秒 80 | * @return 81 | */ 82 | 83 | public String getAvailableConfigureInfomationFromSnapshot(long timeout); 84 | 85 | 86 | /** 87 | * 同步获取Properties格式的配置信息 88 | * 89 | * @param timeout 90 | * 单位:毫秒 91 | * @return 92 | */ 93 | public Properties getPropertiesConfigureInfomation(long timeout); 94 | 95 | 96 | /** 97 | * 同步获取Properties格式的配置信息,本地snapshot优先 98 | * 99 | * @param timeout 100 | * @return 101 | */ 102 | public Properties getAvailablePropertiesConfigureInfomationFromSnapshot(long timeout); 103 | 104 | 105 | /** 106 | * 同步获取一份有效的Properties配置信息,按照本地文件->diamond服务器->上一次正确配置的snapshot 的优先顺序获取, 如果这些途径都无效,则返回null 108 | * 109 | * @param timeout 110 | * 单位:毫秒 111 | * @return 112 | */ 113 | public Properties getAvailablePropertiesConfigureInfomation(long timeout); 114 | 115 | 116 | /** 117 | * 设置DiamondConfigure,一个JVM中所有的DiamondManager对应这一个DiamondConfigure 118 | * 119 | * @param diamondConfigure 120 | */ 121 | public void setDiamondConfigure(DiamondConfigure diamondConfigure); 122 | 123 | 124 | /** 125 | * 获取DiamondConfigure,一个JVM中所有的DiamondManager对应这一个DiamondConfigure 126 | * 127 | * @param diamondConfigure 128 | */ 129 | public DiamondConfigure getDiamondConfigure(); 130 | 131 | 132 | /** 133 | * 关闭这个DiamondManager 134 | */ 135 | public void close(); 136 | 137 | } 138 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/manager/ManagerListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.manager; 11 | 12 | import java.util.concurrent.Executor; 13 | 14 | 15 | /** 16 | * 客户如果想接收DataID对应的配置信息,需要自己实现一个监听器 17 | * 18 | * @author aoqiong 19 | * 20 | */ 21 | public interface ManagerListener { 22 | 23 | public Executor getExecutor(); 24 | 25 | 26 | /** 27 | * 接收配置信息 28 | * 29 | * @param configInfo 30 | */ 31 | public void receiveConfigInfo(final String configInfo); 32 | } 33 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/manager/ManagerListenerAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.manager; 11 | 12 | import java.util.concurrent.Executor; 13 | 14 | 15 | public abstract class ManagerListenerAdapter implements ManagerListener { 16 | 17 | public Executor getExecutor() { 18 | return null; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/manager/impl/DefaultDiamondManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.manager.impl; 11 | 12 | import java.io.IOException; 13 | import java.io.StringReader; 14 | import java.util.LinkedList; 15 | import java.util.List; 16 | import java.util.Properties; 17 | 18 | import org.apache.commons.logging.Log; 19 | import org.apache.commons.logging.LogFactory; 20 | 21 | import com.taobao.diamond.client.DiamondConfigure; 22 | import com.taobao.diamond.client.DiamondSubscriber; 23 | import com.taobao.diamond.client.impl.DefaultSubscriberListener; 24 | import com.taobao.diamond.client.impl.DiamondClientFactory; 25 | import com.taobao.diamond.manager.DiamondManager; 26 | import com.taobao.diamond.manager.ManagerListener; 27 | 28 | 29 | /** 30 | * 需要注意的是:一个JVM中一个DataID只能对应一个DiamondManager 31 | * 32 | * @author aoqiong 33 | * 34 | */ 35 | public class DefaultDiamondManager implements DiamondManager { 36 | 37 | private static final Log log = LogFactory.getLog(DefaultDiamondManager.class); 38 | 39 | private DiamondSubscriber diamondSubscriber = null; 40 | private final List managerListeners = new LinkedList(); 41 | private final String dataId; 42 | private final String group; 43 | 44 | 45 | public DefaultDiamondManager(String dataId, ManagerListener managerListener) { 46 | this(null, dataId, managerListener); 47 | } 48 | 49 | 50 | public DefaultDiamondManager(String group, String dataId, ManagerListener managerListener) { 51 | this.dataId = dataId; 52 | this.group = group; 53 | 54 | diamondSubscriber = DiamondClientFactory.getSingletonDiamondSubscriber(); 55 | 56 | this.managerListeners.add(managerListener); 57 | ((DefaultSubscriberListener) diamondSubscriber.getSubscriberListener()).addManagerListeners(this.dataId, 58 | this.group, this.managerListeners); 59 | diamondSubscriber.addDataId(this.dataId, this.group); 60 | diamondSubscriber.start(); 61 | 62 | } 63 | 64 | 65 | public DefaultDiamondManager(String dataId, List managerListenerList) { 66 | this(null, dataId, managerListenerList); 67 | } 68 | 69 | 70 | /** 71 | * 使用指定的集群类型clusterType 72 | * 73 | * @param group 74 | * @param dataId 75 | * @param managerListenerList 76 | * @param clusterType 77 | */ 78 | public DefaultDiamondManager(String group, String dataId, List managerListenerList) { 79 | this.dataId = dataId; 80 | this.group = group; 81 | 82 | diamondSubscriber = DiamondClientFactory.getSingletonDiamondSubscriber(); 83 | 84 | this.managerListeners.addAll(managerListenerList); 85 | ((DefaultSubscriberListener) diamondSubscriber.getSubscriberListener()).addManagerListeners(this.dataId, 86 | this.group, this.managerListeners); 87 | diamondSubscriber.addDataId(this.dataId, this.group); 88 | diamondSubscriber.start(); 89 | } 90 | 91 | 92 | public void setManagerListener(ManagerListener managerListener) { 93 | this.managerListeners.clear(); 94 | this.managerListeners.add(managerListener); 95 | 96 | ((DefaultSubscriberListener) diamondSubscriber.getSubscriberListener()).removeManagerListeners(this.dataId, 97 | this.group); 98 | ((DefaultSubscriberListener) diamondSubscriber.getSubscriberListener()).addManagerListeners(this.dataId, 99 | this.group, this.managerListeners); 100 | } 101 | 102 | 103 | public void close() { 104 | /** 105 | * 因为同一个DataID只能对应一个MnanagerListener,所以,关闭时一次性关闭所有ManagerListener即可 106 | */ 107 | ((DefaultSubscriberListener) diamondSubscriber.getSubscriberListener()).removeManagerListeners(this.dataId, 108 | this.group); 109 | 110 | diamondSubscriber.removeDataId(dataId, group); 111 | if (diamondSubscriber.getDataIds().size() == 0) { 112 | diamondSubscriber.close(); 113 | } 114 | 115 | } 116 | 117 | 118 | public String getConfigureInfomation(long timeout) { 119 | return diamondSubscriber.getConfigureInfomation(this.dataId, this.group, timeout); 120 | } 121 | 122 | 123 | public String getAvailableConfigureInfomation(long timeout) { 124 | return diamondSubscriber.getAvailableConfigureInfomation(dataId, group, timeout); 125 | } 126 | 127 | 128 | public String getAvailableConfigureInfomationFromSnapshot(long timeout) { 129 | return diamondSubscriber.getAvailableConfigureInfomationFromSnapshot(dataId, group, timeout); 130 | } 131 | 132 | 133 | public Properties getAvailablePropertiesConfigureInfomation(long timeout) { 134 | String configInfo = this.getAvailableConfigureInfomation(timeout); 135 | Properties properties = new Properties(); 136 | try { 137 | properties.load(new StringReader(configInfo)); 138 | return properties; 139 | } 140 | catch (IOException e) { 141 | log.warn("装载properties失败:" + configInfo, e); 142 | throw new RuntimeException("装载properties失败:" + configInfo, e); 143 | } 144 | } 145 | 146 | 147 | public Properties getAvailablePropertiesConfigureInfomationFromSnapshot(long timeout) { 148 | String configInfo = this.getAvailableConfigureInfomationFromSnapshot(timeout); 149 | Properties properties = new Properties(); 150 | try { 151 | properties.load(new StringReader(configInfo)); 152 | return properties; 153 | } 154 | catch (IOException e) { 155 | log.warn("装载properties失败:" + configInfo, e); 156 | throw new RuntimeException("装载properties失败:" + configInfo, e); 157 | } 158 | } 159 | 160 | 161 | public void setManagerListeners(List managerListenerList) { 162 | this.managerListeners.clear(); 163 | this.managerListeners.addAll(managerListenerList); 164 | 165 | ((DefaultSubscriberListener) diamondSubscriber.getSubscriberListener()).removeManagerListeners(this.dataId, 166 | this.group); 167 | ((DefaultSubscriberListener) diamondSubscriber.getSubscriberListener()).addManagerListeners(this.dataId, 168 | this.group, this.managerListeners); 169 | } 170 | 171 | 172 | public DiamondConfigure getDiamondConfigure() { 173 | return diamondSubscriber.getDiamondConfigure(); 174 | } 175 | 176 | 177 | public void setDiamondConfigure(DiamondConfigure diamondConfigure) { 178 | diamondSubscriber.setDiamondConfigure(diamondConfigure); 179 | } 180 | 181 | 182 | public Properties getPropertiesConfigureInfomation(long timeout) { 183 | String configInfo = this.getConfigureInfomation(timeout); 184 | Properties properties = new Properties(); 185 | try { 186 | properties.load(new StringReader(configInfo)); 187 | return properties; 188 | } 189 | catch (IOException e) { 190 | log.warn("装载properties失败:" + configInfo, e); 191 | throw new RuntimeException("装载properties失败:" + configInfo, e); 192 | } 193 | } 194 | 195 | 196 | public List getManagerListeners() { 197 | return this.managerListeners; 198 | } 199 | 200 | } 201 | -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/manager/impl/PropertiesListener.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-client/src/main/java/com/taobao/diamond/manager/impl/PropertiesListener.java -------------------------------------------------------------------------------- /diamond-client/src/main/java/com/taobao/diamond/mockserver/MockServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.mockserver; 11 | 12 | import java.util.Map; 13 | import java.util.concurrent.ConcurrentHashMap; 14 | 15 | import com.taobao.diamond.client.impl.DiamondClientFactory; 16 | import com.taobao.diamond.common.Constants; 17 | 18 | 19 | public class MockServer { 20 | 21 | private static class Pair { 22 | String configInfo; 23 | Boolean checkable; 24 | 25 | 26 | public Pair(String configInfo) { 27 | this.configInfo = configInfo; 28 | this.checkable = true; 29 | } 30 | } 31 | 32 | private static ConcurrentHashMap> staticConfigInfos = 33 | new ConcurrentHashMap>(); 34 | private static volatile boolean testMode = false; 35 | 36 | 37 | public static void setUpMockServer() { 38 | testMode = true; 39 | } 40 | 41 | 42 | public static void tearDownMockServer() { 43 | staticConfigInfos.clear(); 44 | DiamondClientFactory.getSingletonDiamondSubscriber().close(); 45 | testMode = false; 46 | } 47 | 48 | 49 | public static String getConfigInfo(String dataId) { 50 | return getConfigInfo(dataId, null); 51 | } 52 | 53 | 54 | public static String getConfigInfo(String dataId, String group) { 55 | if (null == group) { 56 | group = Constants.DEFAULT_GROUP; 57 | } 58 | Map pairs = staticConfigInfos.get(dataId); 59 | if (null == pairs) { 60 | return null; 61 | } 62 | Pair pair = pairs.get(group); 63 | if (null == pair) { 64 | return null; 65 | } 66 | pair.checkable = false; 67 | return pair.configInfo; 68 | } 69 | 70 | 71 | public static String getUpdateConfigInfo(String dataId) { 72 | return getUpdateConfigInfo(dataId, null); 73 | } 74 | 75 | 76 | public static String getUpdateConfigInfo(String dataId, String group) { 77 | if (null == group) { 78 | group = Constants.DEFAULT_GROUP; 79 | } 80 | Map pairs = staticConfigInfos.get(dataId); 81 | if (null == pairs) { 82 | return null; 83 | } 84 | Pair pair = pairs.get(group); 85 | if (null != pair && pair.checkable) { 86 | pair.checkable = false; 87 | return pair.configInfo; 88 | } 89 | return null; 90 | } 91 | 92 | 93 | public static void setConfigInfos(Map configInfos) { 94 | if (null != configInfos) { 95 | for (Map.Entry entry : configInfos.entrySet()) { 96 | setConfigInfo(entry.getKey(), entry.getValue()); 97 | } 98 | } 99 | } 100 | 101 | 102 | public static void setConfigInfo(String dataId, String configInfo) { 103 | setConfigInfo(dataId, null, configInfo); 104 | } 105 | 106 | 107 | public static void setConfigInfo(String dataId, String group, String configInfo) { 108 | if (null == group) { 109 | group = Constants.DEFAULT_GROUP; 110 | } 111 | Pair pair = new Pair(configInfo); 112 | Map newPairs = new ConcurrentHashMap(); 113 | Map pairs = staticConfigInfos.putIfAbsent(dataId, newPairs); 114 | if (null == pairs) { 115 | pairs = newPairs; 116 | } 117 | pairs.put(group, pair); 118 | } 119 | 120 | 121 | public static boolean isTestMode() { 122 | return testMode; 123 | } 124 | } -------------------------------------------------------------------------------- /diamond-client/src/test/java/ClientTest.java: -------------------------------------------------------------------------------- 1 | import com.taobao.diamond.manager.DiamondManager; 2 | import com.taobao.diamond.manager.ManagerListener; 3 | import com.taobao.diamond.manager.impl.DefaultDiamondManager; 4 | 5 | import java.util.concurrent.Executor; 6 | 7 | /** 8 | * Created with IntelliJ IDEA. 9 | * User: gaozhenlong 10 | * Date: 17-5-14 11 | * Time: 下午10:27 12 | * To change this template use File | Settings | File Templates. 13 | */ 14 | public class ClientTest { 15 | public static void main(String[] args) { 16 | 17 | DiamondManager manager = new DefaultDiamondManager("1", new ManagerListener() { 18 | @Override 19 | public Executor getExecutor() { 20 | return null; 21 | } 22 | 23 | @Override 24 | public void receiveConfigInfo(String configInfo) { 25 | System.out.println("receive config: " + configInfo); 26 | } 27 | }); 28 | String configInfo = manager.getAvailableConfigureInfomation(1000); 29 | System.out.println("config: " + configInfo); 30 | 31 | while (true) { 32 | try { 33 | Thread.sleep(1000); 34 | } catch (InterruptedException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /diamond-client/src/test/resources/diamond.properties: -------------------------------------------------------------------------------- 1 | diamond.port=8090 2 | diamond.config.ip=127.0.0.1 -------------------------------------------------------------------------------- /diamond-sdk/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | diamond-all 5 | com.taobao.diamond 6 | 2.0.5.4.taocode-SNAPSHOT 7 | 8 | 9 | com.taobao.diamond 10 | diamond-sdk 11 | diamond-sdk v${project.version} 12 | jar 13 | 14 | 15 | 16 | junit 17 | junit 18 | 19 | 20 | com.taobao.diamond 21 | diamond-utils 22 | 23 | 24 | commons-httpclient 25 | commons-httpclient 26 | 27 | 28 | commons-lang 29 | commons-lang 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /diamond-sdk/src/main/java/com/taobao/diamond/domain/BatchContextResult.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-sdk/src/main/java/com/taobao/diamond/domain/BatchContextResult.java -------------------------------------------------------------------------------- /diamond-sdk/src/main/java/com/taobao/diamond/domain/ContextResult.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-sdk/src/main/java/com/taobao/diamond/domain/ContextResult.java -------------------------------------------------------------------------------- /diamond-sdk/src/main/java/com/taobao/diamond/domain/DiamondConf.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-sdk/src/main/java/com/taobao/diamond/domain/DiamondConf.java -------------------------------------------------------------------------------- /diamond-sdk/src/main/java/com/taobao/diamond/domain/DiamondSDKConf.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-sdk/src/main/java/com/taobao/diamond/domain/DiamondSDKConf.java -------------------------------------------------------------------------------- /diamond-sdk/src/main/java/com/taobao/diamond/domain/PageContextResult.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-sdk/src/main/java/com/taobao/diamond/domain/PageContextResult.java -------------------------------------------------------------------------------- /diamond-sdk/src/main/java/com/taobao/diamond/sdkapi/DiamondSDKManager.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-sdk/src/main/java/com/taobao/diamond/sdkapi/DiamondSDKManager.java -------------------------------------------------------------------------------- /diamond-sdk/src/main/java/com/taobao/diamond/sdkapi/impl/DiamondSDKManagerImpl.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-sdk/src/main/java/com/taobao/diamond/sdkapi/impl/DiamondSDKManagerImpl.java -------------------------------------------------------------------------------- /diamond-sdk/src/main/java/com/taobao/diamond/util/DiamondUtils.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-sdk/src/main/java/com/taobao/diamond/util/DiamondUtils.java -------------------------------------------------------------------------------- /diamond-sdk/src/main/java/com/taobao/diamond/util/PatternUtils.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-sdk/src/main/java/com/taobao/diamond/util/PatternUtils.java -------------------------------------------------------------------------------- /diamond-sdk/src/main/java/com/taobao/diamond/util/RandomDiamondUtils.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-sdk/src/main/java/com/taobao/diamond/util/RandomDiamondUtils.java -------------------------------------------------------------------------------- /diamond-sdk/src/main/java/com/taobao/diamond/util/ResourceUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.util; 11 | 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.io.InputStreamReader; 16 | import java.io.Reader; 17 | import java.net.URL; 18 | import java.util.Properties; 19 | 20 | 21 | /** 22 | * 23 | * @author boyan 24 | * @date 2010-5-4 25 | */ 26 | public class ResourceUtils extends Object { 27 | 28 | /** */ 29 | /** 30 | * Returns the URL of the resource on the classpath 31 | * 32 | * @param resource 33 | * The resource to find 34 | * @throws IOException 35 | * If the resource cannot be found or read 36 | * @return The resource 37 | */ 38 | public static URL getResourceURL(String resource) throws IOException { 39 | URL url = null; 40 | ClassLoader loader = ResourceUtils.class.getClassLoader(); 41 | if (loader != null) 42 | url = loader.getResource(resource); 43 | if (url == null) 44 | url = ClassLoader.getSystemResource(resource); 45 | if (url == null) 46 | throw new IOException("Could not find resource " + resource); 47 | return url; 48 | } 49 | 50 | 51 | /** */ 52 | /** 53 | * Returns the URL of the resource on the classpath 54 | * 55 | * @param loader 56 | * The classloader used to load the resource 57 | * @param resource 58 | * The resource to find 59 | * @throws IOException 60 | * If the resource cannot be found or read 61 | * @return The resource 62 | */ 63 | public static URL getResourceURL(ClassLoader loader, String resource) throws IOException { 64 | URL url = null; 65 | if (loader != null) 66 | url = loader.getResource(resource); 67 | if (url == null) 68 | url = ClassLoader.getSystemResource(resource); 69 | if (url == null) 70 | throw new IOException("Could not find resource " + resource); 71 | return url; 72 | } 73 | 74 | 75 | /** */ 76 | /** 77 | * Returns a resource on the classpath as a Stream object 78 | * 79 | * @param resource 80 | * The resource to find 81 | * @throws IOException 82 | * If the resource cannot be found or read 83 | * @return The resource 84 | */ 85 | public static InputStream getResourceAsStream(String resource) throws IOException { 86 | InputStream in = null; 87 | ClassLoader loader = ResourceUtils.class.getClassLoader(); 88 | if (loader != null) 89 | in = loader.getResourceAsStream(resource); 90 | if (in == null) 91 | in = ClassLoader.getSystemResourceAsStream(resource); 92 | if (in == null) 93 | throw new IOException("Could not find resource " + resource); 94 | return in; 95 | } 96 | 97 | 98 | /** */ 99 | /** 100 | * Returns a resource on the classpath as a Stream object 101 | * 102 | * @param loader 103 | * The classloader used to load the resource 104 | * @param resource 105 | * The resource to find 106 | * @throws IOException 107 | * If the resource cannot be found or read 108 | * @return The resource 109 | */ 110 | public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException { 111 | InputStream in = null; 112 | if (loader != null) 113 | in = loader.getResourceAsStream(resource); 114 | if (in == null) 115 | in = ClassLoader.getSystemResourceAsStream(resource); 116 | if (in == null) 117 | throw new IOException("Could not find resource " + resource); 118 | return in; 119 | } 120 | 121 | 122 | /** */ 123 | /** 124 | * Returns a resource on the classpath as a Properties object 125 | * 126 | * @param resource 127 | * The resource to find 128 | * @throws IOException 129 | * If the resource cannot be found or read 130 | * @return The resource 131 | */ 132 | public static Properties getResourceAsProperties(String resource) throws IOException { 133 | Properties props = new Properties(); 134 | InputStream in = null; 135 | String propfile = resource; 136 | in = getResourceAsStream(propfile); 137 | props.load(in); 138 | in.close(); 139 | return props; 140 | } 141 | 142 | 143 | /** */ 144 | /** 145 | * Returns a resource on the classpath as a Properties object 146 | * 147 | * @param loader 148 | * The classloader used to load the resource 149 | * @param resource 150 | * The resource to find 151 | * @throws IOException 152 | * If the resource cannot be found or read 153 | * @return The resource 154 | */ 155 | public static Properties getResourceAsProperties(ClassLoader loader, String resource) throws IOException { 156 | Properties props = new Properties(); 157 | InputStream in = null; 158 | String propfile = resource; 159 | in = getResourceAsStream(loader, propfile); 160 | props.load(in); 161 | in.close(); 162 | return props; 163 | } 164 | 165 | 166 | /** */ 167 | /** 168 | * Returns a resource on the classpath as a Reader object 169 | * 170 | * @param resource 171 | * The resource to find 172 | * @throws IOException 173 | * If the resource cannot be found or read 174 | * @return The resource 175 | */ 176 | public static InputStreamReader getResourceAsReader(String resource) throws IOException { 177 | return new InputStreamReader(getResourceAsStream(resource)); 178 | } 179 | 180 | 181 | /** */ 182 | /** 183 | * Returns a resource on the classpath as a Reader object 184 | * 185 | * @param loader 186 | * The classloader used to load the resource 187 | * @param resource 188 | * The resource to find 189 | * @throws IOException 190 | * If the resource cannot be found or read 191 | * @return The resource 192 | */ 193 | public static Reader getResourceAsReader(ClassLoader loader, String resource) throws IOException { 194 | return new InputStreamReader(getResourceAsStream(loader, resource)); 195 | } 196 | 197 | 198 | /** */ 199 | /** 200 | * Returns a resource on the classpath as a File object 201 | * 202 | * @param resource 203 | * The resource to find 204 | * @throws IOException 205 | * If the resource cannot be found or read 206 | * @return The resource 207 | */ 208 | public static File getResourceAsFile(String resource) throws IOException { 209 | return new File(getResourceURL(resource).getFile()); 210 | } 211 | 212 | 213 | /** */ 214 | /** 215 | * Returns a resource on the classpath as a File object 216 | * 217 | * @param loader 218 | * The classloader used to load the resource 219 | * @param resource 220 | * The resource to find 221 | * @throws IOException 222 | * If the resource cannot be found or read 223 | * @return The resource 224 | */ 225 | public static File getResourceAsFile(ClassLoader loader, String resource) throws IOException { 226 | return new File(getResourceURL(loader, resource).getFile()); 227 | } 228 | 229 | } -------------------------------------------------------------------------------- /diamond-server/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | diamond-all 6 | com.taobao.diamond 7 | 2.0.5.4.taocode-SNAPSHOT 8 | 9 | 10 | 4.0.0 11 | diamond-server 12 | diamond-server v${project.version} 13 | war 14 | 15 | 16 | diamond-server 17 | 18 | 19 | org.apache.maven.plugins 20 | maven-jar-plugin 21 | 2.3.1 22 | 23 | 24 | **/*.properties 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | com.taobao.diamond 34 | diamond-utils 35 | 36 | 37 | javax.servlet 38 | servlet-api 39 | 40 | 41 | jstl 42 | jstl 43 | 44 | 45 | taglibs 46 | standard 47 | 48 | 49 | org.springframework 50 | spring-jdbc 51 | 52 | 53 | org.springframework 54 | spring-webmvc 55 | 56 | 57 | commons-dbcp 58 | commons-dbcp 59 | 60 | 61 | mysql 62 | mysql-connector-java 63 | 64 | 65 | commons-io 66 | commons-io 67 | 68 | 69 | commons-lang 70 | commons-lang 71 | 72 | 73 | junit 74 | junit 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /diamond-server/release.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | diamond-server 4 | 5 | dir 6 | tar.gz 7 | 8 | 9 | 10 | 11 | com.taobao.diamond:diamond-utils 12 | com.taobao.diamond:diamond-server 13 | 14 | 15 | diamond-server/lib/ 16 | false 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/controller/ConfigController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.server.controller; 11 | 12 | import static com.taobao.diamond.common.Constants.LINE_SEPARATOR; 13 | import static com.taobao.diamond.common.Constants.WORD_SEPARATOR; 14 | 15 | import java.net.URLEncoder; 16 | import java.util.LinkedList; 17 | import java.util.List; 18 | 19 | import javax.servlet.http.HttpServletRequest; 20 | import javax.servlet.http.HttpServletResponse; 21 | 22 | import org.apache.commons.lang.StringUtils; 23 | import org.springframework.beans.factory.annotation.Autowired; 24 | import org.springframework.stereotype.Controller; 25 | 26 | import com.taobao.diamond.common.Constants; 27 | import com.taobao.diamond.server.service.ConfigService; 28 | import com.taobao.diamond.server.service.DiskService; 29 | import com.taobao.diamond.server.utils.GlobalCounter; 30 | 31 | 32 | /** 33 | * 处理配置信息获取和提交的controller 34 | * 35 | * @author boyan 36 | * @date 2010-5-4 37 | */ 38 | @Controller 39 | public class ConfigController { 40 | 41 | @Autowired 42 | private ConfigService configService; 43 | 44 | @Autowired 45 | private DiskService diskService; 46 | 47 | 48 | public String getConfig(HttpServletRequest request, HttpServletResponse response, String dataId, String group) { 49 | response.setHeader("Content-Type", "text/html;charset=GBK"); 50 | final String address = getRemortIP(request); 51 | if (address == null) { 52 | // 未找到远端地址,返回400错误 53 | response.setStatus(HttpServletResponse.SC_BAD_REQUEST); 54 | return "400"; 55 | } 56 | 57 | if (GlobalCounter.getCounter().decrementAndGet() >= 0) { 58 | response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); 59 | return "503"; 60 | } 61 | 62 | String md5 = this.configService.getContentMD5(dataId, group); 63 | if (md5 == null) { 64 | return "404"; 65 | } 66 | 67 | response.setHeader(Constants.CONTENT_MD5, md5); 68 | 69 | // 正在被修改,返回304,这里的检查并没有办法保证一致性,因此做double-check尽力保证 70 | if (diskService.isModified(dataId, group)) { 71 | response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); 72 | return "304"; 73 | } 74 | String path = configService.getConfigInfoPath(dataId, group); 75 | // 再次检查 76 | if (diskService.isModified(dataId, group)) { 77 | response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); 78 | return "304"; 79 | } 80 | // 禁用缓存 81 | response.setHeader("Pragma", "no-cache"); 82 | response.setDateHeader("Expires", 0); 83 | response.setHeader("Cache-Control", "no-cache,no-store"); 84 | return "forward:" + path; 85 | } 86 | 87 | 88 | public String getProbeModifyResult(HttpServletRequest request, HttpServletResponse response, String probeModify) { 89 | response.setHeader("Content-Type", "text/html;charset=GBK"); 90 | final String address = getRemortIP(request); 91 | if (address == null) { 92 | // 未找到远端地址,返回400错误 93 | response.setStatus(HttpServletResponse.SC_BAD_REQUEST); 94 | return "400"; 95 | } 96 | 97 | if (GlobalCounter.getCounter().decrementAndGet() >= 0) { 98 | response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); 99 | return "503"; 100 | } 101 | 102 | final List configKeyList = getConfigKeyList(probeModify); 103 | 104 | StringBuilder resultBuilder = new StringBuilder(); 105 | for (ConfigKey key : configKeyList) { 106 | String md5 = this.configService.getContentMD5(key.getDataId(), key.getGroup()); 107 | if (!StringUtils.equals(md5, key.getMd5())) { 108 | resultBuilder.append(key.getDataId()).append(WORD_SEPARATOR).append(key.getGroup()) 109 | .append(LINE_SEPARATOR); 110 | } 111 | } 112 | 113 | String returnHeader = resultBuilder.toString(); 114 | try { 115 | returnHeader = URLEncoder.encode(resultBuilder.toString(), "UTF-8"); 116 | } 117 | catch (Exception e) { 118 | // ignore 119 | } 120 | 121 | request.setAttribute("content", returnHeader); 122 | // 禁用缓存 123 | response.setHeader("Pragma", "no-cache"); 124 | response.setDateHeader("Expires", 0); 125 | response.setHeader("Cache-Control", "no-cache,no-store"); 126 | return "200"; 127 | } 128 | 129 | 130 | public ConfigService getConfigService() { 131 | return configService; 132 | } 133 | 134 | 135 | public void setConfigService(ConfigService configService) { 136 | this.configService = configService; 137 | } 138 | 139 | 140 | public DiskService getDiskService() { 141 | return diskService; 142 | } 143 | 144 | 145 | public void setDiskService(DiskService diskService) { 146 | this.diskService = diskService; 147 | } 148 | 149 | 150 | /** 151 | * 查找真实的IP地址 152 | * 153 | * @param request 154 | * @return 155 | */ 156 | public String getRemortIP(HttpServletRequest request) { 157 | if (request.getHeader("x-forwarded-for") == null) { 158 | return request.getRemoteAddr(); 159 | } 160 | return request.getHeader("x-forwarded-for"); 161 | } 162 | 163 | 164 | public static List getConfigKeyList(String configKeysString) { 165 | List configKeyList = new LinkedList(); 166 | if (null == configKeysString || "".equals(configKeysString)) { 167 | return configKeyList; 168 | } 169 | String[] configKeyStrings = configKeysString.split(LINE_SEPARATOR); 170 | for (String configKeyString : configKeyStrings) { 171 | String[] configKey = configKeyString.split(WORD_SEPARATOR); 172 | if (configKey.length > 3) { 173 | continue; 174 | } 175 | ConfigKey key = new ConfigKey(); 176 | if ("".equals(configKey[0])) { 177 | continue; 178 | } 179 | key.setDataId(configKey[0]); 180 | if (configKey.length >= 2 && !"".equals(configKey[1])) { 181 | key.setGroup(configKey[1]); 182 | } 183 | if (configKey.length == 3 && !"".equals(configKey[2])) { 184 | key.setMd5(configKey[2]); 185 | } 186 | configKeyList.add(key); 187 | } 188 | 189 | return configKeyList; 190 | } 191 | 192 | public static class ConfigKey { 193 | private String dataId; 194 | private String group; 195 | private String md5; 196 | 197 | 198 | public String getDataId() { 199 | return dataId; 200 | } 201 | 202 | 203 | public void setDataId(String dataId) { 204 | this.dataId = dataId; 205 | } 206 | 207 | 208 | public String getGroup() { 209 | return group; 210 | } 211 | 212 | 213 | public void setGroup(String group) { 214 | this.group = group; 215 | } 216 | 217 | 218 | public String getMd5() { 219 | return md5; 220 | } 221 | 222 | 223 | public void setMd5(String md5) { 224 | this.md5 = md5; 225 | } 226 | 227 | 228 | @Override 229 | public String toString() { 230 | StringBuilder sb = new StringBuilder(); 231 | sb.append("DataID: ").append(dataId).append("\r\n"); 232 | sb.append("Group: ").append((null == group ? "" : group)).append("\r\n"); 233 | sb.append("MD5: ").append((null == md5 ? "" : md5)).append("\r\n"); 234 | return sb.toString(); 235 | } 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/controller/ConfigServlet.java: -------------------------------------------------------------------------------- 1 | package com.taobao.diamond.server.controller; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.RequestDispatcher; 6 | import javax.servlet.ServletException; 7 | import javax.servlet.http.HttpServlet; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | import org.springframework.util.StringUtils; 12 | import org.springframework.web.context.WebApplicationContext; 13 | import org.springframework.web.context.support.WebApplicationContextUtils; 14 | 15 | import com.taobao.diamond.common.Constants; 16 | import com.taobao.diamond.server.service.ConfigService; 17 | import com.taobao.diamond.server.service.DiskService; 18 | 19 | 20 | public class ConfigServlet extends HttpServlet { 21 | 22 | private static final long serialVersionUID = 4339468526746635388L; 23 | 24 | private ConfigController configController; 25 | 26 | 27 | @Override 28 | public void init() throws ServletException { 29 | 30 | super.init(); 31 | WebApplicationContext webApplicationContext = 32 | WebApplicationContextUtils.getWebApplicationContext(getServletContext()); 33 | configService = (ConfigService) webApplicationContext.getBean("configService"); 34 | this.diskService = (DiskService) webApplicationContext.getBean("diskService"); 35 | configController = new ConfigController(); 36 | this.configController.setConfigService(configService); 37 | this.configController.setDiskService(diskService); 38 | } 39 | 40 | private ConfigService configService; 41 | 42 | private DiskService diskService; 43 | 44 | 45 | /** 46 | * 查找真实的IP地址 47 | * 48 | * @param request 49 | * @return 50 | */ 51 | public String getRemortIP(HttpServletRequest request) { 52 | if (request.getHeader("x-forwarded-for") == null) { 53 | return request.getRemoteAddr(); 54 | } 55 | return request.getHeader("x-forwarded-for"); 56 | } 57 | 58 | 59 | public void forward(HttpServletRequest request, HttpServletResponse response, String page, String basePath, 60 | String postfix) throws IOException, ServletException { 61 | RequestDispatcher requestDispatcher = request.getRequestDispatcher(basePath + page + postfix); 62 | requestDispatcher.forward(request, response); 63 | } 64 | 65 | 66 | @Override 67 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, 68 | IOException { 69 | String probeModify = request.getParameter(Constants.PROBE_MODIFY_REQUEST); 70 | if (!StringUtils.hasLength(probeModify)) 71 | throw new IOException("无效的probeModify"); 72 | String page = this.configController.getProbeModifyResult(request, response, probeModify); 73 | forward(request, response, page, "/jsp/", ".jsp"); 74 | } 75 | 76 | 77 | @Override 78 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 79 | String group = request.getParameter("group"); 80 | String dataId = request.getParameter("dataId"); 81 | 82 | if (!StringUtils.hasLength(dataId)) { 83 | throw new IOException("无效的dataId"); 84 | } 85 | 86 | String page = this.configController.getConfig(request, response, dataId, group); 87 | if (page.startsWith("forward:")) { 88 | page = page.substring(8); 89 | forward(request, response, page, "", ""); 90 | } 91 | else { 92 | forward(request, response, page, "/jsp/", ".jsp"); 93 | } 94 | 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/controller/LoginController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.server.controller; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.stereotype.Controller; 16 | import org.springframework.ui.ModelMap; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RequestMethod; 19 | import org.springframework.web.bind.annotation.RequestParam; 20 | 21 | import com.taobao.diamond.server.service.AdminService; 22 | 23 | 24 | /** 25 | * 登录登出控制器 26 | * 27 | * @author boyan 28 | * @date 2010-5-6 29 | */ 30 | @Controller 31 | @RequestMapping("/login.do") 32 | public class LoginController { 33 | @Autowired 34 | private AdminService adminService; 35 | 36 | 37 | @RequestMapping(params = "method=login", method = RequestMethod.POST) 38 | public String login(HttpServletRequest request, @RequestParam("username") String username, 39 | @RequestParam("password") String password, ModelMap modelMap) { 40 | if (adminService.login(username, password)) { 41 | request.getSession().setAttribute("user", username); 42 | return "admin/admin"; 43 | } 44 | else { 45 | modelMap.addAttribute("message", "登录失败,用户名密码不匹配"); 46 | return "login"; 47 | } 48 | } 49 | 50 | 51 | public AdminService getAdminService() { 52 | return adminService; 53 | } 54 | 55 | 56 | public void setAdminService(AdminService adminService) { 57 | this.adminService = adminService; 58 | } 59 | 60 | 61 | @RequestMapping(params = "method=logout", method = RequestMethod.GET) 62 | public String logout(HttpServletRequest request) { 63 | request.getSession().invalidate(); 64 | return "login"; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/controller/NotifyController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.server.controller; 11 | 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.stereotype.Controller; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RequestMethod; 16 | import org.springframework.web.bind.annotation.RequestParam; 17 | 18 | import com.taobao.diamond.server.service.ConfigService; 19 | 20 | 21 | /** 22 | * 用于其他节点通知的控制器 23 | * 24 | * @author boyan 25 | * @date 2010-5-7 26 | */ 27 | @Controller 28 | @RequestMapping("/notify.do") 29 | public class NotifyController { 30 | 31 | @Autowired 32 | private ConfigService configService; 33 | 34 | 35 | public ConfigService getConfigService() { 36 | return configService; 37 | } 38 | 39 | 40 | public void setConfigService(ConfigService configService) { 41 | this.configService = configService; 42 | } 43 | 44 | 45 | /** 46 | * 通知配置信息改变 47 | * 48 | * @param id 49 | * @return 50 | */ 51 | @RequestMapping(method = RequestMethod.GET, params = "method=notifyConfigInfo") 52 | public String notifyConfigInfo(@RequestParam("dataId") String dataId, @RequestParam("group") String group) { 53 | dataId = dataId.trim(); 54 | group = group.trim(); 55 | this.configService.loadConfigInfoToDisk(dataId, group); 56 | return "200"; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/controller/ServerAddressController.java: -------------------------------------------------------------------------------- 1 | package com.taobao.diamond.server.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.ResponseBody; 7 | 8 | import javax.annotation.PostConstruct; 9 | 10 | /** 11 | * Created with IntelliJ IDEA. 12 | * User: gaozhenlong 13 | * Date: 17-5-18 14 | * Time: 10:58 p.m. 15 | * To change this template use File | Settings | File Templates. 16 | */ 17 | @Controller 18 | public class ServerAddressController { 19 | 20 | // @Value("${diamond.server.addr}") 21 | @Value("#{config['diamond.server.addr']}") 22 | private String diamondServerAddr; 23 | 24 | 25 | @PostConstruct 26 | public void init() { 27 | System.out.println("diamond.server.addr - " + diamondServerAddr); 28 | } 29 | 30 | 31 | @RequestMapping("url") 32 | @ResponseBody 33 | public String url() { 34 | // return "127.0.0.1"; 35 | return diamondServerAddr; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/exception/ConfigServiceException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.server.exception; 11 | 12 | /** 13 | * Service层的任何异常都包装成这个Runtime异常抛出 14 | * 15 | * @author boyan 16 | * @date 2010-5-5 17 | */ 18 | public class ConfigServiceException extends RuntimeException { 19 | static final long serialVersionUID = -1L; 20 | 21 | 22 | public ConfigServiceException() { 23 | super(); 24 | 25 | } 26 | 27 | 28 | public ConfigServiceException(String message, Throwable cause) { 29 | super(message, cause); 30 | 31 | } 32 | 33 | 34 | public ConfigServiceException(String message) { 35 | super(message); 36 | 37 | } 38 | 39 | 40 | public ConfigServiceException(Throwable cause) { 41 | super(cause); 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/listener/AuthorizationFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.server.listener; 11 | 12 | import java.io.IOException; 13 | 14 | import javax.servlet.Filter; 15 | import javax.servlet.FilterChain; 16 | import javax.servlet.FilterConfig; 17 | import javax.servlet.ServletException; 18 | import javax.servlet.ServletRequest; 19 | import javax.servlet.ServletResponse; 20 | import javax.servlet.http.HttpServletRequest; 21 | import javax.servlet.http.HttpServletResponse; 22 | import javax.servlet.http.HttpSession; 23 | 24 | import com.taobao.diamond.server.utils.SessionHolder; 25 | 26 | 27 | /** 28 | * 授权验证 29 | * 30 | * @author boyan 31 | * @date 2010-5-5 32 | */ 33 | public class AuthorizationFilter implements Filter { 34 | 35 | public void destroy() { 36 | 37 | } 38 | 39 | 40 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, 41 | ServletException { 42 | HttpServletRequest httpRequest = (HttpServletRequest) request; 43 | HttpSession session = httpRequest.getSession(); 44 | SessionHolder.setSession(session); 45 | try { 46 | // 判断是否登录,没有就跳转到登录页面 47 | if (session.getAttribute("user") == null) 48 | ((HttpServletResponse) response).sendRedirect(httpRequest.getContextPath() + "/jsp/login.jsp"); 49 | else 50 | chain.doFilter(httpRequest, response); 51 | } 52 | finally { 53 | SessionHolder.invalidate(); 54 | } 55 | } 56 | 57 | 58 | public void init(FilterConfig filterConfig) throws ServletException { 59 | 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/service/AdminService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.server.service; 11 | 12 | import java.io.FileInputStream; 13 | import java.io.FileOutputStream; 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.net.URL; 17 | import java.util.Enumeration; 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | import java.util.Properties; 21 | 22 | import org.apache.commons.logging.Log; 23 | import org.apache.commons.logging.LogFactory; 24 | import org.springframework.stereotype.Service; 25 | 26 | import com.taobao.diamond.utils.ResourceUtils; 27 | 28 | 29 | /** 30 | * 管理服务 31 | * 32 | * @author boyan 33 | * @date 2010-5-5 34 | */ 35 | @Service 36 | public class AdminService { 37 | 38 | private static final Log log = LogFactory.getLog(AdminService.class); 39 | 40 | private volatile Properties properties = new Properties(); 41 | 42 | /** 43 | * user.properties的路径url 44 | */ 45 | private URL url; 46 | 47 | 48 | public URL getUrl() { 49 | return url; 50 | } 51 | 52 | 53 | public AdminService() { 54 | loadUsers(); 55 | } 56 | 57 | 58 | public void loadUsers() { 59 | Properties tempProperties = new Properties(); 60 | InputStream in = null; 61 | try { 62 | url = ResourceUtils.getResourceURL("user.properties"); 63 | in = new FileInputStream(url.getPath()); 64 | tempProperties.load(in); 65 | } 66 | catch (IOException e) { 67 | log.error("加载user.properties文件失败", e); 68 | } 69 | finally { 70 | if (in != null) { 71 | try { 72 | in.close(); 73 | } 74 | catch (IOException e) { 75 | log.error("关闭user.properties文件失败", e); 76 | } 77 | } 78 | } 79 | this.properties = tempProperties; 80 | } 81 | 82 | 83 | public synchronized boolean login(String userName, String password) { 84 | String passwordInFile = this.properties.getProperty(userName); 85 | if (passwordInFile != null) 86 | return passwordInFile.equals(password); 87 | else 88 | return false; 89 | } 90 | 91 | 92 | public synchronized boolean addUser(String userName, String password) { 93 | if (this.properties.containsKey(userName)) 94 | return false; 95 | this.properties.put(userName, password); 96 | return saveToDisk(); 97 | 98 | } 99 | 100 | 101 | private boolean saveToDisk() { 102 | FileOutputStream out = null; 103 | try { 104 | out = new FileOutputStream(url.getPath()); 105 | this.properties.store(out, "add user"); 106 | out.flush(); 107 | return true; 108 | } 109 | catch (IOException e) { 110 | log.error("保存user.properties文件失败", e); 111 | return false; 112 | } 113 | finally { 114 | if (out != null) { 115 | try { 116 | out.close(); 117 | } 118 | catch (IOException e) { 119 | log.error("关闭user.properties文件失败", e); 120 | } 121 | } 122 | } 123 | } 124 | 125 | 126 | public synchronized Map getAllUsers() { 127 | Map result = new HashMap(); 128 | Enumeration enu = this.properties.keys(); 129 | while (enu.hasMoreElements()) { 130 | String address = (String) enu.nextElement(); 131 | String group = this.properties.getProperty(address); 132 | result.put(address, group); 133 | } 134 | return result; 135 | } 136 | 137 | 138 | public synchronized boolean updatePassword(String userName, String newPassword) { 139 | if (!this.properties.containsKey(userName)) 140 | return false; 141 | this.properties.put(userName, newPassword); 142 | return saveToDisk(); 143 | } 144 | 145 | 146 | public synchronized boolean removeUser(String userName) { 147 | if (this.properties.size() == 1) 148 | return false; 149 | if (!this.properties.containsKey(userName)) 150 | return false; 151 | this.properties.remove(userName); 152 | return saveToDisk(); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/service/DiskService.java: -------------------------------------------------------------------------------- 1 | package com.taobao.diamond.server.service; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | import javax.servlet.ServletContext; 9 | 10 | import org.apache.commons.io.FileUtils; 11 | import org.apache.commons.logging.Log; 12 | import org.apache.commons.logging.LogFactory; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.web.util.WebUtils; 16 | 17 | import com.taobao.diamond.common.Constants; 18 | import com.taobao.diamond.domain.ConfigInfo; 19 | import com.taobao.diamond.server.exception.ConfigServiceException; 20 | 21 | 22 | /** 23 | * 磁盘操作服务 24 | * 25 | * @author boyan 26 | * @date 2010-5-4 27 | */ 28 | @Service 29 | public class DiskService { 30 | 31 | private static final Log log = LogFactory.getLog(DiskService.class); 32 | 33 | /** 34 | * 修改标记缓存 35 | */ 36 | private final ConcurrentHashMap modifyMarkCache = 37 | new ConcurrentHashMap(); 38 | 39 | @Autowired 40 | private ServletContext servletContext; 41 | 42 | 43 | public void setServletContext(ServletContext servletContext) { 44 | this.servletContext = servletContext; 45 | } 46 | 47 | 48 | public ServletContext getServletContext() { 49 | return this.servletContext; 50 | } 51 | 52 | 53 | /** 54 | * 单元测试用 55 | * 56 | * @return 57 | */ 58 | public ConcurrentHashMap getModifyMarkCache() { 59 | return this.modifyMarkCache; 60 | } 61 | 62 | 63 | /** 64 | * 获取配置文件路径, 单元测试用 65 | * 66 | * @param dataId 67 | * @param group 68 | * @return 69 | * @throws FileNotFoundException 70 | */ 71 | public String getFilePath(String dataId, String group) throws FileNotFoundException { 72 | return getFilePath(Constants.BASE_DIR + "/" + group + "/" + dataId); 73 | } 74 | 75 | 76 | public void saveToDisk(ConfigInfo configInfo) { 77 | String group = configInfo.getGroup(); 78 | String dataId = configInfo.getDataId(); 79 | String content = configInfo.getContent(); 80 | String cacheKey = generateCacheKey(group, dataId); 81 | // 标记正在写磁盘 82 | if (this.modifyMarkCache.putIfAbsent(cacheKey, true) == null) { 83 | File tempFile = null; 84 | try { 85 | // 目标目录 86 | String groupPath = getFilePath(Constants.BASE_DIR + "/" + group); 87 | createDirIfNessary(groupPath); 88 | // 目标文件 89 | File targetFile = createFileIfNessary(groupPath, dataId); 90 | // 创建临时文件 91 | tempFile = createTempFile(dataId, group); 92 | // 写数据至临时文件 93 | FileUtils.writeStringToFile(tempFile, content, Constants.ENCODE); 94 | // 用临时文件覆盖目标文件, 完成本次磁盘操作 95 | FileUtils.copyFile(tempFile, targetFile); 96 | } 97 | catch (Exception e) { 98 | String errorMsg = "save disk error, dataId=" + dataId + ",group=" + group; 99 | log.error(errorMsg, e); 100 | throw new ConfigServiceException(errorMsg, e); 101 | } 102 | finally { 103 | // 删除临时文件 104 | if (tempFile != null && tempFile.exists()) { 105 | FileUtils.deleteQuietly(tempFile); 106 | } 107 | // 清除标记 108 | this.modifyMarkCache.remove(cacheKey); 109 | } 110 | } 111 | else { 112 | throw new ConfigServiceException("config info is being motified, dataId=" + dataId + ",group=" + group); 113 | } 114 | 115 | } 116 | 117 | 118 | public boolean isModified(String dataId, String group) { 119 | return this.modifyMarkCache.get(generateCacheKey(group, dataId)) != null; 120 | } 121 | 122 | 123 | /** 124 | * 生成缓存key,用于标记文件是否正在被修改 125 | * 126 | * @param group 127 | * @param dataId 128 | * 129 | * @return 130 | */ 131 | public final String generateCacheKey(String group, String dataId) { 132 | return group + "/" + dataId; 133 | } 134 | 135 | 136 | public void removeConfigInfo(String dataId, String group) { 137 | String cacheKey = generateCacheKey(group, dataId); 138 | // 标记正在写磁盘 139 | if (this.modifyMarkCache.putIfAbsent(cacheKey, true) == null) { 140 | try { 141 | String basePath = getFilePath(Constants.BASE_DIR); 142 | createDirIfNessary(basePath); 143 | 144 | String groupPath = getFilePath(Constants.BASE_DIR + "/" + group); 145 | File groupDir = new File(groupPath); 146 | if (!groupDir.exists()) { 147 | return; 148 | } 149 | 150 | String dataPath = getFilePath(Constants.BASE_DIR + "/" + group + "/" + dataId); 151 | File dataFile = new File(dataPath); 152 | if (!dataFile.exists()) { 153 | return; 154 | } 155 | 156 | FileUtils.deleteQuietly(dataFile); 157 | } 158 | catch (Exception e) { 159 | String errorMsg = "delete config info error, dataId=" + dataId + ",group=" + group; 160 | log.error(errorMsg, e); 161 | throw new ConfigServiceException(errorMsg, e); 162 | } 163 | finally { 164 | // 清除标记 165 | this.modifyMarkCache.remove(cacheKey); 166 | } 167 | } 168 | else { 169 | throw new ConfigServiceException("config info is being motified, dataId=" + dataId + ",group=" + group); 170 | } 171 | } 172 | 173 | 174 | private String getFilePath(String dir) throws FileNotFoundException { 175 | return WebUtils.getRealPath(servletContext, dir); 176 | } 177 | 178 | 179 | private void createDirIfNessary(String path) { 180 | final File dir = new File(path); 181 | if (!dir.exists()) { 182 | dir.mkdirs(); 183 | } 184 | } 185 | 186 | 187 | private File createFileIfNessary(String parent, String child) throws IOException { 188 | final File file = new File(parent, child); 189 | if (!file.exists()) { 190 | file.createNewFile(); 191 | // 设置文件权限 192 | changeFilePermission(file); 193 | } 194 | return file; 195 | } 196 | 197 | 198 | private void changeFilePermission(File file) { 199 | // 文件权限设置为600 200 | file.setExecutable(false, false); 201 | file.setWritable(false, false); 202 | file.setReadable(false, false); 203 | file.setExecutable(false, true); 204 | file.setWritable(true, true); 205 | file.setReadable(true, true); 206 | } 207 | 208 | 209 | private File createTempFile(String dataId, String group) throws IOException { 210 | return File.createTempFile(group + "-" + dataId, ".tmp"); 211 | } 212 | 213 | } 214 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/service/DumpConfigInfoTask.java: -------------------------------------------------------------------------------- 1 | package com.taobao.diamond.server.service; 2 | 3 | import java.io.IOException; 4 | 5 | import org.apache.commons.logging.Log; 6 | import org.apache.commons.logging.LogFactory; 7 | 8 | import com.taobao.diamond.domain.ConfigInfo; 9 | import com.taobao.diamond.domain.Page; 10 | 11 | 12 | /** 13 | * Dump配置信息任务 14 | * 15 | * @author boyan 16 | * @date 2010-5-10 17 | */ 18 | public final class DumpConfigInfoTask implements Runnable { 19 | 20 | private static final Log log = LogFactory.getLog(DumpConfigInfoTask.class); 21 | 22 | private static final int PAGE_SIZE = 1000; 23 | 24 | private final TimerTaskService timerTaskService; 25 | 26 | 27 | public DumpConfigInfoTask(TimerTaskService timerTaskService) { 28 | this.timerTaskService = timerTaskService; 29 | } 30 | 31 | 32 | public void run() { 33 | try { 34 | Page page = this.timerTaskService.getPersistService().findAllConfigInfo(1, PAGE_SIZE); 35 | if (page != null) { 36 | // 总页数 37 | int totalPages = page.getPagesAvailable(); 38 | updateConfigInfo(page); 39 | if (totalPages > 1) { 40 | for (int pageNo = 2; pageNo <= totalPages; pageNo++) { 41 | page = this.timerTaskService.getPersistService().findAllConfigInfo(pageNo, PAGE_SIZE); 42 | if (page != null) { 43 | updateConfigInfo(page); 44 | } 45 | } 46 | } 47 | } 48 | } 49 | catch (Throwable t) { 50 | log.error("dump task run error", t); 51 | } 52 | } 53 | 54 | 55 | private void updateConfigInfo(Page page) throws IOException { 56 | for (ConfigInfo configInfo : page.getPageItems()) { 57 | if (configInfo == null) { 58 | continue; 59 | } 60 | try { 61 | // 写入磁盘,更新缓存 62 | this.timerTaskService.getConfigService().updateMD5Cache(configInfo); 63 | this.timerTaskService.getDiskService().saveToDisk(configInfo); 64 | } 65 | catch (Throwable t) { 66 | log.error( 67 | "dump config info error, dataId=" + configInfo.getDataId() + ", group=" + configInfo.getGroup(), t); 68 | } 69 | 70 | } 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/service/NotifyService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.server.service; 11 | 12 | import java.io.BufferedReader; 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.io.InputStreamReader; 16 | import java.net.HttpURLConnection; 17 | import java.net.URL; 18 | import java.util.Enumeration; 19 | import java.util.Properties; 20 | 21 | import javax.annotation.PostConstruct; 22 | 23 | import org.apache.commons.logging.Log; 24 | import org.apache.commons.logging.LogFactory; 25 | import org.springframework.stereotype.Service; 26 | import org.springframework.util.StringUtils; 27 | 28 | import com.taobao.diamond.server.utils.SystemConfig; 29 | import com.taobao.diamond.utils.ResourceUtils; 30 | 31 | 32 | /** 33 | * 通知服务,用于通知其他节点 34 | * 35 | * @author boyan 36 | * @date 2010-5-6 37 | */ 38 | @Service 39 | public class NotifyService { 40 | private static final int TIMEOUT = 5000; 41 | 42 | private final String URL_PREFIX = "/diamond-server/notify.do"; 43 | 44 | private final String PROTOCOL = "http://"; 45 | 46 | private final Properties nodeProperties = new Properties(); 47 | 48 | static final Log log = LogFactory.getLog(NotifyService.class); 49 | 50 | 51 | Properties getNodeProperties() { 52 | return this.nodeProperties; 53 | } 54 | 55 | 56 | @PostConstruct 57 | public void loadNodes() { 58 | InputStream in = null; 59 | try { 60 | in = ResourceUtils.getResourceAsStream("node.properties"); 61 | nodeProperties.load(in); 62 | } 63 | catch (IOException e) { 64 | log.error("加载节点配置文件失败"); 65 | } 66 | finally { 67 | try { 68 | if (in != null) 69 | in.close(); 70 | } 71 | catch (IOException e) { 72 | log.error("关闭node.properties失败", e); 73 | } 74 | } 75 | log.info("节点列表:" + nodeProperties); 76 | } 77 | 78 | 79 | /** 80 | * 通知配置信息改变 81 | * 82 | * @param id 83 | */ 84 | public void notifyConfigInfoChange(String dataId, String group) { 85 | Enumeration enu = nodeProperties.propertyNames(); 86 | while (enu.hasMoreElements()) { 87 | String address = (String) enu.nextElement(); 88 | if (address.contains(SystemConfig.LOCAL_IP)) { 89 | continue; 90 | } 91 | String urlString = generateNotifyConfigInfoPath(dataId, group, address); 92 | final String result = invokeURL(urlString); 93 | log.info("通知节点" + address + "分组信息改变:" + result); 94 | } 95 | } 96 | 97 | 98 | String generateNotifyConfigInfoPath(String dataId, String group, String address) { 99 | String specialUrl = this.nodeProperties.getProperty(address); 100 | String urlString = PROTOCOL + address + URL_PREFIX; 101 | // 如果有指定url,使用指定的url 102 | if (specialUrl != null && StringUtils.hasLength(specialUrl.trim())) { 103 | urlString = specialUrl; 104 | } 105 | urlString += "?method=notifyConfigInfo&dataId=" + dataId + "&group=" + group; 106 | return urlString; 107 | } 108 | 109 | 110 | /** 111 | * http get调用 112 | * 113 | * @param urlString 114 | * @return 115 | */ 116 | private String invokeURL(String urlString) { 117 | HttpURLConnection conn = null; 118 | URL url = null; 119 | try { 120 | url = new URL(urlString); 121 | conn = (HttpURLConnection) url.openConnection(); 122 | conn.setConnectTimeout(TIMEOUT); 123 | conn.setReadTimeout(TIMEOUT); 124 | conn.setRequestMethod("GET"); 125 | conn.connect(); 126 | InputStream urlStream = conn.getInputStream(); 127 | StringBuilder sb = new StringBuilder(); 128 | BufferedReader reader = null; 129 | try { 130 | reader = new BufferedReader(new InputStreamReader(urlStream)); 131 | String line = null; 132 | while ((line = reader.readLine()) != null) { 133 | sb.append(line); 134 | } 135 | } 136 | finally { 137 | if (reader != null) 138 | reader.close(); 139 | } 140 | return sb.toString(); 141 | 142 | } 143 | catch (Exception e) { 144 | log.error("http调用失败,url=" + urlString, e); 145 | } 146 | finally { 147 | if (conn != null) { 148 | conn.disconnect(); 149 | } 150 | } 151 | return "error"; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/service/TimerTaskService.java: -------------------------------------------------------------------------------- 1 | package com.taobao.diamond.server.service; 2 | 3 | import java.util.concurrent.Executors; 4 | import java.util.concurrent.ScheduledExecutorService; 5 | import java.util.concurrent.ThreadFactory; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import javax.annotation.PostConstruct; 9 | import javax.annotation.PreDestroy; 10 | 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Service; 13 | 14 | import com.taobao.diamond.server.utils.SystemConfig; 15 | 16 | 17 | /** 18 | * 定时任务服务 19 | * 20 | * @author boyan 21 | */ 22 | @Service 23 | public class TimerTaskService { 24 | 25 | private static final String THREAD_NAME = "diamond dump config thread"; 26 | 27 | @Autowired 28 | private PersistService persistService; 29 | 30 | @Autowired 31 | private DiskService diskService; 32 | 33 | @Autowired 34 | private ConfigService configService; 35 | 36 | private ScheduledExecutorService scheduledExecutorService; 37 | 38 | 39 | @PostConstruct 40 | public void init() { 41 | this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { 42 | 43 | public Thread newThread(Runnable r) { 44 | Thread t = new Thread(r); 45 | t.setName(THREAD_NAME); 46 | t.setDaemon(true); 47 | return t; 48 | } 49 | 50 | }); 51 | 52 | DumpConfigInfoTask dumpTask = new DumpConfigInfoTask(this); 53 | dumpTask.run(); 54 | this.scheduledExecutorService.scheduleWithFixedDelay(dumpTask, SystemConfig.getDumpConfigInterval(), 55 | SystemConfig.getDumpConfigInterval(), TimeUnit.SECONDS); 56 | } 57 | 58 | 59 | @PreDestroy 60 | public void dispose() { 61 | if (this.scheduledExecutorService != null) { 62 | this.scheduledExecutorService.shutdown(); 63 | } 64 | } 65 | 66 | 67 | public void setPersistService(PersistService persistService) { 68 | this.persistService = persistService; 69 | } 70 | 71 | 72 | public PersistService getPersistService() { 73 | return persistService; 74 | } 75 | 76 | 77 | public void setDiskService(DiskService diskService) { 78 | this.diskService = diskService; 79 | } 80 | 81 | 82 | public ConfigService getConfigService() { 83 | return configService; 84 | } 85 | 86 | 87 | public void setConfigService(ConfigService configService) { 88 | this.configService = configService; 89 | } 90 | 91 | 92 | public DiskService getDiskService() { 93 | return diskService; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/utils/DiamondUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.server.utils; 11 | 12 | import java.sql.Timestamp; 13 | import java.util.Date; 14 | 15 | 16 | public class DiamondUtils { 17 | static final char[] INVALID_CHAR = { ';', '&', '%', '#', '$', '@', ',', '*', '^', '~', '(', ')', '/', '\\', '|', 18 | '+' }; 19 | 20 | 21 | /** 22 | * 判断字符串是否有空格 23 | * 24 | * @param str 25 | * @return 26 | */ 27 | public static boolean hasInvalidChar(String str) { 28 | if (str == null || str.length() == 0) 29 | return true; 30 | int strLen = str.length(); 31 | for (int i = 0; i < strLen; i++) { 32 | char ch = str.charAt(i); 33 | if (Character.isWhitespace(ch) || isInvalidChar(ch)) { 34 | return true; 35 | } 36 | } 37 | return false; 38 | } 39 | 40 | 41 | public static boolean isInvalidChar(char ch) { 42 | for (char c : INVALID_CHAR) { 43 | if (c == ch) 44 | return true; 45 | } 46 | return false; 47 | } 48 | 49 | 50 | public static Timestamp getCurrentTime() { 51 | Date date = new Date(); 52 | return new Timestamp(date.getTime()); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/utils/GlobalCounter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.server.utils; 11 | 12 | /** 13 | * 全局计数器 14 | * 15 | * @author boyan 16 | * @date 2010-5-31 17 | */ 18 | public class GlobalCounter { 19 | private static GlobalCounter instance = new GlobalCounter(); 20 | 21 | private long count = 0; 22 | 23 | 24 | public static GlobalCounter getCounter() { 25 | return instance; 26 | } 27 | 28 | 29 | public synchronized long decrementAndGet() { 30 | if (count == Long.MIN_VALUE) { 31 | count = 0; 32 | } 33 | else 34 | count--; 35 | return count; 36 | } 37 | 38 | 39 | public synchronized long get() { 40 | return this.count; 41 | } 42 | 43 | 44 | public synchronized void set(long value) { 45 | this.count = value; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/utils/PaginationHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.server.utils; 11 | 12 | import java.sql.ResultSet; 13 | import java.sql.SQLException; 14 | import java.util.List; 15 | 16 | import org.springframework.dao.DataAccessException; 17 | import org.springframework.jdbc.core.JdbcTemplate; 18 | import org.springframework.jdbc.core.ResultSetExtractor; 19 | import org.springframework.jdbc.core.simple.ParameterizedRowMapper; 20 | 21 | import com.taobao.diamond.domain.Page; 22 | 23 | 24 | /** 25 | * 分页辅助类 26 | * 27 | * @author boyan 28 | * @date 2010-5-6 29 | * @param 30 | */ 31 | public class PaginationHelper { 32 | 33 | /** 34 | * 取分页 35 | * 36 | * @param jt 37 | * jdbcTemplate 38 | * @param sqlCountRows 39 | * 查询总数的SQL 40 | * @param sqlFetchRows 41 | * 查询数据的sql 42 | * @param args 43 | * 查询参数 44 | * @param pageNo 45 | * 页数 46 | * @param pageSize 47 | * 每页大小 48 | * @param rowMapper 49 | * @return 50 | */ 51 | public Page fetchPage(final JdbcTemplate jt, final String sqlCountRows, final String sqlFetchRows, 52 | final Object args[], final int pageNo, final int pageSize, final ParameterizedRowMapper rowMapper) { 53 | if (pageSize == 0) { 54 | return null; 55 | } 56 | 57 | // 查询当前记录总数 58 | final int rowCount = jt.queryForInt(sqlCountRows, args); 59 | 60 | // 计算页数 61 | int pageCount = rowCount / pageSize; 62 | if (rowCount > pageSize * pageCount) { 63 | pageCount++; 64 | } 65 | 66 | // 创建Page对象 67 | final Page page = new Page(); 68 | page.setPageNumber(pageNo); 69 | page.setPagesAvailable(pageCount); 70 | page.setTotalCount(rowCount); 71 | 72 | if (pageNo > pageCount) 73 | return null; 74 | // 取单页数据,计算起始位置 75 | final int startRow = (pageNo - 1) * pageSize; 76 | // TODO 在数据量很大时, limit效率很低 77 | final String selectSQL = sqlFetchRows + " limit " + startRow + "," + pageSize; 78 | jt.query(selectSQL, args, new ResultSetExtractor() { 79 | public Object extractData(ResultSet rs) throws SQLException, DataAccessException { 80 | final List pageItems = page.getPageItems(); 81 | int currentRow = 0; 82 | while (rs.next()) { 83 | pageItems.add(rowMapper.mapRow(rs, currentRow++)); 84 | } 85 | return page; 86 | } 87 | }); 88 | return page; 89 | } 90 | 91 | } -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/utils/SessionHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.server.utils; 11 | 12 | import javax.servlet.http.HttpSession; 13 | 14 | 15 | /** 16 | * 通过ThreadLocal传递HttpSession 17 | * 18 | * @author boyan 19 | * @date 2010-5-26 20 | */ 21 | public class SessionHolder { 22 | private static ThreadLocal sessionThreadLocal = new ThreadLocal() { 23 | 24 | @Override 25 | protected HttpSession initialValue() { 26 | return null; 27 | } 28 | 29 | }; 30 | 31 | 32 | public static void invalidate() { 33 | sessionThreadLocal.remove(); 34 | } 35 | 36 | 37 | public static void setSession(HttpSession session) { 38 | sessionThreadLocal.set(session); 39 | } 40 | 41 | 42 | public static HttpSession getSession() { 43 | return sessionThreadLocal.get(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /diamond-server/src/main/java/com/taobao/diamond/server/utils/SystemConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.server.utils; 11 | 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.net.InetAddress; 15 | import java.net.NetworkInterface; 16 | import java.util.Enumeration; 17 | import java.util.Properties; 18 | 19 | import org.apache.commons.logging.Log; 20 | import org.apache.commons.logging.LogFactory; 21 | 22 | import com.taobao.diamond.utils.ResourceUtils; 23 | 24 | 25 | public class SystemConfig { 26 | 27 | private static final Log log = LogFactory.getLog(SystemConfig.class); 28 | 29 | /** 30 | * Dump配置信息的时间间隔,默认10分钟 31 | */ 32 | private static int dumpConfigInterval = 600; 33 | 34 | public static final String LOCAL_IP = getHostAddress(); 35 | 36 | static { 37 | InputStream in = null; 38 | try { 39 | in = ResourceUtils.getResourceAsStream("system.properties"); 40 | Properties props = new Properties(); 41 | props.load(in); 42 | dumpConfigInterval = Integer.parseInt(props.getProperty("dump_config_interval", "600")); 43 | } 44 | catch (IOException e) { 45 | log.error("加载system.properties出错", e); 46 | } 47 | finally { 48 | if (in != null) { 49 | try { 50 | in.close(); 51 | } 52 | catch (IOException e) { 53 | log.error("关闭system.properties出错", e); 54 | } 55 | } 56 | } 57 | } 58 | 59 | 60 | public SystemConfig() { 61 | 62 | } 63 | 64 | 65 | public static int getDumpConfigInterval() { 66 | return dumpConfigInterval; 67 | } 68 | 69 | 70 | private static String getHostAddress() { 71 | String address = "127.0.0.1"; 72 | try { 73 | Enumeration en = NetworkInterface.getNetworkInterfaces(); 74 | while (en.hasMoreElements()) { 75 | NetworkInterface ni = en.nextElement(); 76 | Enumeration ads = ni.getInetAddresses(); 77 | while (ads.hasMoreElements()) { 78 | InetAddress ip = ads.nextElement(); 79 | if (!ip.isLoopbackAddress() && ip.isSiteLocalAddress()) { 80 | return ip.getHostAddress(); 81 | } 82 | } 83 | } 84 | } 85 | catch (Exception e) { 86 | } 87 | return address; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /diamond-server/src/main/resources/jdbc.properties: -------------------------------------------------------------------------------- 1 | db.url=jdbc:mysql://localhost:3306/diamond?characterEncoding=utf8&connectTimeout=1000&autoReconnect=true 2 | db.user=root 3 | db.password= 4 | db.initialSize=10 5 | db.maxActive=10 6 | db.maxIdle=5 7 | db.maxWait=5 8 | db.poolPreparedStatements=true -------------------------------------------------------------------------------- /diamond-server/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=info, ServerDailyRollingFile 2 | log4j.appender.ServerDailyRollingFile=org.apache.log4j.DailyRollingFileAppender 3 | log4j.appender.ServerDailyRollingFile.DatePattern='.'yyyy-MM-dd_HH 4 | log4j.appender.ServerDailyRollingFile.File=${webapp.root}/WEB-INF/logs/diamondServer.log 5 | log4j.appender.ServerDailyRollingFile.layout=org.apache.log4j.PatternLayout 6 | log4j.appender.ServerDailyRollingFile.layout.ConversionPattern=%d %-5p %c{2} - %m%n 7 | log4j.appender.ServerDailyRollingFile.Append=true -------------------------------------------------------------------------------- /diamond-server/src/main/resources/node.properties: -------------------------------------------------------------------------------- 1 | #ip\:port= -------------------------------------------------------------------------------- /diamond-server/src/main/resources/system.properties: -------------------------------------------------------------------------------- 1 | dump_config_interval=600 2 | diamond.server.addr=127.0.0.1 -------------------------------------------------------------------------------- /diamond-server/src/main/resources/user.properties: -------------------------------------------------------------------------------- 1 | abc=123 2 | -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Class-Path: 3 | 4 | -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/WEB-INF/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 14 | 15 | 17 | 19 | 20 | 22 | 23 | 24 | 26 | 27 | 28 | classpath:system.properties 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/WEB-INF/diamond-servlet.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | webAppRootKey 9 | webapp.root 10 | 11 | 12 | log4jConfigLocation 13 | classpath:/log4j.properties 14 | 15 | 16 | log4jRefreshInterval 17 | 60000 18 | 19 | 20 | 21 | org.springframework.web.util.Log4jConfigListener 22 | 23 | 24 | 25 | org.springframework.web.context.ContextLoaderListener 26 | 27 | 28 | 29 | 30 | encodingFilter 31 | org.springframework.web.filter.CharacterEncodingFilter 32 | 33 | encoding 34 | utf-8 35 | 36 | 37 | 38 | 39 | authorizationFilter 40 | com.taobao.diamond.server.listener.AuthorizationFilter 41 | 42 | 43 | 44 | encodingFilter 45 | *.do 46 | 47 | 48 | 49 | authorizationFilter 50 | /jsp/admin/* 51 | 52 | 53 | 54 | authorizationFilter 55 | /admin.do 56 | 57 | 58 | 59 | diamond 60 | org.springframework.web.servlet.DispatcherServlet 61 | 1 62 | 63 | 64 | 65 | ConfigServlet 66 | com.taobao.diamond.server.controller.ConfigServlet 67 | -1 68 | 69 | 70 | 71 | diamond 72 | *.do 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | ConfigServlet 84 | /config.co 85 | 86 | 87 | 88 | /jsp/login.jsp 89 | 90 | 91 | 92 | 500 93 | /jsp/500.jsp 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/js/fabtabulous.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Fabtabulous! Simple tabs using Prototype 3 | * http://tetlaw.id.au/view/blog/fabtabulous-simple-tabs-using-prototype/ 4 | * Andrew Tetlaw 5 | * version 1.1 2006-05-06 6 | * http://creativecommons.org/licenses/by-sa/2.5/ 7 | */ 8 | var Fabtabs = Class.create(); 9 | 10 | Fabtabs.prototype = { 11 | initialize : function(element) { 12 | this.element = $(element); 13 | var options = Object.extend({}, arguments[1] || {}); 14 | this.menu = $A(this.element.getElementsByTagName('a')); 15 | this.show(this.getInitialTab()); 16 | this.menu.each(this.setupTab.bind(this)); 17 | }, 18 | setupTab : function(elm) { 19 | Event.observe(elm,'click',this.activate.bindAsEventListener(this),false) 20 | }, 21 | activate : function(ev) { 22 | var elm = Event.findElement(ev, "a"); 23 | //Event.stop(ev); 24 | this.show(elm); 25 | this.menu.without(elm).each(this.hide.bind(this)); 26 | }, 27 | hide : function(elm) { 28 | $(elm).removeClassName('active-tab'); 29 | $(this.tabID(elm)).removeClassName('active-tab-body'); 30 | }, 31 | show : function(elm) { 32 | $(elm).addClassName('active-tab'); 33 | $(this.tabID(elm)).addClassName('active-tab-body'); 34 | 35 | }, 36 | tabID : function(elm) { 37 | elm.href.match(/#(\w.+)/); 38 | return RegExp.$1; 39 | }, 40 | getInitialTab : function() { 41 | if(document.location.href.match(/#(\w.+)/)) { 42 | var loc = RegExp.$1; 43 | var elm = this.menu.find(function(value) { value.href.match(/#(\w.+)/); return RegExp.$1 == loc; }); 44 | return elm || this.menu.first(); 45 | } else { 46 | return this.menu.first(); 47 | } 48 | } 49 | } 50 | 51 | Event.observe(window,'load',function(){ new Fabtabs('tabs'); },false); 52 | -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/js/tooltips.js: -------------------------------------------------------------------------------- 1 | //compatible with prototype 2 | if(typeof Prototype != 'undefined' && (typeof $ != 'undefined')) { 3 | $prototype = $; 4 | } 5 | 6 | 7 | // Tooltip Object 8 | var Tooltip = Class.create(); 9 | Tooltip.prototype = { 10 | initialize: function(el, options) { 11 | this.el = $prototype(el); 12 | this.initialized = false; 13 | this.setOptions(options); 14 | 15 | // Event handlers 16 | this.showEvent = this.show.bindAsEventListener(this); 17 | this.hideEvent = this.hide.bindAsEventListener(this); 18 | this.updateEvent = this.update.bindAsEventListener(this); 19 | Event.observe(this.el, "mouseover", this.showEvent ); 20 | Event.observe(this.el, "mouseout", this.hideEvent ); 21 | 22 | // Removing title from DOM element to avoid showing it 23 | this.content = this.el.title; 24 | this.el.title = ""; 25 | 26 | // If descendant elements has 'alt' attribute defined, clear it 27 | this.el.descendants().each(function(el){ 28 | if(Element.readAttribute(el, 'alt')) 29 | el.alt = ""; 30 | }); 31 | }, 32 | setOptions: function(options) { 33 | this.options = { 34 | backgroundColor: '#999', // Default background color 35 | borderColor: '#666', // Default border color 36 | textColor: '', // Default text color (use CSS value) 37 | textShadowColor: '', // Default text shadow color (use CSS value) 38 | maxWidth: 250, // Default tooltip width 39 | align: "left", // Default align 40 | delay: 250, // Default delay before tooltip appears in ms 41 | mouseFollow: true, // Tooltips follows the mouse moving 42 | opacity: .75, // Default tooltips opacity 43 | appearDuration: .25, // Default appear duration in sec 44 | hideDuration: .25 // Default disappear duration in sec 45 | }; 46 | Object.extend(this.options, options || {}); 47 | }, 48 | show: function(e) { 49 | this.xCord = Event.pointerX(e); 50 | this.yCord = Event.pointerY(e); 51 | if(!this.initialized) 52 | this.timeout = window.setTimeout(this.appear.bind(this), this.options.delay); 53 | }, 54 | hide: function(e) { 55 | if(this.initialized) { 56 | //this.appearingFX.cancel(); 57 | if(this.options.mouseFollow) 58 | Event.stopObserving(this.el, "mousemove", this.updateEvent); 59 | this.tooltip.hide(); 60 | //new Effect.Fade(this.tooltip, {duration: this.options.hideDuration, afterFinish: function() { Element.remove(this.tooltip) }.bind(this) }); 61 | } 62 | this._clearTimeout(this.timeout); 63 | 64 | this.initialized = false; 65 | }, 66 | update: function(e){ 67 | this.xCord = Event.pointerX(e); 68 | this.yCord = Event.pointerY(e); 69 | this.setup(); 70 | }, 71 | appear: function() { 72 | // Building tooltip container 73 | /* 74 | this.tooltip = Builder.node("div", {className: "tooltip", style: "display: none;" }, [ 75 | Builder.node("div", {className:"xtop"}, [ 76 | Builder.node("div", {className:"xb1", style:"background-color:" + this.options.borderColor + ";"}), 77 | Builder.node("div", {className:"xb2", style: "background-color:" + this.options.backgroundColor + "; border-color:" + this.options.borderColor + ";"}), 78 | Builder.node("div", {className:"xb3", style: "background-color:" + this.options.backgroundColor + "; border-color:" + this.options.borderColor + ";"}), 79 | Builder.node("div", {className:"xb4", style: "background-color:" + this.options.backgroundColor + "; border-color:" + this.options.borderColor + ";"}) 80 | ]), 81 | Builder.node("div", {className: "xboxcontent", style: "background-color:" + this.options.backgroundColor + 82 | "; border-color:" + this.options.borderColor + 83 | ((this.options.textColor != '') ? "; color:" + this.options.textColor : "") + 84 | ((this.options.textShadowColor != '') ? "; text-shadow:2px 2px 0" + this.options.textShadowColor + ";" : "")}, this.content), 85 | Builder.node("div", {className:"xbottom"}, [ 86 | Builder.node("div", {className:"xb4", style: "background-color:" + this.options.backgroundColor + "; border-color:" + this.options.borderColor + ";"}), 87 | Builder.node("div", {className:"xb3", style: "background-color:" + this.options.backgroundColor + "; border-color:" + this.options.borderColor + ";"}), 88 | Builder.node("div", {className:"xb2", style: "background-color:" + this.options.backgroundColor + "; border-color:" + this.options.borderColor + ";"}), 89 | Builder.node("div", {className:"xb1", style:"background-color:" + this.options.borderColor + ";"}) 90 | ]), 91 | ]); 92 | */ 93 | 94 | var tooltipString = ''+ 95 | '' 112 | new Insertion.Before(document.body.childNodes[0], tooltipString) 113 | this.tooltip = document.body.childNodes[0]; 114 | //document.body.insertBefore(this.tooltip, document.body.childNodes[0]); 115 | 116 | Element.extend(this.tooltip); // IE needs element to be manually extended 117 | this.options.width = this.tooltip.getWidth(); 118 | this.tooltip.style.width = this.options.width + 'px'; // IE7 needs width to be defined 119 | 120 | this.setup(); 121 | 122 | if(this.options.mouseFollow) 123 | Event.observe(this.el, "mousemove", this.updateEvent); 124 | 125 | this.initialized = true; 126 | this.tooltip.show(); 127 | //this.appearingFX = new Effect.Appear(this.tooltip, {duration: this.options.appearDuration, to: this.options.opacity }); 128 | }, 129 | setup: function(){ 130 | // If content width is more then allowed max width, set width to max 131 | if(this.options.width > this.options.maxWidth) { 132 | this.options.width = this.options.maxWidth; 133 | this.tooltip.style.width = this.options.width + 'px'; 134 | } 135 | 136 | // Tooltip doesn't fit the current document dimensions 137 | if(this.xCord + this.options.width >= Element.getWidth(document.body)) { 138 | this.options.align = "right"; 139 | this.xCord = this.xCord - this.options.width + 20; 140 | } 141 | 142 | this.tooltip.style.left = this.xCord - 7 + "px"; 143 | this.tooltip.style.top = this.yCord + 12 + "px"; 144 | }, 145 | stop: function () { 146 | this.hide(); 147 | Event.stopObserving(this.el, "mouseover", this.showEvent); 148 | Event.stopObserving(this.el, "mouseout", this.hideEvent); 149 | Event.stopObserving(this.el, "mousemove", this.updateEvent); 150 | }, 151 | _clearTimeout: function(timer) { 152 | clearTimeout(timer); 153 | clearInterval(timer); 154 | return null; 155 | } 156 | }; -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/js/validation_cn.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-server/src/main/webapp/js/validation_cn.js -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/200.jsp: -------------------------------------------------------------------------------- 1 | <% 2 | Object o = request.getAttribute("content"); 3 | if(o==null||o.equals("")){ 4 | out.println("OK"); 5 | }else{ 6 | out.println(o); 7 | } 8 | %> -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/400.jsp: -------------------------------------------------------------------------------- 1 | remote ip is null -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/500.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-server/src/main/webapp/jsp/500.jsp -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/503.jsp: -------------------------------------------------------------------------------- 1 | Serivce is unavailable now.Request is refused. -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/admin/admin.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=GBK" pageEncoding="GBK"%> 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/admin/config/batch_result.jsp: -------------------------------------------------------------------------------- 1 | ${json} -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/admin/config/edit.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-server/src/main/webapp/jsp/admin/config/edit.jsp -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/admin/config/list.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-server/src/main/webapp/jsp/admin/config/list.jsp -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/admin/config/list_json.jsp: -------------------------------------------------------------------------------- 1 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 2 | <%@ page contentType="application/json;charset=GBK" pageEncoding="GBK"%> 3 | -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/admin/config/new.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-server/src/main/webapp/jsp/admin/config/new.jsp -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/admin/config/upload.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-server/src/main/webapp/jsp/admin/config/upload.jsp -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/admin/count.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-server/src/main/webapp/jsp/admin/count.jsp -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/admin/menu.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-server/src/main/webapp/jsp/admin/menu.jsp -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/admin/user/list.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-server/src/main/webapp/jsp/admin/user/list.jsp -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/admin/user/new.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-server/src/main/webapp/jsp/admin/user/new.jsp -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/admin/welcome.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-server/src/main/webapp/jsp/admin/welcome.jsp -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/common/message.jsp: -------------------------------------------------------------------------------- 1 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 2 | <%@ page contentType="text/html; charset=GBK" pageEncoding="GBK"%> 3 | 4 | 5 | -------------------------------------------------------------------------------- /diamond-server/src/main/webapp/jsp/login.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gzllol/diamond/f559792388c5f340c3dfaf45a4b082af5246ec38/diamond-server/src/main/webapp/jsp/login.jsp -------------------------------------------------------------------------------- /diamond-utils/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | diamond-all 6 | com.taobao.diamond 7 | 2.0.5.4.taocode-SNAPSHOT 8 | 9 | 10 | 4.0.0 11 | diamond-utils 12 | diamond-utils v${project.version} 13 | 14 | 15 | 16 | commons-logging 17 | commons-logging 18 | 19 | 20 | commons-io 21 | commons-io 22 | 23 | 24 | org.codehaus.jackson 25 | jackson-core-lgpl 26 | 27 | 28 | org.codehaus.jackson 29 | jackson-mapper-lgpl 30 | 31 | 32 | junit 33 | junit 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/common/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.common; 11 | 12 | public interface Constants { 13 | 14 | public static final String DEFAULT_GROUP = "DEFAULT_GROUP"; 15 | 16 | public static final String BASE_DIR = "config-data"; 17 | 18 | public static final String DEFAULT_DOMAINNAME = "config.diamond.org"; 19 | 20 | public static final String DAILY_DOMAINNAME = "config.diamond.org"; 21 | 22 | public static final int DEFAULT_PORT = 8080; 23 | 24 | public static final String NULL = ""; 25 | 26 | public static final String DATAID = "dataId"; 27 | 28 | public static final String GROUP = "group"; 29 | 30 | public static final String LAST_MODIFIED = "Last-Modified"; 31 | 32 | public static final String ACCEPT_ENCODING = "Accept-Encoding"; 33 | 34 | public static final String CONTENT_ENCODING = "Content-Encoding"; 35 | 36 | public static final String PROBE_MODIFY_REQUEST = "Probe-Modify-Request"; 37 | 38 | public static final String PROBE_MODIFY_RESPONSE = "Probe-Modify-Response"; 39 | 40 | public static final String PROBE_MODIFY_RESPONSE_NEW = "Probe-Modify-Response-New"; 41 | 42 | public static final String CONTENT_MD5 = "Content-MD5"; 43 | 44 | public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; 45 | 46 | public static final String SPACING_INTERVAL = "client-spacing-interval"; 47 | 48 | public static final int POLLING_INTERVAL_TIME = 15;// 秒 49 | 50 | public static final int ONCE_TIMEOUT = 2000;// 毫秒 51 | 52 | public static final int CONN_TIMEOUT = 2000;// 毫秒 53 | 54 | public static final int RECV_WAIT_TIMEOUT = ONCE_TIMEOUT * 5;// 毫秒 55 | 56 | public static final String HTTP_URI_FILE = "/config.co"; 57 | 58 | public static final String CONFIG_HTTP_URI_FILE = "/url.do"; 59 | 60 | public static final String HTTP_URI_LOGIN = "/url"; 61 | 62 | public static final String ENCODE = "GBK"; 63 | 64 | public static final String LINE_SEPARATOR = Character.toString((char) 1); 65 | 66 | public static final String WORD_SEPARATOR = Character.toString((char) 2); 67 | 68 | public static final String DEFAULT_USERNAME = "xxx"; 69 | 70 | public static final String DEFAULT_PASSWORD = "xxx"; 71 | 72 | /* 73 | * 批量操作时, 单条数据的状态码 74 | */ 75 | // 发生异常 76 | public static final int BATCH_OP_ERROR = -1; 77 | // 查询成功, 数据存在 78 | public static final int BATCH_QUERY_EXISTS = 1; 79 | // 查询成功, 数据不存在 80 | public static final int BATCH_QUERY_NONEXISTS = 2; 81 | // 新增成功 82 | public static final int BATCH_ADD_SUCCESS = 3; 83 | // 更新成功 84 | public static final int BATCH_UPDATE_SUCCESS = 4; 85 | 86 | String CONF_KEY_CONFIG_IP = "diamond.config.ip"; 87 | String CONF_KEY_PORT = "diamond.port"; 88 | 89 | } -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/domain/ConfigInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.domain; 11 | 12 | import java.io.PrintWriter; 13 | import java.io.Serializable; 14 | 15 | import com.taobao.diamond.md5.MD5; 16 | 17 | 18 | /** 19 | * 配置信息类 20 | * 21 | * @author boyan 22 | * @date 2010-5-4 23 | */ 24 | public class ConfigInfo implements Serializable, Comparable { 25 | static final long serialVersionUID = -1L; 26 | private String dataId; 27 | private String content; 28 | private String md5; 29 | 30 | private String group; 31 | private long id; 32 | 33 | 34 | public ConfigInfo() { 35 | 36 | } 37 | 38 | 39 | public ConfigInfo(String dataId, String group, String content) { 40 | super(); 41 | this.dataId = dataId; 42 | this.content = content; 43 | this.group = group; 44 | if (this.content != null) { 45 | this.md5 = MD5.getInstance().getMD5String(this.content); 46 | } 47 | } 48 | 49 | 50 | public long getId() { 51 | return id; 52 | } 53 | 54 | 55 | public void setId(long id) { 56 | this.id = id; 57 | } 58 | 59 | 60 | public String getDataId() { 61 | return dataId; 62 | } 63 | 64 | 65 | public void setDataId(String dataId) { 66 | this.dataId = dataId; 67 | } 68 | 69 | 70 | public String getGroup() { 71 | return group; 72 | } 73 | 74 | 75 | public void setGroup(String group) { 76 | this.group = group; 77 | } 78 | 79 | 80 | public String getContent() { 81 | return content; 82 | } 83 | 84 | 85 | public void setContent(String content) { 86 | this.content = content; 87 | } 88 | 89 | 90 | public void dump(PrintWriter writer) { 91 | writer.write(this.content); 92 | } 93 | 94 | 95 | public String getMd5() { 96 | return md5; 97 | } 98 | 99 | 100 | public void setMd5(String md5) { 101 | this.md5 = md5; 102 | } 103 | 104 | 105 | public int compareTo(ConfigInfo o) { 106 | if (o == null) 107 | return 1; 108 | 109 | if (this.dataId == null && o.getDataId() != null) 110 | return -1; 111 | int cmpDataId = this.dataId.compareTo(o.getDataId()); 112 | if (cmpDataId != 0) { 113 | return cmpDataId; 114 | } 115 | if (this.group == null && o.getGroup() != null) 116 | return -1; 117 | int cmpGroup = this.group.compareTo(o.getGroup()); 118 | if (cmpGroup != 0) { 119 | return cmpGroup; 120 | } 121 | if (this.content == null && o.getContent() != null) 122 | return -1; 123 | int cmpContent = this.content.compareTo(o.getContent()); 124 | if (cmpContent != 0) { 125 | return cmpContent; 126 | } 127 | return 0; 128 | } 129 | 130 | 131 | @Override 132 | public int hashCode() { 133 | final int prime = 31; 134 | int result = 1; 135 | result = prime * result + ((content == null) ? 0 : content.hashCode()); 136 | result = prime * result + ((dataId == null) ? 0 : dataId.hashCode()); 137 | result = prime * result + ((group == null) ? 0 : group.hashCode()); 138 | result = prime * result + ((md5 == null) ? 0 : md5.hashCode()); 139 | return result; 140 | } 141 | 142 | 143 | @Override 144 | public boolean equals(Object obj) { 145 | if (this == obj) 146 | return true; 147 | if (obj == null) 148 | return false; 149 | if (getClass() != obj.getClass()) 150 | return false; 151 | ConfigInfo other = (ConfigInfo) obj; 152 | if (content == null) { 153 | if (other.content != null) 154 | return false; 155 | } 156 | else if (!content.equals(other.content)) 157 | return false; 158 | if (dataId == null) { 159 | if (other.dataId != null) 160 | return false; 161 | } 162 | else if (!dataId.equals(other.dataId)) 163 | return false; 164 | if (group == null) { 165 | if (other.group != null) 166 | return false; 167 | } 168 | else if (!group.equals(other.group)) 169 | return false; 170 | if (md5 == null) { 171 | if (other.md5 != null) 172 | return false; 173 | } 174 | else if (!md5.equals(other.md5)) 175 | return false; 176 | return true; 177 | } 178 | 179 | 180 | @Override 181 | public String toString() { 182 | return "[" + "dataId=" + dataId + "," + "groupName=" + group + "," + "context=" + content + "," + "]"; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/domain/ConfigInfoEx.java: -------------------------------------------------------------------------------- 1 | package com.taobao.diamond.domain; 2 | 3 | /** 4 | * ConfigInfo的扩展类, 解决老版本的SDK与新版本的server由于反序列化字段错误而产生的不兼容问题 5 | * 6 | * @author leiwen.zh 7 | * 8 | */ 9 | public class ConfigInfoEx extends ConfigInfo { 10 | 11 | private static final long serialVersionUID = -1L; 12 | 13 | // 批量查询时, 单条数据的状态码, 具体的状态码在Constants.java中 14 | private int status; 15 | // 批量查询时, 单条数据的信息 16 | private String message; 17 | 18 | 19 | public ConfigInfoEx() { 20 | super(); 21 | } 22 | 23 | 24 | public ConfigInfoEx(String dataId, String group, String content) { 25 | super(dataId, group, content); 26 | } 27 | 28 | 29 | public int getStatus() { 30 | return status; 31 | } 32 | 33 | 34 | public void setStatus(int status) { 35 | this.status = status; 36 | } 37 | 38 | 39 | public String getMessage() { 40 | return message; 41 | } 42 | 43 | 44 | public void setMessage(String message) { 45 | this.message = message; 46 | } 47 | 48 | 49 | @Override 50 | public String toString() { 51 | return "ConfigInfoEx [status=" + status + ", message=" + message 52 | + ", getDataId()=" + getDataId() + ", getGroup()=" + getGroup() 53 | + ", getContent()=" + getContent() + ", getMd5()=" + getMd5() 54 | + "]"; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/domain/Page.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.domain; 11 | 12 | import java.io.Serializable; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | 17 | /** 18 | * 分页对象 19 | * 20 | * @author boyan 21 | * @date 2010-5-6 22 | * @param 23 | */ 24 | public class Page implements Serializable { 25 | static final long serialVersionUID = -1L; 26 | 27 | private int totalCount; // 总记录数 28 | private int pageNumber; // 页数 29 | private int pagesAvailable; // 总页数 30 | private List pageItems = new ArrayList(); // 该页内容 31 | 32 | 33 | public void setPageNumber(int pageNumber) { 34 | this.pageNumber = pageNumber; 35 | } 36 | 37 | 38 | public void setPagesAvailable(int pagesAvailable) { 39 | this.pagesAvailable = pagesAvailable; 40 | } 41 | 42 | 43 | public void setPageItems(List pageItems) { 44 | this.pageItems = pageItems; 45 | } 46 | 47 | 48 | public int getTotalCount() { 49 | return totalCount; 50 | } 51 | 52 | 53 | public void setTotalCount(int totalCount) { 54 | this.totalCount = totalCount; 55 | } 56 | 57 | 58 | public int getPageNumber() { 59 | return pageNumber; 60 | } 61 | 62 | 63 | public int getPagesAvailable() { 64 | return pagesAvailable; 65 | } 66 | 67 | 68 | public List getPageItems() { 69 | return pageItems; 70 | } 71 | } -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/io/FileSystem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.io; 11 | 12 | import com.taobao.diamond.io.watch.WatchService; 13 | 14 | 15 | /** 16 | * 文件系统类,提供基础操作 17 | * 18 | * @author boyan 19 | * @date 2010-5-4 20 | */ 21 | public class FileSystem { 22 | private static final FileSystem instance = new FileSystem(); 23 | 24 | private String interval = System.getProperty("diamon.watch.interval", "5000"); 25 | 26 | 27 | public void setInterval(String interval) { 28 | this.interval = interval; 29 | } 30 | 31 | 32 | public static final FileSystem getDefault() { 33 | return instance; 34 | } 35 | 36 | 37 | /** 38 | * 生成一个新的WatchService 39 | * 40 | * @return 41 | */ 42 | public WatchService newWatchService() { 43 | return new WatchService(Long.valueOf(interval)); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/io/Path.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.io; 11 | 12 | import java.io.File; 13 | import java.io.FileFilter; 14 | import java.io.FilenameFilter; 15 | import java.io.IOException; 16 | import java.net.URI; 17 | 18 | import com.taobao.diamond.io.watch.WatchEvent.Kind; 19 | import com.taobao.diamond.io.watch.WatchKey; 20 | import com.taobao.diamond.io.watch.WatchService; 21 | import com.taobao.diamond.io.watch.Watchable; 22 | 23 | 24 | /** 25 | * File对象的封装 26 | * 27 | * @author boyan 28 | * @date 2010-5-4 29 | */ 30 | public class Path implements Watchable { 31 | private File file; 32 | 33 | 34 | public Path(File file) { 35 | super(); 36 | this.file = file; 37 | } 38 | 39 | 40 | public File getFile() { 41 | return file; 42 | } 43 | 44 | 45 | public boolean canExecute() { 46 | return file.canExecute(); 47 | } 48 | 49 | 50 | public boolean canRead() { 51 | return file.canRead(); 52 | } 53 | 54 | 55 | public boolean canWrite() { 56 | return file.canWrite(); 57 | } 58 | 59 | 60 | public int compareTo(File pathname) { 61 | return file.compareTo(pathname); 62 | } 63 | 64 | 65 | public boolean createNewFile() throws IOException { 66 | return file.createNewFile(); 67 | } 68 | 69 | 70 | public boolean delete() { 71 | return file.delete(); 72 | } 73 | 74 | 75 | public void deleteOnExit() { 76 | file.deleteOnExit(); 77 | } 78 | 79 | 80 | public boolean equals(Object obj) { 81 | return file.equals(obj); 82 | } 83 | 84 | 85 | public boolean exists() { 86 | return file.exists(); 87 | } 88 | 89 | 90 | public File getAbsoluteFile() { 91 | return file.getAbsoluteFile(); 92 | } 93 | 94 | 95 | public String getAbsolutePath() { 96 | return file.getAbsolutePath(); 97 | } 98 | 99 | 100 | public File getCanonicalFile() throws IOException { 101 | return file.getCanonicalFile(); 102 | } 103 | 104 | 105 | public String getCanonicalPath() throws IOException { 106 | return file.getCanonicalPath(); 107 | } 108 | 109 | 110 | public long getFreeSpace() { 111 | return file.getFreeSpace(); 112 | } 113 | 114 | 115 | public String getName() { 116 | return file.getName(); 117 | } 118 | 119 | 120 | public String getParent() { 121 | return file.getParent(); 122 | } 123 | 124 | 125 | public File getParentFile() { 126 | return file.getParentFile(); 127 | } 128 | 129 | 130 | public String getPath() { 131 | return file.getPath(); 132 | } 133 | 134 | 135 | public long getTotalSpace() { 136 | return file.getTotalSpace(); 137 | } 138 | 139 | 140 | public long getUsableSpace() { 141 | return file.getUsableSpace(); 142 | } 143 | 144 | 145 | public int hashCode() { 146 | return file.hashCode(); 147 | } 148 | 149 | 150 | public boolean isAbsolute() { 151 | return file.isAbsolute(); 152 | } 153 | 154 | 155 | public boolean isDirectory() { 156 | return file.isDirectory(); 157 | } 158 | 159 | 160 | public boolean isFile() { 161 | return file.isFile(); 162 | } 163 | 164 | 165 | public boolean isHidden() { 166 | return file.isHidden(); 167 | } 168 | 169 | 170 | public long lastModified() { 171 | return file.lastModified(); 172 | } 173 | 174 | 175 | public long length() { 176 | return file.length(); 177 | } 178 | 179 | 180 | public String[] list() { 181 | return file.list(); 182 | } 183 | 184 | 185 | public String[] list(FilenameFilter filter) { 186 | return file.list(filter); 187 | } 188 | 189 | 190 | public File[] listFiles() { 191 | return file.listFiles(); 192 | } 193 | 194 | 195 | public File[] listFiles(FileFilter filter) { 196 | return file.listFiles(filter); 197 | } 198 | 199 | 200 | public File[] listFiles(FilenameFilter filter) { 201 | return file.listFiles(filter); 202 | } 203 | 204 | 205 | public boolean mkdir() { 206 | return file.mkdir(); 207 | } 208 | 209 | 210 | public boolean mkdirs() { 211 | return file.mkdirs(); 212 | } 213 | 214 | 215 | public boolean renameTo(File dest) { 216 | return file.renameTo(dest); 217 | } 218 | 219 | 220 | public boolean setExecutable(boolean executable, boolean ownerOnly) { 221 | return file.setExecutable(executable, ownerOnly); 222 | } 223 | 224 | 225 | public boolean setExecutable(boolean executable) { 226 | return file.setExecutable(executable); 227 | } 228 | 229 | 230 | public boolean setLastModified(long time) { 231 | return file.setLastModified(time); 232 | } 233 | 234 | 235 | public boolean setReadable(boolean readable, boolean ownerOnly) { 236 | return file.setReadable(readable, ownerOnly); 237 | } 238 | 239 | 240 | public boolean setReadable(boolean readable) { 241 | return file.setReadable(readable); 242 | } 243 | 244 | 245 | public boolean setReadOnly() { 246 | return file.setReadOnly(); 247 | } 248 | 249 | 250 | public boolean setWritable(boolean writable, boolean ownerOnly) { 251 | return file.setWritable(writable, ownerOnly); 252 | } 253 | 254 | 255 | public boolean setWritable(boolean writable) { 256 | return file.setWritable(writable); 257 | } 258 | 259 | 260 | public String toString() { 261 | return file.toString(); 262 | } 263 | 264 | 265 | public URI toURI() { 266 | return file.toURI(); 267 | } 268 | 269 | 270 | public WatchKey register(WatchService watcher, Kind... events) { 271 | return watcher.register(this, events); 272 | } 273 | 274 | } 275 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/io/watch/StandardWatchEventKind.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.io.watch; 11 | 12 | import com.taobao.diamond.io.Path; 13 | 14 | 15 | /** 16 | * 标准WatchEvent 17 | * 18 | * @author boyan 19 | * 20 | */ 21 | public class StandardWatchEventKind { 22 | 23 | /** 24 | * Directory entry created 25 | */ 26 | public static final WatchEvent.Kind ENTRY_CREATE = new WatchEvent.Kind() { 27 | public String name() { 28 | return "ENTRY_CREATE"; 29 | } 30 | 31 | 32 | public Class type() { 33 | return Path.class; 34 | } 35 | 36 | }; 37 | 38 | /** 39 | * Directory entry deleted 40 | */ 41 | public static final WatchEvent.Kind ENTRY_DELETE = new WatchEvent.Kind() { 42 | public String name() { 43 | return "ENTRY_DELETE"; 44 | } 45 | 46 | 47 | public Class type() { 48 | return Path.class; 49 | } 50 | 51 | }; 52 | 53 | /** 54 | * Directory entry modified 55 | */ 56 | public static final WatchEvent.Kind ENTRY_MODIFY = new WatchEvent.Kind() { 57 | public String name() { 58 | return "ENTRY_MODIFY"; 59 | } 60 | 61 | 62 | public Class type() { 63 | return Path.class; 64 | } 65 | 66 | }; 67 | 68 | /** 69 | * Directory entry overflow 70 | */ 71 | public static final WatchEvent.Kind OVERFLOW = new WatchEvent.Kind() { 72 | public String name() { 73 | return "OVERFLOW"; 74 | } 75 | 76 | 77 | public Class type() { 78 | return Void.class; 79 | } 80 | 81 | }; 82 | } 83 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/io/watch/WatchEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.io.watch; 11 | 12 | /** 13 | * 14 | * @author boyan 15 | * @date 2010-5-4 16 | * @param 17 | */ 18 | public class WatchEvent { 19 | public static interface Kind { 20 | public String name(); 21 | 22 | 23 | public Class type(); 24 | } 25 | 26 | private Kind kind; 27 | 28 | private int count; 29 | 30 | private T context; 31 | 32 | 33 | public WatchEvent(Kind kind, int count, T context) { 34 | super(); 35 | this.kind = kind; 36 | this.count = count; 37 | this.context = context; 38 | } 39 | 40 | 41 | public Kind kind() { 42 | return kind; 43 | 44 | } 45 | 46 | 47 | public int count() { 48 | return count; 49 | } 50 | 51 | 52 | public T context() { 53 | return context; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/io/watch/WatchKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.io.watch; 11 | 12 | import java.io.File; 13 | import java.util.HashSet; 14 | import java.util.Iterator; 15 | import java.util.LinkedList; 16 | import java.util.List; 17 | import java.util.Set; 18 | 19 | import com.taobao.diamond.io.Path; 20 | import com.taobao.diamond.io.watch.util.PathNode; 21 | 22 | 23 | /** 24 | * WatchKey,表示一个注册的的凭证 25 | * 26 | * @author boyan 27 | * @date 2010-5-4 28 | */ 29 | public class WatchKey { 30 | 31 | private volatile boolean valid; 32 | 33 | private final PathNode root; 34 | 35 | private List> changedEvents; 36 | 37 | private final Set> filterSet = new HashSet>(); 38 | 39 | private final WatchService watcher; 40 | 41 | 42 | public WatchKey(final Path path, final WatchService watcher, boolean fireCreatedEventOnIndex, 43 | WatchEvent.Kind... events) { 44 | valid = true; 45 | this.watcher = watcher; 46 | // 建立内存索引 47 | this.root = new PathNode(path, true); 48 | if (events != null) { 49 | for (WatchEvent.Kind event : events) { 50 | filterSet.add(event); 51 | } 52 | } 53 | LinkedList> changedEvents = new LinkedList>(); 54 | index(this.root, fireCreatedEventOnIndex, changedEvents); 55 | this.changedEvents = changedEvents; 56 | } 57 | 58 | 59 | /** 60 | * 索引目录 61 | * 62 | * @param node 63 | */ 64 | private void index(PathNode node, boolean fireCreatedEventOnIndex, LinkedList> changedEvents) { 65 | File file = node.getPath().getFile(); 66 | if (!file.isDirectory()) { 67 | return; 68 | } 69 | File[] subFiles = file.listFiles(); 70 | if (subFiles != null) { 71 | for (File subFile : subFiles) { 72 | PathNode subNode = new PathNode(new Path(subFile), false); 73 | if (fireCreatedEventOnIndex) { 74 | changedEvents.add(new WatchEvent(StandardWatchEventKind.ENTRY_CREATE, 1, subNode.getPath())); 75 | } 76 | node.addChild(subNode); 77 | if (subNode.getPath().isDirectory()) { 78 | index(subNode, fireCreatedEventOnIndex, changedEvents); 79 | } 80 | } 81 | } 82 | } 83 | 84 | 85 | public void cancel() { 86 | this.valid = false; 87 | } 88 | 89 | 90 | @Override 91 | public String toString() { 92 | return "WatchKey [root=" + root + ", valid=" + valid + "]"; 93 | } 94 | 95 | 96 | public boolean isValid() { 97 | return valid && root != null; 98 | } 99 | 100 | 101 | public List> pollEvents() { 102 | if (changedEvents != null) { 103 | List> result = changedEvents; 104 | changedEvents = null; 105 | return result; 106 | } 107 | return null; 108 | } 109 | 110 | 111 | /** 112 | * 检测是否有变化 113 | * 114 | * @return 115 | */ 116 | boolean check() { 117 | if (this.changedEvents != null && this.changedEvents.size() > 0) 118 | return true; 119 | if (!this.valid) 120 | return false; 121 | List> list = new LinkedList>(); 122 | if (check(root, list)) { 123 | this.changedEvents = list; 124 | return true; 125 | } 126 | else { 127 | return false; 128 | } 129 | } 130 | 131 | 132 | private boolean check(PathNode node, List> changedEvents) { 133 | Path nodePath = node.getPath(); 134 | File nodeNewFile = new File(nodePath.getAbsolutePath()); 135 | if (nodePath != null) { 136 | if (node.isRoot()) { 137 | if (!nodeNewFile.exists()) 138 | return fireOnRootDeleted(changedEvents, nodeNewFile); 139 | else { 140 | return checkNodeChildren(node, changedEvents, nodeNewFile); 141 | } 142 | } 143 | else { 144 | return checkNodeChildren(node, changedEvents, nodeNewFile); 145 | } 146 | } 147 | else 148 | throw new IllegalStateException("PathNode没有path"); 149 | } 150 | 151 | 152 | private boolean checkNodeChildren(PathNode node, List> changedEvents, File nodeNewFile) { 153 | boolean changed = false; 154 | Iterator it = node.getChildren().iterator(); 155 | // 用于判断是否有新增文件或者目录的现有名称集合 156 | Set childNameSet = new HashSet(); 157 | while (it.hasNext()) { 158 | PathNode child = it.next(); 159 | Path childPath = child.getPath(); 160 | childNameSet.add(childPath.getName()); 161 | File childNewFile = new File(childPath.getAbsolutePath()); 162 | // 1、判断文件是否还存在 163 | if (!childNewFile.exists() && filterSet.contains(StandardWatchEventKind.ENTRY_DELETE)) { 164 | changed = true; 165 | changedEvents.add(new WatchEvent(StandardWatchEventKind.ENTRY_DELETE, 1, childPath)); 166 | it.remove();// 移除节点 167 | } 168 | // 2、如果是文件,判断是否被修改 169 | if (childPath.isFile()) { 170 | if (checkFile(changedEvents, child, childNewFile) && !changed) { 171 | changed = true; 172 | } 173 | 174 | } 175 | // 3、递归检测目录 176 | if (childPath.isDirectory()) { 177 | if (check(child, changedEvents) && !changed) { 178 | changed = true; 179 | } 180 | } 181 | } 182 | 183 | // 查看是否有新增文件 184 | File[] newChildFiles = nodeNewFile.listFiles(); 185 | if(newChildFiles!=null) 186 | for (File newChildFile : newChildFiles) { 187 | if (!childNameSet.contains(newChildFile.getName()) 188 | && filterSet.contains(StandardWatchEventKind.ENTRY_CREATE)) { 189 | changed = true; 190 | Path newChildPath = new Path(newChildFile); 191 | changedEvents.add(new WatchEvent(StandardWatchEventKind.ENTRY_CREATE, 1, newChildPath)); 192 | PathNode newSubNode = new PathNode(newChildPath, false); 193 | node.addChild(newSubNode);// 新增子节点 194 | // 如果是目录,递归调用 195 | if (newChildFile.isDirectory()) { 196 | checkNodeChildren(newSubNode, changedEvents, newChildFile); 197 | } 198 | } 199 | } 200 | return changed; 201 | } 202 | 203 | 204 | private boolean checkFile(List> changedEvents, PathNode child, File childNewFile) { 205 | boolean changed = false; 206 | // 查看文件是否被修改 207 | if (childNewFile.lastModified() != child.lastModified() 208 | && filterSet.contains(StandardWatchEventKind.ENTRY_MODIFY)) { 209 | changed = true; 210 | Path newChildPath = new Path(childNewFile); 211 | changedEvents.add(new WatchEvent(StandardWatchEventKind.ENTRY_MODIFY, 1, newChildPath)); 212 | child.setPath(newChildPath);// 更新path 213 | } 214 | return changed; 215 | } 216 | 217 | 218 | private boolean fireOnRootDeleted(List> changedEvents, File nodeNewFile) { 219 | this.valid = false; 220 | if (filterSet.contains(StandardWatchEventKind.ENTRY_DELETE)) { 221 | changedEvents.add(new WatchEvent(StandardWatchEventKind.ENTRY_DELETE, 1, new Path(nodeNewFile))); 222 | return true; 223 | } 224 | return false; 225 | } 226 | 227 | 228 | public boolean reset() { 229 | if (!valid) 230 | return false; 231 | if (root == null) 232 | return false; 233 | return this.watcher.resetKey(this); 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/io/watch/WatchService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.io.watch; 11 | 12 | import java.util.Iterator; 13 | import java.util.concurrent.BlockingQueue; 14 | import java.util.concurrent.Executors; 15 | import java.util.concurrent.LinkedBlockingQueue; 16 | import java.util.concurrent.ScheduledExecutorService; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | import org.apache.commons.logging.Log; 20 | import org.apache.commons.logging.LogFactory; 21 | 22 | import com.taobao.diamond.io.Path; 23 | 24 | 25 | /** 26 | * Watch服务,为文件系统提供监视功能,当文件或者目录添加、删除或者更改的时候提供主动通知服务 27 | * 28 | * @author boyan 29 | * @date 2010-5-4 30 | */ 31 | public final class WatchService { 32 | private BlockingQueue changedKeys = new LinkedBlockingQueue(); 33 | 34 | private BlockingQueue watchedKeys = new LinkedBlockingQueue(); 35 | 36 | private static final Log log = LogFactory.getLog(WatchService.class); 37 | 38 | private ScheduledExecutorService service; 39 | 40 | 41 | public WatchService(long checkInterval) { 42 | service = Executors.newSingleThreadScheduledExecutor(); 43 | service.scheduleAtFixedRate(new CheckThread(), checkInterval, checkInterval, TimeUnit.MILLISECONDS); 44 | } 45 | 46 | private final class CheckThread implements Runnable { 47 | public void run() { 48 | check(); 49 | } 50 | 51 | } 52 | 53 | 54 | /** 55 | * 主动check 56 | */ 57 | public void check() { 58 | synchronized (this) { 59 | Iterator it = watchedKeys.iterator(); 60 | while (it.hasNext()) { 61 | WatchKey key = it.next(); 62 | try { 63 | if (key.check()) { 64 | changedKeys.add(key); 65 | it.remove(); 66 | } 67 | } 68 | catch (Throwable t) { 69 | log.error("检测WatchKey异常,key=" + key, t); 70 | } 71 | } 72 | } 73 | } 74 | 75 | 76 | /** 77 | * 注册目录 78 | * 79 | * @param root 80 | * @param events 81 | * @return 82 | */ 83 | public WatchKey register(Path root, WatchEvent.Kind... events) { 84 | if (events == null || events.length == 0) 85 | throw new UnsupportedOperationException("null events"); 86 | if (this.service.isShutdown()) 87 | throw new IllegalStateException("服务已经关闭"); 88 | if (!root.exists()) 89 | throw new IllegalArgumentException("监视的目录不存在"); 90 | WatchKey key = new WatchKey(root, this, false, events); 91 | resetKey(key); 92 | return key; 93 | } 94 | 95 | 96 | public WatchKey register(Path root, boolean fireCreatedEventOnIndex, WatchEvent.Kind... events) { 97 | if (events == null || events.length == 0) 98 | throw new UnsupportedOperationException("null events"); 99 | if (this.service.isShutdown()) 100 | throw new IllegalStateException("服务已经关闭"); 101 | if (!root.exists()) 102 | throw new IllegalArgumentException("监视的目录不存在"); 103 | WatchKey key = new WatchKey(root, this, fireCreatedEventOnIndex, events); 104 | resetKey(key); 105 | return key; 106 | } 107 | 108 | 109 | boolean resetKey(WatchKey key) { 110 | return this.watchedKeys.add(key); 111 | } 112 | 113 | 114 | /** 115 | * 停止服务 116 | */ 117 | public void close() { 118 | this.service.shutdown(); 119 | } 120 | 121 | 122 | /** 123 | * 获取改变的WatchKey 124 | * 125 | * @return 126 | */ 127 | public WatchKey poll() { 128 | return changedKeys.poll(); 129 | } 130 | 131 | 132 | /** 133 | * 获取改变的WatchKey 134 | * 135 | * @return 136 | */ 137 | public WatchKey poll(long timeout, TimeUnit unit) throws InterruptedException { 138 | return changedKeys.poll(timeout, unit); 139 | } 140 | 141 | 142 | /** 143 | * 获取改变的WatchKey 144 | * 145 | * @return 146 | */ 147 | public WatchKey take() throws InterruptedException { 148 | return changedKeys.take(); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/io/watch/Watchable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.io.watch; 11 | 12 | /** 13 | * 标记接口,实现此接口的类可以被注册到WatchService 14 | * 15 | * @author boyan 16 | * 17 | */ 18 | public interface Watchable { 19 | public WatchKey register(WatchService watcher, WatchEvent.Kind... events); 20 | } 21 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/io/watch/util/PathNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.io.watch.util; 11 | 12 | import java.util.LinkedList; 13 | import java.util.List; 14 | 15 | import com.taobao.diamond.io.Path; 16 | 17 | 18 | /** 19 | * 树形目录结构的节点,缓存lastModified 20 | * 21 | * @author boyan 22 | * 23 | */ 24 | public class PathNode { 25 | private List children; 26 | 27 | public Path path; 28 | 29 | private final boolean root; 30 | 31 | private long lastModified; 32 | 33 | 34 | public PathNode(Path path, boolean root) { 35 | super(); 36 | this.children = new LinkedList(); 37 | this.path = path; 38 | this.root = root; 39 | this.lastModified = path.lastModified(); 40 | } 41 | 42 | 43 | public long lastModified() { 44 | return lastModified; 45 | } 46 | 47 | 48 | public boolean isRoot() { 49 | return root; 50 | } 51 | 52 | 53 | public List getChildren() { 54 | return children; 55 | } 56 | 57 | 58 | public void setPath(Path path) { 59 | this.path = path; 60 | this.lastModified = path.lastModified(); 61 | } 62 | 63 | 64 | public Path getPath() { 65 | return path; 66 | } 67 | 68 | 69 | public void addChild(PathNode node) { 70 | this.children.add(node); 71 | } 72 | 73 | 74 | public void removeChild(PathNode node) { 75 | this.children.remove(node); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/md5/MD5.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.md5; 11 | 12 | import java.io.UnsupportedEncodingException; 13 | import java.security.MessageDigest; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | import java.util.concurrent.locks.ReentrantLock; 17 | 18 | import org.apache.commons.logging.Log; 19 | import org.apache.commons.logging.LogFactory; 20 | 21 | import com.taobao.diamond.common.Constants; 22 | 23 | 24 | public class MD5 { 25 | private static final Log log = LogFactory.getLog(MD5.class); 26 | private static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 27 | 28 | private static Map rDigits = new HashMap(16); 29 | static { 30 | for (int i = 0; i < digits.length; ++i) { 31 | rDigits.put(digits[i], i); 32 | } 33 | } 34 | 35 | private static MD5 me = new MD5(); 36 | private MessageDigest mHasher; 37 | private ReentrantLock opLock = new ReentrantLock(); 38 | 39 | 40 | private MD5() { 41 | try { 42 | mHasher = MessageDigest.getInstance("md5"); 43 | } 44 | catch (Exception e) { 45 | throw new RuntimeException(e); 46 | } 47 | 48 | } 49 | 50 | 51 | public static MD5 getInstance() { 52 | return me; 53 | } 54 | 55 | 56 | public String getMD5String(String content) { 57 | return bytes2string(hash(content)); 58 | } 59 | 60 | 61 | public String getMD5String(byte[] content) { 62 | return bytes2string(hash(content)); 63 | } 64 | 65 | 66 | public byte[] getMD5Bytes(byte[] content) { 67 | return hash(content); 68 | } 69 | 70 | 71 | /** 72 | * 对字符串进行md5 73 | * 74 | * @param str 75 | * @return md5 byte[16] 76 | */ 77 | public byte[] hash(String str) { 78 | opLock.lock(); 79 | try { 80 | byte[] bt = mHasher.digest(str.getBytes(Constants.ENCODE)); 81 | if (null == bt || bt.length != 16) { 82 | throw new IllegalArgumentException("md5 need"); 83 | } 84 | return bt; 85 | } 86 | catch (UnsupportedEncodingException e) { 87 | throw new RuntimeException("unsupported utf-8 encoding", e); 88 | } 89 | finally { 90 | opLock.unlock(); 91 | } 92 | } 93 | 94 | 95 | /** 96 | * 对二进制数据进行md5 97 | * 98 | * @param str 99 | * @return md5 byte[16] 100 | */ 101 | public byte[] hash(byte[] data) { 102 | opLock.lock(); 103 | try { 104 | byte[] bt = mHasher.digest(data); 105 | if (null == bt || bt.length != 16) { 106 | throw new IllegalArgumentException("md5 need"); 107 | } 108 | return bt; 109 | } 110 | finally { 111 | opLock.unlock(); 112 | } 113 | } 114 | 115 | 116 | /** 117 | * 将一个字节数组转化为可见的字符串 118 | * 119 | * @param bt 120 | * @return 121 | */ 122 | public String bytes2string(byte[] bt) { 123 | int l = bt.length; 124 | 125 | char[] out = new char[l << 1]; 126 | 127 | for (int i = 0, j = 0; i < l; i++) { 128 | out[j++] = digits[(0xF0 & bt[i]) >>> 4]; 129 | out[j++] = digits[0x0F & bt[i]]; 130 | } 131 | 132 | if (log.isDebugEnabled()) { 133 | log.debug("[hash]" + (new String(out))); 134 | } 135 | 136 | return new String(out); 137 | } 138 | 139 | 140 | /** 141 | * 将字符串转换为bytes 142 | * 143 | * @param str 144 | * @return byte[] 145 | */ 146 | public byte[] string2bytes(String str) { 147 | if (null == str) { 148 | throw new NullPointerException("参数不能为空"); 149 | } 150 | if (str.length() != 32) { 151 | throw new IllegalArgumentException("字符串长度必须是32"); 152 | } 153 | byte[] data = new byte[16]; 154 | char[] chs = str.toCharArray(); 155 | for (int i = 0; i < 16; ++i) { 156 | int h = rDigits.get(chs[i * 2]).intValue(); 157 | int l = rDigits.get(chs[i * 2 + 1]).intValue(); 158 | data[i] = (byte) ((h & 0x0F) << 4 | (l & 0x0F)); 159 | } 160 | return data; 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.utils; 11 | 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.io.RandomAccessFile; 15 | 16 | import com.taobao.diamond.common.Constants; 17 | 18 | 19 | public class FileUtils { 20 | 21 | public static boolean isFile(String path) { 22 | File file = new File(path); 23 | return file.isFile(); 24 | } 25 | 26 | 27 | public static boolean isDirectory(String path) { 28 | File dir = new File(path); 29 | return dir.isDirectory(); 30 | } 31 | 32 | 33 | public static String getFileName(String path) { 34 | File file = new File(path); 35 | if (!file.isFile()) { 36 | throw new RuntimeException("此路径表达的不是文件"); 37 | } 38 | return file.getName(); 39 | } 40 | 41 | 42 | public static String getParentDir(String path) { 43 | File file = new File(path); 44 | if (!file.isFile()) { 45 | throw new RuntimeException("此路径表达的不是文件"); 46 | } 47 | File parent = file.getParentFile(); 48 | if (parent.isDirectory()) { 49 | return parent.getName(); 50 | } 51 | else { 52 | throw new RuntimeException("父目录不是目录"); 53 | } 54 | } 55 | 56 | 57 | public static String getGrandpaDir(String path) { 58 | File file = new File(path); 59 | if (file.isDirectory()) { 60 | throw new RuntimeException("此路径表达的不是文件"); 61 | } 62 | File parent = file.getParentFile(); 63 | if (parent.isDirectory()) { 64 | File grandpa = parent.getParentFile(); 65 | if (grandpa.isDirectory()) { 66 | return grandpa.getName(); 67 | } 68 | else { 69 | throw new RuntimeException("祖目录不是目录"); 70 | } 71 | } 72 | else { 73 | throw new RuntimeException("父目录不是目录"); 74 | } 75 | } 76 | 77 | 78 | public static String getFileContent(String path) throws IOException { 79 | File tFile = new File(path); 80 | if (!tFile.isFile()) { 81 | throw new RuntimeException("不是文件"); 82 | } 83 | RandomAccessFile file = new RandomAccessFile(tFile, "r"); 84 | long fileSize = file.length(); 85 | byte[] bytes = new byte[(int) fileSize]; 86 | long readLength = 0L; 87 | while (readLength < fileSize) { 88 | int onceLength = file.read(bytes, (int) readLength, (int) (fileSize - readLength)); 89 | if (onceLength > 0) { 90 | readLength += onceLength; 91 | } 92 | else { 93 | break; 94 | } 95 | } 96 | try { 97 | file.close(); 98 | } 99 | catch (Exception e) { 100 | 101 | } 102 | return new String(bytes, Constants.ENCODE); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/utils/JSONUtils.java: -------------------------------------------------------------------------------- 1 | package com.taobao.diamond.utils; 2 | 3 | import org.codehaus.jackson.map.ObjectMapper; 4 | import org.codehaus.jackson.type.TypeReference; 5 | 6 | 7 | public class JSONUtils { 8 | 9 | static ObjectMapper mapper = new ObjectMapper(); 10 | 11 | public static String serializeObject(Object o) throws Exception { 12 | return mapper.writeValueAsString(o); 13 | } 14 | 15 | public static Object deserializeObject(String s, Class clazz) throws Exception { 16 | return mapper.readValue(s, clazz); 17 | } 18 | 19 | public static Object deserializeObject(String s,TypeReference typeReference) throws Exception { 20 | return mapper.readValue(s, typeReference); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/utils/LoggerInit.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.utils; 11 | 12 | import java.io.File; 13 | import java.util.Enumeration; 14 | import java.util.Properties; 15 | 16 | import org.apache.commons.logging.Log; 17 | import org.apache.commons.logging.LogFactory; 18 | import org.apache.log4j.Appender; 19 | import org.apache.log4j.FileAppender; 20 | import org.apache.log4j.Logger; 21 | import org.apache.log4j.PropertyConfigurator; 22 | 23 | 24 | /** 25 | * 26 | * 27 | * logger初始化,把日志输出到应用的目录里 28 | * 29 | */ 30 | public class LoggerInit { 31 | static public final String LOG_NAME_CONFIG_DATA = "DiamondConfigDataLog"; 32 | 33 | static public final Log log = LogFactory.getLog(LoggerInit.class); 34 | 35 | static private volatile boolean initOK = false; 36 | 37 | static private Properties defaultProperties = new Properties(); 38 | static { 39 | defaultProperties.put("log4j.logger.DiamondConfigDataLog", "info, DiamondConfigDataLogFile"); 40 | defaultProperties.put("log4j.additivity.DiamondConfigDataLog", "false"); 41 | defaultProperties.put("log4j.appender.DiamondConfigDataLogFile", "org.apache.log4j.DailyRollingFileAppender"); 42 | defaultProperties.put("log4j.appender.DiamondConfigDataLogFile.DatePattern", "'.'yyyy-MM-dd"); 43 | defaultProperties.put("log4j.appender.DiamondConfigDataLogFile.File", "diamond_config_data.log"); 44 | defaultProperties.put("log4j.appender.DiamondConfigDataLogFile.layout", "org.apache.log4j.PatternLayout"); 45 | defaultProperties.put("log4j.appender.DiamondConfigDataLogFile.layout.ConversionPattern", 46 | "%d{MM-dd HH:mm:ss} - %m%n"); 47 | defaultProperties.put("log4j.appender.DiamondConfigDataLogFile.Append", "true"); 48 | } 49 | 50 | 51 | public static void initLogFromBizLog() { 52 | 53 | if (initOK) { 54 | return; 55 | } 56 | 57 | ClassLoader cl = Thread.currentThread().getContextClassLoader(); 58 | Thread.currentThread().setContextClassLoader(LoggerInit.class.getClassLoader()); 59 | 60 | try { 61 | // 使缺省的配置生效(Logger, Appender) 62 | PropertyConfigurator.configure(defaultProperties); 63 | 64 | /** 65 | * 找到上层应用在Root Logger上设置的FileAppender,以及HSF配置的FileAppender。 66 | * 目的是为了让HSF的日志与上层应用的日志输出到同一个目录。 67 | */ 68 | FileAppender bizFileAppender = getFileAppender(Logger.getRootLogger()); 69 | if (null == bizFileAppender) { 70 | log.warn("上层业务层没有在ROOT LOGGER上设置FileAppender!!!"); 71 | bizFileAppender = new FileAppender(); 72 | bizFileAppender.setFile(System.getProperty("user.home") + "/diamond/logs/diamond_config_data.log"); 73 | } 74 | 75 | setFileAppender(bizFileAppender, LOG_NAME_CONFIG_DATA); 76 | 77 | initOK = true; 78 | } 79 | finally { 80 | Thread.currentThread().setContextClassLoader(cl); 81 | } 82 | } 83 | 84 | 85 | private static void setFileAppender(FileAppender bizFileAppender, String logName) { 86 | FileAppender fileAppender = getFileAppender(Logger.getLogger(logName)); 87 | String bizLogDir = new File(bizFileAppender.getFile()).getParent(); 88 | 89 | File newLogFile = new File(bizLogDir, fileAppender.getFile()); 90 | 91 | fileAppender.setFile(newLogFile.getAbsolutePath()); 92 | fileAppender.activateOptions(); // 很重要,否则原有日志内容会被清空 93 | log.warn("成功为" + logName + "添加Appender. 输出路径:" + newLogFile.getAbsolutePath()); 94 | } 95 | 96 | 97 | static private FileAppender getFileAppender(Logger logger) { 98 | FileAppender fileAppender = null; 99 | for (Enumeration appenders = logger.getAllAppenders(); (null == fileAppender) && appenders.hasMoreElements();) { 100 | Appender appender = (Appender) appenders.nextElement(); 101 | if (FileAppender.class.isInstance(appender)) { 102 | fileAppender = (FileAppender) appender; 103 | } 104 | } 105 | return fileAppender; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/utils/ResourceUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.utils; 11 | 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.io.InputStreamReader; 16 | import java.io.Reader; 17 | import java.net.URL; 18 | import java.util.Properties; 19 | 20 | 21 | /** 22 | * 23 | * @author boyan 24 | * @date 2010-5-4 25 | */ 26 | public class ResourceUtils extends Object { 27 | 28 | /** */ 29 | /** 30 | * Returns the URL of the resource on the classpath 31 | * 32 | * @param resource 33 | * The resource to find 34 | * @throws IOException 35 | * If the resource cannot be found or read 36 | * @return The resource 37 | */ 38 | public static URL getResourceURL(String resource) throws IOException { 39 | URL url = null; 40 | ClassLoader loader = ResourceUtils.class.getClassLoader(); 41 | if (loader != null) 42 | url = loader.getResource(resource); 43 | if (url == null) 44 | url = ClassLoader.getSystemResource(resource); 45 | if (url == null) 46 | throw new IOException("Could not find resource " + resource); 47 | return url; 48 | } 49 | 50 | 51 | /** */ 52 | /** 53 | * Returns the URL of the resource on the classpath 54 | * 55 | * @param loader 56 | * The classloader used to load the resource 57 | * @param resource 58 | * The resource to find 59 | * @throws IOException 60 | * If the resource cannot be found or read 61 | * @return The resource 62 | */ 63 | public static URL getResourceURL(ClassLoader loader, String resource) throws IOException { 64 | URL url = null; 65 | if (loader != null) 66 | url = loader.getResource(resource); 67 | if (url == null) 68 | url = ClassLoader.getSystemResource(resource); 69 | if (url == null) 70 | throw new IOException("Could not find resource " + resource); 71 | return url; 72 | } 73 | 74 | 75 | /** */ 76 | /** 77 | * Returns a resource on the classpath as a Stream object 78 | * 79 | * @param resource 80 | * The resource to find 81 | * @throws IOException 82 | * If the resource cannot be found or read 83 | * @return The resource 84 | */ 85 | public static InputStream getResourceAsStream(String resource) throws IOException { 86 | InputStream in = null; 87 | ClassLoader loader = ResourceUtils.class.getClassLoader(); 88 | if (loader != null) 89 | in = loader.getResourceAsStream(resource); 90 | if (in == null) 91 | in = ClassLoader.getSystemResourceAsStream(resource); 92 | if (in == null) 93 | throw new IOException("Could not find resource " + resource); 94 | return in; 95 | } 96 | 97 | 98 | /** */ 99 | /** 100 | * Returns a resource on the classpath as a Stream object 101 | * 102 | * @param loader 103 | * The classloader used to load the resource 104 | * @param resource 105 | * The resource to find 106 | * @throws IOException 107 | * If the resource cannot be found or read 108 | * @return The resource 109 | */ 110 | public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException { 111 | InputStream in = null; 112 | if (loader != null) 113 | in = loader.getResourceAsStream(resource); 114 | if (in == null) 115 | in = ClassLoader.getSystemResourceAsStream(resource); 116 | if (in == null) 117 | throw new IOException("Could not find resource " + resource); 118 | return in; 119 | } 120 | 121 | 122 | /** */ 123 | /** 124 | * Returns a resource on the classpath as a Properties object 125 | * 126 | * @param resource 127 | * The resource to find 128 | * @throws IOException 129 | * If the resource cannot be found or read 130 | * @return The resource 131 | */ 132 | public static Properties getResourceAsProperties(String resource) throws IOException { 133 | Properties props = new Properties(); 134 | InputStream in = null; 135 | String propfile = resource; 136 | in = getResourceAsStream(propfile); 137 | props.load(in); 138 | in.close(); 139 | return props; 140 | } 141 | 142 | 143 | /** */ 144 | /** 145 | * Returns a resource on the classpath as a Properties object 146 | * 147 | * @param loader 148 | * The classloader used to load the resource 149 | * @param resource 150 | * The resource to find 151 | * @throws IOException 152 | * If the resource cannot be found or read 153 | * @return The resource 154 | */ 155 | public static Properties getResourceAsProperties(ClassLoader loader, String resource) throws IOException { 156 | Properties props = new Properties(); 157 | InputStream in = null; 158 | String propfile = resource; 159 | in = getResourceAsStream(loader, propfile); 160 | props.load(in); 161 | in.close(); 162 | return props; 163 | } 164 | 165 | 166 | /** */ 167 | /** 168 | * Returns a resource on the classpath as a Reader object 169 | * 170 | * @param resource 171 | * The resource to find 172 | * @throws IOException 173 | * If the resource cannot be found or read 174 | * @return The resource 175 | */ 176 | public static InputStreamReader getResourceAsReader(String resource) throws IOException { 177 | return new InputStreamReader(getResourceAsStream(resource)); 178 | } 179 | 180 | 181 | /** */ 182 | /** 183 | * Returns a resource on the classpath as a Reader object 184 | * 185 | * @param loader 186 | * The classloader used to load the resource 187 | * @param resource 188 | * The resource to find 189 | * @throws IOException 190 | * If the resource cannot be found or read 191 | * @return The resource 192 | */ 193 | public static Reader getResourceAsReader(ClassLoader loader, String resource) throws IOException { 194 | return new InputStreamReader(getResourceAsStream(loader, resource)); 195 | } 196 | 197 | 198 | /** */ 199 | /** 200 | * Returns a resource on the classpath as a File object 201 | * 202 | * @param resource 203 | * The resource to find 204 | * @throws IOException 205 | * If the resource cannot be found or read 206 | * @return The resource 207 | */ 208 | public static File getResourceAsFile(String resource) throws IOException { 209 | return new File(getResourceURL(resource).getFile()); 210 | } 211 | 212 | 213 | /** */ 214 | /** 215 | * Returns a resource on the classpath as a File object 216 | * 217 | * @param loader 218 | * The classloader used to load the resource 219 | * @param resource 220 | * The resource to find 221 | * @throws IOException 222 | * If the resource cannot be found or read 223 | * @return The resource 224 | */ 225 | public static File getResourceAsFile(ClassLoader loader, String resource) throws IOException { 226 | return new File(getResourceURL(loader, resource).getFile()); 227 | } 228 | 229 | } -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/utils/SimpleCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2007-2012 Alibaba Group Holding Limited. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | * Authors: 8 | * leiwen , boyan 9 | */ 10 | package com.taobao.diamond.utils; 11 | 12 | import java.util.concurrent.ConcurrentHashMap; 13 | import java.util.concurrent.ConcurrentMap; 14 | 15 | import com.taobao.diamond.common.Constants; 16 | 17 | 18 | /** 19 | * 一个带TTL的简单Cache,对于过期的entry没有清理 20 | * 21 | * @author fenghan 22 | * 23 | * @param 24 | */ 25 | public class SimpleCache { 26 | 27 | private ConcurrentMap> cache; 28 | 29 | private long cacheTTL; 30 | 31 | private static class CacheEntry { 32 | public final long timestamp; 33 | public final E value; 34 | 35 | 36 | public CacheEntry(E value, long timestamp) { 37 | this.timestamp = timestamp; 38 | this.value = value; 39 | } 40 | 41 | } 42 | 43 | 44 | public SimpleCache() { 45 | this(Constants.POLLING_INTERVAL_TIME * 1000L); 46 | } 47 | 48 | 49 | public SimpleCache(long cacheTTL) { 50 | this.cache = new ConcurrentHashMap>(); 51 | this.cacheTTL = cacheTTL; 52 | } 53 | 54 | 55 | public void put(String key, E e) { 56 | if (key == null || e == null) { 57 | return; 58 | } 59 | CacheEntry entry = new CacheEntry(e, System.currentTimeMillis() + cacheTTL); 60 | cache.put(key, entry); 61 | } 62 | 63 | 64 | public E get(String key) { 65 | E result = null; 66 | CacheEntry entry = cache.get(key); 67 | if (entry != null) { 68 | if (entry.timestamp > System.currentTimeMillis()) { 69 | result = entry.value; 70 | } 71 | } 72 | 73 | return result; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /diamond-utils/src/main/java/com/taobao/diamond/utils/TimeUtils.java: -------------------------------------------------------------------------------- 1 | package com.taobao.diamond.utils; 2 | 3 | import java.sql.Timestamp; 4 | import java.util.Date; 5 | 6 | 7 | public class TimeUtils { 8 | 9 | public static Timestamp getCurrentTime() { 10 | Date date = new Date(); 11 | return new Timestamp(date.getTime()); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 2010 6 | com.taobao.diamond 7 | diamond-all 8 | pom 9 | 2.0.5.4.taocode-SNAPSHOT 10 | taobao diamond v${project.version} 11 | 12 | 13 | UTF-8 14 | 15 | 16 | 17 | diamond-client 18 | diamond-sdk 19 | diamond-server 20 | diamond-utils 21 | 22 | 23 | 24 | 25 | 26 | com.atlassian.maven.plugins 27 | maven-clover2-plugin 28 | 29 | clover.license 30 | true 31 | 32 | **/notjunit/*.java 33 | 34 | true 35 | true 36 | 37 | 38 | 39 | org.apache.maven.plugins 40 | maven-eclipse-plugin 41 | 2.5.1 42 | 43 | true 44 | false 45 | 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-surefire-plugin 50 | 2.3 51 | 52 | -Xms512m -Xmx1024m 53 | always 54 | 55 | **/*Test.java 56 | 57 | 58 | 59 | 60 | org.apache.maven.plugins 61 | maven-site-plugin 62 | 63 | zh_CN 64 | GBK 65 | GBK 66 | 67 | 68 | 69 | 70 | org.apache.maven.plugins 71 | maven-release-plugin 72 | 2.0-beta-9 73 | 74 | http://www.xx.com/repos/diamond/tags 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | ${pom.groupId} 85 | diamond-client 86 | ${project.version} 87 | 88 | 89 | ${pom.groupId} 90 | diamond-utils 91 | ${project.version} 92 | 93 | 94 | javax.servlet 95 | servlet-api 96 | 2.5 97 | provided 98 | 99 | 100 | jstl 101 | jstl 102 | 1.1.2 103 | 104 | 105 | taglibs 106 | standard 107 | 1.1.2 108 | 109 | 110 | org.springframework 111 | spring-jdbc 112 | 3.1.1.RELEASE 113 | 114 | 115 | org.springframework 116 | spring-webmvc 117 | 3.1.1.RELEASE 118 | 119 | 120 | 121 | mysql 122 | mysql-connector-java 123 | 5.1.5 124 | 125 | 126 | 127 | log4j 128 | log4j 129 | 1.2.14 130 | 131 | 132 | commons-logging 133 | commons-logging 134 | 1.1 135 | 136 | 137 | commons-httpclient 138 | commons-httpclient 139 | 3.1 140 | 141 | 142 | commons-dbcp 143 | commons-dbcp 144 | 1.2.2 145 | 146 | 147 | commons-io 148 | commons-io 149 | 1.4 150 | 151 | 152 | commons-lang 153 | commons-lang 154 | 2.6 155 | 156 | 157 | 158 | org.codehaus.jackson 159 | jackson-core-lgpl 160 | 1.4.0 161 | 162 | 163 | org.codehaus.jackson 164 | jackson-mapper-lgpl 165 | 1.4.0 166 | 167 | 168 | 169 | junit 170 | junit 171 | 4.4 172 | test 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | org.apache.maven.plugins 181 | maven-javadoc-plugin 182 | 2.5 183 | 184 | GBK 185 | GBK 186 | 187 | 188 | 189 | 190 | javadoc 191 | 192 | 193 | 194 | 195 | 196 | 197 | org.apache.maven.plugins 198 | maven-surefire-report-plugin 199 | 2.4.2 200 | 201 | 202 | org.apache.maven.plugins 203 | maven-checkstyle-plugin 204 | 2.3 205 | 206 | checkstyle.xml 207 | 208 | 209 | 210 | org.apache.maven.plugins 211 | maven-clover-plugin 212 | 213 | clover.license 214 | true 215 | true 216 | true 217 | 218 | 219 | 220 | org.apache.maven.plugins 221 | maven-pmd-plugin 222 | 223 | true 224 | 1.6 225 | 226 | 227 | 228 | org.codehaus.mojo 229 | findbugs-maven-plugin 230 | 2.0.1 231 | 232 | true 233 | true 234 | true 235 | 236 | 237 | 238 | maven-compiler-plugin 239 | 240 | 1.7 241 | 1.7 242 | UTF-8 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | --------------------------------------------------------------------------------