├── diamond-server
├── src
│ └── main
│ │ ├── resources
│ │ ├── node.properties
│ │ ├── user.properties
│ │ ├── system.properties
│ │ ├── jdbc.properties
│ │ └── log4j.properties
│ │ ├── webapp
│ │ ├── jsp
│ │ │ ├── 400.jsp
│ │ │ ├── admin
│ │ │ │ ├── config
│ │ │ │ │ ├── batch_result.jsp
│ │ │ │ │ ├── edit.jsp
│ │ │ │ │ ├── list.jsp
│ │ │ │ │ ├── new.jsp
│ │ │ │ │ ├── upload.jsp
│ │ │ │ │ └── list_json.jsp
│ │ │ │ ├── menu.jsp
│ │ │ │ ├── count.jsp
│ │ │ │ ├── user
│ │ │ │ │ ├── list.jsp
│ │ │ │ │ └── new.jsp
│ │ │ │ ├── welcome.jsp
│ │ │ │ └── admin.jsp
│ │ │ ├── 503.jsp
│ │ │ ├── 500.jsp
│ │ │ ├── login.jsp
│ │ │ ├── 200.jsp
│ │ │ └── common
│ │ │ │ └── message.jsp
│ │ ├── META-INF
│ │ │ └── MANIFEST.MF
│ │ ├── js
│ │ │ ├── validation_cn.js
│ │ │ ├── fabtabulous.js
│ │ │ └── tooltips.js
│ │ └── WEB-INF
│ │ │ ├── diamond-servlet.xml
│ │ │ ├── applicationContext.xml
│ │ │ └── web.xml
│ │ └── java
│ │ └── com
│ │ └── taobao
│ │ └── diamond
│ │ └── server
│ │ ├── controller
│ │ ├── ServerAddressController.java
│ │ ├── NotifyController.java
│ │ ├── LoginController.java
│ │ ├── ConfigServlet.java
│ │ └── ConfigController.java
│ │ ├── exception
│ │ └── ConfigServiceException.java
│ │ ├── utils
│ │ ├── GlobalCounter.java
│ │ ├── SessionHolder.java
│ │ ├── DiamondUtils.java
│ │ ├── SystemConfig.java
│ │ └── PaginationHelper.java
│ │ ├── listener
│ │ └── AuthorizationFilter.java
│ │ └── service
│ │ ├── DumpConfigInfoTask.java
│ │ ├── TimerTaskService.java
│ │ ├── AdminService.java
│ │ ├── NotifyService.java
│ │ └── DiskService.java
├── release.xml
└── pom.xml
├── .gitignore
├── diamond-client
├── src
│ ├── test
│ │ ├── resources
│ │ │ └── diamond.properties
│ │ └── java
│ │ │ └── ClientTest.java
│ └── main
│ │ └── java
│ │ └── com
│ │ └── taobao
│ │ └── diamond
│ │ ├── manager
│ │ ├── impl
│ │ │ ├── PropertiesListener.java
│ │ │ └── DefaultDiamondManager.java
│ │ ├── ManagerListenerAdapter.java
│ │ ├── ManagerListener.java
│ │ └── DiamondManager.java
│ │ ├── client
│ │ ├── processor
│ │ │ ├── ServerAddressProcessor.java
│ │ │ ├── SnapshotConfigInfoProcessor.java
│ │ │ └── LocalConfigInfoProcessor.java
│ │ ├── SubscriberListener.java
│ │ ├── impl
│ │ │ ├── DiamondClientFactory.java
│ │ │ └── DefaultSubscriberListener.java
│ │ ├── DiamondClientSub.java
│ │ └── DiamondSubscriber.java
│ │ ├── configinfo
│ │ ├── ConfigureInfomation.java
│ │ └── CacheData.java
│ │ └── mockserver
│ │ └── MockServer.java
└── pom.xml
├── diamond-sdk
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── taobao
│ │ └── diamond
│ │ ├── domain
│ │ ├── DiamondConf.java
│ │ ├── ContextResult.java
│ │ ├── DiamondSDKConf.java
│ │ ├── PageContextResult.java
│ │ └── BatchContextResult.java
│ │ ├── util
│ │ ├── DiamondUtils.java
│ │ ├── PatternUtils.java
│ │ ├── RandomDiamondUtils.java
│ │ └── ResourceUtils.java
│ │ └── sdkapi
│ │ ├── DiamondSDKManager.java
│ │ └── impl
│ │ └── DiamondSDKManagerImpl.java
└── pom.xml
├── clover.license
├── diamond-utils
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── taobao
│ │ └── diamond
│ │ ├── utils
│ │ ├── TimeUtils.java
│ │ ├── JSONUtils.java
│ │ ├── SimpleCache.java
│ │ ├── FileUtils.java
│ │ ├── LoggerInit.java
│ │ └── ResourceUtils.java
│ │ ├── io
│ │ ├── watch
│ │ │ ├── Watchable.java
│ │ │ ├── WatchEvent.java
│ │ │ ├── util
│ │ │ │ └── PathNode.java
│ │ │ ├── StandardWatchEventKind.java
│ │ │ ├── WatchService.java
│ │ │ └── WatchKey.java
│ │ ├── FileSystem.java
│ │ └── Path.java
│ │ ├── domain
│ │ ├── ConfigInfoEx.java
│ │ ├── Page.java
│ │ └── ConfigInfo.java
│ │ ├── common
│ │ └── Constants.java
│ │ └── md5
│ │ └── MD5.java
└── pom.xml
├── create_table.sql
├── README.md
└── pom.xml
/diamond-server/src/main/resources/node.properties:
--------------------------------------------------------------------------------
1 | #ip\:port=
--------------------------------------------------------------------------------
/diamond-server/src/main/resources/user.properties:
--------------------------------------------------------------------------------
1 | abc=123
2 |
--------------------------------------------------------------------------------
/diamond-server/src/main/webapp/jsp/400.jsp:
--------------------------------------------------------------------------------
1 | remote ip is null
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .svn
3 | .idea
4 | *.iml
5 | target/
6 | *.log
--------------------------------------------------------------------------------
/diamond-server/src/main/webapp/jsp/admin/config/batch_result.jsp:
--------------------------------------------------------------------------------
1 | ${json}
--------------------------------------------------------------------------------
/diamond-server/src/main/webapp/jsp/503.jsp:
--------------------------------------------------------------------------------
1 | Serivce is unavailable now.Request is refused.
--------------------------------------------------------------------------------
/diamond-client/src/test/resources/diamond.properties:
--------------------------------------------------------------------------------
1 | diamond.port=8090
2 | diamond.config.ip=127.0.0.1
--------------------------------------------------------------------------------
/diamond-server/src/main/webapp/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Class-Path:
3 |
4 |
--------------------------------------------------------------------------------
/diamond-server/src/main/resources/system.properties:
--------------------------------------------------------------------------------
1 | dump_config_interval=600
2 | diamond.server.addr=127.0.0.1
--------------------------------------------------------------------------------
/diamond-server/src/main/webapp/jsp/500.jsp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-server/src/main/webapp/jsp/500.jsp
--------------------------------------------------------------------------------
/diamond-server/src/main/webapp/jsp/login.jsp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-server/src/main/webapp/jsp/login.jsp
--------------------------------------------------------------------------------
/diamond-server/src/main/webapp/jsp/admin/menu.jsp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-server/src/main/webapp/jsp/admin/menu.jsp
--------------------------------------------------------------------------------
/diamond-server/src/main/webapp/js/validation_cn.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-server/src/main/webapp/js/validation_cn.js
--------------------------------------------------------------------------------
/diamond-server/src/main/webapp/jsp/admin/count.jsp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-server/src/main/webapp/jsp/admin/count.jsp
--------------------------------------------------------------------------------
/diamond-server/src/main/webapp/jsp/admin/user/list.jsp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/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/HEAD/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/HEAD/diamond-server/src/main/webapp/jsp/admin/welcome.jsp
--------------------------------------------------------------------------------
/diamond-server/src/main/webapp/jsp/admin/config/edit.jsp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/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/HEAD/diamond-server/src/main/webapp/jsp/admin/config/list.jsp
--------------------------------------------------------------------------------
/diamond-server/src/main/webapp/jsp/admin/config/new.jsp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/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/HEAD/diamond-server/src/main/webapp/jsp/admin/config/upload.jsp
--------------------------------------------------------------------------------
/diamond-sdk/src/main/java/com/taobao/diamond/domain/DiamondConf.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-sdk/src/main/java/com/taobao/diamond/domain/DiamondConf.java
--------------------------------------------------------------------------------
/diamond-sdk/src/main/java/com/taobao/diamond/util/DiamondUtils.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/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/HEAD/diamond-sdk/src/main/java/com/taobao/diamond/util/PatternUtils.java
--------------------------------------------------------------------------------
/diamond-sdk/src/main/java/com/taobao/diamond/domain/ContextResult.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-sdk/src/main/java/com/taobao/diamond/domain/ContextResult.java
--------------------------------------------------------------------------------
/diamond-sdk/src/main/java/com/taobao/diamond/domain/DiamondSDKConf.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/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/HEAD/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/HEAD/diamond-sdk/src/main/java/com/taobao/diamond/sdkapi/DiamondSDKManager.java
--------------------------------------------------------------------------------
/diamond-sdk/src/main/java/com/taobao/diamond/util/RandomDiamondUtils.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-sdk/src/main/java/com/taobao/diamond/util/RandomDiamondUtils.java
--------------------------------------------------------------------------------
/diamond-sdk/src/main/java/com/taobao/diamond/domain/BatchContextResult.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-sdk/src/main/java/com/taobao/diamond/domain/BatchContextResult.java
--------------------------------------------------------------------------------
/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-client/src/main/java/com/taobao/diamond/manager/impl/PropertiesListener.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-client/src/main/java/com/taobao/diamond/manager/impl/PropertiesListener.java
--------------------------------------------------------------------------------
/diamond-sdk/src/main/java/com/taobao/diamond/sdkapi/impl/DiamondSDKManagerImpl.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-sdk/src/main/java/com/taobao/diamond/sdkapi/impl/DiamondSDKManagerImpl.java
--------------------------------------------------------------------------------
/clover.license:
--------------------------------------------------------------------------------
1 | ooOPSrijRSMpkBwoEAQSTuiIrMxGWnLOtfdENlSCmVniQk
2 | mi2KTt8nwsN0xZ0yQ>773SoN2KN>MUkQEpTg>kY2ykbpJ>
3 | QOppsSpRNrMoNpqMQROSxqqQRMRPRmNOrrUVWSVStvmXXU
4 | wURnmpmUUnoumopvommmmmUUnoumopvommmmmUUvvplcqk
5 | ZljUUn
6 |
--------------------------------------------------------------------------------
/diamond-client/src/main/java/com/taobao/diamond/client/processor/ServerAddressProcessor.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-client/src/main/java/com/taobao/diamond/client/processor/ServerAddressProcessor.java
--------------------------------------------------------------------------------
/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-client/src/main/java/com/taobao/diamond/client/processor/SnapshotConfigInfoProcessor.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gzllol/diamond/HEAD/diamond-client/src/main/java/com/taobao/diamond/client/processor/SnapshotConfigInfoProcessor.java
--------------------------------------------------------------------------------
/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/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/admin/admin.jsp:
--------------------------------------------------------------------------------
1 | <%@ page contentType="text/html; charset=GBK" pageEncoding="GBK"%>
2 |
6 |
7 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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-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-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-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-server/src/main/webapp/WEB-INF/diamond-servlet.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/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/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/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/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-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-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-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-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/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-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-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-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/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-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 |
--------------------------------------------------------------------------------
/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-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/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-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-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-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-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/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-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/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-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/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/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/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/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/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-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-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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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-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-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-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
107 | * strong> 的优先顺序获取, 如果这些途径都无效,则返回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/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/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-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-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-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/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-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/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-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-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-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-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/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-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-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-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-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-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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------