├── .DS_Store ├── .gitignore ├── README-v2.0.md ├── README.md ├── build.sh ├── pom.xml ├── reference ├── cluster-design.png ├── design.png ├── design2.png ├── dispatch.png ├── image │ ├── TaskDispatch-01.png │ ├── TaskDispatch.jpg │ ├── TaskModal.jpg │ ├── TaskMonitor-01.jpg │ ├── TaskMonitor-02.jpg │ ├── TaskMonitor-03.jpg │ ├── TaskMonitor-04.jpg │ └── TaskProcess.jpg ├── monitor.png ├── page │ ├── dispatch.md │ ├── extension.md │ ├── overview.md │ ├── quickstart.md │ ├── taskconf.md │ ├── taskmonitor.md │ └── taskproduce.md └── 任务容器设计流程图.bmp ├── task-kernal ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── peaceful │ │ │ └── task │ │ │ └── kernal │ │ │ ├── NewTaskContext.java │ │ │ ├── Task.java │ │ │ ├── TaskBeanFactory.java │ │ │ ├── TaskClient.java │ │ │ ├── TaskCoding.java │ │ │ ├── TaskContext.java │ │ │ ├── TaskController.java │ │ │ ├── TaskDispatcher.java │ │ │ ├── TaskExecutor.java │ │ │ ├── TaskModule.java │ │ │ ├── TaskMonitor.java │ │ │ ├── TaskProxy.java │ │ │ ├── TaskQueue.java │ │ │ ├── annotation │ │ │ └── Task.java │ │ │ ├── client │ │ │ ├── TaskClientService.java │ │ │ └── TaskProxyByCglib.java │ │ │ ├── coding │ │ │ ├── TU.java │ │ │ ├── TUR.java │ │ │ ├── TaskCodingService.java │ │ │ └── decoding │ │ │ │ ├── InvokeContext.java │ │ │ │ ├── Magic.java │ │ │ │ ├── NotSupportParamType.java │ │ │ │ ├── Parse.java │ │ │ │ ├── ParseChain.java │ │ │ │ ├── TypeAdapter.java │ │ │ │ └── impl │ │ │ │ ├── BooleanParse.java │ │ │ │ ├── DoubleParse.java │ │ │ │ ├── EmptyParse.java │ │ │ │ ├── IntegerParse.java │ │ │ │ ├── ListParse.java │ │ │ │ ├── LongParse.java │ │ │ │ ├── MapParse.java │ │ │ │ ├── NullParse.java │ │ │ │ ├── PrimitiveParse.java │ │ │ │ ├── SetParse.java │ │ │ │ ├── StringParse.java │ │ │ │ └── UserDefinedParse.java │ │ │ ├── conf │ │ │ ├── Executor.java │ │ │ ├── ExecutorsConf.java │ │ │ ├── TaskConfService.java │ │ │ └── TaskConfigOps.java │ │ │ ├── controller │ │ │ ├── CloudController.java │ │ │ ├── LocalTaskController.java │ │ │ └── RedisCloudTaskController.java │ │ │ ├── dispatch │ │ │ ├── NoBlockAutoConsumer.java │ │ │ ├── PullTask.java │ │ │ ├── TaskBeanFactoryImpl.java │ │ │ ├── TaskDispatcherService.java │ │ │ ├── TaskMeta.java │ │ │ ├── actor │ │ │ │ ├── DispatchManagerActor.java │ │ │ │ ├── ExecutorSupervisionActor.java │ │ │ │ ├── ExecutorsManagerActor.java │ │ │ │ ├── PublicActor.java │ │ │ │ ├── TaskRouterActor.java │ │ │ │ ├── WorkerActor.java │ │ │ │ └── msg │ │ │ │ │ ├── DecorateTask.java │ │ │ │ │ └── TaskCompleted.java │ │ │ └── executor │ │ │ │ ├── JUCTaskExecutor.java │ │ │ │ └── SimpleTaskExecutor.java │ │ │ ├── helper │ │ │ ├── GetNextTaskException.java │ │ │ ├── IdGenerate.java │ │ │ ├── IllegalTaskStateException.java │ │ │ ├── NetHelper.java │ │ │ ├── Node.java │ │ │ ├── ServiceCenter.java │ │ │ └── TaskLog.java │ │ │ ├── monitor │ │ │ ├── CloudTaskCountMonitor.java │ │ │ └── LocalTaskCountMonitor.java │ │ │ ├── package-info.java │ │ │ └── queue │ │ │ ├── local │ │ │ └── LocalQueue.java │ │ │ └── redis │ │ │ └── RedisQueue.java │ └── resources │ │ ├── application.conf │ │ └── task-reference.conf │ └── test │ ├── java │ └── com │ │ └── peaceful │ │ └── task │ │ └── kernal │ │ ├── Hello.java │ │ ├── SetUp.java │ │ └── User.java │ └── resources │ └── log4j.xml └── task-ops ├── .DS_Store ├── pom.xml └── src ├── .DS_Store ├── main ├── .DS_Store ├── filters │ ├── dev.properties │ ├── product.properties │ └── test.properties ├── java │ └── com │ │ └── peaceful │ │ └── task │ │ └── ops │ │ ├── admin │ │ └── controller │ │ │ ├── ConfController.java │ │ │ ├── OnloadController.java │ │ │ ├── TaskController.java │ │ │ └── WelcomeController.java │ │ ├── common │ │ ├── ClusterConsoleFilter.java │ │ ├── Conf.java │ │ └── SQLiteHelper.java │ │ └── task │ │ └── api │ │ ├── CycleQueue.java │ │ ├── GraphData.java │ │ └── RedisControllerApi.java ├── resources │ ├── application.properties │ ├── log4j.xml │ └── taskCluster.conf └── webapp │ ├── .DS_Store │ ├── WEB-INF │ ├── page │ │ ├── ftl │ │ │ └── test.ftl │ │ └── jsp │ │ │ ├── errors │ │ │ ├── 404.jsp │ │ │ └── error.jsp │ │ │ ├── help │ │ │ └── index.jsp │ │ │ ├── test.jsp │ │ │ └── welcome │ │ │ ├── index.jsp │ │ │ ├── template01.jsp │ │ │ ├── template02.jsp │ │ │ ├── template03.jsp │ │ │ └── template04.jsp │ ├── springMvc-servlet.xml │ └── web.xml │ ├── css │ ├── bootstrap-3.5.css │ ├── bootstrap-theme-3.5.css │ ├── font-awesome.min.css │ ├── ionicons.min.css │ └── metisMenu.min.css │ ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ ├── glyphicons-halflings-regular.woff2 │ ├── ionicons.eot │ ├── ionicons.svg │ ├── ionicons.ttf │ └── ionicons.woff │ ├── image │ ├── 123.png │ └── header.jpg │ ├── js │ ├── Chart.js │ ├── bootstrap-3.5.js │ ├── echart │ │ ├── chart │ │ │ ├── bar.js │ │ │ ├── chord.js │ │ │ ├── eventRiver.js │ │ │ ├── force.js │ │ │ ├── funnel.js │ │ │ ├── gauge.js │ │ │ ├── heatmap.js │ │ │ ├── k.js │ │ │ ├── line.js │ │ │ ├── map.js │ │ │ ├── pie.js │ │ │ ├── radar.js │ │ │ ├── scatter.js │ │ │ ├── tree.js │ │ │ ├── treemap.js │ │ │ ├── venn.js │ │ │ └── wordCloud.js │ │ ├── echarts-all.js │ │ └── echarts.js │ ├── helper │ │ └── Map.js │ ├── holder.js │ ├── jquery-1.9.1.js │ ├── jquery-2.2.2.js │ ├── jquery-ui.min.js │ ├── metisMenu.min.js │ └── page │ │ ├── index.js │ │ └── nav.js │ ├── static │ ├── .DS_Store │ ├── image │ │ ├── TaskDispatch-01.png │ │ ├── TaskDispatch.jpg │ │ ├── TaskModal.jpg │ │ ├── TaskMonitor-01.jpg │ │ ├── TaskMonitor-02.jpg │ │ ├── TaskMonitor-03.jpg │ │ ├── TaskMonitor-04.jpg │ │ └── TaskProcess.jpg │ ├── page │ │ ├── dispatch.html │ │ ├── extension.html │ │ ├── overview.html │ │ ├── quickstart.html │ │ ├── taskconf.html │ │ ├── taskmonitor.html │ │ └── taskproduce.html │ ├── template01 │ │ └── dashboard.css │ ├── template02 │ │ ├── sb-admin-2.css │ │ └── sb-admin-2.js │ ├── template03 │ │ └── simple-sidebar.css │ └── template04 │ │ ├── AdminLTE.min.css │ │ ├── app.js │ │ ├── app.min.js │ │ ├── dashboard.js │ │ ├── dashboard2.js │ │ ├── demo.js │ │ ├── img │ │ ├── avatar.png │ │ ├── avatar04.png │ │ ├── avatar2.png │ │ ├── avatar3.png │ │ ├── avatar5.png │ │ ├── boxed-bg.jpg │ │ ├── boxed-bg.png │ │ ├── credit │ │ │ ├── american-express.png │ │ │ ├── cirrus.png │ │ │ ├── mastercard.png │ │ │ ├── mestro.png │ │ │ ├── paypal.png │ │ │ ├── paypal2.png │ │ │ └── visa.png │ │ ├── default-50x50.gif │ │ ├── icons.png │ │ ├── photo1.png │ │ ├── photo2.png │ │ ├── photo3.jpg │ │ ├── photo4.jpg │ │ ├── user1-128x128.jpg │ │ ├── user2-160x160.jpg │ │ ├── user3-128x128.jpg │ │ ├── user4-128x128.jpg │ │ ├── user5-128x128.jpg │ │ ├── user6-128x128.jpg │ │ ├── user7-128x128.jpg │ │ └── user8-128x128.jpg │ │ ├── pages │ │ ├── dashboard.js │ │ └── dashboard2.js │ │ └── skins │ │ ├── _all-skins.css │ │ ├── _all-skins.min.css │ │ ├── skin-black-light.css │ │ ├── skin-black-light.min.css │ │ ├── skin-black.css │ │ ├── skin-black.min.css │ │ ├── skin-blue-light.css │ │ ├── skin-blue-light.min.css │ │ ├── skin-blue.css │ │ ├── skin-blue.min.css │ │ ├── skin-green-light.css │ │ ├── skin-green-light.min.css │ │ ├── skin-green.css │ │ ├── skin-green.min.css │ │ ├── skin-purple-light.css │ │ ├── skin-purple-light.min.css │ │ ├── skin-purple.css │ │ ├── skin-purple.min.css │ │ ├── skin-red-light.css │ │ ├── skin-red-light.min.css │ │ ├── skin-red.css │ │ ├── skin-red.min.css │ │ ├── skin-yellow-light.css │ │ ├── skin-yellow-light.min.css │ │ ├── skin-yellow.css │ │ └── skin-yellow.min.css │ └── template │ ├── 01 │ ├── nav.jsp │ ├── pageFooter.jsp │ └── pageHeader.jsp │ ├── 02 │ ├── nav.jsp │ ├── pageFooter.jsp │ └── pageHeader.jsp │ ├── 03 │ ├── nav-02.jsp │ ├── nav.jsp │ ├── pageFooter.jsp │ └── pageHeader.jsp │ ├── 04 │ ├── index.html │ ├── nav.jsp │ ├── pageFooter.jsp │ └── pageHeader.jsp │ └── myModal.jsp └── test ├── java └── msg └── resources ├── log4j.properties └── log4j.xml /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | */*.iml 3 | *.idea 4 | */target/* 5 | target/* 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Task系统设计与使用 2 | ---------------- 3 | 4 | Task是一个轻量级的分布式任务计算系统,他可以帮助你快速编写一个可以在集群环境下运行的分布式方法,而这只需要你使用一行代码就可以在你原有的方法上做到. 5 | 6 | 一个简单例子: 7 | 8 | ```` 9 | 10 | public class Hello { 11 | 12 | public void say(String msg) throws InterruptedException { 13 | Thread.sleep(1000); 14 | System.out.println(msg); 15 | } 16 | } 17 | 18 | 19 | public class SetUp { 20 | 21 | public static void main(String[] args) throws InterruptedException { 22 | // 获取Hello对象的代理实例 23 | Hello hello = Task.registerASyncClass(Hello.class); 24 | // 此时say方法会被立即返回且是被集群中的某个节点给调用执行 25 | hello.say("hello world"); 26 | } 27 | } 28 | 29 | ```` 30 | 31 | ## Task说明文档 32 | 33 | 此文档只适合2.6-SNAPSHOT版本 34 | 35 | 1. [概述](./reference/page/overview.md) 36 | 2. [快速上手](./reference/page/quickstart.md) 37 | 2. [Task配置](./reference/page/taskconf.md) 38 | 2. [任务生产](./reference/page/taskproduce.md) 39 | 2. [调度策略](./reference/page/dispatch.md) 40 | 2. [可扩展](./reference/page/extension.md) 41 | 2. [监控部署](./reference/page/taskmonitor.md) 42 | 3. ...待更新 43 | 44 | 45 | ## 交流 46 | 47 | QQ群:365133362 群名称:互联网从业者 -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #======================== 3 | # create by WangJun 4 | # date 2014-11-06 5 | # email wangjuntytl@163.com 6 | # 7 | # ============================= 8 | # 9 | # 描述:构建脚本 10 | # 11 | # 如果你的开发平台是window,需要手动执行以下步骤 12 | # 1. git clone https://github.com/WangJunTYTL/peaceful-basic-platform.git 13 | # 2. 进入peaceful-basic-platform 目录 ,先执行 mvn clean -f peaceful-parent/pom.xml install -Dmaven.test.skip=true 后执行 mvn install -Dmaven.test.skip=true 14 | # 3. git clone https://github.com/WangJunTYTL/redismanage.git 15 | # 4. 进入redismanage 目录 ,执行 mvn install -Dmaven.test.skip=true 16 | # 5. 进入task目录,执行 mvn install -Dmaven.test.skip=true 17 | #================================== 18 | 19 | source /etc/profile 20 | ENV=$1 21 | [ "x${ENV}" == "x" ] && ENV='dev' # dev test product 22 | echo '----------------------------------------------' 23 | echo "构建环境:${ENV}" 24 | echo '----------------------------------------------' 25 | echo "构建工具git、mvn 安装检测" 26 | 27 | cmd_is_exist(){ 28 | echo "check $1 cmd is install ... " 29 | _r=`which $1` 30 | if [ $? == 0 ];then 31 | echo "OK" 32 | else 33 | echo "请先安装$1,并添加$1到PATH变量中" && exit 1 34 | fi 35 | } 36 | 37 | cmd_is_exist "mvn" 38 | cmd_is_exist "git" 39 | echo '----------------------------------------------' 40 | 41 | wait 42 | echo "准备下载依赖包并开始构建 ..." 43 | 44 | #下载依赖包,最好手动将依赖包install到你的本地仓库 45 | echo "下载依赖包peaceful-basic-platform" 46 | [ -d "peaceful-basic-platform" ] && rm -rf peaceful-basic-platform 47 | git clone https://github.com/WangJunTYTL/peaceful-basic-platform.git || exit 1 48 | cd peaceful-basic-platform 49 | mvn clean -P${ENV} -f peaceful-parent/pom.xml install -Dmaven.test.skip=true || exit 1 50 | mvn clean -P${ENV} install -Dmaven.test.skip=true || exit 1 51 | cd .. 52 | 53 | echo "下载依赖包redismanage" 54 | [ -d "redismanage" ] && rm -rf redismanage 55 | git clone https://github.com/WangJunTYTL/redismanage.git || exit 1 56 | cd redismanage 57 | mvn clean -P${ENV} install -Dmaven.test.skip=true || exit 1 58 | cd .. 59 | 60 | wait 61 | rm -rf peaceful-basic-platform 62 | rm -rf redismanage 63 | 64 | mvn -P${ENV} clean install -Dmaven.test.skip=true -U || exit 1 65 | echo '-------------------------------------------------------------------------------' 66 | echo "恭喜你,构建成功!" 67 | echo '-------------------------------------------------------------------------------' 68 | 69 | 70 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.peaceful 8 | task 9 | 2.6-SNAPSHOT 10 | pom 11 | 12 | 13 | task-kernal 14 | task-ops 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /reference/cluster-design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/cluster-design.png -------------------------------------------------------------------------------- /reference/design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/design.png -------------------------------------------------------------------------------- /reference/design2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/design2.png -------------------------------------------------------------------------------- /reference/dispatch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/dispatch.png -------------------------------------------------------------------------------- /reference/image/TaskDispatch-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/image/TaskDispatch-01.png -------------------------------------------------------------------------------- /reference/image/TaskDispatch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/image/TaskDispatch.jpg -------------------------------------------------------------------------------- /reference/image/TaskModal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/image/TaskModal.jpg -------------------------------------------------------------------------------- /reference/image/TaskMonitor-01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/image/TaskMonitor-01.jpg -------------------------------------------------------------------------------- /reference/image/TaskMonitor-02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/image/TaskMonitor-02.jpg -------------------------------------------------------------------------------- /reference/image/TaskMonitor-03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/image/TaskMonitor-03.jpg -------------------------------------------------------------------------------- /reference/image/TaskMonitor-04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/image/TaskMonitor-04.jpg -------------------------------------------------------------------------------- /reference/image/TaskProcess.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/image/TaskProcess.jpg -------------------------------------------------------------------------------- /reference/monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/monitor.png -------------------------------------------------------------------------------- /reference/page/dispatch.md: -------------------------------------------------------------------------------- 1 | 调度策略 2 | ------------- 3 | 4 | 为了更灵活的控制任务调度,Task专门设计了一个无阻塞调度模型,支持以下特点 5 | 6 | 1. 任务的开始\暂停\结束 7 | 2. 优先级配置,为不同优先级的任务分配不同性能的Executor 8 | 3. 任务路由控制,可以控制任务在指定的节点运行 9 | 4. 设置节点的运行模式,可分为server和client模式,在client模式下只可以提交任务 10 | 5. 专门设计的dispatch模块,可以减少因为宕机或特别原因引起的任务丢失 11 | 6. 任务监管模式设计,可以在异常时自动尝试或重启 12 | 13 | 14 | ## 节点调度模型 15 | 16 | 17 | 18 | Task采用主动拉取的方式进行任务分配,每个节点可以根据当前机器的性能去执行任务.在拉取模式中主要分为外部拉取[OutDispatch]和内部拉取[InnerDispatch]. 19 | 它们主要的区别是:OutDispatch会定时到MQ服务中拉取任务,默认是1s.如果有任务就会交给Executor执行,Executor在执行完后都会通知InnerDispatch,InnerDispatch会 20 | 根据收到的通知消息来判断任务的执行情况去决定InnerDispatch是否需要到MQ中拉取任务在派给该Executor.下面是一个正常的任务执行完成后Executor发给InnerDispatch的消息 21 | 22 | ```` 23 | completed Test07-wangjun的MacBook-main-55083111199 on default remote wait 77121982ms local wait 103ms cost 1003ms 24 | ```` 25 | 26 | 这条消息的意思是说:Test07-wangjun的MacBook-main-55083111199这条任务在名为default的Executor执行,该任务在从MQ到拉取到该节点前在MQ中存储的时间是77121982ms, 27 | 本地等待Executor执行的时间是103ms,任务执行耗时是1003ms 28 | 29 | 按照上述理论,如果一个Executor支持同时执行8个任务,每个任务用时都是1s,那它达到最大并发的时间是8s,它的消费速率变化应该如下所示 30 | 31 | 32 | 33 | 这样设计的目的:第一规避了节点盲目访问MQ的问题.第二节点可以在合适的时间从MQ拉取,不会照成任务拉取到本地而不能被及时被执行的问题. 34 | 35 | ## 集群调度控制 36 | 集群调度控制是从宏观上进行任务干预,控制集群中每个节点。 37 | 38 | ### 设置节点模式 39 | 40 | 节点模式分为server和client模式,在client模式下任务只可以提交不可以消费。server模式是既可以消费也可以生成任务。这样设计的目的是你可以根据机器的用途,单独划分出消费机器。设置模式的方式有两种,第一在启动前设置: 41 | 42 | 1. 可以通过启动时添加java命令参数: -Dtask.boot.mode=server[client] 43 | 2. 也可以在配置文件中指定:boot-mode = "server"["client"] 44 | 3. 在运行时也可以切换模式,已在监控部署章节描述 45 | 46 | 注意:各种方式的区别,在运行前如果指定为client模式,Task将不会启动Dispatch和Executor模块,且设置后不可以在运行期进行模式切换 47 | 48 | ### 设置任务路由 49 | 50 | 控制任务在指定的节点消费的功能在实际使用中很有用处。比如你正在预发布环境测试一个功能,在分布式环境下你很难进行回测,但你把任务指定带指定的机器问题就转变的简单了。另外,如果你发现某个任务阻塞到了其它任务调度而系统的调度算法又不可以很好的解决阻塞,我们可以认为干预它的调度,为它单独分配资源,避免阻塞其它资源 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /reference/page/extension.md: -------------------------------------------------------------------------------- 1 | 可扩展 2 | ------------ 3 | 4 | Task的设计是定位是作为一款分布式任务执行引擎。可以本身单独运行,也可以灵活方便的和其它系统组件配合使用。 5 | 6 | ### 扩展MQ组件 7 | 8 | Task默认的MQ组件实现是基于Redis的List数据结构。具体可参考:com.peaceful.task.queue.redis.RedisQueue。有关Redis的配置使用可参考:https://github.com/WangJunTYTL/redismanage 9 | 10 | 如果你要对接自己公司内部的MQ组件,需要继承TaskQueue接口:实现如下接口 11 | 12 | ``` 13 | public interface TaskQueue { 14 | 15 | 16 | boolean push(String name, T object); 17 | 18 | T pop(String name); 19 | 20 | long size(String key); 21 | } 22 | ``` 23 | 24 | 另外需要在配置文件中设置: queue = "MQ实现类全名" 25 | 26 | ### 扩展BeanFactory 27 | 28 | Task在被执行时,需要获取任务所属的实例,Task默认的Bean管理方式是通过反射获取实例并缓存起来。如果你想自己管理Bean实例或某些bean实例被DI容器管理再或者某些复杂的bean需要自己手动实例,你可以实现 29 | TaskBeanFactory接口: 30 | 31 | ``` 32 | public interface TaskBeanFactory { 33 | 34 | 35 | T getBean(Class zclass); 36 | 37 | // 对于复杂的bean手动实例化并添加到BeanFactory 38 | void newInstance(Object instance); 39 | 40 | } 41 | 42 | ``` 43 | 另外需要在配置文件中设置: bean-factory = "BeanFactory实现类全名" 44 | 45 | ### 扩展Executor 46 | 47 | Task在执行时会被回放成一个Runnable对象交给Executor执行,Task是建议用户管理自己Executor,这样可以方便用户隔离不同的任务,可以支持任务的优先级、防止任务阻塞的特性。Task默认只是给了3个样例,它们的特点是: 48 | 49 | 1. com.peaceful.task.executor.impl.actor.ActorTaskExecutor: 交由Dispatch模块管理运行任务 50 | 2. com.peaceful.task.executor.impl.SimpleTaskExecutor: 直接执行任务 51 | 3. com.peaceful.task.executor.impl.JUCTaskExecutor: 利用JUC包下的Executors框架实现 52 | 53 | 在一个Task系统下可以支持同时启动多个Executor,有关配置可以参照task-reference.conf配置文件 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /reference/page/overview.md: -------------------------------------------------------------------------------- 1 | 2 | Task系统设计与使用 3 | ---------------- 4 | 5 | Task是一个轻量级的分布式任务计算系统,它可以帮助你快速编写一个可以在集群环境下运行的分布式方法,而这只需要你使用一行代码就可以在你原有的方法上做到. 6 | 7 | 一个简单例子: 8 | 9 | ```` 10 | 11 | public class Hello { 12 | 13 | public void say(String msg) throws InterruptedException { 14 | Thread.sleep(1000); 15 | System.out.println(msg); 16 | } 17 | } 18 | 19 | 20 | public class SetUp { 21 | 22 | public static void main(String[] args) throws InterruptedException { 23 | // 获取Hello对象的代理实例 24 | Hello hello = Task.registerASyncClass(Hello.class); 25 | // 此时say方法会被立即返回且是被集群中的某个节点给调用了 26 | hello.say("hello world"); 27 | } 28 | } 29 | 30 | ```` 31 | ## Task支持业务场景 32 | 33 | Task的设计的目的是支持分布式任务计算,可以作为一款任务执行引擎.支持一下特点: 34 | 35 | 1. 支持任务的开始\暂停\删除 36 | 1. 采用多种调度算法,可以指定任务在特定节点消费\在不同的Executor上执行 37 | 1. 扩展性强,可以对接各种mq服务\executor模块\支持Spring的BeanFactory或者第三方DI容器 38 | 1. 支持分布式任务执行,整个调用过程可以让开发者无感知 39 | 1. 携带监控系统,可以随时了解系统运行的状态 40 | 41 | 42 | ## Task系统架构 43 | Task主要分为以下几个模块: 44 | 45 | 46 | 47 | **ClientProxy:** 用于获取任务提交的代理对象,如上`Task.registerASyncClass(Hello.class)`可以获取Hello对象的代理实例,用于提交任务到mq服务。 48 | 49 | **Coding:** 可以对方法的调用动作进行描述和重放方法的执行,并可以对描述信息进行序列化存取到mq服务和反序列化成一个Runnable对象 50 | 51 | **MQ:** 用于存放方法调用信息描述的地方,默认支持Redis的List结构队列,并预留扩展用于对接各个MQ组件 52 | 53 | **Controller:** 任务调度的控制中心,负责任务调度路由,任务的开始、暂停等动作 54 | 55 | **Diapatch:** Task采用的是拉取的方式进行任务调用。Dispatch模块设计的目的主要是合适的时间去从MQ中拉取任务并监管任务的执行情况,异常处理 56 | 57 | **BeanFactory:** 任务所属对象的Bean管理,默认采用google的guice管理,已预留扩展,可以方便支持其它DI容器,可以方便扩展Spring的BeanFactory 58 | 59 | **Executor:** 任务真正执行的地方,Dispatch模块会把拉取到任务通过Coding转成Runnable对象,并交给Executor模块,Executor模块类似于本地的ExecutorService框架,用于本地的并发模型。已预留扩展,可以实现自己的Executor模块 60 | 61 | ## 你想好了吗 62 | 63 | 你是否真的需要这样的一个工具,到底是异步还是同步,什么样的才可以称的上任务。在使用前,希望你也可以考虑清楚这些问题。这里我需要声明的是, 64 | `能同步的最好不要异步`。异步分布执行虽然可以提高系统吞吐量,但它是在高于一定得计算量请求量的情况下才可以显现出来这一特点。当你决定需要它时, 65 | 你就要决定放弃及时响应的特性,虽然它可以达到近实时的计算(在无压力下,一个任务默认可能会出现延迟1s执行,这个时间可以设置)。另外,你是否需要的是一个分布式的异步并行框架, 66 | 还是JDK自带的单机并发框架,如果`executorservice`就可以满足了,那你也不必使用它了,虽然我个人觉得这个在使用时会更方便,但我并不想让你那么做,`能满足需求就好`, 67 | 方案永远不止一个,用你最熟悉的吧。 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /reference/page/quickstart.md: -------------------------------------------------------------------------------- 1 | Task快速上手 2 | --------------- 3 | 4 | 这里主要目的是帮助你快速上手,为了没这么多麻烦,你有必要按照以下步骤完整的学习下,如果你正在使用window系统,需要按照build.sh脚本的步骤一步步实践 5 | 6 | ## 为构建做准备 7 | 8 | Task默认采用maven的方式进行依赖管理和构建.所以这之前请确认你已经安装了maven.另外由于在构建过程中会去到github上拉取其它依赖项目,所以在 9 | 这之前还有必要安装git 10 | 11 | ## 开始构建 12 | 13 | 准备动作完成后,构建过程就很简单了,只需要执行`build.sh`即可,如果构架成功,会在最后提示:恭喜你,构建成功! 14 | 15 | ## 实践 16 | 17 | 下面就可以在实际项目中操练了.你需要新建一个项目,或是在你的实际项目中,引入以下依赖: 18 | 19 | ```` 20 | 21 | com.peaceful 22 | task-system 23 | 24 | XX-SNAPSHOT 25 | 26 | ```` 27 | 然后像最开始说的代码样例进行尝试 28 | 29 | ```` 30 | 31 | public class Hello { 32 | 33 | public void say(String msg) throws InterruptedException { 34 | Thread.sleep(1000); 35 | System.out.println(msg); 36 | } 37 | } 38 | 39 | 40 | public class SetUp { 41 | 42 | public static void main(String[] args) throws InterruptedException { 43 | // 获取Hello对象的代理实例 44 | Hello hello = Task.registerASyncClass(Hello.class); 45 | // 此时say方法会被立即返回且是被集群中的某个节点给调用了 46 | hello.say("hello world"); 47 | } 48 | } 49 | 50 | ```` 51 | 52 | ## 启动Redis服务 53 | 54 | 在本地启动redis服务.采用默认连接:127.0.0.1:6379 55 | 56 | 运行上面的SetUp方法并观察结果 57 | -------------------------------------------------------------------------------- /reference/page/taskconf.md: -------------------------------------------------------------------------------- 1 | Task配置 2 | --------------- 3 | 4 | Task在启动时会首先加载默认的配置文件:task-reference.conf,然后再去加载用户自定义的配置文件。 5 | 用户自定义配置文件默认路径是classpath下的task.conf文件,也可以在启动时通过-Dtask.conf.file fileName指定用户配置文件路径。 6 | 7 | **注意:** 8 | 1. 如果用户没有提供自己的配置文件,系统会使用默认的参数配置,即只加载task-reference.conf的配置。 9 | 2. 如果用户有自己的配置文件,用户自定义配置和系统配置采用合并的策略,对于同样的配置项用户配置会覆盖系统默认配置 10 | 11 | ### 默认配置信息如下: 12 | 13 | ``` 14 | task { 15 | 16 | # 系统命名,主要用于创建多个系统实例时的命名空间的区分 17 | name = "TASK" 18 | 19 | # 启动模式,如果是client模式,只可以提交任务,不会调度任务执行,server模式可提交任务,也可以调度任务执行 20 | boot-mode = "server" # server[client] 21 | 22 | # 开发模式,在test模式下,系统会打印更多的日志信息 23 | develop-mode = "test" # test[product] 24 | 25 | # 任务队列实现,你也可以实现自己的队列通过继承TaskQueue 26 | queue = "com.peaceful.task.queue.redis.RedisQueue" 27 | 28 | # 任务bean实例获取工厂,任务在被执行时,需要获取任务的实例,你也可以实现自己的bean管理工厂,比如对接Spring的BeanFactory或其它DI容器 29 | bean-factory = "com.peaceful.task.context.dispatch.TaskBeanFactoryImpl" 30 | 31 | // 任务执行器 32 | executor = [ 33 | { 34 | name: "default" 35 | # 系统默认的executor实现,基于akka的actor并发模型 36 | implementation: "com.peaceful.task.executor.impl.actor.ActorTaskExecutor" 37 | }, 38 | { 39 | name: "simple" 40 | # 最简单的executor实现 41 | implementation: "com.peaceful.task.executor.impl.SimpleTaskExecutor" 42 | }, 43 | { 44 | name: "jucExecutor" 45 | implementation: "com.peaceful.task.executor.impl.JUCTaskExecutor" 46 | } 47 | ] 48 | 49 | # 从MQ中拉取任务的频率 50 | dispatch-tick = 2s 51 | } 52 | ``` 53 | -------------------------------------------------------------------------------- /reference/page/taskmonitor.md: -------------------------------------------------------------------------------- 1 | 监控部署 2 | ----------- 3 | 监控项目是独立于Task项目之外,你可以通过监控项目随时了解你的Task系统的运行情况,并可以通过监控进行一些简单的设置 4 | 5 | ## 部署方式 6 | 7 | 如果你已经成功启动Task项目并看到了预期的结果,你在去部署监控项目也不迟.你可以通过默认携带的jetty插件启动监控项目,进入到task-ops目录运行以下命令: 8 | 9 | mvn jetty:run 10 | 11 | 项目启动成功后访问:127.0.0.1:8888,你将看到以下内容 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | **01 **Task集群列表,其中集群的名字和task.conf配置的name要一致 20 | 21 | **02、03 **任务消费和生成的实时速率,左侧图表是整体速率,右侧是每个队列的消费生成速率 22 | 23 | **04 **正在调度中的任务列表 24 | 25 | **05 **集群列表 26 | 27 | **06 **系统启动的Executor列表 28 | 29 | **07 **系统已完成调度任务列表 30 | 31 | **08 **可以具体查看任务信息并可以配置任务的调度策略 32 | 33 | **09 **查看节点信息,并可以配置节点的运行模式 34 | 35 | 关于调度策略和运行模式会在下文解释 36 | 37 | 38 | -------------------------------------------------------------------------------- /reference/page/taskproduce.md: -------------------------------------------------------------------------------- 1 | 任务生产 2 | --------------- 3 | 4 | Task是一个轻量级的任务分布式计算系统,它突出的轻量级特点之一就是可以让开发者以最快、最简洁的方式编写自己的分布式方法。如果你在review这样的代码时稍不留心 5 | 也许这个方法就是一个分布式地方法。 6 | 7 | ## 获取对象代理 8 | 9 | 生产任务的方式已在概述中列出了一个例子,你只需要向下面这样获得一个对象的代理实例即可,例如 10 | 11 | Hello hello = Task.registerASyncClass(Hello.class); 12 | 13 | 此时Hello对象下的方法就变成了一个分布式的任务生产方法。原理上它是获得对象的代理实例,把方法的调用描述成一个可以在集群中的任意一个节点在被回放执行且可以暂时存取到MQ组件中的一种调用描述。 14 | 由coding模块负责实现这种描述和回放,在回放过程,可以把存取到的MQ任务转成一个Runnable对象交给dispatch模块,最终由Executor执行,具体的调用描述和回放可以参照TaskCoding接口的实现。 15 | 16 | 17 | ## Task注解 18 | 19 | 在生产任务时默认情况下,每个方法被描述成任务送入到MQ的队列位置是对象的名字和方法名,比如概述中的say方法,生产任务的队列是`Hello.say`.但有时也许你不想这样,那么Task注解 20 | 就可以帮组你更灵活的控制 21 | 22 | @Task("myQueue",executor="myExecutor") 23 | public void say(String msg) throws InterruptedException { 24 | Thread.sleep(1000); 25 | System.out.println(msg); 26 | } 27 | 28 | 上面的意思是说say方法将被送入到MQ的队列名是myQueue。最终是被名为myExecutor的Executor执行,就是这么简单,你也可以不指定队列名和executor的名字,默认queue、executor的名字分别是default和default。 29 | 30 | ## 方法描述 31 | 32 | 方法调用被描述为一个任务后被放入MQ服务中。当前默认MQ服务采用的是Redis的List结构作为MQ服务,方法调用描述采用Json的方式,比如概述中的say方法调用描述信息如下 33 | 34 | ``` 35 | "{ 36 | "aclass": "com.peaceful.task.system.Hello", 37 | "args": [ 38 | "helloworld!" 39 | ], 40 | "executor": "default", 41 | "id": "Test06-wangjunxe7x9ax84MacBook-main-9897997744", 42 | "method": "say", 43 | "parameterTypes": [ 44 | "java.lang.String" 45 | ], 46 | "queueName": "Test06", 47 | "submitTime": 1460741276765, 48 | "version": "2.0" 49 | }" 50 | ``` 51 | 52 | 这非常类似于一个RPC的远程调用协议,但还是有些区别,比如任务的场景主要是为了计算,所以不允许作为任务的方法有返回值,方法的参数也收到一些限制,主要支持 53 | 含有状态属性的参数,支持如下类型: 54 | 55 | 1. 支持基本类型即对应的包装类型。但除外基本类型中char、byte、float、short即对应的包装类型默认`不支持`。 56 | 3. 支持简单POJO类型支持,且变量属性是public修饰 57 | 2. 支持3大集合类型:Set、List、Map,集合内实际类型也受到该约束限制 58 | 4. 复杂类型需要用户自定义类型解释器 59 | 60 | ## 任务执行 61 | 62 | 任务执行过程是完全透明的,它可能在集群中的随机一个JVM实例上执行,你也可以通过设定调度策略控制它的执行机器。下面是整个任务的生命周期过程 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /reference/任务容器设计流程图.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/reference/任务容器设计流程图.bmp -------------------------------------------------------------------------------- /task-kernal/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-kernal/README.md -------------------------------------------------------------------------------- /task-kernal/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.peaceful 8 | task-kernal 9 | 2.6-SNAPSHOT 10 | 11 | 12 | 13 | 14 | true 15 | org.apache.maven.plugins 16 | maven-compiler-plugin 17 | 3.3 18 | 19 | 1.6 20 | 1.6 21 | true 22 | UTF-8 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | com.typesafe 31 | config 32 | 1.2.1 33 | 34 | 35 | 36 | cglib 37 | cglib 38 | 3.2.0 39 | 40 | 41 | 42 | com.alibaba 43 | fastjson 44 | 1.2.6 45 | 46 | 47 | 48 | com.peaceful 49 | redis-manage 50 | 1.1-SNAPSHOT 51 | 52 | 53 | 54 | com.google.inject 55 | guice 56 | 4.0 57 | 58 | 59 | 60 | com.google.guava 61 | guava 62 | 18.0 63 | 64 | 65 | 66 | 67 | com.typesafe.akka 68 | akka-actor_2.10 69 | 2.3.8 70 | 71 | 72 | 73 | com.typesafe.akka 74 | akka-slf4j_2.10 75 | 2.3.8 76 | 77 | 78 | 79 | junit 80 | junit 81 | 4.12 82 | test 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/NewTaskContext.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | import com.google.inject.Injector; 4 | import com.peaceful.task.kernal.conf.TaskConfigOps; 5 | 6 | /** 7 | * Task主要模块信息,系统所有模块启动成功后方可安全使用该context 8 | * Created by wangjun on 16-8-27. 9 | */ 10 | public class NewTaskContext implements TaskContext { 11 | 12 | private Injector injector; 13 | 14 | public NewTaskContext(Injector injector) { 15 | this.injector = injector; 16 | } 17 | 18 | @Override 19 | public TaskConfigOps getConfigOps() { 20 | return injector.getInstance(TaskConfigOps.class); 21 | } 22 | 23 | @Override 24 | public TaskQueue getTaskQueue() { 25 | return injector.getInstance(TaskQueue.class); 26 | } 27 | 28 | @Override 29 | public TaskController getTaskController() { 30 | return injector.getInstance(TaskController.class); 31 | } 32 | 33 | @Override 34 | public TaskProxy getTaskProxy() { 35 | return injector.getInstance(TaskProxy.class); 36 | } 37 | 38 | @Override 39 | public TaskDispatcher getTaskDispatcher() { 40 | return injector.getInstance(TaskDispatcher.class); 41 | } 42 | 43 | @Override 44 | public TaskBeanFactory getTaskBeanFactory() { 45 | return injector.getInstance(TaskBeanFactory.class); 46 | } 47 | 48 | @Override 49 | public TaskCoding getTaskCoding() { 50 | return injector.getInstance(TaskCoding.class); 51 | } 52 | 53 | @Override 54 | public TaskMonitor getTaskMonitor() { 55 | return injector.getInstance(TaskMonitor.class); 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | return super.toString(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/Task.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | import com.google.inject.Guice; 4 | import com.google.inject.Injector; 5 | import com.google.inject.Stage; 6 | import com.peaceful.task.kernal.conf.TaskConfService; 7 | import com.peaceful.task.kernal.conf.TaskConfigOps; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * Task系统入口 14 | * Created by wangjun on 16-8-28. 15 | */ 16 | public class Task { 17 | 18 | // 当前Task实例上下文信息 19 | private TaskContext context; 20 | // Task代理类实例 21 | private Map proxyInstanceCache = new HashMap(); 22 | // 多个Task实例,j建议一个程序中只有一个Task实例 23 | private static Map contextMap = new HashMap(); 24 | 25 | /** 26 | * @return 创建一个新的Task实例, 如果同名的Task实例已经存在, 将抛出重复创建异常 27 | */ 28 | public synchronized static Task create() { 29 | Injector injector = Guice.createInjector(Stage.PRODUCTION, new TaskModule()); 30 | Task task = new Task(); 31 | task.context = new NewTaskContext(injector); 32 | contextMap.put(injector.getInstance(TaskConfigOps.class).name, task.context); 33 | return task; 34 | } 35 | 36 | /** 37 | * 注册Java原生类到容器中,通过容器获取到的Java实例,可以通过Task调度器异步执行 38 | * 39 | * @param clszz 40 | * @param 41 | * @return Task代理实例 42 | */ 43 | public T registerASyncClass(Class clszz) { 44 | if (proxyInstanceCache.containsKey(clszz)) { 45 | return (T) proxyInstanceCache.get(clszz); 46 | } else { 47 | proxyInstanceCache.put(clszz, context.getTaskProxy().getProxyInstance(clszz)); 48 | } 49 | return (T) proxyInstanceCache.get(clszz); 50 | } 51 | 52 | /** 53 | * 根据Task实例名返回上下文,这是一个内部方法 54 | * 55 | * @param name 56 | * @return 57 | */ 58 | public static TaskContext getTaskContext(String name) { 59 | return contextMap.get(name); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/TaskBeanFactory.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | /** 4 | * 管理Task系统在执行任务时 ,任务对象所属实例获取方式. 5 | *

6 | * 如果你的项目使用类似ioc容器管理bean,你也可以自己实现该接口,从你的ioc容器中获取任务所属实例 7 | * 8 | * @author WangJun 9 | * @version 1.0 16/3/31 10 | */ 11 | public interface TaskBeanFactory { 12 | 13 | T getBean(Class zclass); 14 | 15 | void newInstance(Class zClass,Object instance); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/TaskClient.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | import com.peaceful.task.kernal.coding.TU; 4 | 5 | /** 6 | * Created by wangjun on 2016/9/30. 7 | */ 8 | public interface TaskClient { 9 | 10 | void submit(TU tu); 11 | } 12 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/TaskCoding.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | import com.peaceful.task.kernal.coding.TU; 4 | import com.peaceful.task.kernal.coding.TUR; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * 对异步类内方法调用的编码和解码 10 | *

11 | * 我们在调用Java方法时,每次调用其实就是产生一个Task,该接口是描述对调用信息的编码和解码操作 12 | * 13 | * @author WangJun 14 | * @version 1.0 16/1/12 15 | */ 16 | public interface TaskCoding { 17 | 18 | /** 19 | * encoding将方法的调用转为可序列化的Task对象,最终目的是序列化成一串指令,可以存储到queue服务中,并支持可以反序列化,还原方法的调用信息 20 | * 21 | * @param zClass 22 | * @param method 23 | * @param args 24 | * @return SimpleTaskContext 25 | */ 26 | TU encoding(Class zClass, Method method, Object[] args); 27 | 28 | /** 29 | * encoding方法将方法的调用动作编码为一个Task对象,Task对象序列化可以存储到queue服务中 30 | * decoding在根据queue中序列化的Task对象进行反序列化,主要操作包括类型转换,并包装为Runnable对象可供executor执行 31 | * 32 | * @param taskJson 33 | * @return Runnable的子对象TaskUnit, 可以被executor模块执行 34 | */ 35 | TUR decoding(String taskJson); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/TaskContext.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | import com.peaceful.task.kernal.conf.TaskConfigOps; 4 | 5 | /** 6 | * Created by wangjun on 16-8-27. 7 | */ 8 | public interface TaskContext { 9 | 10 | /** 11 | * @return 任务系统配置 12 | */ 13 | TaskConfigOps getConfigOps(); 14 | /** 15 | * @return 任务存储器 16 | */ 17 | TaskQueue getTaskQueue(); 18 | 19 | /** 20 | * @return 任务控制器 21 | */ 22 | TaskController getTaskController(); 23 | 24 | /** 25 | * @return 任务代理器 26 | */ 27 | TaskProxy getTaskProxy(); 28 | 29 | /** 30 | * @return 任务调度器 31 | */ 32 | TaskDispatcher getTaskDispatcher(); 33 | 34 | TaskBeanFactory getTaskBeanFactory(); 35 | 36 | /** 37 | * @return 任务编码器 38 | */ 39 | TaskCoding getTaskCoding(); 40 | 41 | /** 42 | * @return 任务监视器 43 | */ 44 | TaskMonitor getTaskMonitor(); 45 | 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/TaskController.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | import com.peaceful.task.kernal.conf.Executor; 4 | import com.peaceful.task.kernal.dispatch.TaskMeta; 5 | 6 | import java.util.*; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | /** 10 | * 任务控制器:可以在这里查看所有的任务生产消费情况,通过特定的API干预任务的执行 11 | * 12 | * @author WangJun 13 | * @version 1.0 16/3/30 14 | */ 15 | public interface TaskController { 16 | 17 | // 执行器列表 18 | List EXECUTOR_LIST = new ArrayList(); 19 | // 可能已经完成的任务调度列表,此处必须使用线程安全的集合 20 | Map TASK_HISTORY_LIST = new ConcurrentHashMap(); 21 | // 正在调度任务列表 22 | Map TASK_LIST = new ConcurrentHashMap(); 23 | 24 | /** 25 | * 获取所有的任务,包括可能完成的任务与正在调度的任务 26 | * 27 | * @return 28 | */ 29 | Collection findAllTasks(); 30 | 31 | /** 32 | * 加入任务,如果任务已经存在,则更新任务的更新时间 33 | * 34 | * @param name 35 | */ 36 | void insertTask(String name); 37 | 38 | 39 | void removeTask(TaskMeta task); 40 | 41 | /** 42 | * 获取本地可以调度的任务 43 | * 44 | * @return 45 | */ 46 | Collection findNeedDispatchTasks(); 47 | 48 | /** 49 | * 获取所有的任务执行器 50 | * 51 | * @return 52 | */ 53 | Collection findAllExecutors(); 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/TaskDispatcher.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | /** 4 | * 任务调度器 5 | * 6 | * @author WangJun 7 | * @version 1.0 16/3/31 8 | */ 9 | public interface TaskDispatcher { 10 | 11 | void dispatch(); 12 | } 13 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/TaskExecutor.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | /** 4 | * 任务执行器 5 | * 6 | * @author WangJun 7 | * @version 1.0 16/1/11 8 | */ 9 | public interface TaskExecutor { 10 | 11 | /** 12 | * 任务在某个节点被消费时,会被包装成一个Runnable对象,然后可以被Executor执行,或者直接调用起run方法执行 13 | * 14 | * @param task 一个实现Runnable接口的任务对象 15 | */ 16 | void execute(Runnable task); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/TaskModule.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | import com.google.inject.AbstractModule; 4 | import com.peaceful.task.kernal.client.TaskClientService; 5 | import com.peaceful.task.kernal.client.TaskProxyByCglib; 6 | import com.peaceful.task.kernal.coding.TaskCodingService; 7 | import com.peaceful.task.kernal.conf.TaskConfService; 8 | import com.peaceful.task.kernal.conf.TaskConfigOps; 9 | import com.peaceful.task.kernal.controller.RedisCloudTaskController; 10 | import com.peaceful.task.kernal.dispatch.TaskBeanFactoryImpl; 11 | import com.peaceful.task.kernal.dispatch.TaskDispatcherService; 12 | import com.peaceful.task.kernal.monitor.CloudTaskCountMonitor; 13 | import com.peaceful.task.kernal.queue.redis.RedisQueue; 14 | 15 | /** 16 | * Task Mail Module load 17 | *

18 | * Created by wangjun on 16-8-27. 19 | */ 20 | public class TaskModule extends AbstractModule { 21 | 22 | @Override 23 | protected void configure() { 24 | // 初始化conf 25 | bind(TaskConfigOps.class).toInstance(TaskConfService.startUp()); 26 | // 绑定任务控制器 27 | bind(TaskController.class).to(RedisCloudTaskController.class).asEagerSingleton(); 28 | // 绑定任务编码器 29 | bind(TaskCoding.class).to(TaskCodingService.class).asEagerSingleton(); 30 | // 绑定任务存储器 31 | bind(TaskQueue.class).to(RedisQueue.class).asEagerSingleton(); 32 | // 绑定beanFactory 33 | bind(TaskBeanFactory.class).to(TaskBeanFactoryImpl.class).asEagerSingleton(); 34 | // 装绑定任务监控器 35 | bind(TaskMonitor.class).to(CloudTaskCountMonitor.class).asEagerSingleton(); 36 | // 绑定Task Client 37 | bind(TaskClient.class).to(TaskClientService.class).asEagerSingleton(); 38 | // 绑定任务代理器 39 | bind(TaskProxy.class).to(TaskProxyByCglib.class).asEagerSingleton(); 40 | // 绑定任务调度器 41 | bind(TaskDispatcher.class).to(TaskDispatcherService.class).asEagerSingleton(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/TaskMonitor.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | import com.peaceful.task.kernal.coding.TU; 4 | 5 | /** 6 | * @author WangJun 7 | * @version 1.0 16/3/31 8 | */ 9 | public interface TaskMonitor { 10 | 11 | void produce(TU tu); 12 | 13 | void consume(TU tu); 14 | 15 | void exceptionIncr(String name); 16 | } 17 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/TaskProxy.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | /** 4 | * Task任务的提交代理 5 | * 6 | * @author WangJun 7 | * @version 1.0 16/3/29 8 | */ 9 | public interface TaskProxy { 10 | 11 | /** 12 | * 获取代理类实例 13 | * 14 | * @param zclass 15 | * @param 16 | * @return 17 | */ 18 | T getProxyInstance(Class zclass); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/TaskQueue.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | /** 4 | * 用于存放任务的队列服务 5 | * 6 | * @author WangJun 7 | * @version 1.0 16/3/29 8 | */ 9 | public interface TaskQueue { 10 | 11 | /** 12 | * 写入任务 13 | * 14 | * @param name 任务所在队列的名称 15 | * @param object 任务调用描述对象 16 | * @return true 表示写入成功 否则 return false 17 | */ 18 | boolean push(String name, String object); 19 | 20 | /** 21 | * 从队列中取出一条任务 22 | * 23 | * @param name 任务所在队列的名称 24 | * @return 加入存在任务返回任务对象,否则返回null 25 | */ 26 | String pop(String name); 27 | 28 | /** 29 | * 获取指定任务队列中含有任务的个数 30 | * 31 | * @param name 任务队列的名称 32 | * @return 33 | */ 34 | long size(String name); 35 | } 36 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/annotation/Task.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 任务单元描述:用于描述任务存放的队列和任务的执行器 10 | * 11 | * @author WangJun 12 | * @version 1.0 15/8/16 13 | * @since 1.6 14 | */ 15 | 16 | @Retention(RetentionPolicy.RUNTIME) 17 | @Target({ElementType.METHOD}) 18 | public @interface Task { 19 | 20 | /** 21 | * 所存放队列 22 | * 23 | * @return 24 | */ 25 | String value(); 26 | 27 | /** 28 | * 执行者 29 | * 30 | * @return 31 | */ 32 | String executor() default "default"; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/client/TaskClientService.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.client; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.serializer.SerializerFeature; 5 | import com.google.inject.Inject; 6 | import com.peaceful.task.kernal.TaskClient; 7 | import com.peaceful.task.kernal.TaskController; 8 | import com.peaceful.task.kernal.TaskMonitor; 9 | import com.peaceful.task.kernal.TaskQueue; 10 | import com.peaceful.task.kernal.coding.TU; 11 | import com.peaceful.task.kernal.conf.TaskConfigOps; 12 | import com.peaceful.task.kernal.helper.TaskLog; 13 | 14 | /** 15 | * Created by wangjun on 2016/9/30. 16 | */ 17 | public class TaskClientService implements TaskClient { 18 | 19 | @Inject 20 | TaskConfigOps ops; 21 | @Inject 22 | TaskQueue queue; 23 | @Inject 24 | private TaskController controller; 25 | @Inject 26 | private TaskMonitor monitor; 27 | 28 | @Override 29 | public void submit(TU tu) { 30 | //解决FastJson循环引用的问题 31 | SerializerFeature feature = SerializerFeature.DisableCircularReferenceDetect; 32 | tu.setSubmitTime(System.currentTimeMillis()); 33 | String cmd = JSON.toJSONString(tu, feature); 34 | // 提交到队列服务 35 | queue.push(ops.name + "-" + tu.queueName, cmd); 36 | controller.insertTask(tu.queueName); 37 | monitor.produce(tu); 38 | TaskLog.SUBMIT_TASK.info("submit task: {}", tu); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/client/TaskProxyByCglib.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.client; 2 | 3 | import com.google.inject.Inject; 4 | import com.peaceful.task.kernal.*; 5 | import com.peaceful.task.kernal.coding.TU; 6 | import com.peaceful.task.kernal.conf.TaskConfigOps; 7 | import com.alibaba.fastjson.JSON; 8 | import com.alibaba.fastjson.serializer.SerializerFeature; 9 | import com.peaceful.common.util.ExceptionUtils; 10 | import com.peaceful.task.kernal.helper.TaskLog; 11 | import net.sf.cglib.proxy.Enhancer; 12 | import net.sf.cglib.proxy.InvocationHandler; 13 | import org.perf4j.StopWatch; 14 | import org.perf4j.slf4j.Slf4JStopWatch; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | import java.lang.reflect.Method; 19 | 20 | /** 21 | * 通过代理将方法调用编码成任务对象并序列化成json对象提交任务到任务队列中 22 | * 23 | * @author WangJun 24 | * @version 1.0 16/1/9 25 | */ 26 | public class TaskProxyByCglib implements TaskProxy { 27 | 28 | private static Logger logger = LoggerFactory.getLogger(TaskProxyByCglib.class); 29 | @Inject 30 | private TaskClient client; 31 | @Inject 32 | private TaskCoding coding; 33 | 34 | @Override 35 | public T getProxyInstance(final Class tClass) { 36 | Enhancer enhancer = new Enhancer(); 37 | enhancer.setSuperclass(tClass); 38 | enhancer.setCallback(new InvocationHandler() { 39 | @Override 40 | public Object invoke(Object proxy, Method method, Object[] args) 41 | throws Throwable { 42 | StopWatch watch = new Slf4JStopWatch(); 43 | // 调用信息编码 44 | TU tu = coding.encoding(tClass, method, args); 45 | if (tu != null) { 46 | try { 47 | client.submit(tu); 48 | watch.stop("task.produce"); 49 | watch.stop("task." + tu.queueName + ".produce"); 50 | } catch (Exception e) { 51 | TaskLog.SUBMIT_TASK.error("task submit fail:{},cause:{}", tu.toString(), ExceptionUtils.getStackTrace(e)); 52 | throw new RuntimeException("task submit fail:" + tu, e); 53 | } 54 | } 55 | return null; 56 | } 57 | }); 58 | T t = (T) enhancer.create(); 59 | return t; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/TU.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.peaceful.task.kernal.TaskCoding; 5 | import com.alibaba.fastjson.annotation.JSONField; 6 | 7 | import java.io.Serializable; 8 | import java.lang.reflect.Method; 9 | 10 | /** 11 | * 任务描述协议 12 | * 13 | * 每次方法的调用都是一个Task的生成,通过{@link TaskCoding#encoding(Class, Method, Object[])}可以把 14 | * 方法的调用指令信息编码为一个TU对象,支持状态序列化 15 | * 16 | * @author WangJun 17 | * @version 1.0 16/1/9 18 | */ 19 | public class TU implements Serializable { 20 | 21 | // 任务创建时应生成一个唯一id,用于log跟踪 22 | public String id; 23 | // 任务单元存放队列位置 24 | public String queueName = "default"; 25 | // 该任务单元的Class入口 26 | @JSONField(deserialize = true) 27 | public Class aclass; 28 | // 该任务单元的方法入口 29 | public String method; 30 | // 该任务单元的方法参数类星列表 31 | public Class[] parameterTypes; 32 | // 该任务单元的方法参数列表 33 | public Object[] args; 34 | // 任务最终的执行器 35 | public String executor = "default"; 36 | // 任务协议版本 37 | public String version = "2.0"; 38 | // 任务提交时间 39 | public long submitTime; 40 | 41 | public long getSubmitTime() { 42 | return submitTime; 43 | } 44 | 45 | public void setSubmitTime(long submitTime) { 46 | this.submitTime = submitTime; 47 | } 48 | 49 | public Class getAclass() { 50 | return aclass; 51 | } 52 | 53 | public void setAclass(Class aclass) { 54 | this.aclass = aclass; 55 | } 56 | 57 | public String getExecutor() { 58 | return executor; 59 | } 60 | 61 | public Object[] getArgs() { 62 | return args; 63 | } 64 | 65 | public void setArgs(Object[] args) { 66 | this.args = args; 67 | } 68 | 69 | public String getId() { 70 | return id; 71 | } 72 | 73 | public void setId(String id) { 74 | this.id = id; 75 | } 76 | 77 | public String getMethod() { 78 | return method; 79 | } 80 | 81 | public void setMethod(String method) { 82 | this.method = method; 83 | } 84 | 85 | public Class[] getParameterTypes() { 86 | return parameterTypes; 87 | } 88 | 89 | public void setParameterTypes(Class[] parameterTypes) { 90 | this.parameterTypes = parameterTypes; 91 | } 92 | 93 | public String getQueueName() { 94 | return queueName; 95 | } 96 | 97 | public void setQueueName(String queueName) { 98 | this.queueName = queueName; 99 | } 100 | 101 | public void setExecutor(String executor) { 102 | this.executor = executor; 103 | } 104 | 105 | @Override 106 | public String toString() { 107 | return id + " " + aclass.getSimpleName() + "." + method + " " + arrayToString(args); 108 | } 109 | 110 | private String arrayToString(Object[] args) { 111 | StringBuffer buffer = new StringBuffer(); 112 | buffer.append("["); 113 | for (Object o : args) { 114 | buffer.append(JSON.toJSONString(o) + ","); 115 | } 116 | return buffer.substring(0, buffer.length() - 1) + "]"; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/TUR.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding; 2 | 3 | import com.google.common.base.Preconditions; 4 | import com.google.common.base.Throwables; 5 | import com.peaceful.task.kernal.TaskContext; 6 | import com.peaceful.task.kernal.helper.TaskLog; 7 | import org.apache.commons.lang3.exception.ExceptionUtils; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.lang.reflect.Method; 13 | import java.lang.reflect.UndeclaredThrowableException; 14 | 15 | /** 16 | * TU协议解析 17 | *

18 | * 将TU协议解析,这将会被解析成Runnable对象,然后可以被Executor执行 19 | *

20 | * 任务执行异常处理 21 | *

22 | * 任务在执行时如果抛出异常,则会将异常转为运行期异常并向上进行传播 23 | * 24 | * @author WangJun 25 | * @version 1.0 16/1/12 26 | */ 27 | public class TUR implements Runnable { 28 | 29 | // TU协议信息 30 | private TU tu; 31 | // Task Context 32 | public TaskContext context; 33 | // 生成TUR的时间 34 | public long createTime = System.currentTimeMillis(); 35 | private Logger logger = LoggerFactory.getLogger(getClass()); 36 | 37 | public TUR(TU tu) { 38 | this.tu = tu; 39 | } 40 | 41 | @Override 42 | public void run() { 43 | if (tu == null) return; 44 | // 获取调用方法 45 | Method method = null; 46 | try { 47 | method = tu.aclass.getMethod(tu.method, tu.parameterTypes); 48 | } catch (NoSuchMethodException e) { 49 | throw new RuntimeException("task execute error:task->" + tu.id + ", not found method " + tu.aclass.getSimpleName() + "." + tu.method + " cause:" + ExceptionUtils.getStackTrace(e)); 50 | } 51 | // 获取调用bean 52 | Object bean = null; 53 | try { 54 | bean = context.getTaskBeanFactory().getBean(tu.aclass); 55 | } catch (Exception e) { 56 | throw new RuntimeException("task execute error:task->" + tu.id + " not found bean instance " + tu.aclass.getSimpleName() + "." + tu.method + " cause:" + ExceptionUtils.getStackTrace(e)); 57 | } 58 | Preconditions.checkState(method != null, "execute task fail,Not Fount " + tu.aclass.getName() + "." + tu.method); 59 | Preconditions.checkState(bean != null, "execute task fail,Not Fount bean instance for " + tu.aclass.getName() + "." + tu.method); 60 | // 开始执行方法 61 | try { 62 | method.invoke(bean, tu.args); 63 | } catch (Exception e) { 64 | TaskLog.DISPATCH_TASK.error("task execute error:task->{},TaskSystem only log the exception but catch it,cause:{}",this,Throwables.getStackTraceAsString(unwrapThrowable(e))); 65 | Throwables.propagate(unwrapThrowable(e)); 66 | } 67 | } 68 | 69 | public TU getTask() { 70 | return tu; 71 | } 72 | 73 | public static Throwable unwrapThrowable(Throwable wrapped) { 74 | Throwable unwrapped = wrapped; 75 | 76 | while(true) { 77 | while(!(unwrapped instanceof InvocationTargetException)) { 78 | if(!(unwrapped instanceof UndeclaredThrowableException)) { 79 | return unwrapped; 80 | } 81 | 82 | unwrapped = ((UndeclaredThrowableException)unwrapped).getUndeclaredThrowable(); 83 | } 84 | 85 | unwrapped = ((InvocationTargetException)unwrapped).getTargetException(); 86 | } 87 | } 88 | 89 | @Override 90 | public String toString() { 91 | return tu.id+"["+ tu.aclass.getSimpleName()+"."+tu.method+"]"; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/TaskCodingService.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.google.inject.Inject; 5 | import com.peaceful.common.util.ExceptionUtils; 6 | import com.peaceful.task.kernal.TaskCoding; 7 | import com.peaceful.task.kernal.annotation.Task; 8 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 9 | import com.peaceful.task.kernal.coding.decoding.Magic; 10 | import com.peaceful.task.kernal.coding.decoding.TypeAdapter; 11 | import com.peaceful.task.kernal.helper.IdGenerate; 12 | import org.apache.commons.lang3.StringUtils; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import java.lang.reflect.Method; 17 | 18 | /** 19 | * @author WangJun 20 | * @version 1.0 16/1/9 21 | */ 22 | public class TaskCodingService implements TaskCoding { 23 | 24 | private Logger logger = LoggerFactory.getLogger(getClass()); 25 | @Inject 26 | private TypeAdapter typeAdapter; 27 | @Inject 28 | private Magic magic; 29 | 30 | /** 31 | * 把调用信息按TU协议进行编码 32 | * @param zClass 33 | * @param method 34 | * @param args 35 | * @return 36 | */ 37 | public TU encoding(Class zClass, Method method, Object[] args) { 38 | if (method.getDeclaringClass() != Object.class) { 39 | TU tu = new TU(); 40 | tu.setAclass(zClass); 41 | tu.setMethod(method.getName()); 42 | tu.setParameterTypes(method.getParameterTypes()); 43 | tu.setArgs(args); 44 | Task taskAno = method.getAnnotation(Task.class); 45 | if (taskAno == null) { 46 | tu.setQueueName(zClass.getSimpleName()+"."+method.getName()); 47 | }else{ 48 | tu.setQueueName(taskAno.value()); 49 | tu.setExecutor(taskAno.executor()); 50 | } 51 | tu.setId(IdGenerate.getNext(tu.queueName)); 52 | return tu; 53 | } 54 | if (method.getReturnType().toString().equals("void")) { 55 | // ignore 56 | } else { 57 | logger.warn("TaskSystem suggested that do not have a return value"); 58 | } 59 | return null; 60 | } 61 | 62 | /** 63 | * 解析TU协议为一个Runnable对象 64 | * @param taskJson 65 | * @return 66 | */ 67 | 68 | public TUR decoding(String taskJson) { 69 | if (StringUtils.isEmpty(taskJson)) return null; 70 | TU tu = JSON.parseObject(taskJson, TU.class); 71 | if (tu.aclass == null) { 72 | logger.error("can't decoding the {} ,may be the task matched class object not in the jvm", taskJson); 73 | return null; 74 | } 75 | try { 76 | InvokeContext invokeContext = new InvokeContext(tu); 77 | TUR taskUnit = magic.go(typeAdapter.execute(invokeContext)); 78 | return taskUnit; 79 | } catch (Exception e) { 80 | logger.error("decoding task id {}, method {} error {}", tu.id, tu.aclass.getSimpleName() + "." + tu.method, ExceptionUtils.getStackTrace(e)); 81 | return null; 82 | } 83 | } 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/InvokeContext.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding; 2 | 3 | 4 | import com.peaceful.common.util.chain.BaseContext; 5 | import com.peaceful.common.util.chain.Context; 6 | import com.peaceful.task.kernal.coding.TU; 7 | 8 | import java.lang.reflect.Method; 9 | import java.lang.reflect.Type; 10 | 11 | /** 12 | * 调用信息上下文,每个任务单元都应该一个独立的调用上下文 13 | * 该类不是线程安全,为了保证安全,需要为每个任务单元创建一个上下文 14 | * 15 | * @author WangJun 16 | * @version 1.0 15/8/27 17 | * @since 1.6 18 | */ 19 | 20 | public class InvokeContext extends BaseContext implements Context { 21 | 22 | public String id; 23 | 24 | // 调用类 25 | public Class aClass; 26 | 27 | // 调用方法 28 | public String methodName; 29 | 30 | // 参数类型列表 31 | public Class[] parameterTypes; 32 | 33 | // 获取实际参数类型,针对泛型问题进行解决 34 | public Type[] types; 35 | 36 | // 调用实际传参 37 | public Object[] args; 38 | 39 | // 解析参数到对应的类型 40 | public Object[] newArgs; 41 | 42 | public String executor; 43 | 44 | public String queueName; 45 | 46 | // 解析进度 47 | public int index; 48 | 49 | // 解析总进度 50 | public int length; 51 | 52 | // 任务提交时间 53 | public long submitTime; 54 | 55 | public Method method; 56 | 57 | // 利用Task2任务单元构造调用上下文信息 58 | public InvokeContext(TU task2) throws NoSuchMethodException { 59 | id = task2.id; 60 | queueName = task2.queueName; 61 | aClass = task2.aclass; 62 | methodName = task2.method; 63 | parameterTypes = task2.parameterTypes; 64 | args = task2.args; 65 | executor = task2.executor; 66 | length = args.length; 67 | newArgs = new Object[length]; 68 | index = 0; 69 | submitTime = task2.getSubmitTime(); 70 | method = aClass.getMethod(methodName, parameterTypes); 71 | types = method.getGenericParameterTypes(); 72 | } 73 | 74 | public Type getCurrentParamType() { 75 | return types[index - 1]; 76 | } 77 | 78 | public Object getCurrentArg() { 79 | return newArgs[index - 1]; 80 | } 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/Magic.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding; 2 | 3 | 4 | import com.google.inject.Singleton; 5 | import com.peaceful.task.kernal.coding.TU; 6 | import com.peaceful.task.kernal.coding.TUR; 7 | 8 | /** 9 | * @author WangJun 10 | * @version 1.0 16/1/12 11 | */ 12 | @Singleton 13 | public class Magic { 14 | 15 | public TUR go(InvokeContext invokeContext) { 16 | TU task02 = new TU(); 17 | task02.id = invokeContext.id; 18 | task02.queueName = invokeContext.queueName; 19 | task02.aclass = invokeContext.aClass; 20 | task02.method = invokeContext.methodName; 21 | task02.args = invokeContext.newArgs; 22 | task02.parameterTypes = invokeContext.parameterTypes; 23 | task02.executor = invokeContext.executor; 24 | task02.submitTime = invokeContext.submitTime; 25 | TUR taskUnit = new TUR(task02); 26 | return taskUnit; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/NotSupportParamType.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding; 2 | 3 | import java.lang.reflect.Type; 4 | 5 | /** 6 | * @author WangJun 7 | * @version 1.0 15/8/28 8 | * @since 1.6 9 | */ 10 | 11 | public class NotSupportParamType extends RuntimeException { 12 | 13 | public NotSupportParamType(Class zClass){ 14 | super("not support paramType "+zClass); 15 | } 16 | 17 | public NotSupportParamType(Type type){ 18 | super("not support paramType "+type); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/Parse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding; 2 | 3 | 4 | import com.peaceful.common.util.chain.Command; 5 | 6 | /** 7 | * 8 | * 参数解析 9 | * 10 | * @author WangJun 11 | * @version 1.0 15/8/27 12 | * @since 1.6 13 | */ 14 | 15 | public interface Parse extends Command { 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/ParseChain.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding; 2 | 3 | 4 | import com.peaceful.common.util.chain.BaseChain; 5 | 6 | /** 7 | * @author WangJun 8 | * @version 1.0 15/8/27 9 | * @since 1.6 10 | */ 11 | 12 | public class ParseChain extends BaseChain { 13 | 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/TypeAdapter.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding; 2 | 3 | import com.google.inject.Singleton; 4 | import com.peaceful.common.util.chain.Context; 5 | import com.peaceful.task.kernal.coding.decoding.impl.*; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * 对Task进行解码,并包装成TaskUnit对象,提供给Executor执行 11 | * 12 | * @author WangJun 13 | * @version 1.0 15/8/28 14 | * @since 1.6 15 | */ 16 | @Singleton 17 | public class TypeAdapter { 18 | 19 | Logger logger = LoggerFactory.getLogger(getClass()); 20 | 21 | private static ParseChain parseChain; 22 | 23 | static { 24 | parseChain = new ParseChain(); 25 | parseChain.addCommand(new NullParse()); 26 | parseChain.addCommand(new EmptyParse()); 27 | parseChain.addCommand(new PrimitiveParse()); 28 | parseChain.addCommand(new StringParse()); 29 | parseChain.addCommand(new IntegerParse()); 30 | parseChain.addCommand(new BooleanParse()); 31 | parseChain.addCommand(new LongParse()); 32 | parseChain.addCommand(new DoubleParse()); 33 | parseChain.addCommand(new ListParse()); 34 | parseChain.addCommand(new MapParse()); 35 | parseChain.addCommand(new SetParse()); 36 | parseChain.addCommand(new UserDefinedParse()); 37 | } 38 | 39 | public InvokeContext execute(Context context) throws Exception { 40 | InvokeContext invokeContext = (InvokeContext) context; 41 | for (int i = 0; i < invokeContext.length; i++) { 42 | if (parseChain.execute(invokeContext)) { 43 | logger.debug("{} param[{}] {} {}", invokeContext.aClass.getSimpleName()+"."+invokeContext.methodName,i,invokeContext.getCurrentParamType(), invokeContext.getCurrentArg()); 44 | } else { 45 | throw new NotSupportParamType(invokeContext.getCurrentParamType()); 46 | } 47 | } 48 | return invokeContext; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/impl/BooleanParse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding.impl; 2 | 3 | 4 | import com.peaceful.common.util.chain.Context; 5 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 6 | import com.peaceful.task.kernal.coding.decoding.Parse; 7 | 8 | /** 9 | * Boolean类型参数解析 10 | * 11 | * @author WangJun 12 | * @version 1.0 15/8/27 13 | * @since 1.6 14 | */ 15 | 16 | public class BooleanParse implements Parse { 17 | 18 | @Override 19 | public boolean execute(Context context) throws Exception { 20 | InvokeContext invokeContext = (InvokeContext) context; 21 | if (invokeContext.parameterTypes[invokeContext.index].equals(Boolean.class)) { 22 | invokeContext.newArgs[invokeContext.index] = Boolean.valueOf(invokeContext.args[invokeContext.index].toString()); 23 | invokeContext.index++; 24 | return PROCESSING_COMPLETE; 25 | } 26 | return CONTINUE_PROCESSING; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/impl/DoubleParse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding.impl; 2 | 3 | 4 | import com.peaceful.common.util.chain.Context; 5 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 6 | import com.peaceful.task.kernal.coding.decoding.Parse; 7 | 8 | /** 9 | * Double类型参数解析 10 | * 11 | * @author WangJun 12 | * @version 1.0 15/8/27 13 | * @since 1.6 14 | */ 15 | 16 | public class DoubleParse implements Parse { 17 | 18 | @Override 19 | public boolean execute(Context context) throws Exception { 20 | InvokeContext invokeContext = (InvokeContext) context; 21 | if (invokeContext.parameterTypes[invokeContext.index].equals(Double.class)) { 22 | invokeContext.newArgs[invokeContext.index] = Double.valueOf(invokeContext.args[invokeContext.index].toString()); 23 | invokeContext.index++; 24 | return PROCESSING_COMPLETE; 25 | } 26 | return CONTINUE_PROCESSING; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/impl/EmptyParse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding.impl; 2 | 3 | import com.peaceful.common.util.chain.Context; 4 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 5 | import com.peaceful.task.kernal.coding.decoding.NotSupportParamType; 6 | import com.peaceful.task.kernal.coding.decoding.Parse; 7 | 8 | /** 9 | * 这里会验证所有不支持的参数类型,包括 10 | *

11 | * char(Character) 12 | * short(Short) 13 | * byte(Byte) 14 | * float(Float) 15 | *

16 | * 如果遇到这些参数类型,将会抛出 NotSupportParamType() 17 | * 18 | * @author WangJun 19 | * @version 1.0 15/8/28 20 | * @since 1.6 21 | */ 22 | 23 | public class EmptyParse implements Parse { 24 | 25 | @Override 26 | public boolean execute(Context context) throws Exception { 27 | InvokeContext invokeContext = (InvokeContext) context; 28 | int index = invokeContext.index; 29 | boolean flag = false; 30 | Class zClass = invokeContext.parameterTypes[index]; 31 | if (zClass.isPrimitive()) { 32 | if (zClass.equals(char.class)) { 33 | flag = true; 34 | } else if (zClass.equals(byte.class)) { 35 | flag = true; 36 | } else if (zClass.equals(float.class)) { 37 | flag = true; 38 | } else if (zClass.equals(short.class)) { 39 | flag = true; 40 | } 41 | } else { 42 | if (zClass.equals(Character.class)) { 43 | flag = true; 44 | } else if (zClass.equals(Byte.class)) { 45 | flag = true; 46 | } else if (zClass.equals(Float.class)) { 47 | flag = true; 48 | } else if (zClass.equals(Short.class)) { 49 | flag = true; 50 | } 51 | } 52 | 53 | if (flag) { 54 | invokeContext.newArgs[index] = null; 55 | invokeContext.index++; 56 | throw new NotSupportParamType(zClass); 57 | } 58 | return CONTINUE_PROCESSING; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/impl/IntegerParse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding.impl; 2 | 3 | 4 | import com.peaceful.common.util.chain.Context; 5 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 6 | import com.peaceful.task.kernal.coding.decoding.Parse; 7 | 8 | /** 9 | * Integer类型参数解析 10 | * 11 | * @author WangJun 12 | * @version 1.0 15/8/27 13 | * @since 1.6 14 | */ 15 | 16 | public class IntegerParse implements Parse { 17 | 18 | @Override 19 | public boolean execute(Context context) throws Exception { 20 | InvokeContext invokeContext = (InvokeContext) context; 21 | if (invokeContext.parameterTypes[invokeContext.index].equals(Integer.class)) { 22 | invokeContext.newArgs[invokeContext.index] = Integer.valueOf(invokeContext.args[invokeContext.index].toString()); 23 | invokeContext.index++; 24 | return PROCESSING_COMPLETE; 25 | } 26 | return CONTINUE_PROCESSING; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/impl/ListParse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding.impl; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONArray; 5 | import com.peaceful.common.util.chain.Context; 6 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 7 | import com.peaceful.task.kernal.coding.decoding.Parse; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * List类型参数解析 13 | * 14 | * @author WangJun 15 | * @version 1.0 15/8/27 16 | * @since 1.6 17 | */ 18 | 19 | public class ListParse implements Parse { 20 | 21 | @Override 22 | public boolean execute(Context context) throws Exception { 23 | InvokeContext invokeContext = (InvokeContext) context; 24 | if (invokeContext.parameterTypes[invokeContext.index].equals(List.class)) { 25 | JSONArray object = (JSONArray) invokeContext.args[invokeContext.index]; 26 | invokeContext.newArgs[invokeContext.index] = JSON.parseObject(object.toJSONString(), invokeContext.types[invokeContext.index]); 27 | invokeContext.index++; 28 | return PROCESSING_COMPLETE; 29 | } 30 | return CONTINUE_PROCESSING; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/impl/LongParse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding.impl; 2 | 3 | 4 | import com.peaceful.common.util.chain.Context; 5 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 6 | import com.peaceful.task.kernal.coding.decoding.Parse; 7 | 8 | /** 9 | * Long类型参数解析 10 | * 11 | * @author WangJun 12 | * @version 1.0 15/8/27 13 | * @since 1.6 14 | */ 15 | 16 | public class LongParse implements Parse { 17 | 18 | @Override 19 | public boolean execute(Context context) throws Exception { 20 | InvokeContext invokeContext = (InvokeContext) context; 21 | if (invokeContext.parameterTypes[invokeContext.index].equals(Long.class)) { 22 | invokeContext.newArgs[invokeContext.index] = Long.valueOf(invokeContext.args[invokeContext.index].toString()); 23 | invokeContext.index++; 24 | return PROCESSING_COMPLETE; 25 | } 26 | return CONTINUE_PROCESSING; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/impl/MapParse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding.impl; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.peaceful.common.util.chain.Context; 6 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 7 | import com.peaceful.task.kernal.coding.decoding.Parse; 8 | 9 | import java.util.Map; 10 | 11 | /** 12 | * Map类型参数解析 13 | * 14 | * @author WangJun 15 | * @version 1.0 15/8/27 16 | * @since 1.6 17 | */ 18 | 19 | public class MapParse implements Parse { 20 | 21 | @Override 22 | public boolean execute(Context context) throws Exception { 23 | InvokeContext invokeContext = (InvokeContext) context; 24 | if (invokeContext.parameterTypes[invokeContext.index].equals(Map.class)) { 25 | JSONObject object = (JSONObject) invokeContext.args[invokeContext.index]; 26 | invokeContext.newArgs[invokeContext.index] = JSON.parseObject(object.toJSONString(), invokeContext.types[invokeContext.index]); 27 | invokeContext.index++; 28 | return PROCESSING_COMPLETE; 29 | } 30 | return CONTINUE_PROCESSING; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/impl/NullParse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding.impl; 2 | 3 | import com.peaceful.common.util.chain.Context; 4 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 5 | import com.peaceful.task.kernal.coding.decoding.Parse; 6 | 7 | /** 8 | * Null类型参数解析,该解析器的位置应该放置第一位 9 | * 10 | * @author WangJun 11 | * @version 1.0 15/8/27 12 | * @since 1.6 13 | */ 14 | 15 | public class NullParse implements Parse { 16 | 17 | @Override 18 | public boolean execute(Context context) throws Exception { 19 | InvokeContext invokeContext = (InvokeContext) context; 20 | if (invokeContext.args[invokeContext.index] == null) { 21 | invokeContext.newArgs[invokeContext.index] = null; 22 | invokeContext.index++; 23 | return PROCESSING_COMPLETE; 24 | } 25 | return CONTINUE_PROCESSING; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/impl/PrimitiveParse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding.impl; 2 | 3 | import com.peaceful.common.util.chain.Context; 4 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 5 | import com.peaceful.task.kernal.coding.decoding.Parse; 6 | 7 | /** 8 | * Primitive类型参数解析 {@link Class#isPrimitive()} 9 | * 10 | * 下面这些类型虽然也是Primitive类型,但这些类型的解析,需要单独考虑,请注意{@link EmptyParse} 11 | * char 12 | * short 13 | * byte 14 | * float 15 | * 16 | * @author WangJun 17 | * @version 1.0 15/8/27 18 | * @since 1.6 19 | */ 20 | 21 | public class PrimitiveParse implements Parse { 22 | 23 | @Override 24 | public boolean execute(Context context) throws Exception { 25 | InvokeContext invokeContext = (InvokeContext) context; 26 | if (invokeContext.parameterTypes[invokeContext.index].isPrimitive()) { 27 | invokeContext.newArgs[invokeContext.index] = invokeContext.args[invokeContext.index]; 28 | invokeContext.index++; 29 | return PROCESSING_COMPLETE; 30 | } 31 | return CONTINUE_PROCESSING; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/impl/SetParse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding.impl; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONArray; 5 | import com.peaceful.common.util.chain.Context; 6 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 7 | import com.peaceful.task.kernal.coding.decoding.Parse; 8 | 9 | import java.util.Set; 10 | 11 | /** 12 | * Long类型参数解析 13 | * 14 | * @author WangJun 15 | * @version 1.0 15/8/27 16 | * @since 1.6 17 | */ 18 | 19 | public class SetParse implements Parse { 20 | 21 | @Override 22 | public boolean execute(Context context) throws Exception { 23 | InvokeContext invokeContext = (InvokeContext) context; 24 | if (invokeContext.parameterTypes[invokeContext.index].equals(Set.class)) { 25 | JSONArray object = (JSONArray) invokeContext.args[invokeContext.index]; 26 | invokeContext.newArgs[invokeContext.index] = JSON.parseObject(object.toJSONString(), invokeContext.types[invokeContext.index]); 27 | invokeContext.index++; 28 | return PROCESSING_COMPLETE; 29 | } 30 | return CONTINUE_PROCESSING; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/impl/StringParse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding.impl; 2 | 3 | import com.peaceful.common.util.chain.Context; 4 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 5 | import com.peaceful.task.kernal.coding.decoding.Parse; 6 | 7 | /** 8 | * Long类型参数解析 9 | * 10 | * @author WangJun 11 | * @version 1.0 15/8/27 12 | * @since 1.6 13 | */ 14 | 15 | public class StringParse implements Parse { 16 | 17 | @Override 18 | public boolean execute(Context context) throws Exception { 19 | InvokeContext invokeContext = (InvokeContext) context; 20 | if (invokeContext.parameterTypes[invokeContext.index].equals(String.class)) { 21 | invokeContext.newArgs[invokeContext.index] = invokeContext.args[invokeContext.index]; 22 | invokeContext.index++; 23 | return PROCESSING_COMPLETE; 24 | } 25 | return CONTINUE_PROCESSING; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/coding/decoding/impl/UserDefinedParse.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.coding.decoding.impl; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.peaceful.common.util.chain.Context; 6 | import com.peaceful.task.kernal.coding.decoding.InvokeContext; 7 | import com.peaceful.task.kernal.coding.decoding.Parse; 8 | 9 | /** 10 | * @author WangJun 11 | * @version 1.0 15/8/27 12 | * @since 1.6 13 | */ 14 | 15 | public class UserDefinedParse implements Parse { 16 | 17 | @Override 18 | public boolean execute(Context context) throws Exception { 19 | InvokeContext invokeContext = (InvokeContext) context; 20 | if (invokeContext.parameterTypes[invokeContext.index].isPrimitive()) { 21 | 22 | } else { 23 | JSONObject object = (JSONObject) invokeContext.args[invokeContext.index]; 24 | invokeContext.newArgs[invokeContext.index] = JSON.parseObject(object.toJSONString(), invokeContext.parameterTypes[invokeContext.index]); 25 | invokeContext.index++; 26 | return PROCESSING_COMPLETE; 27 | } 28 | return CONTINUE_PROCESSING; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/conf/Executor.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.conf; 2 | 3 | /** 4 | * 任务执行器 5 | * 6 | * Created by wangjun on 16/1/12. 7 | */ 8 | public class Executor { 9 | 10 | // 执行器的名称 11 | public String name; 12 | // 执行器的完整类名称 13 | public String implementation; 14 | // 执行器对应的Class对象 15 | public java.lang.Class Class; 16 | } 17 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/conf/ExecutorsConf.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.conf; 2 | 3 | import com.google.common.util.concurrent.ThreadFactoryBuilder; 4 | 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.ScheduledExecutorService; 7 | import java.util.concurrent.ThreadFactory; 8 | 9 | /** 10 | * Created by wangjun on 16/8/28. 11 | */ 12 | public class ExecutorsConf { 13 | 14 | 15 | private final static ThreadFactory threadFactoryBuilder = new ThreadFactoryBuilder() 16 | .setNameFormat("task-commons-%d") 17 | .setDaemon(true) 18 | .build(); 19 | public static final ScheduledExecutorService SINGLE_THREAD_SCHEDULED = Executors.newSingleThreadScheduledExecutor(threadFactoryBuilder); 20 | } 21 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/conf/TaskConfigOps.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.conf; 2 | 3 | import com.google.inject.Singleton; 4 | import com.peaceful.task.kernal.helper.NetHelper; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by wangjun on 16/1/10. 11 | */ 12 | @Singleton 13 | public class TaskConfigOps { 14 | 15 | // 当前系统版本号 16 | public static final String VERSION = "2.6"; 17 | // 系统名称,用于区分多个系统 18 | public String name = null; 19 | //系统启动模式,client or server 20 | public String bootMode = "client"; 21 | // TaskQueue 任务队列实现 22 | public String queue; 23 | // BeanFactory实现 24 | public String beanFactory; 25 | // test or product 26 | public String developMode = "product"; 27 | //executor module conf 28 | public ExecutorConfigOps executorConfigOps = new ExecutorConfigOps(); 29 | public class ExecutorConfigOps { 30 | public List executorNodeList = new ArrayList(); 31 | 32 | @Override 33 | public String toString() { 34 | StringBuffer buffer = new StringBuffer(); 35 | buffer.append("[").append("\n"); 36 | for (Executor executor:executorNodeList){ 37 | buffer.append("\t").append(executor.name).append("->").append(executor.implementation).append("\n"); 38 | } 39 | buffer.append("]"); 40 | return buffer.toString(); 41 | } 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return "Task Kernal["+VERSION+"]"+ " Name["+name+"]"; 47 | } 48 | 49 | public String detail(){ 50 | StringBuffer buffer = new StringBuffer(); 51 | buffer.append("----------------------Task Kernal--------------------------------------").append("\n"); 52 | buffer.append(toString()).append("\n"); 53 | buffer.append("hostname:").append(NetHelper.getHostname()).append("\n"); 54 | buffer.append("task.boot.mode:").append(bootMode).append("\n"); 55 | buffer.append("task.queue.impl:").append(queue).append("\n"); 56 | buffer.append("task.bean.factory.impl:").append(beanFactory).append("\n"); 57 | buffer.append("task.executor.list:").append(executorConfigOps).append("\n"); 58 | buffer.append("-----------------------------------------------------------------------"); 59 | return buffer.toString(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/controller/CloudController.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.controller; 2 | 3 | import com.peaceful.task.kernal.TaskController; 4 | import com.peaceful.task.kernal.helper.Node; 5 | 6 | import java.util.Collection; 7 | import java.util.Map; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | /** 11 | * @author WangJun 12 | * @version 1.0 16/3/31 13 | */ 14 | public interface CloudController extends TaskController { 15 | 16 | 17 | Map NODE_MAP = new ConcurrentHashMap(); 18 | 19 | /** 20 | * 本地和云端进行信息同步 21 | */ 22 | void sync(); 23 | 24 | 25 | /** 26 | * 获取集群中所有的服务节点 27 | * 28 | * @return 29 | */ 30 | Collection findNodes(); 31 | 32 | 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/NoBlockAutoConsumer.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch; 2 | 3 | import akka.actor.ActorSystem; 4 | import akka.actor.Props; 5 | import com.google.common.util.concurrent.AbstractIdleService; 6 | import com.google.inject.Inject; 7 | import com.google.inject.Singleton; 8 | import com.peaceful.task.kernal.Task; 9 | import com.peaceful.task.kernal.coding.TUR; 10 | import com.peaceful.task.kernal.conf.TaskConfigOps; 11 | import com.peaceful.task.kernal.dispatch.actor.DispatchManagerActor; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | /** 19 | * 无阻塞自动任务调度模块 20 | * Created by wangjun on 16-8-27. 21 | */ 22 | @Singleton 23 | public class NoBlockAutoConsumer extends AbstractIdleService { 24 | 25 | private ActorSystem system; 26 | private Logger logger = LoggerFactory.getLogger(getClass()); 27 | private static Map systemMap = new HashMap(); 28 | 29 | @Inject 30 | private TaskConfigOps ops; 31 | 32 | // 接收来自TaskDispatchService的消息,并将消息直接传入到ExecutorsManagerActor 33 | public void tell(TUR tur) { 34 | system.actorSelection("/user/dispatcher/executors").tell(tur,system.actorFor("/user/dispatcher/")); 35 | } 36 | 37 | protected void startUp() throws Exception { 38 | system = ActorSystem.create(ops.name); 39 | // 创建actor系统的top actor,所有actor都要求从这里继承下去 40 | system.actorOf(Props.create(DispatchManagerActor.class, Task.getTaskContext(ops.name)), "dispatcher"); 41 | systemMap.put(ops.name,system); 42 | logger.info("no block auto dispatch service start..."); 43 | } 44 | 45 | protected void shutDown() throws Exception { 46 | if (!system.isTerminated()) { 47 | system.shutdown(); 48 | } 49 | } 50 | 51 | public static ActorSystem getSystem(String name){ 52 | return systemMap.get(name); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/PullTask.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch; 2 | 3 | import com.google.common.base.Throwables; 4 | import com.peaceful.task.kernal.*; 5 | import com.peaceful.task.kernal.coding.TUR; 6 | import com.peaceful.task.kernal.conf.TaskConfigOps; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | /** 12 | * Created by wangjun on 16/1/12. 13 | */ 14 | public class PullTask { 15 | 16 | private TaskConfigOps ops; 17 | private TaskMonitor monitor; 18 | private TaskController controller; 19 | private TaskCoding coding; 20 | private TaskQueue queue; 21 | private Logger logger = LoggerFactory.getLogger(getClass()); 22 | 23 | public static PullTask get(TaskContext context) { 24 | PullTask pullTask = new PullTask(); 25 | pullTask.ops = context.getConfigOps(); 26 | pullTask.monitor = context.getTaskMonitor(); 27 | pullTask.controller = context.getTaskController(); 28 | pullTask.coding = context.getTaskCoding(); 29 | pullTask.queue = context.getTaskQueue(); 30 | return pullTask; 31 | } 32 | 33 | /** 34 | * 从队列服务中取出task指令 35 | * 36 | * @param queueName 37 | * @return 38 | */ 39 | public TUR next(String queueName) { 40 | try { 41 | if (controller.findNeedDispatchTasks().contains(new TaskMeta(queueName))) { 42 | String taskJson = queue.pop(ops.name + "-" + queueName); 43 | if (StringUtils.isNoneEmpty(taskJson)) { 44 | TUR taskUnit = coding.decoding(taskJson); 45 | monitor.consume(taskUnit.getTask()); 46 | return taskUnit; 47 | } 48 | } 49 | } catch (Exception e) { 50 | // 关键性日志 51 | logger.error("can't get next task from {},cause:{}", queueName, Throwables.getStackTraceAsString(e)); 52 | } 53 | return null; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/TaskBeanFactoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch; 2 | 3 | import com.peaceful.task.kernal.TaskBeanFactory; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.Map; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | /** 11 | * @author WangJun 12 | * @version 1.0 16/3/31 13 | */ 14 | public class TaskBeanFactoryImpl implements TaskBeanFactory { 15 | 16 | // 任务对象实例容器 17 | private final static Map ASYNC_TASK_INSTANCE = new ConcurrentHashMap(); 18 | 19 | private final static Logger LOGGER = LoggerFactory.getLogger(TaskBeanFactoryImpl.class); 20 | 21 | @Override 22 | public T getBean(Class zclass) { 23 | if (ASYNC_TASK_INSTANCE.containsKey(zclass)) { 24 | return (T) ASYNC_TASK_INSTANCE.get(zclass); 25 | } else { 26 | try { 27 | Object instance = zclass.newInstance(); 28 | LOGGER.debug("auto create {} instance OK...", zclass.getName()); 29 | ASYNC_TASK_INSTANCE.put(zclass, instance); 30 | return (T) instance; 31 | } catch (InstantiationException e) { 32 | LOGGER.error("Error:{}", e); 33 | } catch (IllegalAccessException e) { 34 | LOGGER.error("Error:{}", e); 35 | } 36 | } 37 | return null; 38 | } 39 | 40 | @Override 41 | public void newInstance(Class zClass,Object instance) { 42 | if (!ASYNC_TASK_INSTANCE.containsKey(zClass)) { 43 | ASYNC_TASK_INSTANCE.put(zClass, instance); 44 | LOGGER.info("new instance info ,insert instance suc {}", zClass); 45 | } else { 46 | LOGGER.warn("new instance warn , instance {} is exist", zClass); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/TaskDispatcherService.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch; 2 | 3 | import com.google.common.base.Throwables; 4 | import com.google.common.util.concurrent.AbstractScheduledService; 5 | import com.google.inject.Inject; 6 | import com.peaceful.task.kernal.Task; 7 | import com.peaceful.task.kernal.TaskController; 8 | import com.peaceful.task.kernal.TaskDispatcher; 9 | import com.peaceful.task.kernal.coding.TUR; 10 | import com.peaceful.task.kernal.conf.TaskConfigOps; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.util.Collection; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | /** 18 | * 定时从任务队列中拉取任务消息 19 | * Created by wangjun on 16-8-27. 20 | */ 21 | public class TaskDispatcherService extends AbstractScheduledService implements TaskDispatcher { 22 | 23 | @Inject 24 | private TaskController controller; 25 | @Inject 26 | private NoBlockAutoConsumer noBlockAutoDispatch; 27 | @Inject 28 | private TaskConfigOps ops; 29 | private PullTask pullTask; 30 | private Logger logger = LoggerFactory.getLogger(getClass()); 31 | 32 | @Inject 33 | public TaskDispatcherService() { 34 | this.startAsync(); 35 | } 36 | 37 | @Override 38 | public void dispatch() { 39 | try { 40 | if (noBlockAutoDispatch.state() == State.NEW || noBlockAutoDispatch.state() == State.STARTING) { 41 | noBlockAutoDispatch.startAsync(); 42 | noBlockAutoDispatch.awaitRunning(); 43 | pullTask = PullTask.get(Task.getTaskContext(ops.name)); 44 | } 45 | // 从controller中获取需要调度的任务 46 | Collection taskMetas = controller.findNeedDispatchTasks(); 47 | if (taskMetas == null && taskMetas.isEmpty()) { 48 | return; 49 | } 50 | for (TaskMeta meta : taskMetas) { 51 | TUR unit = pullTask.next(meta.name); 52 | if (unit != null) { 53 | if (noBlockAutoDispatch.isRunning()) { 54 | noBlockAutoDispatch.tell(unit); 55 | } else { 56 | logger.error("dispatcher service not running,current state->{},task->{} ", noBlockAutoDispatch.state(),unit); 57 | } 58 | } 59 | } 60 | } catch (Exception e) { 61 | // dispatch 失败,需要记录日志,关键性日志 62 | logger.error("dispatch exception:{}", Throwables.getStackTraceAsString(e)); 63 | } 64 | } 65 | 66 | @Override 67 | protected void runOneIteration() throws Exception { 68 | dispatch(); 69 | } 70 | 71 | @Override 72 | protected Scheduler scheduler() { 73 | return Scheduler.newFixedRateSchedule(1, 1, TimeUnit.SECONDS); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/TaskMeta.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch; 2 | 3 | /** 4 | * 任务队列描述 5 | * 6 | * @author WangJun 7 | * @version 1.0 16/3/30 8 | */ 9 | public class TaskMeta { 10 | 11 | public String name;// 队列名 12 | public String desc;// 描述 13 | public String state = "OK"; // 状态 OK 可以被所有机器调用 hostname 只能被某台机器调用 isLock 不允许被调用 14 | public long reserve = 0; 15 | public long createTime;// 任务创建时间 16 | public long updateTime;// 任务最近更新时间 17 | public boolean expire;// 是否已经过期 18 | 19 | public TaskMeta() { 20 | 21 | } 22 | 23 | public TaskMeta(String name) { 24 | this.name = name; 25 | state = "OK"; 26 | } 27 | 28 | 29 | @Override 30 | public boolean equals(Object o) { 31 | if (this == o) return true; 32 | if (!(o instanceof TaskMeta)) return false; 33 | TaskMeta task = (TaskMeta) o; 34 | return name != null ? name.equals(task.name) : task.name == null; 35 | } 36 | 37 | @Override 38 | public int hashCode() { 39 | return name != null ? name.hashCode() : 0; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/actor/DispatchManagerActor.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch.actor; 2 | 3 | import akka.actor.*; 4 | import akka.event.DiagnosticLoggingAdapter; 5 | import akka.event.Logging; 6 | import akka.japi.Function; 7 | import com.peaceful.task.kernal.TaskContext; 8 | import com.peaceful.task.kernal.helper.GetNextTaskException; 9 | import scala.concurrent.duration.Duration; 10 | 11 | /** 12 | * 其只负责ExecutorsManagerActor的运行情况 13 | * 14 | * @author WangJun 15 | * @version 1.0 16/1/12 16 | */ 17 | public class DispatchManagerActor extends UntypedActor { 18 | 19 | DiagnosticLoggingAdapter log = Logging.getLogger(this); 20 | 21 | private TaskContext context; 22 | 23 | public DispatchManagerActor(TaskContext context) { 24 | this.context = context; 25 | } 26 | 27 | @Override 28 | public void preStart() throws Exception { 29 | getContext().actorOf(Props.create(ExecutorsManagerActor.class, context), "executors"); 30 | // public actor 作为其它需要利用到actor地方的监管者 31 | getContext().actorOf(Props.create(PublicActor.class), "public"); 32 | super.preStart(); 33 | } 34 | 35 | @Override 36 | public void onReceive(Object message) throws Exception { 37 | log.info("{}", message); 38 | unhandled(message); 39 | 40 | } 41 | 42 | 43 | /** 44 | * top actor supervisor is restart 45 | * 46 | * @return 47 | */ 48 | @Override 49 | public SupervisorStrategy supervisorStrategy() { 50 | final SupervisorStrategy strategy = new OneForOneStrategy( 51 | 10, Duration.create("1 minute"), new Function() { 52 | @Override 53 | public SupervisorStrategy.Directive apply(Throwable t) { 54 | if (t instanceof GetNextTaskException) { 55 | log.error("{} receive message [{}] from child,resume", getSelf().path(), t.getMessage()); 56 | return SupervisorStrategy.resume(); 57 | } 58 | log.error("{} supervisor will restart child actor exception {}", self().path().name(), t); 59 | return SupervisorStrategy.restart(); 60 | } 61 | }); 62 | return strategy; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/actor/ExecutorSupervisionActor.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch.actor; 2 | 3 | import akka.actor.UntypedActor; 4 | import akka.event.DiagnosticLoggingAdapter; 5 | import akka.event.Logging; 6 | import com.peaceful.task.kernal.TaskContext; 7 | import com.peaceful.task.kernal.TaskExecutor; 8 | import com.peaceful.task.kernal.coding.TUR; 9 | import com.peaceful.task.kernal.dispatch.actor.msg.DecorateTask; 10 | 11 | /** 12 | * executor监控者 13 | *

14 | * Created by wangjun on 16/1/12. 15 | */ 16 | public class ExecutorSupervisionActor extends UntypedActor { 17 | 18 | // // TODO: 16/1/12 测试executor失败的情况 19 | private TaskExecutor taskExecutor; 20 | private TaskContext context; 21 | DiagnosticLoggingAdapter log = Logging.getLogger(this); 22 | 23 | public ExecutorSupervisionActor(TaskExecutor taskExecutor, TaskContext context) { 24 | this.taskExecutor = taskExecutor; 25 | this.context = context; 26 | } 27 | 28 | @Override 29 | public void onReceive(Object o) throws Exception { 30 | if (o instanceof TUR) { 31 | TUR taskUnit = (TUR) o; 32 | DecorateTask decorate = new DecorateTask(context, taskUnit, self()); 33 | taskExecutor.execute(decorate); 34 | } else { 35 | unhandled(o); 36 | } 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/actor/PublicActor.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch.actor; 2 | 3 | import akka.actor.OneForOneStrategy; 4 | import akka.actor.Props; 5 | import akka.actor.SupervisorStrategy; 6 | import akka.actor.UntypedActor; 7 | import akka.event.DiagnosticLoggingAdapter; 8 | import akka.event.Logging; 9 | import akka.japi.Function; 10 | import scala.concurrent.duration.Duration; 11 | 12 | /** 13 | * 如果需要扩展,请以该public actor为root 向下创建actor 14 | * supervisor strategy: restart 15 | *

16 | * Created by wangjun on 16/1/13. 17 | */ 18 | public class PublicActor extends UntypedActor { 19 | 20 | DiagnosticLoggingAdapter log = Logging.getLogger(this); 21 | 22 | @Override 23 | public void preStart() throws Exception { 24 | getContext().actorOf(Props.create(TaskRouterActor.class), "taskDispatch"); 25 | super.preStart(); 26 | } 27 | 28 | @Override 29 | public void onReceive(Object message) throws Exception { 30 | log.info("public unhandle message {}", message); 31 | unhandled(message); 32 | } 33 | 34 | /** 35 | * top actor supervisor is restart 36 | * 37 | * @return 38 | */ 39 | @Override 40 | public SupervisorStrategy supervisorStrategy() { 41 | SupervisorStrategy strategy = new OneForOneStrategy( 42 | 10, Duration.create("1 minute"), new Function() { 43 | @Override 44 | public SupervisorStrategy.Directive apply(Throwable t) { 45 | log.error("{} supervisor will resume child actor exception {}", self().path().name(), t); 46 | return SupervisorStrategy.restart(); 47 | } 48 | }); 49 | return strategy; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/actor/TaskRouterActor.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch.actor; 2 | 3 | import akka.actor.*; 4 | import akka.event.DiagnosticLoggingAdapter; 5 | import akka.event.Logging; 6 | import akka.japi.Function; 7 | import akka.routing.ActorRefRoutee; 8 | import akka.routing.RoundRobinRoutingLogic; 9 | import akka.routing.Routee; 10 | import akka.routing.Router; 11 | import com.peaceful.task.kernal.dispatch.actor.msg.DecorateTask; 12 | import scala.concurrent.duration.Duration; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * 任务调度路由中心 19 | *

20 | * 路由中心分发任务方式有两种: 21 | * 第一,由系统的任务存储和调度监管委派,路由在把该任务分发给某个适合的actor,这种分发称之为强制分发,目的是为了路由中心和worker不会在一个任务队列上循环 22 | * 使每个任务队列都有机会被调度 23 | * 第二,由路由中心和worker之间的内部协调分发,这种分发称之为协调分发,目的是为了路由中心和某个actor之间维持一种近长连接的状态,快速循环调度 24 | *

25 | *

26 | * 调度中心模块的router采用轮询的方式调用worker 27 | * Created by wangjun on 15/3/11. 28 | */ 29 | public class TaskRouterActor extends UntypedActor { 30 | 31 | final DiagnosticLoggingAdapter log = Logging.getLogger(this); 32 | Router router; 33 | 34 | 35 | { 36 | List routees = new ArrayList(); 37 | for (int i = 0; i < 8; i++) { 38 | ActorRef r = getContext().actorOf(Props.create(WorkerActor.class), "worker-" + i); 39 | getContext().watch(r); 40 | routees.add(new ActorRefRoutee(r)); 41 | } 42 | router = new Router(new RoundRobinRoutingLogic(), routees); 43 | } 44 | 45 | 46 | @Override 47 | public void onReceive(Object msg) throws Exception { 48 | if (msg instanceof DecorateTask) { 49 | router.route(msg, getSelf()); 50 | } 51 | else if (msg instanceof Terminated) { 52 | router = router.removeRoutee(((Terminated) msg).actor()); 53 | ActorRef r = getContext().actorOf(Props.create(WorkerActor.class), ((Terminated) msg).actor().path().name()); 54 | getContext().watch(r); 55 | router = router.addRoutee(new ActorRefRoutee(r)); 56 | } 57 | } 58 | 59 | 60 | /** 61 | * worker 监管策略 restart 62 | * 如果worker在执行过程中发生异常,目前只是简单的尝试重启worker,如果1分钟内尝试10次还是不可以执行,则停止尝试 63 | * 64 | * @return 65 | */ 66 | @Override 67 | public SupervisorStrategy supervisorStrategy() { 68 | SupervisorStrategy strategy = new OneForOneStrategy( 69 | 10, Duration.create("1 minute"), new Function() { 70 | @Override 71 | public SupervisorStrategy.Directive apply(Throwable t) { 72 | log.error("supervise worker found error {},cause {}", t, t.getCause()); 73 | return SupervisorStrategy.restart(); 74 | } 75 | }); 76 | return strategy; 77 | } 78 | } -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/actor/WorkerActor.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch.actor; 2 | 3 | import akka.actor.UntypedActor; 4 | 5 | /** 6 | * @author WangJun 7 | * @version 1.0 16/1/11 8 | */ 9 | public class WorkerActor extends UntypedActor { 10 | 11 | @Override 12 | public void onReceive(Object message) throws Exception { 13 | Runnable task = (Runnable) message; 14 | task.run(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/actor/msg/DecorateTask.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch.actor.msg; 2 | 3 | import akka.actor.ActorRef; 4 | import akka.actor.ActorSystem; 5 | import akka.event.Logging; 6 | import akka.event.LoggingAdapter; 7 | import com.google.common.base.Throwables; 8 | import com.peaceful.task.kernal.TaskContext; 9 | import com.peaceful.task.kernal.coding.TUR; 10 | import com.peaceful.task.kernal.dispatch.NoBlockAutoConsumer; 11 | import org.perf4j.StopWatch; 12 | import org.perf4j.slf4j.Slf4JStopWatch; 13 | 14 | /** 15 | * 装饰TaskUnit,使其在完成任务后通知executor dispatch 16 | *

17 | * Created by wangjun on 16/1/15. 18 | */ 19 | public class DecorateTask implements Runnable { 20 | 21 | TUR taskUnit; 22 | ActorRef executorActor; 23 | private final LoggingAdapter log; 24 | private ActorSystem system; 25 | 26 | public DecorateTask(TaskContext context, TUR taskUnit, ActorRef execuotActor) { 27 | this.taskUnit = taskUnit; 28 | this.taskUnit.context = context; 29 | this.executorActor = execuotActor; 30 | this.system = NoBlockAutoConsumer.getSystem(context.getConfigOps().name); 31 | log = Logging.getLogger(system, DecorateTask.class); 32 | } 33 | 34 | @Override 35 | public void run() { 36 | TaskCompleted completed = new TaskCompleted(taskUnit); 37 | completed.startTime = System.currentTimeMillis(); 38 | StopWatch watch = new Slf4JStopWatch(); 39 | try { 40 | taskUnit.run(); 41 | watch.stop("task.consume"); 42 | watch.stop("task." + taskUnit.getTask().queueName + ".consume"); 43 | } catch (Exception e) { 44 | watch.stop("task.consume.error"); 45 | completed.isHasException = true; 46 | Throwables.propagate(e); 47 | } finally { 48 | completed.completeTime = System.currentTimeMillis(); 49 | // 通知所属ExecutorActor任务完成 50 | system.actorSelection("/user/dispatcher/executors").tell(completed, executorActor); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/actor/msg/TaskCompleted.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch.actor.msg; 2 | 3 | 4 | import com.peaceful.task.kernal.coding.TUR; 5 | 6 | /** 7 | * confirm task unit completed msg 8 | *

9 | * Created by wangjun on 16/1/12. 10 | */ 11 | public class TaskCompleted { 12 | 13 | // task id 14 | public String id; 15 | // QUEUE of task 16 | public String queue; 17 | // execute of task 18 | public String executor; 19 | // task 提交时间 20 | public long submitTime; 21 | // task 拉取时间 22 | public long createTime; 23 | // task 开始时间 24 | public long startTime; 25 | // task 完成时间 26 | public long completeTime; 27 | 28 | public boolean isHasException; 29 | 30 | public TaskCompleted(TUR taskUnit) { 31 | this.id = taskUnit.getTask().id; 32 | this.queue = taskUnit.getTask().queueName; 33 | this.executor = taskUnit.getTask().executor; 34 | this.createTime = taskUnit.createTime; 35 | this.submitTime = taskUnit.getTask().getSubmitTime(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/executor/JUCTaskExecutor.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch.executor; 2 | 3 | import com.peaceful.task.kernal.TaskExecutor; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.concurrent.ExecutorService; 8 | import java.util.concurrent.Executors; 9 | 10 | /** 11 | * Created by wangjun on 16/1/12. 12 | */ 13 | public class JUCTaskExecutor implements TaskExecutor { 14 | 15 | Logger logger = LoggerFactory.getLogger(getClass()); 16 | ExecutorService executorService = Executors.newFixedThreadPool(8); 17 | 18 | @Override 19 | public void execute(Runnable task) { 20 | executorService.submit(task); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/dispatch/executor/SimpleTaskExecutor.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.dispatch.executor; 2 | 3 | 4 | import com.peaceful.task.kernal.TaskExecutor; 5 | 6 | /** 7 | * Created by wangjun on 16/1/13. 8 | */ 9 | public class SimpleTaskExecutor implements TaskExecutor { 10 | 11 | @Override 12 | public void execute(Runnable task) { 13 | task.run(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/helper/GetNextTaskException.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.helper; 2 | 3 | /** 4 | * @author WangJun 5 | * @version 1.0 16/4/2 6 | */ 7 | public class GetNextTaskException extends RuntimeException { 8 | 9 | public GetNextTaskException(String msg){ 10 | super(msg); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/helper/IdGenerate.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.helper; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.net.InetAddress; 7 | import java.net.UnknownHostException; 8 | 9 | /** 10 | * 唯一id生成器 11 | * 12 | * @author WangJun 13 | * @version 1.0 15/8/16 14 | * @since 1.6 15 | */ 16 | 17 | public class IdGenerate { 18 | 19 | static Logger logger = LoggerFactory.getLogger(IdGenerate.class); 20 | 21 | /** 22 | * 通过nanoTime作为唯一ID 23 | * 24 | * @return 25 | */ 26 | public static String getNext() { 27 | String hostName = "null"; 28 | try { 29 | hostName = InetAddress.getLocalHost().getHostName(); 30 | } catch (UnknownHostException e) { 31 | logger.error("id generate error {}", e); 32 | } 33 | return String.valueOf(hostName + "-" + System.currentTimeMillis()); 34 | } 35 | 36 | public static String getNext(String prefix) { 37 | return prefix + "-" + getNext(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/helper/IllegalTaskStateException.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.helper; 2 | 3 | /** 4 | * @author WangJun 5 | * @version 1.0 16/4/1 6 | */ 7 | public class IllegalTaskStateException extends RuntimeException{ 8 | 9 | public IllegalTaskStateException(String msg){ 10 | super(msg); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/helper/NetHelper.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.helper; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.IOException; 7 | import java.net.InetAddress; 8 | import java.net.UnknownHostException; 9 | 10 | /** 11 | * Created by wangjun on 16/1/18. 12 | */ 13 | public class NetHelper { 14 | 15 | static Logger logger = LoggerFactory.getLogger(NetHelper.class); 16 | 17 | public static String getIp() { 18 | try { 19 | return InetAddress.getLocalHost().getHostAddress(); 20 | } catch (UnknownHostException e) { 21 | logger.error("Error:{} ", e); 22 | } 23 | return "Empty"; 24 | } 25 | 26 | 27 | public static String getHostname() { 28 | try { 29 | return InetAddress.getLocalHost().getHostName(); 30 | } catch (UnknownHostException e) { 31 | e.printStackTrace(); 32 | logger.error("Error: {}", e); 33 | } 34 | return "Empty"; 35 | } 36 | 37 | public static boolean ping(String ip, int seconds) { 38 | int timeOut = seconds; 39 | try { 40 | return InetAddress.getByName(ip).isReachable(timeOut); 41 | } catch (IOException e) { 42 | logger.error("Error: {}", e); 43 | return false; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/helper/Node.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.helper; 2 | 3 | /** 4 | * SimpleTaskContext 集群节点信息 5 | * 6 | * @author WangJun 7 | * @version 1.0 16/1/11 8 | */ 9 | public class Node { 10 | 11 | // 节点hostname 12 | public String hostName; 13 | // 节点ip 14 | public String ip; 15 | // 节点启动模式 16 | public String mode; 17 | // 节点状态 18 | public String state; 19 | // 节点启动时间 20 | public long startTime; 21 | // 节点信息更新时间 22 | public long updateTime; 23 | 24 | public Node() { 25 | } 26 | 27 | public Node(String hostName, String ip) { 28 | this.hostName = hostName; 29 | this.ip = ip; 30 | this.state = "OK"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/helper/ServiceCenter.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.helper; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.Set; 6 | 7 | /** 8 | * 服务中心用于管理TaskSystem运行期的状态信息 9 | * 10 | * @author WangJun 11 | * @version 1.0 16/1/11 12 | */ 13 | public interface ServiceCenter { 14 | 15 | 16 | /** 17 | * 获取系统的名字 18 | * 19 | * @return 20 | */ 21 | String getSystemName(); 22 | 23 | /** 24 | * 获取集群中所有的服务节点 25 | * 26 | * @return 27 | */ 28 | List getAllServiceNode(); 29 | 30 | /** 31 | * 获取master节点 32 | * 33 | * @return 34 | */ 35 | String getMaster(); 36 | 37 | 38 | /** 39 | * 加入当前节点到服务中心 40 | */ 41 | void addServiceNode(); 42 | 43 | /** 44 | * 移除当前节点 45 | */ 46 | void removeServiceNode(); 47 | 48 | /** 49 | * 移除指定服务节点 50 | * 51 | * @param hostName 52 | */ 53 | void removeServiceNode(String hostName); 54 | 55 | /** 56 | * 选举master节点 57 | * 58 | * @return 59 | */ 60 | Node electMasterNode(); 61 | 62 | /** 63 | * 当前节点是否是master节点 64 | * 65 | * @return 66 | */ 67 | boolean isMasterNode(); 68 | 69 | boolean addRouter(String queueName, String hostname); 70 | 71 | boolean removeRouter(String queueName); 72 | 73 | Map getRouterTable(); 74 | 75 | 76 | /** 77 | * 添加 focused task 78 | * 79 | * @param queueName 80 | * @return 81 | */ 82 | boolean addFocusedTask(String queueName); 83 | 84 | // Map updateQueue(); 85 | 86 | // void updateQueueState(); 87 | 88 | 89 | /** 90 | * 清除focused task 列表 91 | * 92 | * @return 93 | */ 94 | boolean clearFocusedTask(); 95 | 96 | /** 97 | * 添加 flexible task 98 | * 99 | * @param queueName 100 | * @return 101 | */ 102 | boolean addFlexibleTask(String queueName); 103 | 104 | /** 105 | * 获取focused task 列表 106 | * 107 | * @return 108 | */ 109 | Set getAllFocusedTask(); 110 | 111 | /** 112 | * 获取flexible task 列表 113 | * 114 | * @return 115 | */ 116 | Set getAllFlexibleTask(); 117 | 118 | /** 119 | * 停止指定队列的调度 120 | * 121 | * @param queueName 122 | * @return 123 | */ 124 | boolean lockQueue(String queueName); 125 | 126 | boolean queueIsLock(String queueName); 127 | 128 | /** 129 | * 打开指定队列的调度 130 | * 131 | * @param queueName 132 | * @return 133 | */ 134 | boolean openQueueLock(String queueName); 135 | 136 | /** 137 | * 停止指定节点的调度 138 | * 139 | * @param hostname 140 | * @return 141 | */ 142 | boolean lockNode(String hostname); 143 | 144 | boolean nodeIsLock(String hostname); 145 | 146 | /** 147 | * 打开指定节点的调度 148 | * 149 | * @param hostname 150 | * @return 151 | */ 152 | boolean openNodeLock(String hostname); 153 | 154 | 155 | 156 | } 157 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/helper/TaskLog.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.helper; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | /** 7 | * 系统关键性日志 8 | * Created by wangjun on 16/8/29. 9 | */ 10 | public class TaskLog { 11 | 12 | public static final Logger SUBMIT_TASK = LoggerFactory.getLogger("task.kernal.log.client.submit"); 13 | public static final Logger DISPATCH_TASK = LoggerFactory.getLogger("task.kernal.log.dispatch"); 14 | public static final Logger COMPLETE_TASK = LoggerFactory.getLogger("task.kernal.log.dispatch.complete"); 15 | public static final Logger ERROR_TASK = LoggerFactory.getLogger("task.kernal.log.dispatch.complete"); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/monitor/CloudTaskCountMonitor.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.monitor; 2 | 3 | import com.google.inject.Inject; 4 | import com.peaceful.task.kernal.conf.TaskConfigOps; 5 | import com.peaceful.common.redis.service.Redis; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.ScheduledExecutorService; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | /** 14 | * 同步本地记录的任务提交和消费次数到一个集中的地方。在一个中心记录生产次数和消费次数的目的是 15 | *

16 | * 1. 合并各个节点的生产消费次数 17 | * 2. 监控系统可以查询该中心的数据,做实时系统监控 18 | *

19 | * 目前实现的版本是集中地方是Redis。 20 | * 21 | * @author WangJun 22 | * @version 1.0 16/4/4 23 | */ 24 | public class CloudTaskCountMonitor extends LocalTaskCountMonitor { 25 | 26 | private static String CLOUD_TASK_PRODUCE_COUNT; 27 | private static String CLOUD_TASK_CONSUME_COUNT; 28 | private static String CLOUD_TASK_FAIL_COUNT; 29 | Logger logger = LoggerFactory.getLogger(getClass()); 30 | 31 | @Inject 32 | public CloudTaskCountMonitor(TaskConfigOps ops) { 33 | CLOUD_TASK_PRODUCE_COUNT = "TASK-" + ops.name + "-PRODUCE-COUNT-MONITOR"; 34 | CLOUD_TASK_CONSUME_COUNT = "TASK-" + ops.name + "-CONSUME-COUNT-MONITOR"; 35 | CLOUD_TASK_FAIL_COUNT = "TASK-" + ops.name + "-EXCEPTION-COUNT-MONITOR"; 36 | ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); 37 | executorService.scheduleAtFixedRate(new CloudMonitorSync(), 6, 6, TimeUnit.SECONDS); 38 | } 39 | 40 | private class CloudMonitorSync implements Runnable { 41 | 42 | @Override 43 | public void run() { 44 | try { 45 | // 定时清空本地记录数据,将数据同步记录到Redis中 46 | for (String queue : TASK_PRODUCT_COUNT.keySet()) { 47 | Redis.cmd().hincrBy(CLOUD_TASK_PRODUCE_COUNT, queue, TASK_PRODUCT_COUNT.get(queue).getAndSet(0)); 48 | } 49 | for (String queue : TASK_CONSUME_COUNT.keySet()) { 50 | Redis.cmd().hincrBy(CLOUD_TASK_CONSUME_COUNT, queue, TASK_CONSUME_COUNT.get(queue).getAndSet(0)); 51 | } 52 | for (String queue : TASK_FAIL_COUNT.keySet()) { 53 | Redis.cmd().hincrBy(CLOUD_TASK_FAIL_COUNT, queue, TASK_FAIL_COUNT.get(queue).getAndSet(0)); 54 | } 55 | } catch (Exception e) { 56 | logger.error("upload task submit & consume count error", e); 57 | } 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/monitor/LocalTaskCountMonitor.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.monitor; 2 | 3 | import com.peaceful.task.kernal.TaskMonitor; 4 | import com.peaceful.task.kernal.coding.TU; 5 | 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | import java.util.concurrent.atomic.AtomicLong; 9 | 10 | /** 11 | * 记录本地机器的任务提交次数和消费次数 12 | * 13 | * @author WangJun 14 | * @version 1.0 16/4/4 15 | */ 16 | public class LocalTaskCountMonitor implements TaskMonitor { 17 | 18 | 19 | // 记录提交次数 20 | public static final Map TASK_PRODUCT_COUNT = new ConcurrentHashMap(); 21 | // 记录消费次数 22 | public static final Map TASK_CONSUME_COUNT = new ConcurrentHashMap(); 23 | // 记录任务执行失败次数 24 | public static final Map TASK_FAIL_COUNT = new ConcurrentHashMap(); 25 | 26 | @Override 27 | public void produce(TU tu) { 28 | AtomicLong count = TASK_PRODUCT_COUNT.get(tu.getQueueName()); 29 | if (count == null) { 30 | AtomicLong atomicLong = new AtomicLong(1); 31 | TASK_PRODUCT_COUNT.put(tu.getQueueName(), atomicLong); 32 | } else { 33 | count.incrementAndGet(); 34 | } 35 | } 36 | 37 | @Override 38 | public void consume(TU tu) { 39 | AtomicLong count = TASK_CONSUME_COUNT.get(tu.getQueueName()); 40 | if (count == null) { 41 | AtomicLong atomicLong = new AtomicLong(1); 42 | TASK_CONSUME_COUNT.put(tu.getQueueName(), atomicLong); 43 | } else { 44 | count.incrementAndGet(); 45 | } 46 | } 47 | 48 | @Override 49 | public void exceptionIncr(String name) { 50 | AtomicLong count = TASK_FAIL_COUNT.get(name); 51 | if (count == null) { 52 | AtomicLong atomicLong = new AtomicLong(1); 53 | TASK_FAIL_COUNT.put(name, atomicLong); 54 | } else { 55 | count.incrementAndGet(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * context是Task系统各个module都需要依赖的模块,在这里定义了Task运行期的上下文信息和各个module需要实现的功能接口 3 | * 4 | * @author WangJun 5 | * @version 1.0 16/5/28 6 | */ 7 | package com.peaceful.task.kernal; -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/queue/local/LocalQueue.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.queue.local; 2 | 3 | 4 | import com.peaceful.task.kernal.TaskQueue; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.Queue; 9 | import java.util.concurrent.ArrayBlockingQueue; 10 | 11 | /** 12 | * 仅用于本地测试 13 | *

14 | * Created by wangjun on 16/1/13. 15 | * @since 1.7 16 | */ 17 | public class LocalQueue implements TaskQueue { 18 | 19 | Map> map = new HashMap>(); 20 | 21 | @Override 22 | public long size(String name) { 23 | if (map.containsKey(name)) { 24 | return map.get(name).size(); 25 | } 26 | return 0; 27 | } 28 | 29 | @Override 30 | public synchronized boolean push(String name, String object) { 31 | if (map.containsKey(name)) { 32 | return map.get(name).offer(object); 33 | } else { 34 | Queue queue = new ArrayBlockingQueue(1024); 35 | map.put(name, queue); 36 | return map.get(name).offer(object); 37 | } 38 | } 39 | 40 | @Override 41 | public String pop(String name) { 42 | if (map.containsKey(name)) { 43 | return map.get(name).poll(); 44 | } 45 | return null; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /task-kernal/src/main/java/com/peaceful/task/kernal/queue/redis/RedisQueue.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal.queue.redis; 2 | 3 | import com.peaceful.common.redis.service.Redis; 4 | import com.peaceful.task.kernal.TaskQueue; 5 | 6 | /** 7 | * @author WangJun 8 | * @version 1.0 16/1/10 9 | */ 10 | public class RedisQueue implements TaskQueue { 11 | 12 | @Override 13 | public boolean push(String key, String object) { 14 | Redis.cmd().lpush(key, object); 15 | return true; 16 | } 17 | 18 | @Override 19 | public String pop(String key) { 20 | return Redis.cmd().rpop(key); 21 | } 22 | 23 | @Override 24 | public long size(String key) { 25 | return Redis.cmd().llen(key); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /task-kernal/src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | akka { 2 | loggers = ["akka.event.slf4j.Slf4jLogger"] 3 | // loglevel = "DEBUG" 4 | loglevel = "INFO" 5 | logging-filter = "akka.event.slf4j.Slf4jLoggingFilter" 6 | actor { 7 | debug { 8 | # enable DEBUG logging of all AutoReceiveMessages (Kill, PoisonPill et.c.) 9 | autoreceive = on 10 | # enable DEBUG logging of actor lifecycle changes 11 | lifecycle = on 12 | # enable DEBUG logging of unhandled messages 13 | unhandled = on 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /task-kernal/src/main/resources/task-reference.conf: -------------------------------------------------------------------------------- 1 | # task系统配置文件 2 | 3 | task { 4 | 5 | # 系统命名,主要用于创建多个系统实例时的命名空间的区分 6 | name = "TASK" 7 | 8 | # 启动模式,如果是client模式,只可以提交任务,不会调度任务执行,server模式可提交任务,也可以调度任务执行 9 | boot-mode = "server" # server[client] 10 | 11 | # 开发模式,在test模式下,系统会打印更多的日志信息 12 | develop-mode = "test" # test[product] 13 | 14 | # 任务队列实现,你也可以实现自己的队列通过继承TaskQueue 15 | queue = "com.peaceful.task.kernal.queue.redis.RedisQueue" 16 | 17 | # 任务bean实例获取工厂,任务在被执行时,需要获取任务的实例,你也可以实现自己的bean管理工厂,比如对接Spring的BeanFactory或其它DI容器 18 | bean-factory = "com.peaceful.task.kernal.dispatch.TaskBeanFactoryImpl" 19 | 20 | // 任务执行器 21 | executor = [ 22 | 23 | { 24 | name: "default" 25 | # 最简单的executor实现 26 | implementation: "com.peaceful.task.kernal.dispatch.executor.SimpleTaskExecutor" 27 | }, 28 | { 29 | name: "jucExecutor" 30 | implementation: "com.peaceful.task.kernal.dispatch.executor.JUCTaskExecutor" 31 | } 32 | ] 33 | 34 | # 从MQ中拉取任务的频率 35 | dispatch-tick = 2s 36 | } -------------------------------------------------------------------------------- /task-kernal/src/test/java/com/peaceful/task/kernal/Hello.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | import com.peaceful.task.kernal.annotation.Task; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Set; 8 | 9 | /** 10 | * @author WangJun 11 | * @version 1.0 16/1/11 12 | */ 13 | public class Hello { 14 | 15 | @Task(value = "Test06",executor = "jucExecutor") 16 | public void say(String msg) throws InterruptedException { 17 | // Thread.sleep(1000); 18 | int x= 1 /0; 19 | System.out.println(msg); 20 | } 21 | 22 | @Task("Test08") 23 | public void testPOJO(User user) throws InterruptedException { 24 | System.out.println(user.name); 25 | } 26 | 27 | public void testMap(Map user) throws InterruptedException { 28 | System.out.println(user.get("01").name); 29 | } 30 | 31 | public void testList(List user) throws InterruptedException { 32 | System.out.println(user.get(0).name); 33 | } 34 | 35 | public void testSet(Set user) throws InterruptedException { 36 | System.out.println(user); 37 | } 38 | 39 | public void testAll(String msg, User user, Map userMap, List userList, Set userSet) throws InterruptedException { 40 | System.out.println(msg); 41 | System.out.println(userMap.get("01").name); 42 | System.out.println(userList.get(0).name); 43 | System.out.println(user); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /task-kernal/src/test/java/com/peaceful/task/kernal/SetUp.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * @author WangJun 7 | * @version 1.0 16/3/30 8 | */ 9 | public class SetUp { 10 | 11 | public static void main(String[] args) throws InterruptedException { 12 | 13 | Task task = Task.create(); 14 | Hello hello = task.registerASyncClass(Hello.class); 15 | int time = 1000; 16 | for (int i=0;i< time;i++) { 17 | // 基本类型测试 18 | hello.say("hello world!"); 19 | 20 | User user = new User(); 21 | user.name = "123"; 22 | 23 | // 简单POJO类型 24 | hello.testPOJO(user); 25 | 26 | // Map类型 27 | Map userMap = new HashMap(); 28 | userMap.put("01", user); 29 | hello.testMap(userMap); 30 | 31 | // List 类型 32 | List users = new ArrayList(); 33 | users.add(user); 34 | hello.testList(users); 35 | 36 | // Set 类型 37 | Set userSet = new HashSet(); 38 | userSet.add(user); 39 | hello.testSet(userSet); 40 | 41 | hello.testAll("Hello World!", user, userMap, users, userSet); 42 | } 43 | 44 | // int time = 1; 45 | /* int time = 10000; 46 | for (int i = 0; i < time; i++) { 47 | hello.say("hello world"); 48 | }*/ 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /task-kernal/src/test/java/com/peaceful/task/kernal/User.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.kernal; 2 | 3 | /** 4 | * @author WangJun 5 | * @version 1.0 16/4/14 6 | */ 7 | public class User { 8 | 9 | public String name; 10 | public int id; 11 | } 12 | -------------------------------------------------------------------------------- /task-kernal/src/test/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /task-ops/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/.DS_Store -------------------------------------------------------------------------------- /task-ops/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | com.peaceful 9 | peaceful-parent 10 | 1.0-SNAPSHOT 11 | 12 | 13 | com.peaceful 14 | task-ops 15 | 2.6-SNAPSHOT 16 | 17 | 18 | 19 | 20 | org.springframework 21 | spring-webmvc 22 | 23 | 24 | 25 | org.springframework.security 26 | spring-security-web 27 | 28 | 29 | 30 | org.springframework.security 31 | spring-security-config 32 | 33 | 34 | 35 | 36 | org.freemarker 37 | freemarker 38 | 39 | 40 | 41 | 42 | 43 | org.mybatis 44 | mybatis-spring 45 | 1.2.2 46 | 47 | 48 | 49 | org.mybatis 50 | mybatis 51 | 3.2.8 52 | 53 | 54 | 55 | 56 | jstl 57 | jstl 58 | 59 | 60 | 61 | com.peaceful 62 | peaceful-common-utils 63 | 1.0-SNAPSHOT 64 | 65 | 66 | 67 | javax 68 | javaee-api 69 | 7.0 70 | provided 71 | 72 | 73 | 74 | org.apache.httpcomponents 75 | httpclient 76 | 77 | 78 | 79 | com.typesafe 80 | config 81 | 1.2.1 82 | 83 | 84 | 85 | com.peaceful 86 | redis-manage 87 | 1.1-SNAPSHOT 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /task-ops/src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/.DS_Store -------------------------------------------------------------------------------- /task-ops/src/main/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/.DS_Store -------------------------------------------------------------------------------- /task-ops/src/main/filters/dev.properties: -------------------------------------------------------------------------------- 1 | #dev.properties 2 | #Sun Mar 30 01:01:22 CST 2014 3 | #create by WangJun 4 | #email wangjuntytl@163.com 5 | 6 | #env conf 7 | running.mode=dev 8 | 9 | # log conf 10 | root.log.level=debug 11 | root.log.appender=console-appender 12 | -------------------------------------------------------------------------------- /task-ops/src/main/filters/product.properties: -------------------------------------------------------------------------------- 1 | #product.properties 2 | #Sun Mar 30 01:01:22 CST 2014 3 | #create by WangJun 4 | #email wangjuntytl@163.com 5 | 6 | #env conf 7 | running.mode=product 8 | 9 | # log conf 10 | root.log.level=info 11 | root.log.appender=file-appender 12 | -------------------------------------------------------------------------------- /task-ops/src/main/filters/test.properties: -------------------------------------------------------------------------------- 1 | #test.properties 2 | #Sun Mar 30 01:01:22 CST 2014 3 | #create by WangJun 4 | #email wangjuntytl@163.com 5 | 6 | #env conf 7 | running.mode=test 8 | 9 | # log conf 10 | root.log.level=debug 11 | root.log.appender=file-appender -------------------------------------------------------------------------------- /task-ops/src/main/java/com/peaceful/task/ops/admin/controller/ConfController.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.ops.admin.controller; 2 | 3 | import com.peaceful.common.util.Http; 4 | import com.peaceful.task.ops.common.Conf; 5 | import org.springframework.context.annotation.Description; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | 10 | /** 11 | * @author WangJun 12 | * @version 1.0 16/4/7 13 | */ 14 | @RequestMapping("/conf") 15 | @Controller 16 | @ResponseBody 17 | public class ConfController { 18 | 19 | @RequestMapping("/cluster") 20 | @Description("获取集群列表") 21 | public void getClusterList() { 22 | Http.responseJSON(Conf.getConf().clusterList); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /task-ops/src/main/java/com/peaceful/task/ops/admin/controller/OnloadController.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.ops.admin.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | 5 | /** 6 | * @author WangJun 7 | * @version 1.0 16/4/25 8 | */ 9 | @Controller 10 | public class OnloadController { 11 | 12 | 13 | static { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /task-ops/src/main/java/com/peaceful/task/ops/admin/controller/WelcomeController.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.ops.admin.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | 8 | import static com.peaceful.common.redis.service.Redis.cmd; 9 | 10 | /** 11 | * @author WangJun 12 | * @version 1.0 16/3/31 13 | */ 14 | @RequestMapping("/") 15 | @Controller 16 | public class WelcomeController { 17 | 18 | 19 | @RequestMapping(value = {"index", ""}) 20 | public String index(HttpServletRequest request) { 21 | return "welcome/index"; 22 | } 23 | 24 | @RequestMapping(value = "01") 25 | public String template01(HttpServletRequest request) { 26 | return "welcome/template01"; 27 | } 28 | 29 | @RequestMapping(value = "02") 30 | public String template02(HttpServletRequest request) { 31 | return "welcome/template02"; 32 | } 33 | 34 | @RequestMapping(value = "03") 35 | public String template03(HttpServletRequest request) { 36 | return "welcome/template03"; 37 | } 38 | 39 | @RequestMapping(value = "04") 40 | public String template04(HttpServletRequest request) { 41 | return "welcome/template04"; 42 | } 43 | 44 | 45 | @RequestMapping(value = {"help"}) 46 | public String help(HttpServletRequest request) { 47 | return "help/index"; 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /task-ops/src/main/java/com/peaceful/task/ops/common/ClusterConsoleFilter.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.ops.common; 2 | 3 | import javax.servlet.*; 4 | import javax.servlet.http.HttpServletRequest; 5 | import java.io.IOException; 6 | import java.util.List; 7 | 8 | /** 9 | * @author WangJun 10 | * @version 1.0 15/9/25 11 | * @since 1.6 12 | */ 13 | 14 | public class ClusterConsoleFilter implements Filter { 15 | 16 | 17 | @Override 18 | public void init(FilterConfig filterConfig) throws ServletException { 19 | 20 | } 21 | 22 | @Override 23 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 24 | HttpServletRequest request = (HttpServletRequest) servletRequest; 25 | String currentCluster = request.getParameter("currentCluster"); 26 | if (currentCluster == null || currentCluster.equals("")) { 27 | List keys = Conf.getConf().clusterList; 28 | for (String key : keys) { 29 | currentCluster = key; 30 | break; 31 | } 32 | } 33 | request.setAttribute("currentCluster", currentCluster); 34 | filterChain.doFilter(request, servletResponse); 35 | } 36 | 37 | @Override 38 | public void destroy() { 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /task-ops/src/main/java/com/peaceful/task/ops/common/Conf.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.ops.common; 2 | 3 | import com.typesafe.config.Config; 4 | import com.typesafe.config.ConfigFactory; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.concurrent.Executors; 11 | import java.util.concurrent.ScheduledExecutorService; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * container cluster list conf and web front-end conf 16 | * 17 | * @author WangJun 18 | * @version 1.0 15/9/24 19 | * @since 1.6 20 | */ 21 | 22 | public class Conf { 23 | 24 | public List clusterList = new ArrayList(); 25 | private Logger logger = LoggerFactory.getLogger(getClass()); 26 | private static final ScheduledExecutorService SCHEDULE = Executors.newScheduledThreadPool(1); 27 | 28 | private Conf() { 29 | SCHEDULE.scheduleAtFixedRate(new Runnable() { 30 | @Override 31 | public void run() { 32 | Config config = ConfigFactory.load("taskCluster"); 33 | // cluster list 34 | List list = config.getStringList("taskCluster.clusterList"); 35 | clusterList = list; 36 | } 37 | },0,5, TimeUnit.SECONDS); 38 | 39 | 40 | } 41 | 42 | private static class Single { 43 | public static Conf conf = new Conf(); 44 | } 45 | 46 | public static Conf getConf() { 47 | return Single.conf; 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /task-ops/src/main/java/com/peaceful/task/ops/common/SQLiteHelper.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.ops.common; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.apache.commons.lang3.exception.ExceptionUtils; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.sql.*; 9 | 10 | /** 11 | * @author WangJun 12 | * @version 1.0 16/4/25 13 | */ 14 | public class SQLiteHelper { 15 | 16 | private static final String userDir = System.getProperty("user.dir"); 17 | private static final String driver = "org.sqlite.JDBC"; 18 | private static final String url = "jdbc:sqlite:"+userDir+"/task.dashboard.db"; 19 | private static Connection connection = null; 20 | private static final Object CONN_MONITOR = new Object(); 21 | private static final Logger LOGGER = LoggerFactory.getLogger(SQLiteHelper.class); 22 | 23 | public static Connection getConn() { 24 | 25 | if (connection != null) { 26 | return connection; 27 | } else { 28 | synchronized (CONN_MONITOR) { 29 | if (connection != null) { 30 | return connection; 31 | } 32 | try { 33 | Class.forName(driver); 34 | // 默认在当前目录下创建 35 | connection = DriverManager.getConnection(url); 36 | return connection; 37 | } catch (Exception e) { 38 | System.err.println(e.getClass().getName() + ": " + e.getMessage()); 39 | LOGGER.error(ExceptionUtils.getRootCauseMessage(e)); 40 | return null; 41 | } 42 | } 43 | } 44 | } 45 | 46 | public static int createTable(String sql, String... indexs) throws SQLException { 47 | String table = sql.split("\\s+")[2]; 48 | if (StringUtils.isBlank(table)) { 49 | return -1; 50 | } 51 | String existSql = String.format("select count(*) from sqlite_master where type='table' and name = '%s' ", table); 52 | PreparedStatement preparedStatement = getConn().prepareStatement(existSql); 53 | ResultSet resultSet = preparedStatement.executeQuery(); 54 | if (resultSet.getInt(1) > 0) { 55 | resultSet.close(); 56 | preparedStatement.close(); 57 | return 0; 58 | } else { 59 | resultSet.close(); 60 | preparedStatement.close(); 61 | execute(sql); 62 | if (indexs != null && indexs.length > 0) { 63 | for (String index : indexs) { 64 | sql = String.format("CREATE INDEX %s_%s_index ON %s (%s)", table, index, table, index); 65 | execute(sql); 66 | } 67 | } 68 | return 1; 69 | } 70 | } 71 | 72 | /** 73 | * execute sql 74 | * 75 | * @param sql 76 | * @throws SQLException 77 | */ 78 | public static void execute(String sql) throws SQLException { 79 | PreparedStatement preparedStatement = getConn().prepareStatement(sql); 80 | LOGGER.info("executor sql {} ,result is {} ", sql, preparedStatement.execute()); 81 | preparedStatement.close(); 82 | } 83 | 84 | public static int executeUpdate(String sql) throws SQLException { 85 | PreparedStatement preparedStatement = getConn().prepareStatement(sql); 86 | int rows = preparedStatement.executeUpdate(); 87 | LOGGER.info("executor sql {} ,result is {} ", sql, rows); 88 | preparedStatement.close(); 89 | return rows; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /task-ops/src/main/java/com/peaceful/task/ops/task/api/CycleQueue.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.ops.task.api; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * 基于数据实现的循环队列,用于存取最新的固定长度的数据 7 | * 8 | * @author WangJun 9 | * @version 1.0 15/9/16 10 | * @since 1.6 11 | */ 12 | 13 | public class CycleQueue implements Serializable { 14 | 15 | /** 16 | * 数组下一个索引位置 17 | */ 18 | private int index; 19 | /** 20 | * 循环队列的大小 21 | */ 22 | private int length; 23 | /** 24 | * 是否队列已处于循环转态 25 | */ 26 | private boolean cycle; 27 | /** 28 | * 存取具体数据的容器 29 | */ 30 | private Object[] data; 31 | 32 | 33 | /** 34 | * 利用指定大小的值初始化循环队列容器 35 | * 36 | * @param length 37 | */ 38 | public CycleQueue(int length) { 39 | this.length = length; 40 | data = new Object[length]; 41 | } 42 | 43 | /** 44 | * 线程安全的存入最新值到容器中 45 | * 46 | * @param value 47 | */ 48 | public synchronized void push(E value) { 49 | if (index >= length) { 50 | index = index - length; 51 | cycle = true; 52 | } 53 | data[index] = value; 54 | index++; 55 | } 56 | 57 | /** 58 | * 获取目前容器内的所有值 59 | * 60 | * @return 61 | */ 62 | public Object[] get() { 63 | Object[] truthData = new Object[length]; 64 | int currentIndex = (index - 1); 65 | if (cycle) { 66 | for (int i = (length - 1); i >= 0; i--) { 67 | if (currentIndex < 0) { 68 | truthData[i] = data[currentIndex + length]; 69 | } else { 70 | truthData[i] = data[currentIndex]; 71 | } 72 | currentIndex--; 73 | } 74 | } else { 75 | Object[] data = new Object[index]; 76 | for (int i = 0; i <= currentIndex; i++) { 77 | data[i] = this.data[i]; 78 | } 79 | return data; 80 | } 81 | return truthData; 82 | } 83 | 84 | /** 85 | * 获取容器内的最新值 86 | * 87 | * @return 88 | */ 89 | public E getCurrentValue() { 90 | int currentIndex = (index - 1); 91 | if (currentIndex < 0) currentIndex = 0; 92 | return (E) data[currentIndex]; 93 | } 94 | 95 | @Override 96 | public String toString() { 97 | Object[] data = get(); 98 | String res = "[ "; 99 | for (Object object : data) { 100 | res += object + ","; 101 | } 102 | res = res.substring(0, res.length() - 1); 103 | res += " ]"; 104 | return res; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /task-ops/src/main/java/com/peaceful/task/ops/task/api/GraphData.java: -------------------------------------------------------------------------------- 1 | package com.peaceful.task.ops.task.api; 2 | 3 | /** 4 | * @author WangJun 5 | * @version 1.0 16/4/5 6 | */ 7 | public class GraphData { 8 | 9 | public String tag; 10 | public CycleQueue timeAxis; 11 | public CycleQueue produceAxis; 12 | public CycleQueue consumeAxis; 13 | 14 | public GraphData(String tag,int size){ 15 | this.tag = tag; 16 | this.timeAxis = new CycleQueue(size); 17 | produceAxis = new CycleQueue(size); 18 | consumeAxis = new CycleQueue(size); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /task-ops/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #create by WangJun 2 | #date 2014-10-29 3 | #app global configs 4 | 5 | dev.mode=${dev.mode} 6 | running.mode=${dev.mode} 7 | build.version=${timestamp} 8 | 9 | -------------------------------------------------------------------------------- /task-ops/src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /task-ops/src/main/resources/taskCluster.conf: -------------------------------------------------------------------------------- 1 | taskCluster: { 2 | 3 | clusterList: ["TASK","demo02","demo03"] 4 | 5 | } -------------------------------------------------------------------------------- /task-ops/src/main/webapp/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/.DS_Store -------------------------------------------------------------------------------- /task-ops/src/main/webapp/WEB-INF/page/ftl/test.ftl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/WEB-INF/page/ftl/test.ftl -------------------------------------------------------------------------------- /task-ops/src/main/webapp/WEB-INF/page/jsp/errors/404.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: wangjun 4 | Date: 15/1/27 5 | Time: 上午11:03 6 | To change this weixin.template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 | Task 12 | 13 | 14 | 15 |

Sorry, request service is not exist

16 | 17 | 18 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/WEB-INF/page/jsp/errors/error.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: wangjun 4 | Date: 15/1/27 5 | Time: 上午11:03 6 | To change this weixin.template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 | Task 12 | 13 | 14 | 15 |
16 | 17 | 18 |
19 | ERROR 20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/WEB-INF/page/jsp/help/index.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: wangjun 4 | Date: 15/1/27 5 | Time: 上午11:03 6 | To change this weixin.template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Url Search 19 | 20 | 21 | 22 | 23 | 24 | 38 | 39 | 48 | 84 | 85 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/WEB-INF/page/jsp/test.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: wangjun 4 | Date: 14/11/1 5 | Time: 下午1:21 6 | To change this weixin.template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 | 12 | 13 | 14 |

hello world

15 | 16 | 17 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/WEB-INF/page/jsp/welcome/template01.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: wangjun 4 | Date: 15/1/27 5 | Time: 上午11:03 6 | To change this weixin.template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 | <%--container 居中,container-fluid 满屏--%> 12 |
13 | Hello world 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/WEB-INF/page/jsp/welcome/template02.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: wangjun 4 | Date: 15/1/27 5 | Time: 上午11:03 6 | To change this weixin.template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 |
12 |
13 | 14 |
15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/WEB-INF/page/jsp/welcome/template03.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: wangjun 4 | Date: 15/1/27 5 | Time: 上午11:03 6 | To change this weixin.template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 | <%--container 居中,container-fluid 满屏--%> 12 |
13 |
14 |
15 |

Simple Sidebar

16 |
17 |
18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/WEB-INF/springMvc-servlet.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 55 | 56 | 57 | errors/error 58 | errors/err 59 | 60 | 61 | 62 | 63 | 500 64 | 404 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | index.html 8 | 9 | 10 | contextConfigLocation 11 | 12 | WEB-INF/springMvc-servlet.xml 13 | 14 | 15 | 16 | springMvc 17 | org.springframework.web.servlet.DispatcherServlet 18 | 1 19 | 20 | 21 | springMvc 22 | / 23 | 24 | 25 | org.springframework.web.context.ContextLoaderListener 26 | 27 | 28 | org.springframework.web.context.request.RequestContextListener 29 | 30 | 31 | org.springframework.web.util.IntrospectorCleanupListener 32 | 33 | 34 | springSecurityFilterChain 35 | org.springframework.web.filter.DelegatingFilterProxy 36 | 37 | targetFilterLifecycle 38 | true 39 | 40 | 41 | 42 | springSecurityFilterChain 43 | /* 44 | 45 | 46 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/css/metisMenu.min.css: -------------------------------------------------------------------------------- 1 | /* 2 | * metismenu - v2.5.0 3 | * A jQuery menu plugin 4 | * https://github.com/onokumus/metisMenu#readme 5 | * 6 | * Made by Osman Nuri Okumuş (https://github.com/onokumus) 7 | * Under MIT License 8 | */ 9 | 10 | .metismenu .arrow { 11 | float: right; 12 | line-height: 1.42857 13 | } 14 | 15 | [dir=rtl] .metismenu .arrow { 16 | float: left 17 | } 18 | 19 | .metismenu .glyphicon.arrow:before { 20 | content: "\e079" 21 | } 22 | 23 | .metismenu .active > a > .glyphicon.arrow:before { 24 | content: "\e114" 25 | } 26 | 27 | .metismenu .fa.arrow:before { 28 | content: "\f104" 29 | } 30 | 31 | .metismenu .active > a > .fa.arrow:before { 32 | content: "\f107" 33 | } 34 | 35 | .metismenu .ion.arrow:before { 36 | content: "\f3d2" 37 | } 38 | 39 | .metismenu .active > a > .ion.arrow:before { 40 | content: "\f3d0" 41 | } 42 | 43 | .metismenu .plus-times { 44 | float: right 45 | } 46 | 47 | [dir=rtl] .metismenu .plus-times { 48 | float: left 49 | } 50 | 51 | .metismenu .fa.plus-times:before { 52 | content: "\f067" 53 | } 54 | 55 | .metismenu .active > a > .fa.plus-times { 56 | -webkit-transform: rotate(45deg); 57 | -ms-transform: rotate(45deg); 58 | -o-transform: rotate(45deg); 59 | transform: rotate(45deg) 60 | } 61 | 62 | .metismenu .plus-minus { 63 | float: right 64 | } 65 | 66 | [dir=rtl] .metismenu .plus-minus { 67 | float: left 68 | } 69 | 70 | .metismenu .fa.plus-minus:before { 71 | content: "\f067" 72 | } 73 | 74 | .metismenu .active > a > .fa.plus-minus:before { 75 | content: "\f068" 76 | } 77 | 78 | .metismenu .collapse { 79 | display: none 80 | } 81 | 82 | .metismenu .collapse.in { 83 | display: block 84 | } 85 | 86 | .metismenu .collapsing { 87 | position: relative; 88 | height: 0; 89 | overflow: hidden; 90 | -webkit-transition-timing-function: ease; 91 | -o-transition-timing-function: ease; 92 | transition-timing-function: ease; 93 | -webkit-transition-duration: .35s; 94 | -o-transition-duration: .35s; 95 | transition-duration: .35s; 96 | -webkit-transition-property: height, visibility; 97 | -o-transition-property: height, visibility; 98 | transition-property: height, visibility 99 | } 100 | 101 | 102 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /task-ops/src/main/webapp/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /task-ops/src/main/webapp/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /task-ops/src/main/webapp/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /task-ops/src/main/webapp/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /task-ops/src/main/webapp/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /task-ops/src/main/webapp/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /task-ops/src/main/webapp/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /task-ops/src/main/webapp/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/fonts/ionicons.eot -------------------------------------------------------------------------------- /task-ops/src/main/webapp/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/fonts/ionicons.ttf -------------------------------------------------------------------------------- /task-ops/src/main/webapp/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/fonts/ionicons.woff -------------------------------------------------------------------------------- /task-ops/src/main/webapp/image/123.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/image/123.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/image/header.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/image/header.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/js/helper/Map.js: -------------------------------------------------------------------------------- 1 | Array.prototype.remove = function(s) { 2 | for (var i = 0; i < this.length; i++) { 3 | if (s == this[i]) 4 | this.splice(i, 1); 5 | } 6 | }; 7 | 8 | /** 9 | * Simple Map 10 | * 11 | * 12 | * var m = new Map(); 13 | * m.put('key','value'); 14 | * ... 15 | * var s = ""; 16 | * m.each(function(key,value,index){ 17 | * s += index+":"+ key+"="+value+"/n"; 18 | * }); 19 | * alert(s); 20 | * 21 | * @author dewitt 22 | * @date 2008-05-24 23 | */ 24 | function Map() { 25 | /** 存放键的数组(遍历用到) */ 26 | this.keys = []; 27 | /** 存放数据 */ 28 | this.data = {}; 29 | 30 | /** 31 | * 放入一个键值对 32 | * @param {String} key 33 | * @param {Object} value 34 | */ 35 | this.put = function(key, value) { 36 | if(this.data[key] == null){ 37 | this.keys.push(key); 38 | } 39 | this.data[key] = value; 40 | }; 41 | 42 | /** 43 | * 获取某键对应的值 44 | * @param {String} key 45 | * @return {Object} value 46 | */ 47 | this.get = function(key) { 48 | return this.data[key]; 49 | }; 50 | 51 | /** 52 | * 删除一个键值对 53 | * @param {String} key 54 | */ 55 | this.remove = function(key) { 56 | this.keys.remove(key); 57 | this.data[key] = null; 58 | }; 59 | 60 | /** 61 | * 遍历Map,执行处理函数 62 | * 63 | * @param {Function} 回调函数 function(key,value,index){..} 64 | */ 65 | this.each = function(fn){ 66 | if(typeof fn != 'function'){ 67 | return; 68 | } 69 | var len = this.keys.length; 70 | for(var i=0;i").append($("").attr("class", "active").append($('')).html( clusterList[i]))); 8 | } else { 9 | $("#cluster_list").append($("
  • ").append($("").append($('')).html( clusterList[i]))); 10 | } 11 | 12 | } 13 | /*var url = window.location; 14 | var element = $('ul.nav a').filter(function() { 15 | return this.href == url; 16 | }).addClass('active').parent().parent().addClass('in').parent(); 17 | if (element.is('li')) { 18 | element.addClass('active'); 19 | }*/ 20 | }); 21 | 22 | $(document).on('click', '.cluster_nav', function () { 23 | var name = $(this).html(); 24 | var url = window.location.pathname; 25 | window.location.href = url + "?currentCluster=" + name; 26 | }); 27 | }); -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/.DS_Store -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/image/TaskDispatch-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/image/TaskDispatch-01.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/image/TaskDispatch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/image/TaskDispatch.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/image/TaskModal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/image/TaskModal.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/image/TaskMonitor-01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/image/TaskMonitor-01.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/image/TaskMonitor-02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/image/TaskMonitor-02.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/image/TaskMonitor-03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/image/TaskMonitor-03.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/image/TaskMonitor-04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/image/TaskMonitor-04.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/image/TaskProcess.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/image/TaskProcess.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template01/dashboard.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Base structure 3 | */ 4 | 5 | /* Move down content because we have a fixed navbar that is 50px tall */ 6 | body { 7 | padding-top: 50px; 8 | } 9 | 10 | 11 | /* 12 | * Global add-ons 13 | */ 14 | 15 | .sub-header { 16 | padding-bottom: 10px; 17 | border-bottom: 1px solid #eee; 18 | } 19 | 20 | /* 21 | * Top navigation 22 | * Hide default border to remove 1px line. 23 | */ 24 | .navbar-fixed-top { 25 | border: 0; 26 | } 27 | 28 | /* 29 | * Sidebar 30 | */ 31 | 32 | /* Hide for mobile, show later */ 33 | .sidebar { 34 | display: none; 35 | } 36 | @media (min-width: 768px) { 37 | .sidebar { 38 | position: fixed; 39 | top: 51px; 40 | bottom: 0; 41 | left: 0; 42 | z-index: 1000; 43 | display: block; 44 | padding: 20px; 45 | overflow-x: hidden; 46 | overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ 47 | background-color: #f5f5f5; 48 | border-right: 1px solid #eee; 49 | } 50 | } 51 | 52 | /* Sidebar navigation */ 53 | .nav-sidebar { 54 | margin-right: -21px; /* 20px padding + 1px border */ 55 | margin-bottom: 20px; 56 | margin-left: -20px; 57 | } 58 | .nav-sidebar > li > a { 59 | padding-right: 20px; 60 | padding-left: 20px; 61 | } 62 | .nav-sidebar > .active > a, 63 | .nav-sidebar > .active > a:hover, 64 | .nav-sidebar > .active > a:focus { 65 | color: #fff; 66 | background-color: #428bca; 67 | } 68 | 69 | 70 | /* 71 | * Main content 72 | */ 73 | 74 | .main { 75 | padding: 20px; 76 | } 77 | @media (min-width: 768px) { 78 | .main { 79 | padding-right: 40px; 80 | padding-left: 40px; 81 | } 82 | } 83 | .main .page-header { 84 | margin-top: 0; 85 | } 86 | 87 | 88 | /* 89 | * Placeholder dashboard ideas 90 | */ 91 | 92 | .placeholders { 93 | margin-bottom: 30px; 94 | text-align: center; 95 | } 96 | .placeholders h4 { 97 | margin-bottom: 0; 98 | } 99 | .placeholder { 100 | margin-bottom: 20px; 101 | } 102 | .placeholder img { 103 | display: inline-block; 104 | border-radius: 50%; 105 | } 106 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template02/sb-admin-2.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $('#side-menu').metisMenu(); 3 | 4 | }); 5 | 6 | //Loads the correct sidebar on window load, 7 | //collapses the sidebar on window resize. 8 | // Sets the min-height of #page-wrapper to window size 9 | $(function() { 10 | $(window).on("load resize", function() { 11 | var topOffset = 50; 12 | var width = (this.window.innerWidth > 0) ? this.window.innerWidth : this.screen.width; 13 | if (width < 768) { 14 | $('div.navbar-collapse').addClass('collapse'); 15 | topOffset = 100; // 2-row-menu 16 | } else { 17 | $('div.navbar-collapse').removeClass('collapse'); 18 | } 19 | 20 | var height = ((this.window.innerHeight > 0) ? this.window.innerHeight : this.screen.height) - 1; 21 | height = height - topOffset; 22 | if (height < 1) height = 1; 23 | if (height > topOffset) { 24 | $("#page-wrapper").css("min-height", (height) + "px"); 25 | } 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template03/simple-sidebar.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - Simple Sidebar HTML Template (http://startbootstrap.com) 3 | * Code licensed under the Apache License v2.0. 4 | * For details, see http://www.apache.org/licenses/LICENSE-2.0. 5 | */ 6 | 7 | /* Toggle Styles */ 8 | 9 | #wrapper { 10 | padding-left: 0; 11 | -webkit-transition: all 0.5s ease; 12 | -moz-transition: all 0.5s ease; 13 | -o-transition: all 0.5s ease; 14 | transition: all 0.5s ease; 15 | } 16 | 17 | #wrapper.toggled { 18 | padding-left: 250px; 19 | } 20 | 21 | #sidebar-wrapper { 22 | z-index: 1000; 23 | position: fixed; 24 | left: 250px; 25 | width: 0; 26 | height: 100%; 27 | margin-left: -250px; 28 | overflow-y: auto; 29 | background: #000; 30 | -webkit-transition: all 0.5s ease; 31 | -moz-transition: all 0.5s ease; 32 | -o-transition: all 0.5s ease; 33 | transition: all 0.5s ease; 34 | } 35 | 36 | #wrapper.toggled #sidebar-wrapper { 37 | width: 250px; 38 | } 39 | 40 | #page-content-wrapper { 41 | width: 100%; 42 | position: absolute; 43 | padding: 15px; 44 | } 45 | 46 | #wrapper.toggled #page-content-wrapper { 47 | position: absolute; 48 | margin-right: -250px; 49 | } 50 | 51 | /* Sidebar Styles */ 52 | 53 | .sidebar-nav { 54 | position: absolute; 55 | top: 0; 56 | width: 250px; 57 | margin: 0; 58 | padding: 0; 59 | list-style: none; 60 | } 61 | 62 | .sidebar-nav li { 63 | text-indent: 20px; 64 | line-height: 40px; 65 | } 66 | 67 | .sidebar-nav li a { 68 | display: block; 69 | text-decoration: none; 70 | color: #999999; 71 | } 72 | 73 | .sidebar-nav li a:hover { 74 | text-decoration: none; 75 | color: #fff; 76 | background: rgba(255,255,255,0.2); 77 | } 78 | 79 | .sidebar-nav li a:active, 80 | .sidebar-nav li a:focus { 81 | text-decoration: none; 82 | } 83 | 84 | .sidebar-nav > .sidebar-brand { 85 | height: 65px; 86 | font-size: 18px; 87 | line-height: 60px; 88 | } 89 | 90 | .sidebar-nav > .sidebar-brand a { 91 | color: #999999; 92 | } 93 | 94 | .sidebar-nav > .sidebar-brand a:hover { 95 | color: #fff; 96 | background: none; 97 | } 98 | 99 | @media(min-width:768px) { 100 | #wrapper { 101 | padding-left: 250px; 102 | } 103 | 104 | #wrapper.toggled { 105 | padding-left: 0; 106 | } 107 | 108 | #sidebar-wrapper { 109 | width: 250px; 110 | } 111 | 112 | #wrapper.toggled #sidebar-wrapper { 113 | width: 0; 114 | } 115 | 116 | #page-content-wrapper { 117 | padding: 20px; 118 | position: relative; 119 | } 120 | 121 | #wrapper.toggled #page-content-wrapper { 122 | position: relative; 123 | margin-right: 0; 124 | } 125 | } -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/avatar.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/avatar04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/avatar04.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/avatar2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/avatar2.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/avatar3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/avatar3.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/avatar5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/avatar5.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/boxed-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/boxed-bg.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/boxed-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/boxed-bg.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/credit/american-express.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/credit/american-express.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/credit/cirrus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/credit/cirrus.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/credit/mastercard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/credit/mastercard.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/credit/mestro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/credit/mestro.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/credit/paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/credit/paypal.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/credit/paypal2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/credit/paypal2.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/credit/visa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/credit/visa.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/default-50x50.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/default-50x50.gif -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/icons.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/photo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/photo1.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/photo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/photo2.png -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/photo3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/photo3.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/photo4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/photo4.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/user1-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/user1-128x128.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/user2-160x160.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/user2-160x160.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/user3-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/user3-128x128.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/user4-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/user4-128x128.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/user5-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/user5-128x128.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/user6-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/user6-128x128.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/user7-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/user7-128x128.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/img/user8-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJunTYTL/Task/e9b84759c048c785a46fea49d43d8f9219a4e3f5/task-ops/src/main/webapp/static/template04/img/user8-128x128.jpg -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/skins/skin-black.min.css: -------------------------------------------------------------------------------- 1 | .skin-black .main-header{-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.skin-black .main-header .navbar-toggle{color:#333}.skin-black .main-header .navbar-brand{color:#333;border-right:1px solid #eee}.skin-black .main-header>.navbar{background-color:#fff}.skin-black .main-header>.navbar .nav>li>a{color:#333}.skin-black .main-header>.navbar .nav>li>a:hover,.skin-black .main-header>.navbar .nav>li>a:active,.skin-black .main-header>.navbar .nav>li>a:focus,.skin-black .main-header>.navbar .nav .open>a,.skin-black .main-header>.navbar .nav .open>a:hover,.skin-black .main-header>.navbar .nav .open>a:focus,.skin-black .main-header>.navbar .nav>.active>a{background:#fff;color:#999}.skin-black .main-header>.navbar .sidebar-toggle{color:#333}.skin-black .main-header>.navbar .sidebar-toggle:hover{color:#999;background:#fff}.skin-black .main-header>.navbar>.sidebar-toggle{color:#333;border-right:1px solid #eee}.skin-black .main-header>.navbar .navbar-nav>li>a{border-right:1px solid #eee}.skin-black .main-header>.navbar .navbar-custom-menu .navbar-nav>li>a,.skin-black .main-header>.navbar .navbar-right>li>a{border-left:1px solid #eee;border-right-width:0}.skin-black .main-header>.logo{background-color:#fff;color:#333;border-bottom:0 solid transparent;border-right:1px solid #eee}.skin-black .main-header>.logo:hover{background-color:#fcfcfc}@media (max-width:767px){.skin-black .main-header>.logo{background-color:#222;color:#fff;border-bottom:0 solid transparent;border-right:none}.skin-black .main-header>.logo:hover{background-color:#1f1f1f}}.skin-black .main-header li.user-header{background-color:#222}.skin-black .content-header{background:transparent;box-shadow:none}.skin-black .wrapper,.skin-black .main-sidebar,.skin-black .left-side{background-color:#222d32}.skin-black .user-panel>.info,.skin-black .user-panel>.info>a{color:#fff}.skin-black .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-black .sidebar-menu>li>a{border-left:3px solid transparent}.skin-black .sidebar-menu>li:hover>a,.skin-black .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#fff}.skin-black .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-black .sidebar a{color:#b8c7ce}.skin-black .sidebar a:hover{text-decoration:none}.skin-black .treeview-menu>li>a{color:#8aa4af}.skin-black .treeview-menu>li.active>a,.skin-black .treeview-menu>li>a:hover{color:#fff}.skin-black .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-black .sidebar-form input[type="text"],.skin-black .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-black .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-black .sidebar-form input[type="text"]:focus,.skin-black .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-black .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-black .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-black .pace .pace-progress{background:#222}.skin-black .pace .pace-activity{border-top-color:#222;border-left-color:#222} -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/skins/skin-blue.min.css: -------------------------------------------------------------------------------- 1 | .skin-blue .main-header .navbar{background-color:#3c8dbc}.skin-blue .main-header .navbar .nav>li>a{color:#fff}.skin-blue .main-header .navbar .nav>li>a:hover,.skin-blue .main-header .navbar .nav>li>a:active,.skin-blue .main-header .navbar .nav>li>a:focus,.skin-blue .main-header .navbar .nav .open>a,.skin-blue .main-header .navbar .nav .open>a:hover,.skin-blue .main-header .navbar .nav .open>a:focus,.skin-blue .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-blue .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-blue .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue .main-header .navbar .sidebar-toggle:hover{background-color:#367fa9}@media (max-width:767px){.skin-blue .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-blue .main-header .navbar .dropdown-menu li a{color:#fff}.skin-blue .main-header .navbar .dropdown-menu li a:hover{background:#367fa9}}.skin-blue .main-header .logo{background-color:#367fa9;color:#fff;border-bottom:0 solid transparent}.skin-blue .main-header .logo:hover{background-color:#357ca5}.skin-blue .main-header li.user-header{background-color:#3c8dbc}.skin-blue .content-header{background:transparent}.skin-blue .wrapper,.skin-blue .main-sidebar,.skin-blue .left-side{background-color:#222d32}.skin-blue .user-panel>.info,.skin-blue .user-panel>.info>a{color:#fff}.skin-blue .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-blue .sidebar-menu>li>a{border-left:3px solid transparent}.skin-blue .sidebar-menu>li:hover>a,.skin-blue .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#3c8dbc}.skin-blue .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-blue .sidebar a{color:#b8c7ce}.skin-blue .sidebar a:hover{text-decoration:none}.skin-blue .treeview-menu>li>a{color:#8aa4af}.skin-blue .treeview-menu>li.active>a,.skin-blue .treeview-menu>li>a:hover{color:#fff}.skin-blue .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-blue .sidebar-form input[type="text"],.skin-blue .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-blue .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-blue .sidebar-form input[type="text"]:focus,.skin-blue .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-blue .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-blue .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-blue.layout-top-nav .main-header>.logo{background-color:#3c8dbc;color:#fff;border-bottom:0 solid transparent}.skin-blue.layout-top-nav .main-header>.logo:hover{background-color:#3b8ab8} -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/skins/skin-green.min.css: -------------------------------------------------------------------------------- 1 | .skin-green .main-header .navbar{background-color:#00a65a}.skin-green .main-header .navbar .nav>li>a{color:#fff}.skin-green .main-header .navbar .nav>li>a:hover,.skin-green .main-header .navbar .nav>li>a:active,.skin-green .main-header .navbar .nav>li>a:focus,.skin-green .main-header .navbar .nav .open>a,.skin-green .main-header .navbar .nav .open>a:hover,.skin-green .main-header .navbar .nav .open>a:focus,.skin-green .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-green .main-header .navbar .sidebar-toggle{color:#fff}.skin-green .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-green .main-header .navbar .sidebar-toggle{color:#fff}.skin-green .main-header .navbar .sidebar-toggle:hover{background-color:#008d4c}@media (max-width:767px){.skin-green .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-green .main-header .navbar .dropdown-menu li a{color:#fff}.skin-green .main-header .navbar .dropdown-menu li a:hover{background:#008d4c}}.skin-green .main-header .logo{background-color:#008d4c;color:#fff;border-bottom:0 solid transparent}.skin-green .main-header .logo:hover{background-color:#008749}.skin-green .main-header li.user-header{background-color:#00a65a}.skin-green .content-header{background:transparent}.skin-green .wrapper,.skin-green .main-sidebar,.skin-green .left-side{background-color:#222d32}.skin-green .user-panel>.info,.skin-green .user-panel>.info>a{color:#fff}.skin-green .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-green .sidebar-menu>li>a{border-left:3px solid transparent}.skin-green .sidebar-menu>li:hover>a,.skin-green .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#00a65a}.skin-green .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-green .sidebar a{color:#b8c7ce}.skin-green .sidebar a:hover{text-decoration:none}.skin-green .treeview-menu>li>a{color:#8aa4af}.skin-green .treeview-menu>li.active>a,.skin-green .treeview-menu>li>a:hover{color:#fff}.skin-green .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-green .sidebar-form input[type="text"],.skin-green .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-green .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-green .sidebar-form input[type="text"]:focus,.skin-green .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-green .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-green .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0} -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/skins/skin-purple.min.css: -------------------------------------------------------------------------------- 1 | .skin-purple .main-header .navbar{background-color:#605ca8}.skin-purple .main-header .navbar .nav>li>a{color:#fff}.skin-purple .main-header .navbar .nav>li>a:hover,.skin-purple .main-header .navbar .nav>li>a:active,.skin-purple .main-header .navbar .nav>li>a:focus,.skin-purple .main-header .navbar .nav .open>a,.skin-purple .main-header .navbar .nav .open>a:hover,.skin-purple .main-header .navbar .nav .open>a:focus,.skin-purple .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-purple .main-header .navbar .sidebar-toggle{color:#fff}.skin-purple .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-purple .main-header .navbar .sidebar-toggle{color:#fff}.skin-purple .main-header .navbar .sidebar-toggle:hover{background-color:#555299}@media (max-width:767px){.skin-purple .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-purple .main-header .navbar .dropdown-menu li a{color:#fff}.skin-purple .main-header .navbar .dropdown-menu li a:hover{background:#555299}}.skin-purple .main-header .logo{background-color:#555299;color:#fff;border-bottom:0 solid transparent}.skin-purple .main-header .logo:hover{background-color:#545096}.skin-purple .main-header li.user-header{background-color:#605ca8}.skin-purple .content-header{background:transparent}.skin-purple .wrapper,.skin-purple .main-sidebar,.skin-purple .left-side{background-color:#222d32}.skin-purple .user-panel>.info,.skin-purple .user-panel>.info>a{color:#fff}.skin-purple .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-purple .sidebar-menu>li>a{border-left:3px solid transparent}.skin-purple .sidebar-menu>li:hover>a,.skin-purple .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#605ca8}.skin-purple .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-purple .sidebar a{color:#b8c7ce}.skin-purple .sidebar a:hover{text-decoration:none}.skin-purple .treeview-menu>li>a{color:#8aa4af}.skin-purple .treeview-menu>li.active>a,.skin-purple .treeview-menu>li>a:hover{color:#fff}.skin-purple .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-purple .sidebar-form input[type="text"],.skin-purple .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-purple .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-purple .sidebar-form input[type="text"]:focus,.skin-purple .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-purple .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-purple .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0} -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/skins/skin-red-light.min.css: -------------------------------------------------------------------------------- 1 | .skin-red-light .main-header .navbar{background-color:#dd4b39}.skin-red-light .main-header .navbar .nav>li>a{color:#fff}.skin-red-light .main-header .navbar .nav>li>a:hover,.skin-red-light .main-header .navbar .nav>li>a:active,.skin-red-light .main-header .navbar .nav>li>a:focus,.skin-red-light .main-header .navbar .nav .open>a,.skin-red-light .main-header .navbar .nav .open>a:hover,.skin-red-light .main-header .navbar .nav .open>a:focus,.skin-red-light .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-red-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-red-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-red-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-red-light .main-header .navbar .sidebar-toggle:hover{background-color:#d73925}@media (max-width:767px){.skin-red-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-red-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-red-light .main-header .navbar .dropdown-menu li a:hover{background:#d73925}}.skin-red-light .main-header .logo{background-color:#dd4b39;color:#fff;border-bottom:0 solid transparent}.skin-red-light .main-header .logo:hover{background-color:#dc4735}.skin-red-light .main-header li.user-header{background-color:#dd4b39}.skin-red-light .content-header{background:transparent}.skin-red-light .wrapper,.skin-red-light .main-sidebar,.skin-red-light .left-side{background-color:#f9fafc}.skin-red-light .content-wrapper,.skin-red-light .main-footer{border-left:1px solid #d2d6de}.skin-red-light .user-panel>.info,.skin-red-light .user-panel>.info>a{color:#444}.skin-red-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-red-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-red-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-red-light .sidebar-menu>li:hover>a,.skin-red-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-red-light .sidebar-menu>li.active{border-left-color:#dd4b39}.skin-red-light .sidebar-menu>li.active>a{font-weight:600}.skin-red-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-red-light .sidebar a{color:#444}.skin-red-light .sidebar a:hover{text-decoration:none}.skin-red-light .treeview-menu>li>a{color:#777}.skin-red-light .treeview-menu>li.active>a,.skin-red-light .treeview-menu>li>a:hover{color:#000}.skin-red-light .treeview-menu>li.active>a{font-weight:600}.skin-red-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-red-light .sidebar-form input[type="text"],.skin-red-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-red-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-red-light .sidebar-form input[type="text"]:focus,.skin-red-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-red-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-red-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-red-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}} -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/skins/skin-red.min.css: -------------------------------------------------------------------------------- 1 | .skin-red .main-header .navbar{background-color:#dd4b39}.skin-red .main-header .navbar .nav>li>a{color:#fff}.skin-red .main-header .navbar .nav>li>a:hover,.skin-red .main-header .navbar .nav>li>a:active,.skin-red .main-header .navbar .nav>li>a:focus,.skin-red .main-header .navbar .nav .open>a,.skin-red .main-header .navbar .nav .open>a:hover,.skin-red .main-header .navbar .nav .open>a:focus,.skin-red .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-red .main-header .navbar .sidebar-toggle{color:#fff}.skin-red .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-red .main-header .navbar .sidebar-toggle{color:#fff}.skin-red .main-header .navbar .sidebar-toggle:hover{background-color:#d73925}@media (max-width:767px){.skin-red .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-red .main-header .navbar .dropdown-menu li a{color:#fff}.skin-red .main-header .navbar .dropdown-menu li a:hover{background:#d73925}}.skin-red .main-header .logo{background-color:#d73925;color:#fff;border-bottom:0 solid transparent}.skin-red .main-header .logo:hover{background-color:#d33724}.skin-red .main-header li.user-header{background-color:#dd4b39}.skin-red .content-header{background:transparent}.skin-red .wrapper,.skin-red .main-sidebar,.skin-red .left-side{background-color:#222d32}.skin-red .user-panel>.info,.skin-red .user-panel>.info>a{color:#fff}.skin-red .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-red .sidebar-menu>li>a{border-left:3px solid transparent}.skin-red .sidebar-menu>li:hover>a,.skin-red .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#dd4b39}.skin-red .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-red .sidebar a{color:#b8c7ce}.skin-red .sidebar a:hover{text-decoration:none}.skin-red .treeview-menu>li>a{color:#8aa4af}.skin-red .treeview-menu>li.active>a,.skin-red .treeview-menu>li>a:hover{color:#fff}.skin-red .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-red .sidebar-form input[type="text"],.skin-red .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-red .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-red .sidebar-form input[type="text"]:focus,.skin-red .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-red .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-red .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0} -------------------------------------------------------------------------------- /task-ops/src/main/webapp/static/template04/skins/skin-yellow.min.css: -------------------------------------------------------------------------------- 1 | .skin-yellow .main-header .navbar{background-color:#f39c12}.skin-yellow .main-header .navbar .nav>li>a{color:#fff}.skin-yellow .main-header .navbar .nav>li>a:hover,.skin-yellow .main-header .navbar .nav>li>a:active,.skin-yellow .main-header .navbar .nav>li>a:focus,.skin-yellow .main-header .navbar .nav .open>a,.skin-yellow .main-header .navbar .nav .open>a:hover,.skin-yellow .main-header .navbar .nav .open>a:focus,.skin-yellow .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-yellow .main-header .navbar .sidebar-toggle{color:#fff}.skin-yellow .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-yellow .main-header .navbar .sidebar-toggle{color:#fff}.skin-yellow .main-header .navbar .sidebar-toggle:hover{background-color:#e08e0b}@media (max-width:767px){.skin-yellow .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-yellow .main-header .navbar .dropdown-menu li a{color:#fff}.skin-yellow .main-header .navbar .dropdown-menu li a:hover{background:#e08e0b}}.skin-yellow .main-header .logo{background-color:#e08e0b;color:#fff;border-bottom:0 solid transparent}.skin-yellow .main-header .logo:hover{background-color:#db8b0b}.skin-yellow .main-header li.user-header{background-color:#f39c12}.skin-yellow .content-header{background:transparent}.skin-yellow .wrapper,.skin-yellow .main-sidebar,.skin-yellow .left-side{background-color:#222d32}.skin-yellow .user-panel>.info,.skin-yellow .user-panel>.info>a{color:#fff}.skin-yellow .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-yellow .sidebar-menu>li>a{border-left:3px solid transparent}.skin-yellow .sidebar-menu>li:hover>a,.skin-yellow .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#f39c12}.skin-yellow .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-yellow .sidebar a{color:#b8c7ce}.skin-yellow .sidebar a:hover{text-decoration:none}.skin-yellow .treeview-menu>li>a{color:#8aa4af}.skin-yellow .treeview-menu>li.active>a,.skin-yellow .treeview-menu>li>a:hover{color:#fff}.skin-yellow .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-yellow .sidebar-form input[type="text"],.skin-yellow .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-yellow .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-yellow .sidebar-form input[type="text"]:focus,.skin-yellow .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-yellow .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-yellow .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0} -------------------------------------------------------------------------------- /task-ops/src/main/webapp/template/01/nav.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=utf-8" %> 2 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 | <%-- 4 | ~ Copyright (c) 2014. 5 | ~ Author WangJun 6 | ~ Email wangjuntytl@163.com 7 | --%> 8 | 9 | <%--导航栏--%> 10 | 36 | 37 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/template/01/pageFooter.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=utf-8" %> 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/template/01/pageHeader.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=utf-8" %> 2 | <%-- 3 | ~ Copyright (c) 2014. 4 | ~ Author WangJun 5 | ~ Email wangjuntytl@163.com 6 | --%> 7 | <%--页面头部基本内容--%> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Task Console 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/template/02/pageFooter.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=utf-8" %> 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/template/02/pageHeader.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=utf-8" %> 2 | <%-- 3 | ~ Copyright (c) 2014. 4 | ~ Author WangJun 5 | ~ Email wangjuntytl@163.com 6 | --%> 7 | <%--页面头部基本内容--%> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Task Dashboard V2.6 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | <%--图标--%> 27 | 28 | 29 | <%--左侧导航栏--%> 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
    -------------------------------------------------------------------------------- /task-ops/src/main/webapp/template/03/nav.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=utf-8" %> 2 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 | <%-- 4 | ~ Copyright (c) 2014. 5 | ~ Author WangJun 6 | ~ Email wangjuntytl@163.com 7 | --%> 8 | 9 |
    10 | 11 | 41 | 42 | 43 | 69 | 70 | 71 | 77 | 78 | 79 |
    -------------------------------------------------------------------------------- /task-ops/src/main/webapp/template/03/pageFooter.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=utf-8" %> 2 | 3 |
    4 |
    5 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/template/03/pageHeader.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=utf-8" %> 2 | <%-- 3 | ~ Copyright (c) 2014. 4 | ~ Author WangJun 5 | ~ Email wangjuntytl@163.com 6 | --%> 7 | <%--页面头部基本内容--%> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Task Console 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /task-ops/src/main/webapp/template/myModal.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=utf-8" %> 2 | 3 | <%--触发modal的方式 4 | 1. data-toggle='modal' data-target='#myModal' 5 | 6 | 或者手动方式 7 | 1. $("#myModal).modal('show') 8 | 2. $("#myModal).modal('hide') 9 | --%> 10 | 28 | -------------------------------------------------------------------------------- /task-ops/src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=debug, stdout 2 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 3 | #log4j.appender.stdout=org.apache.log4j.FileAppender 4 | #log4j.appender.R.File=D:\\test.txt 5 | #log4j.appender.R.MaxFileSize= 100KB 6 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 7 | log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n -------------------------------------------------------------------------------- /task-ops/src/test/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | --------------------------------------------------------------------------------