From 727f860abda40058d2d38e64bee90cb4ae8f0553 Mon Sep 17 00:00:00 2001 From: mrbird <852252810@qq.com> Date: Mon, 25 Mar 2019 09:25:59 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9B=91=E6=8E=A7Dubbo=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 52.Dubbo-OPS-Mointor/dubbo-admin/pom.xml | 80 ++ .../dubboadmin/DubboAdminApplication.java | 33 + .../com/alibaba/dubboadmin/SpringUtil.java | 60 ++ .../alibaba/dubboadmin/config/I18nConfig.java | 58 ++ .../dubboadmin/config/XmlConfiguration.java | 28 + .../dubboadmin/filter/LoginFilter.java | 232 +++++ .../common/i18n/MessageResourceService.java | 25 + .../i18n/impl/MessageResourceServiceImpl.java | 53 + .../governance/service/ConfigService.java | 34 + .../governance/service/ConsumerService.java | 58 ++ .../governance/service/OverrideService.java | 49 + .../governance/service/OwnerService.java | 41 + .../governance/service/ProviderService.java | 73 ++ .../governance/service/RouteService.java | 57 ++ .../governance/service/UserService.java | 51 + .../service/impl/AbstractService.java | 46 + .../service/impl/ConfigServiceImpl.java | 46 + .../service/impl/ConsumerServiceImpl.java | 223 ++++ .../service/impl/OverrideServiceImpl.java | 191 ++++ .../service/impl/OwnerServiceImpl.java | 160 +++ .../service/impl/ProviderServiceImpl.java | 461 +++++++++ .../service/impl/RouteServiceImpl.java | 169 ++++ .../service/impl/UserServiceImpl.java | 134 +++ .../governance/sync/RegistryServerSync.java | 162 +++ .../dubboadmin/governance/sync/util/Pair.java | 84 ++ .../governance/sync/util/SyncUtils.java | 256 +++++ .../governance/util/ContextUtil.java | 38 + .../governance/util/GovernanceWarmup.java | 108 ++ .../dubboadmin/governance/util/Paginator.java | 195 ++++ .../dubboadmin/governance/util/UrlUtils.java | 61 ++ .../governance/util/WebConstants.java | 85 ++ .../registry/common/ChangeListener.java | 28 + .../registry/common/StatusManager.java | 122 +++ .../registry/common/domain/Access.java | 70 ++ .../registry/common/domain/Agreement.java | 104 ++ .../registry/common/domain/Approval.java | 89 ++ .../common/domain/ApprovalRequisition.java | 99 ++ .../registry/common/domain/Change.java | 99 ++ .../registry/common/domain/Cluster.java | 60 ++ .../registry/common/domain/Config.java | 97 ++ .../registry/common/domain/Consumer.java | 229 +++++ .../registry/common/domain/DependItem.java | 97 ++ .../registry/common/domain/Dependency.java | 45 + .../registry/common/domain/Document.java | 86 ++ .../registry/common/domain/Entity.java | 121 +++ .../registry/common/domain/Favorite.java | 60 ++ .../registry/common/domain/Feature.java | 62 ++ .../registry/common/domain/Layer.java | 66 ++ .../registry/common/domain/LoadBalance.java | 75 ++ .../registry/common/domain/Mock.java | 124 +++ .../registry/common/domain/Operation.java | 100 ++ .../registry/common/domain/Override.java | 202 ++++ .../registry/common/domain/Owner.java | 63 ++ .../registry/common/domain/PageList.java | 101 ++ .../registry/common/domain/Provider.java | 214 ++++ .../registry/common/domain/Registry.java | 94 ++ .../registry/common/domain/Route.java | 201 ++++ .../registry/common/domain/SearchHistory.java | 60 ++ .../registry/common/domain/Test.java | 114 +++ .../registry/common/domain/User.java | 259 +++++ .../registry/common/domain/Weight.java | 71 ++ .../registry/common/registry/ConvertUtil.java | 117 +++ .../registry/common/route/OverrideUtils.java | 119 +++ .../registry/common/route/ParseUtils.java | 335 ++++++ .../registry/common/route/RouteRule.java | 567 +++++++++++ .../registry/common/route/RouteRuleUtils.java | 155 +++ .../registry/common/route/RouteUtils.java | 314 ++++++ .../common/status/DatabaseStatusChecker.java | 99 ++ .../common/status/LoadStatusChecker.java | 45 + .../common/status/MemoryStatusChecker.java | 40 + .../registry/common/util/Coder.java | 59 ++ .../registry/common/util/Entities.java | 953 ++++++++++++++++++ .../registry/common/util/IntHashMap.java | 357 +++++++ .../registry/common/util/LocaleUtils.java | 38 + .../registry/common/util/MessageSource.java | 64 ++ .../registry/common/util/OverrideUtils.java | 125 +++ .../common/util/StringEscapeUtils.java | 661 ++++++++++++ .../dubboadmin/registry/common/util/Tool.java | 167 +++ .../dubboadmin/web/mvc/BaseController.java | 85 ++ .../dubboadmin/web/mvc/RouterController.java | 344 +++++++ .../web/mvc/common/auth/DubboUser.java | 44 + .../web/mvc/common/i18n/LocaleUtil.java | 36 + .../mvc/governance/AccessesController.java | 303 ++++++ .../mvc/governance/AddressesController.java | 155 +++ .../governance/ApplicationsController.java | 336 ++++++ .../mvc/governance/ConsumersController.java | 538 ++++++++++ .../governance/LoadbalancesController.java | 191 ++++ .../NoServicePrivilegeController.java | 36 + .../mvc/governance/OverridesController.java | 441 ++++++++ .../web/mvc/governance/OwnersController.java | 132 +++ .../mvc/governance/ProvidersController.java | 507 ++++++++++ .../web/mvc/governance/RoutesController.java | 644 ++++++++++++ .../mvc/governance/ServicesController.java | 236 +++++ .../web/mvc/governance/WeightsController.java | 305 ++++++ .../web/mvc/home/DisableController.java | 65 ++ .../web/mvc/home/IndexController.java | 87 ++ .../web/mvc/home/LookupController.java | 83 ++ .../web/mvc/home/RegController.java | 42 + .../web/mvc/home/RegisterController.java | 75 ++ .../web/mvc/home/RestfulController.java | 99 ++ .../web/mvc/home/ResultController.java | 78 ++ .../web/mvc/home/ServicestatusController.java | 66 ++ .../web/mvc/home/ShellController.java | 78 ++ .../web/mvc/home/StatusController.java | 68 ++ .../web/mvc/home/UnregController.java | 56 + .../web/mvc/home/UnregisterController.java | 64 ++ .../web/mvc/home/UnregisterallController.java | 61 ++ .../web/mvc/personal/InfosController.java | 51 + .../web/mvc/personal/PasswdsController.java | 49 + .../web/mvc/sysinfo/DumpController.java | 164 +++ .../web/mvc/sysinfo/DumpsController.java | 67 ++ .../web/mvc/sysinfo/EnvsController.java | 117 +++ .../web/mvc/sysinfo/LogsController.java | 99 ++ .../web/mvc/sysinfo/StatusesController.java | 55 + .../web/mvc/sysinfo/VersionsController.java | 114 +++ .../web/mvc/sysmanage/ConfigsController.java | 89 ++ .../mvc/sysmanage/PrivilegesController.java | 23 + .../web/mvc/sysmanage/UserownController.java | 43 + .../web/pulltool/DateFormatUtil.java | 74 ++ .../web/pulltool/I18nMessageTool.java | 46 + .../web/pulltool/RootContextPath.java | 41 + .../alibaba/dubboadmin/web/pulltool/Tool.java | 489 +++++++++ .../dubboadmin/web/pulltool/ToolUtil.java | 52 + .../src/main/resources/application.properties | 27 + .../src/main/resources/dubbo-admin.xml | 29 + .../main/resources/i18n/message.properties | 16 + .../main/resources/i18n/message_en.properties | 768 ++++++++++++++ .../main/resources/i18n/message_zh.properties | 802 +++++++++++++++ .../resources/i18n/message_zh_CN.properties | 802 +++++++++++++++ .../resources/i18n/message_zh_TW.properties | 726 +++++++++++++ .../src/main/resources/log4j.properties | 37 + .../src/main/resources/static/css/common.css | 689 +++++++++++++ .../src/main/resources/static/css/dubbo.css | 335 ++++++ .../src/main/resources/static/css/skin.css | 275 +++++ .../main/resources/static/images/404error.gif | Bin 0 -> 2131 bytes .../src/main/resources/static/images/bg01.gif | Bin 0 -> 52 bytes .../src/main/resources/static/images/bg02.gif | Bin 0 -> 52 bytes .../src/main/resources/static/images/bg03.gif | Bin 0 -> 52 bytes .../src/main/resources/static/images/bg04.gif | Bin 0 -> 816 bytes .../main/resources/static/images/btn_info.png | Bin 0 -> 3713 bytes .../resources/static/images/btn_service.png | Bin 0 -> 3718 bytes .../resources/static/images/button_hover.png | Bin 0 -> 3084 bytes .../resources/static/images/button_normal.png | Bin 0 -> 3551 bytes .../main/resources/static/images/co_01.gif | Bin 0 -> 138 bytes .../main/resources/static/images/co_02.gif | Bin 0 -> 141 bytes .../main/resources/static/images/co_03.gif | Bin 0 -> 141 bytes .../main/resources/static/images/co_04.gif | Bin 0 -> 142 bytes .../src/main/resources/static/images/dog.gif | Bin 0 -> 1908 bytes .../resources/static/images/dubbo_list_th.png | Bin 0 -> 3558 bytes .../src/main/resources/static/images/exit.png | Bin 0 -> 3888 bytes .../resources/static/images/fav_arrow.png | Bin 0 -> 3888 bytes .../static/images/fav_tab_active.png | Bin 0 -> 2889 bytes .../static/images/fav_tab_normal.png | Bin 0 -> 2867 bytes .../resources/static/images/fav_title.png | Bin 0 -> 3553 bytes .../main/resources/static/images/head_bg.png | Bin 0 -> 2836 bytes .../main/resources/static/images/ico_add.png | Bin 0 -> 3050 bytes .../main/resources/static/images/ico_back.png | Bin 0 -> 3258 bytes .../resources/static/images/ico_balance.png | Bin 0 -> 3090 bytes .../resources/static/images/ico_cancel.png | Bin 0 -> 3487 bytes .../resources/static/images/ico_delete.png | Bin 0 -> 3223 bytes .../resources/static/images/ico_disable.png | Bin 0 -> 3206 bytes .../main/resources/static/images/ico_down.png | Bin 0 -> 318 bytes .../main/resources/static/images/ico_edit.png | Bin 0 -> 3053 bytes .../resources/static/images/ico_enable.png | Bin 0 -> 3252 bytes .../resources/static/images/ico_error.png | Bin 0 -> 222 bytes .../resources/static/images/ico_favorite.png | Bin 0 -> 3287 bytes .../main/resources/static/images/ico_forb.png | Bin 0 -> 3924 bytes .../resources/static/images/ico_graph.png | Bin 0 -> 280 bytes .../main/resources/static/images/ico_help.png | Bin 0 -> 924 bytes .../main/resources/static/images/ico_list.png | Bin 0 -> 344 bytes .../resources/static/images/ico_password.png | Bin 0 -> 3267 bytes .../resources/static/images/ico_reconnect.png | Bin 0 -> 3018 bytes .../resources/static/images/ico_recover.png | Bin 0 -> 3371 bytes .../resources/static/images/ico_register.png | Bin 0 -> 3312 bytes .../resources/static/images/ico_reload.png | Bin 0 -> 3016 bytes .../resources/static/images/ico_renotify.png | Bin 0 -> 3173 bytes .../main/resources/static/images/ico_run.png | Bin 0 -> 3592 bytes .../main/resources/static/images/ico_save.png | Bin 0 -> 3084 bytes .../resources/static/images/ico_search.png | Bin 0 -> 3326 bytes .../main/resources/static/images/ico_show.png | Bin 0 -> 3195 bytes .../resources/static/images/ico_subscribe.png | Bin 0 -> 3142 bytes .../main/resources/static/images/ico_tree.png | Bin 0 -> 356 bytes .../main/resources/static/images/ico_up.png | Bin 0 -> 1499 bytes .../main/resources/static/images/ico_user.png | Bin 0 -> 3066 bytes .../main/resources/static/images/ico_warn.png | Bin 0 -> 644 bytes .../main/resources/static/images/input.png | Bin 0 -> 3586 bytes .../main/resources/static/images/login_bg.png | Bin 0 -> 145515 bytes .../resources/static/images/login_box.png | Bin 0 -> 13308 bytes .../static/images/login_btn_hover.png | Bin 0 -> 2983 bytes .../static/images/login_btn_normal.png | Bin 0 -> 296 bytes .../resources/static/images/login_shadow.png | Bin 0 -> 3585 bytes .../src/main/resources/static/images/logo.png | Bin 0 -> 15743 bytes .../main/resources/static/images/main_bg.png | Bin 0 -> 2864 bytes .../main/resources/static/images/nav_bg.png | Bin 0 -> 2857 bytes .../resources/static/images/nav_btn_bg22.png | Bin 0 -> 3211 bytes .../resources/static/images/nav_btn_bg3.png | Bin 0 -> 1996 bytes .../resources/static/images/nav_btn_bg33.png | Bin 0 -> 4856 bytes .../resources/static/images/nav_btn_bg44.png | Bin 0 -> 4594 bytes .../main/resources/static/images/nav_pass.png | Bin 0 -> 3662 bytes .../resources/static/images/nav_selected.png | Bin 0 -> 3652 bytes .../resources/static/images/pop_close.png | Bin 0 -> 3950 bytes .../main/resources/static/images/pop_left.png | Bin 0 -> 3546 bytes .../static/images/pop_leftbottom.png | Bin 0 -> 3693 bytes .../static/images/pop_lefttop_small.png | Bin 0 -> 6954 bytes .../resources/static/images/pop_midbottom.png | Bin 0 -> 3549 bytes .../static/images/pop_midtop_small.png | Bin 0 -> 3549 bytes .../resources/static/images/pop_right.png | Bin 0 -> 3547 bytes .../static/images/pop_rightbottom.png | Bin 0 -> 2973 bytes .../static/images/pop_righttop_small.png | Bin 0 -> 5186 bytes .../resources/static/images/search_active.png | Bin 0 -> 2866 bytes .../resources/static/images/search_btn.png | Bin 0 -> 654 bytes .../static/images/search_global_m.png | Bin 0 -> 3579 bytes .../resources/static/images/search_input.png | Bin 0 -> 4228 bytes .../resources/static/images/search_line.png | Bin 0 -> 2795 bytes .../resources/static/images/tab_active.png | Bin 0 -> 3541 bytes .../static/images/table_title_bg.png | Bin 0 -> 3595 bytes .../resources/static/images/tip_choose.png | Bin 0 -> 10725 bytes .../resources/static/images/tip_confirm.png | Bin 0 -> 11185 bytes .../main/resources/static/images/tip_del.png | Bin 0 -> 19215 bytes .../resources/static/images/tip_succeed.png | Bin 0 -> 19527 bytes .../resources/static/images/tree-blank.gif | Bin 0 -> 69 bytes .../static/images/tree-down-left.gif | Bin 0 -> 100 bytes .../resources/static/images/tree-down.gif | Bin 0 -> 103 bytes .../resources/static/images/tree-left-up.gif | Bin 0 -> 98 bytes .../static/images/tree-right-down.gif | Bin 0 -> 94 bytes .../resources/static/images/tree-up-right.gif | Bin 0 -> 101 bytes .../main/resources/static/images/tree-up.gif | Bin 0 -> 104 bytes .../src/main/resources/static/js/ajax.js | 89 ++ .../src/main/resources/static/js/box.js | 97 ++ .../src/main/resources/static/js/dubbo.js | 546 ++++++++++ .../resources/static/js/jquery-1.4.2.min.js | 154 +++ .../resources/static/js/jquery.hoverIntent.js | 150 +++ .../static/js/jquery.simplemodal-1.4.js | 721 +++++++++++++ .../src/main/resources/static/js/menu.js | 69 ++ .../src/main/resources/static/js/pop.js | 82 ++ .../src/main/resources/static/js/trcolor.js | 47 + .../templates/common/screen/error_404.vm | 152 +++ .../templates/common/screen/error_other.vm | 133 +++ .../src/main/resources/templates/default.vm | 15 + .../templates/governance/layout/default.vm | 294 ++++++ .../governance/layout/noServicePrivilege.vm | 29 + .../templates/governance/layout/redirect.vm | 29 + .../templates/governance/layout/search.vm | 15 + .../governance/screen/accesses/add.vm | 108 ++ .../governance/screen/accesses/index.vm | 92 ++ .../governance/screen/addresses/index.vm | 62 ++ .../governance/screen/addresses/search.vm | 19 + .../governance/screen/applications/index.vm | 156 +++ .../governance/screen/applications/search.vm | 19 + .../governance/screen/consumers/edit.vm | 143 +++ .../governance/screen/consumers/index.vm | 219 ++++ .../governance/screen/consumers/notified.vm | 133 +++ .../governance/screen/consumers/routed.vm | 139 +++ .../governance/screen/consumers/show.vm | 139 +++ .../templates/governance/screen/error.vm | 15 + .../governance/screen/loadbalances/add.vm | 120 +++ .../governance/screen/loadbalances/edit.vm | 103 ++ .../governance/screen/loadbalances/index.vm | 82 ++ .../governance/screen/loadbalances/show.vm | 45 + .../governance/screen/noServicePrivilege.vm | 44 + .../governance/screen/overrides/add.vm | 208 ++++ .../governance/screen/overrides/edit.vm | 232 +++++ .../governance/screen/overrides/index.vm | 90 ++ .../governance/screen/overrides/show.vm | 183 ++++ .../templates/governance/screen/owners/add.vm | 71 ++ .../governance/screen/owners/index.vm | 55 + .../governance/screen/providers/add.vm | 98 ++ .../governance/screen/providers/edit.vm | 109 ++ .../governance/screen/providers/index.vm | 182 ++++ .../governance/screen/providers/show.vm | 126 +++ .../templates/governance/screen/redirect.vm | 73 ++ .../templates/governance/screen/routes/add.vm | 265 +++++ .../governance/screen/routes/edit.vm | 268 +++++ .../governance/screen/routes/index.vm | 122 +++ .../governance/screen/routes/preview.vm | 29 + .../governance/screen/routes/routeselect.vm | 108 ++ .../governance/screen/routes/show.vm | 95 ++ .../governance/screen/services/index.vm | 169 ++++ .../governance/screen/services/search.vm | 19 + .../governance/screen/weights/add.vm | 142 +++ .../governance/screen/weights/edit.vm | 132 +++ .../governance/screen/weights/index.vm | 69 ++ .../governance/screen/weights/show.vm | 90 ++ .../resources/templates/home/control/menu.vm | 136 +++ .../resources/templates/home/screen/ajax.vm | 15 + .../resources/templates/home/screen/index.vm | 284 ++++++ .../templates/home/screen/services.vm | 26 + .../templates/sysinfo/layout/default.vm | 148 +++ .../templates/sysinfo/layout/redirect.vm | 29 + .../templates/sysinfo/layout/search.vm | 15 + .../templates/sysinfo/screen/dumps/index.vm | 76 ++ .../templates/sysinfo/screen/envs/index.vm | 35 + .../templates/sysinfo/screen/logs/index.vm | 55 + .../templates/sysinfo/screen/redirect.vm | 71 ++ .../templates/sysinfo/screen/socketConn.vm | 122 +++ .../sysinfo/screen/statuses/index.vm | 59 ++ .../sysinfo/screen/versions/index.vm | 35 + .../templates/sysinfo/screen/versions/show.vm | 38 + .../DubboAdminApplicationTests.java | 35 + .../dubbo-monitor-simple/pom.xml | 112 ++ .../src/main/assembly/assembly.xml | 40 + .../dubbo/monitor/simple/MonitorStarter.java | 27 + .../monitor/simple/SimpleMonitorService.java | 400 ++++++++ .../monitor/simple/common/CountUtils.java | 92 ++ .../dubbo/monitor/simple/common/Menu.java | 39 + .../monitor/simple/common/MenuComparator.java | 45 + .../dubbo/monitor/simple/common/Page.java | 82 ++ .../simple/container/JettyContainer.java | 89 ++ .../simple/container/RegistryContainer.java | 293 ++++++ .../simple/pages/ApplicationsPageHandler.java | 82 ++ .../simple/pages/ChartsPageHandler.java | 95 ++ .../simple/pages/ClientsPageHandler.java | 77 ++ .../simple/pages/ConsumersPageHandler.java | 88 ++ .../simple/pages/DependenciesPageHandler.java | 88 ++ .../monitor/simple/pages/HomePageHandler.java | 48 + .../simple/pages/HostsPageHandler.java | 75 ++ .../monitor/simple/pages/LogPageHandler.java | 106 ++ .../simple/pages/ProvidersPageHandler.java | 88 ++ .../simple/pages/RegisteredPageHandler.java | 78 ++ .../simple/pages/RegistriesPageHandler.java | 70 ++ .../simple/pages/ServersPageHandler.java | 55 + .../simple/pages/ServicesPageHandler.java | 72 ++ .../simple/pages/StatisticsPageHandler.java | 167 +++ .../simple/pages/StatusPageHandler.java | 84 ++ .../simple/pages/SubscribedPageHandler.java | 78 ++ .../simple/pages/SystemPageHandler.java | 137 +++ .../simple/pages/UnregisterPageHandler.java | 49 + .../simple/pages/UnsubscribePageHandler.java | 64 ++ .../monitor/simple/servlet/PageHandler.java | 37 + .../monitor/simple/servlet/PageServlet.java | 282 ++++++ .../simple/servlet/ResourceFilter.java | 151 +++ .../resources/META-INF/assembly/bin/dump.sh | 92 ++ .../META-INF/assembly/bin/restart.sh | 4 + .../resources/META-INF/assembly/bin/server.sh | 24 + .../resources/META-INF/assembly/bin/start.bat | 22 + .../resources/META-INF/assembly/bin/start.sh | 106 ++ .../resources/META-INF/assembly/bin/stop.sh | 44 + .../com.alibaba.dubbo.container.Container | 2 + ...a.dubbo.monitor.simple.servlet.PageHandler | 19 + .../META-INF/spring/dubbo-monitor-simple.xml | 41 + .../src/main/resources/conf/dubbo.properties | 29 + .../src/main/resources/log4j.xml | 29 + .../dubbo/monitor/simple/SimpleMonitor.java | 25 + .../simple/SimpleMonitorServiceTest.java | 34 + .../src/test/resources/dubbo.properties | 29 + .../src/test/resources/log4j.xml | 29 + .../common-api/pom.xml | 14 + .../cc/mrbird/common/api/HelloService.java | 5 + .../spring-boot-dubbo-applicaiton/pom.xml | 73 ++ .../server-consumer/pom.xml | 21 + .../java/cc/mrbird/ConsumerApplicaiton.java | 13 + .../consumer/controller/HelloController.java | 19 + .../src/main/resources/application.yml | 15 + .../server-provider/pom.xml | 21 + .../java/cc/mrbird/ProviderApplicaiton.java | 14 + .../provider/service/HelloServiceImpl.java | 14 + .../src/main/resources/application.yml | 18 + 357 files changed, 34532 insertions(+) create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/pom.xml create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/DubboAdminApplication.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/SpringUtil.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/config/I18nConfig.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/config/XmlConfiguration.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/filter/LoginFilter.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/biz/common/i18n/MessageResourceService.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/biz/common/i18n/impl/MessageResourceServiceImpl.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/ConfigService.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/ConsumerService.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/OverrideService.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/OwnerService.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/ProviderService.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/RouteService.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/UserService.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/AbstractService.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/ConfigServiceImpl.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/ConsumerServiceImpl.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/OverrideServiceImpl.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/OwnerServiceImpl.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/ProviderServiceImpl.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/RouteServiceImpl.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/UserServiceImpl.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/sync/RegistryServerSync.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/sync/util/Pair.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/sync/util/SyncUtils.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/ContextUtil.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/GovernanceWarmup.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/Paginator.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/UrlUtils.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/WebConstants.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/ChangeListener.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/StatusManager.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Access.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Agreement.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Approval.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/ApprovalRequisition.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Change.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Cluster.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Config.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Consumer.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/DependItem.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Dependency.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Document.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Entity.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Favorite.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Feature.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Layer.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/LoadBalance.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Mock.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Operation.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Override.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Owner.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/PageList.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Provider.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Registry.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Route.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/SearchHistory.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Test.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/User.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Weight.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/registry/ConvertUtil.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/OverrideUtils.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/ParseUtils.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/RouteRule.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/RouteRuleUtils.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/RouteUtils.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/status/DatabaseStatusChecker.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/status/LoadStatusChecker.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/status/MemoryStatusChecker.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/Coder.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/Entities.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/IntHashMap.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/LocaleUtils.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/MessageSource.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/OverrideUtils.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/StringEscapeUtils.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/Tool.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/BaseController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/RouterController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/common/auth/DubboUser.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/common/i18n/LocaleUtil.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/AccessesController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/AddressesController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ApplicationsController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ConsumersController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/LoadbalancesController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/NoServicePrivilegeController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/OverridesController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/OwnersController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ProvidersController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/RoutesController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ServicesController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/WeightsController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/DisableController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/IndexController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/LookupController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/RegController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/RegisterController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/RestfulController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/ResultController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/ServicestatusController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/ShellController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/StatusController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/UnregController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/UnregisterController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/UnregisterallController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/personal/InfosController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/personal/PasswdsController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/DumpController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/DumpsController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/EnvsController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/LogsController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/StatusesController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/VersionsController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysmanage/ConfigsController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysmanage/PrivilegesController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysmanage/UserownController.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/DateFormatUtil.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/I18nMessageTool.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/RootContextPath.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/Tool.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/ToolUtil.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/application.properties create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/dubbo-admin.xml create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message.properties create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_en.properties create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_zh.properties create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_zh_CN.properties create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_zh_TW.properties create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/log4j.properties create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/css/common.css create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/css/dubbo.css create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/css/skin.css create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/404error.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/bg01.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/bg02.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/bg03.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/bg04.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/btn_info.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/btn_service.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/button_hover.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/button_normal.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/co_01.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/co_02.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/co_03.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/co_04.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/dog.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/dubbo_list_th.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/exit.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/fav_arrow.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/fav_tab_active.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/fav_tab_normal.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/fav_title.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/head_bg.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_add.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_back.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_balance.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_cancel.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_delete.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_disable.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_down.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_edit.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_enable.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_error.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_favorite.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_forb.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_graph.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_help.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_list.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_password.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_reconnect.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_recover.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_register.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_reload.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_renotify.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_run.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_save.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_search.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_show.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_subscribe.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_tree.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_up.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_user.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_warn.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/input.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/login_bg.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/login_box.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/login_btn_hover.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/login_btn_normal.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/login_shadow.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/logo.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/main_bg.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_bg.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_btn_bg22.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_btn_bg3.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_btn_bg33.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_btn_bg44.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_pass.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_selected.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_close.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_left.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_leftbottom.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_lefttop_small.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_midbottom.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_midtop_small.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_right.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_rightbottom.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_righttop_small.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/search_active.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/search_btn.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/search_global_m.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/search_input.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/search_line.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tab_active.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/table_title_bg.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tip_choose.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tip_confirm.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tip_del.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tip_succeed.png create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-blank.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-down-left.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-down.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-left-up.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-right-down.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-up-right.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-up.gif create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/ajax.js create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/box.js create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/dubbo.js create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/jquery-1.4.2.min.js create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/jquery.hoverIntent.js create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/jquery.simplemodal-1.4.js create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/menu.js create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/pop.js create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/trcolor.js create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/common/screen/error_404.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/common/screen/error_other.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/default.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/layout/default.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/layout/noServicePrivilege.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/layout/redirect.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/layout/search.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/accesses/add.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/accesses/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/addresses/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/addresses/search.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/applications/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/applications/search.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/consumers/edit.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/consumers/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/consumers/notified.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/consumers/routed.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/consumers/show.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/error.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/loadbalances/add.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/loadbalances/edit.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/loadbalances/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/loadbalances/show.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/noServicePrivilege.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/overrides/add.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/overrides/edit.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/overrides/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/overrides/show.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/owners/add.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/owners/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/providers/add.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/providers/edit.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/providers/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/providers/show.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/redirect.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/routes/add.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/routes/edit.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/routes/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/routes/preview.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/routes/routeselect.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/routes/show.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/services/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/services/search.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/weights/add.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/weights/edit.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/weights/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/governance/screen/weights/show.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/home/control/menu.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/home/screen/ajax.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/home/screen/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/home/screen/services.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/layout/default.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/layout/redirect.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/layout/search.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/dumps/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/envs/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/logs/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/redirect.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/socketConn.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/statuses/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/versions/index.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/versions/show.vm create mode 100644 52.Dubbo-OPS-Mointor/dubbo-admin/src/test/java/com/alibaba/dubboadmin/DubboAdminApplicationTests.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/pom.xml create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/assembly/assembly.xml create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/MonitorStarter.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/SimpleMonitorService.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/common/CountUtils.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/common/Menu.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/common/MenuComparator.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/common/Page.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/container/JettyContainer.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/container/RegistryContainer.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/ApplicationsPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/ChartsPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/ClientsPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/ConsumersPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/DependenciesPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/HomePageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/HostsPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/LogPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/ProvidersPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/RegisteredPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/RegistriesPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/ServersPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/ServicesPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/StatisticsPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/StatusPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/SubscribedPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/SystemPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/UnregisterPageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/pages/UnsubscribePageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/servlet/PageHandler.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/servlet/PageServlet.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/java/com/alibaba/dubbo/monitor/simple/servlet/ResourceFilter.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/resources/META-INF/assembly/bin/dump.sh create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/resources/META-INF/assembly/bin/restart.sh create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/resources/META-INF/assembly/bin/server.sh create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/resources/META-INF/assembly/bin/start.bat create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/resources/META-INF/assembly/bin/start.sh create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/resources/META-INF/assembly/bin/stop.sh create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.container.Container create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.monitor.simple.servlet.PageHandler create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/resources/META-INF/spring/dubbo-monitor-simple.xml create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/resources/conf/dubbo.properties create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/main/resources/log4j.xml create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/test/java/com/alibaba/dubbo/monitor/simple/SimpleMonitor.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/test/java/com/alibaba/dubbo/monitor/simple/SimpleMonitorServiceTest.java create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/test/resources/dubbo.properties create mode 100644 52.Dubbo-OPS-Mointor/dubbo-monitor-simple/src/test/resources/log4j.xml create mode 100644 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/common-api/pom.xml create mode 100644 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/common-api/src/main/java/cc/mrbird/common/api/HelloService.java create mode 100644 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/pom.xml create mode 100644 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-consumer/pom.xml create mode 100644 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-consumer/src/main/java/cc/mrbird/ConsumerApplicaiton.java create mode 100644 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-consumer/src/main/java/cc/mrbird/consumer/controller/HelloController.java create mode 100644 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-consumer/src/main/resources/application.yml create mode 100644 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-provider/pom.xml create mode 100644 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-provider/src/main/java/cc/mrbird/ProviderApplicaiton.java create mode 100644 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-provider/src/main/java/cc/mrbird/provider/service/HelloServiceImpl.java create mode 100644 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-provider/src/main/resources/application.yml diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/pom.xml b/52.Dubbo-OPS-Mointor/dubbo-admin/pom.xml new file mode 100644 index 0000000..8639254 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/pom.xml @@ -0,0 +1,80 @@ + + + 4.0.0 + + com.alibaba + dubbo-admin + 0.0.1-SNAPSHOT + jar + + dubbo-admin + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.alibaba.boot + velocity-spring-boot-starter + 0.1.0 + + + + org.apache.commons + commons-lang3 + 3.7 + + + + com.alibaba + dubbo + 2.6.2 + + + + org.apache.curator + curator-framework + 2.12.0 + + + com.alibaba + fastjson + 1.2.46 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/DubboAdminApplication.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/DubboAdminApplication.java new file mode 100644 index 0000000..58ba7c3 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/DubboAdminApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.dubboadmin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; + +@SpringBootApplication +public class DubboAdminApplication { + + public static void main(String[] args) { + ApplicationContext act = SpringApplication.run(DubboAdminApplication.class, args); + SpringUtil.setApplicationContext(act); + + + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/SpringUtil.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/SpringUtil.java new file mode 100644 index 0000000..c390c09 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/SpringUtil.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.dubboadmin; + + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; + +import org.springframework.context.ApplicationContext; + +public class SpringUtil { + + public static final Logger logger = LoggerFactory.getLogger(SpringUtil.class); + private static ApplicationContext applicationContext = null; + + public static void setApplicationContext(ApplicationContext applicationContext){ + if(SpringUtil.applicationContext == null){ + logger.info("set applicationcontext"); + SpringUtil.applicationContext = applicationContext; + } + + } + + //获取applicationContext + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + //通过name获取 Bean. + public static Object getBean(String name){ + return getApplicationContext().getBean(name); + + } + + //通过class获取Bean. + public static T getBean(Class clazz){ + return getApplicationContext().getBean(clazz); + } + + //通过name,以及Clazz返回指定的Bean + public static T getBean(String name,Class clazz){ + return getApplicationContext().getBean(name, clazz); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/config/I18nConfig.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/config/I18nConfig.java new file mode 100644 index 0000000..669949d --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/config/I18nConfig.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.dubboadmin.config; + +import java.util.Locale; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.web.servlet.i18n.SessionLocaleResolver; + + +@Configuration +@EnableAutoConfiguration +@ComponentScan +//@ImportResource({"classpath*:dubbo-admin.xml"}) +public class I18nConfig implements WebMvcConfigurer { + + @Bean + public LocaleResolver localeResolver() { + SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver(); + sessionLocaleResolver.setDefaultLocale(Locale.CHINA); + return sessionLocaleResolver; + + } + + @Bean + public LocaleChangeInterceptor localeChangeInterceptor() { + LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); + lci.setParamName("lang"); + return lci; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(localeChangeInterceptor()); + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/config/XmlConfiguration.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/config/XmlConfiguration.java new file mode 100644 index 0000000..9c94a83 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/config/XmlConfiguration.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.dubboadmin.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; + + +@Configuration +@ImportResource({"classpath*:dubbo-admin.xml"}) +public class XmlConfiguration { + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/filter/LoginFilter.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/filter/LoginFilter.java new file mode 100644 index 0000000..fe6c3aa --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/filter/LoginFilter.java @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.dubboadmin.filter; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.UserService; +import com.alibaba.dubboadmin.governance.util.WebConstants; +import com.alibaba.dubboadmin.registry.common.domain.User; +import com.alibaba.dubboadmin.registry.common.util.Coder; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class LoginFilter implements Filter{ + + private static final Logger logger = LoggerFactory.getLogger(LoginFilter.class); + private static Pattern PARAMETER_PATTERN = Pattern.compile("(\\w+)=[\"]?([^,\"]+)[\"]?[,]?\\s*"); + private static final String BASIC_CHALLENGE = "Basic"; + private static final String DIGEST_CHALLENGE = "Digest"; + private static final String CHALLENGE = BASIC_CHALLENGE; + private static final String REALM = User.REALM; + + @Autowired + private UserService userService; + private String logout = "/logout"; + private String logoutCookie = "logout"; + + static Map parseParameters(String query) { + Matcher matcher = PARAMETER_PATTERN.matcher(query); + Map map = new HashMap(); + while (matcher.find()) { + String key = matcher.group(1); + String value = matcher.group(2); + map.put(key, value); + } + return map; + } + + static byte[] readToBytes(InputStream in) throws IOException { + byte[] buf = new byte[in.available()]; + in.read(buf); + return buf; + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + HttpServletRequest req = (HttpServletRequest)request; + HttpServletResponse resp = (HttpServletResponse) response; + if (logger.isInfoEnabled()) { + logger.info("AuthorizationValve of uri: " + req.getRequestURI()); + } + String uri = req.getRequestURI(); + String contextPath = req.getContextPath(); + if (contextPath != null && contextPath.length() > 0 && !"/".equals(contextPath)) { + uri = uri.substring(contextPath.length()); + } + if (uri.equals(logout)) { + if (!isLogout(req)) { + setLogout(true, resp); + showLoginForm(resp); + } else { + setLogout(false, resp); + resp.sendRedirect(contextPath == null || contextPath.length() == 0 ? "/" : contextPath); + } + return; + } + User user = null; + String authType = null; + String authorization = req.getHeader("Authorization"); + if (authorization != null && authorization.length() > 0) { + int i = authorization.indexOf(' '); + if (i >= 0) { + authType = authorization.substring(0, i); + String authPrincipal = authorization.substring(i + 1); + if (BASIC_CHALLENGE.equalsIgnoreCase(authType)) { + user = loginByBase(authPrincipal); + } else if (DIGEST_CHALLENGE.equalsIgnoreCase(authType)) { + user = loginByDigest(authPrincipal, req); + } + } + } + if (user == null || user.getUsername() == null || user.getUsername().length() == 0) { + showLoginForm(resp); + return; + //pipelineContext.breakPipeline(1); + } + if (user != null && StringUtils.isNotEmpty(user.getUsername())) { + req.getSession().setAttribute(WebConstants.CURRENT_USER_KEY, user); + chain.doFilter(request, response); + } + + } + + @Override + public void destroy() { + + } + + private void showLoginForm(HttpServletResponse response) throws IOException { + if (DIGEST_CHALLENGE.equals(CHALLENGE)) { + response.setHeader("WWW-Authenticate", CHALLENGE + " realm=\"" + REALM + "\", qop=\"auth\", nonce=\"" + + UUID.randomUUID().toString().replace("-", "") + "\", opaque=\"" + + Coder.encodeMd5(REALM) + "\""); + } else { + response.setHeader("WWW-Authenticate", CHALLENGE + " realm=\"" + REALM + "\""); + } + response.setHeader("Cache-Control", "must-revalidate,no-cache,no-store"); + response.setHeader("Content-Type", "text/html; charset=iso-8859-1"); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + } + + private User getUser(String username) { + return userService.findUser(username); + } + + private User loginByBase(String authorization) { + authorization = Coder.decodeBase64(authorization); + int i = authorization.indexOf(':'); + String username = authorization.substring(0, i); + if (username != null && username.length() > 0) { + String password = authorization.substring(i + 1); + if (password != null && password.length() > 0) { + String passwordDigest = Coder.encodeMd5(username + ":" + REALM + ":" + password); + User user = getUser(username); + if (user != null) { + String pwd = user.getPassword(); + if (pwd != null && pwd.length() > 0) { + if (passwordDigest.equals(pwd)) { + return user; + } + } + } + } + } + return null; + } + + private User loginByDigest(String value, HttpServletRequest request) throws IOException { + Map params = parseParameters(value); + String username = params.get("username"); + if (username != null && username.length() > 0) { + String passwordDigest = params.get("response"); + if (passwordDigest != null && passwordDigest.length() > 0) { + User user = getUser(username); + if (user != null) { + String pwd = user.getPassword(); + // A valid user, validate password + if (pwd != null && pwd.length() > 0) { + String uri = params.get("uri"); + String nonce = params.get("nonce"); + String nc = params.get("nc"); + String cnonce = params.get("cnonce"); + String qop = params.get("qop"); + String method = request.getMethod(); + String a1 = pwd; + + String a2 = "auth-int".equals(qop) + ? Coder.encodeMd5(method + ":" + uri + ":" + Coder.encodeMd5(readToBytes(request.getInputStream()))) + : Coder.encodeMd5(method + ":" + uri); + String digest = "auth".equals(qop) || "auth-int".equals(qop) + ? Coder.encodeMd5(a1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + a2) + : Coder.encodeMd5(a1 + ":" + nonce + ":" + a2); + if (digest.equals(passwordDigest)) { + return user; + } + } + } + } + } + return null; + } + + private boolean isLogout(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + if (cookies != null && cookies.length > 0) { + for (Cookie cookie : cookies) { + if (cookie != null && logoutCookie.equals(cookie.getName())) { + return "true".equals(cookie.getValue()); + } + } + } + return false; + } + + private void setLogout(boolean logoutValue, HttpServletResponse response) { + response.addCookie(new Cookie(logoutCookie, String.valueOf(logoutValue))); + } +} + diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/biz/common/i18n/MessageResourceService.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/biz/common/i18n/MessageResourceService.java new file mode 100644 index 0000000..e70c5ce --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/biz/common/i18n/MessageResourceService.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.biz.common.i18n; + +public interface MessageResourceService { + + public String get(String key, Object... args); + + public String getMessage(String key, Object... args); + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/biz/common/i18n/impl/MessageResourceServiceImpl.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/biz/common/i18n/impl/MessageResourceServiceImpl.java new file mode 100644 index 0000000..c0b47b8 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/biz/common/i18n/impl/MessageResourceServiceImpl.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.biz.common.i18n.impl; + + +import com.alibaba.dubboadmin.governance.biz.common.i18n.MessageResourceService; +import com.alibaba.dubboadmin.web.mvc.common.i18n.LocaleUtil; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.NoSuchMessageException; +import org.springframework.stereotype.Component; + +@Component +public class MessageResourceServiceImpl implements MessageResourceService { + + @Autowired + private MessageSource messageSource; + + public void setMessageSource(MessageSource messageSource) { + this.messageSource = messageSource; + } + + public String get(String key, Object... args) { + try { + if (messageSource != null) { + return messageSource.getMessage(key, args, key, LocaleUtil.getLocale()); + } + return key; + } catch (NoSuchMessageException e) { + return key; + } + } + + public String getMessage(String key, Object... args) { + return get(key, args); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/ConfigService.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/ConfigService.java new file mode 100644 index 0000000..a3a0ee8 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/ConfigService.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service; + +import java.util.List; +import java.util.Map; + +import com.alibaba.dubboadmin.registry.common.domain.Config; + +/** + * TODO Comment of ConfigDAO + * + */ +public interface ConfigService { + + void update(List configs); + + Map findAllConfigsMap(); + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/ConsumerService.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/ConsumerService.java new file mode 100644 index 0000000..e980eeb --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/ConsumerService.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service; + +import java.util.List; + +import com.alibaba.dubboadmin.registry.common.domain.Consumer; + +/** + * Query service for consumer info + * + */ +public interface ConsumerService { + + List findByService(String serviceName); + + Consumer findConsumer(Long id); + + List findAll(); + + /** + * query for all consumer addresses + */ + List findAddresses(); + + List findAddressesByApplication(String application); + + List findAddressesByService(String serviceName); + + List findByAddress(String consumerAddress); + + List findServicesByAddress(String consumerAddress); + + List findApplications(); + + List findApplicationsByServiceName(String serviceName); + + List findByApplication(String application); + + List findServicesByApplication(String application); + + List findServices(); + +} \ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/OverrideService.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/OverrideService.java new file mode 100644 index 0000000..afa2a67 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/OverrideService.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service; + +import java.util.List; + +import com.alibaba.dubboadmin.registry.common.domain.Override; + +public interface OverrideService { + + void saveOverride(Override override); + + void updateOverride(Override override); + + void deleteOverride(Long id); + + void enableOverride(Long id); + + void disableOverride(Long id); + + List findByService(String service); + + List findByAddress(String address); + + List findByServiceAndAddress(String service, String address); + + List findByApplication(String application); + + List findByServiceAndApplication(String service, String application); + + List findAll(); + + Override findById(Long id); + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/OwnerService.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/OwnerService.java new file mode 100644 index 0000000..367125a --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/OwnerService.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service; + +import java.util.List; + +import com.alibaba.dubboadmin.registry.common.domain.Owner; + +public interface OwnerService { + + List findAllServiceNames(); + + List findServiceNamesByUsername(String username); + + List findUsernamesByServiceName(String serviceName); + + List findByService(String serviceName); + + List findAll(); + + Owner findById(Long id); + + void saveOwner(Owner owner); + + void deleteOwner(Owner owner); + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/ProviderService.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/ProviderService.java new file mode 100644 index 0000000..15ba776 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/ProviderService.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service; + +import java.util.List; + +import com.alibaba.dubboadmin.registry.common.domain.Provider; + +/** + * ProviderService + * + */ +public interface ProviderService { + + void create(Provider provider); + + void enableProvider(Long id); + + void disableProvider(Long id); + + void doublingProvider(Long id); + + void halvingProvider(Long id); + + void deleteStaticProvider(Long id); + + void updateProvider(Provider provider); + + Provider findProvider(Long id); + + List findServices(); + + List findAddresses(); + + List findAddressesByApplication(String application); + + List findAddressesByService(String serviceName); + + List findApplicationsByServiceName(String serviceName); + + List findByService(String serviceName); + + List findAll(); + + List findByAddress(String providerAddress); + + List findServicesByAddress(String providerAddress); + + List findApplications(); + + List findByApplication(String application); + + List findServicesByApplication(String application); + + List findMethodsByService(String serviceName); + + Provider findByServiceAndAddress(String service, String address); + +} \ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/RouteService.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/RouteService.java new file mode 100644 index 0000000..236d881 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/RouteService.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service; + +import java.util.List; + +import com.alibaba.dubboadmin.registry.common.domain.Route; + +/** + * RouteService + * + */ +public interface RouteService { + + void createRoute(Route route); + + void updateRoute(Route route); + + void deleteRoute(Long id); + + void enableRoute(Long id); + + void disableRoute(Long id); + + Route findRoute(Long id); + + List findAll(); + + List findByService(String serviceName); + + List findByAddress(String address); + + List findByServiceAndAddress(String service, String address); + + List findForceRouteByService(String service); + + List findForceRouteByAddress(String address); + + List findForceRouteByServiceAndAddress(String service, String address); + + List findAllForceRoute(); + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/UserService.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/UserService.java new file mode 100644 index 0000000..1869859 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/UserService.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service; + +import java.util.List; + +import com.alibaba.dubboadmin.registry.common.domain.User; + +/** + * UserService + * + */ +public interface UserService { + + List findAllUsers(); + + User findUser(String username); + + User findById(Long id); + + void createUser(User user); + + void updateUser(User user); + + void modifyUser(User user); + + boolean updatePassword(User user, String oldPassword); + + void resetPassword(User user); + + void enableUser(User user); + + void disableUser(User user); + + void deleteUser(User user); + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/AbstractService.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/AbstractService.java new file mode 100644 index 0000000..3c01d63 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/AbstractService.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service.impl; + +import java.util.Map; +import java.util.concurrent.ConcurrentMap; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.registry.RegistryService; +import com.alibaba.dubboadmin.governance.sync.RegistryServerSync; + +import org.springframework.beans.factory.annotation.Autowired; + +/** + * IbatisDAO + * + */ +public class AbstractService { + + protected static final Logger logger = LoggerFactory.getLogger(AbstractService.class); + @Autowired + protected RegistryService registryService; + @Autowired + private RegistryServerSync sync; + + public ConcurrentMap>> getRegistryCache() { + return sync.getRegistryCache(); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/ConfigServiceImpl.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/ConfigServiceImpl.java new file mode 100644 index 0000000..7921ac6 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/ConfigServiceImpl.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service.impl; + +import java.util.List; +import java.util.Map; + +import com.alibaba.dubboadmin.governance.service.ConfigService; +import com.alibaba.dubboadmin.registry.common.domain.Config; + +/** + * TODO Comment of IbatisConfigDAO + * + */ +public class ConfigServiceImpl extends AbstractService implements ConfigService { + + /* (non-Javadoc) + * @see com.alibaba.dubbo.governance.service.ConfigService#update(java.util.List) + */ + public void update(List configs) { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see com.alibaba.dubbo.governance.service.ConfigService#findAllConfigsMap() + */ + public Map findAllConfigsMap() { + // TODO Auto-generated method stub + return null; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/ConsumerServiceImpl.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/ConsumerServiceImpl.java new file mode 100644 index 0000000..bf7c3da --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/ConsumerServiceImpl.java @@ -0,0 +1,223 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentMap; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubboadmin.governance.service.ConsumerService; +import com.alibaba.dubboadmin.governance.sync.util.Pair; +import com.alibaba.dubboadmin.governance.sync.util.SyncUtils; +import com.alibaba.dubboadmin.registry.common.domain.Consumer; + +import org.springframework.stereotype.Component; + +@Component +public class ConsumerServiceImpl extends AbstractService implements ConsumerService { + + public List findByService(String service) { + return SyncUtils.url2ConsumerList(findConsumerUrlByService(service)); + } + + public Consumer findConsumer(Long id) { + return SyncUtils.url2Consumer(findConsumerUrl(id)); + } + + private Pair findConsumerUrl(Long id) { + return SyncUtils.filterFromCategory(getRegistryCache(), Constants.CONSUMERS_CATEGORY, id); + } + + public List findAll() { + return SyncUtils.url2ConsumerList(findAllConsumerUrl()); + } + + private Map findAllConsumerUrl() { + Map filter = new HashMap(); + filter.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY); + return SyncUtils.filterFromCategory(getRegistryCache(), filter); + } + + public List findAddresses() { + List ret = new ArrayList(); + ConcurrentMap> consumerUrls = getRegistryCache().get(Constants.CONSUMERS_CATEGORY); + if (null == consumerUrls) return ret; + + for (Map.Entry> e1 : consumerUrls.entrySet()) { + Map value = e1.getValue(); + for (Map.Entry e2 : value.entrySet()) { + URL u = e2.getValue(); + String app = u.getAddress(); + if (app != null) ret.add(app); + } + } + + return ret; + } + + public List findAddressesByApplication(String application) { + List ret = new ArrayList(); + ConcurrentMap> consumerUrls = getRegistryCache().get(Constants.CONSUMERS_CATEGORY); + + if(consumerUrls == null) + return ret; + + for (Map.Entry> e1 : consumerUrls.entrySet()) { + Map value = e1.getValue(); + for (Map.Entry e2 : value.entrySet()) { + URL u = e2.getValue(); + if (application.equals(u.getParameter(Constants.APPLICATION_KEY))) { + String addr = u.getAddress(); + if (addr != null) ret.add(addr); + } + } + } + + return ret; + } + + public List findAddressesByService(String service) { + List ret = new ArrayList(); + ConcurrentMap> consumerUrls = getRegistryCache().get(Constants.CONSUMERS_CATEGORY); + if (null == consumerUrls) return ret; + + for (Map.Entry e2 : consumerUrls.get(service).entrySet()) { + URL u = e2.getValue(); + String app = u.getAddress(); + if (app != null) ret.add(app); + } + + return ret; + } + + public List findByAddress(String consumerAddress) { + return SyncUtils.url2ConsumerList(findConsumerUrlByAddress(consumerAddress)); + } + + public List findServicesByAddress(String address) { + List ret = new ArrayList(); + ConcurrentMap> consumerUrls = getRegistryCache().get(Constants.CONSUMERS_CATEGORY); + if (consumerUrls == null || address == null || address.length() == 0) return ret; + + for (Map.Entry> e1 : consumerUrls.entrySet()) { + Map value = e1.getValue(); + for (Map.Entry e2 : value.entrySet()) { + URL u = e2.getValue(); + if (address.equals(u.getAddress())) { + ret.add(e1.getKey()); + break; + } + } + } + + return ret; + } + + private Map findConsumerUrlByAddress(String address) { + Map filter = new HashMap(); + filter.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY); + filter.put(SyncUtils.ADDRESS_FILTER_KEY, address); + + return SyncUtils.filterFromCategory(getRegistryCache(), filter); + } + + public List findApplications() { + List ret = new ArrayList(); + ConcurrentMap> consumerUrls = getRegistryCache().get(Constants.CONSUMERS_CATEGORY); + if (consumerUrls == null) return ret; + + for (Map.Entry> e1 : consumerUrls.entrySet()) { + Map value = e1.getValue(); + for (Map.Entry e2 : value.entrySet()) { + URL u = e2.getValue(); + String app = u.getParameter(Constants.APPLICATION_KEY); + if (app != null) ret.add(app); + } + } + + return ret; + } + + public List findApplicationsByServiceName(String service) { + List ret = new ArrayList(); + ConcurrentMap> consumerUrls = getRegistryCache().get(Constants.CONSUMERS_CATEGORY); + if (consumerUrls == null) return ret; + + Map value = consumerUrls.get(service); + if (value == null) { + return ret; + } + for (Map.Entry e2 : value.entrySet()) { + URL u = e2.getValue(); + String app = u.getParameter(Constants.APPLICATION_KEY); + if (app != null) ret.add(app); + } + + return ret; + } + + public List findByApplication(String application) { + return SyncUtils.url2ConsumerList(findConsumerUrlByApplication(application)); + } + + private Map findConsumerUrlByApplication(String application) { + Map filter = new HashMap(); + filter.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY); + filter.put(Constants.APPLICATION_KEY, application); + + return SyncUtils.filterFromCategory(getRegistryCache(), filter); + } + + public List findServicesByApplication(String application) { + List ret = new ArrayList(); + ConcurrentMap> consumerUrls = getRegistryCache().get(Constants.CONSUMERS_CATEGORY); + if (consumerUrls == null || application == null || application.length() == 0) return ret; + + for (Map.Entry> e1 : consumerUrls.entrySet()) { + Map value = e1.getValue(); + for (Map.Entry e2 : value.entrySet()) { + URL u = e2.getValue(); + if (application.equals(u.getParameter(Constants.APPLICATION_KEY))) { + ret.add(e1.getKey()); + break; + } + } + } + + return ret; + } + + public List findServices() { + List ret = new ArrayList(); + ConcurrentMap> consumerUrls = getRegistryCache().get(Constants.CONSUMERS_CATEGORY); + if (consumerUrls != null) ret.addAll(consumerUrls.keySet()); + return ret; + } + + public Map findConsumerUrlByService(String service) { + Map filter = new HashMap(); + filter.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY); + filter.put(SyncUtils.SERVICE_FILTER_KEY, service); + + return SyncUtils.filterFromCategory(getRegistryCache(), filter); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/OverrideServiceImpl.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/OverrideServiceImpl.java new file mode 100644 index 0000000..151bbac --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/OverrideServiceImpl.java @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubboadmin.governance.service.OverrideService; +import com.alibaba.dubboadmin.governance.sync.util.Pair; +import com.alibaba.dubboadmin.governance.sync.util.SyncUtils; +import com.alibaba.dubboadmin.registry.common.domain.Override; + +import org.springframework.stereotype.Component; + +/** + * IbatisOverrideDAO.java + * + */ +@Component +public class OverrideServiceImpl extends AbstractService implements OverrideService { + + public void saveOverride(Override override) { + URL url = getUrlFromOverride(override); + registryService.register(url); + } + + public void updateOverride(Override override) { + Long id = override.getId(); + if (id == null) { + throw new IllegalStateException("no override id"); + } + URL oldOverride = findOverrideUrl(id); + if (oldOverride == null) { + throw new IllegalStateException("Route was changed!"); + } + URL newOverride = getUrlFromOverride(override); + + registryService.unregister(oldOverride); + registryService.register(newOverride); + + } + + public void deleteOverride(Long id) { + URL oldOverride = findOverrideUrl(id); + if (oldOverride == null) { + throw new IllegalStateException("Route was changed!"); + } + registryService.unregister(oldOverride); + } + + public void enableOverride(Long id) { + if (id == null) { + throw new IllegalStateException("no override id"); + } + + URL oldOverride = findOverrideUrl(id); + if (oldOverride == null) { + throw new IllegalStateException("Override was changed!"); + } + if (oldOverride.getParameter("enabled", true)) { + return; + } + + URL newOverride = oldOverride.addParameter("enabled", true); + registryService.unregister(oldOverride); + registryService.register(newOverride); + + } + + public void disableOverride(Long id) { + if (id == null) { + throw new IllegalStateException("no override id"); + } + + URL oldProvider = findOverrideUrl(id); + if (oldProvider == null) { + throw new IllegalStateException("Override was changed!"); + } + if (!oldProvider.getParameter("enabled", true)) { + return; + } + + URL newProvider = oldProvider.addParameter("enabled", false); + registryService.unregister(oldProvider); + registryService.register(newProvider); + + } + + private Map findOverrideUrl(String service, String address, String application) { + Map filter = new HashMap(); + filter.put(Constants.CATEGORY_KEY, Constants.CONFIGURATORS_CATEGORY); + if (service != null && service.length() > 0) { + filter.put(SyncUtils.SERVICE_FILTER_KEY, service); + } + if (address != null && address.length() > 0) { + filter.put(SyncUtils.ADDRESS_FILTER_KEY, address); + } + if (application != null && application.length() > 0) { + filter.put(Constants.APPLICATION_KEY, application); + } + return SyncUtils.filterFromCategory(getRegistryCache(), filter); + } + + public List findByAddress(String address) { + return SyncUtils.url2OverrideList(findOverrideUrl(null, address, null)); + } + + public List findByServiceAndAddress(String service, String address) { + return SyncUtils.url2OverrideList(findOverrideUrl(service, address, null)); + } + + public List findByApplication(String application) { + return SyncUtils.url2OverrideList(findOverrideUrl(null, null, application)); + } + + public List findByService(String service) { + return SyncUtils.url2OverrideList(findOverrideUrl(service, null, null)); + } + + public List findByServiceAndApplication(String service, String application) { + return SyncUtils.url2OverrideList(findOverrideUrl(service, null, application)); + } + + public List findAll() { + return SyncUtils.url2OverrideList(findOverrideUrl(null, null, null)); + } + + private Pair findOverrideUrlPair(Long id) { + return SyncUtils.filterFromCategory(getRegistryCache(), Constants.CONFIGURATORS_CATEGORY, id); + } + + public Override findById(Long id) { + return SyncUtils.url2Override(findOverrideUrlPair(id)); + } + + private URL getUrlFromOverride(Override override) { + return override.toUrl(); + /*Map params = ConvertUtil.serviceName2Map(override.getService()); + if(!params.containsKey(Constants.INTERFACE_KEY)) { + throw new IllegalArgumentException("No interface info"); + } + if(!params.containsKey(Constants.VERSION_KEY)) { + throw new IllegalArgumentException("No version info"); + } + + boolean enabled = override.isEnabled(); + if(!enabled) { + params.put("enabled", "false"); + } + String application = override.getApplication(); + if(!StringUtils.isEmpty(application)) { + params.put("application", application); + } + String address = override.getAddress(); + if(!StringUtils.isEmpty(address)) { + params.put("address", address); + } + + String overrideAddress = override.getOverrideAddress(); + if(StringUtils.isEmpty(overrideAddress)) { + overrideAddress = "0.0.0.0"; + } + params.put(Constants.CATEGORY_KEY, Constants.CONFIGURATORS_CATEGORY); + + URL url = new URL("override", overrideAddress, -1, params); + url = url.addParameterString(override.getParams()); + return url;*/ + } + + URL findOverrideUrl(Long id) { + return getUrlFromOverride(findById(id)); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/OwnerServiceImpl.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/OwnerServiceImpl.java new file mode 100644 index 0000000..4fa2613 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/OwnerServiceImpl.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.OverrideService; +import com.alibaba.dubboadmin.governance.service.OwnerService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.Override; +import com.alibaba.dubboadmin.registry.common.domain.Owner; +import com.alibaba.dubboadmin.registry.common.domain.Provider; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class OwnerServiceImpl extends AbstractService implements OwnerService { + + @Autowired + ProviderService providerService; + + @Autowired + OverrideService overrideService; + + public List findAllServiceNames() { + // TODO Auto-generated method stub + return null; + } + + public List findServiceNamesByUsername(String username) { + // TODO Auto-generated method stub + return null; + } + + public List findUsernamesByServiceName(String serviceName) { + // TODO Auto-generated method stub + return null; + } + + public List findByService(String serviceName) { + List pList = providerService.findByService(serviceName); + List cList = overrideService.findByServiceAndAddress(serviceName, Constants.ANYHOST_VALUE); + return toOverrideLiset(pList, cList); + } + + public List findAll() { + List pList = providerService.findAll(); + List cList = overrideService.findAll(); + return toOverrideLiset(pList, cList); + } + + public Owner findById(Long id) { + + return null; + } + + private List toOverrideLiset(List pList, List cList) { + Map oList = new HashMap(); + for (Provider p : pList) { + if (p.getUsername() != null) { + for (String username : Constants.COMMA_SPLIT_PATTERN.split(p.getUsername())) { + Owner o = new Owner(); + o.setService(p.getService()); + o.setUsername(username); + oList.put(o.getService() + "/" + o.getUsername(), o); + } + } + } + for (Override c : cList) { + Map params = StringUtils.parseQueryString(c.getParams()); + String usernames = params.get("owner"); + if (usernames != null && usernames.length() > 0) { + for (String username : Constants.COMMA_SPLIT_PATTERN.split(usernames)) { + Owner o = new Owner(); + o.setService(c.getService()); + o.setUsername(username); + oList.put(o.getService() + "/" + o.getUsername(), o); + } + } + } + return new ArrayList(oList.values()); + } + + public void saveOwner(Owner owner) { + List overrides = overrideService.findByServiceAndAddress(owner.getService(), Constants.ANYHOST_VALUE); + if (overrides == null || overrides.size() == 0) { + Override override = new Override(); + override.setAddress(Constants.ANYHOST_VALUE); + override.setService(owner.getService()); + override.setEnabled(true); + override.setParams("owner=" + owner.getUsername()); + overrideService.saveOverride(override); + } else { + for (Override override : overrides) { + Map params = StringUtils.parseQueryString(override.getParams()); + String usernames = params.get("owner"); + if (usernames == null || usernames.length() == 0) { + usernames = owner.getUsername(); + } else { + usernames = usernames + "," + owner.getUsername(); + } + params.put("owner", usernames); + override.setParams(StringUtils.toQueryString(params)); + overrideService.updateOverride(override); + } + } + } + + public void deleteOwner(Owner owner) { + List overrides = overrideService.findByServiceAndAddress(owner.getService(), Constants.ANYHOST_VALUE); + if (overrides == null || overrides.size() == 0) { + Override override = new Override(); + override.setAddress(Constants.ANYHOST_VALUE); + override.setService(owner.getService()); + override.setEnabled(true); + override.setParams("owner=" + owner.getUsername()); + overrideService.saveOverride(override); + } else { + for (Override override : overrides) { + Map params = StringUtils.parseQueryString(override.getParams()); + String usernames = params.get("owner"); + if (usernames != null && usernames.length() > 0) { + if (usernames.equals(owner.getUsername())) { + params.remove("owner"); + } else { + usernames = usernames.replace(owner.getUsername() + ",", "").replace("," + owner.getUsername(), ""); + params.put("owner", usernames); + } + if (params.size() > 0) { + override.setParams(StringUtils.toQueryString(params)); + overrideService.updateOverride(override); + } else { + overrideService.deleteOverride(override.getId()); + } + } + } + } + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/ProviderServiceImpl.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/ProviderServiceImpl.java new file mode 100644 index 0000000..8ee59e1 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/ProviderServiceImpl.java @@ -0,0 +1,461 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentMap; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.OverrideService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.governance.sync.util.Pair; +import com.alibaba.dubboadmin.governance.sync.util.SyncUtils; +import com.alibaba.dubboadmin.registry.common.domain.Override; +import com.alibaba.dubboadmin.registry.common.domain.Provider; +import com.alibaba.dubboadmin.registry.common.route.ParseUtils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * IbatisProviderService + * + */ +@Component +public class ProviderServiceImpl extends AbstractService implements ProviderService { + + @Autowired + OverrideService overrideService; + + public void create(Provider provider) { + URL url = provider.toUrl(); + registryService.register(url); + } + + public void enableProvider(Long id) { + if (id == null) { + throw new IllegalStateException("no provider id"); + } + + Provider oldProvider = findProvider(id); + + if (oldProvider == null) { + throw new IllegalStateException("Provider was changed!"); + } + if (oldProvider.isDynamic()) { + // Make sure we only have one override configured disable property. + if (!oldProvider.isEnabled()) { + Override override = new Override(); + override.setAddress(oldProvider.getAddress()); + override.setService(oldProvider.getService()); + override.setEnabled(true); + override.setParams(Constants.DISABLED_KEY + "=false"); + overrideService.saveOverride(override); + return; + } + List oList = overrideService.findByServiceAndAddress(oldProvider.getService(), oldProvider.getAddress()); + + for (Override o : oList) { + Map params = StringUtils.parseQueryString(o.getParams()); + if (params.containsKey(Constants.DISABLED_KEY)) { + if (params.get(Constants.DISABLED_KEY).equals("true")) { + overrideService.deleteOverride(o.getId()); + } + } + } + } else { + oldProvider.setEnabled(true); + updateProvider(oldProvider); + } + } + + public void disableProvider(Long id) { + if (id == null) { + throw new IllegalStateException("no provider id"); + } + + Provider oldProvider = findProvider(id); + if (oldProvider == null) { + throw new IllegalStateException("Provider was changed!"); + } + + if (oldProvider.isDynamic()) { + // Make sure we only have one override configured disable property. + if (oldProvider.isEnabled()) { + Override override = new Override(); + override.setAddress(oldProvider.getAddress()); + override.setService(oldProvider.getService()); + override.setEnabled(true); + override.setParams(Constants.DISABLED_KEY + "=true"); + overrideService.saveOverride(override); + return; + } + List oList = overrideService.findByServiceAndAddress(oldProvider.getService(), oldProvider.getAddress()); + + for (Override o : oList) { + Map params = StringUtils.parseQueryString(o.getParams()); + if (params.containsKey(Constants.DISABLED_KEY)) { + if (params.get(Constants.DISABLED_KEY).equals("false")) { + overrideService.deleteOverride(o.getId()); + } + } + } + } else { + oldProvider.setEnabled(false); + updateProvider(oldProvider); + } + + } + + public void doublingProvider(Long id) { + setWeight(id, 2F); + } + + public void halvingProvider(Long id) { + setWeight(id, 0.5F); + } + + public void setWeight(Long id, float factor) { + if (id == null) { + throw new IllegalStateException("no provider id"); + } + Provider oldProvider = findProvider(id); + if (oldProvider == null) { + throw new IllegalStateException("Provider was changed!"); + } + Map map = StringUtils.parseQueryString(oldProvider.getParameters()); + String weight = map.get(Constants.WEIGHT_KEY); + if (oldProvider.isDynamic()) { + // Make sure we only have one override configured disable property. + List overrides = overrideService.findByServiceAndAddress(oldProvider.getService(), oldProvider.getAddress()); + if (overrides == null || overrides.size() == 0) { + int value = getWeight(weight, factor); + if (value != Constants.DEFAULT_WEIGHT) { + Override override = new Override(); + override.setAddress(oldProvider.getAddress()); + override.setService(oldProvider.getService()); + override.setEnabled(true); + override.setParams(Constants.WEIGHT_KEY + "=" + String.valueOf(value)); + overrideService.saveOverride(override); + } + } else { + for (Override override : overrides) { + Map params = StringUtils.parseQueryString(override.getParams()); + String overrideWeight = params.get(Constants.WEIGHT_KEY); + if (overrideWeight == null || overrideWeight.length() == 0) { + overrideWeight = weight; + } + int value = getWeight(overrideWeight, factor); + if (value == getWeight(weight, 1)) { + params.remove(Constants.WEIGHT_KEY); + } else { + params.put(Constants.WEIGHT_KEY, String.valueOf(value)); + } + if (params.size() > 0) { + override.setParams(StringUtils.toQueryString(params)); + overrideService.updateOverride(override); + } else { + overrideService.deleteOverride(override.getId()); + } + } + } + } else { + int value = getWeight(weight, factor); + if (value == Constants.DEFAULT_WEIGHT) { + map.remove(Constants.WEIGHT_KEY); + } else { + map.put(Constants.WEIGHT_KEY, String.valueOf(value)); + } + oldProvider.setParameters(StringUtils.toQueryString(map)); + updateProvider(oldProvider); + } + } + + private int getWeight(String value, float factor) { + int weight = 100; + if (value != null && value.length() > 0) { + weight = Integer.parseInt(value); + } + weight = (int) (weight * factor); + if (weight < 1) weight = 1; + if (weight == 2) weight = 3; + if (weight == 24) weight = 25; + return weight; + } + + public void deleteStaticProvider(Long id) { + URL oldProvider = findProviderUrl(id); + if (oldProvider == null) { + throw new IllegalStateException("Provider was changed!"); + } + registryService.unregister(oldProvider); + } + + public void updateProvider(Provider provider) { + Long id = provider.getId(); + if (id == null) { + throw new IllegalStateException("no provider id"); + } + + URL oldProvider = findProviderUrl(id); + if (oldProvider == null) { + throw new IllegalStateException("Provider was changed!"); + } + URL newProvider = provider.toUrl(); + + registryService.unregister(oldProvider); + registryService.register(newProvider); + } + + public Provider findProvider(Long id) { + return SyncUtils.url2Provider(findProviderUrlPair(id)); + } + + public Pair findProviderUrlPair(Long id) { + return SyncUtils.filterFromCategory(getRegistryCache(), Constants.PROVIDERS_CATEGORY, id); + } + + public List findServices() { + List ret = new ArrayList(); + ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); + if (providerUrls != null) ret.addAll(providerUrls.keySet()); + return ret; + } + + public List findAddresses() { + List ret = new ArrayList(); + + ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); + if (null == providerUrls) return ret; + + for (Map.Entry> e1 : providerUrls.entrySet()) { + Map value = e1.getValue(); + for (Map.Entry e2 : value.entrySet()) { + URL u = e2.getValue(); + String app = u.getAddress(); + if (app != null) ret.add(app); + } + } + + return ret; + } + + public List findAddressesByApplication(String application) { + List ret = new ArrayList(); + ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); + for (Map.Entry> e1 : providerUrls.entrySet()) { + Map value = e1.getValue(); + for (Map.Entry e2 : value.entrySet()) { + URL u = e2.getValue(); + if (application.equals(u.getParameter(Constants.APPLICATION_KEY))) { + String addr = u.getAddress(); + if (addr != null) ret.add(addr); + } + } + } + + return ret; + } + + public List findAddressesByService(String service) { + List ret = new ArrayList(); + ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); + if (null == providerUrls) return ret; + + for (Map.Entry e2 : providerUrls.get(service).entrySet()) { + URL u = e2.getValue(); + String app = u.getAddress(); + if (app != null) ret.add(app); + } + + return ret; + } + + public List findApplicationsByServiceName(String service) { + List ret = new ArrayList(); + ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); + if (null == providerUrls) return ret; + + Map value = providerUrls.get(service); + if (value == null) { + return ret; + } + for (Map.Entry e2 : value.entrySet()) { + URL u = e2.getValue(); + String app = u.getParameter(Constants.APPLICATION_KEY); + if (app != null) ret.add(app); + } + + return ret; + } + + public List findByService(String serviceName) { + return SyncUtils.url2ProviderList(findProviderUrlByService(serviceName)); + } + + private Map findProviderUrlByService(String service) { + Map filter = new HashMap(); + filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); + filter.put(SyncUtils.SERVICE_FILTER_KEY, service); + + return SyncUtils.filterFromCategory(getRegistryCache(), filter); + } + + public List findAll() { + return SyncUtils.url2ProviderList(findAllProviderUrl()); + } + + private Map findAllProviderUrl() { + Map filter = new HashMap(); + filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); + return SyncUtils.filterFromCategory(getRegistryCache(), filter); + } + + public List findByAddress(String providerAddress) { + return SyncUtils.url2ProviderList(findProviderUrlByAddress(providerAddress)); + } + + public Map findProviderUrlByAddress(String address) { + Map filter = new HashMap(); + filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); + filter.put(SyncUtils.ADDRESS_FILTER_KEY, address); + + return SyncUtils.filterFromCategory(getRegistryCache(), filter); + } + + public List findServicesByAddress(String address) { + List ret = new ArrayList(); + + ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); + if (providerUrls == null || address == null || address.length() == 0) return ret; + + for (Map.Entry> e1 : providerUrls.entrySet()) { + Map value = e1.getValue(); + for (Map.Entry e2 : value.entrySet()) { + URL u = e2.getValue(); + if (address.equals(u.getAddress())) { + ret.add(e1.getKey()); + break; + } + } + } + + return ret; + } + + public List findApplications() { + List ret = new ArrayList(); + ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); + if (providerUrls == null) return ret; + + for (Map.Entry> e1 : providerUrls.entrySet()) { + Map value = e1.getValue(); + for (Map.Entry e2 : value.entrySet()) { + URL u = e2.getValue(); + String app = u.getParameter(Constants.APPLICATION_KEY); + if (app != null) ret.add(app); + } + } + + return ret; + } + + public List findByApplication(String application) { + return SyncUtils.url2ProviderList(findProviderUrlByApplication(application)); + } + + private Map findProviderUrlByApplication(String application) { + Map filter = new HashMap(); + filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); + filter.put(Constants.APPLICATION_KEY, application); + return SyncUtils.filterFromCategory(getRegistryCache(), filter); + } + + public List findServicesByApplication(String application) { + List ret = new ArrayList(); + + ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); + if (providerUrls == null || application == null || application.length() == 0) return ret; + + for (Map.Entry> e1 : providerUrls.entrySet()) { + Map value = e1.getValue(); + for (Map.Entry e2 : value.entrySet()) { + URL u = e2.getValue(); + if (application.equals(u.getParameter(Constants.APPLICATION_KEY))) { + ret.add(e1.getKey()); + break; + } + } + } + + return ret; + } + + public List findMethodsByService(String service) { + List ret = new ArrayList(); + + ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); + if (providerUrls == null || service == null || service.length() == 0) return ret; + + Map providers = providerUrls.get(service); + if (null == providers || providers.isEmpty()) return ret; + + Entry p = providers.entrySet().iterator().next(); + String value = p.getValue().getParameter("methods"); + if (value == null || value.length() == 0) { + return ret; + } + String[] methods = value.split(ParseUtils.METHOD_SPLIT); + if (methods == null || methods.length == 0) { + return ret; + } + + for (String m : methods) { + ret.add(m); + } + return ret; + } + + private URL findProviderUrl(Long id) { + return findProvider(id).toUrl(); + } + + public Provider findByServiceAndAddress(String service, String address) { + return SyncUtils.url2Provider(findProviderUrl(service, address)); + } + + private Pair findProviderUrl(String service, String address) { + Map filter = new HashMap(); + filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); + filter.put(SyncUtils.ADDRESS_FILTER_KEY, address); + + Map ret = SyncUtils.filterFromCategory(getRegistryCache(), filter); + if (ret.isEmpty()) { + return null; + } else { + Long key = ret.entrySet().iterator().next().getKey(); + return new Pair(key, ret.get(key)); + } + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/RouteServiceImpl.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/RouteServiceImpl.java new file mode 100644 index 0000000..f618e90 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/RouteServiceImpl.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubboadmin.governance.service.RouteService; +import com.alibaba.dubboadmin.governance.sync.util.Pair; +import com.alibaba.dubboadmin.governance.sync.util.SyncUtils; +import com.alibaba.dubboadmin.registry.common.domain.Route; + +import org.springframework.stereotype.Component; + +/** + * IbatisRouteService + * + */ +@Component +public class RouteServiceImpl extends AbstractService implements RouteService { + + public void createRoute(Route route) { + registryService.register(route.toUrl()); + } + + public void updateRoute(Route route) { + Long id = route.getId(); + if (id == null) { + throw new IllegalStateException("no route id"); + } + URL oldRoute = findRouteUrl(id); + if (oldRoute == null) { + throw new IllegalStateException("Route was changed!"); + } + + registryService.unregister(oldRoute); + registryService.register(route.toUrl()); + } + + public void deleteRoute(Long id) { + URL oldRoute = findRouteUrl(id); + if (oldRoute == null) { + throw new IllegalStateException("Route was changed!"); + } + registryService.unregister(oldRoute); + } + + public void enableRoute(Long id) { + if (id == null) { + throw new IllegalStateException("no route id"); + } + + URL oldRoute = findRouteUrl(id); + if (oldRoute == null) { + throw new IllegalStateException("Route was changed!"); + } + if (oldRoute.getParameter("enabled", true)) { + return; + } + + registryService.unregister(oldRoute); + URL newRoute = oldRoute.addParameter("enabled", true); + registryService.register(newRoute); + + } + + public void disableRoute(Long id) { + if (id == null) { + throw new IllegalStateException("no route id"); + } + + URL oldRoute = findRouteUrl(id); + if (oldRoute == null) { + throw new IllegalStateException("Route was changed!"); + } + if (!oldRoute.getParameter("enabled", true)) { + return; + } + + URL newRoute = oldRoute.addParameter("enabled", false); + registryService.unregister(oldRoute); + registryService.register(newRoute); + + } + + public List findAll() { + return SyncUtils.url2RouteList(findAllUrl()); + } + + private Map findAllUrl() { + Map filter = new HashMap(); + filter.put(Constants.CATEGORY_KEY, Constants.ROUTERS_CATEGORY); + + return SyncUtils.filterFromCategory(getRegistryCache(), filter); + } + + public Route findRoute(Long id) { + return SyncUtils.url2Route(findRouteUrlPair(id)); + } + + public Pair findRouteUrlPair(Long id) { + return SyncUtils.filterFromCategory(getRegistryCache(), Constants.ROUTERS_CATEGORY, id); + } + + private URL findRouteUrl(Long id) { + return findRoute(id).toUrl(); + } + + private Map findRouteUrl(String service, String address, boolean force) { + Map filter = new HashMap(); + filter.put(Constants.CATEGORY_KEY, Constants.ROUTERS_CATEGORY); + if (service != null && service.length() > 0) { + filter.put(SyncUtils.SERVICE_FILTER_KEY, service); + } + if (address != null && address.length() > 0) { + filter.put(SyncUtils.ADDRESS_FILTER_KEY, address); + } + if (force) { + filter.put("force", "true"); + } + return SyncUtils.filterFromCategory(getRegistryCache(), filter); + } + + public List findByService(String serviceName) { + return SyncUtils.url2RouteList(findRouteUrl(serviceName, null, false)); + } + + public List findByAddress(String address) { + return SyncUtils.url2RouteList(findRouteUrl(null, address, false)); + } + + public List findByServiceAndAddress(String service, String address) { + return SyncUtils.url2RouteList(findRouteUrl(service, address, false)); + } + + public List findForceRouteByService(String service) { + return SyncUtils.url2RouteList(findRouteUrl(service, null, true)); + } + + public List findForceRouteByAddress(String address) { + return SyncUtils.url2RouteList(findRouteUrl(null, address, true)); + } + + public List findForceRouteByServiceAndAddress(String service, String address) { + return SyncUtils.url2RouteList(findRouteUrl(service, address, true)); + } + + public List findAllForceRoute() { + return SyncUtils.url2RouteList(findRouteUrl(null, null, true)); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/UserServiceImpl.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..b100bad --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/service/impl/UserServiceImpl.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.service.impl; + +import java.util.List; +import java.util.Map; + +import com.alibaba.dubboadmin.governance.service.UserService; +import com.alibaba.dubboadmin.registry.common.domain.User; +import com.alibaba.dubboadmin.registry.common.util.Coder; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * IBatisUserService + * + */ +@Component +public class UserServiceImpl extends AbstractService implements UserService { + + @Value("${spring.root.password}") + private String rootPassword; + @Value("${spring.guest.password}") + private String guestPassword; + + public void setRootPassword(String password) { + this.rootPassword = (password == null ? "" : password); + } + + public void setGuestPassword(String password) { + this.guestPassword = (password == null ? "" : password); + } + + public User findUser(String username) { + if ("guest".equals(username)) { + User user = new User(); + user.setUsername(username); + user.setPassword(Coder.encodeMd5(username + ":" + User.REALM + ":" + guestPassword)); + user.setName(username); + user.setRole(User.GUEST); + user.setEnabled(true); + user.setLocale("zh"); + user.setServicePrivilege(""); + return user; + } else if ("root".equals(username)) { + User user = new User(); + user.setUsername(username); + user.setPassword(Coder.encodeMd5(username + ":" + User.REALM + ":" + rootPassword)); + user.setName(username); + user.setRole(User.ROOT); + user.setEnabled(true); + user.setLocale("zh"); + user.setServicePrivilege("*"); + return user; + } + return null; + } + + public List findAllUsers() { + // TODO Auto-generated method stub + return null; + } + + public Map findAllUsersMap() { + // TODO Auto-generated method stub + return null; + } + + public User findById(Long id) { + // TODO Auto-generated method stub + return null; + } + + public void createUser(User user) { + // TODO Auto-generated method stub + + } + + public void updateUser(User user) { + // TODO Auto-generated method stub + + } + + public void modifyUser(User user) { + // TODO Auto-generated method stub + + } + + public boolean updatePassword(User user, String oldPassword) { + // TODO Auto-generated method stub + return false; + } + + public void resetPassword(User user) { + // TODO Auto-generated method stub + + } + + public void enableUser(User user) { + // TODO Auto-generated method stub + + } + + public void disableUser(User user) { + // TODO Auto-generated method stub + + } + + public void deleteUser(User user) { + // TODO Auto-generated method stub + + } + + public List findUsersByServiceName(String serviceName) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/sync/RegistryServerSync.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/sync/RegistryServerSync.java new file mode 100644 index 0000000..40d2ea2 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/sync/RegistryServerSync.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.sync; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.registry.NotifyListener; +import com.alibaba.dubbo.registry.RegistryService; +import com.alibaba.dubboadmin.web.pulltool.Tool; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class RegistryServerSync implements InitializingBean, DisposableBean, NotifyListener { + + private static final Logger logger = LoggerFactory.getLogger(RegistryServerSync.class); + + private static final URL SUBSCRIBE = new URL(Constants.ADMIN_PROTOCOL, NetUtils.getLocalHost(), 0, "", + Constants.INTERFACE_KEY, Constants.ANY_VALUE, + Constants.GROUP_KEY, Constants.ANY_VALUE, + Constants.VERSION_KEY, Constants.ANY_VALUE, + Constants.CLASSIFIER_KEY, Constants.ANY_VALUE, + Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY + "," + + Constants.CONSUMERS_CATEGORY + "," + + Constants.ROUTERS_CATEGORY + "," + + Constants.CONFIGURATORS_CATEGORY, + Constants.ENABLED_KEY, Constants.ANY_VALUE, + Constants.CHECK_KEY, String.valueOf(false)); + + private static final AtomicLong ID = new AtomicLong(); + + /** + * Make sure ID never changed when the same url notified many times + */ + private final ConcurrentHashMap URL_IDS_MAPPER = new ConcurrentHashMap(); + + // ConcurrentMap>> + private final ConcurrentMap>> + registryCache = new ConcurrentHashMap>>(); + @Autowired + private RegistryService registryService; + + public ConcurrentMap>> getRegistryCache() { + return registryCache; + } + + public void afterPropertiesSet() throws Exception { + logger.info("Init Dubbo Admin Sync Cache..."); + registryService.subscribe(SUBSCRIBE, this); + } + + public void destroy() throws Exception { + registryService.unsubscribe(SUBSCRIBE, this); + } + + // Notification of of any service with any type (override、subcribe、route、provider) is full. + public void notify(List urls) { + if (urls == null || urls.isEmpty()) { + return; + } + // Map>> + final Map>> categories = new HashMap>>(); + String interfaceName = null; + for (URL url : urls) { + String category = url.getParameter(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); + if (Constants.EMPTY_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { // NOTE: group and version in empty protocol is * + ConcurrentMap> services = registryCache.get(category); + if (services != null) { + String group = url.getParameter(Constants.GROUP_KEY); + String version = url.getParameter(Constants.VERSION_KEY); + // NOTE: group and version in empty protocol is * + if (!Constants.ANY_VALUE.equals(group) && !Constants.ANY_VALUE.equals(version)) { + services.remove(url.getServiceKey()); + } else { + for (Map.Entry> serviceEntry : services.entrySet()) { + String service = serviceEntry.getKey(); + if (Tool.getInterface(service).equals(url.getServiceInterface()) + && (Constants.ANY_VALUE.equals(group) || StringUtils.isEquals(group, Tool.getGroup(service))) + && (Constants.ANY_VALUE.equals(version) || StringUtils.isEquals(version, Tool.getVersion(service)))) { + services.remove(service); + } + } + } + } + } else { + if (StringUtils.isEmpty(interfaceName)) { + interfaceName = url.getServiceInterface(); + } + Map> services = categories.get(category); + if (services == null) { + services = new HashMap>(); + categories.put(category, services); + } + String service = url.getServiceKey(); + Map ids = services.get(service); + if (ids == null) { + ids = new HashMap(); + services.put(service, ids); + } + + // Make sure we use the same ID for the same URL + if (URL_IDS_MAPPER.containsKey(url.toFullString())) { + ids.put(URL_IDS_MAPPER.get(url.toFullString()), url); + } else { + long currentId = ID.incrementAndGet(); + ids.put(currentId, url); + URL_IDS_MAPPER.putIfAbsent(url.toFullString(), currentId); + } + } + } + if (categories.size() == 0) { + return; + } + for (Map.Entry>> categoryEntry : categories.entrySet()) { + String category = categoryEntry.getKey(); + ConcurrentMap> services = registryCache.get(category); + if (services == null) { + services = new ConcurrentHashMap>(); + registryCache.put(category, services); + } else {// Fix map can not be cleared when service is unregistered: when a unique “group/service:version” service is unregistered, but we still have the same services with different version or group, so empty protocols can not be invoked. + Set keys = new HashSet(services.keySet()); + for (String key : keys) { + if (Tool.getInterface(key).equals(interfaceName) && !categoryEntry.getValue().entrySet().contains(key)) { + services.remove(key); + } + } + } + services.putAll(categoryEntry.getValue()); + } + } +} + diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/sync/util/Pair.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/sync/util/Pair.java new file mode 100644 index 0000000..0fbed83 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/sync/util/Pair.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.sync.util; + +import java.util.Map; + +public class Pair implements Map.Entry { + + private K key; + + private V value; + + public Pair() { + } + + public Pair(K key, V value) { + this.key = key; + this.value = value; + } + + public K getKey() { + return key; + } + + public void setKey(K key) { + this.key = key; + } + + public V getValue() { + return value; + } + + public V setValue(V value) { + V old = this.value; + this.value = value; + return old; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((key == null) ? 0 : key.hashCode()); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Pair other = (Pair) obj; + if (key == null) { + if (other.key != null) + return false; + } else if (!key.equals(other.key)) + return false; + if (value == null) { + if (other.value != null) + return false; + } else if (!value.equals(other.value)) + return false; + return true; + } + +} \ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/sync/util/SyncUtils.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/sync/util/SyncUtils.java new file mode 100644 index 0000000..96e94a3 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/sync/util/SyncUtils.java @@ -0,0 +1,256 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.sync.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.registry.common.domain.Consumer; +import com.alibaba.dubboadmin.registry.common.domain.Override; +import com.alibaba.dubboadmin.registry.common.domain.Provider; +import com.alibaba.dubboadmin.registry.common.domain.Route; + +public class SyncUtils { + + public static final String SERVICE_FILTER_KEY = ".service"; + + public static final String ADDRESS_FILTER_KEY = ".address"; + + public static final String ID_FILTER_KEY = ".id"; + + public static Provider url2Provider(Pair pair) { + if (pair == null) { + return null; + } + + Long id = pair.getKey(); + URL url = pair.getValue(); + + if (url == null) + return null; + + Provider p = new Provider(); + p.setId(id); + p.setService(url.getServiceKey()); + p.setAddress(url.getAddress()); + p.setApplication(url.getParameter(Constants.APPLICATION_KEY)); + p.setUrl(url.toIdentityString()); + p.setParameters(url.toParameterString()); + + p.setDynamic(url.getParameter("dynamic", true)); + p.setEnabled(url.getParameter(Constants.ENABLED_KEY, true)); + p.setWeight(url.getParameter(Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT)); + p.setUsername(url.getParameter("owner")); + + return p; + } + + public static List url2ProviderList(Map ps) { + List ret = new ArrayList(); + for (Map.Entry entry : ps.entrySet()) { + ret.add(url2Provider(new Pair(entry.getKey(), entry.getValue()))); + } + return ret; + } + + public static Consumer url2Consumer(Pair pair) { + if (pair == null) { + return null; + } + + Long id = pair.getKey(); + URL url = pair.getValue(); + + if (null == url) + return null; + + Consumer c = new Consumer(); + c.setId(id); + c.setService(url.getServiceKey()); + c.setAddress(url.getHost()); + c.setApplication(url.getParameter(Constants.APPLICATION_KEY)); + c.setParameters(url.toParameterString()); + + return c; + } + + public static List url2ConsumerList(Map cs) { + List list = new ArrayList(); + if (cs == null) return list; + for (Map.Entry entry : cs.entrySet()) { + list.add(url2Consumer(new Pair(entry.getKey(), entry.getValue()))); + } + return list; + } + + public static Route url2Route(Pair pair) { + if (pair == null) { + return null; + } + + Long id = pair.getKey(); + URL url = pair.getValue(); + + if (null == url) + return null; + + Route r = new Route(); + r.setId(id); + r.setName(url.getParameter("name")); + r.setService(url.getServiceKey()); + r.setPriority(url.getParameter(Constants.PRIORITY_KEY, 0)); + r.setEnabled(url.getParameter(Constants.ENABLED_KEY, true)); + r.setForce(url.getParameter(Constants.FORCE_KEY, false)); + r.setRule(url.getParameterAndDecoded(Constants.RULE_KEY)); + return r; + } + + public static List url2RouteList(Map cs) { + List list = new ArrayList(); + if (cs == null) return list; + for (Map.Entry entry : cs.entrySet()) { + list.add(url2Route(new Pair(entry.getKey(), entry.getValue()))); + } + return list; + } + + public static Override url2Override(Pair pair) { + if (pair == null) { + return null; + } + + Long id = pair.getKey(); + URL url = pair.getValue(); + + if (null == url) + return null; + + Override o = new Override(); + o.setId(id); + + Map parameters = new HashMap(url.getParameters()); + + o.setService(url.getServiceKey()); + parameters.remove(Constants.INTERFACE_KEY); + parameters.remove(Constants.GROUP_KEY); + parameters.remove(Constants.VERSION_KEY); + parameters.remove(Constants.APPLICATION_KEY); + parameters.remove(Constants.CATEGORY_KEY); + parameters.remove(Constants.DYNAMIC_KEY); + parameters.remove(Constants.ENABLED_KEY); + + o.setEnabled(url.getParameter(Constants.ENABLED_KEY, true)); + + String host = url.getHost(); + boolean anyhost = url.getParameter(Constants.ANYHOST_VALUE, false); + if (!anyhost || !"0.0.0.0".equals(host)) { + o.setAddress(url.getAddress()); + } + + o.setApplication(url.getParameter(Constants.APPLICATION_KEY, url.getUsername())); + parameters.remove(Constants.VERSION_KEY); + + o.setParams(StringUtils.toQueryString(parameters)); + + return o; + } + + // Map>> + public static >> Map filterFromCategory(Map urls, Map filter) { + String c = (String) filter.get(Constants.CATEGORY_KEY); + if (c == null) throw new IllegalArgumentException("no category"); + + filter.remove(Constants.CATEGORY_KEY); + return filterFromService(urls.get(c), filter); + } + + public static List url2OverrideList(Map cs) { + List + list = new ArrayList(); + if (cs == null) return list; + for (Map.Entry entry : cs.entrySet()) { + list.add(url2Override(new Pair(entry.getKey(), entry.getValue()))); + } + return list; + } + + + // Map> + public static Map filterFromService(Map> urls, Map filter) { + Map ret = new HashMap(); + if (urls == null) return ret; + + String s = (String) filter.remove(SERVICE_FILTER_KEY); + if (s == null) { + for (Map.Entry> entry : urls.entrySet()) { + filterFromUrls(entry.getValue(), ret, filter); + } + } else { + Map map = urls.get(s); + filterFromUrls(map, ret, filter); + } + + return ret; + } + + // Map + static void filterFromUrls(Map from, Map to, Map filter) { + if (from == null || from.isEmpty()) return; + + for (Map.Entry entry : from.entrySet()) { + URL url = entry.getValue(); + + boolean match = true; + for (Map.Entry e : filter.entrySet()) { + String key = e.getKey(); + String value = e.getValue(); + + if (ADDRESS_FILTER_KEY.equals(key)) { + if (!value.equals(url.getAddress())) { + match = false; + break; + } + } else { + if (!value.equals(url.getParameter(key))) { + match = false; + break; + } + } + } + + if (match) { + to.put(entry.getKey(), url); + } + } + } + + public static >> Pair filterFromCategory(Map urls, String category, Long id) { + SM services = urls.get(category); + if (services == null) return null; + + for (Map.Entry> e1 : services.entrySet()) { + Map u = e1.getValue(); + if (u.containsKey(id)) return new Pair(id, u.get(id)); + } + return null; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/ContextUtil.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/ContextUtil.java new file mode 100644 index 0000000..d4e6838 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/ContextUtil.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.util; + +import java.util.Map; + +/** + * TODO Comment of ContextUtil + * + */ +public class ContextUtil { + + private ContextUtil(Map c) { + } + + public static Object get(Map context, Object key, Object defaultv) { + Object res = context.get(key); + if (res == null) { + res = defaultv; + } + return res; + } +} + diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/GovernanceWarmup.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/GovernanceWarmup.java new file mode 100644 index 0000000..e23c86a --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/GovernanceWarmup.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.util; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubboadmin.registry.common.StatusManager; + +import org.springframework.beans.factory.InitializingBean; + +public class GovernanceWarmup implements InitializingBean { + + private static final Logger logger = LoggerFactory.getLogger(GovernanceWarmup.class); + + private StatusChecker memoryStatusChecker; + + private StatusChecker threadPoolStatusChecker; + + private StatusChecker cacheStatusChecker; + + private StatusChecker databaseStatusChecker; + + private StatusChecker failureStatusChecker; + + private StatusChecker loadStatusChecker; + + private StatusChecker SocketStatusChecker; + + private StatusChecker timerStatusChecker; + + private StatusChecker warmupStatusChecker; + + public void afterPropertiesSet() throws Exception { + logger.info("Registry Console warn up."); + + StatusManager statusManager = StatusManager.getInstance(); + + statusManager.addStatusHandler("memory", memoryStatusChecker); + statusManager.addStatusHandler("load", loadStatusChecker); +// statusManager.addStatusHandler("database",databaseStatusChecker); +// statusManager.addStatusHandler("cache",cacheStatusChecker); +// statusManager.addStatusHandler("threadpool",threadPoolStatusChecker); +// statusManager.addStatusHandler("failure",failureStatusChecker); +// statusManager.addStatusHandler("socket",SocketStatusChecker); +// statusManager.addStatusHandler("threadpool",threadPoolStatusChecker); +// statusManager.addStatusHandler("timer",timerStatusChecker); +// statusManager.addStatusHandler("warmup",warmupStatusChecker); + } + + public void setMemoryStatusChecker(StatusChecker memoryStatusChecker) { + this.memoryStatusChecker = memoryStatusChecker; + } + + + public void setThreadPoolStatusChecker(StatusChecker threadPoolStatusChecker) { + this.threadPoolStatusChecker = threadPoolStatusChecker; + } + + + public void setCacheStatusChecker(StatusChecker cacheStatusChecker) { + this.cacheStatusChecker = cacheStatusChecker; + } + + + public void setDatabaseStatusChecker(StatusChecker databaseStatusChecker) { + this.databaseStatusChecker = databaseStatusChecker; + } + + + public void setFailureStatusChecker(StatusChecker failureStatusChecker) { + this.failureStatusChecker = failureStatusChecker; + } + + + public void setLoadStatusChecker(StatusChecker loadStatusChecker) { + this.loadStatusChecker = loadStatusChecker; + } + + + public void setSocketStatusChecker(StatusChecker socketStatusChecker) { + SocketStatusChecker = socketStatusChecker; + } + + + public void setTimerStatusChecker(StatusChecker timerStatusChecker) { + this.timerStatusChecker = timerStatusChecker; + } + + public void setWarmupStatusChecker(StatusChecker warmupStatusChecker) { + this.warmupStatusChecker = warmupStatusChecker; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/Paginator.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/Paginator.java new file mode 100644 index 0000000..4ec1152 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/Paginator.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.util; + +import java.io.Serializable; + +/** + * TODO Comment of Paginator + * + */ +public class Paginator implements Serializable, Cloneable { + + private static final long serialVersionUID = 3688506614705500726L; + + // The default number of items per page; default is 10 + int itemsPerPage = 10; + + // Sliding window default size; default: 7 + int sliderSize = 7; + + // The current page. + int currentPage; + + // The current page. + String path; + + // total mumber of items + int totalItems; + + // total number of pages + int totalPage; + + /** + * The most simple paging constructor. + * + * @param currentPage + * @param totalItems + * @param path + */ + public Paginator(int currentPage, int totalItems, String path) { + initPagination(currentPage, totalItems, 0, 0, path); + } + + public Paginator(String currentPage, int totalItems, String path) { + int currentPageTemp = 1; + if (!(currentPage == null || currentPage.equals(""))) { + currentPageTemp = Integer.parseInt(currentPage); + } + initPagination(currentPageTemp, totalItems, 0, 0, path); + } + + /** + * Complete paging constructor. + * + * @param currentPageT + * @param totalItemsT + * @param sliderSizeT + * @param itemsPerPageT + * @param path + */ + public void initPagination(int currentPageT, int totalItemsT, int sliderSizeT, int itemsPerPageT, String path) { + this.totalItems = (totalItemsT > 0) ? totalItemsT : 0; + this.sliderSize = (sliderSizeT > 0) ? sliderSizeT : sliderSize; + this.itemsPerPage = (itemsPerPageT > 0) ? itemsPerPageT : itemsPerPage; + this.totalPage = totalItems / itemsPerPage + (totalItems % itemsPerPage == 0 ? 0 : 1); + this.currentPage = (currentPageT > 0) ? currentPageT : 1; + this.currentPage = currentPage < totalPage ? currentPage : totalPage; + this.currentPage = (currentPage == 0) ? 1 : currentPage; + this.path = path; + } + + public int getItemsPerPage() { + return this.itemsPerPage; + } + + /** + * Get a sliding window of fixed size, and the current page should lie in the middle of the sliding window. + * For example: a total of 13 pages, the current page is page 5, a size of 5 sliding window should consists of 3,4,5,6,7, page 5 is placed in the middle. If the current page is 12, the return page number should be 9, 10, 11, 12, 13. + * + * @return An array containing page numbers, or an empty array if the specified sliding window size is less than 1 or the total number of pages is zero. + */ + public int[] getSlider() { + int width = sliderSize; + if ((totalItems < 1)) { + return new int[0]; + + } else { + if (width > totalPage) { + width = totalPage; + } + + int[] slider = new int[width]; + + int startPage = currentPage - ((width - 1) / 2); + + if (startPage < 1) { + startPage = 1; + } + + if (((startPage + width) - 1) > totalPage) { + startPage = totalPage - width + 1; + } + + for (int i = 0; i < width; i++) { + slider[i] = startPage + i; + } + return slider; + } + } + + /** + * Construction pagination toolbar + */ + public String getPaginatorBar() { + + StringBuffer str = new StringBuffer("
"); + str.append(""); + + // generate flip section + // The total number of records + str.append("total items: " + this.totalItems + "  "); + + // 2. Pages: current page / total pages + str.append("page " + this.currentPage + " of " + this.totalPage + "nbsp; "); + + // 3. Home, Previous + if (this.currentPage > 1) { + str.append("Home"); + str.append("Previous"); + } else { + str.append("Home"); + str.append("Previous"); + } + + // 4. Activity block + int[] slider = getSlider(); + for (int i = 0; i < slider.length; i++) { + if (slider[i] == this.currentPage) { + str.append(""); + } else { + str.append(""); + } + str.append(slider[i] + ""); + } + + // 5. Next page + if (this.currentPage < this.totalPage) { + str.append(""); + } else { + str.append(""); + } + str.append("Next  "); + + // 6. Jump section + str.append("jump to page "); + str.append(""); + + // 7. Implicit conditions + str.append("
"); + return str.toString(); + } + + /** + * Get the initial record + * + * @return + */ + public int getStartIndex() { + return (this.currentPage - 1) * this.itemsPerPage + 1; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/UrlUtils.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/UrlUtils.java new file mode 100644 index 0000000..15fa653 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/UrlUtils.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.util; + +import java.util.Map; +import java.util.Map.Entry; + +/** + * UrlUtils.java + * + */ +public class UrlUtils { + + public static String paramsMapToString(Map params) { + StringBuilder paramsString = new StringBuilder(); + for (Entry param : params.entrySet()) { + if (paramsString != null) { + paramsString.append("&"); + } + paramsString.append(param.getKey()); + paramsString.append("="); + for (int i = 0; i < param.getValue().length; i++) { + if (i == 0) { + paramsString.append(param.getValue()[i]); + } else { + paramsString.append(","); + paramsString.append(param.getValue()[i]); + } + } + } + return paramsString.toString(); + } + + public static String arrayToString(String[] values) { + StringBuilder paramsString = new StringBuilder(); + for (int i = 0; i < values.length; i++) { + if (i == 0) { + paramsString.append(values[i]); + } else { + paramsString.append(","); + paramsString.append(values[i]); + } + } + return paramsString.toString(); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/WebConstants.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/WebConstants.java new file mode 100644 index 0000000..9d6cc3f --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/governance/util/WebConstants.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.governance.util; + +import java.util.HashMap; +import java.util.Map; + +/** + * Contains the constants used in the web layer + * + */ +public class WebConstants { + + /** + * In the session to save the current user object's key. + */ + public static final String CURRENT_USER_KEY = "currentUser"; + /** + * The current registered server address + */ + public static final String REGISTRY_ADDRESS = "registryAddress"; + /** + * Service exposed address + */ + public static final String SERVICE_URL = "serviceUrl"; + /** + * Service name + */ + public static final String SERVICE_NAME = "serviceName"; + /** + * Service name + */ + public static final String ENTRY = "entry"; + /** + * buc sso logout + */ + public static final String SSO_LOGOUT_URL = "SSO_LOGOUT_URL"; + /** + * buc sso logon + */ + public static final String BUC_SSO_USERNAME = "buc_sso_username"; + /** + * Operation record page The default page record shows the number of records + */ + public static final Integer OPRATION_RECORDS_PAGE_SIZE = 100; + + /** + * Help Url + */ + public static final String HELP_URL="https://github.com/apache/incubator-dubbo-ops"; + Map context; + + public static final Map mapper = new HashMap<>(); + + static { + mapper.put("providers", "providersController"); + mapper.put("consumers", "consumersController"); + mapper.put("applications", "applicationsController"); + mapper.put("routes", "routesController"); + mapper.put("overrides", "overridesController"); + mapper.put("accesses", "accessesController"); + mapper.put("loadbalances", "loadbalancesController"); + mapper.put("owners", "ownersController"); + mapper.put("weights", "weightsController"); + mapper.put("addresses", "addressesController"); + mapper.put("services", "servicesController"); + } + + + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/ChangeListener.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/ChangeListener.java new file mode 100644 index 0000000..d74361c --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/ChangeListener.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common; + +public interface ChangeListener { + + /** + * Invoked when data changed + * + * @param type data type + */ + void onChanged(String type); + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/StatusManager.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/StatusManager.java new file mode 100644 index 0000000..5120bae --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/StatusManager.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.Status.Level; +import com.alibaba.dubbo.common.status.StatusChecker; + +/** + * StatusManager + * + */ +public class StatusManager { + + private static final StatusManager INSTANCE = new StatusManager(); + private final Map statusHandlers = new ConcurrentHashMap(); + + private StatusManager() { + } + + public static StatusManager getInstance() { + return INSTANCE; + } + + public static Status getStatusSummary(Map statusList) { + return getSummaryStatus(statusList); + } + + public static Status getSummaryStatus(Map statuses) { + Level level = Level.OK; + StringBuilder msg = new StringBuilder(); + for (Map.Entry entry : statuses.entrySet()) { + String key = entry.getKey(); + Status status = entry.getValue(); + Level l = status.getLevel(); + if (Level.ERROR.equals(l)) { + level = Level.ERROR; + if (msg.length() > 0) { + msg.append(","); + } + msg.append(key); + } else if (Level.WARN.equals(l)) { + if (!Level.ERROR.equals(level)) { + level = Level.WARN; + } + if (msg.length() > 0) { + msg.append(","); + } + msg.append(key); + } + } + return new Status(level, msg.toString()); + } + + public void addStatusHandler(String name, StatusChecker statusHandler) { + this.statusHandlers.put(name, statusHandler); + } + + public void addStatusHandlers(Map statusHandlers) { + this.statusHandlers.putAll(statusHandlers); + } + + public void addStatusHandlers(Collection statusHandlers) { + for (StatusChecker statusChecker : statusHandlers) { + String name = statusChecker.getClass().getSimpleName(); + if (name.endsWith(StatusChecker.class.getSimpleName())) { + name = name.substring(0, name.length() - StatusChecker.class.getSimpleName().length()); + } + this.statusHandlers.put(name, statusChecker); + } + } + + public void removeStatusHandler(String name) { + this.statusHandlers.remove(name); + } + + public void clearStatusHandlers() { + this.statusHandlers.clear(); + } + + public Map getStatusList() { + return getStatusList(null); + } + + /** + * Exclude items do not need to show in Summary Page + */ + public Map getStatusList(String[] excludes) { + Map statuses = new HashMap(); + Map temp = new HashMap(); + temp.putAll(statusHandlers); + if (excludes != null && excludes.length > 0) { + for (String exclude : excludes) { + temp.remove(exclude); + } + } + for (Map.Entry entry : temp.entrySet()) { + statuses.put(entry.getKey(), entry.getValue().check()); + } + return statuses; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Access.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Access.java new file mode 100644 index 0000000..28baf26 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Access.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +public class Access extends Entity { + + private static final long serialVersionUID = -962351722638094446L; + + private String service; /*service name*/ + + private String address; /*address of consumer*/ + + private boolean allow; /*status*/ + + private String username; /*user name*/ + + public Access() { + } + + public Access(Long id) { + super(id); + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public boolean isAllow() { + return allow; + } + + public void setAllow(boolean allow) { + this.allow = allow; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Agreement.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Agreement.java new file mode 100644 index 0000000..8a55871 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Agreement.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +/** + * Specifies the applied Quality of Service Level Agreement (SLA) object. + * + */ +public class Agreement extends Entity { + + private static final long serialVersionUID = -4888604682731513790L; + + private String service; // service name + + private String consumerApplication; // application of consumer + + private long invocationQuantity; // call of the day + + private int tps; // TPS limit + + private int responseTime; // Response time in milliseconds + + private double availability; // ratio of available + + private String username; + + public Agreement() { + } + + public Agreement(Long id) { + super(id); + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getConsumerApplication() { + return consumerApplication; + } + + public void setConsumerApplication(String consumerApplication) { + this.consumerApplication = consumerApplication; + } + + public long getInvocationQuantity() { + return invocationQuantity; + } + + public void setInvocationQuantity(long invocationQuantity) { + this.invocationQuantity = invocationQuantity; + } + + public int getTps() { + return tps; + } + + public void setTps(int tps) { + this.tps = tps; + } + + public int getResponseTime() { + return responseTime; + } + + public void setResponseTime(int responseTime) { + this.responseTime = responseTime; + } + + public double getAvailability() { + return availability; + } + + public void setAvailability(double availability) { + this.availability = availability; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Approval.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Approval.java new file mode 100644 index 0000000..921381c --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Approval.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +/** + * Service online approval. + * + */ +public class Approval extends Entity { + private static final long serialVersionUID = -8778092807313048367L; + + private String service; // service name + + private String version; + // You can use wildcards, *,1.1.* + // Can contain more than one, 1.1.3,1.1.5,2.* + + private boolean forProvider; // Provider or consumer + + private String machineList; // service machine + // You can use wildcards, 172.3.8.* + // an contain more than one, 172.1.9.8,172.1.9.123,172.3.3.* + + private String username; + + private String approveUser; // approver + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public boolean isForProvider() { + return forProvider; + } + + public void setForProvider(boolean forProvider) { + this.forProvider = forProvider; + } + + public String getMachineList() { + return machineList; + } + + public void setMachineList(String machineList) { + this.machineList = machineList; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getApproveUser() { + return approveUser; + } + + public void setApproveUser(String approveUser) { + this.approveUser = approveUser; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/ApprovalRequisition.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/ApprovalRequisition.java new file mode 100644 index 0000000..d28ef0a --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/ApprovalRequisition.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +/** + * Service online / offline approval + * + */ +public class ApprovalRequisition extends Entity { + private static final long serialVersionUID = -8778092807313048367L; + + private char operation; // Apply for action: add (C), modify (U), delete (D) + + private Long approvalId; + + private String service; // service name + + private String version; + // wildcards, *,1.1.* + // more than one, 1.1.3,1.1.5,2.* + + private boolean forProvider; + + private String machineList; // servcice machine + // wildcards, 172.3.8.* + // more thaan one, 172.1.9.8,172.1.9.123,172.3.3.* + + private String username; + + public char getOperation() { + return operation; + } + + public void setOperation(char operation) { + this.operation = operation; + } + + public Long getApprovalId() { + return approvalId; + } + + public void setApprovalId(Long approvalId) { + this.approvalId = approvalId; + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public boolean isForProvider() { + return forProvider; + } + + public void setForProvider(boolean forProvider) { + this.forProvider = forProvider; + } + + public String getMachineList() { + return machineList; + } + + public void setMachineList(String machineList) { + this.machineList = machineList; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Change.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Change.java new file mode 100644 index 0000000..6859de7 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Change.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +/** + * Service change information object + * + */ +public class Change extends Entity { + + public static final String PROVIDER_TYPE = "P"; //provider change + public static final String CONSUMER_TYPE = "N"; //consumer change + public static final String ROUTE_TYPE = "R"; //route change + public static final String WEIGHT_TYPE = "W"; //weight change + public static final String LOADBALANCE_TYPE = "L"; //loadbalance change + public static final String CLUSTER_TYPE = "G"; //group change + public static final String USER_TYPE = "U"; //user change + public static final String CONFIG_TYPE = "C"; //system config change + public static final String FEATURE_TYPE = "F"; //feature change + public static final String LAYER_TYPE = "Y"; //layer change + public static final String TEST_TYPE = "T"; //service test change + public static final String MOCK_TYPE = "M"; //service mock change + public static final String ACCESS_TYPE = "A"; //access change + public static final String OVERRIDE_TYPE = "O"; //override change + private static final long serialVersionUID = 15528419903956898L; + private String type; /* type of change */ + + private String service; /* service name */ + + private long sequence; /* NO. of change */ + + private String data; /* what is changed */ + + public Change() { + } + + public Change(Long id) { + super(id); + } + + public Change(String type, String serviceName) { + this.type = type; + this.service = serviceName; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + @Deprecated + /** + * us id as sequence + */ + public long getSequence() { + return sequence; + } + + @Deprecated + /** + * use id as sequence + */ + public void setSequence(long sequence) { + this.sequence = sequence; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Cluster.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Cluster.java new file mode 100644 index 0000000..15124e3 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Cluster.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +public class Cluster extends Entity { + + private static final long serialVersionUID = 8704571999015097948L; + + private String name; /* Service provider group name, a group can contain several providers*/ + + private String address; /* address of consumer */ + + private String username; + + public Cluster() { + } + + public Cluster(Long id) { + super(id); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Config.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Config.java new file mode 100644 index 0000000..72bfd40 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Config.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +/** + * Config instance + * + */ +public class Config extends Entity { + + public static final String MAIL_ENABLED = "MailEnabled"; + public static final String MAIL_HOST = "MailHost"; + public static final String MAIL_PORT = "MailPort"; + public static final String MAIL_FROM = "MailFrom"; + public static final String MAIL_AUTH = "MailAuth"; + public static final String MAIL_USERNAME = "MailUsername"; + public static final String MAIL_PASSWORD = "MailPassword"; + public static final String BULLETIN_MESSAGE = "BulletinMessage"; + public static final String ALLOW_ANONYMOUS_LOGIN = "AllowAnonymousLogin"; // Whether to allow anonymous login + public static final String ALLOW_LEGACY_LOGIN = "AllowLegacyLogin"; // Whether to allow legacy system login + public static final String MAX_THREAD_SIZE = "MaxThreadSize"; // The maximum number of threads + public static final String MAX_CONNECTION_SIZE = "MaxConnectionSize"; // The maximum number of connections + public static final String MAX_CACHE_SIZE = "MaxCacheSize"; // The maximum number of cache (not space) + public static final String MAX_MAIL_SIZE = "MaxMailSize"; // The maximum number of mail queues + public static final String ALIVED_CHECK_INTERVAL = "AlivedCheckInterval"; + public static final String DIRTY_CHECK_INTERVAL = "DirtyCheckInterval"; + public static final String CHANGED_CHECK_INTERVAL = "ChangedCheckInterval"; + public static final String CHANGED_CLEAR_INTERVAL = "ChangedClearInterval"; + public static final String FAILED_RETRY_INTERVAL = "FailedRetryInterval"; + public static final String HEARTBEAT_CHECK_INTERVAL = "HeartbeatCheckInterval";// Heartbeat check interval + public static final String HEARTBEAT_CHECK_TIMEOUT = "HeartbeatCheckTimeout";// The biggest interval for not receive a heartbeat + public static final String WARMUP_WAIT_TIME = "WarmupWaitTime"; + public static final String AUTO_REDIRECT_INTERVAL = "AutoRedirectInterval"; + public static final String AUTO_REDIRECT_THRESHOLD = "AutoRedirectThreshold"; + public static final String AUTO_REDIRECT_TOLERATE_PERCENT = "AutoRedirectToleratePercent"; + public static final String NOTIFY_TIMEOUT = "NotifyTimeout"; + public static final String ROUTE_ENABLED = "RouteEnabled"; + public static final String BUC_SERVICE_ADDRESS = "BucServiceAddress"; + public static final String DEFAULT_SERVICE_PARAMETERS = "DefaultServiceParameters"; + public static final String WARM_UP_ENABLED = "WarmupEnabled"; + public static final String HELP_DOCUMENT_URL = "HelpDocumentUrl"; + public static final String HOMEPAGE_DOMAIN = "HomepageDomain"; + public static final String HOMEPAGE_URL = "HomepageUrl"; + public static final String LOG_LEVEL = "LogLevel"; + public static final String DEFAULT_ROLE = "DefaultRole"; // The default role of user + public static final String SERVER_ROUTE_ENABLED = "ServerRouteEnabled"; + private static final long serialVersionUID = 7938303018328907548L; + private String key; + + private String value; + + private String username; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + @java.lang.Override + public String toString() { + return key + "=" + value; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Consumer.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Consumer.java new file mode 100644 index 0000000..c02f802 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Consumer.java @@ -0,0 +1,229 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.StringUtils; + +/** + * Consumer + * + */ +public class Consumer extends Entity { + + private static final long serialVersionUID = -1140894843784583237L; + + private String service; /* The name of the service referenced by the consumer */ + + private String parameters; + + private String result; /*route result*/ + + private String address; /* address of consumer */ + + private String registry; /* Consumer connected registry address */ + + private String application; /* application name */ + + private String username; /* user name of consumer */ + + private String statistics; /* Service call statistics */ + + private Date collected; /* Date statistics was recorded */ + + private Override override; + + private List overrides; + + private List routes; + + private List providers; + + private Date expired; + + private long alived; /*Time to live in milliseconds*/ + + public Consumer() { + } + + public Consumer(Long id) { + super(id); + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getParameters() { + return parameters; + } + + public void setParameters(String parameters) { + this.parameters = parameters; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getRegistry() { + return registry; + } + + public void setRegistry(String registry) { + this.registry = registry; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getStatistics() { + return statistics; + } + + public void setStatistics(String statistics) { + this.statistics = statistics; + } + + public Date getCollected() { + return collected; + } + + public void setCollected(Date collected) { + this.collected = collected; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public String getApplication() { + return application; + } + + public void setApplication(String application) { + this.application = application; + } + + public Date getExpired() { + return expired; + } + + + public void setExpired(Date expired) { + this.expired = expired; + } + + + public long getAlived() { + return alived; + } + + + public void setAlived(long alived) { + this.alived = alived; + } + + public Override getOverride() { + return override; + } + + public void setOverride(Override override) { + this.override = override; + } + + public List getOverrides() { + return overrides; + } + + public void setOverrides(List overrides) { + this.overrides = overrides; + } + + public List getRoutes() { + return routes; + } + + public void setRoutes(List routes) { + this.routes = routes; + } + + public List getProviders() { + return providers; + } + + public void setProviders(List providers) { + this.providers = providers; + } + + public String toString() { + return "Consumer [service=" + service + ", parameters=" + parameters + ", result=" + result + + ", address=" + address + ", registry=" + registry + ", application=" + + application + ", username=" + username + ", statistics=" + statistics + + ", collected=" + collected + ", routes=" + routes + ", overrides=" + overrides + + ", expired=" + expired + ", alived=" + alived + "]"; + } + + public URL toUrl() { + String group = null; + String version = null; + String path = service; + int i = path.indexOf("/"); + if (i > 0) { + group = path.substring(0, i); + path = path.substring(i + 1); + } + i = path.lastIndexOf(":"); + if (i > 0) { + version = path.substring(i + 1); + path = path.substring(0, i); + } + Map param = StringUtils.parseQueryString(parameters); + param.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY); + if (group != null) { + param.put(Constants.GROUP_KEY, group); + } + if (version != null) { + param.put(Constants.VERSION_KEY, version); + } + return URL.valueOf(Constants.CONSUMER_PROTOCOL + "://" + address + "/" + path + + "?" + StringUtils.toQueryString(param)); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/DependItem.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/DependItem.java new file mode 100644 index 0000000..0a0524b --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/DependItem.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +import java.util.ArrayList; +import java.util.List; + +/** + * DependItem + * + */ +public class DependItem { + + private final List recursives = new ArrayList(); + private String application; + private int index; + private int level; + private DependItem parent; + + public DependItem() { + } + + public DependItem(String application, int level) { + this.application = application; + this.level = level; + } + + public DependItem(DependItem parent, String application, int level, int index) { + this.parent = parent; + this.application = application; + this.level = level; + this.index = index; + } + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } + + public String getApplication() { + return application; + } + + public void setApplication(String application) { + this.application = application; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public DependItem getParent() { + return parent; + } + + public void setParent(DependItem parent) { + this.parent = parent; + } + + public List getRecursives() { + return recursives; + } + + public void addRecursive(int padding, int value) { + while (recursives.size() < padding) { + recursives.add(0); + } + recursives.add(value); + } + + public String toString() { + return "DependItem [application=" + application + ", index=" + index + ", level=" + level + + "]"; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Dependency.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Dependency.java new file mode 100644 index 0000000..46f1032 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Dependency.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +import java.io.Serializable; + +public class Dependency implements Serializable { + + private static final long serialVersionUID = 8526869025719540547L; + + private String providerApplication; + + private String consumerApplication; + + public String getProviderApplication() { + return providerApplication; + } + + public void setProviderApplication(String providerApplication) { + this.providerApplication = providerApplication; + } + + public String getConsumerApplication() { + return consumerApplication; + } + + public void setConsumerApplication(String consumerApplication) { + this.consumerApplication = consumerApplication; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Document.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Document.java new file mode 100644 index 0000000..95b8f9b --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Document.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +/** + * Document + * + */ +public class Document extends Entity { + + public static final String EXTERNAL_TYPE = "E"; + public static final String INTERNAL_TYPE = "I"; + public static final String API_TYPE = "A"; + private static final long serialVersionUID = 5059135057592486874L; + private String service; + + private String title; + + private String type; + + private String content; + + private String username; + + public Document() { + } + + public Document(Long id) { + super(id); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Entity.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Entity.java new file mode 100644 index 0000000..54531f7 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Entity.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * Entity + * + */ +public abstract class Entity implements Serializable { + + private static final long serialVersionUID = -3031128781434583143L; + + private List ids; + + private Long id; + + private Date created; + + private Date modified; + + private Date now; + + private String operator; + + private String operatorAddress; + + private boolean miss; + + public Entity() { + } + + public Entity(Long id) { + this.id = id; + } + + public List getIds() { + return ids; + } + + public void setIds(List ids) { + this.ids = ids; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getModified() { + return modified; + } + + public void setModified(Date modified) { + this.modified = modified; + } + + public Date getNow() { + return now; + } + + public void setNow(Date now) { + this.now = now; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + if (operator != null && operator.length() > 200) { + operator = operator.substring(0, 200); + } + this.operator = operator; + } + + public String getOperatorAddress() { + return operatorAddress; + } + + public void setOperatorAddress(String operatorAddress) { + this.operatorAddress = operatorAddress; + } + + public boolean isMiss() { + return miss; + } + + public void setMiss(boolean miss) { + this.miss = miss; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Favorite.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Favorite.java new file mode 100644 index 0000000..bc65057 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Favorite.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +public class Favorite extends Entity { + + private static final long serialVersionUID = -1281982267153430266L; + + private String name; + + private String url; + + private String username; + + public Favorite() { + } + + public Favorite(Long id) { + super(id); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Feature.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Feature.java new file mode 100644 index 0000000..f751ff5 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Feature.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +/** + * System features + */ +public class Feature extends Entity { + + private static final long serialVersionUID = 3246619851259746169L; + + private String name; + + private boolean enabled; + + private String username; + + public Feature() { + } + + public Feature(Long id) { + super(id); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean getEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Layer.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Layer.java new file mode 100644 index 0000000..0ad3acf --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Layer.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +public class Layer extends Entity { + private static final long serialVersionUID = 6114868933223039253L; + + private String username; + + private String arch; + private String name; + private int value; + + public Layer(Long id) { + super(id); + } + + public Layer() { + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getArch() { + return arch; + } + + public void setArch(String arch) { + this.arch = arch; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/LoadBalance.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/LoadBalance.java new file mode 100644 index 0000000..651b8ca --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/LoadBalance.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +/** + * LoadBalance + * + */ +public class LoadBalance extends Entity { + + public static final String ALL_METHOD = "*"; + private static final long serialVersionUID = -6050324375352581440L; + private String service; /* service name */ + + private String method; /* method name */ + + private String strategy; /*loadbalance policy*/ + + private String username; + + public LoadBalance() { + } + + public LoadBalance(Long id) { + super(id); + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getStrategy() { + return strategy; + } + + public void setStrategy(String strategy) { + this.strategy = strategy; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Mock.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Mock.java new file mode 100644 index 0000000..1d88db7 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Mock.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +/** + * Mock + * + */ +public class Mock extends Entity { + + private static final long serialVersionUID = 872527738197173003L; + + private String name; + + private String service; + + private String method; + + private String parameters; + + private boolean exception; + + private String result; + + private String username; + + private boolean autoRun; + + private String consumerAddr; + + public Mock() { + } + + public Mock(Long id) { + super(id); + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getParameters() { + return parameters; + } + + public void setParameters(String parameters) { + this.parameters = parameters; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public boolean isException() { + return exception; + } + + public void setException(boolean exception) { + this.exception = exception; + } + + public boolean isAutoRun() { + return autoRun; + } + + public void setAutoRun(boolean autoRun) { + this.autoRun = autoRun; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getConsumerAddr() { + return consumerAddr; + } + + public void setConsumerAddr(String consumerAddr) { + this.consumerAddr = consumerAddr; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Operation.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Operation.java new file mode 100644 index 0000000..6043242 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Operation.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Record error messages and record all user operations + * + */ +public class Operation extends Entity { + + public static final String PROVIDER_TYPE = "Provider"; + public static final String CONSUMER_TYPE = "Consumer"; + public static final String ROUTE_TYPE = "Route"; + public static final String WEIGHT_TYPE = "Weight"; + public static final String CLUSTER_TYPE = "Cluster"; + public static final String DOCUMENT_TYPE = "Document"; + public static final String LOADBALANCE_TYPE = "LoadBalance"; + public static final String TEST_TYPE = "Test"; + public static final String MOCK_TYPE = "Mock"; + public static final String AGREEMENT_TYPE = "Agreement"; + public static final String APPROVAL_TYPE = "Approval"; + public static final String APPROVAL_REQUISITION_TYPE = "ApprovalRequisition"; + public static final String USER_TYPE = "User"; + public static final String FEATURE_TYPE = "Feature"; + public static final String LAYER_TYPE = "Layer"; + public static final String CONFIG_TYPE = "Config"; + public static final List TYPES = + Collections.unmodifiableList( + Arrays.asList(new String[]{PROVIDER_TYPE, CONSUMER_TYPE, ROUTE_TYPE, WEIGHT_TYPE, + CLUSTER_TYPE, DOCUMENT_TYPE, LOADBALANCE_TYPE, TEST_TYPE, + AGREEMENT_TYPE, USER_TYPE, FEATURE_TYPE, CONFIG_TYPE})); + private static final long serialVersionUID = 8220325876753890396L; + private String username; // operator + + private String dataType; // data type, e.g., route, cluster + + private String operateType; // operations, e.g. update, create + + private String data; // record data information + + public Operation() { + } + + public Operation(Long id) { + super(id); + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getDataType() { + return dataType; + } + + public void setDataType(String dataType) { + this.dataType = dataType; + } + + public String getData() { + return data; + } + + public void setData(String data) { + if (data != null && data.length() > 1000) { + data = data.substring(0, 1000); + } + this.data = data; + } + + public String getOperateType() { + return operateType; + } + + public void setOperateType(String operateType) { + this.operateType = operateType; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Override.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Override.java new file mode 100644 index 0000000..eeedd20 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Override.java @@ -0,0 +1,202 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.StringUtils; + +public class Override extends Entity { + + private static final long serialVersionUID = 114828505391757846L; + + private String service; + + private String params; + + private String application; + + private String address; + + private String username; + + private boolean enabled; + + public Override() { + } + + public Override(long id) { + super(id); + } + + public String getService() { + return service; + } + + + public void setService(String service) { + this.service = service; + } + + + public String getParams() { + return params; + } + + + public void setParams(String params) { + this.params = params; + } + + + public String getApplication() { + return application; + } + + + public void setApplication(String application) { + this.application = application; + } + + + public String getAddress() { + return address; + } + + + public void setAddress(String address) { + this.address = address; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + + public boolean isEnabled() { + return enabled; + } + + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String toString() { + return "Override [service=" + service + ", params=" + params + ", application=" + + application + ", address=" + address + ", username=" + username + ", enabled=" + enabled + "]"; + } + + public boolean isDefault() { + return (getAddress() == null || getAddress().length() == 0 || Constants.ANY_VALUE.equals(getAddress()) || Constants.ANYHOST_VALUE.equals(getAddress())) + && (getApplication() == null || getApplication().length() == 0 || Constants.ANY_VALUE.equals(getApplication())); + } + + public boolean isMatch(String service, String address, String application) { + return isEnabled() && getParams() != null && getParams().length() > 0 + && service.equals(getService()) + && (address == null || getAddress() == null || getAddress().length() == 0 || getAddress().equals(Constants.ANY_VALUE) || getAddress().equals(Constants.ANYHOST_VALUE) || getAddress().equals(address)) + && (application == null || getApplication() == null || getApplication().length() == 0 || getApplication().equals(Constants.ANY_VALUE) || getApplication().equals(application)); + } + + public boolean isUniqueMatch(Provider provider) { + return isEnabled() && getParams() != null && getParams().length() > 0 + && provider.getService().equals(getService()) + && provider.getAddress().equals(getAddress()); + } + + public boolean isMatch(Provider provider) { + return isEnabled() && getParams() != null && getParams().length() > 0 + && provider.getService().equals(getService()) + && (getAddress() == null || getAddress().length() == 0 || getAddress().equals(Constants.ANY_VALUE) || getAddress().equals(Constants.ANYHOST_VALUE) || getAddress().equals(provider.getAddress())) + && (getApplication() == null || getApplication().length() == 0 || getApplication().equals(Constants.ANY_VALUE) || getApplication().equals(provider.getApplication())); + } + + public boolean isUniqueMatch(Consumer consumer) { + return isEnabled() && getParams() != null && getParams().length() > 0 + && consumer.getService().equals(getService()) + && consumer.getAddress().equals(getAddress()); + } + + public boolean isMatch(Consumer consumer) { + return isEnabled() && getParams() != null && getParams().length() > 0 + && consumer.getService().equals(getService()) + && (getAddress() == null || getAddress().length() == 0 || getAddress().equals(Constants.ANY_VALUE) || getAddress().equals(Constants.ANYHOST_VALUE) || getAddress().equals(consumer.getAddress())) + && (getApplication() == null || getApplication().length() == 0 || getApplication().equals(Constants.ANY_VALUE) || getApplication().equals(consumer.getApplication())); + } + + public Map toParametersMap() { + Map map = StringUtils.parseQueryString(getParams()); + map.remove(Constants.INTERFACE_KEY); + map.remove(Constants.GROUP_KEY); + map.remove(Constants.VERSION_KEY); + map.remove(Constants.APPLICATION_KEY); + map.remove(Constants.CATEGORY_KEY); + map.remove(Constants.DYNAMIC_KEY); + map.remove(Constants.ENABLED_KEY); + return map; + } + + public URL toUrl() { + String group = null; + String version = null; + String path = service; + int i = path.indexOf("/"); + if (i > 0) { + group = path.substring(0, i); + path = path.substring(i + 1); + } + i = path.lastIndexOf(":"); + if (i > 0) { + version = path.substring(i + 1); + path = path.substring(0, i); + } + StringBuilder sb = new StringBuilder(); + sb.append(Constants.OVERRIDE_PROTOCOL); + sb.append("://"); + if (!StringUtils.isBlank(address) && !Constants.ANY_VALUE.equals(address)) { + sb.append(address); + } else { + sb.append(Constants.ANYHOST_VALUE); + } + sb.append("/"); + sb.append(path); + sb.append("?"); + Map param = StringUtils.parseQueryString(params); + param.put(Constants.CATEGORY_KEY, Constants.CONFIGURATORS_CATEGORY); + param.put(Constants.ENABLED_KEY, String.valueOf(isEnabled())); + param.put(Constants.DYNAMIC_KEY, "false"); + if (!StringUtils.isBlank(application) && !Constants.ANY_VALUE.equals(application)) { + param.put(Constants.APPLICATION_KEY, application); + } + if (group != null) { + param.put(Constants.GROUP_KEY, group); + } + if (version != null) { + param.put(Constants.VERSION_KEY, version); + } + sb.append(StringUtils.toQueryString(param)); + return URL.valueOf(sb.toString()); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Owner.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Owner.java new file mode 100644 index 0000000..278fb83 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Owner.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +public class Owner extends Entity { + + private static final long serialVersionUID = -4891350118145794727L; + + /** + * wildcards allowed + */ + private String service; + + private String username; + + private User user; + + public Owner() { + } + + public Owner(Long id) { + super(id); + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/PageList.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/PageList.java new file mode 100644 index 0000000..6405c32 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/PageList.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +import java.io.Serializable; +import java.util.List; + +/** + * PageList + * + */ +public class PageList implements Serializable { + + private static final long serialVersionUID = 43869560130672722L; + + private int start; + + private int limit; + + private int total; + + private List list; + + public PageList() { + } + + public PageList(int start, int limit, int total, List list) { + this.start = start; + this.limit = limit; + this.total = total; + this.list = list; + } + + public int getStart() { + return start; + } + + public void setStart(int start) { + this.start = start; + } + + public int getLimit() { + return limit; + } + + public void setLimit(int limit) { + this.limit = limit; + } + + public int getTotal() { + return total; + } + + public void setTotal(int total) { + this.total = total; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public int getPageCount() { + + int lim = limit; + if (limit < 1) { + lim = 1; + } + + int page = total / lim; + if (page < 1) { + return 1; + } + + int remain = total % lim; + + if (remain > 0) { + page += 1; + } + + return page; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Provider.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Provider.java new file mode 100644 index 0000000..5675874 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Provider.java @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubboadmin.registry.common.registry.ConvertUtil; + +/** + * Provider + * + */ +public class Provider extends Entity { + + private static final long serialVersionUID = 5981342400350878171L; + + private String service;/* The name of the service provided by the provider */ + + private String url; /* Provider's address for service */ + + private String parameters; /* Provider provides service parameters */ + + private String address; /* Provider address */ + + private String registry;/* The provider's registry address */ + + private boolean dynamic; /* provider was registered dynamically */ + + private boolean enabled; /* provider enabled or not */ + + private int weight; /* provider weight */ + + private String application; /* application name */ + + private String username; /* operator */ + + private Date expired; /* time to expire */ + + private long alived; /* time to live in milliseconds */ + + private Override override; + + private List overrides; + + public Provider() { + } + + public Provider(Long id) { + super(id); + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getParameters() { + return parameters; + } + + public void setParameters(String parameters) { + this.parameters = parameters; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getRegistry() { + return registry; + } + + public void setRegistry(String registry) { + this.registry = registry; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getApplication() { + return application; + } + + public void setApplication(String application) { + this.application = application; + } + + public boolean isDynamic() { + return dynamic; + } + + public void setDynamic(boolean dynamic) { + this.dynamic = dynamic; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + + public Date getExpired() { + return expired; + } + + + public void setExpired(Date expired) { + this.expired = expired; + } + + public long getAlived() { + return alived; + } + + public void setAlived(long aliveSeconds) { + this.alived = aliveSeconds; + } + + public int getWeight() { + return weight; + } + + public void setWeight(int weight) { + this.weight = weight; + } + + public Override getOverride() { + return override; + } + + public void setOverride(Override override) { + this.override = override; + } + + public List getOverrides() { + return overrides; + } + + public void setOverrides(List overrides) { + this.overrides = overrides; + } + + public URL toUrl() { + Map serviceName2Map = ConvertUtil.serviceName2Map(getService()); + /*if(!serviceName2Map.containsKey(Constants.INTERFACE_KEY)) { + throw new IllegalArgumentException("No interface info"); + } + if(!serviceName2Map.containsKey(Constants.VERSION_KEY)) { + throw new IllegalArgumentException("No version info"); + }*/ + + String u = getUrl(); + URL url = URL.valueOf(u + "?" + getParameters()); + + url = url.addParameters(serviceName2Map); + + boolean dynamic = isDynamic(); + if (!dynamic) { + url = url.addParameter(Constants.DYNAMIC_KEY, false); + } + boolean enabled = isEnabled(); + if (enabled != url.getParameter("enabled", true)) { + if (enabled) { + url = url.removeParameter("enabled"); + } else { + url = url.addParameter("enabled", false); + } + } + + return url; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Registry.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Registry.java new file mode 100644 index 0000000..a70464e --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Registry.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +import java.util.Date; + +/** + * Registry + * + */ +public class Registry extends Entity { + + private static final long serialVersionUID = -8866645978415551309L; + + private String registry;/* registry address */ + + private String url; + + private int connections = 0;/* connections number to registry */ + + private Date expired; /*time to expire*/ + + private long alived; + + public Registry() { + } + + public Registry(Long id) { + super(id); + } + + public Registry(String registryAddress, String consoleUrl, int aliveSeconds) { + this.registry = registryAddress; + this.url = consoleUrl; + this.alived = aliveSeconds; + } + + public String getAddress() { + return registry; + } + + public void setAddress(String registry) { + this.registry = registry; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Date getExpired() { + return expired; + } + + public void setExpired(Date expiredDate) { + this.expired = expiredDate; + } + + public long getAlived() { + return alived; + } + + public void setAlived(long aliveSeconds) { + this.alived = aliveSeconds; + } + + + public int getConnections() { + return connections; + } + + + public void setConnections(int connections) { + this.connections = connections; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Route.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Route.java new file mode 100644 index 0000000..b6e8d47 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Route.java @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; + +/** + * Route + * + */ +public class Route extends Entity { + + public static final String ALL_METHOD = "*"; + public static final String KEY_METHOD = "method"; + + // WHEN KEY + public static final String KEY_CONSUMER_APPLICATION = "consumer.application"; + public static final String KEY_CONSUMER_GROUP = "consumer.cluster"; + public static final String KEY_CONSUMER_VERSION = "consumer.version"; + public static final String KEY_CONSUMER_HOST = "consumer.host"; + public static final String KEY_CONSUMER_METHODS = "consumer.methods"; + public static final String KEY_PROVIDER_APPLICATION = "provider.application"; + + // THEN KEY + public static final String KEY_PROVIDER_GROUP = "provider.cluster"; + public static final String KEY_PROVIDER_PROTOCOL = "provider.protocol"; + public static final String KEY_PROVIDER_VERSION = "provider.version"; + public static final String KEY_PROVIDER_HOST = "provider.host"; + public static final String KEY_PROVIDER_PORT = "provider.port"; + private static final long serialVersionUID = -7630589008164140656L; + private long parentId; //default 0 + + private String name; + + private String service; + + private String rule; + + private String matchRule; + + private String filterRule; + + private int priority; + + private String username; + + private boolean enabled; + + private boolean force; + + private List children; + + public Route() { + } + + public Route(Long id) { + super(id); + } + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public long getParentId() { + return parentId; + } + + public void setParentId(long parentId) { + this.parentId = parentId; + } + + public List getChildren() { + return children; + } + + public void setChildren(List subRules) { + this.children = subRules; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isForce() { + return force; + } + + public void setForce(boolean force) { + this.force = force; + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getRule() { + return rule; + } + + public void setRule(String rule) { + this.rule = rule; + String[] rules = rule.split(" => "); + if (rules.length != 2) { + throw new IllegalArgumentException("Illegal Route Condition Rule"); + } + this.matchRule = rules[0]; + this.filterRule = rules[1]; + } + + public String getMatchRule() { + return matchRule; + } + + public void setMatchRule(String matchRule) { + this.matchRule = matchRule; + } + + public String getFilterRule() { + return filterRule; + } + + public void setFilterRule(String filterRule) { + this.filterRule = filterRule; + } + + @java.lang.Override + public String toString() { + return "Route [parentId=" + parentId + ", name=" + name + + ", serviceName=" + service + ", matchRule=" + matchRule + + ", filterRule=" + filterRule + ", priority=" + priority + + ", username=" + username + ", enabled=" + enabled + "]"; + } + + public URL toUrl() { + String group = null; + String version = null; + String path = service; + int i = path.indexOf("/"); + if (i > 0) { + group = path.substring(0, i); + path = path.substring(i + 1); + } + i = path.lastIndexOf(":"); + if (i > 0) { + version = path.substring(i + 1); + path = path.substring(0, i); + } + return URL.valueOf(Constants.ROUTE_PROTOCOL + "://" + Constants.ANYHOST_VALUE + "/" + path + + "?" + Constants.CATEGORY_KEY + "=" + Constants.ROUTERS_CATEGORY + + "&router=condition&runtime=false&enabled=" + isEnabled() + "&priority=" + getPriority() + "&force=" + isForce() + "&dynamic=false" + + "&name=" + getName() + "&" + Constants.RULE_KEY + "=" + URL.encode(getMatchRule() + " => " + getFilterRule()) + + (group == null ? "" : "&" + Constants.GROUP_KEY + "=" + group) + + (version == null ? "" : "&" + Constants.VERSION_KEY + "=" + version)); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/SearchHistory.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/SearchHistory.java new file mode 100644 index 0000000..32c405b --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/SearchHistory.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +public class SearchHistory extends Entity { + + private static final long serialVersionUID = -1281982267153430266L; + + private String name; + + private String type; + + private String url; + + public SearchHistory() { + } + + public SearchHistory(Long id) { + super(id); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Test.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Test.java new file mode 100644 index 0000000..e4a1530 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Test.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +/** + * Test + * + */ +public class Test extends Entity { + + private static final long serialVersionUID = 872527738197173003L; + + private String name; + + private String service; + + private String method; + + private String parameters; + + private boolean exception; + + private String result; + + private String username; + + private boolean autoRun; + + public Test() { + } + + public Test(Long id) { + super(id); + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getParameters() { + return parameters; + } + + public void setParameters(String parameters) { + this.parameters = parameters; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public boolean isException() { + return exception; + } + + public void setException(boolean exception) { + this.exception = exception; + } + + public boolean isAutoRun() { + return autoRun; + } + + public void setAutoRun(boolean autoRun) { + this.autoRun = autoRun; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/User.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/User.java new file mode 100644 index 0000000..e9826d3 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/User.java @@ -0,0 +1,259 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +import java.util.Arrays; +import java.util.List; + +import com.alibaba.dubboadmin.registry.common.route.ParseUtils; + +/** + * User + * + */ +public class User extends Entity { + + public static final String REALM = "dubbo"; + public static final String ROOT = "R"; + public static final String ADMINISTRATOR = "A"; + public static final String MANAGER = "M"; + public static final String GUEST = "G"; + public static final String ANONYMOUS = "anonymous"; + public static final String LEGACY = "legacy"; + private static final long serialVersionUID = 7330539198581235339L; + private String username; + + private String password; + + private String role; + + private String creator; + + private boolean enabled; + + private String name; + + private String department; + + private String email; + + private String phone; + + private String alitalk; + + private String locale; + + private String servicePrivilege; + + private List servicePrivileges; + + public User() { + } + + public User(Long id) { + super(id); + } + + public static boolean isValidPrivilege(String servicePrivilege) { + if (servicePrivilege == null || servicePrivilege.length() == 0) { + return true; + } + String[] privileges = servicePrivilege.trim().split("\\s*,\\s*"); + for (String privilege : privileges) { + if (privilege.endsWith("*")) { + privilege = privilege.substring(0, privilege.length() - 1); + } + if (privilege.indexOf('*') > -1) { + return false; + } + } + return true; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public boolean hasServicePrivilege(String[] services) { + if (services == null || services.length == 0) + throw new IllegalArgumentException("services == null"); + for (String service : services) { + boolean r = hasServicePrivilege(service); + if (!r) + return false; + } + return true; + } + + public boolean canGrantPrivilege(String servicePrivilege) { + if (servicePrivilege == null || servicePrivilege.length() == 0) { + return true; + } + if (servicePrivileges == null || servicePrivileges.size() == 0) { + return false; + } + String[] privileges = servicePrivilege.trim().split("\\s*,\\s*"); + for (String privilege : privileges) { + boolean hasPrivilege = false; + for (String ownPrivilege : servicePrivileges) { + if (matchPrivilege(ownPrivilege, privilege)) { + hasPrivilege = true; + } + } + if (!hasPrivilege) { + return false; + } + } + return true; + } + + private boolean matchPrivilege(String ownPrivilege, String privilege) { + if ("*".equals(ownPrivilege) || ownPrivilege.equals(privilege)) { + return true; + } + if (privilege.endsWith("*")) { + if (!ownPrivilege.endsWith("*")) { + return false; + } + privilege = privilege.substring(0, privilege.length() - 1); + ownPrivilege = ownPrivilege.substring(0, ownPrivilege.length() - 1); + return privilege.startsWith(ownPrivilege); + } else { + if (ownPrivilege.endsWith("*")) { + ownPrivilege = ownPrivilege.substring(0, ownPrivilege.length() - 1); + } + return privilege.startsWith(ownPrivilege); + } + } + + public boolean hasServicePrivilege(String service) { + if (service == null || service.length() == 0) + return false; + if (role == null || GUEST.equalsIgnoreCase(role)) { + return false; + } + if (ROOT.equalsIgnoreCase(role)) { + return true; + } + + if (servicePrivileges != null && servicePrivileges.size() > 0) { + for (String privilege : servicePrivileges) { + boolean ok = ParseUtils.isMatchGlobPattern(privilege, service); + if (ok) { + return true; + } + } + } + return false; + } + + public String getServicePrivilege() { + return servicePrivilege; + } + + public void setServicePrivilege(String servicePrivilege) { + this.servicePrivilege = servicePrivilege; + if (servicePrivilege != null && servicePrivilege.length() > 0) { + servicePrivileges = Arrays.asList(servicePrivilege.trim().split("\\s*,\\s*")); + } + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getAlitalk() { + return alitalk; + } + + public void setAlitalk(String alitalk) { + this.alitalk = alitalk; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getLocale() { + return locale; + } + + public void setLocale(String locale) { + this.locale = locale; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Weight.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Weight.java new file mode 100644 index 0000000..2f3f0da --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/domain/Weight.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.domain; + +public class Weight extends Entity { + + //default weight value + public static final int DEFAULT_WEIGHT = 5; + private static final long serialVersionUID = -1281982267153430266L; + private String address; /* User-configured provider address expression */ + + private String serviceName; + + private int weight; /* weight value */ + + private String username; + + public Weight() { + } + + public Weight(Long id) { + super(id); + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getService() { + return serviceName; + } + + public void setService(String serviceName) { + this.serviceName = serviceName; + } + + public int getWeight() { + return weight; + } + + public void setWeight(int weight) { + this.weight = weight; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/registry/ConvertUtil.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/registry/ConvertUtil.java new file mode 100644 index 0000000..b3b1508 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/registry/ConvertUtil.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.registry; + +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.utils.StringUtils; + +public class ConvertUtil { + private ConvertUtil() { + } + + public static Map> convertRegister(Map> register) { + Map> newRegister = new HashMap>(); + for (Map.Entry> entry : register.entrySet()) { + String serviceName = entry.getKey(); + Map serviceUrls = entry.getValue(); + if (!serviceName.contains(":") && !serviceName.contains("/")) { + for (Map.Entry entry2 : serviceUrls.entrySet()) { + String serviceUrl = entry2.getKey(); + String serviceQuery = entry2.getValue(); + Map params = StringUtils.parseQueryString(serviceQuery); + String group = params.get("group"); + String version = params.get("version"); + params.remove("group"); + params.remove("version"); + String name = serviceName; + if (group != null && group.length() > 0) { + name = group + "/" + name; + } + if (version != null && version.length() > 0 && !"0.0.0".equals(version)) { + name = name + ":" + version; + } + Map newUrls = newRegister.get(name); + if (newUrls == null) { + newUrls = new HashMap(); + newRegister.put(name, newUrls); + } + newUrls.put(serviceUrl, StringUtils.toQueryString(params)); + } + } else { + newRegister.put(serviceName, serviceUrls); + } + } + return newRegister; + } + + public static Map convertSubscribe(Map subscribe) { + Map newSubscribe = new HashMap(); + for (Map.Entry entry : subscribe.entrySet()) { + String serviceName = entry.getKey(); + String serviceQuery = entry.getValue(); + if (!serviceName.contains(":") && !serviceName.contains("/")) { + Map params = StringUtils.parseQueryString(serviceQuery); + String group = params.get("group"); + String version = params.get("version"); + params.remove("group"); + params.remove("version"); + String name = serviceName; + if (group != null && group.length() > 0) { + name = group + "/" + name; + } + if (version != null && version.length() > 0 && !"0.0.0".equals(version)) { + name = name + ":" + version; + } + newSubscribe.put(name, StringUtils.toQueryString(params)); + } else { + newSubscribe.put(serviceName, serviceQuery); + } + } + return newSubscribe; + } + + public static Map serviceName2Map(String serviceName) { + String group = null; + String version = null; + int i = serviceName.indexOf("/"); + if (i > 0) { + group = serviceName.substring(0, i); + serviceName = serviceName.substring(i + 1); + } + i = serviceName.lastIndexOf(":"); + if (i > 0) { + version = serviceName.substring(i + 1); + serviceName = serviceName.substring(0, i); + } + + Map ret = new HashMap(); + if (!StringUtils.isEmpty(serviceName)) { + ret.put(Constants.INTERFACE_KEY, serviceName); + } + if (!StringUtils.isEmpty(version)) { + ret.put(Constants.VERSION_KEY, version); + } + if (!StringUtils.isEmpty(group)) { + ret.put(Constants.GROUP_KEY, group); + } + + return ret; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/OverrideUtils.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/OverrideUtils.java new file mode 100644 index 0000000..6de10ee --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/OverrideUtils.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.route; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubboadmin.registry.common.domain.Consumer; +import com.alibaba.dubboadmin.registry.common.domain.Override; +import com.alibaba.dubboadmin.registry.common.domain.Provider; + +public class OverrideUtils { + + public static final Comparator OVERRIDE_COMPARATOR = new Comparator() { + public int compare(Override o1, Override o2) { + if (o1 == null && o2 == null) { + return 0; + } + if (o1 == null) { + return -1; + } + if (o2 == null) { + return 1; + } + int cmp = cmp(o1.getAddress(), o2.getAddress()); + if (cmp != 0) { + return cmp; + } + cmp = cmp(o1.getApplication(), o2.getApplication()); + if (cmp != 0) { + return cmp; + } + return cmp(o1.getService(), o2.getService()); + } + + private int cmp(String s1, String s2) { + if (s1 == null && s2 == null) { + return 0; + } + if (s1 == null) { + return -1; + } + if (s2 == null) { + return 1; + } + if (s1.equals(s2)) { + return 0; + } + if (isAny(s1)) { + return 1; + } + if (isAny(s2)) { + return -1; + } + return s1.compareTo(s2); + } + + private boolean isAny(String s) { + return s == null || s.length() == 0 || Constants.ANY_VALUE.equals(s) || Constants.ANYHOST_VALUE.equals(s); + } + }; + + public static void setConsumerOverrides(Consumer consumer, List overrides) { + if (consumer == null || overrides == null) { + return; + } + List result = new ArrayList(overrides.size()); + for (Override override : overrides) { + if (!override.isEnabled()) { + continue; + } + if (override.isMatch(consumer)) { + result.add(override); + } + if (override.isUniqueMatch(consumer)) { + consumer.setOverride(override); + } + } + Collections.sort(result, OverrideUtils.OVERRIDE_COMPARATOR); + consumer.setOverrides(result); + } + + public static void setProviderOverrides(Provider provider, List overrides) { + if (provider == null || overrides == null) { + return; + } + List result = new ArrayList(overrides.size()); + for (Override override : overrides) { + if (!override.isEnabled()) { + continue; + } + if (override.isMatch(provider)) { + result.add(override); + } + if (override.isUniqueMatch(provider)) { + provider.setOverride(override); + } + } + provider.setOverrides(overrides); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/ParseUtils.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/ParseUtils.java new file mode 100644 index 0000000..396b4e7 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/ParseUtils.java @@ -0,0 +1,335 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.route; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.alibaba.dubbo.common.utils.StringUtils; + +/** + * String parsing tools related to interpolation, including Glob mode, Query string, Service URL processing. + * + */ +public class ParseUtils { + + private static final ConcurrentMap + REPLACE_PARAMETER_PATTERNS = new ConcurrentHashMap(); + public static String METHOD_SPLIT = ","; + private static Pattern VARIABLE_PATTERN = Pattern.compile( + "\\$\\s*\\{?\\s*([\\._0-9a-zA-Z]+)\\s*\\}?"); + private static Pattern QUERY_PATTERN = Pattern + .compile("([&=]?)\\s*([^&=\\s]+)"); + + private ParseUtils() { + } + + /** + * Execute interpolation (variable insertion). + * + * @param expression Expression string containing variables. Variable names in expressions can also be enclosed in {} 。 + * @param params Variable set. Variable names can include . , _ characters. + * @return After the completion of the interpolation string. Such as:
 xxx $ {name} zzz -> xxxjerryzzz   (where the variable name = "jerry")
+     * @throws IllegalStateException The variables used in the expression string are not in the variable set
+     */
+    // FIXME Is it reasonable to throw an IllegalStateException??
+    public static String interpolate(String expression, Map params) {
+        if (expression == null || expression.length() == 0) {
+            throw new IllegalArgumentException("glob pattern is empty!");
+        }
+        if (expression.indexOf('$') < 0) {
+            return expression;
+        }
+        Matcher matcher = VARIABLE_PATTERN.matcher(expression);
+        StringBuffer sb = new StringBuffer();
+        while (matcher.find()) { // match one by one
+            String key = matcher.group(1);
+            String value = params == null ? null : params.get(key);
+            if (value == null) {
+                value = "";
+            }
+            matcher.appendReplacement(sb, value);
+        }
+        matcher.appendTail(sb);
+        return sb.toString();
+    }
+
+    public static List interpolate(List expressions, Map params) {
+        List ret = new ArrayList();
+
+        if (null == expressions || expressions.isEmpty()) {
+            return ret;
+        }
+
+        for (String expr : expressions) {
+            ret.add(interpolate(expr, params));
+        }
+
+        return ret;
+    }
+
+    /**
+     * Match Glob mode. The current implementation only supports * and supports only one. Does not support ?.
+     * @return For code or value of  null , return  false  directly.
+     */
+    public static boolean isMatchGlobPattern(String pattern, String value) {
+        if ("*".equals(pattern))
+            return true;
+        if ((pattern == null || pattern.length() == 0)
+                && (value == null || value.length() == 0))
+            return true;
+        if ((pattern == null || pattern.length() == 0)
+                || (value == null || value.length() == 0))
+            return false;
+
+        int i = pattern.lastIndexOf('*');
+        // No asterisk found
+        if (i == -1) {
+            return value.equals(pattern);
+        }
+        // Asterisk at the end
+        else if (i == pattern.length() - 1) {
+            return value.startsWith(pattern.substring(0, i));
+        }
+        // Asterisk at the beginning
+        else if (i == 0) {
+            return value.endsWith(pattern.substring(i + 1));
+        }
+        // Asterisk in the middle of the string
+        else {
+            String prefix = pattern.substring(0, i);
+            String suffix = pattern.substring(i + 1);
+            return value.startsWith(prefix) && value.endsWith(suffix);
+        }
+    }
+
+    /**
+     * Whether to match Glob mode. Glob mode is the expression to be interpolated. Glob pattern has more than one, as long as matching a pattern, that match is successful.
+     *
+     * @param patternsNeedInterpolate Multiple Glob patterns to interpolate
+         * @param interpolateParams Set of variables used for interpolation
+         * @param value Glob mode value
+     */
+    public static boolean isMatchGlobPatternsNeedInterpolate(
+        Collection patternsNeedInterpolate,
+        Map interpolateParams, String value) {
+        if (patternsNeedInterpolate != null && !patternsNeedInterpolate.isEmpty()) {
+            for (String patternNeedItp : patternsNeedInterpolate) {
+                if (StringUtils.isEmpty(patternNeedItp)) {
+                    continue;
+                }
+                // FIXME ERROR!! The original implementation, here and only the first non-blank pattern comparison, return the corresponding result!
+                // FIXME ERROR!! Should be confirmed with Liang Fei!!
+                String pattern = interpolate(patternNeedItp, interpolateParams);
+                if (isMatchGlobPattern(pattern, value)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the entries in the collection that match the Glob pattern.
+     */
+    public static Set filterByGlobPattern(String pattern, Collection values) {
+        Set ret = new HashSet();
+        if (pattern == null || values == null) {
+            return ret;
+        }
+
+        for (String v : values) {
+            if (isMatchGlobPattern(pattern, v)) {
+                ret.add(v);
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Find the string that matches the Glob pattern. Multiple patterns, as long as a match pattern, it returns this string.
+     */
+    public static Set filterByGlobPattern(Collection patterns, Collection values) {
+        Set ret = new HashSet();
+        if (null == patterns || values == null || patterns.isEmpty() || values.isEmpty()) {
+            return ret;
+        }
+
+        for (String p : patterns) {
+            for (String v : values) {
+                if (isMatchGlobPattern(p, v)) {
+                    ret.add(v);
+                }
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Whether two Glob patterns have intersection.
+     */
+    public static boolean hasIntersection(String glob1, String glob2) {
+        if (null == glob1 || null == glob2) {
+            return false;
+        }
+
+        if (glob1.contains("*") && glob2.contains("*")) {
+            int index1 = glob1.indexOf("*");
+            int index2 = glob2.indexOf("*");
+
+            String s11 = glob1.substring(0, index1);
+            String s12 = glob1.substring(index1 + 1, glob1.length());
+
+            String s21 = glob2.substring(0, index2);
+            String s22 = glob2.substring(index2 + 1, glob2.length());
+
+            if (!s11.startsWith(s21) && !s21.startsWith(s11)) return false;
+            if (!s12.endsWith(s22) && !s22.endsWith(s12)) return false;
+            return true;
+        } else if (glob1.contains("*")) {
+            return isMatchGlobPattern(glob1, glob2);
+        } else if (glob2.contains("*")) {
+            return isMatchGlobPattern(glob2, glob1);
+        } else {
+            return glob1.equals(glob2);
+        }
+    }
+
+    /**
+     * Parse Query String into Map. For strings that have only Key, key3 =  is ignored.
+     *
+     * @param keyPrefix In the output of the Map Key plus a unified prefix.
+     * @param query Query String,For example: key1=value1&key2=value2
+     * @return When Query String is key1=value1&key2=value2, and prefix is pre.,
+     *         then Map{pre.key1=value1, pre.key=value2} will be returned.
+     */
+    // FIXME Is it reasonable to throw an IllegalStateException??
+    public static Map parseQuery(String keyPrefix, String query) {
+        if (query == null)
+            return new HashMap();
+        if (keyPrefix == null)
+            keyPrefix = "";
+
+        Matcher matcher = QUERY_PATTERN.matcher(query);
+        Map routeQuery = new HashMap();
+        String key = null;
+        while (matcher.find()) { // Match one by one
+            String separator = matcher.group(1);
+            String content = matcher.group(2);
+            if (separator == null || separator.length() == 0
+                    || "&".equals(separator)) {
+                if (key != null)
+                    throw new IllegalStateException("Illegal query string \""
+                            + query + "\", The error char '" + separator
+                            + "' at index " + matcher.start() + " before \""
+                            + content + "\".");
+                key = content;
+            } else if ("=".equals(separator)) {
+                if (key == null)
+                    throw new IllegalStateException("Illegal query string \""
+                            + query + "\", The error char '" + separator
+                            + "' at index " + matcher.start() + " before \""
+                            + content + "\".");
+                routeQuery.put(keyPrefix + key, content);
+                key = null;
+            } else {
+                if (key == null)
+                    throw new IllegalStateException("Illegal query string \""
+                            + query + "\", The error char '" + separator
+                            + "' at index " + matcher.start() + " before \""
+                            + content + "\".");
+            }
+        }
+        /*if (key != null)
+        throw new IllegalStateException("Illegal route rule \"" + query
+                + "\", The error in the end char: " + key);*/
+        return routeQuery;
+    }
+
+    public static Map parseQuery(String query) {
+        return parseQuery("", query);
+    }
+
+    /**
+     * Replace the value of the url parameter.
+     */
+    public static String replaceParameter(String query, String key, String value) {
+        if (query == null || query.length() == 0) {
+            return key + "=" + value;
+        }
+        if (query.indexOf(key + "=") == -1) {
+            return query + "&" + key + "=" + value;
+        }
+        Pattern pattern = REPLACE_PARAMETER_PATTERNS.get(key);
+        if (pattern == null) {
+            pattern = Pattern.compile(key.replaceAll("([^(_0-9A-Za-z)])", "\\\\$0") + "=[^&]+");
+        }
+        Matcher matcher = pattern.matcher(query);
+        StringBuffer sb = new StringBuffer();
+        while (matcher.find()) {
+            matcher.appendReplacement(sb, (key + "=" + value).replace("$", "\\$"));
+        }
+        matcher.appendTail(sb);
+        return sb.toString();
+    }
+
+    public static String appendParamToUri(String uri, String name, String value) {
+        if (StringUtils.isEmpty(name) || StringUtils.isEmpty(value)) return uri;
+        if (uri.indexOf('?') != -1) {
+            uri += "&" + name + "=" + value;
+        } else {
+            uri += "?" + name + "=" + value;
+        }
+        return uri;
+    }
+
+    public static String appendParamsToUri(String uri, Map params) {
+        StringBuilder buf = new StringBuilder(uri);
+        boolean first = (uri.indexOf('?') < 0);
+        for (Map.Entry entry : params.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+            if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value))
+                continue;
+            if (first) {
+                buf.append("?");
+                first = false;
+            } else {
+                buf.append("&");
+            }
+            buf.append(key);
+            buf.append("=");
+            buf.append(value);
+        }
+        return buf.toString();
+    }
+
+    public static boolean matchEndStarPattern(String value, String pattern) {
+        if (!pattern.endsWith("*")) throw new IllegalArgumentException("not end star pattern!");
+        String perfix = pattern.substring(0, pattern.length() - 1);
+        return value.startsWith(perfix);
+    }
+}
diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/RouteRule.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/RouteRule.java
new file mode 100644
index 0000000..4e6ce27
--- /dev/null
+++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/RouteRule.java
@@ -0,0 +1,567 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubboadmin.registry.common.route;
+
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.alibaba.dubbo.common.utils.StringUtils;
+import com.alibaba.dubboadmin.registry.common.domain.Route;
+
+/**
+ * Router rule can be divided into two parts, When Condition and Then Condition 
+ * When/Then Confition is expressed in a style of (KV) pair, the V part of the condition pair can contain multiple values (a list)
+ * The meaning of Rule: If a request matches When Condition, then use Then Condition to filter providers (only providers match Then Condition will be returned).
+ * The process of using Conditions to match consumers and providers is called `Filter`. + * When Condition are used to filter ConsumersController, while Then Condition are used to filter ProvidersController. + * RouteRule performs like this: If a Consumer matches When Condition, then only return the ProvidersController matches Then Condition. This means RouteRule should be applied to current Consumer and the providers returned are filtered by RouteRule.
+ * + * An example of Route Rule: + * key1 = value11,value12 & key2 = value21 & key2 != value22 => key3 = value3 & key4 = value41,vlaue42 & key5 !=value51 + * 。 + * The part before => is called When Condition, it's a KV pair; the follower part is Then Condition, also a KV pair. V part in KV can have more than one value, separated by ','

+ * + * Value object, thread safe. + * + */ +public class RouteRule { + @SuppressWarnings("unchecked") + static RouteRule EMPTY = new RouteRule(Collections.EMPTY_MAP, Collections.EMPTY_MAP); + private static Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)"); + private static Pattern CONDITION_SEPERATOR = Pattern.compile("(.*)=>(.*)"); + private static Pattern VALUE_LIST_SEPARATOR = Pattern.compile("\\s*,\\s*"); + final Map whenCondition; + final Map thenCondition; + private volatile String tostring = null; + + // FIXME + private RouteRule(Map when, Map then) { + for (Map.Entry entry : when.entrySet()) { + entry.getValue().freeze(); + } + for (Map.Entry entry : then.entrySet()) { + entry.getValue().freeze(); + } + + // NOTE: Both When Condition and Then Condition can be null + this.whenCondition = when; + this.thenCondition = then; + } + + public static Map parseRule(String rule) + throws ParseException { + Map condition = new HashMap(); + if (StringUtils.isBlank(rule)) { + return condition; + } + // K-V pair, contains matches part and mismatches part + MatchPair pair = null; + // V part has multiple values + Set values = null; + final Matcher matcher = ROUTE_PATTERN.matcher(rule); + while (matcher.find()) { // match one by one + String separator = matcher.group(1); + String content = matcher.group(2); + // The expression starts + if (separator == null || separator.length() == 0) { + pair = new MatchPair(); + condition.put(content, pair); + } + // The KV starts + else if ("&".equals(separator)) { + if (condition.get(content) == null) { + pair = new MatchPair(); + condition.put(content, pair); + } else { + condition.put(content, pair); + } + + } + // The Value part of KV starts + else if ("=".equals(separator)) { + if (pair == null) + throw new ParseException("Illegal route rule \"" + + rule + "\", The error char '" + separator + + "' at index " + matcher.start() + " before \"" + + content + "\".", matcher.start()); + + values = pair.matches; + values.add(content); + } + // The Value part of KV starts + else if ("!=".equals(separator)) { + if (pair == null) + throw new ParseException("Illegal route rule \"" + + rule + "\", The error char '" + separator + + "' at index " + matcher.start() + " before \"" + + content + "\".", matcher.start()); + + values = pair.unmatches; + values.add(content); + } + // The Value part of KV has multiple values, separated by ',' + else if (",".equals(separator)) { // separated by ',' + if (values == null || values.size() == 0) + throw new ParseException("Illegal route rule \"" + + rule + "\", The error char '" + separator + + "' at index " + matcher.start() + " before \"" + + content + "\".", matcher.start()); + values.add(content); + } else { + throw new ParseException("Illegal route rule \"" + rule + + "\", The error char '" + separator + "' at index " + + matcher.start() + " before \"" + content + "\".", matcher.start()); + } + } + return condition; + } + + /** + * Parse the RouteRule as a string into an object. + * + * @throws ParseException RouteRule string format is wrong. The following input conditions, RouteRule are illegal. + *
  • input is null。 + *
  • input is "" or " "。 + *
  • input Rule doesn't have a When Condition + *
  • input Rule doesn't have a Then Condition + *
+ */ + public static RouteRule parse(Route route) throws ParseException { + if (route == null) + throw new ParseException("null route!", 0); + + if (route.getMatchRule() == null && route.getFilterRule() == null) { + return parse(route.getRule()); + } + + return parse(route == null ? null : route.getMatchRule(), route == null ? null : route.getFilterRule()); + } + + public static RouteRule parse(String whenRule, String thenRule) throws ParseException { + /*if (whenRule == null || whenRule.trim().length() == 0) { + throw new ParseException("Illegal route rule without when express", 0); + }*/ + if (thenRule == null || thenRule.trim().length() == 0) { + throw new ParseException("Illegal route rule without then express", 0); + } + Map when = parseRule(whenRule.trim()); + Map then = parseRule(thenRule.trim()); + return new RouteRule(when, then); + } + + public static RouteRule parse(String rule) throws ParseException { + if (StringUtils.isBlank(rule)) { + throw new ParseException("Illegal blank route rule", 0); + } + + final Matcher matcher = CONDITION_SEPERATOR.matcher(rule); + if (!matcher.matches()) throw new ParseException("condition seperator => not found!", 0); + + return parse(matcher.group(1), matcher.group(2)); + } + + /** + * @see #parse(String) + * @throws RuntimeException This is an wrapper exception for the {@link ParseException} thrown by the {@link #parse (String)} method. + */ + public static RouteRule parseQuitely(Route route) { + try { + return parse(route); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + static Map parseNameAndValueListString2Condition(Map params, Map notParams) { + Map condition = new HashMap(); + + for (Entry entry : params.entrySet()) { + String valueListString = entry.getValue(); + if (StringUtils.isBlank(valueListString)) { + continue; + } + String[] list = VALUE_LIST_SEPARATOR.split(valueListString); + Set set = new HashSet(); + for (String item : list) { + if (StringUtils.isBlank(item)) { + continue; + } + set.add(item.trim()); + } + if (set.isEmpty()) { + continue; + } + + String key = entry.getKey(); + MatchPair matchPair = condition.get(key); + if (null == matchPair) { + matchPair = new MatchPair(); + condition.put(key, matchPair); + } + + matchPair.matches = set; + } + for (Entry entry : notParams.entrySet()) { + String valueListString = entry.getValue(); + if (StringUtils.isBlank(valueListString)) { + continue; + } + String[] list = VALUE_LIST_SEPARATOR.split(valueListString); + Set set = new HashSet(); + for (String item : list) { + if (StringUtils.isBlank(item)) { + continue; + } + set.add(item.trim()); + } + if (set.isEmpty()) { + continue; + } + + String key = entry.getKey(); + MatchPair matchPair = condition.get(key); + if (null == matchPair) { + matchPair = new MatchPair(); + condition.put(key, matchPair); + } + + matchPair.unmatches = set; + } + + return condition; + } + + public static RouteRule createFromNameAndValueListString(Map whenParams, Map notWhenParams, + Map thenParams, Map notThenParams) { + Map when = parseNameAndValueListString2Condition(whenParams, notWhenParams); + Map then = parseNameAndValueListString2Condition(thenParams, notThenParams); + + return new RouteRule(when, then); + } + + public static RouteRule createFromCondition(Map whenCondition, Map thenCondition) { + return new RouteRule(whenCondition, thenCondition); + } + + public static RouteRule copyWithRemove(RouteRule copy, Set whenParams, Set thenParams) { + Map when = new HashMap(); + for (Entry entry : copy.getWhenCondition().entrySet()) { + if (whenParams == null || !whenParams.contains(entry.getKey())) { + when.put(entry.getKey(), entry.getValue()); + } + } + + Map then = new HashMap(); + for (Entry entry : copy.getThenCondition().entrySet()) { + if (thenParams == null || !thenParams.contains(entry.getKey())) { + then.put(entry.getKey(), entry.getValue()); + } + } + + return new RouteRule(when, then); + } + + /** + * Replace with the new condition value. + * + * @param copy Replace Base + * @param whenCondition WhenCondition to replace, if Base does not have an item, insert it directly. + * @param thenCondition ThenCondition to replace, if Base has no items, then insert directly. + * @return RouteRule after replacement + */ + public static RouteRule copyWithReplace(RouteRule copy, Map whenCondition, Map thenCondition) { + if (null == copy) { + throw new NullPointerException("Argument copy is null!"); + } + + Map when = new HashMap(); + when.putAll(copy.getWhenCondition()); + if (whenCondition != null) { + when.putAll(whenCondition); + } + + Map then = new HashMap(); + then.putAll(copy.getThenCondition()); + if (thenCondition != null) { + then.putAll(thenCondition); + } + + return new RouteRule(when, then); + } + + // TODO ToString out of the current list is out of order, should we sort? + static void join(StringBuilder sb, Set valueSet) { + boolean isFirst = true; + for (String s : valueSet) { + if (isFirst) { + isFirst = false; + } else { + sb.append(","); + } + + sb.append(s); + } + } + + /** + * Whether the sample passed the conditions. + *

+ * If there is a Key in the KV for the sample, there is a corresponding MatchPair, and Value does not pass through MatchPair; {@code false} is returned; otherwise, {@code true} is returned. + * + * @see MatchPair#pass(String) + */ + public static boolean matchCondition(Map sample, + Map condition) { + for (Map.Entry entry : sample.entrySet()) { + String key = entry.getKey(); + + MatchPair pair = condition.get(key); + if (pair != null && !pair.pass(entry.getValue())) { + return false; + } + } + return true; + } + + + // FIXME Remove such method calls + public static String join(Set valueSet) { + StringBuilder sb = new StringBuilder(128); + join(sb, valueSet); + return sb.toString(); + } + + // TODO At present, the multiple Key of Condition is in disorder. Should we sort it? + public static void contidionToString(StringBuilder sb, Map condition) { + boolean isFirst = true; + for (Entry entry : condition.entrySet()) { + String keyName = entry.getKey(); + MatchPair p = entry.getValue(); + + @SuppressWarnings("unchecked") + Set[] setArray = new Set[]{p.matches, p.unmatches}; + String[] opArray = {" = ", " != "}; + + for (int i = 0; i < setArray.length; ++i) { + if (setArray[i].isEmpty()) { + continue; + } + if (isFirst) { + isFirst = false; + } else { + sb.append(" & "); + } + + sb.append(keyName); + sb.append(opArray[i]); + join(sb, setArray[i]); + } + } + } + + public boolean isWhenContainValue(String key, String value) { + MatchPair matchPair = whenCondition.get(key); + if (null == matchPair) { + return false; + } + + return matchPair.containeValue(value); + } + + public boolean isThenContainValue(String key, String value) { + MatchPair matchPair = thenCondition.get(key); + if (null == matchPair) { + return false; + } + + return matchPair.containeValue(value); + } + + public boolean isContainValue(String key, String value) { + return isWhenContainValue(key, value) || isThenContainValue(key, value); + } + + public Map getWhenCondition() { + return whenCondition; + } + + public Map getThenCondition() { + return thenCondition; + } + + public String getWhenConditionString() { + StringBuilder sb = new StringBuilder(512); + contidionToString(sb, whenCondition); + return sb.toString(); + } + + public String getThenConditionString() { + StringBuilder sb = new StringBuilder(512); + contidionToString(sb, thenCondition); + return sb.toString(); + } + + @Override + public String toString() { + if (tostring != null) + return tostring; + StringBuilder sb = new StringBuilder(512); + contidionToString(sb, whenCondition); + sb.append(" => "); + contidionToString(sb, thenCondition); + return tostring = sb.toString(); + } + + // Automatic generation with Eclipse + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((thenCondition == null) ? 0 : thenCondition.hashCode()); + result = prime * result + ((whenCondition == null) ? 0 : whenCondition.hashCode()); + return result; + } + + // Automatic generation with Eclipse + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RouteRule other = (RouteRule) obj; + if (thenCondition == null) { + if (other.thenCondition != null) + return false; + } else if (!thenCondition.equals(other.thenCondition)) + return false; + if (whenCondition == null) { + if (other.whenCondition != null) + return false; + } else if (!whenCondition.equals(other.whenCondition)) + return false; + return true; + } + + public static class MatchPair { + Set matches = new HashSet(); + Set unmatches = new HashSet(); + private volatile boolean freezed = false; + + public MatchPair() { + } + + public MatchPair(Set matches, Set unmatches) { + if (matches == null || unmatches == null) { + throw new IllegalArgumentException("argument of MatchPair is null!"); + } + + this.matches = matches; + this.unmatches = unmatches; + } + + public Set getMatches() { + return matches; + } + + public Set getUnmatches() { + return unmatches; + } + + public MatchPair copy() { + MatchPair ret = new MatchPair(); + ret.matches.addAll(matches); + ret.unmatches.addAll(unmatches); + return ret; + } + + void freeze() { + if (freezed) return; + synchronized (this) { + if (freezed) return; + matches = Collections.unmodifiableSet(matches); + unmatches = Collections.unmodifiableSet(unmatches); + } + } + + public boolean containeValue(String value) { + return matches.contains(value) || unmatches.contains(value); + } + + /** + * Whether a given value is matched by the {@link MatchPair}. + * return {@code false}, if + *

    + *
  1. value is in unmatches + *
  2. matches is not null, but value is not in matches. + *
+ * otherwise, returntrue。 + */ + public boolean pass(String sample) { + if (unmatches.contains(sample)) return false; + if (matches.isEmpty()) return true; + return matches.contains(sample); + } + + @Override + public String toString() { + return String.format("{matches=%s,unmatches=%s}", matches.toString(), unmatches.toString()); + } + + // Automatic generation with Eclipse + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((matches == null) ? 0 : matches.hashCode()); + result = prime * result + ((unmatches == null) ? 0 : unmatches.hashCode()); + return result; + } + + // Automatic generation with Eclipse + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MatchPair other = (MatchPair) obj; + if (matches == null) { + if (other.matches != null) + return false; + } else if (!matches.equals(other.matches)) + return false; + if (unmatches == null) { + if (other.unmatches != null) + return false; + } else if (!unmatches.equals(other.unmatches)) + return false; + return true; + } + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/RouteRuleUtils.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/RouteRuleUtils.java new file mode 100644 index 0000000..7d1aebd --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/RouteRuleUtils.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.route; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.alibaba.dubbo.common.utils.StringUtils; + +public class RouteRuleUtils { + private RouteRuleUtils() { + } + + /** + * When one of the value that is bound to a specific key of a condition is expanded, it is merged into another value of a specified key. + * @param generic type + * @param condition + * @param srcKeyName the key to expand + * @param destKeyName the key to merge into + * @param expandName2Set the mapping of values to values that are carried out + */ + public static > Map expandCondition( + Map condition, String srcKeyName, String destKeyName, + Map expandName2Set) { + if (null == condition || StringUtils.isEmpty(srcKeyName) || StringUtils.isEmpty(destKeyName)) { + return condition; + } + + RouteRule.MatchPair matchPair = condition.get(srcKeyName); + if (matchPair == null) { + return condition; + } + + Map ret = new HashMap(); + + Iterator> iterator = condition.entrySet().iterator(); + for (; iterator.hasNext(); ) { + Entry entry = iterator.next(); + String condName = entry.getKey(); + + // Neither source nor destination + if (!condName.equals(srcKeyName) && !condName.equals(destKeyName)) { + RouteRule.MatchPair p = entry.getValue(); + if (p != null) ret.put(condName, p); + } + // equals with source + else if (condName.equals(srcKeyName)) { + RouteRule.MatchPair from = condition.get(srcKeyName); + RouteRule.MatchPair to = condition.get(destKeyName); + + // no items to Expand + if (from == null || from.getMatches().isEmpty() && from.getUnmatches().isEmpty()) { + if (to != null) ret.put(destKeyName, to); + continue; + } + + Set matches = new HashSet(); + Set unmatches = new HashSet(); + // add items from source Expand key + for (String s : from.getMatches()) { + if (expandName2Set == null || !expandName2Set.containsKey(s)) continue; + + matches.addAll(expandName2Set.get(s)); + } + for (String s : from.getUnmatches()) { + if (expandName2Set == null || !expandName2Set.containsKey(s)) continue; + + unmatches.addAll(expandName2Set.get(s)); + } + // add the original items + if (to != null) { + matches.addAll(to.getMatches()); + unmatches.addAll(to.getUnmatches()); + } + + ret.put(destKeyName, new RouteRule.MatchPair(matches, unmatches)); + } + // else, it must be Key == destKeyName, do nothing + } + + return ret; + } + + /** + * Check whether the KV (key=value pair of Provider or Consumer) matches the conditions. + * + * @param condition can contains variable definition. For example, {key1={matches={value1,value2,$var1},unmatches={Vx,Vy,$var2}}} + * @param valueParams Set of values of interpolated variables in a condition + * @param kv key=value pair of Provider or Consumer + * @see RouteRule + */ + public static boolean isMatchCondition(Map condition, + Map valueParams, Map kv) { + if (condition != null && condition.size() > 0) { + for (Map.Entry entry : condition.entrySet()) { + String condName = entry.getKey(); + RouteRule.MatchPair p = entry.getValue(); + String value = kv.get(condName); + Set matches = p.getMatches(); + if (matches != null && matches.size() > 0 + && !ParseUtils.isMatchGlobPatternsNeedInterpolate(matches, valueParams, value)) { // if V is null, return false + // don't match matches + return false; + } + Set unmatches = p.getUnmatches(); + if (unmatches != null && unmatches.size() > 0 + && ParseUtils.isMatchGlobPatternsNeedInterpolate(unmatches, valueParams, value)) { + // match unmatches + return false; + } + } + } + return true; + } + + + /** + * Return services that can match When Condition in Route Rule, use Glob Pattern. + */ + public static Set filterServiceByRule(List services, RouteRule rule) { + if (null == services || services.isEmpty() || rule == null) { + return new HashSet(); + } + + RouteRule.MatchPair p = rule.getWhenCondition().get("service"); + if (p == null) { + return new HashSet(); + } + + Set filter = ParseUtils.filterByGlobPattern(p.getMatches(), services); + Set set = ParseUtils.filterByGlobPattern(p.getUnmatches(), services); + filter.addAll(set); + return filter; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/RouteUtils.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/RouteUtils.java new file mode 100644 index 0000000..6774182 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/route/RouteUtils.java @@ -0,0 +1,314 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.route; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.registry.common.domain.Override; +import com.alibaba.dubboadmin.registry.common.domain.Provider; +import com.alibaba.dubboadmin.registry.common.domain.Route; + +/** + * RouteParser route rule parse tool。 + * + */ +public class RouteUtils { + + public static boolean matchRoute(String consumerAddress, String consumerQueryUrl, Route route, Map> clusters) { + RouteRule rule = RouteRule.parseQuitely(route); + Map when = RouteRuleUtils.expandCondition( + rule.getWhenCondition(), "consumer.cluster", "consumer.host", clusters); + Map consumerSample = ParseUtils.parseQuery("consumer.", consumerQueryUrl); + + final int index = consumerAddress.lastIndexOf(":"); + String consumerHost = null; + if (index != -1) { + consumerHost = consumerAddress.substring(0, index); + } else { + consumerHost = consumerAddress; + } + consumerSample.put("consumer.host", consumerHost); + + return RouteRuleUtils.isMatchCondition(when, consumerSample, consumerSample); + } + + public static Map previewRoute(String serviceName, String consumerAddress, String queryUrl, Map serviceUrls, + Route route, Map> clusters, List routed) { + if (null == route) { + throw new IllegalArgumentException("Route is null."); + } + List routes = new ArrayList(); + routes.add(route); + return route(serviceName, consumerAddress, queryUrl, serviceUrls, routes, clusters, routed); + } + + /** + * @return Map + */ + public static List findUsedRoute(String serviceName, String consumerAddress, String consumerQueryUrl, + List routes, Map> clusters) { + List routed = new ArrayList(); + Map urls = new HashMap(); + urls.put("dubbo://" + consumerAddress + "/" + serviceName, consumerQueryUrl); + RouteUtils.route(serviceName, consumerAddress, consumerQueryUrl, urls, routes, clusters, routed); + return routed; + } + + public static List route(String serviceName, String consumerAddress, String consumerQueryUrl, List providers, + List overrides, List routes, Map> clusters, List routed) { + if (providers == null) { + return null; + } + Map urls = new HashMap(); + urls.put("consumer://" + consumerAddress + "/" + serviceName, consumerQueryUrl); // not empty dummy data + for (Provider provider : providers) { + if (com.alibaba.dubboadmin.web.pulltool.Tool.isProviderEnabled(provider, overrides)) { + urls.put(provider.getUrl(), provider.getParameters()); + } + } + urls = RouteUtils.route(serviceName, consumerAddress, consumerQueryUrl, urls, routes, clusters, routed); + List result = new ArrayList(); + for (Provider provider : providers) { + if (urls.containsKey(provider.getUrl())) { + result.add(provider); + } + } + return result; + } + + /** + * @param serviceName e.g. {@code com.alibaba.morgan.MemberService} + * @param consumerAddress e.g. {@code 192.168.1.3:54333} + * @param consumerQueryUrl metadata of subscribe url, e.g. aplication=nasdaq&dubbo=2.0.3&methods=updateItems,validateNew&revision=1.7.0 + * @param serviceUrls providers + * @param routes all route rules + * @param clusters all clusters + * @return route result, Map + */ + // FIXME The combination of clusters and routes can be done in advance when clusters or routes changes + // FIXME Separating the operation of Cache from the Util method + public static Map route(String serviceName, String consumerAddress, String consumerQueryUrl, Map serviceUrls, + List routes, Map> clusters, List routed) { + if (serviceUrls == null || serviceUrls.size() == 0) { + return serviceUrls; + } + if (routes == null || routes.isEmpty()) { + return serviceUrls; + } + + Map rules = route2RouteRule(routes, clusters); + + final Map consumerSample = ParseUtils.parseQuery("consumer.", consumerQueryUrl); + final int index = consumerAddress.lastIndexOf(":"); + final String consumerHost; + if (consumerAddress != null && index != -1) { + consumerHost = consumerAddress.substring(0, index); + } else { + consumerHost = consumerAddress; + } + consumerSample.put("consumer.host", consumerHost); + + Map> url2ProviderSample = new HashMap>(); + for (Map.Entry entry : serviceUrls.entrySet()) { + URI uri; + try { + uri = new URI(entry.getKey()); + } catch (URISyntaxException e) { + throw new IllegalStateException("fail to parse url(" + entry.getKey() + "):" + e.getMessage(), e); + } + Map sample = new HashMap(); + sample.putAll(ParseUtils.parseQuery("provider.", entry.getValue())); + sample.put("provider.protocol", uri.getScheme()); + sample.put("provider.host", uri.getHost()); + sample.put("provider.port", String.valueOf(uri.getPort())); + + url2ProviderSample.put(entry.getKey(), sample); + } + + + Map> url2Methods = new HashMap>(); + + // Consumer can specify the required methods through the consumer.methods Key + String methodsString = consumerSample.get("consumer.methods"); + String[] methods = methodsString == null || methodsString.length() == 0 ? new String[]{Route.ALL_METHOD} : methodsString.split(ParseUtils.METHOD_SPLIT); + for (String method : methods) { + consumerSample.put("method", method); + // NOTE: + // <*method>only configure + // if method1 matches and , we should reduce the priority of . + if (routes != null && routes.size() > 0) { + for (Route route : routes) { + if (isSerivceNameMatched(route.getService(), serviceName)) { + RouteRule rule = rules.get(route.getId()); + // matches When Condition + if (rule != null && RouteRuleUtils.isMatchCondition( + rule.getWhenCondition(), consumerSample, consumerSample)) { + if (routed != null && !routed.contains(route)) { + routed.add(route); + } + Map then = rule.getThenCondition(); + if (then != null) { + Map> tmp = getUrlsMatchedCondition(then, consumerSample, url2ProviderSample); + // If the result of the rule is empty, the rule is invalid and all Provider is used. + if (route.isForce() || !tmp.isEmpty()) { + url2ProviderSample = tmp; + } + } + } + } + } + } + for (String url : url2ProviderSample.keySet()) { + Set mts = url2Methods.get(url); + if (mts == null) { + mts = new HashSet(); + url2Methods.put(url, mts); + } + mts.add(method); + } + } // end of for methods + + return appendMethodsToUrls(serviceUrls, url2Methods); + } + + static Map route2RouteRule(List routes, + Map> clusters) { + Map rules = new HashMap(); + // route -> RouteRule + if (routes != null && routes.size() > 0) { + for (Route route : routes) { + rules.put(route.getId(), RouteRule.parseQuitely(route)); + } + } + // expand the cluster parameters into conditions of routerule + if (clusters != null && clusters.size() > 0) { + Map rrs = new HashMap(); + for (Map.Entry entry : rules.entrySet()) { + RouteRule rr = entry.getValue(); + + Map when = RouteRuleUtils.expandCondition( + rr.getWhenCondition(), "consumer.cluster", "consumer.host", clusters); + Map then = RouteRuleUtils.expandCondition( + rr.getThenCondition(), "provider.cluster", "provider.host", clusters); + + rrs.put(entry.getKey(), RouteRule.createFromCondition(when, then)); + } + rules = rrs; + } + return rules; + } + + static Map appendMethodsToUrls(Map serviceUrls, + Map> url2Methods) { + // Add method parameters to URL + Map results = new HashMap(); + for (Map.Entry> entry : url2Methods.entrySet()) { + String url = entry.getKey(); + String query = serviceUrls.get(url); + + Set methodNames = entry.getValue(); + if (methodNames != null && methodNames.size() > 0) { + String ms = StringUtils.join(methodNames.toArray(new String[0]), ParseUtils.METHOD_SPLIT); + query = ParseUtils.replaceParameter(query, "methods", ms); + } + results.put(url, query); + } + return results; + } + + static Route getFirstRouteMatchedWhenConditionOfRule(String serviceName, Map consumerSample, List routes, Map routeRuleMap) { + if (serviceName == null || serviceName.length() == 0) { + return null; + } + if (routes != null && routes.size() > 0) { + for (Route route : routes) { + if (isSerivceNameMatched(route.getService(), serviceName)) { + RouteRule rule = routeRuleMap.get(route.getId()); + // if matches When Condition + if (rule != null && RouteRuleUtils.isMatchCondition( + rule.getWhenCondition(), consumerSample, consumerSample)) { + return route; // will return if the first condition matches + } + } + } + } + return null; + } + + /** + * Check if a service name matches pattern + * + * @param servicePattern + * @param serviceName + */ + static boolean isSerivceNameMatched(String servicePattern, String serviceName) { + final int pip = servicePattern.indexOf('/'); + final int pi = serviceName.indexOf('/'); + if (pip != -1) { // pattern has group + if (pi == -1) return false; // servicename doesn't have group + + String gp = servicePattern.substring(0, pip); + servicePattern = servicePattern.substring(pip + 1); + + String g = serviceName.substring(0, pi); + if (!gp.equals(g)) return false; + } + if (pi != -1) + serviceName = serviceName.substring(pi + 1); + + final int vip = servicePattern.lastIndexOf(':'); + final int vi = serviceName.lastIndexOf(':'); + if (vip != -1) { // pattern has group + if (vi == -1) return false; + + String vp = servicePattern.substring(vip + 1); + servicePattern = servicePattern.substring(0, vip); + + String v = serviceName.substring(vi + 1); + if (!vp.equals(v)) return false; + } + if (vi != -1) + serviceName = serviceName.substring(0, vi); + + return ParseUtils.isMatchGlobPattern(servicePattern, serviceName); + } + + static Map> getUrlsMatchedCondition(Map condition, + Map parameters, Map> url2Sample) { + Map> result = new HashMap>(); + for (Map.Entry> entry : url2Sample.entrySet()) { + Map sample = entry.getValue(); + + Map params = new HashMap(); + params.putAll(sample); + params.putAll(parameters); + + if (RouteRuleUtils.isMatchCondition(condition, params, sample)) { + result.put(entry.getKey(), entry.getValue()); + } + } + return result; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/status/DatabaseStatusChecker.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/status/DatabaseStatusChecker.java new file mode 100644 index 0000000..d02def8 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/status/DatabaseStatusChecker.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.status; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; + +import javax.sql.DataSource; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; + +import org.springframework.beans.factory.annotation.Autowired; + +/** + * DatabaseStatus + * + */ +public class DatabaseStatusChecker implements StatusChecker { + + private static final Logger logger = LoggerFactory.getLogger(DatabaseStatusChecker.class); + + private int version; + + private String message; + + @Autowired + private DataSource dataSource; + + public void setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + check(); // init + } + + public Status check() { + boolean ok; + try { + Connection connection = dataSource.getConnection(); + try { + DatabaseMetaData metaData = connection.getMetaData(); + ResultSet resultSet = metaData.getTypeInfo(); + try { + ok = resultSet.next(); + } finally { + resultSet.close(); + } + if (message == null) { + message = metaData.getURL() + + " (" + metaData.getDatabaseProductName() + + " " + metaData.getDatabaseProductVersion() + + ", " + getIsolation(metaData.getDefaultTransactionIsolation()) + ")"; + } + if (version == 0) { + version = metaData.getDatabaseMajorVersion(); + } + } finally { + connection.close(); + } + } catch (Throwable e) { + logger.error(e.getMessage(), e); + ok = false; + } + return new Status(!ok ? Status.Level.ERROR : (version < 5 ? Status.Level.WARN : Status.Level.OK), message); + } + + private String getIsolation(int i) { + if (i == Connection.TRANSACTION_READ_COMMITTED) { + return "READ_COMMITTED"; + } + if (i == Connection.TRANSACTION_READ_UNCOMMITTED) { + return "READ_UNCOMMITTED"; + } + if (i == Connection.TRANSACTION_REPEATABLE_READ) { + return "REPEATABLE_READ"; + } + if (i == Connection.TRANSACTION_SERIALIZABLE) { + return "SERIALIZABLE)"; + } + return "NONE"; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/status/LoadStatusChecker.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/status/LoadStatusChecker.java new file mode 100644 index 0000000..cfbf5cc --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/status/LoadStatusChecker.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.status; + +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; +import java.lang.reflect.Method; + +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; + +/** + * Load StatusController + * + */ +public class LoadStatusChecker implements StatusChecker { + + public Status check() { + OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); + double load; + try { + Method method = OperatingSystemMXBean.class.getMethod("getSystemLoadAverage", new Class[0]); + load = (Double) method.invoke(operatingSystemMXBean, new Object[0]); + } catch (Throwable e) { + load = -1; + } + int cpu = operatingSystemMXBean.getAvailableProcessors(); + return new Status(load < 0 ? Status.Level.UNKNOWN : (load < cpu ? Status.Level.OK : Status.Level.WARN), "Load: " + load + " / CPU: " + cpu); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/status/MemoryStatusChecker.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/status/MemoryStatusChecker.java new file mode 100644 index 0000000..c28e35a --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/status/MemoryStatusChecker.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.status; + +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; + +/** + * MemoryStatus + * + */ +public class MemoryStatusChecker implements StatusChecker { + + public Status check() { + Runtime runtime = Runtime.getRuntime(); + long freeMemory = runtime.freeMemory(); + long totalMemory = runtime.totalMemory(); + long maxMemory = runtime.maxMemory(); + boolean ok = (maxMemory - (totalMemory - freeMemory) > 2048); // Alarm when spare memory < 2M + String msg = "Max:" + (maxMemory / 1024 / 1024) + "M, Total:" + + (totalMemory / 1024 / 1024) + "M, Free:" + (freeMemory / 1024 / 1024) + + "M, Use:" + ((totalMemory / 1024 / 1024) - (freeMemory / 1024 / 1024)) + "M"; + return new Status(ok ? Status.Level.OK : Status.Level.WARN, msg); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/Coder.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/Coder.java new file mode 100644 index 0000000..644a12b --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/Coder.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.util; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import com.alibaba.dubbo.common.io.Bytes; + +public class Coder { + + private Coder() { + } + + public static String encodeHex(byte[] bytes) { + StringBuffer buffer = new StringBuffer(bytes.length * 2); + for (int i = 0; i < bytes.length; i++) { + if (((int) bytes[i] & 0xff) < 0x10) + buffer.append("0"); + buffer.append(Long.toString((int) bytes[i] & 0xff, 16)); + } + return buffer.toString(); + } + + public static String encodeMd5(String source) { + return encodeMd5(source.getBytes()); + } + + public static String encodeMd5(byte[] source) { + try { + return encodeHex(MessageDigest.getInstance("MD5").digest(source)); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + public static String encodeBase64(String source) { + return Bytes.bytes2base64(source.getBytes()); + } + + public static String decodeBase64(String source) { + return new String(Bytes.base642bytes(source)); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/Entities.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/Entities.java new file mode 100644 index 0000000..8361430 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/Entities.java @@ -0,0 +1,953 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.dubboadmin.registry.common.util; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +/** + *

+ * Provides HTML and XML entity utilities. + *

+ * + * @version $Id: Entities.java 181192 2012-06-21 05:05:47Z tony.chenl $ + * @see ISO Entities + * @see HTML 3.2 Character Entities for ISO Latin-1 + * @see HTML 4.0 Character entity references + * @see HTML 4.01 Character References + * @see HTML 4.01 Code positions + * @since 2.0 + */ +class Entities { + + /** + *

+ * The set of entities supported by standard XML. + *

+ */ + public static final Entities XML; + /** + *

+ * The set of entities supported by HTML 3.2. + *

+ */ + public static final Entities HTML32; + /** + *

+ * The set of entities supported by HTML 4.0. + *

+ */ + public static final Entities HTML40; + // package scoped for testing + static final String[][] ISO8859_1_ARRAY = {{"nbsp", "160"}, // non-breaking space + {"iexcl", "161"}, // inverted exclamation mark + {"cent", "162"}, // cent sign + {"pound", "163"}, // pound sign + {"curren", "164"}, // currency sign + {"yen", "165"}, // yen sign = yuan sign + {"brvbar", "166"}, // broken bar = broken vertical bar + {"sect", "167"}, // section sign + {"uml", "168"}, // diaeresis = spacing diaeresis + {"copy", "169"}, // � - copyright sign + {"ordf", "170"}, // feminine ordinal indicator + {"laquo", "171"}, // left-pointing double angle quotation mark = left pointing guillemet + {"not", "172"}, // not sign + {"shy", "173"}, // soft hyphen = discretionary hyphen + {"reg", "174"}, // � - registered trademark sign + {"macr", "175"}, // macron = spacing macron = overline = APL overbar + {"deg", "176"}, // degree sign + {"plusmn", "177"}, // plus-minus sign = plus-or-minus sign + {"sup2", "178"}, // superscript two = superscript digit two = squared + {"sup3", "179"}, // superscript three = superscript digit three = cubed + {"acute", "180"}, // acute accent = spacing acute + {"micro", "181"}, // micro sign + {"para", "182"}, // pilcrow sign = paragraph sign + {"middot", "183"}, // middle dot = Georgian comma = Greek middle dot + {"cedil", "184"}, // cedilla = spacing cedilla + {"sup1", "185"}, // superscript one = superscript digit one + {"ordm", "186"}, // masculine ordinal indicator + {"raquo", "187"}, // right-pointing double angle quotation mark = right pointing guillemet + {"frac14", "188"}, // vulgar fraction one quarter = fraction one quarter + {"frac12", "189"}, // vulgar fraction one half = fraction one half + {"frac34", "190"}, // vulgar fraction three quarters = fraction three quarters + {"iquest", "191"}, // inverted question mark = turned question mark + {"Agrave", "192"}, // � - uppercase A, grave accent + {"Aacute", "193"}, // � - uppercase A, acute accent + {"Acirc", "194"}, // � - uppercase A, circumflex accent + {"Atilde", "195"}, // � - uppercase A, tilde + {"Auml", "196"}, // � - uppercase A, umlaut + {"Aring", "197"}, // � - uppercase A, ring + {"AElig", "198"}, // � - uppercase AE + {"Ccedil", "199"}, // � - uppercase C, cedilla + {"Egrave", "200"}, // � - uppercase E, grave accent + {"Eacute", "201"}, // � - uppercase E, acute accent + {"Ecirc", "202"}, // � - uppercase E, circumflex accent + {"Euml", "203"}, // � - uppercase E, umlaut + {"Igrave", "204"}, // � - uppercase I, grave accent + {"Iacute", "205"}, // � - uppercase I, acute accent + {"Icirc", "206"}, // � - uppercase I, circumflex accent + {"Iuml", "207"}, // � - uppercase I, umlaut + {"ETH", "208"}, // � - uppercase Eth, Icelandic + {"Ntilde", "209"}, // � - uppercase N, tilde + {"Ograve", "210"}, // � - uppercase O, grave accent + {"Oacute", "211"}, // � - uppercase O, acute accent + {"Ocirc", "212"}, // � - uppercase O, circumflex accent + {"Otilde", "213"}, // � - uppercase O, tilde + {"Ouml", "214"}, // � - uppercase O, umlaut + {"times", "215"}, // multiplication sign + {"Oslash", "216"}, // � - uppercase O, slash + {"Ugrave", "217"}, // � - uppercase U, grave accent + {"Uacute", "218"}, // � - uppercase U, acute accent + {"Ucirc", "219"}, // � - uppercase U, circumflex accent + {"Uuml", "220"}, // � - uppercase U, umlaut + {"Yacute", "221"}, // � - uppercase Y, acute accent + {"THORN", "222"}, // � - uppercase THORN, Icelandic + {"szlig", "223"}, // � - lowercase sharps, German + {"agrave", "224"}, // � - lowercase a, grave accent + {"aacute", "225"}, // � - lowercase a, acute accent + {"acirc", "226"}, // � - lowercase a, circumflex accent + {"atilde", "227"}, // � - lowercase a, tilde + {"auml", "228"}, // � - lowercase a, umlaut + {"aring", "229"}, // � - lowercase a, ring + {"aelig", "230"}, // � - lowercase ae + {"ccedil", "231"}, // � - lowercase c, cedilla + {"egrave", "232"}, // � - lowercase e, grave accent + {"eacute", "233"}, // � - lowercase e, acute accent + {"ecirc", "234"}, // � - lowercase e, circumflex accent + {"euml", "235"}, // � - lowercase e, umlaut + {"igrave", "236"}, // � - lowercase i, grave accent + {"iacute", "237"}, // � - lowercase i, acute accent + {"icirc", "238"}, // � - lowercase i, circumflex accent + {"iuml", "239"}, // � - lowercase i, umlaut + {"eth", "240"}, // � - lowercase eth, Icelandic + {"ntilde", "241"}, // � - lowercase n, tilde + {"ograve", "242"}, // � - lowercase o, grave accent + {"oacute", "243"}, // � - lowercase o, acute accent + {"ocirc", "244"}, // � - lowercase o, circumflex accent + {"otilde", "245"}, // � - lowercase o, tilde + {"ouml", "246"}, // � - lowercase o, umlaut + {"divide", "247"}, // division sign + {"oslash", "248"}, // � - lowercase o, slash + {"ugrave", "249"}, // � - lowercase u, grave accent + {"uacute", "250"}, // � - lowercase u, acute accent + {"ucirc", "251"}, // � - lowercase u, circumflex accent + {"uuml", "252"}, // � - lowercase u, umlaut + {"yacute", "253"}, // � - lowercase y, acute accent + {"thorn", "254"}, // � - lowercase thorn, Icelandic + {"yuml", "255"}, // � - lowercase y, umlaut + }; + // http://www.w3.org/TR/REC-html40/sgml/entities.html + // package scoped for testing + static final String[][] HTML40_ARRAY = { + // + {"fnof", "402"}, // latin small f with hook = function= florin, U+0192 ISOtech --> + // + {"Alpha", "913"}, // greek capital letter alpha, U+0391 --> + {"Beta", "914"}, // greek capital letter beta, U+0392 --> + {"Gamma", "915"}, // greek capital letter gamma,U+0393 ISOgrk3 --> + {"Delta", "916"}, // greek capital letter delta,U+0394 ISOgrk3 --> + {"Epsilon", "917"}, // greek capital letter epsilon, U+0395 --> + {"Zeta", "918"}, // greek capital letter zeta, U+0396 --> + {"Eta", "919"}, // greek capital letter eta, U+0397 --> + {"Theta", "920"}, // greek capital letter theta,U+0398 ISOgrk3 --> + {"Iota", "921"}, // greek capital letter iota, U+0399 --> + {"Kappa", "922"}, // greek capital letter kappa, U+039A --> + {"Lambda", "923"}, // greek capital letter lambda,U+039B ISOgrk3 --> + {"Mu", "924"}, // greek capital letter mu, U+039C --> + {"Nu", "925"}, // greek capital letter nu, U+039D --> + {"Xi", "926"}, // greek capital letter xi, U+039E ISOgrk3 --> + {"Omicron", "927"}, // greek capital letter omicron, U+039F --> + {"Pi", "928"}, // greek capital letter pi, U+03A0 ISOgrk3 --> + {"Rho", "929"}, // greek capital letter rho, U+03A1 --> + // + {"Sigma", "931"}, // greek capital letter sigma,U+03A3 ISOgrk3 --> + {"Tau", "932"}, // greek capital letter tau, U+03A4 --> + {"Upsilon", "933"}, // greek capital letter upsilon,U+03A5 ISOgrk3 --> + {"Phi", "934"}, // greek capital letter phi,U+03A6 ISOgrk3 --> + {"Chi", "935"}, // greek capital letter chi, U+03A7 --> + {"Psi", "936"}, // greek capital letter psi,U+03A8 ISOgrk3 --> + {"Omega", "937"}, // greek capital letter omega,U+03A9 ISOgrk3 --> + {"alpha", "945"}, // greek small letter alpha,U+03B1 ISOgrk3 --> + {"beta", "946"}, // greek small letter beta, U+03B2 ISOgrk3 --> + {"gamma", "947"}, // greek small letter gamma,U+03B3 ISOgrk3 --> + {"delta", "948"}, // greek small letter delta,U+03B4 ISOgrk3 --> + {"epsilon", "949"}, // greek small letter epsilon,U+03B5 ISOgrk3 --> + {"zeta", "950"}, // greek small letter zeta, U+03B6 ISOgrk3 --> + {"eta", "951"}, // greek small letter eta, U+03B7 ISOgrk3 --> + {"theta", "952"}, // greek small letter theta,U+03B8 ISOgrk3 --> + {"iota", "953"}, // greek small letter iota, U+03B9 ISOgrk3 --> + {"kappa", "954"}, // greek small letter kappa,U+03BA ISOgrk3 --> + {"lambda", "955"}, // greek small letter lambda,U+03BB ISOgrk3 --> + {"mu", "956"}, // greek small letter mu, U+03BC ISOgrk3 --> + {"nu", "957"}, // greek small letter nu, U+03BD ISOgrk3 --> + {"xi", "958"}, // greek small letter xi, U+03BE ISOgrk3 --> + {"omicron", "959"}, // greek small letter omicron, U+03BF NEW --> + {"pi", "960"}, // greek small letter pi, U+03C0 ISOgrk3 --> + {"rho", "961"}, // greek small letter rho, U+03C1 ISOgrk3 --> + {"sigmaf", "962"}, // greek small letter final sigma,U+03C2 ISOgrk3 --> + {"sigma", "963"}, // greek small letter sigma,U+03C3 ISOgrk3 --> + {"tau", "964"}, // greek small letter tau, U+03C4 ISOgrk3 --> + {"upsilon", "965"}, // greek small letter upsilon,U+03C5 ISOgrk3 --> + {"phi", "966"}, // greek small letter phi, U+03C6 ISOgrk3 --> + {"chi", "967"}, // greek small letter chi, U+03C7 ISOgrk3 --> + {"psi", "968"}, // greek small letter psi, U+03C8 ISOgrk3 --> + {"omega", "969"}, // greek small letter omega,U+03C9 ISOgrk3 --> + {"thetasym", "977"}, // greek small letter theta symbol,U+03D1 NEW --> + {"upsih", "978"}, // greek upsilon with hook symbol,U+03D2 NEW --> + {"piv", "982"}, // greek pi symbol, U+03D6 ISOgrk3 --> + // + {"bull", "8226"}, // bullet = black small circle,U+2022 ISOpub --> + // + {"hellip", "8230"}, // horizontal ellipsis = three dot leader,U+2026 ISOpub --> + {"prime", "8242"}, // prime = minutes = feet, U+2032 ISOtech --> + {"Prime", "8243"}, // double prime = seconds = inches,U+2033 ISOtech --> + {"oline", "8254"}, // overline = spacing overscore,U+203E NEW --> + {"frasl", "8260"}, // fraction slash, U+2044 NEW --> + // + {"weierp", "8472"}, // script capital P = power set= Weierstrass p, U+2118 ISOamso --> + {"image", "8465"}, // blackletter capital I = imaginary part,U+2111 ISOamso --> + {"real", "8476"}, // blackletter capital R = real part symbol,U+211C ISOamso --> + {"trade", "8482"}, // trade mark sign, U+2122 ISOnum --> + {"alefsym", "8501"}, // alef symbol = first transfinite cardinal,U+2135 NEW --> + // + // + {"larr", "8592"}, // leftwards arrow, U+2190 ISOnum --> + {"uarr", "8593"}, // upwards arrow, U+2191 ISOnum--> + {"rarr", "8594"}, // rightwards arrow, U+2192 ISOnum --> + {"darr", "8595"}, // downwards arrow, U+2193 ISOnum --> + {"harr", "8596"}, // left right arrow, U+2194 ISOamsa --> + {"crarr", "8629"}, // downwards arrow with corner leftwards= carriage return, U+21B5 NEW --> + {"lArr", "8656"}, // leftwards double arrow, U+21D0 ISOtech --> + // + {"uArr", "8657"}, // upwards double arrow, U+21D1 ISOamsa --> + {"rArr", "8658"}, // rightwards double arrow,U+21D2 ISOtech --> + // + {"dArr", "8659"}, // downwards double arrow, U+21D3 ISOamsa --> + {"hArr", "8660"}, // left right double arrow,U+21D4 ISOamsa --> + // + {"forall", "8704"}, // for all, U+2200 ISOtech --> + {"part", "8706"}, // partial differential, U+2202 ISOtech --> + {"exist", "8707"}, // there exists, U+2203 ISOtech --> + {"empty", "8709"}, // empty set = null set = diameter,U+2205 ISOamso --> + {"nabla", "8711"}, // nabla = backward difference,U+2207 ISOtech --> + {"isin", "8712"}, // element of, U+2208 ISOtech --> + {"notin", "8713"}, // not an element of, U+2209 ISOtech --> + {"ni", "8715"}, // contains as member, U+220B ISOtech --> + // + {"prod", "8719"}, // n-ary product = product sign,U+220F ISOamsb --> + // + {"sum", "8721"}, // n-ary summation, U+2211 ISOamsb --> + // + {"minus", "8722"}, // minus sign, U+2212 ISOtech --> + {"lowast", "8727"}, // asterisk operator, U+2217 ISOtech --> + {"radic", "8730"}, // square root = radical sign,U+221A ISOtech --> + {"prop", "8733"}, // proportional to, U+221D ISOtech --> + {"infin", "8734"}, // infinity, U+221E ISOtech --> + {"ang", "8736"}, // angle, U+2220 ISOamso --> + {"and", "8743"}, // logical and = wedge, U+2227 ISOtech --> + {"or", "8744"}, // logical or = vee, U+2228 ISOtech --> + {"cap", "8745"}, // intersection = cap, U+2229 ISOtech --> + {"cup", "8746"}, // union = cup, U+222A ISOtech --> + {"int", "8747"}, // integral, U+222B ISOtech --> + {"there4", "8756"}, // therefore, U+2234 ISOtech --> + {"sim", "8764"}, // tilde operator = varies with = similar to,U+223C ISOtech --> + // + {"cong", "8773"}, // approximately equal to, U+2245 ISOtech --> + {"asymp", "8776"}, // almost equal to = asymptotic to,U+2248 ISOamsr --> + {"ne", "8800"}, // not equal to, U+2260 ISOtech --> + {"equiv", "8801"}, // identical to, U+2261 ISOtech --> + {"le", "8804"}, // less-than or equal to, U+2264 ISOtech --> + {"ge", "8805"}, // greater-than or equal to,U+2265 ISOtech --> + {"sub", "8834"}, // subset of, U+2282 ISOtech --> + {"sup", "8835"}, // superset of, U+2283 ISOtech --> + // + {"sube", "8838"}, // subset of or equal to, U+2286 ISOtech --> + {"supe", "8839"}, // superset of or equal to,U+2287 ISOtech --> + {"oplus", "8853"}, // circled plus = direct sum,U+2295 ISOamsb --> + {"otimes", "8855"}, // circled times = vector product,U+2297 ISOamsb --> + {"perp", "8869"}, // up tack = orthogonal to = perpendicular,U+22A5 ISOtech --> + {"sdot", "8901"}, // dot operator, U+22C5 ISOamsb --> + // + // + {"lceil", "8968"}, // left ceiling = apl upstile,U+2308 ISOamsc --> + {"rceil", "8969"}, // right ceiling, U+2309 ISOamsc --> + {"lfloor", "8970"}, // left floor = apl downstile,U+230A ISOamsc --> + {"rfloor", "8971"}, // right floor, U+230B ISOamsc --> + {"lang", "9001"}, // left-pointing angle bracket = bra,U+2329 ISOtech --> + // + {"rang", "9002"}, // right-pointing angle bracket = ket,U+232A ISOtech --> + // + // + {"loz", "9674"}, // lozenge, U+25CA ISOpub --> + // + {"spades", "9824"}, // black spade suit, U+2660 ISOpub --> + // + {"clubs", "9827"}, // black club suit = shamrock,U+2663 ISOpub --> + {"hearts", "9829"}, // black heart suit = valentine,U+2665 ISOpub --> + {"diams", "9830"}, // black diamond suit, U+2666 ISOpub --> + + // + {"OElig", "338"}, // -- latin capital ligature OE,U+0152 ISOlat2 --> + {"oelig", "339"}, // -- latin small ligature oe, U+0153 ISOlat2 --> + // + {"Scaron", "352"}, // -- latin capital letter S with caron,U+0160 ISOlat2 --> + {"scaron", "353"}, // -- latin small letter s with caron,U+0161 ISOlat2 --> + {"Yuml", "376"}, // -- latin capital letter Y with diaeresis,U+0178 ISOlat2 --> + // + {"circ", "710"}, // -- modifier letter circumflex accent,U+02C6 ISOpub --> + {"tilde", "732"}, // small tilde, U+02DC ISOdia --> + // + {"ensp", "8194"}, // en space, U+2002 ISOpub --> + {"emsp", "8195"}, // em space, U+2003 ISOpub --> + {"thinsp", "8201"}, // thin space, U+2009 ISOpub --> + {"zwnj", "8204"}, // zero width non-joiner,U+200C NEW RFC 2070 --> + {"zwj", "8205"}, // zero width joiner, U+200D NEW RFC 2070 --> + {"lrm", "8206"}, // left-to-right mark, U+200E NEW RFC 2070 --> + {"rlm", "8207"}, // right-to-left mark, U+200F NEW RFC 2070 --> + {"ndash", "8211"}, // en dash, U+2013 ISOpub --> + {"mdash", "8212"}, // em dash, U+2014 ISOpub --> + {"lsquo", "8216"}, // left single quotation mark,U+2018 ISOnum --> + {"rsquo", "8217"}, // right single quotation mark,U+2019 ISOnum --> + {"sbquo", "8218"}, // single low-9 quotation mark, U+201A NEW --> + {"ldquo", "8220"}, // left double quotation mark,U+201C ISOnum --> + {"rdquo", "8221"}, // right double quotation mark,U+201D ISOnum --> + {"bdquo", "8222"}, // double low-9 quotation mark, U+201E NEW --> + {"dagger", "8224"}, // dagger, U+2020 ISOpub --> + {"Dagger", "8225"}, // double dagger, U+2021 ISOpub --> + {"permil", "8240"}, // per mille sign, U+2030 ISOtech --> + {"lsaquo", "8249"}, // single left-pointing angle quotation mark,U+2039 ISO proposed --> + // + {"rsaquo", "8250"}, // single right-pointing angle quotation mark,U+203A ISO proposed --> + // + {"euro", "8364"}, // -- euro sign, U+20AC NEW --> + }; + private static final String[][] BASIC_ARRAY = {{"quot", "34"}, // " - double-quote + {"amp", "38"}, // & - ampersand + {"lt", "60"}, // < - less-than + {"gt", "62"}, // > - greater-than + }; + private static final String[][] APOS_ARRAY = {{"apos", "39"}, // XML apostrophe + }; + + static { + XML = new Entities(); + XML.addEntities(BASIC_ARRAY); + XML.addEntities(APOS_ARRAY); + } + + static { + HTML32 = new Entities(); + HTML32.addEntities(BASIC_ARRAY); + HTML32.addEntities(ISO8859_1_ARRAY); + } + + static { + HTML40 = new Entities(); + fillWithHtml40Entities(HTML40); + } + + // package scoped for testing + EntityMap map = new Entities.LookupEntityMap(); + + /** + *

+ * Fills the specified entities instance with HTML 40 entities. + *

+ * + * @param entities the instance to be filled. + */ + static void fillWithHtml40Entities(Entities entities) { + entities.addEntities(BASIC_ARRAY); + entities.addEntities(ISO8859_1_ARRAY); + entities.addEntities(HTML40_ARRAY); + } + + /** + *

+ * Adds entities to this entity. + *

+ * + * @param entityArray array of entities to be added + */ + public void addEntities(String[][] entityArray) { + for (int i = 0; i < entityArray.length; ++i) { + addEntity(entityArray[i][0], Integer.parseInt(entityArray[i][1])); + } + } + + /** + *

+ * Add an entity to this entity. + *

+ * + * @param name name of the entity + * @param value vale of the entity + */ + public void addEntity(String name, int value) { + map.add(name, value); + } + + /** + *

+ * Returns the name of the entity identified by the specified value. + *

+ * + * @param value the value to locate + * @return entity name associated with the specified value + */ + public String entityName(int value) { + return map.name(value); + } + + /** + *

+ * Returns the value of the entity identified by the specified name. + *

+ * + * @param name the name to locate + * @return entity value associated with the specified name + */ + public int entityValue(String name) { + return map.value(name); + } + + /** + *

+ * Escapes the characters in a String. + *

+ *

+ *

+ * For example, if you have called addEntity("foo", 0xA1), escape("\u00A1") will return + * "&foo;" + *

+ * + * @param str The String to escape. + * @return A new escaped String. + */ + public String escape(String str) { + StringWriter stringWriter = createStringWriter(str); + try { + this.escape(stringWriter, str); + } catch (IOException e) { + // This should never happen because ALL the StringWriter methods called by #escape(Writer, String) do not + // throw IOExceptions. + throw new IllegalStateException(e); + } + return stringWriter.toString(); + } + + /** + *

+ * Escapes the characters in the String passed and writes the result to the Writer + * passed. + *

+ * + * @param writer The Writer to write the results of the escaping to. Assumed to be a non-null value. + * @param str The String to escape. Assumed to be a non-null value. + * @throws IOException when Writer passed throws the exception from calls to the {@link Writer#write(int)} + * methods. + * @see #escape(String) + * @see Writer + */ + public void escape(Writer writer, String str) throws IOException { + int len = str.length(); + for (int i = 0; i < len; i++) { + char c = str.charAt(i); + String entityName = this.entityName(c); + if (entityName == null) { + if (c > 0x7F) { + writer.write("&#"); + writer.write(Integer.toString(c, 10)); + writer.write(';'); + } else { + writer.write(c); + } + } else { + writer.write('&'); + writer.write(entityName); + writer.write(';'); + } + } + } + + /** + *

+ * Unescapes the entities in a String. + *

+ *

+ *

+ * For example, if you have called addEntity("foo", 0xA1), unescape("&foo;") will return + * "\u00A1" + *

+ * + * @param str The String to escape. + * @return A new escaped String. + */ + public String unescape(String str) { + int firstAmp = str.indexOf('&'); + if (firstAmp < 0) { + return str; + } else { + StringWriter stringWriter = createStringWriter(str); + try { + this.doUnescape(stringWriter, str, firstAmp); + } catch (IOException e) { + // This should never happen because ALL the StringWriter methods called by #escape(Writer, String) + // do not throw IOExceptions. + throw new IllegalStateException(e); + } + return stringWriter.toString(); + } + } + + /** + * Make the StringWriter 10% larger than the source String to avoid growing the writer + * + * @param str The source string + * @return A newly created StringWriter + */ + private StringWriter createStringWriter(String str) { + return new StringWriter((int) (str.length() + (str.length() * 0.1))); + } + + /** + *

+ * Unescapes the escaped entities in the String passed and writes the result to the + * Writer passed. + *

+ * + * @param writer The Writer to write the results to; assumed to be non-null. + * @param str The source String to unescape; assumed to be non-null. + * @throws IOException when Writer passed throws the exception from calls to the {@link Writer#write(int)} + * methods. + * @see #escape(String) + * @see Writer + */ + public void unescape(Writer writer, String str) throws IOException { + int firstAmp = str.indexOf('&'); + if (firstAmp < 0) { + writer.write(str); + return; + } else { + doUnescape(writer, str, firstAmp); + } + } + + /** + * Underlying unescape method that allows the optimisation of not starting from the 0 index again. + * + * @param writer The Writer to write the results to; assumed to be non-null. + * @param str The source String to unescape; assumed to be non-null. + * @param firstAmp The int index of the first ampersand in the source String. + * @throws IOException when Writer passed throws the exception from calls to the {@link Writer#write(int)} + * methods. + */ + private void doUnescape(Writer writer, String str, int firstAmp) throws IOException { + writer.write(str, 0, firstAmp); + int len = str.length(); + for (int i = firstAmp; i < len; i++) { + char c = str.charAt(i); + if (c == '&') { + int nextIdx = i + 1; + int semiColonIdx = str.indexOf(';', nextIdx); + if (semiColonIdx == -1) { + writer.write(c); + continue; + } + int amphersandIdx = str.indexOf('&', i + 1); + if (amphersandIdx != -1 && amphersandIdx < semiColonIdx) { + // Then the text looks like &...&...; + writer.write(c); + continue; + } + String entityContent = str.substring(nextIdx, semiColonIdx); + int entityValue = -1; + int entityContentLen = entityContent.length(); + if (entityContentLen > 0) { + if (entityContent.charAt(0) == '#') { // escaped value content is an integer (decimal or + // hexidecimal) + if (entityContentLen > 1) { + char isHexChar = entityContent.charAt(1); + try { + switch (isHexChar) { + case 'X': + case 'x': { + entityValue = Integer.parseInt(entityContent.substring(2), 16); + break; + } + default: { + entityValue = Integer.parseInt(entityContent.substring(1), 10); + } + } + if (entityValue > 0xFFFF) { + entityValue = -1; + } + } catch (NumberFormatException e) { + entityValue = -1; + } + } + } else { // escaped value content is an entity name + entityValue = this.entityValue(entityContent); + } + } + + if (entityValue == -1) { + writer.write('&'); + writer.write(entityContent); + writer.write(';'); + } else { + writer.write(entityValue); + } + i = semiColonIdx; // move index up to the semi-colon + } else { + writer.write(c); + } + } + } + + static interface EntityMap { + /** + *

+ * Add an entry to this entity map. + *

+ * + * @param name the entity name + * @param value the entity value + */ + void add(String name, int value); + + /** + *

+ * Returns the name of the entity identified by the specified value. + *

+ * + * @param value the value to locate + * @return entity name associated with the specified value + */ + String name(int value); + + /** + *

+ * Returns the value of the entity identified by the specified name. + *

+ * + * @param name the name to locate + * @return entity value associated with the specified name + */ + int value(String name); + } + + static class PrimitiveEntityMap implements EntityMap { + private Map mapNameToValue = new HashMap(); + + private IntHashMap mapValueToName = new IntHashMap(); + + /** + * {@inheritDoc} + */ + public void add(String name, int value) { + mapNameToValue.put(name, Integer.valueOf(value)); + mapValueToName.put(value, name); + } + + /** + * {@inheritDoc} + */ + public String name(int value) { + return (String) mapValueToName.get(value); + } + + /** + * {@inheritDoc} + */ + public int value(String name) { + Object value = mapNameToValue.get(name); + if (value == null) { + return -1; + } + return ((Integer) value).intValue(); + } + } + + static abstract class MapIntMap implements Entities.EntityMap { + protected Map mapNameToValue; + + protected Map mapValueToName; + + /** + * {@inheritDoc} + */ + public void add(String name, int value) { + mapNameToValue.put(name, Integer.valueOf(value)); + mapValueToName.put(Integer.valueOf(value), name); + } + + /** + * {@inheritDoc} + */ + public String name(int value) { + return (String) mapValueToName.get(Integer.valueOf(value)); + } + + /** + * {@inheritDoc} + */ + public int value(String name) { + Object value = mapNameToValue.get(name); + if (value == null) { + return -1; + } + return ((Integer) value).intValue(); + } + } + + static class HashEntityMap extends MapIntMap { + /** + * Constructs a new instance of HashEntityMap. + */ + public HashEntityMap() { + mapNameToValue = new HashMap(); + mapValueToName = new HashMap(); + } + } + + static class TreeEntityMap extends MapIntMap { + /** + * Constructs a new instance of TreeEntityMap. + */ + public TreeEntityMap() { + mapNameToValue = new TreeMap(); + mapValueToName = new TreeMap(); + } + } + + static class LookupEntityMap extends PrimitiveEntityMap { + private String[] lookupTable; + + private int LOOKUP_TABLE_SIZE = 256; + + /** + * {@inheritDoc} + */ + public String name(int value) { + if (value < LOOKUP_TABLE_SIZE) { + return lookupTable()[value]; + } + return super.name(value); + } + + /** + *

+ * Returns the lookup table for this entity map. The lookup table is created if it has not been previously. + *

+ * + * @return the lookup table + */ + private String[] lookupTable() { + if (lookupTable == null) { + createLookupTable(); + } + return lookupTable; + } + + /** + *

+ * Creates an entity lookup table of LOOKUP_TABLE_SIZE elements, initialized with entity names. + *

+ */ + private void createLookupTable() { + lookupTable = new String[LOOKUP_TABLE_SIZE]; + for (int i = 0; i < LOOKUP_TABLE_SIZE; ++i) { + lookupTable[i] = super.name(i); + } + } + } + + static class ArrayEntityMap implements EntityMap { + protected int growBy = 100; + + protected int size = 0; + + protected String[] names; + + protected int[] values; + + /** + * Constructs a new instance of ArrayEntityMap. + */ + public ArrayEntityMap() { + names = new String[growBy]; + values = new int[growBy]; + } + + /** + * Constructs a new instance of ArrayEntityMap specifying the size by which the array should + * grow. + * + * @param growBy array will be initialized to and will grow by this amount + */ + public ArrayEntityMap(int growBy) { + this.growBy = growBy; + names = new String[growBy]; + values = new int[growBy]; + } + + /** + * {@inheritDoc} + */ + public void add(String name, int value) { + ensureCapacity(size + 1); + names[size] = name; + values[size] = value; + size++; + } + + /** + * Verifies the capacity of the entity array, adjusting the size if necessary. + * + * @param capacity size the array should be + */ + protected void ensureCapacity(int capacity) { + if (capacity > names.length) { + int newSize = Math.max(capacity, size + growBy); + String[] newNames = new String[newSize]; + System.arraycopy(names, 0, newNames, 0, size); + names = newNames; + int[] newValues = new int[newSize]; + System.arraycopy(values, 0, newValues, 0, size); + values = newValues; + } + } + + /** + * {@inheritDoc} + */ + public String name(int value) { + for (int i = 0; i < size; ++i) { + if (values[i] == value) { + return names[i]; + } + } + return null; + } + + /** + * {@inheritDoc} + */ + public int value(String name) { + for (int i = 0; i < size; ++i) { + if (names[i].equals(name)) { + return values[i]; + } + } + return -1; + } + } + + static class BinaryEntityMap extends ArrayEntityMap { + + /** + * Constructs a new instance of BinaryEntityMap. + */ + public BinaryEntityMap() { + super(); + } + + /** + * Constructs a new instance of ArrayEntityMap specifying the size by which the underlying array + * should grow. + * + * @param growBy array will be initialized to and will grow by this amount + */ + public BinaryEntityMap(int growBy) { + super(growBy); + } + + /** + * Performs a binary search of the entity array for the specified key. This method is based on code in + * {@link java.util.Arrays}. + * + * @param key the key to be found + * @return the index of the entity array matching the specified key + */ + private int binarySearch(int key) { + int low = 0; + int high = size - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + int midVal = values[mid]; + + if (midVal < key) { + low = mid + 1; + } else if (midVal > key) { + high = mid - 1; + } else { + return mid; // key found + } + } + return -(low + 1); // key not found. + } + + /** + * {@inheritDoc} + */ + public void add(String name, int value) { + ensureCapacity(size + 1); + int insertAt = binarySearch(value); + if (insertAt > 0) { + return; // note: this means you can't insert the same value twice + } + insertAt = -(insertAt + 1); // binarySearch returns it negative and off-by-one + System.arraycopy(values, insertAt, values, insertAt + 1, size - insertAt); + values[insertAt] = value; + System.arraycopy(names, insertAt, names, insertAt + 1, size - insertAt); + names[insertAt] = name; + size++; + } + + /** + * {@inheritDoc} + */ + public String name(int value) { + int index = binarySearch(value); + if (index < 0) { + return null; + } + return names[index]; + } + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/IntHashMap.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/IntHashMap.java new file mode 100644 index 0000000..4713cb8 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/IntHashMap.java @@ -0,0 +1,357 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.dubboadmin.registry.common.util; + +/** + *

A hash map that uses primitive ints for the key rather than objects.

+ *

+ *

Note that this class is for internal optimization purposes only, and may + * not be supported in future releases of Apache Commons Lang. Utilities of + * this sort may be included in future releases of Apache Commons Collections.

+ * + * @version $Revision: 181192 $ + * @see java.util.HashMap + * @since 2.0 + */ +class IntHashMap { + + /** + * The hash table data. + */ + private transient Entry table[]; + + /** + * The total number of entries in the hash table. + */ + private transient int count; + + /** + * The table is rehashed when its size exceeds this threshold. (The + * value of this field is (int)(capacity * loadFactor).) + * + * @serial + */ + private int threshold; + + /** + * The load factor for the hashtable. + * + * @serial + */ + private float loadFactor; + + /** + *

Constructs a new, empty hashtable with a default capacity and load + * factor, which is 20 and 0.75 respectively.

+ */ + public IntHashMap() { + this(20, 0.75f); + } + + /** + *

Constructs a new, empty hashtable with the specified initial capacity + * and default load factor, which is 0.75.

+ * + * @param initialCapacity the initial capacity of the hashtable. + * @throws IllegalArgumentException if the initial capacity is less + * than zero. + */ + public IntHashMap(int initialCapacity) { + this(initialCapacity, 0.75f); + } + + /** + *

Constructs a new, empty hashtable with the specified initial + * capacity and the specified load factor.

+ * + * @param initialCapacity the initial capacity of the hashtable. + * @param loadFactor the load factor of the hashtable. + * @throws IllegalArgumentException if the initial capacity is less + * than zero, or if the load factor is nonpositive. + */ + public IntHashMap(int initialCapacity, float loadFactor) { + super(); + if (initialCapacity < 0) { + throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); + } + if (loadFactor <= 0) { + throw new IllegalArgumentException("Illegal Load: " + loadFactor); + } + if (initialCapacity == 0) { + initialCapacity = 1; + } + + this.loadFactor = loadFactor; + table = new Entry[initialCapacity]; + threshold = (int) (initialCapacity * loadFactor); + } + + /** + *

Returns the number of keys in this hashtable.

+ * + * @return the number of keys in this hashtable. + */ + public int size() { + return count; + } + + /** + *

Tests if this hashtable maps no keys to values.

+ * + * @return true if this hashtable maps no keys to values; + * false otherwise. + */ + public boolean isEmpty() { + return count == 0; + } + + /** + *

Tests if some key maps into the specified value in this hashtable. + * This operation is more expensive than the containsKey + * method.

+ *

+ *

Note that this method is identical in functionality to containsValue, + * (which is part of the Map interface in the collections framework).

+ * + * @param value a value to search for. + * @return true if and only if some key maps to the + * value argument in this hashtable as + * determined by the equals method; + * false otherwise. + * @throws NullPointerException if the value is null. + * @see #containsKey(int) + * @see #containsValue(Object) + * @see java.util.Map + */ + public boolean contains(Object value) { + if (value == null) { + throw new NullPointerException(); + } + + Entry tab[] = table; + for (int i = tab.length; i-- > 0; ) { + for (Entry e = tab[i]; e != null; e = e.next) { + if (e.value.equals(value)) { + return true; + } + } + } + return false; + } + + /** + *

Returns true if this HashMap maps one or more keys + * to this value.

+ *

+ *

Note that this method is identical in functionality to contains + * (which predates the Map interface).

+ * + * @param value value whose presence in this HashMap is to be tested. + * @return boolean true if the value is contained + * @see java.util.Map + * @since JDK1.2 + */ + public boolean containsValue(Object value) { + return contains(value); + } + + /** + *

Tests if the specified object is a key in this hashtable.

+ * + * @param key possible key. + * @return true if and only if the specified object is a + * key in this hashtable, as determined by the equals + * method; false otherwise. + * @see #contains(Object) + */ + public boolean containsKey(int key) { + Entry tab[] = table; + int hash = key; + int index = (hash & 0x7FFFFFFF) % tab.length; + for (Entry e = tab[index]; e != null; e = e.next) { + if (e.hash == hash) { + return true; + } + } + return false; + } + + /** + *

Returns the value to which the specified key is mapped in this map.

+ * + * @param key a key in the hashtable. + * @return the value to which the key is mapped in this hashtable; + * null if the key is not mapped to any value in + * this hashtable. + * @see #put(int, Object) + */ + public Object get(int key) { + Entry tab[] = table; + int hash = key; + int index = (hash & 0x7FFFFFFF) % tab.length; + for (Entry e = tab[index]; e != null; e = e.next) { + if (e.hash == hash) { + return e.value; + } + } + return null; + } + + /** + *

Increases the capacity of and internally reorganizes this + * hashtable, in order to accommodate and access its entries more + * efficiently.

+ *

+ *

This method is called automatically when the number of keys + * in the hashtable exceeds this hashtable's capacity and load + * factor.

+ */ + protected void rehash() { + int oldCapacity = table.length; + Entry oldMap[] = table; + + int newCapacity = oldCapacity * 2 + 1; + Entry newMap[] = new Entry[newCapacity]; + + threshold = (int) (newCapacity * loadFactor); + table = newMap; + + for (int i = oldCapacity; i-- > 0; ) { + for (Entry old = oldMap[i]; old != null; ) { + Entry e = old; + old = old.next; + + int index = (e.hash & 0x7FFFFFFF) % newCapacity; + e.next = newMap[index]; + newMap[index] = e; + } + } + } + + /** + *

Maps the specified key to the specified + * value in this hashtable. The key cannot be + * null.

+ *

+ *

The value can be retrieved by calling the get method + * with a key that is equal to the original key.

+ * + * @param key the hashtable key. + * @param value the value. + * @return the previous value of the specified key in this hashtable, + * or null if it did not have one. + * @throws NullPointerException if the key is null. + * @see #get(int) + */ + public Object put(int key, Object value) { + // Makes sure the key is not already in the hashtable. + Entry tab[] = table; + int hash = key; + int index = (hash & 0x7FFFFFFF) % tab.length; + for (Entry e = tab[index]; e != null; e = e.next) { + if (e.hash == hash) { + Object old = e.value; + e.value = value; + return old; + } + } + + if (count >= threshold) { + // Rehash the table if the threshold is exceeded + rehash(); + + tab = table; + index = (hash & 0x7FFFFFFF) % tab.length; + } + + // Creates the new entry. + Entry e = new Entry(hash, key, value, tab[index]); + tab[index] = e; + count++; + return null; + } + + /** + *

Removes the key (and its corresponding value) from this + * hashtable.

+ *

+ *

This method does nothing if the key is not present in the + * hashtable.

+ * + * @param key the key that needs to be removed. + * @return the value to which the key had been mapped in this hashtable, + * or null if the key did not have a mapping. + */ + public Object remove(int key) { + Entry tab[] = table; + int hash = key; + int index = (hash & 0x7FFFFFFF) % tab.length; + for (Entry e = tab[index], prev = null; e != null; prev = e, e = e.next) { + if (e.hash == hash) { + if (prev != null) { + prev.next = e.next; + } else { + tab[index] = e.next; + } + count--; + Object oldValue = e.value; + e.value = null; + return oldValue; + } + } + return null; + } + + /** + *

Clears this hashtable so that it contains no keys.

+ */ + public synchronized void clear() { + Entry tab[] = table; + for (int index = tab.length; --index >= 0; ) { + tab[index] = null; + } + count = 0; + } + + /** + *

Innerclass that acts as a datastructure to create a new entry in the + * table.

+ */ + private static class Entry { + int hash; + int key; + Object value; + Entry next; + + /** + *

Create a new entry with the given values.

+ * + * @param hash The code used to hash the object with + * @param key The key used to enter this in the table + * @param value The value for this key + * @param next A reference to the next entry in the table + */ + protected Entry(int hash, int key, Object value, Entry next) { + this.hash = hash; + this.key = key; + this.value = value; + this.next = next; + } + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/LocaleUtils.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/LocaleUtils.java new file mode 100644 index 0000000..58a29c1 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/LocaleUtils.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.dubboadmin.registry.common.util; + +import java.util.Locale; + +public class LocaleUtils { + + private LocaleUtils() { + } + + public static Locale getLocale(String language) { + if ("en".equalsIgnoreCase(language)) { + return Locale.ENGLISH; + } else if ("zh".equalsIgnoreCase(language)) { + return Locale.SIMPLIFIED_CHINESE; + } else if ("zh_TW".equalsIgnoreCase(language)) { + return Locale.TRADITIONAL_CHINESE; + } + return Locale.getDefault(); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/MessageSource.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/MessageSource.java new file mode 100644 index 0000000..3613abb --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/MessageSource.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.util; + +import java.text.MessageFormat; +import java.util.ResourceBundle; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; + +/** + * MessageSource + * + */ +public class MessageSource { + + private static final Logger logger = LoggerFactory.getLogger(MessageSource.class); + + private final ResourceBundle resourceBundle; + + private final String errorPrefix; + + public MessageSource(ResourceBundle resourceBundle) { + this(resourceBundle, null); + } + + public MessageSource(ResourceBundle resourceBundle, String errorPrefix) { + this.resourceBundle = resourceBundle; + this.errorPrefix = errorPrefix == null ? "" : errorPrefix + " "; + } + + public String getString(String key) { + try { + return resourceBundle.getString(key); + } catch (Throwable t) { + logger.warn(errorPrefix + t.getMessage(), t); + return key; + } + } + + public String getString(String key, Object... args) { + try { + return new MessageFormat(resourceBundle.getString(key)).format(args); + } catch (Throwable t) { + logger.warn(errorPrefix + t.getMessage(), t); + return key; + } + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/OverrideUtils.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/OverrideUtils.java new file mode 100644 index 0000000..3c20cae --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/OverrideUtils.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.registry.common.domain.LoadBalance; +import com.alibaba.dubboadmin.registry.common.domain.Override; +import com.alibaba.dubboadmin.registry.common.domain.Weight; + +/** + * OverrideUtils.java + * + */ +public class OverrideUtils { + public static List overridesToWeights(List overrides) { + List weights = new ArrayList(); + if (overrides == null) { + return weights; + } + for (Override o : overrides) { + if (StringUtils.isEmpty(o.getParams())) { + continue; + } else { + Map params = StringUtils.parseQueryString(o.getParams()); + for (Map.Entry entry : params.entrySet()) { + if (entry.getKey().equals("weight")) { + Weight weight = new Weight(); + weight.setAddress(o.getAddress()); + weight.setId(o.getId()); + weight.setService(o.getService()); + weight.setWeight(Integer.valueOf(entry.getValue())); + weights.add(weight); + } + } + } + } + return weights; + } + + public static Weight overrideToWeight(Override override) { + return overridesToWeights(Arrays.asList(override)).get(0); + } + + public static Override weightToOverride(Weight weight) { + Override override = new Override(); + override.setId(weight.getId()); + override.setAddress(weight.getAddress()); + override.setEnabled(true); + override.setParams("weight=" + weight.getWeight()); + override.setService(weight.getService()); + return override; + } + + public static List overridesToLoadBalances(List overrides) { + List loadBalances = new ArrayList(); + if (overrides == null) { + return loadBalances; + } + for (Override o : overrides) { + if (StringUtils.isEmpty(o.getParams())) { + continue; + } else { + Map params = StringUtils.parseQueryString(o.getParams()); + for (Map.Entry entry : params.entrySet()) { + if (entry.getKey().endsWith("loadbalance")) { + LoadBalance loadBalance = new LoadBalance(); + String method = null; + if (entry.getKey().endsWith(".loadbalance")) { + method = entry.getKey().split(".loadbalance")[0]; + } else { + method = "*"; + } + + loadBalance.setMethod(method); + loadBalance.setId(o.getId()); + loadBalance.setService(o.getService()); + loadBalance.setStrategy(entry.getValue()); + loadBalances.add(loadBalance); + + } + } + } + } + return loadBalances; + } + + public static LoadBalance overrideToLoadBalance(Override override) { + return OverrideUtils.overridesToLoadBalances(Arrays.asList(override)).get(0); + } + + public static Override loadBalanceToOverride(LoadBalance loadBalance) { + Override override = new Override(); + override.setId(loadBalance.getId()); + override.setService(loadBalance.getService()); + override.setEnabled(true); + String method = loadBalance.getMethod(); + String strategy = loadBalance.getStrategy(); + if (StringUtils.isEmpty(method) || method.equals("*")) { + override.setParams("loadbalance=" + strategy); + } else { + override.setParams(method + ".loadbalance=" + strategy); + } + return override; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/StringEscapeUtils.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/StringEscapeUtils.java new file mode 100644 index 0000000..32419a9 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/StringEscapeUtils.java @@ -0,0 +1,661 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.util; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; + +/** + *

Escapes and unescapes Strings for + * Java, Java Script, HTML, XML, and SQL.

+ * + * @version $Id: StringEscapeUtils.java 181192 2012-06-21 05:05:47Z tony.chenl $ + * @since 2.0 + */ +public class StringEscapeUtils { + + private static final char CSV_DELIMITER = ','; + private static final char CSV_QUOTE = '"'; + private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE); + private static final char[] CSV_SEARCH_CHARS = new char[]{CSV_DELIMITER, CSV_QUOTE, '\r', '\n'}; + + /** + *

StringEscapeUtils instances should NOT be constructed in + * standard programming.

+ *

+ *

Instead, the class should be used as: + *

StringEscapeUtils.escapeJava("foo");

+ * + *

This constructor is public to permit tools that require a JavaBean + * instance to operate.

+ */ + public StringEscapeUtils() { + super(); + } + + // Java and JavaScript + //-------------------------------------------------------------------------- + + /** + *

Escapes the characters in a String using Java String rules.

+ *

+ *

Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.)

+ *

+ *

So a tab becomes the characters '\\' and + * 't'.

+ *

+ *

The only difference between Java strings and JavaScript strings + * is that in JavaScript, a single quote must be escaped.

+ *

+ *

Example: + *

+     * input string: He didn't say, "Stop!"
+     * output string: He didn't say, \"Stop!\"
+     * 
+ *

+ * + * @param str String to escape values in, may be null + * @return String with escaped values, null if null string input + */ + public static String escapeJava(String str) { + return escapeJavaStyleString(str, false); + } + + /** + *

Escapes the characters in a String using Java String rules to + * a Writer.

+ *

+ *

A null string input has no effect.

+ * + * @param out Writer to write escaped string into + * @param str String to escape values in, may be null + * @throws IllegalArgumentException if the Writer is null + * @throws IOException if error occurs on underlying Writer + * @see #escapeJava(java.lang.String) + */ + public static void escapeJava(Writer out, String str) throws IOException { + escapeJavaStyleString(out, str, false); + } + + /** + *

Escapes the characters in a String using JavaScript String rules.

+ *

Escapes any values it finds into their JavaScript String form. + * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.)

+ *

+ *

So a tab becomes the characters '\\' and + * 't'.

+ *

+ *

The only difference between Java strings and JavaScript strings + * is that in JavaScript, a single quote must be escaped.

+ *

+ *

Example: + *

+     * input string: He didn't say, "Stop!"
+     * output string: He didn\'t say, \"Stop!\"
+     * 
+ *

+ * + * @param str String to escape values in, may be null + * @return String with escaped values, null if null string input + */ + public static String escapeJavaScript(String str) { + return escapeJavaStyleString(str, true); + } + + /** + *

Escapes the characters in a String using JavaScript String rules + * to a Writer.

+ *

+ *

A null string input has no effect.

+ * + * @param out Writer to write escaped string into + * @param str String to escape values in, may be null + * @throws IllegalArgumentException if the Writer is null + * @throws IOException if error occurs on underlying Writer + * @see #escapeJavaScript(java.lang.String) + **/ + public static void escapeJavaScript(Writer out, String str) throws IOException { + escapeJavaStyleString(out, str, true); + } + + /** + *

Worker method for the {@link #escapeJavaScript(String)} method.

+ * + * @param str String to escape values in, may be null + * @param escapeSingleQuotes escapes single quotes if true + * @return the escaped string + */ + private static String escapeJavaStyleString(String str, boolean escapeSingleQuotes) { + if (str == null) { + return null; + } + try { + StringWriter writer = new StringWriter(str.length() * 2); + escapeJavaStyleString(writer, str, escapeSingleQuotes); + return writer.toString(); + } catch (IOException ioe) { + // this should never ever happen while writing to a StringWriter + ioe.printStackTrace(); + return null; + } + } + + /** + *

Worker method for the {@link #escapeJavaScript(String)} method.

+ * + * @param out write to receieve the escaped string + * @param str String to escape values in, may be null + * @param escapeSingleQuote escapes single quotes if true + * @throws IOException if an IOException occurs + */ + private static void escapeJavaStyleString(Writer out, String str, boolean escapeSingleQuote) throws IOException { + if (out == null) { + throw new IllegalArgumentException("The Writer must not be null"); + } + if (str == null) { + return; + } + int sz; + sz = str.length(); + for (int i = 0; i < sz; i++) { + char ch = str.charAt(i); + + // handle unicode + if (ch > 0xfff) { + out.write("\\u" + hex(ch)); + } else if (ch > 0xff) { + out.write("\\u0" + hex(ch)); + } else if (ch > 0x7f) { + out.write("\\u00" + hex(ch)); + } else if (ch < 32) { + switch (ch) { + case '\b': + out.write('\\'); + out.write('b'); + break; + case '\n': + out.write('\\'); + out.write('n'); + break; + case '\t': + out.write('\\'); + out.write('t'); + break; + case '\f': + out.write('\\'); + out.write('f'); + break; + case '\r': + out.write('\\'); + out.write('r'); + break; + default: + if (ch > 0xf) { + out.write("\\u00" + hex(ch)); + } else { + out.write("\\u000" + hex(ch)); + } + break; + } + } else { + switch (ch) { + case '\'': + if (escapeSingleQuote) { + out.write('\\'); + } + out.write('\''); + break; + case '"': + out.write('\\'); + out.write('"'); + break; + case '\\': + out.write('\\'); + out.write('\\'); + break; + case '/': + out.write('\\'); + out.write('/'); + break; + default: + out.write(ch); + break; + } + } + } + } + + /** + *

Returns an upper case hexadecimal String for the given + * character.

+ * + * @param ch The character to convert. + * @return An upper case hexadecimal String + */ + private static String hex(char ch) { + return Integer.toHexString(ch).toUpperCase(); + } + + /** + *

Unescapes any Java literals found in the String. + * For example, it will turn a sequence of '\' and + * 'n' into a newline character, unless the '\' + * is preceded by another '\'.

+ * + * @param str the String to unescape, may be null + * @return a new unescaped String, null if null string input + */ + public static String unescapeJava(String str) { + if (str == null) { + return null; + } + try { + StringWriter writer = new StringWriter(str.length()); + unescapeJava(writer, str); + return writer.toString(); + } catch (IOException ioe) { + // this should never ever happen while writing to a StringWriter + ioe.printStackTrace(); + return null; + } + } + + /** + *

Unescapes any Java literals found in the String to a + * Writer.

+ *

+ *

For example, it will turn a sequence of '\' and + * 'n' into a newline character, unless the '\' + * is preceded by another '\'.

+ *

+ *

A null string input has no effect.

+ * + * @param out the Writer used to output unescaped characters + * @param str the String to unescape, may be null + * @throws IllegalArgumentException if the Writer is null + * @throws IOException if error occurs on underlying Writer + */ + public static void unescapeJava(Writer out, String str) throws IOException { + if (out == null) { + throw new IllegalArgumentException("The Writer must not be null"); + } + if (str == null) { + return; + } + int sz = str.length(); + StringBuffer unicode = new StringBuffer(4); + boolean hadSlash = false; + boolean inUnicode = false; + for (int i = 0; i < sz; i++) { + char ch = str.charAt(i); + if (inUnicode) { + // if in unicode, then we're reading unicode + // values in somehow + unicode.append(ch); + if (unicode.length() == 4) { + // unicode now contains the four hex digits + // which represents our unicode character + try { + int value = Integer.parseInt(unicode.toString(), 16); + out.write((char) value); + unicode.setLength(0); + inUnicode = false; + hadSlash = false; + } catch (NumberFormatException nfe) { + throw new RuntimeException("Unable to parse unicode value: " + unicode, nfe); + } + } + continue; + } + if (hadSlash) { + // handle an escaped value + hadSlash = false; + switch (ch) { + case '\\': + out.write('\\'); + break; + case '\'': + out.write('\''); + break; + case '\"': + out.write('"'); + break; + case 'r': + out.write('\r'); + break; + case 'f': + out.write('\f'); + break; + case 't': + out.write('\t'); + break; + case 'n': + out.write('\n'); + break; + case 'b': + out.write('\b'); + break; + case 'u': { + // uh-oh, we're in unicode country.... + inUnicode = true; + break; + } + default: + out.write(ch); + break; + } + continue; + } else if (ch == '\\') { + hadSlash = true; + continue; + } + out.write(ch); + } + if (hadSlash) { + // then we're in the weird case of a \ at the end of the + // string, let's output it anyway. + out.write('\\'); + } + } + + /** + *

Unescapes any JavaScript literals found in the String.

+ *

+ *

For example, it will turn a sequence of '\' and 'n' + * into a newline character, unless the '\' is preceded by another + * '\'.

+ * + * @param str the String to unescape, may be null + * @return A new unescaped String, null if null string input + * @see #unescapeJava(String) + */ + public static String unescapeJavaScript(String str) { + return unescapeJava(str); + } + + /** + *

Unescapes any JavaScript literals found in the String to a + * Writer.

+ *

+ *

For example, it will turn a sequence of '\' and 'n' + * into a newline character, unless the '\' is preceded by another + * '\'.

+ *

+ *

A null string input has no effect.

+ * + * @param out the Writer used to output unescaped characters + * @param str the String to unescape, may be null + * @throws IllegalArgumentException if the Writer is null + * @throws IOException if error occurs on underlying Writer + * @see #unescapeJava(Writer, String) + */ + public static void unescapeJavaScript(Writer out, String str) throws IOException { + unescapeJava(out, str); + } + + // HTML and XML + //-------------------------------------------------------------------------- + + /** + *

Escapes the characters in a String using HTML entities.

+ *

+ *

+ * For example: + *

+ *

"bread" & "butter"

+ * becomes: + *

+ * &quot;bread&quot; &amp; &quot;butter&quot;. + *

+ *

+ *

Supports all known HTML 4.0 entities, including funky accents. + * Note that the commonly used apostrophe escape character (&apos;) + * is not a legal entity and so is not supported).

+ * + * @param str the String to escape, may be null + * @return a new escaped String, null if null string input + * @see #unescapeHtml(String) + * @see ISO Entities + * @see HTML 3.2 Character Entities for ISO Latin-1 + * @see HTML 4.0 Character entity references + * @see HTML 4.01 Character References + * @see HTML 4.01 Code positions + */ + public static String escapeHtml(String str) { + if (str == null) { + return null; + } + try { + StringWriter writer = new StringWriter((int) (str.length() * 1.5)); + escapeHtml(writer, str); + return writer.toString(); + } catch (IOException e) { + //assert false; + //should be impossible + e.printStackTrace(); + return null; + } + } + + /** + *

Escapes the characters in a String using HTML entities and writes + * them to a Writer.

+ *

+ *

+ * For example: + *

+ * "bread" & "butter" + *

becomes:

+ * &quot;bread&quot; &amp; &quot;butter&quot;. + *

+ *

Supports all known HTML 4.0 entities, including funky accents. + * Note that the commonly used apostrophe escape character (&apos;) + * is not a legal entity and so is not supported).

+ * + * @param writer the writer receiving the escaped string, not null + * @param string the String to escape, may be null + * @throws IllegalArgumentException if the writer is null + * @throws IOException when Writer passed throws the exception from + * calls to the {@link Writer#write(int)} methods. + * @see #escapeHtml(String) + * @see #unescapeHtml(String) + * @see ISO Entities + * @see HTML 3.2 Character Entities for ISO Latin-1 + * @see HTML 4.0 Character entity references + * @see HTML 4.01 Character References + * @see HTML 4.01 Code positions + */ + public static void escapeHtml(Writer writer, String string) throws IOException { + if (writer == null) { + throw new IllegalArgumentException("The Writer must not be null."); + } + if (string == null) { + return; + } + Entities.HTML40.escape(writer, string); + } + + //----------------------------------------------------------------------- + + /** + *

Unescapes a string containing entity escapes to a string + * containing the actual Unicode characters corresponding to the + * escapes. Supports HTML 4.0 entities.

+ *

+ *

For example, the string "&lt;Fran&ccedil;ais&gt;" + * will become "<Français>"

+ *

+ *

If an entity is unrecognized, it is left alone, and inserted + * verbatim into the result string. e.g. "&gt;&zzzz;x" will + * become ">&zzzz;x".

+ * + * @param str the String to unescape, may be null + * @return a new unescaped String, null if null string input + * @see #escapeHtml(Writer, String) + */ + public static String unescapeHtml(String str) { + if (str == null) { + return null; + } + try { + StringWriter writer = new StringWriter((int) (str.length() * 1.5)); + unescapeHtml(writer, str); + return writer.toString(); + } catch (IOException e) { + //assert false; + //should be impossible + e.printStackTrace(); + return null; + } + } + + /** + *

Unescapes a string containing entity escapes to a string + * containing the actual Unicode characters corresponding to the + * escapes. Supports HTML 4.0 entities.

+ *

+ *

For example, the string "&lt;Fran&ccedil;ais&gt;" + * will become "<Français>"

+ *

+ *

If an entity is unrecognized, it is left alone, and inserted + * verbatim into the result string. e.g. "&gt;&zzzz;x" will + * become ">&zzzz;x".

+ * + * @param writer the writer receiving the unescaped string, not null + * @param string the String to unescape, may be null + * @throws IllegalArgumentException if the writer is null + * @throws IOException if an IOException occurs + * @see #escapeHtml(String) + */ + public static void unescapeHtml(Writer writer, String string) throws IOException { + if (writer == null) { + throw new IllegalArgumentException("The Writer must not be null."); + } + if (string == null) { + return; + } + Entities.HTML40.unescape(writer, string); + } + + //----------------------------------------------------------------------- + + /** + *

Escapes the characters in a String using XML entities.

+ *

+ *

For example: "bread" & "butter" => + * &quot;bread&quot; &amp; &quot;butter&quot;. + *

+ *

+ *

Supports only the five basic XML entities (gt, lt, quot, amp, apos). + * Does not support DTDs or external entities.

+ *

+ *

Note that unicode characters greater than 0x7f are currently escaped to + * their numerical \\u equivalent. This may change in future releases.

+ * + * @param writer the writer receiving the unescaped string, not null + * @param str the String to escape, may be null + * @throws IllegalArgumentException if the writer is null + * @throws IOException if there is a problem writing + * @see #unescapeXml(java.lang.String) + */ + public static void escapeXml(Writer writer, String str) throws IOException { + if (writer == null) { + throw new IllegalArgumentException("The Writer must not be null."); + } + if (str == null) { + return; + } + Entities.XML.escape(writer, str); + } + + /** + *

Escapes the characters in a String using XML entities.

+ *

+ *

For example: "bread" & "butter" => + * &quot;bread&quot; &amp; &quot;butter&quot;. + *

+ *

+ *

Supports only the five basic XML entities (gt, lt, quot, amp, apos). + * Does not support DTDs or external entities.

+ *

+ *

Note that unicode characters greater than 0x7f are currently escaped to + * their numerical \\u equivalent. This may change in future releases.

+ * + * @param str the String to escape, may be null + * @return a new escaped String, null if null string input + * @see #unescapeXml(java.lang.String) + */ + public static String escapeXml(String str) { + if (str == null) { + return null; + } + return Entities.XML.escape(str); + } + + //----------------------------------------------------------------------- + + /** + *

Unescapes a string containing XML entity escapes to a string + * containing the actual Unicode characters corresponding to the + * escapes.

+ *

+ *

Supports only the five basic XML entities (gt, lt, quot, amp, apos). + * Does not support DTDs or external entities.

+ *

+ *

Note that numerical \\u unicode codes are unescaped to their respective + * unicode characters. This may change in future releases.

+ * + * @param writer the writer receiving the unescaped string, not null + * @param str the String to unescape, may be null + * @throws IllegalArgumentException if the writer is null + * @throws IOException if there is a problem writing + * @see #escapeXml(String) + */ + public static void unescapeXml(Writer writer, String str) throws IOException { + if (writer == null) { + throw new IllegalArgumentException("The Writer must not be null."); + } + if (str == null) { + return; + } + Entities.XML.unescape(writer, str); + } + + /** + *

Unescapes a string containing XML entity escapes to a string + * containing the actual Unicode characters corresponding to the + * escapes.

+ *

+ *

Supports only the five basic XML entities (gt, lt, quot, amp, apos). + * Does not support DTDs or external entities.

+ *

+ *

Note that numerical \\u unicode codes are unescaped to their respective + * unicode characters. This may change in future releases.

+ * + * @param str the String to unescape, may be null + * @return a new unescaped String, null if null string input + * @see #escapeXml(String) + */ + public static String unescapeXml(String str) { + if (str == null) { + return null; + } + return Entities.XML.unescape(str); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/Tool.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/Tool.java new file mode 100644 index 0000000..a5d3e95 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/registry/common/util/Tool.java @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.registry.common.util; + +import java.lang.reflect.Array; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.StringUtils; + +/** + * Tool + * + */ +public class Tool { + + private static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$"); + private static final Comparator SIMPLE_NAME_COMPARATOR = new Comparator() { + public int compare(String s1, String s2) { + if (s1 == null && s2 == null) { + return 0; + } + if (s1 == null) { + return -1; + } + if (s2 == null) { + return 1; + } + s1 = getSimpleName(s1); + s2 = getSimpleName(s2); + return s1.compareToIgnoreCase(s2); + } + }; + + public static boolean startWith(String value, String prefix) { + return value.startsWith(prefix); + } + + public static boolean isContains(String[] values, String value) { + return StringUtils.isContains(values, value); + } + + public static boolean isValidAddress(String address) { + return IP_PATTERN.matcher(address).matches(); + } + + public static String getHostName(String address) { + if (address != null && address.length() > 0) { + String hostname = NetUtils.getHostName(address); + if (!address.equals(hostname)) { + return hostname + "/"; + } + } + return ""; + } + + public static String getIP(String address) { + if (address != null && address.length() > 0) { + int i = address.indexOf("://"); + if (i >= 0) { + address = address.substring(i + 3); + } + i = address.indexOf('/'); + if (i >= 0) { + address = address.substring(0, i); + } + i = address.indexOf('@'); + if (i >= 0) { + address = address.substring(i + 1); + } + i = address.indexOf(':'); + if (i >= 0) { + address = address.substring(0, i); + } + if (address.matches("[a-zA-Z]+")) { + try { + address = InetAddress.getByName(address).getHostAddress(); + } catch (UnknownHostException e) { + } + } + } + return address; + } + + public static String encodeUrl(String url) { + return URL.encode(url); + } + + public static String decodeUrl(String url) { + return URL.decode(url); + } + + public static String encodeHtml(String html) { + return StringEscapeUtils.escapeHtml(html); + } + + public static String decodeHtml(String html) { + return StringEscapeUtils.unescapeHtml(html); + } + + public static int countMapValues(Map map) { + int total = 0; + if (map != null && map.size() > 0) { + for (Object value : map.values()) { + if (value != null) { + if (value instanceof Number) { + total += ((Number) value).intValue(); + } else if (value.getClass().isArray()) { + total += Array.getLength(value); + } else if (value instanceof Collection) { + total += ((Collection) value).size(); + } else if (value instanceof Map) { + total += ((Map) value).size(); + } else { + total += 1; + } + } + } + } + return total; + } + + public static List sortSimpleName(List list) { + if (list != null && list.size() > 0) { + Collections.sort(list, SIMPLE_NAME_COMPARATOR); + } + return list; + } + + public static String getSimpleName(String name) { + if (name != null && name.length() > 0) { + final int ip = name.indexOf('/'); + String v = ip != -1 ? name.substring(0, ip + 1) : ""; + + int i = name.lastIndexOf(':'); + int j = (i >= 0 ? name.lastIndexOf('.', i) : name.lastIndexOf('.')); + if (j >= 0) { + name = name.substring(j + 1); + } + name = v + name; + } + return name; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/BaseController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/BaseController.java new file mode 100644 index 0000000..4cab02f --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/BaseController.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.dubboadmin.web.mvc; + +import java.util.Map; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubboadmin.governance.biz.common.i18n.MessageResourceService; +import com.alibaba.dubboadmin.governance.util.WebConstants; +import com.alibaba.dubboadmin.registry.common.domain.User; +import com.alibaba.dubboadmin.web.pulltool.RootContextPath; +import com.alibaba.dubboadmin.web.pulltool.Tool; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.ui.Model; + +public class BaseController { + protected static final Logger logger = LoggerFactory.getLogger(BaseController.class); + + protected static final Pattern SPACE_SPLIT_PATTERN = Pattern.compile("\\s+"); + //FIXME, to extract these auxiliary methods + protected String role = null; + protected String operator = null; + protected User currentUser = null; + protected String operatorAddress = null; + protected String currentRegistry = null; + @Autowired + private MessageResourceService messageResourceService; + + @Autowired + protected Tool tool; + + public void prepare(HttpServletRequest request, HttpServletResponse response, Model model, + String methodName, String type) { + if (request.getSession().getAttribute(WebConstants.CURRENT_USER_KEY) != null) { + User user = (User) request.getSession().getAttribute(WebConstants.CURRENT_USER_KEY); + currentUser = user; + operator = user.getUsername(); + role = user.getRole(); + request.getSession().setAttribute(WebConstants.CURRENT_USER_KEY, user); + } + operatorAddress = request.getRemoteHost(); + request.getMethod(); + model.addAttribute("operator", operator); + model.addAttribute("operatorAddress", operatorAddress); + + model.addAttribute("currentRegistry", currentRegistry); + model.addAttribute("rootContextPath", new RootContextPath(request.getContextPath())); + model.addAttribute("tool", tool); + model.addAttribute("_method", methodName); + model.addAttribute("helpUrl", WebConstants.HELP_URL); + model.addAttribute("_type", type); + + } + + public String getMessage(String key, Object... args) { + return messageResourceService.getMessage(key, args); + } + + private String getDefaultRedirect(Map context, String operate) { + String defaultRedirect = (String) context.get("defaultRedirect"); + return defaultRedirect; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/RouterController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/RouterController.java new file mode 100644 index 0000000..adf04d3 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/RouterController.java @@ -0,0 +1,344 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.dubboadmin.web.mvc; + +import java.lang.reflect.Method; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubboadmin.SpringUtil; +import com.alibaba.dubboadmin.governance.util.WebConstants; +import com.alibaba.dubboadmin.web.mvc.governance.ServicesController; + +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + + +@Controller +public class RouterController { + + @Autowired + ServicesController servicesController; + + private boolean isPrimitive(Class cls) { + return cls.isPrimitive() || cls == Boolean.class || cls == Byte.class + || cls == Character.class || cls == Short.class || cls == Integer.class + || cls == Long.class || cls == Float.class || cls == Double.class + || cls == String.class; + } + + private Object convertPrimitive(Class cls, String value) { + if (cls == boolean.class || cls == Boolean.class) { + return value == null || value.length() == 0 ? false : Boolean.valueOf(value); + } else if (cls == byte.class || cls == Byte.class) { + return value == null || value.length() == 0 ? 0 : Byte.valueOf(value); + } else if (cls == char.class || cls == Character.class) { + return value == null || value.length() == 0 ? '\0' : value.charAt(0); + } else if (cls == short.class || cls == Short.class) { + return value == null || value.length() == 0 ? 0 : Short.valueOf(value); + } else if (cls == int.class || cls == Integer.class) { + return value == null || value.length() == 0 ? 0 : Integer.valueOf(value); + } else if (cls == long.class || cls == Long.class) { + return value == null || value.length() == 0 ? 0 : Long.valueOf(value); + } else if (cls == float.class || cls == Float.class) { + return value == null || value.length() == 0 ? 0 : Float.valueOf(value); + } else if (cls == double.class || cls == Double.class) { + return value == null || value.length() == 0 ? 0 : Double.valueOf(value); + } + return value; + } + + //address mapping + @RequestMapping("/governance/addresses/{ip:[0-9.]+:?[0-9]+}/{type}") + public String addressRouter(@PathVariable("ip") String ip, @PathVariable("type") String type, + HttpServletRequest request, HttpServletResponse response, Model model) { + model.addAttribute("address", ip); + return appRouter(null, "addresses", ip, type, request, response, model); + } + + @RequestMapping("/governance/addresses/{ip:[0-9.]+:?[0-9]+}/{type}/{action}") + public String addresswithIDRouter(@RequestParam Map params, @PathVariable("ip") String ip, @PathVariable("type") String type, + @PathVariable("action") String action, HttpServletRequest request, + HttpServletResponse response, Model model) { + model.addAttribute("address", ip); + return appAction(params, null, "addresses",ip, type, action, request, response, model); + } + + @RequestMapping("/governance/addresses/{ip:[0-9.]+:?[0-9]+}/{type}/{id}/{action}") + public String addressWithIDandAction(@PathVariable("ip") String ip, @PathVariable("type") String type, + @PathVariable("id") String id, @PathVariable("action") String action, + HttpServletRequest request, HttpServletResponse response, Model model) { + model.addAttribute("address", ip); + return appActionWithIdandAction(null, null, type, id, action, request, response, model); + } + + + // service mapping + @RequestMapping("/governance/services/{service}/{type}") + public String servicerRouter(@PathVariable("service") String service, @PathVariable("type") String type, + HttpServletRequest request, HttpServletResponse response, Model model) { + model.addAttribute("service", service); + return appRouter(null, "services", service, type, request, response, model); + } + + @RequestMapping("/governance/services/{service}/{type}/{action}") + public String serviceAction(@RequestParam Map param, + @PathVariable("service") String service, @PathVariable("type") String type, + @PathVariable("action") String action, HttpServletRequest request, + HttpServletResponse response, Model model) { + for (Map.Entry entry : param.entrySet()) { + System.out.println("key: " + entry.getKey()); + System.out.println("value: " + entry.getValue()); + } + model.addAttribute("service", service); + return appAction(param, null, "services", service, type, action, request, response, model); + } + + @RequestMapping("/governance/services/{service}/{type}/{id}/{action}") + public String serviceActionWithId(@RequestParam Map param, + @PathVariable("service") String service, + @PathVariable("type") String type, @PathVariable("id") String id, + @PathVariable("action") String action, HttpServletRequest request, HttpServletResponse response, Model model) { + String method = request.getMethod(); + String app = null; + System.out.println("type: " + type); + System.out.println("action: " + action); + System.out.println("method: " + method); + for (Map.Entry entry : param.entrySet()) { + if (entry.getKey().equals("application")) { + app = (String)entry.getValue(); + } + System.out.println("key: " + entry.getKey()); + System.out.println("value: " + entry.getValue()); + } + return appActionWithIdandAction(app, service, type, id, action, request, response, model); + } + + // app mapping all execute goes here + //@RequestMapping("/governance/applications/{app}/services/{ids}/{action}") + //public String serviceActionWithApp(@PathVariable("app") String app, @PathVariable("ids") String ids, + // @PathVariable("type") String type, HttpServletRequest request, + // HttpServletResponse response, Model model) { + // return ""; + //} + + @RequestMapping("/governance/applications/{app}/{elements}/{element}/{type}") + public String appRouter(@PathVariable("app") String app, @PathVariable("elements") String elements, + @PathVariable("element") String element, @PathVariable("type") String type, + HttpServletRequest request, + HttpServletResponse response, Model model) { + if (app != null) { + model.addAttribute("app", app); + } + if (StringUtils.isNumeric(element)) { + //service action, shield, recover.. + Long[] ids = new Long[1]; + ids[0] = Long.valueOf(element); + model.addAttribute("service", request.getParameter("service")); + try { + Method m = servicesController.getClass().getDeclaredMethod(type, Long[].class, HttpServletRequest.class, + HttpServletResponse.class, Model.class); + Object result = m.invoke(servicesController, ids, request, response, model); + return (String) result; + } catch (Exception e) { + e.printStackTrace(); + } + } + if (elements.equals("services")) { + model.addAttribute("service", element); + } else if (elements.equals("addresses")) { + model.addAttribute("address", element); + } + + String name = WebConstants.mapper.get(type); + if (name != null) { + Object controller = SpringUtil.getBean(name); + if (controller != null) { + try { + Method index = controller.getClass().getDeclaredMethod("index", HttpServletRequest.class, HttpServletResponse.class, + Model.class); + Object result = index.invoke(controller, request, response, model); + return (String)result; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return ""; + } + + @RequestMapping("/governance/applications/{app}/{type}") + public String appWithService(@PathVariable("app") String app, @PathVariable("type") String type, + HttpServletRequest request, + HttpServletResponse response, + Model model) { + model.addAttribute("app", app); + String name = WebConstants.mapper.get(type); + if (name != null) { + Object controller = SpringUtil.getBean(name); + try { + Method index = controller.getClass().getDeclaredMethod("index", HttpServletRequest.class, + HttpServletResponse.class, Model.class); + Object result = index.invoke(controller, request, response, model); + return (String) result; + } catch (Exception e) { + e.printStackTrace(); + } + + } + return ""; + } + + + @RequestMapping("/governance/applications/{app}/{elements}/{element}/{type}/{action}") + public String appAction(@RequestParam Map params, @PathVariable("app") String app, + @PathVariable("elements") String elements, @PathVariable("element") String element, + @PathVariable("type") String type, @PathVariable("action") String action, + HttpServletRequest request, HttpServletResponse response, Model model) { + if (app != null) { + model.addAttribute("app", app); + } + if (elements.equals("services")) { + model.addAttribute("service", element); + } else if (elements.equals("addresses")) { + model.addAttribute("address", element); + } + + String name = WebConstants.mapper.get(type); + if (name != null) { + Object controller = SpringUtil.getBean(name); + if (controller != null) { + if (request.getMethod().equals("POST")) { + Method[] methods = controller.getClass().getDeclaredMethods(); + for (Method method : methods) { + if (method.getName().equals(action)) { + Class param = method.getParameterTypes()[0]; + try { + if (!param.isAssignableFrom(HttpServletRequest.class)) { + Object value = param.newInstance(); + Method[] mms = param.getDeclaredMethods(); + for (Method m : mms) { + if (m.getName().toLowerCase().startsWith("set")) { + String methodName = m.getName(); + String key = methodName.substring(3).toLowerCase(); + String tmp = params.get(key); + Object obj = tmp; + if (tmp != null) { + Class t = m.getParameterTypes()[0]; + if (isPrimitive(t)) { + obj = convertPrimitive(t, tmp); + } + m.invoke(value, obj); + } + + } + } + return (String)method.invoke(controller, value, request, response, model); + } else { + return (String)method.invoke(controller, request, response, model); + } + } catch (Exception e) { + e.printStackTrace(); + } + + + } + } + } else { + try { + if (StringUtils.isNumeric(action)) { + // action is id, call show method + Method show = controller.getClass().getDeclaredMethod("show", Long.class, HttpServletRequest.class, HttpServletResponse.class, + Model.class); + Object result = show.invoke(controller, Long.valueOf(action), request, response, model); + return (String)result; + } else { + Method m = controller.getClass().getDeclaredMethod(action, HttpServletRequest.class, + HttpServletResponse.class, + Model.class); + Object result = m.invoke(controller, request, response, model); + return (String)result; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + return ""; + } + + + @RequestMapping("/governance/applications/{app}/services/{service}/{type}/{id}/{action}") + public String appActionWithIdandAction(@PathVariable("app") String app, @PathVariable("service") String service, + @PathVariable("type") String type, @PathVariable("id") String id, + @PathVariable("action") String action, + HttpServletRequest request, HttpServletResponse response, Model model) { + if (app != null) { + model.addAttribute("app", app); + } + model.addAttribute("service", service); + String name = WebConstants.mapper.get(type); + if (name != null) { + Object controller = SpringUtil.getBean(name); + if (controller != null) { + try { + Object result = null; + if (StringUtils.isNumeric(id)) { + //single id + Method m = null; + try { + m = controller.getClass().getDeclaredMethod(action, Long.class, HttpServletRequest.class, + HttpServletResponse.class, Model.class); + result = m.invoke(controller, Long.valueOf(id), request, response, model); + } catch (NoSuchMethodException e) { + m = controller.getClass().getDeclaredMethod(action, Long[].class, HttpServletRequest.class, + HttpServletResponse.class, Model.class); + result = m.invoke(controller, new Long[]{Long.valueOf(id)}, request, response, model); + + } + } else { + //id array + String[] array = id.split(","); + Long[] ids = new Long[array.length]; + for (int i = 0; i < array.length; i ++) { + ids[i] = Long.valueOf(array[i]); + } + + Method m = controller.getClass().getDeclaredMethod(action, Long[].class, HttpServletRequest.class, + HttpServletResponse.class, Model.class); + + result = m.invoke(controller, ids, request, response, model); + } + return (String)result; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return ""; + + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/common/auth/DubboUser.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/common/auth/DubboUser.java new file mode 100644 index 0000000..9339417 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/common/auth/DubboUser.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.common.auth; + +import java.io.Serializable; + +import com.alibaba.dubboadmin.registry.common.domain.User; + +/** + * MinasUser: DubboUser + * + */ +public class DubboUser implements Serializable { + + private static final long serialVersionUID = 1L; + + private static final ThreadLocal userHolder = new ThreadLocal(); + + private DubboUser() { + } + + public static final User getCurrentUser() { + return (User) userHolder.get(); + } + + public static final void setCurrentUser(User user) { + userHolder.set(user); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/common/i18n/LocaleUtil.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/common/i18n/LocaleUtil.java new file mode 100644 index 0000000..5d61e8a --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/common/i18n/LocaleUtil.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.common.i18n; + +import java.util.Locale; + +public class LocaleUtil { + private static ThreadLocal userLocale = new ThreadLocal(); + + public static void cleanLocale() { + userLocale.remove(); + } + + public static Locale getLocale() { + return userLocale.get(); + } + + public static void setLocale(Locale locale) { + userLocale.set(locale); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/AccessesController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/AccessesController.java new file mode 100644 index 0000000..d814f4c --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/AccessesController.java @@ -0,0 +1,303 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.governance; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.governance.service.RouteService; +import com.alibaba.dubboadmin.registry.common.domain.Access; +import com.alibaba.dubboadmin.registry.common.domain.Route; +import com.alibaba.dubboadmin.registry.common.route.RouteRule; +import com.alibaba.dubboadmin.registry.common.route.RouteRule.MatchPair; +import com.alibaba.dubboadmin.web.mvc.BaseController; +import com.alibaba.dubboadmin.web.pulltool.Tool; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.support.BindingAwareModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * ProvidersController. URI: /services/$service/accesses + * + */ + +@Controller +@RequestMapping("/governance/accesses") +public class AccessesController extends BaseController { + + private static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3}$"); + private static final Pattern LOCAL_IP_PATTERN = Pattern.compile("127(\\.\\d{1,3}){3}$"); + private static final Pattern ALL_IP_PATTERN = Pattern.compile("0{1,3}(\\.0{1,3}){3}$"); + + @Autowired + private RouteService routeService; + @Autowired + private ProviderService providerService; + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "index", "accesses"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String address = (String)newModel.get("address"); + String service = (String)newModel.get("service"); + + address = Tool.getIP(address); + List routes; + if (service != null && service.length() > 0) { + routes = routeService.findForceRouteByService(service); + } else if (address != null && address.length() > 0) { + routes = routeService.findForceRouteByAddress(address); + } else { + routes = routeService.findAllForceRoute(); + } + List accesses = new ArrayList(); + if (routes == null) { + model.addAttribute("accesses", accesses); + return "governance/screen/accesses/index"; + } + for (Route route : routes) { + Map rule = null; + try { + rule = RouteRule.parseRule(route.getMatchRule()); + } catch (ParseException e) { + logger.error("parse rule error", e); + } + MatchPair pair = rule.get("consumer.host"); + if (pair != null) { + for (String host : pair.getMatches()) { + Access access = new Access(); + access.setAddress(host); + access.setService(route.getService()); + access.setAllow(false); + accesses.add(access); + } + for (String host : pair.getUnmatches()) { + Access access = new Access(); + access.setAddress(host); + access.setService(route.getService()); + access.setAllow(true); + accesses.add(access); + } + } + } + model.addAttribute("accesses", accesses); + return "governance/screen/accesses/index"; + } + + @RequestMapping("/add") + public String add(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "add", "accesses"); + List serviceList = Tool.sortSimpleName(providerService.findServices()); + model.addAttribute("serviceList", serviceList); + return "governance/screen/accesses/add"; + } + + @RequestMapping("/create") + public String create(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + prepare(request, response, model, "create", "accesses"); + String addr = request.getParameter("consumerAddress"); + String services = request.getParameter("service"); + Set consumerAddresses = toAddr(addr); + Set aimServices = toService(services); + for (String aimService : aimServices) { + boolean isFirst = false; + List routes = routeService.findForceRouteByService(aimService); + Route route = null; + if (routes == null || routes.size() == 0) { + isFirst = true; + route = new Route(); + route.setService(aimService); + route.setForce(true); + route.setName(aimService + " blackwhitelist"); + route.setFilterRule("false"); + route.setEnabled(true); + } else { + route = routes.get(0); + } + Map when = null; + MatchPair matchPair = null; + if (isFirst) { + when = new HashMap(); + matchPair = new MatchPair(new HashSet(), new HashSet()); + when.put("consumer.host", matchPair); + } else { + when = RouteRule.parseRule(route.getMatchRule()); + matchPair = when.get("consumer.host"); + } + for (String consumerAddress : consumerAddresses) { + if (Boolean.valueOf((String) request.getParameter("allow"))) { + matchPair.getUnmatches().add(Tool.getIP(consumerAddress)); + + } else { + matchPair.getMatches().add(Tool.getIP(consumerAddress)); + } + } + StringBuilder sb = new StringBuilder(); + RouteRule.contidionToString(sb, when); + route.setMatchRule(sb.toString()); + route.setUsername(operator); + if (isFirst) { + routeService.createRoute(route); + } else { + routeService.updateRoute(route); + } + + } + model.addAttribute("success", true); + model.addAttribute("redirect", "../accesses"); + return "governance/screen/redirect"; + + } + + private Set toAddr(String addr) throws IOException { + Set consumerAddresses = new HashSet(); + BufferedReader reader = new BufferedReader(new StringReader(addr)); + while (true) { + String line = reader.readLine(); + if (null == line) + break; + + String[] split = line.split("[\\s,;]+"); + for (String s : split) { + if (s.length() == 0) + continue; + if (!IP_PATTERN.matcher(s).matches()) { + throw new IllegalStateException("illegal IP: " + s); + } + if (LOCAL_IP_PATTERN.matcher(s).matches() || ALL_IP_PATTERN.matcher(s).matches()) { + throw new IllegalStateException("local IP or any host ip is illegal: " + s); + } + + consumerAddresses.add(s); + } + } + return consumerAddresses; + } + + private Set toService(String services) throws IOException { + Set aimServices = new HashSet(); + BufferedReader reader = new BufferedReader(new StringReader(services)); + while (true) { + String line = reader.readLine(); + if (null == line) + break; + + String[] split = line.split("[\\s,;]+"); + for (String s : split) { + if (s.length() == 0) + continue; + aimServices.add(s); + } + } + return aimServices; + } + + /** + * + * @throws ParseException + */ + @RequestMapping("/delete") + public String delete(@RequestParam String accesses, HttpServletRequest request, HttpServletResponse response, Model model) throws ParseException { + prepare(request, response, model, "delete", "accesses"); + String[] temp = accesses.split(" "); + Map> prepareToDeleate = new HashMap>(); + for (String s : temp) { + String service = s.split("=")[0]; + String address = s.split("=")[1]; + Set addresses = prepareToDeleate.get(service); + if (addresses == null) { + prepareToDeleate.put(service, new HashSet()); + addresses = prepareToDeleate.get(service); + } + addresses.add(address); + } + for (Entry> entry : prepareToDeleate.entrySet()) { + + String service = entry.getKey(); + List routes = routeService.findForceRouteByService(service); + if (routes == null || routes.size() == 0) { + continue; + } + for (Route blackwhitelist : routes) { + MatchPair pairs = RouteRule.parseRule(blackwhitelist.getMatchRule()).get("consumer.host"); + Set matches = new HashSet(); + matches.addAll(pairs.getMatches()); + Set unmatches = new HashSet(); + unmatches.addAll(pairs.getUnmatches()); + for (String pair : pairs.getMatches()) { + for (String address : entry.getValue()) { + if (pair.equals(address)) { + matches.remove(pair); + break; + } + } + } + for (String pair : pairs.getUnmatches()) { + for (String address : entry.getValue()) { + if (pair.equals(address)) { + unmatches.remove(pair); + break; + } + } + } + if (matches.size() == 0 && unmatches.size() == 0) { + routeService.deleteRoute(blackwhitelist.getId()); + } else { + Map condition = new HashMap(); + condition.put("consumer.host", new MatchPair(matches, unmatches)); + StringBuilder sb = new StringBuilder(); + RouteRule.contidionToString(sb, condition); + blackwhitelist.setMatchRule(sb.toString()); + routeService.updateRoute(blackwhitelist); + } + } + + } + model.addAttribute("success", true); + model.addAttribute("redirect", "../accesses"); + return "governance/screen/redirect"; + } + + public void show(Map context) { + } + + public void edit(Map context) { + } + + public String update(Map context) { + return null; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/AddressesController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/AddressesController.java new file mode 100644 index 0000000..d728e97 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/AddressesController.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.governance; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.ConsumerService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.support.BindingAwareModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * ProvidersController. + * URI: /services/$service/providers + * + */ +@Controller +@RequestMapping("/governance/addresses") +public class AddressesController extends BaseController { + + @Autowired + private ProviderService providerService; + + @Autowired + private ConsumerService consumerService; + + @Autowired + ServicesController servicesController; + + private Map context = new HashMap<>(); + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "index", "addresses"); + List providerAddresses = null; + List consumerAddresses = null; + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String application = (String)newModel.get("app"); + String service = (String)newModel.get("service"); + String address = (String)newModel.get("address"); + String keyword = (String)newModel.get("keyword"); + + if (application != null && application.length() > 0) { + providerAddresses = providerService.findAddressesByApplication(application); + consumerAddresses = consumerService.findAddressesByApplication(application); + } else if (service != null && service.length() > 0) { + providerAddresses = providerService.findAddressesByService(service); + consumerAddresses = consumerService.findAddressesByService(service); + } else { + providerAddresses = providerService.findAddresses(); + consumerAddresses = consumerService.findAddresses(); + } + + Set addresses = new TreeSet(); + if (providerAddresses != null) { + addresses.addAll(providerAddresses); + } + if (consumerAddresses != null) { + addresses.addAll(consumerAddresses); + } + model.addAttribute("providerAddresses", providerAddresses); + model.addAttribute("consumerAddresses", consumerAddresses); + model.addAttribute("addresses", addresses); + + if (service == null && application == null + && address == null) { + model.addAttribute("address", "*"); + } + + if (StringUtils.isNotEmpty(keyword)) { + if ("*".equals(keyword)) { + return "governance/screen/addresses/index"; + } + + keyword = keyword.toLowerCase(); + Set newList = new HashSet(); + Set newProviders = new HashSet(); + Set newConsumers = new HashSet(); + + for (String o : addresses) { + if (o.toLowerCase().indexOf(keyword) != -1) { + newList.add(o); + } + } + for (String o : providerAddresses) { + if (o.toLowerCase().indexOf(keyword) != -1) { + newProviders.add(o); + } + } + for (String o : consumerAddresses) { + if (o.toLowerCase().indexOf(keyword) != -1) { + newConsumers.add(o); + } + } + context.put("addresses", newList); + model.addAttribute("addresses", newList); + model.addAttribute("providerAddresses", newProviders); + model.addAttribute("consumerAddresses", newConsumers); + } + return "governance/screen/addresses/index"; + } + + //@RequestMapping("/{ip:[0-9.]+}/{type}") + //public String addressMapping(@PathVariable("ip") String ip, @PathVariable("type") String type, + // HttpServletRequest request, HttpServletResponse response, Model model) { + // return servicesController.route(null, type, null, ip, request, response, model); + //} + + //public void search( + // HttpServletRequest request, HttpServletResponse response, Model model) { + // index(request, response, model); + // + // Set newList = new HashSet(); + // @SuppressWarnings("unchecked") + // Set list = (Set) context.get("addresses"); + // if (StringUtils.isNotEmpty(keyword)) { + // keyword = keyword.toLowerCase(); + // for (String o : list) { + // if (o.toLowerCase().indexOf(keyword) != -1) { + // newList.add(o); + // } + // } + // } + // context.put("addresses", newList); + // model.addAttribute("addresses", newList); + //} +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ApplicationsController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ApplicationsController.java new file mode 100644 index 0000000..c277a37 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ApplicationsController.java @@ -0,0 +1,336 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.governance; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.ConsumerService; +import com.alibaba.dubboadmin.governance.service.OverrideService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.Override; +import com.alibaba.dubboadmin.registry.common.route.OverrideUtils; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.support.BindingAwareModelMap; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * ProvidersController. + * URI: /applications + * + */ +@Controller +@RequestMapping("/governance/applications") +public class ApplicationsController extends BaseController { + + @Autowired + private ProviderService providerService; + + @Autowired + private ConsumerService consumerService; + + @Autowired + private OverrideService overrideService; + + @Autowired + ServicesController servicesController; + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "index", "applications"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String)newModel.get("service"); + String application = (String)newModel.get("app"); + String address = (String)newModel.get("address"); + String keyword = request.getParameter("keyword"); + if (service != null) { + Set applications = new TreeSet(); + List providerApplications = providerService.findApplicationsByServiceName(service); + if (providerApplications != null && providerApplications.size() > 0) { + applications.addAll(providerApplications); + } + List consumerApplications = consumerService.findApplicationsByServiceName(service); + if (consumerApplications != null && consumerApplications.size() > 0) { + applications.addAll(consumerApplications); + } + model.addAttribute("applications", applications); + model.addAttribute("providerApplications", providerApplications); + model.addAttribute("consumerApplications", consumerApplications); + if (service != null && service.length() > 0) { + List overrides = overrideService.findByService(service); + Map> application2Overrides = new HashMap>(); + if (overrides != null && overrides.size() > 0 + && applications != null && applications.size() > 0) { + for (String a : applications) { + if (overrides != null && overrides.size() > 0) { + List appOverrides = new ArrayList(); + for (Override override : overrides) { + if (override.isMatch(service, null, a)) { + appOverrides.add(override); + } + } + Collections.sort(appOverrides, OverrideUtils.OVERRIDE_COMPARATOR); + application2Overrides.put(a, appOverrides); + } + } + } + model.addAttribute("overrides", application2Overrides); + } + return "governance/screen/applications/index"; + } + if (service == null && application == null + && address == null) { + model.addAttribute("app", "*"); + } + Set applications = new TreeSet(); + List providerApplications = providerService.findApplications(); + if (providerApplications != null && providerApplications.size() > 0) { + applications.addAll(providerApplications); + } + List consumerApplications = consumerService.findApplications(); + if (consumerApplications != null && consumerApplications.size() > 0) { + applications.addAll(consumerApplications); + } + + Set newList = new HashSet(); + Set newProviders = new HashSet(); + Set newConsumers = new HashSet(); + model.addAttribute("applications", applications); + model.addAttribute("providerApplications", providerApplications); + model.addAttribute("consumerApplications", consumerApplications); + + if (StringUtils.isNotEmpty(keyword) && !"*".equals(keyword)) { + keyword = keyword.toLowerCase(); + for (String o : applications) { + if (o.toLowerCase().indexOf(keyword) != -1) { + newList.add(o); + } + } + for (String o : providerApplications) { + if (o.toLowerCase().indexOf(keyword) != -1) { + newProviders.add(o); + } + } + for (String o : consumerApplications) { + if (o.toLowerCase().indexOf(keyword) != -1) { + newConsumers.add(o); + } + } + model.addAttribute("applications", newList); + model.addAttribute("providerApplications", newProviders); + model.addAttribute("consumerApplications", newConsumers); + } + return "governance/screen/applications/index"; + } + + //@RequestMapping("/{application}/services") + //public String getService(@PathVariable("application") String app, HttpServletRequest request, + // HttpServletResponse response, + // Model model) { + // return servicesController.index(app, null, null, null, request, response, model); + //} + + //@RequestMapping("/{application}/services/{serviceName}/{type}") + //public String serviceMapping(@PathVariable("application") String app, + // @PathVariable("serviceName") String serviceName, + // @PathVariable("type") String type, HttpServletRequest request, HttpServletResponse response, + // Model model) { + // return servicesController.route(serviceName, type, app, null, request, response, model); + //} + + //public void search(@RequestParam(required = false) String service, + // @RequestParam(required = false) String address, + // @RequestParam(required = false) String application, + // @RequestParam(required = false) String keyword, + // HttpServletRequest request, HttpServletResponse response, Model model) { + // index(service, address, application, keyword, request, response, model); + // + // //Set newList = new HashSet(); + // //@SuppressWarnings("unchecked") + // //Set apps = (Set) .get("applications"); + // //String keyword = (String) context.get("keyword"); + // //if (StringUtils.isNotEmpty(keyword)) { + // // keyword = keyword.toLowerCase(); + // // for (String o : apps) { + // // if (o.toLowerCase().indexOf(keyword) != -1) { + // // newList.add(o); + // // } + // // } + // //} + // //context.put("applications", newList); + //} + + @RequestMapping("/{ids}/shield") + public String shield(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return mock(ids, "force:return null", "shield", request, response, model); + } + + @RequestMapping("/{ids}/tolerant") + public String tolerant(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return mock(ids, "fail:return null", "tolerant", request, response, model); + } + + @RequestMapping("/{ids}/recover") + public String recover(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return mock(ids, "", "recover", request, response, model); + } + + private String mock(Long[] ids, String mock, String methodName, HttpServletRequest request, + HttpServletResponse response, Model model) throws Exception { + prepare(request, response, model, methodName, "applications"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String) newModel.get("service"); + String applications = (String) newModel.get("app"); + if (service == null || service.length() == 0 + || applications == null || applications.length() == 0) { + model.addAttribute("message", getMessage("NoSuchOperationData")); + model.addAttribute("success", false); + model.addAttribute("redirect", "../../applications"); + return "governance/screen/redirect"; + } + if (!super.currentUser.hasServicePrivilege(service)) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", service)); + model.addAttribute("success", false); + model.addAttribute("redirect", "../../applications"); + return "governance/screen/redirect"; + } + for (String application : SPACE_SPLIT_PATTERN.split(applications)) { + List overrides = overrideService.findByServiceAndApplication(service, application); + if (overrides != null && overrides.size() > 0) { + for (Override override : overrides) { + Map map = StringUtils.parseQueryString(override.getParams()); + if (mock == null || mock.length() == 0) { + map.remove("mock"); + } else { + map.put("mock", URL.encode(mock)); + } + if (map.size() > 0) { + override.setParams(StringUtils.toQueryString(map)); + override.setEnabled(true); + override.setOperator(operator); + override.setOperatorAddress(operatorAddress); + overrideService.updateOverride(override); + } else { + overrideService.deleteOverride(override.getId()); + } + } + } else if (mock != null && mock.length() > 0) { + Override override = new Override(); + override.setService(service); + override.setApplication(application); + override.setParams("mock=" + URL.encode(mock)); + override.setEnabled(true); + override.setOperator(operator); + override.setOperatorAddress(operatorAddress); + overrideService.saveOverride(override); + } + } + model.addAttribute("success", true); + model.addAttribute("redirect", "../../applications"); + return "governance/screen/redirect"; + } + + @RequestMapping("/allshield") + public String allshield(@RequestParam(required = false) String service, HttpServletRequest request, + HttpServletResponse response, Model model) throws Exception { + return allmock(service, "force:return null", "allshield", request, response, model); + } + + @RequestMapping("/alltolerant") + public String alltolerant(@RequestParam(required = false) String service, HttpServletRequest request, + HttpServletResponse response, Model model) throws Exception { + return allmock(service, "fail:return null", "alltolerant", request, response, model); + } + + @RequestMapping("/allrecover") + public String allrecover(@RequestParam(required = false) String service, HttpServletRequest request, + HttpServletResponse response, Model model) throws Exception { + return allmock(service, "", "allrecover", request, response, model); + } + + private String allmock(String service, String mock, String methodName, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + prepare(request, response, model, methodName, "applications"); + if (service == null || service.length() == 0) { + model.addAttribute("message", getMessage("NoSuchOperationData")); + model.addAttribute("success", false); + model.addAttribute("redirect", "../../applications"); + return "governance/screen/redirect"; + } + if (!super.currentUser.hasServicePrivilege(service)) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", service)); + model.addAttribute("success", false); + model.addAttribute("redirect", "../../applications"); + return "governance/screen/redirect"; + } + List overrides = overrideService.findByService(service); + Override allOverride = null; + if (overrides != null && overrides.size() > 0) { + for (Override override : overrides) { + if (override.isDefault()) { + allOverride = override; + break; + } + } + } + if (allOverride != null) { + Map map = StringUtils.parseQueryString(allOverride.getParams()); + if (mock == null || mock.length() == 0) { + map.remove("mock"); + } else { + map.put("mock", URL.encode(mock)); + } + if (map.size() > 0) { + allOverride.setParams(StringUtils.toQueryString(map)); + allOverride.setEnabled(true); + allOverride.setOperator(operator); + allOverride.setOperatorAddress(operatorAddress); + overrideService.updateOverride(allOverride); + } else { + overrideService.deleteOverride(allOverride.getId()); + } + } else if (mock != null && mock.length() > 0) { + Override override = new Override(); + override.setService(service); + override.setParams("mock=" + URL.encode(mock)); + override.setEnabled(true); + override.setOperator(operator); + override.setOperatorAddress(operatorAddress); + overrideService.saveOverride(override); + } + model.addAttribute("success", false); + model.addAttribute("redirect", "../../applications"); + return "governance/screen/redirect"; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ConsumersController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ConsumersController.java new file mode 100644 index 0000000..7fa1675 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ConsumersController.java @@ -0,0 +1,538 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.governance; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.ConsumerService; +import com.alibaba.dubboadmin.governance.service.OverrideService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.governance.service.RouteService; +import com.alibaba.dubboadmin.registry.common.domain.Consumer; +import com.alibaba.dubboadmin.registry.common.domain.Override; +import com.alibaba.dubboadmin.registry.common.domain.Provider; +import com.alibaba.dubboadmin.registry.common.domain.Route; +import com.alibaba.dubboadmin.registry.common.route.OverrideUtils; +import com.alibaba.dubboadmin.registry.common.route.RouteRule; +import com.alibaba.dubboadmin.registry.common.route.RouteRule.MatchPair; +import com.alibaba.dubboadmin.registry.common.route.RouteUtils; +import com.alibaba.dubboadmin.web.mvc.BaseController; +import com.alibaba.dubboadmin.web.pulltool.Tool; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.support.BindingAwareModelMap; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * ConsumersController. URI: /services/$service/consumers + * + */ +@Controller +@RequestMapping("/governance/consumers") +public class ConsumersController extends BaseController { + + @Autowired + private ProviderService providerService; + + @Autowired + private ConsumerService consumerService; + + @Autowired + private OverrideService overrideService; + + @Autowired + private RouteService routeService; + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, + Model model) { + prepare(request, response, model, "index", "consumers"); + List consumers; + List overrides; + List providers = null; + List routes = null; + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String)newModel.get("service"); + String address = (String)newModel.get("address"); + String application = (String)newModel.get("app"); + // service + if (service != null && service.length() > 0) { + consumers = consumerService.findByService(service); + overrides = overrideService.findByService(service); + providers = providerService.findByService(service); + routes = routeService.findByService(service); + } + // address + else if (address != null && address.length() > 0) { + consumers = consumerService.findByAddress(address); + overrides = overrideService.findByAddress(Tool.getIP(address)); + } + // application + else if (application != null && application.length() > 0) { + consumers = consumerService.findByApplication(application); + overrides = overrideService.findByApplication(application); + } + // all + else { + consumers = consumerService.findAll(); + overrides = overrideService.findAll(); + } + if (consumers != null && consumers.size() > 0) { + for (Consumer consumer : consumers) { + if (service == null || service.length() == 0) { + providers = providerService.findByService(consumer.getService()); + routes = routeService.findByService(consumer.getService()); + } + List routed = new ArrayList(); + consumer.setProviders(RouteUtils + .route(consumer.getService(), consumer.getAddress(), consumer.getParameters(), providers, overrides, routes, null, routed)); + consumer.setRoutes(routed); + OverrideUtils.setConsumerOverrides(consumer, overrides); + } + } + model.addAttribute("consumers", consumers); + return "governance/screen/consumers/index"; + } + + @RequestMapping("/{id}") + public String show(@PathVariable("id") Long id, + HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "show", "consumers"); + Consumer consumer = consumerService.findConsumer(id); + List providers = providerService.findByService(consumer.getService()); + List routes = routeService.findByService(consumer.getService()); + List overrides = overrideService.findByService(consumer.getService()); + List routed = new ArrayList(); + consumer.setProviders(RouteUtils.route(consumer.getService(), consumer.getAddress(), consumer.getParameters(), providers, overrides, routes, null, routed)); + consumer.setRoutes(routed); + OverrideUtils.setConsumerOverrides(consumer, overrides); + model.addAttribute("consumer", consumer); + model.addAttribute("providers", consumer.getProviders()); + model.addAttribute("routes", consumer.getRoutes()); + model.addAttribute("overrides", consumer.getOverrides()); + return "governance/screen/consumers/show"; + } + + @RequestMapping("/{id}/edit") + public String edit(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "edit", "consumers"); + Consumer consumer = consumerService.findConsumer(id); + List providers = providerService.findByService(consumer.getService()); + List routes = routeService.findByService(consumer.getService()); + List overrides = overrideService.findByService(consumer.getService()); + List routed = new ArrayList(); + consumer.setProviders(RouteUtils.route(consumer.getService(), consumer.getAddress(), consumer.getParameters(), providers, overrides, routes, null, routed)); + consumer.setRoutes(routed); + OverrideUtils.setConsumerOverrides(consumer, overrides); + model.addAttribute("consumer", consumer); + model.addAttribute("providers", consumer.getProviders()); + model.addAttribute("routes", consumer.getRoutes()); + model.addAttribute("overrides", consumer.getOverrides()); + return "governance/screen/consumers/edit"; + } + + @RequestMapping(value = "/update", method = RequestMethod.POST) //post + public String update(@ModelAttribute Consumer newConsumer, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "update", "consumers"); + boolean success = true; + Long id = newConsumer.getId(); + String parameters = newConsumer.getParameters(); + Consumer consumer = consumerService.findConsumer(id); + if (consumer == null) { + model.addAttribute("message", getMessage("NoSuchOperationData", id)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "governance/consumers"); + return "governance/screen/redirect"; + } + String service = consumer.getService(); + if (!super.currentUser.hasServicePrivilege(service)) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", service)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "governance/consumers"); + return "governance/screen/redirect"; + } + Map oldMap = StringUtils.parseQueryString(consumer.getParameters()); + Map newMap = StringUtils.parseQueryString(parameters); + for (Map.Entry entry : oldMap.entrySet()) { + if (entry.getValue().equals(newMap.get(entry.getKey()))) { + newMap.remove(entry.getKey()); + } + } + String address = consumer.getAddress(); + List overrides = overrideService.findByServiceAndAddress(consumer.getService(), consumer.getAddress()); + OverrideUtils.setConsumerOverrides(consumer, overrides); + Override override = consumer.getOverride(); + if (override != null) { + if (newMap.size() > 0) { + override.setParams(StringUtils.toQueryString(newMap)); + override.setEnabled(true); + override.setOperator(operator); + override.setOperatorAddress(operatorAddress); + overrideService.updateOverride(override); + } else { + overrideService.deleteOverride(override.getId()); + } + } else { + override = new Override(); + override.setService(service); + override.setAddress(address); + override.setParams(StringUtils.toQueryString(newMap)); + override.setEnabled(true); + override.setOperator(operator); + override.setOperatorAddress(operatorAddress); + overrideService.saveOverride(override); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "governance/consumers"); + return "governance/screen/redirect"; + } + + @RequestMapping("/{id}/routed") + public String routed(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "routed", "consumers"); + showDetail(id, request, response, model); + return "governance/screen/consumers/routed"; + } + + @RequestMapping("/{id}/notified") + public String notified(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "notified", "consumers"); + showDetail(id, request, response, model); + return "governance/screen/consumers/notified"; + } + + @RequestMapping("/{id}/overrided") + public String overrided(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "overrided", "consumers"); + showDetail(id, request, response, model); + return "governance/screen/consumers/overrided"; + } + + @RequestMapping("/{ids}/shield") + public String shield(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return mock(ids, "force:return null", "shield", request, response, model); + } + + @RequestMapping("/{ids}/tolerant") + public String tolerant(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return mock(ids, "fail:return null", "tolerant", request, response, model); + } + + @RequestMapping("/{ids}/recover") + public String recover(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return mock(ids, "", "recover", request, response, model); + } + + private String mock(Long[] ids, String mock, String methodName, HttpServletRequest request, + HttpServletResponse response, Model model) throws Exception { + prepare(request, response, model, methodName, "consumers"); + boolean success = true; + if (ids == null || ids.length == 0) { + model.addAttribute("message", getMessage("NoSuchOperationData")); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../consumers"); + return "governance/screen/redirect"; + } + List consumers = new ArrayList(); + for (Long id : ids) { + Consumer c = consumerService.findConsumer(id); + if (c != null) { + consumers.add(c); + if (!super.currentUser.hasServicePrivilege(c.getService())) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", c.getService())); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../consumers"); + return "governance/screen/redirect"; + } + } + } + for (Consumer consumer : consumers) { + String service = consumer.getService(); + String address = Tool.getIP(consumer.getAddress()); + List overrides = overrideService.findByServiceAndAddress(service, address); + if (overrides != null && overrides.size() > 0) { + for (Override override : overrides) { + Map map = StringUtils.parseQueryString(override.getParams()); + if (mock == null || mock.length() == 0) { + map.remove("mock"); + } else { + map.put("mock", URL.encode(mock)); + } + if (map.size() > 0) { + override.setParams(StringUtils.toQueryString(map)); + override.setEnabled(true); + override.setOperator(operator); + override.setOperatorAddress(operatorAddress); + overrideService.updateOverride(override); + } else { + overrideService.deleteOverride(override.getId()); + } + } + } else if (mock != null && mock.length() > 0) { + Override override = new Override(); + override.setService(service); + override.setAddress(address); + override.setParams("mock=" + URL.encode(mock)); + override.setEnabled(true); + override.setOperator(operator); + override.setOperatorAddress(operatorAddress); + overrideService.saveOverride(override); + } + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../../consumers"); + return "governance/screen/redirect"; + } + + private void showDetail( Long id, + HttpServletRequest request, HttpServletResponse response, Model model) { + Consumer consumer = consumerService.findConsumer(id); + List providers = providerService.findByService(consumer.getService()); + List routes = routeService.findByService(consumer.getService()); + List overrides = overrideService.findByService(consumer.getService()); + List routed = new ArrayList(); + consumer.setProviders(RouteUtils.route(consumer.getService(), consumer.getAddress(), consumer.getParameters(), providers, overrides, routes, null, routed)); + consumer.setRoutes(routed); + OverrideUtils.setConsumerOverrides(consumer, overrides); + model.addAttribute("consumer", consumer); + model.addAttribute("providers", consumer.getProviders()); + model.addAttribute("routes", consumer.getRoutes()); + model.addAttribute("overrides", consumer.getOverrides()); + } + + @RequestMapping("/allshield") + public String allshield(@RequestParam(required = false) String service, HttpServletRequest request, + HttpServletResponse response, Model model) throws Exception { + return allmock(service, "force:return null", "allshield",request, response, model); + } + + @RequestMapping("/alltolerant") + public String alltolerant(@RequestParam(required = false) String service, HttpServletRequest request, + HttpServletResponse response, Model model) throws Exception { + return allmock(service, "fail:return null", "alltolerant", request, response, model); + } + + @RequestMapping("/allrecover") + public String allrecover(@RequestParam(required = false) String service, HttpServletRequest request, + HttpServletResponse response, Model model) throws Exception { + return allmock(service, "", "allrecover", request, response, model); + } + + private String allmock(String service, String mock, String methodName, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + prepare(request, response, model, methodName,"consumers"); + boolean success = true; + if (service == null || service.length() == 0) { + model.addAttribute("message", getMessage("NoSuchOperationData")); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../consumers"); + return "governance/screen/redirect"; + } + if (!super.currentUser.hasServicePrivilege(service)) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", service)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../consumers"); + return "governance/screen/redirect"; + } + List overrides = overrideService.findByService(service); + Override allOverride = null; + if (overrides != null && overrides.size() > 0) { + for (Override override : overrides) { + if (override.isDefault()) { + allOverride = override; + break; + } + } + } + if (allOverride != null) { + Map map = StringUtils.parseQueryString(allOverride.getParams()); + if (mock == null || mock.length() == 0) { + map.remove("mock"); + } else { + map.put("mock", URL.encode(mock)); + } + if (map.size() > 0) { + allOverride.setParams(StringUtils.toQueryString(map)); + allOverride.setEnabled(true); + allOverride.setOperator(operator); + allOverride.setOperatorAddress(operatorAddress); + overrideService.updateOverride(allOverride); + } else { + overrideService.deleteOverride(allOverride.getId()); + } + } else if (mock != null && mock.length() > 0) { + Override override = new Override(); + override.setService(service); + override.setParams("mock=" + URL.encode(mock)); + override.setEnabled(true); + override.setOperator(operator); + override.setOperatorAddress(operatorAddress); + overrideService.saveOverride(override); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../consumers"); + return "governance/screen/redirect"; + } + + @RequestMapping("/{ids}/allow") + public String allow(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return access(request, response, ids, model, true, false, "allow"); + } + + @RequestMapping("/{ids}/forbid") + public String forbid(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return access(request, response, ids, model, false, false, "forbid"); + } + + @RequestMapping("/{ids}/onlyallow") + public String onlyallow(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return access(request, response, ids, model, true, true, "onlyallow"); + } + + @RequestMapping("/{ids}/onlyforbid") + public String onlyforbid(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return access(request, response, ids, model, false, true, "onlyforbid"); + } + + private String access(HttpServletRequest request, HttpServletResponse response, Long[] ids, + Model model, boolean allow, boolean only, String methodName) throws Exception { + prepare(request, response, model, methodName, "consumers"); + boolean success = true; + if (ids == null || ids.length == 0) { + model.addAttribute("message", getMessage("NoSuchOperationData")); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../consumers"); + return "governance/screen/redirect"; + } + List consumers = new ArrayList(); + for (Long id : ids) { + Consumer c = consumerService.findConsumer(id); + if (c != null) { + consumers.add(c); + if (!super.currentUser.hasServicePrivilege(c.getService())) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", c.getService())); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../consumers"); + return "governance/screen/redirect"; + } + } + } + Map> serviceAddresses = new HashMap>(); + for (Consumer consumer : consumers) { + String service = consumer.getService(); + String address = Tool.getIP(consumer.getAddress()); + Set addresses = serviceAddresses.get(service); + if (addresses == null) { + addresses = new HashSet(); + serviceAddresses.put(service, addresses); + } + addresses.add(address); + } + for (Map.Entry> entry : serviceAddresses.entrySet()) { + String service = entry.getKey(); + boolean isFirst = false; + List routes = routeService.findForceRouteByService(service); + Route route = null; + if (routes == null || routes.size() == 0) { + isFirst = true; + route = new Route(); + route.setService(service); + route.setForce(true); + route.setName(service + " blackwhitelist"); + route.setFilterRule("false"); + route.setEnabled(true); + } else { + route = routes.get(0); + } + Map when = null; + MatchPair matchPair = null; + if (isFirst) { + when = new HashMap(); + matchPair = new MatchPair(new HashSet(), new HashSet()); + when.put("consumer.host", matchPair); + } else { + when = RouteRule.parseRule(route.getMatchRule()); + matchPair = when.get("consumer.host"); + } + if (only) { + matchPair.getUnmatches().clear(); + matchPair.getMatches().clear(); + if (allow) { + matchPair.getUnmatches().addAll(entry.getValue()); + } else { + matchPair.getMatches().addAll(entry.getValue()); + } + } else { + for (String consumerAddress : entry.getValue()) { + if (matchPair.getUnmatches().size() > 0) { // whitelist take effect + matchPair.getMatches().remove(consumerAddress); // remove data in blacklist + if (allow) { // if allowed + matchPair.getUnmatches().add(consumerAddress); // add to whitelist + } else { // if not allowed + matchPair.getUnmatches().remove(consumerAddress); // remove from whitelist + } + } else { // blacklist take effect + if (allow) { // if allowed + matchPair.getMatches().remove(consumerAddress); // remove from blacklist + } else { // if not allowed + matchPair.getMatches().add(consumerAddress); // add to blacklist + } + } + } + } + StringBuilder sb = new StringBuilder(); + RouteRule.contidionToString(sb, when); + route.setMatchRule(sb.toString()); + route.setUsername(operator); + if (matchPair.getMatches().size() > 0 || matchPair.getUnmatches().size() > 0) { + if (isFirst) { + routeService.createRoute(route); + } else { + routeService.updateRoute(route); + } + } else if (!isFirst) { + routeService.deleteRoute(route.getId()); + } + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../../consumers"); + return "governance/screen/redirect"; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/LoadbalancesController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/LoadbalancesController.java new file mode 100644 index 0000000..7b19aa8 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/LoadbalancesController.java @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.governance; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.utils.CollectionUtils; +import com.alibaba.dubboadmin.governance.service.OverrideService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.LoadBalance; +import com.alibaba.dubboadmin.registry.common.domain.Provider; +import com.alibaba.dubboadmin.registry.common.util.OverrideUtils; +import com.alibaba.dubboadmin.web.mvc.BaseController; +import com.alibaba.dubboadmin.web.pulltool.Tool; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.support.BindingAwareModelMap; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * ProvidersController. + * URI: /services/$service/loadbalances + * + */ +@Controller +@RequestMapping("/governance/loadbalances") +public class LoadbalancesController extends BaseController { + + @Autowired + private OverrideService overrideService; + + @Autowired + private ProviderService providerService; + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "index", "loadbalances"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String)newModel.get("service"); + service = StringUtils.trimToNull(service); + + List loadbalances; + if (service != null && service.length() > 0) { + loadbalances = OverrideUtils.overridesToLoadBalances(overrideService.findByService(service)); + } else { + loadbalances = OverrideUtils.overridesToLoadBalances(overrideService.findAll()); + } + model.addAttribute("loadbalances", loadbalances); + return "governance/screen/loadbalances/index"; + } + + @RequestMapping("/{id}") + public String show(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "show", "loadbalances"); + LoadBalance loadbalance = OverrideUtils.overrideToLoadBalance(overrideService.findById(id)); + model.addAttribute("loadbalance", loadbalance); + return "governance/screen/loadbalances/show"; + } + + @RequestMapping("/add") + public String add(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "add", "loadbalances"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String)newModel.get("service"); + + if (service != null && service.length() > 0 && !service.contains("*")) { + List providerList = providerService.findByService(service); + List addressList = new ArrayList(); + for (Provider provider : providerList) { + addressList.add(provider.getUrl().split("://")[1].split("/")[0]); + } + model.addAttribute("addressList", addressList); + model.addAttribute("service", service); + model.addAttribute("methods", CollectionUtils.sort(providerService.findMethodsByService(service))); + } else { + List serviceList = Tool.sortSimpleName(providerService.findServices()); + model.addAttribute("serviceList", serviceList); + } + //if (input != null) model.addAttribute("input", input); + return "governance/screen/loadbalances/add"; + } + + @RequestMapping("/{id}/edit") + public String edit(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "edit", "loadbalances"); + String service = request.getParameter("service"); + String input = request.getParameter("input"); + + if (service != null && service.length() > 0 && !service.contains("*")) { + List providerList = providerService.findByService(service); + List addressList = new ArrayList(); + for (Provider provider : providerList) { + addressList.add(provider.getUrl().split("://")[1].split("/")[0]); + } + model.addAttribute("addressList", addressList); + model.addAttribute("service", service); + model.addAttribute("methods", CollectionUtils.sort(providerService.findMethodsByService(service))); + } else { + List serviceList = Tool.sortSimpleName(providerService.findServices()); + model.addAttribute("serviceList", serviceList); + } + if (input != null) model.addAttribute("input", input); + LoadBalance loadbalance = OverrideUtils.overrideToLoadBalance(overrideService.findById(id)); + model.addAttribute("loadbalance", loadbalance); + return "governance/screen/loadbalances/edit"; + } + + @RequestMapping("/create") + public String create(LoadBalance loadBalance, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "create", "loadbalances"); + boolean success = true; + if (!super.currentUser.hasServicePrivilege(loadBalance.getService())) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", loadBalance.getService())); + success = false; + } else { + loadBalance.setUsername((String) ((BindingAwareModelMap)model).get("operator")); + overrideService.saveOverride(OverrideUtils.loadBalanceToOverride(loadBalance)); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../loadbalances"); + return "governance/screen/redirect"; + } + + + @RequestMapping("/update") + public String update(LoadBalance loadBalance, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "update", "loadbalances"); + boolean success = true; + if (!super.currentUser.hasServicePrivilege(loadBalance.getService())) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", loadBalance.getService())); + success = false; + } else { + overrideService.updateOverride(OverrideUtils.loadBalanceToOverride(loadBalance)); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../loadbalances"); + return "governance/screen/redirect"; + + } + + /** + * + * @param ids + * @return + */ + @RequestMapping("/{ids}/delete") + public String delete(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "delete", "loadbalances"); + boolean success = true; + for (Long id : ids) { + LoadBalance lb = OverrideUtils.overrideToLoadBalance(overrideService.findById(id)); + if (!super.currentUser.hasServicePrivilege(lb.getService())) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", lb.getService())); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../loadbalances"); + return "governance/screen/redirect"; + } + } + + for (Long id : ids) { + overrideService.deleteOverride(id); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../../loadbalances"); + return "governance/screen/redirect"; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/NoServicePrivilegeController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/NoServicePrivilegeController.java new file mode 100644 index 0000000..f2a252d --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/NoServicePrivilegeController.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.governance; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; + +/** + * TODO Comment of NoServicePrivilegeController + * + */ +@Controller +public class NoServicePrivilegeController { + + + public void execute(HttpServletRequest request, HttpServletResponse response, Model model) { + model.addAttribute("returnUrl", request.getParameter("returnUrl")); + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/OverridesController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/OverridesController.java new file mode 100644 index 0000000..da7ead3 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/OverridesController.java @@ -0,0 +1,441 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.governance; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.CollectionUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.ConsumerService; +import com.alibaba.dubboadmin.governance.service.OverrideService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.Override; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.support.BindingAwareModelMap; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/governance/overrides") +public class OverridesController extends BaseController { + static final Pattern AND = Pattern.compile("\\&"); + static final Pattern EQUAL = Pattern.compile("([^=\\s]*)\\s*=\\s*(\\S*)"); + static final String DEFAULT_MOCK_JSON_KEY = "mock"; + static final String MOCK_JSON_KEY_POSTFIX = ".mock"; + static final String FORM_OVERRIDE_KEY = "overrideKey"; + static final String FORM_OVERRIDE_VALUE = "overrideValue"; + static final String FORM_DEFAULT_MOCK_METHOD_FORCE = "mockDefaultMethodForce"; + static final String FORM_DEFAULT_MOCK_METHOD_JSON = "mockDefaultMethodJson"; + static final String FORM_ORIGINAL_METHOD_FORCE_PREFIX = "mockMethodForce."; + static final String FORM_ORIGINAL_METHOD_PREFIX = "mockMethod."; + static final String FORM_DYNAMIC_METHOD_NAME_PREFIX = "mockMethodName"; + static final String FORM_DYNAMIC_METHOD_FORCE_PREFIX = "mockMethodForce"; + static final String FORM_DYNAMIC_METHOD_JSON_PREFIX = "mockMethodJson"; + @Autowired + private OverrideService overrideService; + + // FORM KEY + @Autowired + private ProviderService providerService; + @Autowired + private ConsumerService consumerService; + + static Map parseQueryString(String query) { + HashMap ret = new HashMap(); + if (query == null || (query = query.trim()).length() == 0) return ret; + + String[] kvs = AND.split(query); + for (String kv : kvs) { + Matcher matcher = EQUAL.matcher(kv); + if (!matcher.matches()) continue; + String key = matcher.group(1); + String value = matcher.group(2); + ret.put(key, value); + } + + return ret; + } + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "index", "overrides"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String)newModel.get("service"); + String application = (String)newModel.get("app"); + String address = (String)newModel.get("address"); + List overrides; + if (StringUtils.isNotEmpty(service)) { + overrides = overrideService.findByService(service); + } else if (StringUtils.isNotEmpty(application)) { + overrides = overrideService.findByApplication(application); + } else if (StringUtils.isNotEmpty(address)) { + overrides = overrideService.findByAddress(address); + } else { + overrides = overrideService.findAll(); + } + model.addAttribute("overrides", overrides); + return "governance/screen/overrides/index"; + } + + @RequestMapping("/{id}") + public String show(@PathVariable Long id, HttpServletRequest request, HttpServletResponse response, + Model model) { + prepare(request, response, model, "show", "overrides"); + Override override = overrideService.findById(id); + + Map parameters = parseQueryString(override.getParams()); + + if (parameters.get(DEFAULT_MOCK_JSON_KEY) != null) { + String mock = URL.decode(parameters.get(DEFAULT_MOCK_JSON_KEY)); + String[] tokens = parseMock(mock); + model.addAttribute(FORM_DEFAULT_MOCK_METHOD_FORCE, tokens[0]); + model.addAttribute(FORM_DEFAULT_MOCK_METHOD_JSON, tokens[1]); + parameters.remove(DEFAULT_MOCK_JSON_KEY); + } + + Map method2Force = new LinkedHashMap(); + Map method2Json = new LinkedHashMap(); + + for (Iterator> iterator = parameters.entrySet().iterator(); iterator.hasNext(); ) { + Map.Entry e = iterator.next(); + String key = e.getKey(); + + if (key.endsWith(MOCK_JSON_KEY_POSTFIX)) { + String m = key.substring(0, key.length() - MOCK_JSON_KEY_POSTFIX.length()); + parseMock(m, e.getValue(), method2Force, method2Json); + iterator.remove(); + } + } + + model.addAttribute("methodForces", method2Force); + model.addAttribute("methodJsons", method2Json); + model.addAttribute("parameters", parameters); + model.addAttribute("override", override); + return "governance/screen/overrides/show"; + } + + @RequestMapping("/add") + public String add(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model,"add", "overrides"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String application = (String)newModel.get("app"); + String service = (String)newModel.get("service"); + List serviceList = new ArrayList(); + List applicationList = new ArrayList(); + if (StringUtils.isNotEmpty(application)) { + serviceList.addAll(providerService.findServicesByApplication(application)); + serviceList.addAll(consumerService.findServicesByApplication(application)); + model.addAttribute("serviceList", serviceList); + } else if (StringUtils.isNotEmpty(service)) { + applicationList.addAll(providerService.findApplicationsByServiceName(service)); + applicationList.addAll(consumerService.findApplicationsByServiceName(service)); + model.addAttribute("applicationList", applicationList); + } else { + serviceList.addAll(providerService.findServices()); + serviceList.addAll(consumerService.findServices()); + providerService.findServicesByApplication(application); + consumerService.findServicesByApplication(application); + } + model.addAttribute("serviceList", serviceList); + + if (StringUtils.isNotEmpty(service) && !service.contains("*")) { + model.addAttribute("methods", CollectionUtils.sort(new ArrayList(providerService.findMethodsByService(service)))); + } + return "governance/screen/overrides/add"; + } + + @RequestMapping("/{id}/edit") + public String edit(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, + Model model) { + prepare(request, response, model, "edit", "overrides"); + Override override = overrideService.findById(id); + + Map parameters = parseQueryString(override.getParams()); + + if (parameters.get(DEFAULT_MOCK_JSON_KEY) != null) { + String mock = URL.decode(parameters.get(DEFAULT_MOCK_JSON_KEY)); + String[] tokens = parseMock(mock); + model.addAttribute(FORM_DEFAULT_MOCK_METHOD_FORCE, tokens[0]); + model.addAttribute(FORM_DEFAULT_MOCK_METHOD_JSON, tokens[1]); + parameters.remove(DEFAULT_MOCK_JSON_KEY); + } + + Map method2Force = new LinkedHashMap(); + Map method2Json = new LinkedHashMap(); + + List methods = CollectionUtils.sort(new ArrayList(providerService.findMethodsByService(override.getService()))); + if (methods != null && methods.isEmpty()) { + for (String m : methods) { + parseMock(m, parameters.get(m + MOCK_JSON_KEY_POSTFIX), method2Force, method2Json); + parameters.remove(m + MOCK_JSON_KEY_POSTFIX); + } + } + for (Iterator> iterator = parameters.entrySet().iterator(); iterator.hasNext(); ) { + Map.Entry e = iterator.next(); + String key = e.getKey(); + + if (key.endsWith(MOCK_JSON_KEY_POSTFIX)) { + String m = key.substring(0, key.length() - MOCK_JSON_KEY_POSTFIX.length()); + parseMock(m, e.getValue(), method2Force, method2Json); + iterator.remove(); + } + } + + model.addAttribute("methods", methods); + model.addAttribute("methodForces", method2Force); + model.addAttribute("methodJsons", method2Json); + model.addAttribute("parameters", parameters); + model.addAttribute("override", override); + return "governance/screen/overrides/edit"; + } + + private void parseMock(String m, String mock, Map method2Force, Map method2Json) { + String[] tokens = parseMock(mock); + method2Force.put(m, tokens[0]); + method2Json.put(m, tokens[1]); + } + + private String[] parseMock(String mock) { + mock = URL.decode(mock); + String force; + if (mock.startsWith("force:")) { + force = "force"; + mock = mock.substring("force:".length()); + } else if (mock.startsWith("fail:")) { + force = "fail"; + mock = mock.substring("fail:".length()); + } else { + force = "fail"; + } + String[] tokens = new String[2]; + tokens[0] = force; + tokens[1] = mock; + return tokens; + } + + boolean catchParams(Override override, HttpServletRequest request, Model model) { + Map map = request.getParameterMap(); + String service = map.get("service")[0]; + if (service == null || service.trim().length() == 0) { + model.addAttribute("message", getMessage("service is blank!")); + return false; + } + if (!super.currentUser.hasServicePrivilege(service)) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", service)); + return false; + } + + String defaultMockMethodForce = map.get(FORM_DEFAULT_MOCK_METHOD_FORCE)[0]; + String defaultMockMethodJson = map.get(FORM_DEFAULT_MOCK_METHOD_JSON)[0]; + + Map override2Value = new HashMap(); + Map method2Json = new HashMap(); + + for (Map.Entry param : map.entrySet()) { + String key = param.getKey().trim(); + if(param.getValue().length != 1) continue;; + + String value = param.getValue()[0]; + + if (key.startsWith(FORM_OVERRIDE_KEY) && value != null && value.trim().length() > 0) { + String index = key.substring(FORM_OVERRIDE_KEY.length()); + String overrideValue = map.get(FORM_OVERRIDE_VALUE + index)[0]; + if (overrideValue != null && overrideValue.trim().length() > 0) { + override2Value.put(value.trim(), overrideValue.trim()); + } + } + + if (key.startsWith(FORM_ORIGINAL_METHOD_PREFIX) && value != null && value.trim().length() > 0) { + String method = key.substring(FORM_ORIGINAL_METHOD_PREFIX.length()); + String force = map.get(FORM_ORIGINAL_METHOD_FORCE_PREFIX + method)[0]; + method2Json.put(method, force + ":" + value.trim()); + } + + if (key.startsWith(FORM_DYNAMIC_METHOD_NAME_PREFIX) && value != null && value.trim().length() > 0) { + String index = key.substring(FORM_DYNAMIC_METHOD_NAME_PREFIX.length()); + String force = map.get(FORM_DYNAMIC_METHOD_FORCE_PREFIX + index)[0]; + String json = map.get(FORM_DYNAMIC_METHOD_JSON_PREFIX + index)[0]; + + if (json != null && json.trim().length() > 0) { + method2Json.put(value.trim(), force + ":" + json.trim()); + } + } + } + + StringBuilder paramters = new StringBuilder(); + boolean isFirst = true; + if (defaultMockMethodJson != null && defaultMockMethodJson.trim().length() > 0) { + paramters.append("mock=").append(URL.encode(defaultMockMethodForce + ":" + defaultMockMethodJson.trim())); + isFirst = false; + } + for (Map.Entry e : method2Json.entrySet()) { + if (isFirst) isFirst = false; + else paramters.append("&"); + + paramters.append(e.getKey()).append(MOCK_JSON_KEY_POSTFIX).append("=").append(URL.encode(e.getValue())); + } + for (Map.Entry e : override2Value.entrySet()) { + if (isFirst) isFirst = false; + else paramters.append("&"); + + paramters.append(e.getKey()).append("=").append(URL.encode(e.getValue())); + } + + String p = paramters.toString(); + if (p.trim().length() == 0) { + model.addAttribute("message", getMessage("Please enter Parameters!")); + return false; + } + + override.setParams(p); + return true; + } + + + @RequestMapping("/create") + public String create(Override override, HttpServletRequest request, + HttpServletResponse response, Model model) { + prepare(request,response,model,"update", "overrides"); + boolean success = true; + if (!catchParams(override, request, model)) { + success =false; + } else { + overrideService.saveOverride(override); + } + + model.addAttribute("success", success); + model.addAttribute("redirect", "../overrides"); + return "governance/screen/redirect"; + } + + @RequestMapping("/update") + public String update(Override override, HttpServletRequest request, + HttpServletResponse response, Model model) { + prepare(request, response, model, "update", "overrides"); + boolean succcess = true; + Override o = overrideService.findById(override.getId()); + override.setService(o.getService()); + override.setAddress(o.getAddress()); + override.setApplication(o.getApplication()); + + if (!catchParams(override, request, model)) { + succcess = false; + } else { + overrideService.updateOverride(override); + } + + model.addAttribute("success", succcess); + model.addAttribute("redirect", "../overrides"); + return "governance/screen/redirect"; + + } + + @RequestMapping("/{ids}/delete") + public String delete(@PathVariable("ids") Long[] ids, HttpServletRequest request, + HttpServletResponse response, Model model) { + prepare(request, response, model, "delete", "overrides"); + for (Long id : ids) { + overrideService.deleteOverride(id); + } + + model.addAttribute("success", true); + model.addAttribute("redirect", "../../overrides"); + return "governance/screen/redirect"; + } + + @RequestMapping("/{ids}/enable") + public String enable(@PathVariable("ids") Long[] ids, HttpServletRequest request, + HttpServletResponse response, Model model) { + prepare(request, response, model, "enable", "overrides"); + boolean success = true; + for (Long id : ids) { + Override override = overrideService.findById(id); + if (override == null) { + model.addAttribute("message", getMessage("NoSuchOperationData", id)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../overrides"); + return "governance/screen/redirect"; + } else { + if (!super.currentUser.hasServicePrivilege(override.getService())) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", override.getService())); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../overrides"); + return "governance/screen/redirect"; + } + } + } + + for (Long id : ids) { + overrideService.enableOverride(id); + } + + model.addAttribute("success", success); + model.addAttribute("redirect", "../../overrides"); + return "governance/screen/redirect"; + } + + @RequestMapping("/{ids}/disable") + public String disable(@PathVariable("ids") Long[] ids, HttpServletRequest request, + HttpServletResponse response, Model model) { + prepare(request, response, model, "disable", "overrides"); + boolean success = true; + for (Long id : ids) { + Override override = overrideService.findById(id); + if (override == null) { + model.addAttribute("message", getMessage("NoSuchOperationData", id)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../overrides"); + return "governance/screen/redirect"; + } else { + if (!super.currentUser.hasServicePrivilege(override.getService())) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", override.getService())); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../overrides"); + return "governance/screen/redirect"; + } + } + } + + for (Long id : ids) { + overrideService.disableOverride(id); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../../overrides"); + return "governance/screen/redirect"; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/OwnersController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/OwnersController.java new file mode 100644 index 0000000..0bd75a0 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/OwnersController.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.governance; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubboadmin.governance.service.OwnerService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.Owner; +import com.alibaba.dubboadmin.web.mvc.BaseController; +import com.alibaba.dubboadmin.web.pulltool.Tool; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.support.BindingAwareModelMap; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * ProvidersController. URI: /services/$service/owners + * + */ +@Controller +@RequestMapping("/governance/owners") +public class OwnersController extends BaseController { + + @Autowired + private OwnerService ownerService; + + @Autowired + private ProviderService providerService; + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "index", "owners"); + List owners; + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String)newModel.get("service"); + if (service != null && service.length() > 0) { + owners = ownerService.findByService(service); + } else { + owners = ownerService.findAll(); + } + model.addAttribute("owners", owners); + return "governance/screen/owners/index"; + } + + @RequestMapping("/add") + public String add(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "add", "owners"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String)newModel.get("service"); + if (service == null || service.length() == 0) { + List serviceList = Tool.sortSimpleName(new ArrayList(providerService.findServices())); + model.addAttribute("serviceList", serviceList); + } + return "governance/screen/owners/add"; + } + + @RequestMapping(value = "/create", method = RequestMethod.POST) //post + public String create(Owner owner, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "create", "owners"); + String service = owner.getService(); + String username = owner.getUsername(); + if (service == null || service.length() == 0 + || username == null || username.length() == 0) { + model.addAttribute("message", getMessage("NoSuchOperationData")); + model.addAttribute("success", false); + model.addAttribute("redirect", "../owners"); + return "governance/screen/redirect"; + } + if (!super.currentUser.hasServicePrivilege(service)) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", service)); + model.addAttribute("success", false); + model.addAttribute("redirect", "../owners"); + return "governance/screen/redirect"; + } + ownerService.saveOwner(owner); + model.addAttribute("success", true); + model.addAttribute("redirect", "../owners"); + return "governance/screen/redirect"; + } + + @RequestMapping("/{ids}/delete") + public String delete(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "delete", "owners"); + + String service = request.getParameter("service"); + String username = request.getParameter("username"); + Owner owner = new Owner(); + owner.setService(service); + owner.setUsername(username); + if (service == null || service.length() == 0 + || username == null || username.length() == 0) { + model.addAttribute("message", getMessage("NoSuchOperationData")); + model.addAttribute("success", false); + model.addAttribute("redirect", "../../owners"); + return "governance/screen/redirect"; + } + if (!super.currentUser.hasServicePrivilege(service)) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", service)); + model.addAttribute("success", false); + model.addAttribute("redirect", "../../owners"); + return "governance/screen/redirect"; + } + ownerService.deleteOwner(owner); + model.addAttribute("success", true); + model.addAttribute("redirect", "../../owners"); + return "governance/screen/redirect"; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ProvidersController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ProvidersController.java new file mode 100644 index 0000000..0344073 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ProvidersController.java @@ -0,0 +1,507 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.governance; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.OverrideService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.Override; +import com.alibaba.dubboadmin.registry.common.domain.Provider; +import com.alibaba.dubboadmin.registry.common.route.OverrideUtils; +import com.alibaba.dubboadmin.web.mvc.BaseController; +import com.alibaba.dubboadmin.web.pulltool.Tool; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.support.BindingAwareModelMap; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + *

ProvidersController.

+ * URI:
+ * GET /providers, show all providers
+ * GET /providers/add, show web form for add a static provider
+ * POST /provider/create, create a static provider, save form
+ * GET /providers/$id, show provider details
+ * GET /providers/$id/edit, web form for edit provider
+ * POST /providers/$id, update provider, save form
+ * GET /providers/$id/delete, delete a provider
+ * GET /providers/$id/tostatic, transfer to static
+ * GET /providers/$id/todynamic, transfer to dynamic
+ * GET /providers/$id/enable, enable a provider
+ * GET /providers/$id/disable, disable a provider
+ * GET /providers/$id/reconnect, reconnect
+ * GET /providers/$id/recover, recover
+ *
+ * GET /services/$service/providers, show all provider of a specific service
+ * GET /services/$service/providers/add, show web form for add a static provider
+ * POST /services/$service/providers, save a static provider
+ * GET /services/$service/providers/$id, show provider details
+ * GET /services/$service/providers/$id/edit, show web form for edit provider
+ * POST /services/$service/providers/$id, save changes of provider
+ * GET /services/$service/providers/$id/delete, delete provider
+ * GET /services/$service/providers/$id/tostatic, transfer to static
+ * GET /services/$service/providers/$id/todynamic, transfer to dynamic
+ * GET /services/$service/providers/$id/enable, enable
+ * GET /services/$service/providers/$id/disable, diable
+ * GET /services/$service/providers/$id/reconnect, reconnect
+ * GET /services/$service/providers/$id/recover, recover
+ * + */ +@Controller +@RequestMapping("/governance/providers") +public class ProvidersController extends BaseController { + + @Autowired + private ProviderService providerService; + + @Autowired + private OverrideService overrideService; + + + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) { + + + prepare(request, response, model, "index", "providers"); + + String value = ""; + String separators = "...."; + + List providers = null; + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String)newModel.get("service"); + String address = (String)newModel.get("address"); + String application = (String)newModel.get("app"); + + // service + if (service != null && service.length() > 0) { + providers = providerService.findByService(service); + + value = service + separators + request.getRequestURI(); + } + // address + else if (address != null && address.length() > 0) { + providers = providerService.findByAddress(address); + + value = address + separators + request.getRequestURI(); + } + // application + else if (application != null && application.length() > 0) { + providers = providerService.findByApplication(application); + + value = application + separators + request.getRequestURI(); + } + // all + else { + providers = providerService.findAll(); + } + + model.addAttribute("providers", providers); + model.addAttribute("serviceAppMap", getServiceAppMap(providers)); + + // record search history to cookies + try { + setSearchHistroy(value, request, response); + } catch (Exception e) { + // + } + return "governance/screen/providers/index"; + } + + /** + * + * Calculate the application list corresponding to each service, to facilitate the "repeat" prompt on service page + * @param providers app services + */ + private Map> getServiceAppMap(List providers) { + Map> serviceAppMap = new HashMap>(); + if (providers != null && providers.size() > 0) { + for (Provider provider : providers) { + Set appSet; + String service = provider.getService(); + if (serviceAppMap.get(service) == null) { + appSet = new HashSet(); + } else { + appSet = serviceAppMap.get(service); + } + appSet.add(provider.getApplication()); + serviceAppMap.put(service, appSet); + } + } + return serviceAppMap; + } + + /** + * Record search history to cookies, steps: + * Check whether the added record exists in the cookie, and if so, update the list order; if it does not exist, insert it to the front + * + * @param value + */ + private void setSearchHistroy(String value, HttpServletRequest request, HttpServletResponse response) { + //System.out.println("add new cookie: " + value); + // Analyze existing cookies + String separatorsB = "\\.\\.\\.\\.\\.\\."; + String newCookiev = value; + Cookie[] cookies = request.getCookies(); + for (Cookie c : cookies) { + if (c.getName().equals("HISTORY")) { + String cookiev = c.getValue(); + String[] values = cookiev.split(separatorsB); + int count = 1; + for (String v : values) { + if (count <= 10) { + if (!value.equals(v)) { + newCookiev = newCookiev + separatorsB + v; + //System.out.println("new cookie: " + newCookiev); + } + } + count++; + } + break; + } + } + + Cookie _cookie = new Cookie("HISTORY", newCookiev); + _cookie.setMaxAge(60 * 60 * 24 * 7); // Set the cookie's lifetime to 30 minutes + _cookie.setPath("/"); + response.addCookie(_cookie); // Write to client hard disk + } + + @RequestMapping("/{id}") + public String show(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "show", "providers"); + Provider provider = providerService.findProvider(id); + if (provider != null && provider.isDynamic()) { + List overrides = overrideService.findByServiceAndAddress(provider.getService(), provider.getAddress()); + OverrideUtils.setProviderOverrides(provider, overrides); + } + model.addAttribute("provider", provider); + return "governance/screen/providers/show"; + + } + + /** + * Load new service page, get all the service name + */ + + @RequestMapping("/{id}/add") + public String add(@PathVariable("id") Long id, + HttpServletRequest request, HttpServletResponse response, Model model) { + model.addAttribute("id", id); + return add(request, response, model); + } + + @RequestMapping("/add") + public String add(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "add", "providers"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + Long id = (Long)newModel.get("id"); + String service = (String)newModel.get("service"); + if (service == null) { + List serviceList = Tool.sortSimpleName(new ArrayList(providerService.findServices())); + model.addAttribute("serviceList", serviceList); + } + if (id != null) { + Provider p = providerService.findProvider(id); + if (p != null) { + model.addAttribute("provider", p); + String parameters = p.getParameters(); + if (parameters != null && parameters.length() > 0) { + Map map = StringUtils.parseQueryString(parameters); + map.put("timestamp", String.valueOf(System.currentTimeMillis())); + map.remove("pid"); + p.setParameters(StringUtils.toQueryString(map)); + } + } + } + return "governance/screen/providers/add"; + } + + @RequestMapping("/{id}/edit") + public String edit(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model,"edit", "providers"); + Provider provider = providerService.findProvider(id); + if (provider != null && provider.isDynamic()) { + List overrides = overrideService.findByServiceAndAddress(provider.getService(), provider.getAddress()); + OverrideUtils.setProviderOverrides(provider, overrides); + } + model.addAttribute("provider", provider); + return "governance/screen/providers/edit"; + } + + @RequestMapping(value = "/create", method = RequestMethod.POST) //post + public String create(@ModelAttribute Provider provider, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model,"create" ,"providers"); + boolean success = true; + String service = provider.getService(); + if (service == null) { + service = (String)((BindingAwareModelMap)model).get("service"); + provider.setService(service); + } + if (!super.currentUser.hasServicePrivilege(service)) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", service)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../providers"); + return "governance/screen/redirect"; + } + if (provider.getParameters() == null) { + String url = provider.getUrl(); + if (url != null) { + int i = url.indexOf('?'); + if (i > 0) { + provider.setUrl(url.substring(0, i)); + provider.setParameters(url.substring(i + 1)); + } + } + } + provider.setDynamic(false); // Provider add through web page must be static + providerService.create(provider); + model.addAttribute("success", success); + model.addAttribute("redirect", "../providers"); + return "governance/screen/redirect"; + } + + @RequestMapping(value = "/update", method = RequestMethod.POST) //post + public String update(@ModelAttribute Provider newProvider, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "update", "providers"); + boolean success = true; + Long id = newProvider.getId(); + String parameters = newProvider.getParameters(); + Provider provider = providerService.findProvider(id); + if (provider == null) { + model.addAttribute("message", getMessage("NoSuchOperationData", id)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../providers"); + return "governance/screen/redirect"; + } + String service = provider.getService(); + if (!super.currentUser.hasServicePrivilege(service)) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", service)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../providers"); + return "governance/screen/redirect"; + } + Map oldMap = StringUtils.parseQueryString(provider.getParameters()); + Map newMap = StringUtils.parseQueryString(parameters); + for (Map.Entry entry : oldMap.entrySet()) { + if (entry.getValue().equals(newMap.get(entry.getKey()))) { + newMap.remove(entry.getKey()); + } + } + if (provider.isDynamic()) { + String address = provider.getAddress(); + List overrides = overrideService.findByServiceAndAddress(provider.getService(), provider.getAddress()); + OverrideUtils.setProviderOverrides(provider, overrides); + Override override = provider.getOverride(); + if (override != null) { + if (newMap.size() > 0) { + override.setParams(StringUtils.toQueryString(newMap)); + override.setEnabled(true); + override.setOperator(operator); + override.setOperatorAddress(operatorAddress); + overrideService.updateOverride(override); + } else { + overrideService.deleteOverride(override.getId()); + } + } else { + override = new Override(); + override.setService(service); + override.setAddress(address); + override.setParams(StringUtils.toQueryString(newMap)); + override.setEnabled(true); + override.setOperator(operator); + override.setOperatorAddress(operatorAddress); + overrideService.saveOverride(override); + } + } else { + provider.setParameters(parameters); + providerService.updateProvider(provider); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../providers"); + return "governance/screen/redirect"; + } + + @RequestMapping("/{ids}/delete") + public String delete(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "delete", "providers"); + boolean success = true; + for (Long id : ids) { + Provider provider = providerService.findProvider(id); + if (provider == null) { + model.addAttribute("message", getMessage("NoSuchOperationData", id)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } else if (provider.isDynamic()) { + model.addAttribute("message", getMessage("CanNotDeleteDynamicData", id)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } else if (!super.currentUser.hasServicePrivilege(provider.getService())) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", provider.getService())); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } + } + for (Long id : ids) { + providerService.deleteStaticProvider(id); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } + + @RequestMapping("/{ids}/enable") + public String enable(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "enable", "providers"); + boolean success = true; + Map id2Provider = new HashMap(); + for (Long id : ids) { + Provider provider = providerService.findProvider(id); + if (provider == null) { + model.addAttribute("message", getMessage("NoSuchOperationData", id)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } else if (!super.currentUser.hasServicePrivilege(provider.getService())) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", provider.getService())); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } + id2Provider.put(id, provider); + } + for (Long id : ids) { + providerService.enableProvider(id); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } + + @RequestMapping("/{ids}/disable") + public String disable(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "disable", "providers"); + boolean success = true; + for (Long id : ids) { + Provider provider = providerService.findProvider(id); + if (provider == null) { + model.addAttribute("message", getMessage("NoSuchOperationData", id)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } else if (!super.currentUser.hasServicePrivilege(provider.getService())) { + success = false; + model.addAttribute("message", getMessage("HaveNoServicePrivilege", provider.getService())); + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } + } + for (Long id : ids) { + providerService.disableProvider(id); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } + + @RequestMapping("/{ids}/doubling") + public String doubling(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "doubling","providers"); + boolean success = true; + for (Long id : ids) { + Provider provider = providerService.findProvider(id); + if (provider == null) { + success = false; + model.addAttribute("message", getMessage("NoSuchOperationData", id)); + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } else if (!super.currentUser.hasServicePrivilege(provider.getService())) { + success = false; + model.addAttribute("message", getMessage("HaveNoServicePrivilege", provider.getService())); + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } + } + for (Long id : ids) { + providerService.doublingProvider(id); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } + + @RequestMapping("/{ids}/halving") + public String halving(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "halving","providers"); + boolean success = true; + for (Long id : ids) { + Provider provider = providerService.findProvider(id); + if (provider == null) { + success = false; + model.addAttribute("message", getMessage("NoSuchOperationData", id)); + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } else if (!super.currentUser.hasServicePrivilege(provider.getService())) { + success = false; + model.addAttribute("message", getMessage("HaveNoServicePrivilege", provider.getService())); + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } + } + for (Long id : ids) { + providerService.halvingProvider(id); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../../providers"); + return "governance/screen/redirect"; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/RoutesController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/RoutesController.java new file mode 100644 index 0000000..0f95a3e --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/RoutesController.java @@ -0,0 +1,644 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.governance; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.utils.CollectionUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.ConsumerService; +import com.alibaba.dubboadmin.governance.service.OwnerService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.governance.service.RouteService; +import com.alibaba.dubboadmin.registry.common.domain.Consumer; +import com.alibaba.dubboadmin.registry.common.domain.Provider; +import com.alibaba.dubboadmin.registry.common.domain.Route; +import com.alibaba.dubboadmin.registry.common.route.ParseUtils; +import com.alibaba.dubboadmin.registry.common.route.RouteRule; +import com.alibaba.dubboadmin.registry.common.route.RouteUtils; +import com.alibaba.dubboadmin.web.mvc.BaseController; +import com.alibaba.dubboadmin.web.pulltool.Tool; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.support.BindingAwareModelMap; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * ProvidersController. + * URI: /services/$service/routes + * + */ +@Controller +@RequestMapping("/governance/routes") +public class RoutesController extends BaseController { + + private static final int MAX_RULE_LENGTH = 1000; + static String[][] when_names = { + {"method", "method", "unmethod"}, + {"consumer.application", "consumerApplication", "unconsumerApplication"}, + {"consumer.cluster", "consumerCluster", "unconsumerCluster"}, + {"consumer.host", "consumerHost", "unconsumerHost"}, + {"consumer.version", "consumerVersion", "unconsumerVersion"}, + {"consumer.group", "consumerGroup", "unconsumerGroup"}, + }; + static String[][] then_names = { + {"provider.application", "providerApplication", "unproviderApplication"}, + {"provider.cluster", "providerCluster", "unproviderCluster"}, // Must check if Cluster exists + {"provider.host", "providerHost", "unproviderHost"}, + {"provider.protocol", "providerProtocol", "unproviderProtocol"}, + {"provider.port", "providerPort", "unproviderPort"}, + {"provider.version", "providerVersion", "unproviderVersion"}, + {"provider.group", "providerGroup", "unproviderGroup"} + }; + @Autowired + private RouteService routeService; + @Autowired + private ProviderService providerService; + @Autowired + private ConsumerService consumerService; + + static void checkService(String service) { + if (service.contains(",")) throw new IllegalStateException("service(" + service + ") contain illegale ','"); + + String interfaceName = service; + int gi = interfaceName.indexOf("/"); + if (gi != -1) interfaceName = interfaceName.substring(gi + 1); + int vi = interfaceName.indexOf(':'); + if (vi != -1) interfaceName = interfaceName.substring(0, vi); + + if (interfaceName.indexOf('*') != -1 && interfaceName.indexOf('*') != interfaceName.length() - 1) { + throw new IllegalStateException("service(" + service + ") only allow 1 *, and must be last char!"); + } + } + + /** + * add owners related with service + * + * @param usernames the usernames to add + * @param serviceName no wildcards + */ + public static void addOwnersOfService(Set usernames, String serviceName, + OwnerService ownerDAO) { + List serviceNamePatterns = ownerDAO.findAllServiceNames(); + for (String p : serviceNamePatterns) { + if (ParseUtils.isMatchGlobPattern(p, serviceName)) { + List list = ownerDAO.findUsernamesByServiceName(p); + usernames.addAll(list); + } + } + } + + /** + * add owners related with service pattern + * + * @param usernames the usernames to add + * @param serviceNamePattern service pattern, Glob + */ + public static void addOwnersOfServicePattern(Set usernames, String serviceNamePattern, + OwnerService ownerDAO) { + List serviceNamePatterns = ownerDAO.findAllServiceNames(); + for (String p : serviceNamePatterns) { + if (ParseUtils.hasIntersection(p, serviceNamePattern)) { + List list = ownerDAO.findUsernamesByServiceName(p); + usernames.addAll(list); + } + } + } + + /** + * Routing module home page + * + */ + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "index", "routes"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String address = (String)newModel.get("address"); + String service = (String)newModel.get("service"); + address = Tool.getIP(address); + List routes; + if (service != null && service.length() > 0 + && address != null && address.length() > 0) { + routes = routeService.findByServiceAndAddress(service, address); + } else if (service != null && service.length() > 0) { + routes = routeService.findByService(service); + } else if (address != null && address.length() > 0) { + routes = routeService.findByAddress(address); + } else { + routes = routeService.findAll(); + } + model.addAttribute("routes", routes); + return "governance/screen/routes/index"; + } + + /** + * Display routing details + * + */ + @RequestMapping("/{id}") + public String show(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, Model model) { + try { + prepare(request, response, model, "show", "routes"); + Route route = routeService.findRoute(id); + + if (route == null) { + throw new IllegalArgumentException("The route is not existed."); + } + if (route.getService() != null && !route.getService().isEmpty()) { + model.addAttribute("service", route.getService()); + } + + RouteRule routeRule = RouteRule.parse(route); + + @SuppressWarnings("unchecked") + Map[] paramArray = new Map[]{ + routeRule.getWhenCondition(), routeRule.getThenCondition()}; + String[][][] namesArray = new String[][][]{when_names, then_names}; + + for (int i = 0; i < paramArray.length; ++i) { + Map param = paramArray[i]; + String[][] names = namesArray[i]; + for (String[] name : names) { + RouteRule.MatchPair matchPair = param.get(name[0]); + if (matchPair == null) { + continue; + } + + if (!matchPair.getMatches().isEmpty()) { + String m = RouteRule.join(matchPair.getMatches()); + model.addAttribute(name[1], m); + } + if (!matchPair.getUnmatches().isEmpty()) { + String u = RouteRule.join(matchPair.getUnmatches()); + model.addAttribute(name[2], u); + } + } + } + model.addAttribute("route", route); + model.addAttribute("methods", CollectionUtils.sort(new ArrayList(providerService.findMethodsByService(route.getService())))); + } catch (ParseException e) { + e.printStackTrace(); + } + return "governance/screen/routes/show"; + } + + /** + * Load new route page + * + */ + @RequestMapping("/add") + public String add(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "add", "routes"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String)newModel.get("service"); + if (service != null && service.length() > 0 && !service.contains("*")) { + model.addAttribute("service", service); + model.addAttribute("methods", CollectionUtils.sort(new ArrayList(providerService.findMethodsByService(service)))); + } else { + List serviceList = Tool.sortSimpleName(new ArrayList(providerService.findServices())); + model.addAttribute("serviceList", serviceList); + } + + //if (input != null) model.addAttribute("input", input); + return "governance/screen/routes/add"; + } + + /** + * Load modified routing page + * + */ + + @RequestMapping("/{id}/edit") + public String edit(@PathVariable("id") Long id, @RequestParam(required = false) String service, + @RequestParam(required = false) String input, + HttpServletRequest request, HttpServletResponse response, Model model) { + + prepare(request, response, model, "edit", "routes"); + if (service != null && service.length() > 0 && !service.contains("*")) { + model.addAttribute("service", service); + model.addAttribute("methods", CollectionUtils.sort(new ArrayList(providerService.findMethodsByService(service)))); + } else { + List serviceList = Tool.sortSimpleName(new ArrayList(providerService.findServices())); + model.addAttribute("serviceList", serviceList); + } + + if (input != null) model.addAttribute("input", input); + Route route = routeService.findRoute(id); + + if (route == null) { + throw new IllegalArgumentException("The route is not existed."); + } + if (route.getService() != null && !route.getService().isEmpty()) { + model.addAttribute("service", route.getService()); + } + + RouteRule routeRule = null; + try { + routeRule = RouteRule.parse(route); + } catch (ParseException e) { + e.printStackTrace(); + } + + @SuppressWarnings("unchecked") + Map[] paramArray = new Map[]{ + routeRule.getWhenCondition(), routeRule.getThenCondition()}; + String[][][] namesArray = new String[][][]{when_names, then_names}; + + for (int i = 0; i < paramArray.length; ++i) { + Map param = paramArray[i]; + String[][] names = namesArray[i]; + for (String[] name : names) { + RouteRule.MatchPair matchPair = param.get(name[0]); + if (matchPair == null) { + continue; + } + + if (!matchPair.getMatches().isEmpty()) { + String m = RouteRule.join(matchPair.getMatches()); + model.addAttribute(name[1], m); + } + if (!matchPair.getUnmatches().isEmpty()) { + String u = RouteRule.join(matchPair.getUnmatches()); + model.addAttribute(name[2], u); + } + } + } + model.addAttribute("route", route); + model.addAttribute("methods", CollectionUtils.sort(new ArrayList(providerService.findMethodsByService(route.getService())))); + + return "governance/screen/routes/edit"; + } + + /** + * Save the routing information to the database + * + * @return + */ + + @RequestMapping("/create") + public String create(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "update", "routes"); + boolean success = true; + + String name = request.getParameter("name"); + String service = request.getParameter("service"); + if (StringUtils.isNotEmpty(service) + && StringUtils.isNotEmpty(name)) { + checkService(service); + + Map when_name2valueList = new HashMap(); + Map notWhen_name2valueList = new HashMap(); + for (String[] names : when_names) { + when_name2valueList.put(names[0], request.getParameter(names[1])); + notWhen_name2valueList.put(names[0], request.getParameter(names[2])); // TODO. We should guarantee value is never null in here, will be supported later + } + + Map then_name2valueList = new HashMap(); + Map notThen_name2valueList = new HashMap(); + for (String[] names : then_names) { + then_name2valueList.put(names[0], request.getParameter(names[1])); + notThen_name2valueList.put(names[0], request.getParameter(names[2])); + } + + RouteRule routeRule = RouteRule.createFromNameAndValueListString( + when_name2valueList, notWhen_name2valueList, + then_name2valueList, notThen_name2valueList); + + if (routeRule.getThenCondition().isEmpty()) { + model.addAttribute("message", getMessage("Add route error! then is empty.")); + model.addAttribute("success", false); + model.addAttribute("redirect", "../routes"); + return "governance/screen/redirect"; + } + + String matchRule = routeRule.getWhenConditionString(); + String filterRule = routeRule.getThenConditionString(); + + // Limit the length of the expression + if (matchRule.length() > MAX_RULE_LENGTH) { + model.addAttribute("message", getMessage("When rule is too long!")); + model.addAttribute("success", false); + model.addAttribute("redirect", "../routes"); + return "governance/screen/redirect"; + } + if (filterRule.length() > MAX_RULE_LENGTH) { + model.addAttribute("message", getMessage("Then rule is too long!")); + model.addAttribute("success", false); + model.addAttribute("redirect", "../routes"); + return "governance/screen/redirect"; + } + + Route route = new Route(); + route.setService(service); + route.setName(name); + route.setUsername(request.getParameter("operator")); + route.setOperator(request.getParameter("operatorAddress")); + route.setRule(routeRule.toString()); + if (StringUtils.isNotEmpty(request.getParameter("priority"))) { + route.setPriority(Integer.parseInt(request.getParameter("priority"))); + } + routeService.createRoute(route); + + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../routes"); + return "governance/screen/redirect"; + } + + /** + * Save the update data to the database + * + * @return + */ + @RequestMapping("/{id}/update") + public String update(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "update", "routes"); + boolean success = true; + String idStr = String.valueOf(id); + if (idStr != null && idStr.length() > 0) { + String[] blacks = request.getParameterMap().get("black"); + //String[] blacks = (String[]) context.get("black"); + boolean black = false; + if (blacks != null && blacks.length > 0) { + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../routes"); + return "governance/screen/redirect"; + } + + Route oldRoute = routeService.findRoute(Long.valueOf(idStr)); + if (null == oldRoute) { + model.addAttribute("message", getMessage("NoSuchRecord")); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../routes"); + return "governance/screen/redirect"; + } + // Check parameters, patchwork rule + if (StringUtils.isNotEmpty((String) request.getParameter("name"))) { + String service = oldRoute.getService(); + if (((BindingAwareModelMap)model).get("operator") == null) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", service)); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../routes"); + return "governance/screen/redirect"; + } + + Map when_name2valueList = new HashMap(); + Map notWhen_name2valueList = new HashMap(); + for (String[] names : when_names) { + when_name2valueList.put(names[0], (String) request.getParameter(names[1])); + notWhen_name2valueList.put(names[0], (String) request.getParameter(names[2])); + } + + Map then_name2valueList = new HashMap(); + Map notThen_name2valueList = new HashMap(); + for (String[] names : then_names) { + then_name2valueList.put(names[0], (String) request.getParameter(names[1])); + notThen_name2valueList.put(names[0], (String) request.getParameter(names[2])); + } + + RouteRule routeRule = RouteRule.createFromNameAndValueListString( + when_name2valueList, notWhen_name2valueList, + then_name2valueList, notThen_name2valueList); + + RouteRule result = null; + if (black) { + RouteRule.MatchPair matchPair = routeRule.getThenCondition().get("black"); + Map then = null; + if (null == matchPair) { + matchPair = new RouteRule.MatchPair(); + then = new HashMap(); + then.put("black", matchPair); + } else { + matchPair.getMatches().clear(); + } + matchPair.getMatches().add(String.valueOf(black)); + result = RouteRule.copyWithReplace(routeRule, null, then); + } + + if (result == null) { + result = routeRule; + } + + if (result.getThenCondition().isEmpty()) { + model.addAttribute("message", getMessage("Update route error! then is empty.")); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../routes"); + return "governance/screen/redirect"; + } + + String matchRule = result.getWhenConditionString(); + String filterRule = result.getThenConditionString(); + + // Limit the length of the expression + if (matchRule.length() > MAX_RULE_LENGTH) { + model.addAttribute("message", getMessage("When rule is too long!")); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../routes"); + return "governance/screen/redirect"; + } + if (filterRule.length() > MAX_RULE_LENGTH) { + model.addAttribute("message", getMessage("Then rule is too long!")); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../routes"); + return "governance/screen/redirect"; + } + + int priority = 0; + if (StringUtils.isNotEmpty((String) request.getParameter("priority"))) { + priority = Integer.parseInt((String) request.getParameter("priority")); + } + + Route route = new Route(); + route.setRule(result.toString()); + route.setService(service); + route.setPriority(priority); + route.setName((String) request.getParameter("name")); + route.setUsername((String) request.getParameter("operator")); + route.setOperator((String) request.getParameter("operatorAddress")); + route.setId(Long.valueOf(idStr)); + route.setPriority(Integer.parseInt((String) request.getParameter("priority"))); + route.setEnabled(oldRoute.isEnabled()); + routeService.updateRoute(route); + + Set usernames = new HashSet(); + usernames.add((String) request.getParameter("operator")); + usernames.add(route.getUsername()); + //RelateUserUtils.addOwnersOfService(usernames, route.getService(), ownerDAO); + + Map params = new HashMap(); + params.put("action", "update"); + params.put("route", route); + + } else { + model.addAttribute("message", getMessage("MissRequestParameters", "name")); + } + } else { + model.addAttribute("message", getMessage("MissRequestParameters", "id")); + } + + model.addAttribute("success", success); + model.addAttribute("redirect", "../../routes"); + return "governance/screen/redirect"; + } + + /** + * Remove the route rule for the specified ID + * + * @param ids + * @return + */ + @RequestMapping("/{ids}/delete") + public String delete(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, + Model model) { + prepare(request, response, model, "delete", "routes"); + for (Long id : ids) { + routeService.deleteRoute(id); + } + model.addAttribute("success", true); + model.addAttribute("redirect", "../../routes"); + return "governance/screen/redirect"; + + } + + /** + * Enable the specified route ID rules (batch processing) + * + * @param ids + * @return + */ + @RequestMapping("/{ids}/enable") + public String enable(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, + Model model) { + prepare(request, response, model, "enable", "routes"); + for (Long id : ids) { + routeService.enableRoute(id); + } + model.addAttribute("success", true); + model.addAttribute("redirect", "../../routes"); + return "governance/screen/redirect"; + } + + /** + * Disabling route rules for specified IDs (can be batch processed) + * + * @param ids + * @return + */ + @RequestMapping("/{ids}/disable") + public String disable(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, + Model model) { + prepare(request, response, model, "disable", "routes"); + for (Long id : ids) { + routeService.disableRoute(id); + } + model.addAttribute("success", true); + model.addAttribute("redirect", "../../routes"); + return "governance/screen/redirect"; + } + + /** + * Choose consumers + * + * @param context + */ + public void routeselect(Map context) { + long rid = Long.valueOf((String) context.get("id")); + context.put("id", rid); + + Route route = routeService.findRoute(rid); + if (route == null) { + throw new IllegalStateException("Route(id=" + rid + ") is not existed!"); + } + + context.put("route", route); + // retrieve data + List consumers = consumerService.findByService(route.getService()); + context.put("consumers", consumers); + + Map matchRoute = new HashMap(); + for (Consumer c : consumers) { + matchRoute.put(c.getAddress(), RouteUtils.matchRoute(c.getAddress(), null, route, null)); + } + context.put("matchRoute", matchRoute); + } + + public void preview(Map context) throws Exception { + String rid = (String) context.get("id"); + String consumerid = (String) context.get("cid"); + + + if (StringUtils.isEmpty(rid)) { + context.put("message", getMessage("MissRequestParameters", "id")); + } + + Map serviceUrls = new HashMap(); + Route route = routeService.findRoute(Long.valueOf(rid)); + if (null == route) { + context.put("message", getMessage("NoSuchRecord")); + } + List providers = providerService.findByService(route.getService()); + if (providers != null) { + for (Provider p : providers) { + serviceUrls.put(p.getUrl(), p.getParameters()); + } + } + if (StringUtils.isNotEmpty(consumerid)) { + Consumer consumer = consumerService.findConsumer(Long.valueOf(consumerid)); + if (null == consumer) { + context.put("message", getMessage("NoSuchRecord")); + } + Map result = RouteUtils.previewRoute(consumer.getService(), consumer.getAddress(), consumer.getParameters(), serviceUrls, + route, null, null); + context.put("route", route); + context.put("consumer", consumer); + context.put("result", result); + } else { + String address = (String) context.get("address"); + String service = (String) context.get("service"); + + Map result = RouteUtils.previewRoute(service, address, null, serviceUrls, + route, null, null); + context.put("route", route); + + Consumer consumer = new Consumer(); + consumer.setService(service); + consumer.setAddress(address); + context.put("consumer", consumer); + context.put("result", result); + } + + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ServicesController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ServicesController.java new file mode 100644 index 0000000..8d3f181 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/ServicesController.java @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.governance; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.ConsumerService; +import com.alibaba.dubboadmin.governance.service.OverrideService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.Override; +import com.alibaba.dubboadmin.registry.common.route.OverrideUtils; +import com.alibaba.dubboadmin.web.mvc.BaseController; +import com.alibaba.dubboadmin.web.pulltool.Tool; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.support.BindingAwareModelMap; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * ProvidersController. URI: /services/$service/providers /addresses/$address/services /application/$application/services + * + */ +@Controller +@RequestMapping("/governance/services") +public class ServicesController extends BaseController { + + @Autowired + private ProviderService providerService; + + @Autowired + private ConsumerService consumerService; + + @Autowired + private OverrideService overrideService; + + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "index", "services"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String)newModel.get("service"); + String application = (String)newModel.get("app"); + String address = (String)newModel.get("address"); + String keyword = request.getParameter("keyword"); + + if (service == null + && application == null + && address == null) { + model.addAttribute("service", "*"); + } + + List providerServices = null; + List consumerServices = null; + List overrides = null; + if (application != null && application.length() > 0) { + model.addAttribute("app", application); + providerServices = providerService.findServicesByApplication(application); + consumerServices = consumerService.findServicesByApplication(application); + overrides = overrideService.findByApplication(application); + } else if (address != null && address.length() > 0) { + providerServices = providerService.findServicesByAddress(address); + consumerServices = consumerService.findServicesByAddress(address); + overrides = overrideService.findByAddress(Tool.getIP(address)); + } else { + providerServices = providerService.findServices(); + consumerServices = consumerService.findServices(); + overrides = overrideService.findAll(); + } + + Set services = new TreeSet(); + if (providerServices != null) { + services.addAll(providerServices); + } + if (consumerServices != null) { + services.addAll(consumerServices); + } + + Map> service2Overrides = new HashMap>(); + if (overrides != null && overrides.size() > 0 + && services != null && services.size() > 0) { + for (String s : services) { + if (overrides != null && overrides.size() > 0) { + for (Override override : overrides) { + List serOverrides = new ArrayList(); + if (override.isMatch(s, address, application)) { + serOverrides.add(override); + } + Collections.sort(serOverrides, OverrideUtils.OVERRIDE_COMPARATOR); + service2Overrides.put(s, serOverrides); + } + } + } + } + + model.addAttribute("providerServices", providerServices); + model.addAttribute("consumerServices", consumerServices); + model.addAttribute("services", services); + model.addAttribute("overrides", service2Overrides); + + + if (keyword != null && !"*".equals(keyword)) { + keyword = keyword.toLowerCase(); + Set newList = new HashSet(); + Set newProviders = new HashSet(); + Set newConsumers = new HashSet(); + + for (String o : services) { + if (o.toLowerCase().toLowerCase().indexOf(keyword) != -1) { + newList.add(o); + } + if (o.toLowerCase().toLowerCase().equals(keyword.toLowerCase())) { + service = o; + } + } + for (String o : providerServices) { + if (o.toLowerCase().indexOf(keyword) != -1) { + newProviders.add(o); + } + } + for (String o : consumerServices) { + if (o.toLowerCase().indexOf(keyword) != -1) { + newConsumers.add(o); + } + } + model.addAttribute("services", newList); + model.addAttribute("keyword", keyword); + model.addAttribute("providerServices", newProviders); + model.addAttribute("consumerServices", newConsumers); + } + return "governance/screen/services/index"; + } + + + @RequestMapping("/{ids}/shield") + public String shield(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return mock(ids, "force:return null", "shield", request, response, model); + } + + @RequestMapping("/{ids}/tolerant") + public String tolerant(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return mock(ids, "fail:return null", "tolerant", request, response, model); + } + + @RequestMapping("/{ids}/recover") + public String recover(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + return mock(ids, "", "recover", request, response, model); + } + + private String mock(Long[] ids, String mock, String methodName, HttpServletRequest request, + HttpServletResponse response, Model model) throws Exception { + prepare(request, response, model, methodName, "services"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String services = (String) newModel.get("service"); + String application = (String) newModel.get("app"); + + if (services == null || services.length() == 0 + || application == null || application.length() == 0) { + model.addAttribute("message", getMessage("NoSuchOperationData")); + model.addAttribute("success", false); + model.addAttribute("redirect", "../../services"); + return "governance/screen/redirect"; + } + for (String service : SPACE_SPLIT_PATTERN.split(services)) { + if (!super.currentUser.hasServicePrivilege(service)) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", service)); + model.addAttribute("success", false); + model.addAttribute("redirect", "../../services"); + return "governance/screen/redirect"; + } + } + for (String service : SPACE_SPLIT_PATTERN.split(services)) { + List overrides = overrideService.findByServiceAndApplication(service, application); + if (overrides != null && overrides.size() > 0) { + for (Override override : overrides) { + Map map = StringUtils.parseQueryString(override.getParams()); + if (mock == null || mock.length() == 0) { + map.remove("mock"); + } else { + map.put("mock", URL.encode(mock)); + } + if (map.size() > 0) { + override.setParams(StringUtils.toQueryString(map)); + override.setEnabled(true); + override.setOperator(operator); + override.setOperatorAddress(operatorAddress); + overrideService.updateOverride(override); + } else { + overrideService.deleteOverride(override.getId()); + } + } + } else if (mock != null && mock.length() > 0) { + Override override = new Override(); + override.setService(service); + override.setApplication(application); + override.setParams("mock=" + URL.encode(mock)); + override.setEnabled(true); + override.setOperator(operator); + override.setOperatorAddress(operatorAddress); + overrideService.saveOverride(override); + } + } + model.addAttribute("success", true); + model.addAttribute("redirect", "../../services"); + return "governance/screen/redirect"; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/WeightsController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/WeightsController.java new file mode 100644 index 0000000..d94428a --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/governance/WeightsController.java @@ -0,0 +1,305 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.governance; + +import java.io.BufferedReader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.utils.CollectionUtils; +import com.alibaba.dubboadmin.governance.service.OverrideService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.Provider; +import com.alibaba.dubboadmin.registry.common.domain.Weight; +import com.alibaba.dubboadmin.registry.common.util.OverrideUtils; +import com.alibaba.dubboadmin.web.mvc.BaseController; +import com.alibaba.dubboadmin.web.pulltool.Tool; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.support.BindingAwareModelMap; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * ProvidersController. + * URI: /services/$service/weights + * + */ +@Controller +@RequestMapping("/governance/weights") +public class WeightsController extends BaseController { + + private static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3}$"); + private static final Pattern LOCAL_IP_PATTERN = Pattern.compile("127(\\.\\d{1,3}){3}$"); + private static final Pattern ALL_IP_PATTERN = Pattern.compile("0{1,3}(\\.0{1,3}){3}$"); + @Autowired + private OverrideService overrideService; + @Autowired + private ProviderService providerService; + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "index", "weights"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String)newModel.get("service"); + String address = (String)newModel.get("address"); + service = StringUtils.trimToNull(service); + address = Tool.getIP(address); + List weights; + if (service != null && service.length() > 0) { + weights = OverrideUtils.overridesToWeights(overrideService.findByService(service)); + } else if (address != null && address.length() > 0) { + weights = OverrideUtils.overridesToWeights(overrideService.findByAddress(address)); + } else { + weights = OverrideUtils.overridesToWeights(overrideService.findAll()); + } + model.addAttribute("weights", weights); + return "governance/screen/weights/index"; + } + + /** + * load page for the adding + * + */ + @RequestMapping("/add") + public String add(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "add", "weights"); + BindingAwareModelMap newModel = (BindingAwareModelMap)model; + String service = (String)newModel.get("service"); + String input = request.getParameter("input"); + if (service != null && service.length() > 0 && !service.contains("*")) { + List providerList = providerService.findByService(service); + List addressList = new ArrayList(); + for (Provider provider : providerList) { + addressList.add(provider.getUrl().split("://")[1].split("/")[0]); + } + model.addAttribute("addressList", addressList); + model.addAttribute("service", service); + model.addAttribute("methods", CollectionUtils.sort(providerService.findMethodsByService(service))); + } else { + List serviceList = Tool.sortSimpleName(providerService.findServices()); + model.addAttribute("serviceList", serviceList); + } + if (input != null) model.addAttribute("input", input); + return "governance/screen/weights/add"; + } + + /** + * load page for the multi adding + * + * @param context + */ + public void multiadd(Map context) { + List serviceList = Tool.sortSimpleName(providerService.findServices()); + context.put("serviceList", serviceList); + } + + @RequestMapping("/create") + public String create(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + prepare(request, response, model, "create", "weights"); + String addr = request.getParameter("address"); + String services = request.getParameter("multiservice"); + if (services == null || services.trim().length() == 0) { + services = request.getParameter("service"); + } + String weight = request.getParameter("weight"); + + int w = Integer.parseInt(weight); + + Set addresses = new HashSet(); + BufferedReader reader = new BufferedReader(new StringReader(addr)); + while (true) { + String line = reader.readLine(); + if (null == line) + break; + + String[] split = line.split("[\\s,;]+"); + for (String s : split) { + if (s.length() == 0) + continue; + + String ip = s; + String port = null; + if (s.indexOf(":") != -1) { + ip = s.substring(0, s.indexOf(":")); + port = s.substring(s.indexOf(":") + 1, s.length()); + if (port.trim().length() == 0) port = null; + } + if (!IP_PATTERN.matcher(ip).matches()) { + model.addAttribute("message", "illegal IP: " + s); + model.addAttribute("success", false); + model.addAttribute("redirect", "../weights"); + return "governance/screen/redirect"; + } + if (LOCAL_IP_PATTERN.matcher(ip).matches() || ALL_IP_PATTERN.matcher(ip).matches()) { + model.addAttribute("message", "local IP or any host ip is illegal: " + s); + model.addAttribute("success", false); + model.addAttribute("redirect", "../weights"); + return "governance/screen/redirect"; + } + if (port != null) { + if (!NumberUtils.isDigits(port)) { + model.addAttribute("message", "illegal port: " + s); + model.addAttribute("success", false); + model.addAttribute("redirect", "../weights"); + return "governance/screen/redirect"; + } + } + addresses.add(s); + } + } + + Set aimServices = new HashSet(); + reader = new BufferedReader(new StringReader(services)); + while (true) { + String line = reader.readLine(); + if (null == line) + break; + + String[] split = line.split("[\\s,;]+"); + for (String s : split) { + if (s.length() == 0) + continue; + if (!super.currentUser.hasServicePrivilege(s)) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", s)); + model.addAttribute("success", false); + model.addAttribute("redirect", "../weights"); + return "governance/screen/redirect"; + } + aimServices.add(s); + } + } + + for (String aimService : aimServices) { + for (String a : addresses) { + Weight wt = new Weight(); + wt.setUsername((String) ((BindingAwareModelMap)model).get("operator")); + wt.setAddress(Tool.getIP(a)); + wt.setService(aimService); + wt.setWeight(w); + overrideService.saveOverride(OverrideUtils.weightToOverride(wt)); + } + } + model.addAttribute("success", true); + model.addAttribute("redirect", "../weights"); + return "governance/screen/redirect"; + } + + @RequestMapping("/{id}/edit") + public String edit(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "edit", "weights"); + String service = request.getParameter("service"); + String input = request.getParameter("input"); + + if (service != null && service.length() > 0 && !service.contains("*")) { + List providerList = providerService.findByService(service); + List addressList = new ArrayList(); + for (Provider provider : providerList) { + addressList.add(provider.getUrl().split("://")[1].split("/")[0]); + } + model.addAttribute("addressList", addressList); + model.addAttribute("service", service); + model.addAttribute("methods", CollectionUtils.sort(providerService.findMethodsByService(service))); + } else { + List serviceList = Tool.sortSimpleName(providerService.findServices()); + model.addAttribute("serviceList", serviceList); + } + if (input != null) model.addAttribute("input", input); + Weight weight = OverrideUtils.overrideToWeight(overrideService.findById(id)); + model.addAttribute("weight", weight); + model.addAttribute("service", overrideService.findById(id).getService()); + return "governance/screen/weights/edit"; + } + + //public void sameSeviceEdit(Long id, Map context) { + // add(context); + // show(id, context); + //} + + /** + * load weight for editing + * + * @param id + + */ + @RequestMapping("/{id}") + public String show(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "show", "weights"); + Weight weight = OverrideUtils.overrideToWeight(overrideService.findById(id)); + model.addAttribute("weight", weight); + return "governance/screen/weights/show"; + } + + @RequestMapping(value = "/update", method = RequestMethod.POST) //post + public String update(Weight weight, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "update", "weights"); + boolean success = true; + if (!super.currentUser.hasServicePrivilege(weight.getService())) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", weight.getService())); + success = false; + } else { + weight.setAddress(Tool.getIP(weight.getAddress())); + overrideService.updateOverride(OverrideUtils.weightToOverride(weight)); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "governance/weights"); + return "governance/screen/redirect"; + } + + /** + * delete + * + * @param ids + * @return + */ + @RequestMapping("/{ids}/delete") + public String delete(@PathVariable("ids") Long[] ids, HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "delete", "weights"); + boolean success = true; + for (Long id : ids) { + Weight w = OverrideUtils.overrideToWeight(overrideService.findById(id)); + if (!super.currentUser.hasServicePrivilege(w.getService())) { + model.addAttribute("message", getMessage("HaveNoServicePrivilege", w.getService())); + success = false; + model.addAttribute("success", success); + model.addAttribute("redirect", "../../weights"); + return "governance/screen/redirect"; + } + } + + for (Long id : ids) { + overrideService.deleteOverride(id); + } + model.addAttribute("success", success); + model.addAttribute("redirect", "../../weights"); + return "governance/screen/redirect"; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/DisableController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/DisableController.java new file mode 100644 index 0000000..14453a3 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/DisableController.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.home; + +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.Provider; + +import org.springframework.beans.factory.annotation.Autowired; + +public class DisableController extends ShellController { + + @Autowired + private ProviderService providerService; + + @Autowired + private HttpServletRequest request; + + public void setProviderDAO(ProviderService providerDAO) { + this.providerService = providerDAO; + } + + protected String doExecute(Map context) throws Exception { + String address = request.getParameter("provider"); + if (address == null || address.length() == 0) { + address = request.getParameter("client"); + } + if (address == null || address.length() == 0) { + throw new IllegalArgumentException("The url provider parameter is null! Usage: " + request.getRequestURL().toString() + "?provider=" + operatorAddress); + } + List providers = providerService.findByAddress(address); + if (providers != null && providers.size() > 0) { + for (Provider provider : providers) { + if (!currentUser.hasServicePrivilege(provider.getService())) { + throw new IllegalStateException("The user " + currentUser.getUsername() + " have no privilege of service " + provider.getService()); + } + } + for (Provider provider : providers) { + provider.setUsername(operator); + provider.setOperatorAddress(operatorAddress); + providerService.disableProvider(provider.getId()); + } + } + return "DisableController " + (providers == null ? 0 : providers.size()) + " services."; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/IndexController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/IndexController.java new file mode 100644 index 0000000..b6bb565 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/IndexController.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.dubboadmin.web.mvc.home; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubboadmin.governance.service.ConsumerService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.governance.util.WebConstants; +import com.alibaba.dubboadmin.registry.common.domain.Consumer; +import com.alibaba.dubboadmin.registry.common.domain.Provider; +import com.alibaba.dubboadmin.web.pulltool.RootContextPath; +import com.alibaba.dubboadmin.web.pulltool.Tool; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class IndexController { + + private static final Logger logger = LoggerFactory.getLogger(IndexController.class); + @Autowired + private ProviderService providerService; + + @Autowired + private ConsumerService consumerService; + + @RequestMapping("/") + public String indexRequest(HttpServletRequest request, Model model) { + Set applications = new HashSet(); + Set services = new HashSet(); + List pList = new ArrayList(); + try { + pList = providerService.findAll(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + for (Provider p : pList) { + applications.add(p.getApplication()); + services.add(p.getService()); + } + List cList = new ArrayList(); + try { + cList = consumerService.findAll(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + for (Consumer c : cList) { + applications.add(c.getApplication()); + services.add(c.getService()); + } + model.addAttribute("rootContextPath", new RootContextPath(request.getContextPath())); + model.addAttribute("services", services.size()); + model.addAttribute("providers", pList.size()); + model.addAttribute("consumers", cList.size()); + model.addAttribute("applications", applications.size()); + model.addAttribute("helpUrl", WebConstants.HELP_URL); + model.addAttribute("tool", new Tool()); + return "home/screen/index"; + + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/LookupController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/LookupController.java new file mode 100644 index 0000000..df8a795 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/LookupController.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.home; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.registry.RegistryService; +import com.alibaba.dubboadmin.governance.service.ConsumerService; + +import org.springframework.beans.factory.annotation.Autowired; + +public class LookupController extends RestfulController { + + @Autowired + ConsumerService consumerDAO; + + @Autowired + private RegistryService registryService; + + public ResultController doExecute(Map context) throws Exception { + String inf = request.getParameter("interface"); + if (inf == null || inf.isEmpty()) { + throw new IllegalArgumentException("please give me the interface"); + } + String group = null; + if (inf.contains("/")) { + int idx = inf.indexOf('/'); + group = inf.substring(idx); + inf = inf.substring(idx + 1, inf.length()); + } + String version = null; + if (inf.contains(":")) { + int idx = inf.lastIndexOf(':'); + version = inf.substring(idx + 1, inf.length()); + inf = inf.substring(idx); + } + + String parameters = request.getParameter("parameters"); + String url = "subscribe://" + operatorAddress + "/" + request.getParameter("interface"); + if (parameters != null && parameters.trim().length() > 0) { + url += parameters.trim(); + } + + URL u = URL.valueOf(url); + if (group != null) { + u.addParameter("group", group); + } + + if (version != null) u.addParameter("version", version); + + List lookup = registryService.lookup(u); + + Map> serviceUrl = new HashMap>(); + Map urls = new HashMap(); + serviceUrl.put(request.getParameter("interface").trim(), urls); + + for (URL u2 : lookup) { + urls.put(u2.toIdentityString(), u2.toParameterString()); + } + + ResultController resultController = new ResultController(); + resultController.setMessage(serviceUrl); + return resultController; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/RegController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/RegController.java new file mode 100644 index 0000000..cf967a4 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/RegController.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.home; + +import java.util.HashMap; +import java.util.Map; + +public class RegController extends RestfulController { + + public ResultController doExecute(Map context) throws Exception { + if (url == null) { + throw new IllegalArgumentException("please give me the url"); + } + if (url.getPath().isEmpty()) { + throw new IllegalArgumentException("please use interface as your url path"); + } + Map tmp = new HashMap(); + tmp.put(url.toIdentityString(), url.toParameterString()); + Map> register = new HashMap>(); + register.put(url.getPath(), tmp); +// Map> newRegister = RegistryUtils.convertRegister(register); +// registryService.register(operatorAddress, newRegister, false); + ResultController resultController = new ResultController(); + resultController.setMessage("RegisterController Successfully!"); + return resultController; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/RegisterController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/RegisterController.java new file mode 100644 index 0000000..fdcc59d --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/RegisterController.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.home; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import com.alibaba.dubbo.common.utils.CollectionUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.ProviderService; + +import org.springframework.beans.factory.annotation.Autowired; + +public class RegisterController extends ShellController { + + @Autowired + private ProviderService providerDAO; + + @Autowired + private HttpServletRequest request; + +// @Autowired +// private RegistryCache registryCache; + + @SuppressWarnings("unchecked") + protected String doExecute(Map context) throws Exception { + Map params = request.getParameterMap(); + if (params == null || params.size() == 0) { + throw new IllegalArgumentException("The url parameters is null! Usage: " + request.getRequestURL().toString() + "?com.xxx.XxxService=http://" + request.getRemoteAddr() + "/xxxService?application=xxx&foo1=123"); + } + Map> map = new HashMap>(); + for (Map.Entry entry : params.entrySet()) { + if (entry.getKey() != null && entry.getKey().length() > 0 + && entry.getValue() != null && entry.getValue().length > 0 + && entry.getValue()[0] != null && entry.getValue()[0].length() > 0) { + if (!currentUser.hasServicePrivilege(entry.getKey())) { + throw new IllegalStateException("The user " + currentUser.getUsername() + " have no privilege of service " + entry.getKey()); + } + String serviceName = entry.getKey(); + Map url2query = CollectionUtils.split(Arrays.asList(entry.getValue()), "?"); + // check whether url contain application info + for (Map.Entry e : url2query.entrySet()) { + Map query = StringUtils.parseQueryString(e.getValue()); + String app = query.get("application"); + if (StringUtils.isBlank(app)) { + throw new IllegalStateException("No application for service(" + serviceName + "): " + + e.getKey() + "?" + e.getValue()); + } + } + map.put(serviceName, url2query); + } + } + if (map.size() > 0) { +// providerDAO.register(registryCache.getCurrentRegistry(), request.getRemoteAddr(), operatorAddress, operator, map, false, true); + } + return "RegisterController " + map.size() + " services."; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/RestfulController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/RestfulController.java new file mode 100644 index 0000000..f9c208f --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/RestfulController.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.home; + +import java.util.Map; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubboadmin.governance.util.WebConstants; +import com.alibaba.dubboadmin.registry.common.domain.User; +import com.alibaba.fastjson.JSON; + +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class RestfulController { + + protected String role = null; + protected String operator = null; + + // @Autowired +// RegistryValidator registryService; + protected User currentUser = null; + protected String operatorAddress = null; + protected URL url = null; + @Autowired + HttpServletRequest request; + @Autowired + private HttpServletResponse response; + + public void execute(Map context) throws Exception { + ResultController resultController = new ResultController(); + if (request.getParameter("url") != null) { + url = URL.valueOf(URL.decode(request.getParameter("url"))); + } + if (context.get(WebConstants.CURRENT_USER_KEY) != null) { + User user = (User) context.get(WebConstants.CURRENT_USER_KEY); + currentUser = user; + operator = user.getUsername(); + role = user.getRole(); + context.put(WebConstants.CURRENT_USER_KEY, user); + } + operatorAddress = (String) context.get("clientid"); + if (operatorAddress == null || operatorAddress.isEmpty()) { + operatorAddress = (String) context.get("request.remoteHost"); + } + context.put("operator", operator); + context.put("operatorAddress", operatorAddress); + String jsonResult = null; + try { + resultController = doExecute(context); + resultController.setStatus("OK"); + } catch (IllegalArgumentException t) { + resultController.setStatus("ERROR"); + resultController.setCode(3); + resultController.setMessage(t.getMessage()); + } +// catch (InvalidRequestException t) { +// resultController.setStatus("ERROR"); +// resultController.setCode(2); +// resultController.setMessage(t.getMessage()); +// } + catch (Throwable t) { + resultController.setStatus("ERROR"); + resultController.setCode(1); + resultController.setMessage(t.getMessage()); + } + response.setContentType("application/javascript"); + ServletOutputStream os = response.getOutputStream(); + try { + jsonResult = JSON.toJSONString(resultController); + os.print(jsonResult); + } catch (Exception e) { + response.setStatus(500); + os.print(e.getMessage()); + } finally { + os.flush(); + } + } + + protected abstract ResultController doExecute(Map context) throws Exception; + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/ResultController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/ResultController.java new file mode 100644 index 0000000..6b5e667 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/ResultController.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.home; + +import java.io.Serializable; + +public class ResultController implements Serializable { + + private static final long serialVersionUID = 4922467873471920132L; + private String status; + private Object message; + private int code; + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Object getMessage() { + return message; + } + + public void setMessage(Object message) { + this.message = message; + } + + public int getCode() { + return code; + } + + + public void setCode(int code) { + this.code = code; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + code; + result = prime * result + ((message == null) ? 0 : message.hashCode()); + result = prime * result + ((status == null) ? 0 : status.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + ResultController other = (ResultController) obj; + if (code != other.code) return false; + if (message == null) { + if (other.message != null) return false; + } else if (!message.equals(other.message)) return false; + if (status == null) { + if (other.status != null) return false; + } else if (!status.equals(other.status)) return false; + return true; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/ServicestatusController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/ServicestatusController.java new file mode 100644 index 0000000..4aacb22 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/ServicestatusController.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.home; + +import java.io.PrintWriter; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubboadmin.governance.service.ProviderService; + +import org.springframework.beans.factory.annotation.Autowired; + +public class ServicestatusController { +// @Autowired +// private RegistryCache registryCache; + + @Autowired + private HttpServletRequest request; + + @Autowired + private ProviderService providerDAO; + + @Autowired + private HttpServletResponse response; + + public void execute(Map context) throws Exception { + String uri = request.getRequestURI(); + String contextPath = request.getContextPath(); + if (contextPath != null && !"/".equals(contextPath)) { + uri = uri.substring(contextPath.length()); + } + if (uri.startsWith("/status/")) { + uri = uri.substring("/status/".length()); + } +// Map providers = registryCache.getServices().get(uri); +// if (providers == null || providers.size() == 0) { +// providers = providerDAO.lookup(uri); +// } +// if (providers == null || providers.size() == 0) { +// context.put("message", "ERROR" +// + new SimpleDateFormat(" [yyyy-MM-dd HH:mm:ss] ").format(new Date()) +// + StatusController.filterOK("No such any provider for service " + uri)); +// } else { +// context.put("message", "OK"); +// } + PrintWriter writer = response.getWriter(); + writer.print(context.get("message").toString()); + writer.flush(); + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/ShellController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/ShellController.java new file mode 100644 index 0000000..06cc90e --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/ShellController.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.home; + +import java.io.PrintWriter; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubboadmin.governance.util.WebConstants; +import com.alibaba.dubboadmin.registry.common.domain.User; + +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class ShellController { + private static final Pattern OK_PATTERN = Pattern.compile("ok", Pattern.CASE_INSENSITIVE); + private static final Pattern ERROR_PATTERN = Pattern.compile("error", Pattern.CASE_INSENSITIVE); + protected String role = null; + protected String operator = null; + protected User currentUser = null; + protected String operatorAddress = null; + @Autowired + private HttpServletResponse response; + + private static String filterOK(String value) { + if (value == null || value.length() == 0) { + return value; + } + return OK_PATTERN.matcher(value).replaceAll("0k"); + } + + private static String filterERROR(String value) { + if (value == null || value.length() == 0) { + return value; + } + return ERROR_PATTERN.matcher(value).replaceAll("err0r"); + } + + public void execute(Map context) throws Exception { + if (context.get(WebConstants.CURRENT_USER_KEY) != null) { + User user = (User) context.get(WebConstants.CURRENT_USER_KEY); + currentUser = user; + operator = user.getUsername(); + role = user.getRole(); + context.put(WebConstants.CURRENT_USER_KEY, user); + } + operatorAddress = (String) context.get("request.remoteHost"); + context.put("operator", operator); + context.put("operatorAddress", operatorAddress); + try { + String message = doExecute(context); + context.put("message", "OK: " + filterERROR(message)); + } catch (Throwable t) { + context.put("message", "ERROR: " + filterOK(t.getMessage())); + } + PrintWriter writer = response.getWriter(); + writer.print(context.get("message")); + writer.flush(); + } + + protected abstract String doExecute(Map context) throws Exception; + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/StatusController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/StatusController.java new file mode 100644 index 0000000..fabeff7 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/StatusController.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.home; + +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.Date; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.status.Status.Level; +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubboadmin.registry.common.StatusManager; + +import org.springframework.beans.factory.annotation.Autowired; + +public class StatusController { + private static final Pattern OK_PATTERN = Pattern.compile("o(k)", Pattern.CASE_INSENSITIVE); + @Autowired + private HttpServletResponse response; + + public static String filterOK(String message) { + if (message == null) + return ""; + // Avoid the ok keyword, use the number 0 instead of the letter o + return OK_PATTERN.matcher(message).replaceAll("0$1"); + } + + public void execute(Map context) throws Exception { + //FIXME cache monitoring has bad performance, should be removed from summary page. + Map + statuses = StatusManager.getInstance().getStatusList(new String[]{"cache"}); + com.alibaba.dubbo.common.status.Status status = StatusManager.getInstance().getStatusSummary(statuses); + Level level = status.getLevel(); + if (!com.alibaba.dubbo.common.status.Status.Level.OK.equals(level)) { + context.put("message", level + + new SimpleDateFormat(" [yyyy-MM-dd HH:mm:ss] ").format(new Date()) + + filterOK(status.getMessage())); + } else { + context.put("message", level.toString()); + } + PrintWriter writer = response.getWriter(); + writer.print(context.get("message").toString()); + writer.flush(); + } + + public void setStatusHandlers(Collection statusHandlers) { + StatusManager.getInstance().addStatusHandlers(statusHandlers); + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/UnregController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/UnregController.java new file mode 100644 index 0000000..3f76318 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/UnregController.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.home; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * UnReg.java + * + */ +public class UnregController extends RestfulController { + + public ResultController doExecute(Map context) throws Exception { + if (url == null) { + throw new IllegalArgumentException("please give me the url"); + } + if (url.getPath().isEmpty()) { + throw new IllegalArgumentException("please use interface as your url path"); + } + HashMap> services = new HashMap>(); + Set serviceUrl = new HashSet(); + serviceUrl.add(url.toIdentityString()); + String name = url.getPath(); + String version = url.getParameter("version"); + if (version != null) { + name = name + ":" + version; + } + String group = url.getParameter("group"); + if (group != null) { + name = group + "/" + name; + } + services.put(name, serviceUrl); +// registryService.unregister(operatorAddress,services); + ResultController resultController = new ResultController(); + resultController.setMessage("UnregisterController Successfully!"); + return resultController; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/UnregisterController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/UnregisterController.java new file mode 100644 index 0000000..aae1858 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/UnregisterController.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.home; + +import java.util.Arrays; +import java.util.Map; +import java.util.Map.Entry; + +import javax.servlet.http.HttpServletRequest; + +import com.alibaba.dubbo.common.utils.CollectionUtils; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.Provider; + +import org.springframework.beans.factory.annotation.Autowired; + +public class UnregisterController extends ShellController { + + @Autowired + private ProviderService providervice; + + @Autowired + private HttpServletRequest request; + + @SuppressWarnings("unchecked") + protected String doExecute(Map context) throws Exception { + Map params = request.getParameterMap(); + if (params == null || params.size() == 0) { + throw new IllegalArgumentException("The url parameters is null! Usage: " + request.getRequestURL().toString() + "?com.xxx.XxxService=http://" + operatorAddress + "/xxxService"); + } + for (Map.Entry entry : params.entrySet()) { + if (entry.getKey() != null && entry.getKey().length() > 0 + && entry.getValue() != null && entry.getValue().length > 0 + && entry.getValue()[0] != null && entry.getValue()[0].length() > 0) { + if (!currentUser.hasServicePrivilege(entry.getKey())) { + throw new IllegalStateException("The user " + operator + " have no privilege of service " + entry.getKey()); + } + for (Entry e : CollectionUtils.split(Arrays.asList(entry.getValue()), "?").entrySet()) { + Provider provider = providervice.findByServiceAndAddress(entry.getKey(), e.getKey()); + if (provider != null) { + providervice.deleteStaticProvider(provider.getId()); + } + } + } + } + + return "UnregisterController " + params.size() + " services."; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/UnregisterallController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/UnregisterallController.java new file mode 100644 index 0000000..d4138c1 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/home/UnregisterallController.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.home; + +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.Provider; + +import org.springframework.beans.factory.annotation.Autowired; + +public class UnregisterallController extends ShellController { + + @Autowired + private ProviderService providerService; + + @Autowired + private HttpServletRequest request; + + protected String doExecute(Map context) throws Exception { + String address = request.getParameter("provider"); + if (address == null || address.length() == 0) { + address = request.getParameter("client"); + } + if (address == null || address.length() == 0) { + throw new IllegalArgumentException("The url provider parameter is null! Usage: " + request.getRequestURL().toString() + "?provider=" + operatorAddress); + } + List providers = providerService.findByAddress(address); + if (providers != null && providers.size() > 0) { + for (Provider provider : providers) { + if (!currentUser.hasServicePrivilege(provider.getService())) { + throw new IllegalStateException("The user " + currentUser + " have no privilege of service " + provider.getService()); + } + } + for (Provider provider : providers) { + provider.setUsername(operator); + provider.setOperatorAddress(operatorAddress); + providerService.deleteStaticProvider(provider.getId()); + } + } + return "UnregisterController " + (providers == null ? 0 : providers.size()) + " services."; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/personal/InfosController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/personal/InfosController.java new file mode 100644 index 0000000..e7808a2 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/personal/InfosController.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.personal; + +import java.util.Map; + +import com.alibaba.dubboadmin.governance.service.UserService; +import com.alibaba.dubboadmin.registry.common.domain.User; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.beans.factory.annotation.Autowired; + +public class InfosController extends BaseController { + @Autowired + private UserService userDAO; + + public void index(Map context) { + User user = userDAO.findById(currentUser.getId()); + context.put("user", user); + } + + public boolean update(Map context) { + User user = new User(); + user.setId(currentUser.getId()); + user.setUsername(currentUser.getUsername()); + user.setOperatorAddress(operatorAddress); + user.setName((String) context.get("name")); + user.setDepartment((String) context.get("department")); + user.setEmail((String) context.get("email")); + user.setPhone((String) context.get("phone")); + user.setAlitalk((String) context.get("alitalk")); + user.setLocale((String) context.get("locale")); + userDAO.modifyUser(user); + context.put("redirect", "../" + getClass().getSimpleName().toLowerCase()); + return true; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/personal/PasswdsController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/personal/PasswdsController.java new file mode 100644 index 0000000..6dfcd6a --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/personal/PasswdsController.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.personal; + +import java.util.Map; + +import com.alibaba.dubboadmin.governance.service.UserService; +import com.alibaba.dubboadmin.registry.common.domain.User; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.beans.factory.annotation.Autowired; + +public class PasswdsController extends BaseController { + + @Autowired + private UserService userDAO; + + public void index(Map context) { + + } + + public boolean create(Map context) { + User user = new User(); + user.setOperator(operator); + user.setOperatorAddress(operatorAddress); + user.setPassword((String) context.get("newPassword")); + user.setUsername(operator); + + boolean sucess = userDAO.updatePassword(user, (String) context.get("oldPassword")); + if (!sucess) + context.put("message", getMessage("passwd.oldwrong")); + return sucess; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/DumpController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/DumpController.java new file mode 100644 index 0000000..64cfae3 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/DumpController.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.sysinfo; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.ConsumerService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.Consumer; +import com.alibaba.dubboadmin.registry.common.domain.Provider; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/sysinfo/dump") +public class DumpController extends BaseController { + + @Autowired + ProviderService providerDAO; + + @Autowired + ConsumerService consumerDAO; + + + @RequestMapping("/noProviders") + public void noProviders(HttpServletRequest request, HttpServletResponse response, Model model) throws IOException { + prepare(request, response, model, "noProviders", "dump"); + PrintWriter writer = response.getWriter(); + List sortedService = getNoProviders(); + Collections.sort(sortedService); + writer.println(sortedService.size() + " services don't have provider"); + for (String noProvider : sortedService) { + writer.println(noProvider); + } + writer.flush(); + response.setContentType("text/plain"); + } + + @RequestMapping("/services") + public void services(HttpServletRequest request, HttpServletResponse response, Model model) throws IOException { + prepare(request, response, model, "noProviders", "services"); + PrintWriter writer = response.getWriter(); + List sortedService = providerDAO.findServices(); + Collections.sort(sortedService); + writer.println(sortedService.size() + " services"); + for (String service : sortedService) { + writer.println(service + (providerDAO.findByService(service).size())); + } + writer.flush(); + response.setContentType("text/plain"); + } + + @RequestMapping("/providers") + public void providers(HttpServletRequest request, HttpServletResponse response, Model model) throws IOException { + PrintWriter writer = response.getWriter(); + List providers = providerDAO.findAll(); + List sortedProviders = new ArrayList(); + for (Provider provider : providers) { + sortedProviders.add(provider.getUrl() + " " + provider.getService()); + } + Collections.sort(sortedProviders); + writer.println(sortedProviders.size() + " provider instance"); + for (String provider : sortedProviders) { + writer.println(provider); + } + writer.flush(); + response.setContentType("text/plain"); + } + + @RequestMapping("/consumers") + public void consumers(HttpServletRequest request, HttpServletResponse response, Model model) throws IOException { + PrintWriter writer = response.getWriter(); + List consumers = consumerDAO.findAll(); + List sortedConsumerss = new ArrayList(); + for (Consumer consumer : consumers) { + sortedConsumerss.add(consumer.getAddress() + " " + consumer.getService()); + } + Collections.sort(sortedConsumerss); + writer.println(sortedConsumerss.size() + " consumer instance"); + for (String consumer : sortedConsumerss) { + writer.println(consumer); + } + writer.flush(); + response.setContentType("text/plain"); + } + + @RequestMapping("/versions") + public void versions(HttpServletRequest request, HttpServletResponse response, Model model) throws IOException { + PrintWriter writer = response.getWriter(); + List providers = providerDAO.findAll(); + List consumers = consumerDAO.findAll(); + Set parametersSet = new HashSet(); + Map> versions = new HashMap>(); + for (Provider provider : providers) { + parametersSet.add(provider.getParameters()); + } + for (Consumer consumer : consumers) { + parametersSet.add(consumer.getParameters()); + } + Iterator temp = parametersSet.iterator(); + while (temp.hasNext()) { + Map parameter = StringUtils.parseQueryString(temp.next()); + if (parameter != null) { + String dubboversion = parameter.get("dubbo"); + String app = parameter.get("application"); + if (versions.get(dubboversion) == null) { + Set apps = new HashSet(); + versions.put(dubboversion, apps); + } + versions.get(dubboversion).add(app); + } + } + for (String version : versions.keySet()) { + writer.println("dubbo version: " + version); + writer.println(StringUtils.join(versions.get(version), "\n")); + writer.println("\n"); + } + model.addAttribute("versions", versions); + writer.flush(); + response.setContentType("text/plain"); + } + + private List getNoProviders() { + List providerServices = providerDAO.findServices(); + List consumerServices = consumerDAO.findServices(); + List noProviderServices = new ArrayList(); + if (consumerServices != null) { + noProviderServices.addAll(consumerServices); + noProviderServices.removeAll(providerServices); + } + return noProviderServices; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/DumpsController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/DumpsController.java new file mode 100644 index 0000000..d7b4ff0 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/DumpsController.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.sysinfo; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubboadmin.governance.service.ConsumerService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/sysinfo/dumps") +public class DumpsController extends BaseController { + + @Autowired + ProviderService providerDAO; + + @Autowired + ConsumerService consumerDAO; + + @Autowired + HttpServletResponse response; + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "index", "dumps"); + model.addAttribute("noProviderServices", getNoProviders()); + model.addAttribute("services", providerDAO.findServices()); + model.addAttribute("providers", providerDAO.findAll()); + model.addAttribute("consumers", consumerDAO.findAll()); + return "sysinfo/screen/dumps/index"; + } + + private List getNoProviders() { + List providerServices = providerDAO.findServices(); + List consumerServices = consumerDAO.findServices(); + List noProviderServices = new ArrayList(); + if (consumerServices != null) { + noProviderServices.addAll(consumerServices); + noProviderServices.removeAll(providerServices); + } + return noProviderServices; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/EnvsController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/EnvsController.java new file mode 100644 index 0000000..839b413 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/EnvsController.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.sysinfo; + +import java.lang.management.ManagementFactory; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/sysinfo/envs") +public class EnvsController extends BaseController { + + private static final long SECOND = 1000; + private static final long MINUTE = 60 * SECOND; + private static final long HOUR = 60 * MINUTE; + private static final long DAY = 24 * HOUR; + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + prepare(request, response, model, "index", "envs"); + Map properties = new TreeMap(); + StringBuilder msg = new StringBuilder(); + msg.append("Version: "); + msg.append(Version.getVersion(EnvsController.class, "2.2.0")); + properties.put("Registry", msg.toString()); + String address = NetUtils.getLocalHost(); + properties.put("Host", NetUtils.getHostName(address) + "/" + address); + properties.put("Java", System.getProperty("java.runtime.name") + " " + System.getProperty("java.runtime.version")); + properties.put("OS", System.getProperty("os.name") + " " + + System.getProperty("os.version")); + properties.put("CPU", System.getProperty("os.arch", "") + ", " + + String.valueOf(Runtime.getRuntime().availableProcessors()) + " cores"); + properties.put("Locale", Locale.getDefault().toString() + "/" + + System.getProperty("file.encoding")); + properties.put("Uptime", formatUptime(ManagementFactory.getRuntimeMXBean().getUptime()) + + " From " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z").format(new Date( + ManagementFactory.getRuntimeMXBean().getStartTime())) + + " To " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z").format(new Date())); + model.addAttribute("properties", properties); + return "sysinfo/screen/envs/index"; + } + + private String formatUptime(long uptime) { + StringBuilder buf = new StringBuilder(); + if (uptime > DAY) { + long days = (uptime - uptime % DAY) / DAY; + buf.append(days); + buf.append(" Days"); + uptime = uptime % DAY; + } + if (uptime > HOUR) { + long hours = (uptime - uptime % HOUR) / HOUR; + if (buf.length() > 0) { + buf.append(", "); + } + buf.append(hours); + buf.append(" Hours"); + uptime = uptime % HOUR; + } + if (uptime > MINUTE) { + long minutes = (uptime - uptime % MINUTE) / MINUTE; + if (buf.length() > 0) { + buf.append(", "); + } + buf.append(minutes); + buf.append(" Minutes"); + uptime = uptime % MINUTE; + } + if (uptime > SECOND) { + long seconds = (uptime - uptime % SECOND) / SECOND; + if (buf.length() > 0) { + buf.append(", "); + } + buf.append(seconds); + buf.append(" Seconds"); + uptime = uptime % SECOND; + } + if (uptime > 0) { + if (buf.length() > 0) { + buf.append(", "); + } + buf.append(uptime); + buf.append(" Milliseconds"); + } + return buf.toString(); + } + + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/LogsController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/LogsController.java new file mode 100644 index 0000000..0e24af4 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/LogsController.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.sysinfo; + +import java.io.File; +import java.io.FileInputStream; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.logger.Level; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubboadmin.registry.common.domain.User; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/sysinfo/logs") +public class LogsController extends BaseController { + + private static final int SHOW_LOG_LENGTH = 30000; + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + prepare(request, response, model, "index", "logs"); + long size; + String content; + String modified; + File file = LoggerFactory.getFile(); + if (file != null && file.exists()) { + FileInputStream fis = new FileInputStream(file); + FileChannel channel = fis.getChannel(); + size = channel.size(); + ByteBuffer bb; + if (size <= SHOW_LOG_LENGTH) { + bb = ByteBuffer.allocate((int) size); + channel.read(bb, 0); + } else { + int pos = (int) (size - SHOW_LOG_LENGTH); + bb = ByteBuffer.allocate(SHOW_LOG_LENGTH); + channel.read(bb, pos); + } + bb.flip(); + content = new String(bb.array()).replace("<", "<").replace(">", ">"); + modified = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(file.lastModified())); + } else { + size = 0; + content = ""; + modified = "Not exist"; + } + Level level = LoggerFactory.getLevel(); + model.addAttribute("name", file == null ? "" : file.getAbsoluteFile()); + model.addAttribute("size", String.valueOf(size)); + model.addAttribute("level", level == null ? "" : level); + model.addAttribute("modified", modified); + model.addAttribute("content", content); + return "sysinfo/screen/logs/index"; + } + + public boolean change(Map context) throws Exception { + String contextLevel = (String) context.get("level"); + if (contextLevel == null || contextLevel.length() == 0) { + context.put("message", getMessage("MissRequestParameters", "level")); + return false; + } + if (!User.ROOT.equals(role)) { + context.put("message", getMessage("HaveNoRootPrivilege")); + return false; + } + Level level = Level.valueOf(contextLevel); + if (level != LoggerFactory.getLevel()) { + LoggerFactory.setLevel(level); + } + context.put("redirect", "/sysinfo/logs"); + return true; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/StatusesController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/StatusesController.java new file mode 100644 index 0000000..ad2b2fb --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/StatusesController.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.sysinfo; + +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.extension.ExtensionLoader; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubboadmin.registry.common.StatusManager; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/sysinfo/statuses") +public class StatusesController extends BaseController { + + @RequestMapping("") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + + prepare(request, response, model, "index", "status"); + ExtensionLoader loader = ExtensionLoader.getExtensionLoader(StatusChecker.class); + Map statusList = new LinkedHashMap(); + for (String name : loader.getSupportedExtensions()) { + com.alibaba.dubbo.common.status.Status status = loader.getExtension(name).check(); + if (status.getLevel() != null && status.getLevel() != com.alibaba.dubbo.common.status.Status.Level.UNKNOWN) { + statusList.put(name, status); + } + } + statusList.put("summary", StatusManager.getStatusSummary(statusList)); + model.addAttribute("statusList", statusList); + return "sysinfo/screen/statuses/index"; + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/VersionsController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/VersionsController.java new file mode 100644 index 0000000..711d2ff --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysinfo/VersionsController.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.sysinfo; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.ConsumerService; +import com.alibaba.dubboadmin.governance.service.ProviderService; +import com.alibaba.dubboadmin.registry.common.domain.Consumer; +import com.alibaba.dubboadmin.registry.common.domain.Provider; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/sysinfo") +public class VersionsController extends BaseController { + @Autowired + private ProviderService providerService; + + @Autowired + private ConsumerService consumerService; + + @RequestMapping("/versions") + public String index(HttpServletRequest request, HttpServletResponse response, Model model) { + prepare(request, response, model, "index", "versions"); + List providers = providerService.findAll(); + List consumers = consumerService.findAll(); + Set parametersSet = new HashSet(); + for (Provider provider : providers) { + parametersSet.add(provider.getParameters()); + } + for (Consumer consumer : consumers) { + parametersSet.add(consumer.getParameters()); + } + Map> versions = new HashMap>(); + Iterator temp = parametersSet.iterator(); + while (temp.hasNext()) { + Map parameter = StringUtils.parseQueryString(temp.next()); + if (parameter != null) { + String dubbo = parameter.get("dubbo"); + if (dubbo == null) dubbo = "0.0.0"; + String application = parameter.get("application"); + if (versions.get(dubbo) == null) { + Set apps = new HashSet(); + versions.put(dubbo, apps); + } + versions.get(dubbo).add(application); + } + } + model.addAttribute("versions", versions); + return "sysinfo/screen/versions/index"; + } + + @RequestMapping("/version/{version}/versions/show") + public String show(@PathVariable("version") String version, HttpServletRequest request, HttpServletResponse response, + Model model) { + prepare(request, response, model, "show", "versions"); + if (version != null && version.length() > 0) { + List providers = providerService.findAll(); + List consumers = consumerService.findAll(); + Set parametersSet = new HashSet(); + Set applications = new HashSet(); + for (Provider provider : providers) { + parametersSet.add(provider.getParameters()); + } + for (Consumer consumer : consumers) { + parametersSet.add(consumer.getParameters()); + } + Iterator temp = parametersSet.iterator(); + while (temp.hasNext()) { + Map parameter = StringUtils.parseQueryString(temp.next()); + if (parameter != null) { + String dubbo = parameter.get("dubbo"); + if (dubbo == null) dubbo = "0.0.0"; + String application = parameter.get("application"); + if (version.equals(dubbo)) { + applications.add(application); + } + } + } + model.addAttribute("applications", applications); + } + return "sysinfo/screen/versions/show"; + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysmanage/ConfigsController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysmanage/ConfigsController.java new file mode 100644 index 0000000..e7207a2 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysmanage/ConfigsController.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.sysmanage; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; + +import com.alibaba.dubboadmin.governance.service.ConfigService; +import com.alibaba.dubboadmin.registry.common.domain.Config; +import com.alibaba.dubboadmin.registry.common.domain.User; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.beans.factory.annotation.Autowired; + +public class ConfigsController extends BaseController { + + @Autowired + private ConfigService configDAO; + + @Autowired + private HttpServletRequest request; + + public void index(Map context) { + context.put("configs", configDAO.findAllConfigsMap()); + } + + public boolean update(Map context) { + @SuppressWarnings("unchecked") + Map all = request.getParameterMap(); + ; + if (all != null && all.size() > 0) { + if (!User.ROOT.equals(currentUser.getRole())) { + context.put("message", getMessage("HaveNoRootPrivilege")); + return false; + } + List configs = new ArrayList(); + for (Map.Entry entry : all.entrySet()) { + String key = entry.getKey(); + String[] values = entry.getValue(); + if (key != null && key.length() > 0 && !key.startsWith("_")) { + String value = ""; + if (values != null && values.length > 0 + && values[0] != null && values[0].length() > 0) { + value = values[0]; + } + Config config = new Config(); + config.setKey(key); + config.setUsername(currentUser.getUsername()); + config.setOperatorAddress((String) context.get("operatorAddress")); + config.setValue(value); + configs.add(config); + } + } + if (configs.size() > 0) { + configDAO.update(configs); + + Set usernames = new HashSet(); + usernames.add(currentUser.getName()); + + Map params = new HashMap(); + params.put("configs", configs); + } + return true; + } else { + context.put("message", getMessage("MissRequestParameters", "configKey,configValue")); + return false; + } + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysmanage/PrivilegesController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysmanage/PrivilegesController.java new file mode 100644 index 0000000..816d025 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysmanage/PrivilegesController.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.sysmanage; + +import com.alibaba.dubboadmin.web.mvc.BaseController; + +public class PrivilegesController extends BaseController { + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysmanage/UserownController.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysmanage/UserownController.java new file mode 100644 index 0000000..937a1ff --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/mvc/sysmanage/UserownController.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.mvc.sysmanage; + +import java.util.List; +import java.util.Map; + +import com.alibaba.dubboadmin.governance.service.OwnerService; +import com.alibaba.dubboadmin.web.mvc.BaseController; + +import org.springframework.beans.factory.annotation.Autowired; + +/** + * ProvidersController. URI: /services/$service/owners + * + */ +public class UserownController extends BaseController { + + @Autowired + private OwnerService ownerDAO; + + public void index(Map context) { + String user = (String) context.get("user"); + List services; + services = ownerDAO.findServiceNamesByUsername(user); + context.put("user", user); + context.put("services", services); + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/DateFormatUtil.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/DateFormatUtil.java new file mode 100644 index 0000000..caa6819 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/DateFormatUtil.java @@ -0,0 +1,74 @@ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.dubboadmin.web.pulltool; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +/** + * DateFormat Utility + * + */ +public class DateFormatUtil { + + private static final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + private static final ThreadLocal> tl = new ThreadLocal>(); + + /** + * According to the specified format, Get a DateFormat + * + * @param format + * @return + */ + public static DateFormat getDateFormat(String format) { + Map map = tl.get(); + + if (map == null) { + map = new HashMap(); + tl.set(map); + } + + if (StringUtils.isEmpty(format)) { + format = DEFAULT_FORMAT; + } + + DateFormat ret = map.get(format); + + if (ret == null) { + ret = new SimpleDateFormat(format); + map.put(format, ret); + } + + return ret; + } + + /** + * Get Default DateFormat + * + * @return + */ + public static DateFormat getDateFormat() { + return getDateFormat(null); + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/I18nMessageTool.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/I18nMessageTool.java new file mode 100644 index 0000000..6933979 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/I18nMessageTool.java @@ -0,0 +1,46 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +//package com.alibaba.dubboadmin.web.pulltool; +// +//import com.alibaba.citrus.service.pull.ToolFactory; +//import com.alibaba.dubbo.governance.biz.common.i18n.MessageResourceService; +// +//import org.springframework.beans.factory.annotation.Autowired; +// +///** +// * PullTool for accessing message bundle. +// *x +// */ +//public class I18nMessageTool implements ToolFactory { +// +// @Autowired +// private MessageResourceService messageResourceService; +// private boolean singleton = true; +// +// public Object createTool() throws Exception { +// return messageResourceService; +// } +// +// public boolean isSingleton() { +// return this.singleton; +// } +// +// public void setSingleton(boolean singleton) { +// this.singleton = singleton; +// } +// +//} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/RootContextPath.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/RootContextPath.java new file mode 100644 index 0000000..827c58b --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/RootContextPath.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.pulltool; + +public class RootContextPath { + + private String contextPath; + + public RootContextPath(String contextPath) { + this.contextPath = contextPath; + } + + public String getURI(String uri) { + String prefix; + if (contextPath != null && contextPath.length() > 0 && !"/".equals(contextPath)) { + prefix = contextPath; + } else { + prefix = ""; + } + if (uri.startsWith("/")) { + return prefix + uri; + } else { + return prefix + "/" + uri; + } + } + +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/Tool.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/Tool.java new file mode 100644 index 0000000..fd58f37 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/Tool.java @@ -0,0 +1,489 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubboadmin.web.pulltool; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Array; +import java.net.InetAddress; +import java.net.URLEncoder; +import java.net.UnknownHostException; +import java.text.ParseException; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubboadmin.governance.service.OverrideService; +import com.alibaba.dubboadmin.governance.service.RouteService; +import com.alibaba.dubboadmin.registry.common.domain.Consumer; +import com.alibaba.dubboadmin.registry.common.domain.Override; +import com.alibaba.dubboadmin.registry.common.domain.Provider; +import com.alibaba.dubboadmin.registry.common.domain.Route; +import com.alibaba.dubboadmin.registry.common.domain.User; +import com.alibaba.dubboadmin.registry.common.route.ParseUtils; +import com.alibaba.dubboadmin.registry.common.route.RouteRule; +import com.alibaba.dubboadmin.registry.common.route.RouteRule.MatchPair; +import com.alibaba.dubboadmin.registry.common.util.StringEscapeUtils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Tool + * + */ +@Component +public class Tool { + + private static final Comparator SIMPLE_NAME_COMPARATOR = new Comparator() { + public int compare(String s1, String s2) { + if (s1 == null && s2 == null) { + return 0; + } + if (s1 == null) { + return -1; + } + if (s2 == null) { + return 1; + } + s1 = getSimpleName(s1); + s2 = getSimpleName(s2); + return s1.compareToIgnoreCase(s2); + } + }; + @Autowired + private OverrideService overrideService; + @Autowired + private RouteService routeService; + + public static String toStackTraceString(Throwable t) { + StringWriter writer = new StringWriter(); + PrintWriter pw = new PrintWriter(writer); + t.printStackTrace(pw); + return writer.toString(); + } + + public static boolean isContains(String[] values, String value) { + return StringUtils.isContains(values, value); + } + + public static boolean startWith(String value, String prefix) { + return value.startsWith(prefix); + } + + public static String getHostPrefix(String address) { + if (address != null && address.length() > 0) { + String hostname = getHostName(address); + if (!address.startsWith(hostname)) { + return "(" + hostname + ")"; + } + } + return ""; + } + + public static String getHostName(String address) { + return NetUtils.getHostName(address); + } + + public static String getHostAddress(String address) { + if (address != null && address.length() > 0) { + int i = address.indexOf(':'); + String port = address.substring(i + 1); + String hostname = NetUtils.getHostName(address); + if (!address.equals(hostname)) { + return hostname + ":" + port; + } + } + return ""; + } + + public static String getPath(String url) { + try { + return URL.valueOf(url).getPath(); + } catch (Throwable t) { + return url; + } + } + + public static String getAddress(String url) { + try { + return URL.valueOf(url).getAddress(); + } catch (Throwable t) { + return url; + } + } + + public static String getInterface(String service) { + if (service != null && service.length() > 0) { + int i = service.indexOf('/'); + if (i >= 0) { + service = service.substring(i + 1); + } + i = service.lastIndexOf(':'); + if (i >= 0) { + service = service.substring(0, i); + } + } + return service; + } + + public static String getGroup(String service) { + if (service != null && service.length() > 0) { + int i = service.indexOf('/'); + if (i >= 0) { + return service.substring(0, i); + } + } + return null; + } + + public static String getVersion(String service) { + if (service != null && service.length() > 0) { + int i = service.lastIndexOf(':'); + if (i >= 0) { + return service.substring(i + 1); + } + } + return null; + } + + public static String getIP(String address) { + if (address != null && address.length() > 0) { + int i = address.indexOf("://"); + if (i >= 0) { + address = address.substring(i + 3); + } + i = address.indexOf('/'); + if (i >= 0) { + address = address.substring(0, i); + } + i = address.indexOf('@'); + if (i >= 0) { + address = address.substring(i + 1); + } + i = address.indexOf(':'); + if (i >= 0) { + address = address.substring(0, i); + } + if (address.matches("[a-zA-Z]+")) { + try { + address = InetAddress.getByName(address).getHostAddress(); + } catch (UnknownHostException e) { + } + } + } + return address; + } + + public static String encode(String url) { + try { + return URLEncoder.encode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + return url; + } + } + + public static String escape(String html) { + return StringEscapeUtils.escapeHtml(html); + } + + public static String unescape(String html) { + return StringEscapeUtils.unescapeHtml(html); + } + + public static String encodeUrl(String url) { + return URL.encode(url); + } + + public static String decodeUrl(String url) { + return URL.decode(url); + } + + public static String encodeHtml(String html) { + return StringEscapeUtils.escapeHtml(html); + } + + public static int countMapValues(Map map) { + int total = 0; + if (map != null && map.size() > 0) { + for (Object value : map.values()) { + if (value != null) { + if (value instanceof Number) { + total += ((Number) value).intValue(); + } else if (value.getClass().isArray()) { + total += Array.getLength(value); + } else if (value instanceof Collection) { + total += ((Collection) value).size(); + } else if (value instanceof Map) { + total += ((Map) value).size(); + } else { + total += 1; + } + } + } + } + return total; + } + + public static List sortSimpleName(List list) { + if (list != null && list.size() > 0) { + Collections.sort(list, SIMPLE_NAME_COMPARATOR); + } + return list; + } + + public static String getSimpleName(String name) { + if (name != null && name.length() > 0) { + final int ip = name.indexOf('/'); + String v = ip != -1 ? name.substring(0, ip + 1) : ""; + + int i = name.lastIndexOf(':'); + int j = (i >= 0 ? name.lastIndexOf('.', i) : name.lastIndexOf('.')); + if (j >= 0) { + name = name.substring(j + 1); + } + name = v + name; + } + return name; + } + + public static String getParameter(String parameters, String key) { + String value = ""; + if (parameters != null && parameters.length() > 0) { + String[] pairs = parameters.split("&"); + for (String pair : pairs) { + String[] kv = pair.split("="); + if (key.equals(kv[0])) { + value = kv[1]; + break; + } + } + } + return value; + } + + public static Map toParameterMap(String parameters) { + return StringUtils.parseQueryString(parameters); + } + + /** + * Get the version value from the paramters parameter of provider + * + * @param parameters + * @return + */ + public static String getVersionFromPara(String parameters) { + String version = ""; + if (parameters != null && parameters.length() > 0) { + String[] params = parameters.split("&"); + for (String o : params) { + String[] kv = o.split("="); + if ("version".equals(kv[0])) { + version = kv[1]; + break; + } + } + } + return version; + } + + public static boolean isProviderEnabled(Provider provider, List oList) { + for (Override o : oList) { + if (o.isMatch(provider)) { + Map params = StringUtils.parseQueryString(o.getParams()); + String disbaled = params.get(Constants.DISABLED_KEY); + if (disbaled != null && disbaled.length() > 0) { + return !"true".equals(disbaled); + } + } + } + return provider.isEnabled(); + } + + public static int getProviderWeight(Provider provider, List oList) { + for (Override o : oList) { + if (o.isMatch(provider)) { + Map params = StringUtils.parseQueryString(o.getParams()); + String weight = params.get(Constants.WEIGHT_KEY); + if (weight != null && weight.length() > 0) { + return Integer.parseInt(weight); + } + } + } + return provider.getWeight(); + } + + public void setOverrideService(OverrideService overrideService) { + this.overrideService = overrideService; + } + + public void setRouteService(RouteService routeService) { + this.routeService = routeService; + } + + public String formatTimestamp(String timestamp) { + if (timestamp == null || timestamp.length() == 0) { + return ""; + } + return formatDate(new Date(Long.valueOf(timestamp))); + } + + //format date + public String formatDate(Date date) { + if (date == null) { + return ""; + } + return DateFormatUtil.getDateFormat().format(date); + } + + public String formatDate(Date date, String template) { + if (date == null || template == null) { + return ""; + } + return DateFormatUtil.getDateFormat(template).format(date); + } + + public boolean beforeNow(Date date) { + Date now = new Date(); + if (now.after(date)) { + return true; + } + return false; + } + + //minus of date + public long dateMinus(Date date1, Date date2) { + return (date1.getTime() - date1.getTime()) / 1000; + } + + public boolean isProviderEnabled(Provider provider) { + List oList = overrideService.findByServiceAndAddress(provider.getService(), provider.getAddress()); + return isProviderEnabled(provider, oList); + } + + public int getProviderWeight(Provider provider) { + List oList = overrideService.findByServiceAndAddress(provider.getService(), provider.getAddress()); + return getProviderWeight(provider, oList); + } + + public boolean isInBlackList(Consumer consumer) { + String service = consumer.getService(); + List routes = routeService.findForceRouteByService(service); + if (routes == null || routes.size() == 0) { + return false; + } + String ip = getIP(consumer.getAddress()); + for (Route route : routes) { + try { + if (!route.isEnabled()) { + continue; + } + String filterRule = route.getFilterRule(); + if (filterRule == null || filterRule.length() == 0 || "false".equals(filterRule)) { + Map rule = RouteRule.parseRule(route.getMatchRule()); + MatchPair pair = rule.get("consumer.host"); + if (pair == null) { + pair = rule.get("host"); + } + if (pair != null) { + if (pair.getMatches() != null && pair.getMatches().size() > 0) { + for (String host : pair.getMatches()) { + if (ParseUtils.isMatchGlobPattern(host, ip)) { + return true; + } + } + } + if (pair.getUnmatches() != null && pair.getUnmatches().size() > 0) { + boolean forbid = true; + for (String host : pair.getUnmatches()) { + if (ParseUtils.isMatchGlobPattern(host, ip)) { + forbid = false; + } + } + if (forbid) { + return true; + } + } + } + } + } catch (ParseException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + return false; + } + + public String getConsumerMock(Consumer consumer) { + return getOverridesMock(consumer.getOverrides()); + } + + public String getOverridesMock(List overrides) { + if (overrides != null && overrides.size() > 0) { + for (Override override : overrides) { + Map params = StringUtils.parseQueryString(override.getParams()); + String mock = params.get("mock"); + if (mock != null && mock.length() > 0) { + return mock; + } + } + } + return ""; + } + + public boolean checkUrl(User user, String uri) { + return true; + /*if(!User.ROOT.equals(user.getRole())){ + List disabledSysinfo = new ArrayList(); + List disabledSysmanage = new ArrayList(); + Map features = daoCache.getFeatures(); + if (features.size() > 0){ + for(Entry feature : features.entrySet()){ + if(feature.getKey().startsWith("Sysinfo") && !feature.getValue()){ + disabledSysinfo.add(feature.getKey().replace(".", "/").toLowerCase()); + }else if(feature.getKey().startsWith("Sysmanage") && !feature.getValue()){ + disabledSysmanage.add(feature.getKey().replace(".", "/").toLowerCase()); + } + } + if(uri.startsWith("/sysinfo")){ + for(String disabled : disabledSysinfo){ + if (uri.contains(disabled)){ + return false; + } + } + } + if(uri.startsWith("/sysmanage")){ + for(String disabled : disabledSysmanage){ + if (uri.contains(disabled)){ + return false; + } + } + } + }else{ + return true; + } + } + return true;*/ + } +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/ToolUtil.java b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/ToolUtil.java new file mode 100644 index 0000000..5af098b --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/java/com/alibaba/dubboadmin/web/pulltool/ToolUtil.java @@ -0,0 +1,52 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +//package com.alibaba.dubboadmin.web.pulltool; +// +//import com.alibaba.citrus.service.pull.ToolFactory; +//import com.alibaba.dubbo.governance.service.OverrideService; +//import com.alibaba.dubbo.governance.service.RouteService; +// +//import org.springframework.beans.factory.annotation.Autowired; +// +///** +// * PullTool for accessing message bundle. +// * +// */ +//public class ToolUtil implements ToolFactory { +// @Autowired +// OverrideService overrideService; +// +// @Autowired +// RouteService routeService; +// private boolean singleton = false; +// +// public Object createTool() throws Exception { +// Tool tool = new Tool(); +// tool.setOverrideService(overrideService); +// tool.setRouteService(routeService); +// return tool; +// } +// +// public boolean isSingleton() { +// return this.singleton; +// } +// +// public void setSingleton(boolean singleton) { +// this.singleton = singleton; +// } +// +//} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/application.properties b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/application.properties new file mode 100644 index 0000000..477174f --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/application.properties @@ -0,0 +1,27 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +server.port=7001 +spring.velocity.cache=false +spring.velocity.charset=UTF-8 +spring.velocity.layout-url=/templates/default.vm +spring.messages.fallback-to-system-locale=false +spring.messages.basename=i18n/message +spring.root.password=root +spring.guest.password=guest + +dubbo.registry.address=zookeeper://127.0.0.1:2181 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/dubbo-admin.xml b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/dubbo-admin.xml new file mode 100644 index 0000000..f32036c --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/dubbo-admin.xml @@ -0,0 +1,29 @@ + + + + + + + + + + \ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message.properties b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message.properties new file mode 100644 index 0000000..a9fd83f --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message.properties @@ -0,0 +1,16 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# \ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_en.properties b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_en.properties new file mode 100644 index 0000000..431bca0 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_en.properties @@ -0,0 +1,768 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +#menus +home=home +stat=stat +revision=revision +connectionNum=connectionNum +serviceNum=serviceNum +providerNum=providerNum +consumerNum=consumerNum +applicationNum=applicationNum +about=about +help=help +favorites=favorites +histories=histories +governance=governance +applications=applications +efferents=efferents +afferents=afferents +services=services +references=references +addresses=addresses +providers=providers +dependencies=dependencies +layers=layers +clusters=clusters +consumers=consumers +accesses=accesses +routes=routes +weights=weights +loadbalances=loadbalances +tests=tests +mocks=mocks +overrides=overrides +documents=documents +owners=owners +agreements=agreements +approvals=approvals +operations=operations +users=users +envs=envs +helps=helps +registries=registries +configs=configs +features=features +connections=connections +statuses=statuses +failed=failed +cached=cached +dumps=dumps +InvalidIp=InvalidIp +versions=versions +logs=logs +infos=infos +passwds=passwds +dependency.list=dependency.list +dependency.tree=dependency.tree +dependency.graph=dependency.graph +dependency.efferent=dependency.efferent +dependency.afferent=dependency.afferent +provided=provided +consumed=consumed +select=select +clean=clean +information=information +control=control +summary=summary +consumer.application=consumer.application +response.time=response.time +sysinfo.infos=sysinfo.infos +helps.document=helps.document +helps.requirement=helps.requirement +helps.source=helps.source +connections=connections +ReconnectUnkwown=ReconnectUnkwown +confirmReconnectConnection=confirmReconnectConnection +confirmRedirectRegistry=confirmRedirectRegistry +confirmReconnectUnknownConnection=confirmReconnectUnknownConnection +status.resourcename=status.resourcename +status.status=status.status +status.message=status.message +status.description=status.description +status.memoryStatus=status.memoryStatus +status.memoryStatusDesc=status.memoryStatusDesc +status.threadpoolStatus=status.threadpoolStatus +status.threadpoolStatusDesc=status.threadpoolStatusDesc +status.failureStatus=status.failureStatus +status.failureStatusDesc=status.failureStatusDesc +status.cacheStatus=status.cacheStatus +status.cacheStatusDesc=status.cacheStatusDesc +status.timerStatus=status.timerStatus +status.timerStatusDesc=status.timerStatusDesc +status.socketStatus=status.socketStatus +status.socketStatusDesc=status.socketStatusDesc +status.loadStatus=status.loadStatus +status.loadStatusDesc=status.loadStatusDesc +status.datasourceStatus=status.datasourceStatus +status.datasourceStatusDesc=status.datasourceStatusDesc +status.registryStatus=status.registryStatus +status.registryStatusDesc=status.registryStatusDesc +status.monitorStatus=status.monitorStatus +status.monitorStatusDesc=status.monitorStatusDesc +status.summaryStatus=status.summaryStatus +status.summaryStatusDesc=status.summaryStatusDesc +status.warmupStatus=status.warmupStatus +status.warmupStatusDesc=status.warmupStatusDesc +status.OK=status.OK +status.WARN=status.WARN +status.ERROR=status.ERROR +status.UNKNOWN=status.UNKNOWN +Status0=Unknow +Status1=OK +Status2=OK +Status3=ERROR +Status4=FATAL +Status5=UNKNOW +service.filter=service.filter +default.service.filter=default.service.filter +mock=mock +force.mocked=force.mocked +fail.mocked=fail.mocked +no.mocked=no.mocked +force.mock=force.mock +fail.mock=fail.mock +cancel.mock=cancel.mock +confirm.force.mock=\u786e\u8ba4\u5c4f\u853d\u8be5\u670d\u52a1\u7684\u8c03\u7528\uff1f
\u5C4F\u853D\u540E\uFF0C\u5c06\u4e0d\u53d1\u8d77\u8fdc\u7a0b\u8c03\u7528\uff0c\u76f4\u63a5\u5728\u5BA2\u6237\u7AEF\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.fail.mock=\u786e\u8ba4\u5bf9\u8be5\u670d\u52a1\u5bb9\u9519\uff1f
\u5BB9\u9519\u540E\uFF0C\u5f53\u8FDC\u7A0B\u8c03\u7528\u5931\u8d25\u65f6\uff0c\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.cancel.mock=\u786e\u8ba4\u6062\u590d\u8be5\u670d\u52a1\u6b63\u5e38\u8bbf\u95ee\uff1f
\u5c06\u53d6\u6d88\u670d\u52a1\u7684\u5c4f\u853d\u548c\u5bb9\u9519\u884c\u4e3a\u3002 +batch.force.mock=batch.force.mock +batch.fail.mock=batch.fail.mock +batch.cancel.mock=batch.cancel.mock +confirm.batch.force.mock=\u786e\u8ba4\u6279\u91cf\u5c4f\u853d\u670d\u52a1\u7684\u8c03\u7528\uff1f
\u5C4F\u853D\u540E\uFF0C\u5c06\u4e0d\u53d1\u8d77\u8fdc\u7a0b\u8c03\u7528\uff0c\u76f4\u63a5\u5728\u5BA2\u6237\u7AEF\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.batch.fail.mock=\u786e\u8ba4\u6279\u91cf\u5bf9\u670d\u52a1\u5bb9\u9519\uff1f
\u5BB9\u9519\u540E\uFF0C\u5f53\u8FDC\u7A0B\u8c03\u7528\u5931\u8d25\u65f6\uff0c\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.batch.cancel.mock=\u786e\u8ba4\u6279\u91cf\u6062\u590d\u670d\u52a1\u6b63\u5e38\u8bbf\u95ee\uff1f
\u5c06\u53d6\u6d88\u670d\u52a1\u7684\u5c4f\u853d\u548c\u5bb9\u9519\u884c\u4e3a\u3002 +all.force.mock=all.force.mock +all.fail.mock=all.fail.mock +all.cancel.mock=all.cancel.mock +confirm.all.force.mock=\u786e\u8ba4\u7F3A\u7701\u5c4f\u853d\u8be5\u670d\u52a1\u7684\u8c03\u7528\uff1f
\u8BBE\u7F6E\u964D\u7EA7\u7F3A\u7701\u503C\uFF0C\u5C06\u5F71\u54CD\u672A\u964D\u7EA7\u4EE5\u53CA\u65B0\u7684\u6D88\u8D39\u8005\u3002
\u5C4F\u853D\u540E\uFF0C\u5c06\u4e0d\u53d1\u8d77\u8fdc\u7a0b\u8c03\u7528\uff0c\u76f4\u63a5\u5728\u5BA2\u6237\u7AEF\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.all.fail.mock=\u786e\u8ba4\u7F3A\u7701\u5bf9\u8be5\u670d\u52a1\u5bb9\u9519\uff1f
\u8BBE\u7F6E\u964D\u7EA7\u7F3A\u7701\u503C\uFF0C\u5C06\u5F71\u54CD\u672A\u964D\u7EA7\u4EE5\u53CA\u65B0\u7684\u6D88\u8D39\u8005\u3002
\u5BB9\u9519\u540E\uFF0C\u5f53\u8FDC\u7A0B\u8c03\u7528\u5931\u8d25\u65f6\uff0c\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.all.cancel.mock=\u786e\u8ba4\u7F3A\u7701\u6062\u590d\u8be5\u670d\u52a1\u6b63\u5e38\u8bbf\u95ee\uff1f
\u8BBE\u7F6E\u964D\u7EA7\u7F3A\u7701\u503C\uFF0C\u5C06\u5F71\u54CD\u672A\u964D\u7EA7\u4EE5\u53CA\u65B0\u7684\u6D88\u8D39\u8005\u3002
\u5c06\u53d6\u6d88\u670d\u52a1\u7684\u5c4f\u853d\u548c\u5bb9\u9519\u884c\u4e3a\u3002 +agreement.invocation.quantity=agreement.invocation.quantity +agreement.tps=agreement.tps +response.time=response.time +agreement.availability=agreement.availability +layer.name=layer.name +layer.value=layer.value +default.lazy=default.lazy +layer.arch=layer.arch +loadBalanceStrategy=loadBalanceStrategy +ServiceName=ServiceName +cluster.name=cluster.name +cluster.address=cluster.address +property.name=property.name +property.value=property.value +property.count=property.count +getMethods=getMethods +getAddresses=getAddresses +Edit=Edit +Username=Username +Priority=Priority +ConnectionAddress=ConnectionAddress +Role=Role +Reconnect=Reconnect +Redirect=Redirect +staff.query= +configKey=configKey +configValue=configValue +Preview=Preview +routeselect=routeselect +AllOperations=AllOperations +BeforeOneMonthOperations=BeforeOneMonthOperations +BeforeThreeMonthOperations=BeforeThreeMonthOperations +BeforeHalfYearOperations=BeforeHalfYearOperations +BeforeOneYearOperations=BeforeOneYearOperations +PleaseInput=PleaseInput +BulletinConfig=BulletinConfig +BulletinMessage=BulletinMessage +MailConfig=MailConfig +MailEnabled=MailEnabled +MailHost=MailHost +MailPort=MailPort +MailFrom=MailFrom +MailAuth=MailAuth +MailUsername=MailUsername +MailPassword=MailPassword +LoginConfig=LoginConfig +AllowAnonymousLogin=AllowAnonymousLogin +AllowLegacyLogin=AllowLegacyLogin +RouteEnabled=RouteEnabled +WarmupEnabled=WarmupEnabled +LogConfig=LogConfig +LogLevel=LogLevel +RedirectConfig=RedirectConfig +AutoRedirectInterval=AutoRedirectInterval +AutoRedirectThreshold=AutoRedirectThreshold +AutoRedirectToleratePercent=AutoRedirectToleratePercent +ManualRedirect=ManualRedirect +LimitConfig=LimitConfig +MaxConnectionSize=MaxConnectionSize +MaxCacheSize=MaxCacheSize +MaxMailSize=MaxMailSize +TimerConfig=TimerConfig +AlivedCheckInterval=AlivedCheckInterval +ChangedCheckInterval=ChangedCheckInterval +FailedRetryInterval=FailedRetryInterval +DirtyCheckInterval=DirtyCheckInterval +HeartbeatConfig=HeartbeatConfig +HeartbeatCheckInterval=HeartbeatCheckInterval +HeartbeatCheckTimeout=HeartbeatCheckTimeout +TimeoutConfig=TimeoutConfig +NotifyTimeout=NotifyTimeout +WarmupWaitTime=WarmupWaitTime +UrlConfig=UrlConfig +BucServiceAddress=BucServiceAddress +HelpDocumentUrl=HelpDocumentUrl +HomepageDomain=HomepageDomain +HomepageUrl=HomepageUrl +parametersConfig=parametersConfig +DefaultServiceParameters=DefaultServiceParameters +BatchAddressTip=BatchAddressTip +ConsumerAddress=ConsumerAddress +AccessControlTip=AccessControlTip +access=access +Allowed=Allowed +Forbidden=Forbidden +allow=allow +forbid=forbid +confirm.allow=confirm.allow +confirm.forbid=\u786E\u8BA4\u7981\u6B62\u8BBF\u95EE?
\u88AB\u7981\u6B62\u7684\u5BA2\u6237\u7AEF\u5C06\u6536\u5230\u7981\u6B62\u8BBF\u95EE\u5F02\u5E38\u3002 +batch.allow=batch.allow +batch.forbid=batch.forbid +confirm.batch.allow=confirm.batch.allow +confirm.batch.forbid=\u786E\u8BA4\u7981\u6B62\u6240\u9009\u9879\u8BBF\u95EE?
\u88AB\u7981\u6B62\u7684\u5BA2\u6237\u7AEF\u5C06\u6536\u5230\u7981\u6B62\u8BBF\u95EE\u5F02\u5E38\u3002 +only.allow=only.allow +only.forbid=only.forbid +confirm.only.allow=\u786E\u8BA4\u53EA\u5141\u8BB8\u9009\u4E2D\u9879\u8BBF\u95EE?
\u5176\u5B83\u672A\u9009\u4E2D\u9879\u53CA\u4EE5\u540E\u65B0\u589E\u9879\u5C06\u5168\u90E8\u53D8\u4E3A\u7981\u6B62\u8BBF\u95EE\u3002
\u88AB\u7981\u6B62\u7684\u5BA2\u6237\u7AEF\u5C06\u6536\u5230\u7981\u6B62\u8BBF\u95EE\u5F02\u5E38\u3002 +confirm.only.forbid=\u786E\u8BA4\u53EA\u7981\u6B62\u9009\u4E2D\u9879\u8BBF\u95EE?
\u5176\u5B83\u672A\u9009\u4E2D\u9879\u53CA\u4EE5\u540E\u65B0\u589E\u9879\u5C06\u5168\u90E8\u53D8\u4E3A\u5141\u8BB8\u8BBF\u95EE\u3002
\u88AB\u7981\u6B62\u7684\u5BA2\u6237\u7AEF\u5C06\u6536\u5230\u7981\u6B62\u8BBF\u95EE\u5F02\u5E38\u3002 +Choose=Choose +userown=userown +sysmanage.userown=sysmanage.userown +SingleServiceTip=SingleServiceTip +MultiServiceTip=MultiServiceTip +RouteNameTip=\u53ef\u4f7f\u7528\u4e2d\u6587\uff0c\u75311-200\u4e2a\u5b57\u7b26\u7ec4\u6210 +RoutePriorityTip=RoutePriorityTip +RouteServiceTip=RouteServiceTip +#RouteServiceTip=\u670d\u52a1\u63a5\u53e3\u540d\u53ef\u4ee5\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u53ea\u652f\u6301\u4e00\u4e2a*\u7b26\u4e14\u8981\u5728\u63a5\u53e3\u672b\u5c3e\uff08\u5206\u7ec4\u3001\u7248\u672c\u4e0d\u652f\u6301\u901a\u914d\u7b26\uff09 +RouteMethodTip=\u53ea\u6709Dubbo2.0.0\u4ee5\u4e0a\u7248\u672c\u7684\u670d\u52a1\u6d88\u8d39\u7aef\u652f\u6301\u6309\u65b9\u6cd5\u8def\u7531\uff0c\u591a\u4e2a\u65b9\u6cd5\u540d\u7528\u9017\u53f7\u5206\u9694 +RouteClusterTip=\u53ef\u901a\u8fc7\u83dc\u5355"\u670d\u52a1\u63a7\u5236"->"\u670d\u52a1\u5668\u96c6\u7fa4"\u7ba1\u7406 +RouteMatchTip=RouteMatchTip +RouteFilterTip=RouteFilterTip +RouteHostTip=RouteHostTip +RouteApplicationTip=RouteApplicationTip +RouteResult=RouteResult +preview=preview +ConsumerApplication=ConsumerApplication +ConsumerCluster=ConsumerCluster +ConsumerHost=ConsumerHost +ConsumerVersion=ConsumerVersion +ConsumerGroup=ConsumerGroup +ProviderApplication=ProviderApplication +ProviderCluster=ProviderCluster +ProviderProtocol=ProviderProtocol +ProviderHost=ProviderHost +ProviderPort=ProviderPort +ProviderVersion=ProviderVersion +ProviderGroup=ProviderGroup +MatchRule=MatchRule +FilterRule=FilterRule +routeName=routeName +routeRule=routeRule +Match=Match +Mismatch=Mismatch +GetMethods=GetMethods +FeatureName=FeatureName +Features=Features +Disable=Disable +Enable=Enable +Enabled=Enabled +Disabled=Disabled +Unknown=Unknown +Users=Users +UsersDescription=UsersDescription +StatusList=StatusList +StatusListDescription=StatusListDescription +Operations=Operations +OperationsDescription=OperationsDescription +Accesses=Accesses +AccessesDescription=AccessesDescription +Configs=Configs +Clusters=Clusters +ClustersDescription=ClustersDescription +Weights=Weights +WeightsDescription=WeightsDescription +Agreements=Agreements +AgreementsDescription=AgreementsDescription +ConfigsDescription=ConfigsDescription +LoadBalances=LoadBalances +LoadBalancesDescription=LoadBalancesDescription +CachedList=CachedList +CachedListDescription=CachedListDescription +FailedList=FailedList +Registries=Registries +FailedListDescription=FailedListDescription +registryAddress=registryAddress +RegistriesDescription=RegistriesDescription +Help=Help +HelpDescription=HelpDescription +Providers=Providers +ProvidersDescription=ProvidersDescription +Log=Log +LogDescription=LogDescription +Services=Services +ServicesDescription=ervicesDescription +Owned=Owned +OwnedDescription=OwnedDescription +Tests=Tests +TestsDescription=TestsDescription +Documents=Documents +DocumentsDescription=DocumentsDescription +Applications=Applications +ApplicationsDescription=ApplicationsDescription +Consumers=Consumers +ConsumersDescription=ConsumersDescription +System=System +SystemDescription=SystemDescription +Routes=Routes +Route=Route +RoutesDescription=RoutesDescription +Connections=Connections +ConnectionsDescription=ConnectionsDescription +RegistryAddress=RegistryAddress +RegisterUsername=RegisterUsername +RegisterDate=RegisterDate +subscribeDate=subscribeDate +Statistics=Statistics +CheckConnection=CheckConnection +CheckDatabase=CheckDatabase +queryUrl=queryUrl +Status=Status +notify=notify +notified=notified +unnotified=unnotified +Unuse=Unuse +NoProvider=NoProvider +NoConsumer=NoConsumer +route.consumer.not.match=route.consumer.not.match +#labels +all=all +service=service +application=application +recursive=recursive +layer=layer +address=address +dubbo=dubbo +version=version +group=group +url=url +parameters=parameters +provider=provider +consumer=consumer +registry=registry +username=username +created=created +modified=modified +register.date=register.date +type=type +static=static +dynamic=dynamic +status=status +enabled=enabled +disabled=disabled +check=check +operation=operation +role=role +provider=provider +consumer=consumer +consumer.address=consumer.address +no.provider=no.provider +no.consumer=no.consumer +ok=ok +warn=warn +error=error +success=success +failure=failure +operation.success=operation.success +operation.failure=operation.failure +isRegistered=isRegistered +isCached=isCached +isCached.true=isCached.true +isCached.false=isCached.false +isSubscribed=isSubscribed +isSubscribed.true=isSubscribed.true +isSubscribed.false=isSubscribed.false +isSubscribed.unmatch=isSubscribed.unmatch +#operations +search=search +query=query +show=show +add=add +addMock=addMock +multiadd=multiadd +edit=edit +save=save +delete=delete +enable=enable +disable=disable +recover=recover +reload=reload +reconnect=reconnect +renotify=renotify +tostatic=tostatic +todynamic=todynamic +favorite=favorite +register=register +subscribe=subscribe +logout=logout +back=back +cancel=cancel +confirm=confirm +batch.add=batch.add +batch.multiservices.add=batch.multiservices.add +batch.delete=batch.delete +batch.enable=batch.enable +batch.disable=batch.disable +batch.recover=batch.recover +batch.reconnect=batch.reconnect +batch.renotify=batch.renotify +batch.tostatic=batch.tostatic +batch.todynamic=batch.todynamic +batch.favorite=batch.favorite +batch.reload=batch.reload +confirm.batch.disable=confirm.batch.disable +confirm.batch.enable=confirm.batch.enable +#prompts +please.input.service=please.input.service +please.input.application=please.input.application +please.input.address=please.input.address +please.input.layer=please.input.layer +please.input=please.input +please.select=please.select +empty.list=empty.list +not.found=not.found +show.all=show.all +confirm.logout=confirm.logout +confirm.delete=\u786e\u5b9a\u5220\u9664?
\u5220\u9664\u540E\u5C06\u4E0D\u53EF\u8FD8\u539F\u3002 +confirm.enable=confirm.enable? +confirm.disable=confirm.disable? +confirm.recover=confirm.recover? +confirm.reconnect=confirm.reconnect? +confirm.renotify=confirm.renotify? +confirm.tostatic=confirm.tostatic? +confirm.todynamic=confirm.todynamic? +confirm.batch.delete=\u786e\u5b9a\u5220\u9664\u6240\u9009\u9879?
\u5220\u9664\u540E\u5C06\u4E0D\u53EF\u8FD8\u539F\u3002 +confirm.batch.enable=confirm.batch.enable +confirm.batch.disable=confirm.batch.disable +confirm.batch.recover=confirm.batch.recover +confirm.batch.reload=confirm.batch.reload +confirm.batch.reconnect=confirm.batch.reconnect +confirm.batch.renotify=confirm.batch.renotify +confirm.batch.tostatic=confirm.batch.tostatic +confirm.batch.todynamic=confirm.batch.todynamic +current.user=current.user +CheckProviderLocalAddress=CheckProviderLocalAddress +CheckProviderApplicationDifferent=CheckProviderApplicationDifferent +CheckProviderAddressMismatch=CheckProviderAddressMismatch +CheckConnectionDisconnected=CheckConnectionDisconnected +CheckConnectionExpired=CheckConnectionExpired +CheckDatabaseMiss=CheckDatabaseMiss +CheckDatabaseMismatch=CheckDatabaseMismatch +CheckDatabaseDirty2Registered=CheckDatabaseDirty2Registered +CheckDatabaseDirty2Subscribed=CheckDatabaseDirty2Subscribed +CheckCacheRegistered=CheckCacheRegistered +CheckCacheConsumer=CheckCacheConsumer +CheckCacheProvider=CheckCacheProvider +CheckCacheSubscribed=CheckCacheSubscribed +CheckCacheService=CheckCacheService +select.all=select.all +ip.address=ip.address +registry.newservice=registry.newservice +add.new.provider=add.new.provider +add.new.route=add.new.route +message.search.noresult=message.search.noresult +provide.service=provide.service +service.method=service.method +startegy=startegy +route.name=route.name +rule.match=rule.match +rule.filtrate=rule.filtrate +priority=priority +routed=routed +unrouted=unrouted +page.total=page.total +page.records=page.records +page.ordinal=page.ordinal +page.page=page.page +page.next=page.next +page.prev=page.prev +page.first=page.first +page.last=page.last +page.line=page.line +methodName=methodName +proview=proview +cluster.name=cluster.name +cluster.address=cluster.address +sameserviceadd=sameserviceadd +whitelist=whitelist +blacklist=blacklist +toWhiteAndBlackList=toWhiteAndBlackList +obtainProviderAddress=obtainProviderAddress +towhitelist=towhitelist +toblacklist=toblacklist +enable=enable +disable=disable +copy=copy +batch.enable=batch.enable +batch.disable=batch.disable +batch.towhitelist=batch.towhitelist +batch.toblacklist=batch.toblacklist +confirm.favorites=confirm.favorites +confirm.batch.towhitelist=\u786e\u8ba4\u52a0\u5165\u767d\u540d\u5355?
\u5c06\u7981\u6b62\u4e0d\u5728\u767d\u540d\u5355\u5185\u7684\u6240\u6709\u6d88\u8d39\u8005\u8bbf\u95ee\uff0c\u9ed1\u540d\u5355\u5931\u6548\u3002 +confirm.batch.toblacklist=\u786e\u8ba4\u52a0\u5165\u9ed1\u540d\u5355?
\u5982\u679c\u6ca1\u6709\u767d\u540d\u5355\uff0c\u5c06\u7981\u6b62\u5728\u9ed1\u540d\u5355\u5185\u7684\u6240\u6709\u5176\u5b83\u6d88\u8d39\u8005\u8bbf\u95ee\u3002 +confirm.enable=confirm.enable +confirm.disable=confirm.disable +confirm.edit=confirm.edit +confirm.disableFeature=confirm.disableFeature +confirm.enableFeature=confirm.enableFeature +confirmDeleteOwner=confirmDeleteOwner +generic=generic +doubling=doubling +update=update +welcome=welcome +approve=approve +chinese.simple=chinese.simple +chinese.tradition=chinese.tradition +register.service=register.service +erratum.guide=erratum.guide +preview.guide=preview.guide +sysinfo.status=sysinfo.status +sysinfo.registries=sysinfo.registries +sysinfo.connections=sysinfo.connections +sysinfo.cached=sysinfo.cached +sysinfo.failed=sysinfo.failed +sysinfo.operations=sysinfo.operations +sysinfo.logs=sysinfo.logs +sysinfo.versions=sysinfo.versions +sysinfo.dumps=sysinfo.dumps +sysinfo.envs=sysinfo.envs +sysinfo.helps=sysinfo.helps +system.management=system.management +sysmanage.users=sysmanage.users +sysmanage.configs=sysmanage.configs +sysmanage.features=sysmanage.features +system.function.control=system.function +personal.set=personal.set +modify.personalinfo=modify.personalinfo +modify.personal.password=modify.personal.password +operation.operateaddress=operation.operateaddress +operation.operatetype=operation.operatetype +operation.datatype=operation.datatype +operation.data=operation.data +operation.createtime=operation.createtime +operation.clean=operation.clean +passwd.oldwrong=passwd.oldwrong +failed=failed +failed_type=failed_type +failed_data=failed_data +failed_sync=failed_sync +failed_subscribe=failed_subscribe +failed_notify=failed_notify +failed_collect=failed_collect +failed_register=failed_register +failed_redirect=failed_redirect +failed_disconnect=failed_disconnect +clientAddress=clientAddress +overrideAddress=overrideAddress +serviceInfo=serviceInfo +consumerAddress=consumerAddress +providerAddress=providerAddress +registryAddress=registryAddress +serviceName=serviceName +serviceUrl=serviceUrl +overrideConsumerAddress=overrideConsumerAddress +overrideProviderAddress=overrideProviderAddress +tipConsumerAddress=tipConsumerAddress +tipProviderAddress=tipProviderAddress +tipProviderAddress=tipProviderAddress +logs=logs +logs.file=logs.file +logs.size=logs.size +logs.modify=logs.modify +logs.level=logs.level +change.log.level=change.log.level +logs.confirmChangeLogLevel=logs.confirmChangeLogLevel +cached=cached +cached.type=cached.type +cached.data=cached.data +cached.reload=cached.reload +batch.cached.reload=batch.cached.reload +cached.recover=cached.recover +batch.cached.recover=batch.cached.recover +servicePrivilege=servicePrivilege +creator=creator +name=name +department=department +email=email +phone=phone +alitalk=alitalk +password=password +roleR=roleR +roleA=roleA +roleG=roleG +roleDescR=roleDescR +roleDescA=roleDescA +roleDescG=roleDescG +oldPassword=oldPassword +newPassword=newPassword +reset=reset +restPassword=restPassword +confirmNewPassword=confirmNewPassword +owns=owns +confirmPassword=confirmPassword +generatePassword=generatePassword +displayName=displayName +locale=locale +privilegeTip=\u591a\u4e2a\u503c\u7528\u9017\u53f7(,)\u5206\u9694\uff0c\u901a\u914d\u7b26\u7528\u661f\u53f7(*)\u8868\u793a\uff0c\u53ea\u80fd\u5728\u6bcf\u4e2a\u503c\u7684\u672a\u5c3e\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u88ab\u6388\u4e0e\u7684\u6743\u9650\u4e0d\u80fd\u8d85\u51fa\u5f53\u524d\u7ba1\u7406\u4eba\u5458\u7684\u6743\u9650 +displayNameTip=\u7528\u6237\u59d3\u540d\uff0c\u53ef\u4f7f\u7528\u4e2d\u6587\uff0c\u75311-50\u4e2a\u5b57\u7b26\u7ec4\u6210 +emailTip=\u7528\u4e8e\u63a5\u6536\u7cfb\u7edf\u90ae\u4ef6\uff0c\u53ef\u4ee5\u8f93\u5165\u591a\u4e2a\u90ae\u4ef6\u5730\u5740\uff0c\u4f7f\u7528\u82f1\u6587\u5206\u53f7\u5206\u9694(;)\uff0c \u5f62\u5982 foo1@163.comj;foo2@gmail.com +userLocaleTip=\u53d1\u9001\u7cfb\u7edf\u90ae\u4ef6\u65f6\uff0c\u5c06\u6839\u636e\u7528\u6237\u4f7f\u7528\u7684\u8bed\u8a00\u53d1\u9001\u4e0d\u540c\u8bed\u8a00\u7684\u90ae\u4ef6\u5185\u5bb9 +DisplayNameTip=DisplayNameTip +EmailTip=EmailTip +UserLocaleTip=UserLocaleTip +missRequestParameters=missRequestParameters +haveNoRootPrivilege=haveNoRootPrivilege +confirmReloadCache=confirmReloadCache +confirmDeleteRegistry=confirmDeleteRegistry +confirmAutoRedirectRegistry=confirmAutoRedirectRegistry +confirmDeleteExpiredRegistry=confirmDeleteExpiredRegistry +confirmSyncRegistry=confirmSyncRegistry +confirm.toblacklist=\u786e\u8ba4\u52a0\u5165\u9ed1\u540d\u5355?
\u5982\u679c\u6ca1\u6709\u767d\u540d\u5355\uff0c\u5c06\u7981\u6b62\u5728\u9ed1\u540d\u5355\u5185\u7684\u6240\u6709\u6d88\u8d39\u8005\u8bbf\u95ee\u3002 +confirm.towhitelist=\u786e\u8ba4\u52a0\u5165\u767d\u540d\u5355?
\u5c06\u7981\u6b62\u4e0d\u5728\u767d\u540d\u5355\u5185\u7684\u6240\u6709\u5176\u5b83\u6d88\u8d39\u8005\u8bbf\u95ee\uff0c\u9ed1\u540d\u5355\u5931\u6548\u3002 +confirm.clean.operation=confirm.clean.operation +autoRedirect=autoRedirect +deleteExpired=deleteExpired +sync=sync +legacies=legacies +logined=logined +dumps=dumps +Registry=Registry +Java=JDK version +Locale=Locale +OS=OS +Uptime=Uptime +Host=Host +CPU=CPU +confirmEnableUser=confirmEnableUser +confirmDisableUser=confirmDisableUser +documentTitle=documentTitle +documentLink/documentPage=documentLink/documentPage +documentInternal=documentInternal +documentExternal=documentExternal +documentApi=API +documentType=documentType +documentContent=documentContent +Yes=Yes +No=No +returnValue=returnValue +throwException= +testMethodTip=\u5982\u679c\u6709\u65b9\u6cd5\u91cd\u8f7d\u6216\u4f7f\u7528Dubbo1.0.x\u7248\u672c\u7684\u670d\u52a1\u63d0\u4f9b\u8005\uff0c\u9700\u5199\u5168\u65b9\u6cd5\u7b7e\u540d\uff0c\u5982\uff1afindBy(int,java.lang.String)\uff0c\u5426\u5219\u53ea\u9700\u65b9\u6cd5\u540d\uff0c\u5982\uff1afindBy +testJsonTip=JSON\u683c\u5f0f\uff1a\u5b57\u7b26\u4e32\u7528\u53cc\u5f15\u53f7\u8868\u793a\uff0c\u5982\uff1a"\u5b57\u7b26\u4e32"\uff0c\u6570\u5b57\u548cBoolean\u503c\u4e0d\u7528\u5f15\u53f7\uff0c\u5982\uff1a123 \u548c true \u6216 false\uff0cPOJO\u5bf9\u8c61\u6216Map\u7528\u5927\u62ec\u53f7\u8868\u793a\uff0c\u5982\uff1a{"\u5c5e\u6027\u540d1": "\u5c5e\u6027\u503c1", "\u5c5e\u6027\u540d2": "\u5c5e\u6027\u503c2"}\uff0c\u6570\u7ec4\u6216List\u6216Set\u7528\u65b9\u62ec\u53f7\u8868\u793a\uff0c\u5982\uff1a["\u503c1", "\u503c2"] +testParametersTip=\u5f53\u4e3a\u65e0\u53c2\u6570\u65b9\u6cd5\u65f6\u53c2\u6570\u503c\u53ef\u4ee5\u4e0d\u586b\uff0c\u53c2\u6570\u503c\u4f7f\u7528JSON\u683c\u5f0f\u8868\u793a +testResultTip=\u5f53\u4e3avoid\u65b9\u6cd5\u65f6\u7ed3\u679c\u53ef\u4ee5\u4e0d\u586b\uff0c\u629b\u51fa\u5f02\u5e38\u4f7f\u7528\u5f02\u5e38\u7c7b\u5168\u540d\u8868\u793a\uff0c\u8fd4\u56de\u503c\u4f7f\u7528JSON\u683c\u5f0f\u8868\u793a +testAutoRunTip=\u5982\u679c\u8bbe\u7f6e\u4e3a\u81ea\u52a8\u8fd0\u884c\uff0c\u82e5\u8be5\u670d\u52a1\u5df2\u6ce8\u518c\u6216\u65b0\u6ce8\u518c\uff0c\u5219\u81ea\u52a8\u8fd0\u884c\u6b64\u6d4b\u8bd5\u7528\u4f8b\uff0c\u8fd0\u884c\u5931\u8d25\uff0c\u5c06\u53d1\u9001\u90ae\u4ef6 +confirmRunTest=confirmRunTest +confirm.runAll=confirm.runAll +loadBalanceStrategy=loadBalanceStrategy +random=random +roundrobin=roundrobin +leastactive=leastactive +testName=testName +operator=operator +dataFormat=dataFormat +resultType=resultType +resultController=resultController +autoRun=autoRun +manualRun=manualRun +run=run +runAll=runAll +expected=expected +actual=actual +reRun=reRun +startDate=startDate +console=console +total=total +delta=delta +expired=expired +alived=alived +redirect=redirect +current=current +#overrides +override.config=override.config +override.mock=override.mock +parameter=parameter +parameter.key=parameter.key +parameter.value=parameter.value +parameter.tip=\u65b9\u6cd5\u7ea7\u914d\u7f6e\u5982\uff1afindPerson.timeout=1000 +mock.all.method=\u6240\u6709\u65b9\u6cd5\u7684Mock\u503c +mock.method=mock.method +mock.value=mock.value +mock.tip=\u793a\u4f8b\uff1areturn null/empty/JSON\u6216throw com.foo.BarException +protocol=protocol +host=host +port=port +interface=interface +version=version +group=group +methods=methods +category=category +application=application +owner=owner +cluster=cluster +loadbalance=loadbalance +timeout=timeout +retries=retries +threads=threads +connections=connections +accepts=accepts +actives=actives +executes=executes +check=check +side=side +pid=pid +timestamp=timestamp +dubbo=dubbo +anyhost=anyhost +weight=weight +weight.doubling=weight.doubling +weight.halving=weight.halving +confirm.weight.doubling=confirm.weight.doubling +confirm.weight.halving=confirm.weight.halving +batch.weight.doubling=batch.weight.doubling +batch.weight.halving=batch.weight.halving +confirm.batch.weight.doubling=confirm.batch.weight +confirm.batch.weight.halving=confirm.batch.weight +NoSuchOperationData=NoSuchOperationData +CanNotDeleteDynamicData=CanNotDeleteDynamicData +HaveNoServicePrivilege=HaveNoServicePrivilege +dynamic.parameters.tip=dynamic.parameters.tip +default.owner=Owner +logger=logger +default.server=default.server +default.actives=default.actives +default.client=default.client +default.connections=default.connections diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_zh.properties b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_zh.properties new file mode 100644 index 0000000..83e8753 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_zh.properties @@ -0,0 +1,802 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +#menus +home=\u9996\u9875 +stat=\u7edf\u8ba1 +revision=\u4fee\u8ba2\u7248\u672c +connectionNum=\u8fde\u63a5\u6570 +serviceNum=\u670d\u52a1\u6570 +providerNum=\u63d0\u4f9b\u8005\u6570 +consumerNum=\u6d88\u8d39\u8005\u6570 +applicationNum=\u5e94\u7528\u6570 +about=\u5173\u4e8e +help=\u5e2e\u52a9 +favorites=\u6536\u85cf\u5939 +histories=\u5386\u53f2\u8bb0\u5f55 +governance=\u670d\u52a1\u6cbb\u7406 +applications=\u5e94\u7528 +efferents=\u4f9d\u8d56 +afferents=\u88ab\u4f9d\u8d56 +services=\u670d\u52a1 +references=\u5f15\u7528\u670d\u52a1 +addresses=\u673a\u5668 +providers=\u63d0\u4f9b\u8005 +dependencies=\u4f9d\u8d56\u5173\u7cfb +layers=\u5206\u5c42 +clusters=\u96c6\u7fa4 +consumers=\u6d88\u8d39\u8005 +accesses=\u8BBF\u95EE\u63A7\u5236 +routes=\u8def\u7531\u89C4\u5219 +weights=\u6743\u91cd\u8C03\u8282 +loadbalances=\u8d1f\u8f7d\u5747\u8861 +tests=\u6d4b\u8bd5 +mocks=\u6a21\u62df +overrides=\u52a8\u6001\u914d\u7f6e +documents=\u6587\u6863 +owners=\u8d1f\u8d23\u4eba +agreements=\u534f\u5b9a +approvals=\u4e0a\u7ebf\u5ba1\u6279 +operations=\u64cd\u4f5c\u65e5\u5fd7 +users=\u7528\u6237 +envs=\u7cfb\u7edf\u73af\u5883 +helps=\u5e2e\u52a9\u6587\u6863 +registries=\u6ce8\u518c\u4e2d\u5fc3 +configs=\u7cfb\u7edf\u53c2\u6570 +features=\u7cfb\u7edf\u529f\u80fd +connections=\u8fde\u63a5 +statuses=\u7CFB\u7EDF\u72B6\u6001 +failed=\u5931\u8d25\u8bb0\u5f55 +cached=\u7f13\u5b58\u8bb0\u5f55 +dumps=\u5feb\u7167 +InvalidIp=\u65e0\u6548\u0069\u0070\u5730\u5740 +versions=Dubbo\u7248\u672c +logs=\u65e5\u5fd7 +infos=\u4fee\u6539\u4e2a\u4eba\u4fe1\u606f +passwds=\u4fee\u6539\u4e2a\u4eba\u5bc6\u7801 +dependency.list=\u5217\u8868 +dependency.tree=\u6811\u72b6 +dependency.graph=\u56fe\u5f62 +dependency.efferent=\u4f9d\u8d56 +dependency.afferent=\u88ab\u4f9d\u8d56 +provided=\u63d0\u4f9b\u670d\u52a1 +consumed=\u6d88\u8d39\u670d\u52a1 +select=\u9009\u62e9 +clean=\u6e05\u9664 +information=\u4fe1\u606f +control=\u63a7\u5236 +summary=\u6c47\u603b +consumer.application=\u6d88\u8d39\u8005\u5e94\u7528 +response.time=\u54cd\u5e94\u65f6\u95f4 +sysinfo.infos=\u7cfb\u7edf\u4fe1\u606f +helps.document=\u6587\u6863 +helps.requirement=\u9700\u6c42 +helps.source=\u6e90\u4ee3\u7801 +connections=\u5957\u63a5\u5b57\u8fde\u63a5 +ReconnectUnkwown=\u91cd\u8fde\u6240\u6709\u672a\u77e5\u8fde\u63a5 +confirmReconnectConnection=\u786e\u8ba4\u91cd\u5efa\u8fde\u63a5 +confirmRedirectRegistry=\u786e\u8ba4\u91cd\u5b9a\u5411\u6ce8\u518c\u4e2d\u5fc3 +confirmReconnectUnknownConnection=\u786e\u8ba4\u91cd\u8fde\u672a\u77e5\u7684\u8fde\u63a5 +status.resourcename=\u8d44\u6e90\u540d\u79f0 +status.status=\u72b6\u6001 +status.message=\u4fe1\u606f +status.description=\u63cf\u8ff0 +status.memoryStatus=\u5185\u5b58 +status.memoryStatusDesc=\u53ea\u76d1\u63a7Heap\u5185\u5b58\uff0c\u5982\u679c\u7a7a\u95f2\u5185\u5b58\u4e0d\u8db31M\u5219\u8b66\u544a\uff0c\u5426\u5219\u6b63\u5e38 +status.threadpoolStatus=\u7ebf\u7a0b\u6c60 +status.threadpoolStatusDesc=\u53ea\u76d1\u63a7\u6ce8\u518c\u8ba2\u9605\u4e3b\u4e1a\u52a1\u7ebf\u7a0b\u6c60\uff0c\u5982\u679c\u7a7a\u95f2\u7ebf\u7a0b\u5c11\u4e8e1\u4e2a\uff0c\u5219\u8b66\u544a\uff0c\u5426\u5219\u6b63\u5e38 +status.failureStatus=\u5931\u8d25\u8bb0\u5f55 +status.failureStatusDesc=\u5f53\u6709\u4efb\u4f55\u5931\u8d25\u8bb0\u5f55\u5219\u8b66\u544a\uff0c\u5426\u5219\u6b63\u5e38 +status.cacheStatus=\u7f13\u5b58 +status.cacheStatusDesc=\u5982\u679c\u7f13\u5b58\u4e0e\u6570\u636e\u5e93\u4e0d\u4e00\u81f4\u5219\u8b66\u544a\uff0c\u5426\u5219\u6b63\u5e38 +status.timerStatus=\u5b9a\u65f6\u5668 +status.timerStatusDesc=\u5f53\u5b9a\u65f6\u5668\u672a\u6b63\u786e\u542f\u52a8\uff0c\u6216\u88ab\u4e0d\u6b63\u5e38\u53d6\u6d88\uff0c\u5219\u62a5\u9519\uff0c\u5426\u5219\u6b63\u5e38 +status.socketStatus=\u5957\u63a5\u5b57 +status.socketStatusDesc=\u5f53\u5957\u63a5\u53e3\u5f00\u542f\u4e0d\u4e86\u6216\u5df2\u88ab\u5360\u7528\u65f6\u62a5\u9519\uff0c\u5f53\u8fde\u63a5\u6570\u7b49\u4e8e\u6700\u5927\u503c\u65f6\u8b66\u544a\uff0c\u5426\u5219\u6b63\u5e38 +status.loadStatus=\u8d1f\u8f7d +status.loadStatusDesc=\u5982\u679c\u8d1f\u8f7d\u5927\u4e8eCPU\u4e2a\u6570\u5219\u8b66\u544a\uff0c\u5982\u679c\u7cfb\u7edf\u4e0d\u652f\u6301\u67e5\u8be2\u8d1f\u8f7d\u5219\u4e0d\u542f\u7528\uff0c\u5426\u5219\u6b63\u5e38 +status.datasourceStatus=\u6570\u636e\u5e93 +status.datasourceStatusDesc=\u53d1\u9001\u4e00\u6761\u7b80\u5355\u67e5\u8be2SQL\uff0c\u6267\u884c\u6210\u529f\u5219\u6b63\u5e38\uff0c\u5426\u5219\u62a5\u9519 +status.registryStatus=\u6CE8\u518C\u4E2D\u5FC3 +status.registryStatusDesc=\u5982\u679C\u8FDE\u4E0D\u4E0A\u6CE8\u518C\u4E2D\u5FC3\u5219\u62A5\u9519\uFF0C\u5426\u5219\u6B63\u5E38 +status.monitorStatus=\u76d1\u89c6\u5668 +status.monitorStatusDesc=\u76d1\u89c6\u5668 +status.summaryStatus=\u6c47\u603b +status.summaryStatusDesc=\u6709\u72b6\u6001\u6c47\u603b\uff0c\u5ffd\u7565\u672a\u542f\u7528\u7684\u72b6\u6001\uff0c\u53ea\u8981\u6709\u4e00\u4e2a\u62a5\u9519\uff0c\u5219\u62a5\u9519\uff0c\u53ea\u8981\u6709\u4e00\u4e2a\u8b66\u544a\uff0c\u5219\u8b66\u544a\uff0c\u5168\u90e8\u6b63\u5e38\u5219\u6b63\u5e38 +status.warmupStatus=\u8fd0\u884c\u72b6\u6001 +status.warmupStatusDesc=\u5904\u4e8ewarmup\u72b6\u6001\u65f6\uff0c\u810f\u6570\u636e\u68c0\u6d4b\u3001\u91cd\u5b9a\u5411\u3001\u4e8b\u4ef6\u53d8\u66f4\u5b9a\u65f6\u5668\u5747\u4e0d\u5de5\u4f5c,\u4e0d\u63a8\u9001\u53d8\u66f4 +status.OK=\u6b63\u5e38 +status.WARN=\u8b66\u544a +status.ERROR=\u9519\u8bef +status.UNKNOWN=\u672a\u77e5 +Status0=Unknow +Status1=OK +Status2=OK +Status3=ERROR +Status4=FATAL +Status5=UNKNOW +mock=\u964d\u7ea7 +force.mocked=\u5DF2\u5C4F\u853D +fail.mocked=\u5DF2\u5BB9\u9519 +no.mocked=\u672A\u964D\u7EA7 +force.mock=\u5c4f\u853d +fail.mock=\u5bb9\u9519 +cancel.mock=\u6062\u590d +confirm.force.mock=\u786e\u8ba4\u5c4f\u853d\u8be5\u670d\u52a1\u7684\u8c03\u7528\uff1f
\u5C4F\u853D\u540E\uFF0C\u5c06\u4e0d\u53d1\u8d77\u8fdc\u7a0b\u8c03\u7528\uff0c\u76f4\u63a5\u5728\u5BA2\u6237\u7AEF\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.fail.mock=\u786e\u8ba4\u5bf9\u8be5\u670d\u52a1\u5bb9\u9519\uff1f
\u5BB9\u9519\u540E\uFF0C\u5f53\u8FDC\u7A0B\u8c03\u7528\u5931\u8d25\u65f6\uff0c\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.cancel.mock=\u786e\u8ba4\u6062\u590d\u8be5\u670d\u52a1\u6b63\u5e38\u8bbf\u95ee\uff1f
\u5c06\u53d6\u6d88\u670d\u52a1\u7684\u5c4f\u853d\u548c\u5bb9\u9519\u884c\u4e3a\u3002 +batch.force.mock=\u6279\u91cf\u5c4f\u853d +batch.fail.mock=\u6279\u91cf\u5bb9\u9519 +batch.cancel.mock=\u6279\u91cf\u6062\u590d +confirm.batch.force.mock=\u786e\u8ba4\u6279\u91cf\u5c4f\u853d\u670d\u52a1\u7684\u8c03\u7528\uff1f
\u5C4F\u853D\u540E\uFF0C\u5c06\u4e0d\u53d1\u8d77\u8fdc\u7a0b\u8c03\u7528\uff0c\u76f4\u63a5\u5728\u5BA2\u6237\u7AEF\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.batch.fail.mock=\u786e\u8ba4\u6279\u91cf\u5bf9\u670d\u52a1\u5bb9\u9519\uff1f
\u5BB9\u9519\u540E\uFF0C\u5f53\u8FDC\u7A0B\u8c03\u7528\u5931\u8d25\u65f6\uff0c\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.batch.cancel.mock=\u786e\u8ba4\u6279\u91cf\u6062\u590d\u670d\u52a1\u6b63\u5e38\u8bbf\u95ee\uff1f
\u5c06\u53d6\u6d88\u670d\u52a1\u7684\u5c4f\u853d\u548c\u5bb9\u9519\u884c\u4e3a\u3002 +all.force.mock=\u7F3A\u7701\u5c4f\u853d +all.fail.mock=\u7F3A\u7701\u5bb9\u9519 +all.cancel.mock=\u7F3A\u7701\u6062\u590d +confirm.all.force.mock=\u786e\u8ba4\u7F3A\u7701\u5c4f\u853d\u8be5\u670d\u52a1\u7684\u8c03\u7528\uff1f
\u8BBE\u7F6E\u964D\u7EA7\u7F3A\u7701\u503C\uFF0C\u5C06\u5F71\u54CD\u672A\u964D\u7EA7\u4EE5\u53CA\u65B0\u7684\u6D88\u8D39\u8005\u3002
\u5C4F\u853D\u540E\uFF0C\u5c06\u4e0d\u53d1\u8d77\u8fdc\u7a0b\u8c03\u7528\uff0c\u76f4\u63a5\u5728\u5BA2\u6237\u7AEF\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.all.fail.mock=\u786e\u8ba4\u7F3A\u7701\u5bf9\u8be5\u670d\u52a1\u5bb9\u9519\uff1f
\u8BBE\u7F6E\u964D\u7EA7\u7F3A\u7701\u503C\uFF0C\u5C06\u5F71\u54CD\u672A\u964D\u7EA7\u4EE5\u53CA\u65B0\u7684\u6D88\u8D39\u8005\u3002
\u5BB9\u9519\u540E\uFF0C\u5f53\u8FDC\u7A0B\u8c03\u7528\u5931\u8d25\u65f6\uff0c\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.all.cancel.mock=\u786e\u8ba4\u7F3A\u7701\u6062\u590d\u8be5\u670d\u52a1\u6b63\u5e38\u8bbf\u95ee\uff1f
\u8BBE\u7F6E\u964D\u7EA7\u7F3A\u7701\u503C\uFF0C\u5C06\u5F71\u54CD\u672A\u964D\u7EA7\u4EE5\u53CA\u65B0\u7684\u6D88\u8D39\u8005\u3002
\u5c06\u53d6\u6d88\u670d\u52a1\u7684\u5c4f\u853d\u548c\u5bb9\u9519\u884c\u4e3a\u3002 +agreement.invocation.quantity=\u4e00\u5929\u8c03\u7528\u91cf +agreement.tps=TPS\u4e0a\u9650 +response.time=\u54cd\u5e94\u65f6\u95f4 +agreement.availability=\u53ef\u7528\u7387 +layer.name=\u5206\u5c42\u540d\u79f0 +layer.value=\u6570\u5b57\u7b49\u7ea7 +layer.arch=\u5206\u5c42\u67b6\u6784 +loadBalanceStrategy=\u8d1f\u8f7d\u5747\u8861\u7b56\u7565 +ServiceName=\u670d\u52a1\u540d +cluster.name=\u96c6\u7fa4\u540d +cluster.address=\u96c6\u7fa4\u673a\u5668\u5730\u5740 +property.name=\u5c5e\u6027\u540d +property.value=\u5c5e\u6027\u503c +property.count=\u5c5e\u6027\u6570\u91cf +getMethods=\u83b7\u53d6\u670d\u52a1\u65b9\u6cd5 +getAddresses=\u83b7\u53d6\u63d0\u4f9b\u8005\u5730\u5740 +Edit=\u7f16\u8f91 +Username=\u7528\u6237\u540d +Priority=\u4f18\u5148\u7ea7 +ConnectionAddress=\u8fde\u63a5\u5730\u5740 +Role=\u89d2\u8272 +Reconnect=\u91cd\u8fde +Redirect=\u91cd\u5b9a\u5411 +staff.query=\u5185\u7f51\u67e5\u8be2 +configKey=\u914d\u7f6e\u9879 +configValue=\u914d\u7f6e\u9879\u503c +Preview=\u9884\u89c8 +routeselect=\u8def\u7531\u9884\u89c8\uff08\u9009\u62e9\u6d88\u8d39\u8005\uff09 +AllOperations=\u6240\u6709\u64cd\u4f5c\u8bb0\u5f55 +BeforeOneMonthOperations=\u4e00\u4e2a\u6708\u4ee5\u524d\u7684\u6240\u6709\u64cd\u4f5c\u8bb0\u5f55 +BeforeThreeMonthOperations=\u4e09\u4e2a\u6708\u4ee5\u524d\u7684\u6240\u6709\u64cd\u4f5c\u8bb0\u5f55 +BeforeHalfYearOperations=\u534a\u5e74\u4ee5\u524d\u7684\u6240\u6709\u64cd\u4f5c\u8bb0\u5f55 +BeforeOneYearOperations=\u4e00\u5e74\u4ee5\u524d\u7684\u6240\u6709\u64cd\u4f5c\u8bb0\u5f55 +PleaseInput=\u8bf7\u8f93\u5165 +BulletinConfig=\u516c\u544a\u914d\u7f6e +BulletinMessage=\u516c\u544a\u4fe1\u606f +MailConfig=\u90ae\u7bb1\u914d\u7f6e +MailEnabled=\u662f\u5426\u542f\u7528\u90ae\u7bb1 +MailHost=\u90ae\u4ef6\u670d\u52a1\u5668\u4e3b\u673a +MailPort=\u90ae\u4ef6\u670d\u52a1\u5668\u7aef\u53e3 +MailFrom=\u90ae\u4ef6\u53d1\u4ef6\u4eba\u5730\u5740 +MailAuth=\u90ae\u7bb1\u662f\u5426\u9700\u8981\u767b\u5f55 +MailUsername=\u90ae\u7bb1\u767b\u5f55\u7528\u6237\u540d +MailPassword=\u90ae\u7bb1\u767b\u5f55\u5bc6\u7801 +LoginConfig=\u767b\u5f55\u914d\u7f6e +AllowAnonymousLogin=\u5141\u8bb8\u533f\u540d\u767b\u5f55 +AllowLegacyLogin=\u5141\u8bb8\u9057\u7559\u7cfb\u7edf\u767b\u5f55 +RouteEnabled=\u662f\u5426\u5f00\u542f\u8def\u7531\u529f\u80fd +WarmupEnabled=\u662f\u5426\u8fdb\u5165\u9884\u70ed\u72b6\u6001 +LogConfig=\u65e5\u5fd7\u914d\u7f6e +LogLevel=\u65e5\u5fd7\u7ea7\u522b +RedirectConfig=\u91cd\u5b9a\u5411\u914d\u7f6e +AutoRedirectInterval=\u81ea\u52a8\u91cd\u5b9a\u5411\u68c0\u67e5\u95f4\u9694(\u6beb\u79d2) +AutoRedirectThreshold=\u80fd\u591f\u81ea\u52a8\u91cd\u5b9a\u5411\u7684\u8fde\u63a5\u4e0b\u754c +AutoRedirectToleratePercent=\u81ea\u52a8\u91cd\u5b9a\u5411\u65f6\u8fde\u63a5\u6570\u504f\u5dee\u5bb9\u5fcd\u767e\u5206\u6bd4 +ManualRedirect=\u91cd\u5b9a\u5411{0}\u4e2a +LimitConfig=\u8d44\u6e90\u9650\u5236\u914d\u7f6e +MaxThreadSize=\u6700\u5927\u7ebf\u7a0b\u6570 +MaxConnectionSize=\u6700\u5927\u8fde\u63a5\u6570 +MaxCacheSize=\u6700\u5927\u7f13\u5b58\u6570 +MaxMailSize=\u6700\u5927\u90ae\u4ef6\u961f\u5217\u6570 +TimerConfig=\u5b9a\u65f6\u5668\u914d\u7f6e +AlivedCheckInterval=\u6ce8\u518c\u4e2d\u5fc3\u5b58\u6d3b\u72b6\u6001\u68c0\u67e5\u95f4\u9694(\u6beb\u79d2) +ChangedCheckInterval=\u6570\u636e\u53d8\u66f4\u68c0\u67e5\u95f4\u9694(\u6beb\u79d2) +FailedRetryInterval=\u5931\u8d25\u91cd\u8bd5\u95f4\u9694(\u6beb\u79d2) +DirtyCheckInterval=\u810f\u6570\u636e\u68c0\u67e5\u95f4\u9694(\u6beb\u79d2) +HeartbeatConfig=\u5fc3\u8df3\u914d\u7f6e +HeartbeatCheckInterval=\u4e0e\u5ba2\u6237\u7aef\u8fde\u63a5\u5fc3\u8df3\u68c0\u67e5\u95f4\u9694(\u6beb\u79d2) +HeartbeatCheckTimeout=\u5fc3\u8df3\u8d85\u65f6\u65f6\u95f4(\u6beb\u79d2) +TimeoutConfig=\u8d85\u65f6\u914d\u7f6e +NotifyTimeout=\u4e8b\u4ef6\u63a8\u9001\u8d85\u65f6(\u6beb\u79d2) +WarmupWaitTime=\u542f\u52a8\u9884\u70ed\u65f6\u95f4(\u6beb\u79d2) +UrlConfig=URL\u914d\u7f6e +BucServiceAddress=BUC\u670d\u52a1\u5730\u5740 +HelpDocumentUrl=\u5e2e\u52a9\u6587\u6863URL +HomepageDomain=\u663e\u793a\u4e3b\u9875\u57df\u540d +HomepageUrl=\u4e3b\u9875\u5730\u5740 +parametersConfig=\u53c2\u6570\u914d\u7f6e +DefaultServiceParameters=\u7f3a\u7701\u53c2\u6570\u914d\u7f6e +BatchAddressTip=\u591a\u4e2a\u5730\u5740\u7528\u6362\u884c\u7b26\u5206\u9694\uff0c\u5730\u5740\u5fc5\u9700\u662f0.0.0.0\u5230255.255.255.255\u7684IP\u5730\u5740 +ConsumerAddress=\u6d88\u8d39\u8005\u5730\u5740 +AccessControlTip=\u767d\u540d\u5355\u4f18\u5148\uff0c\u53ea\u8981\u6709\u767d\u540d\u5355\uff0c\u5219\u767d\u540d\u5355\u751f\u6548\uff0c\u5426\u5219\u9ed1\u540d\u5355\u751f\u6548 +access=\u8BBF\u95EE +Allowed=\u5DF2\u5141\u8BB8 +Forbidden=\u5DF2\u7981\u6B62 +allow=\u5141\u8BB8 +forbid=\u7981\u6B62 +confirm.allow=\u786E\u8BA4\u5141\u8BB8\u8BBF\u95EE? +confirm.forbid=\u786E\u8BA4\u7981\u6B62\u8BBF\u95EE?
\u88AB\u7981\u6B62\u7684\u5BA2\u6237\u7AEF\u5C06\u6536\u5230\u7981\u6B62\u8BBF\u95EE\u5F02\u5E38\u3002 +batch.allow=\u6279\u91CF\u5141\u8BB8 +batch.forbid=\u6279\u91CF\u7981\u6B62 +confirm.batch.allow=\u786E\u8BA4\u5141\u8BB8\u6240\u9009\u9879\u8BBF\u95EE? +confirm.batch.forbid=\u786E\u8BA4\u7981\u6B62\u6240\u9009\u9879\u8BBF\u95EE?
\u88AB\u7981\u6B62\u7684\u5BA2\u6237\u7AEF\u5C06\u6536\u5230\u7981\u6B62\u8BBF\u95EE\u5F02\u5E38\u3002 +only.allow=\u53EA\u5141\u8BB8 +only.forbid=\u53EA\u7981\u6B62 +confirm.only.allow=\u786E\u8BA4\u53EA\u5141\u8BB8\u9009\u4E2D\u9879\u8BBF\u95EE?
\u5176\u5B83\u672A\u9009\u4E2D\u9879\u53CA\u4EE5\u540E\u65B0\u589E\u9879\u5C06\u5168\u90E8\u53D8\u4E3A\u7981\u6B62\u8BBF\u95EE\u3002
\u88AB\u7981\u6B62\u7684\u5BA2\u6237\u7AEF\u5C06\u6536\u5230\u7981\u6B62\u8BBF\u95EE\u5F02\u5E38\u3002 +confirm.only.forbid=\u786E\u8BA4\u53EA\u7981\u6B62\u9009\u4E2D\u9879\u8BBF\u95EE?
\u5176\u5B83\u672A\u9009\u4E2D\u9879\u53CA\u4EE5\u540E\u65B0\u589E\u9879\u5C06\u5168\u90E8\u53D8\u4E3A\u5141\u8BB8\u8BBF\u95EE\u3002
\u88AB\u7981\u6B62\u7684\u5BA2\u6237\u7AEF\u5C06\u6536\u5230\u7981\u6B62\u8BBF\u95EE\u5F02\u5E38\u3002 +Choose=\u8bf7\u9009\u62e9 +userown=\u8d1f\u8d23\u7684\u670d\u52a1 +sysmanage.userown=\u8d1f\u8d23\u7684\u670d\u52a1 +SingleServiceTip=\u4e00\u4e2a\u8def\u7531\u53ea\u80fd\u5e94\u7528\u4e8e\u4e00\u4e2a\u670d\u52a1\uff0c\u4e0d\u652f\u6301\u591a\u670d\u52a1\u53ca\u901a\u914d\u7b26 +MultiServiceTip=\u670d\u52a1\u63a5\u53e3\u540d\u53ef\u4ee5\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u53ea\u652f\u6301\u4e00\u4e2a*\u7b26\u4e14\u8981\u5728\u63a5\u53e3\u672b\u5c3e\uff08\u5206\u7ec4\u3001\u7248\u672c\u4e0d\u652f\u6301\u901a\u914d\u7b26\uff09 +RouteNameTip=\u53ef\u4f7f\u7528\u4e2d\u6587\uff0c\u75311-200\u4e2a\u5b57\u7b26\u7ec4\u6210 +RoutePriorityTip=\u6570\u5b57\u8d8a\u5927\u8d8a\u4f18\u5148 +RouteServiceTip=\u4e00\u4e2a\u8def\u7531\u53ea\u80fd\u5e94\u7528\u4e8e\u4e00\u4e2a\u670d\u52a1\uff0c\u4e0d\u652f\u6301\u591a\u670d\u52a1\u53ca\u901a\u914d\u7b26 +#RouteServiceTip=\u670d\u52a1\u63a5\u53e3\u540d\u53ef\u4ee5\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u53ea\u652f\u6301\u4e00\u4e2a*\u7b26\u4e14\u8981\u5728\u63a5\u53e3\u672b\u5c3e\uff08\u5206\u7ec4\u3001\u7248\u672c\u4e0d\u652f\u6301\u901a\u914d\u7b26\uff09 +RouteMethodTip=\u53ea\u6709Dubbo2.0.0\u4ee5\u4e0a\u7248\u672c\u7684\u670d\u52a1\u6d88\u8d39\u7aef\u652f\u6301\u6309\u65b9\u6cd5\u8def\u7531\uff0c\u591a\u4e2a\u65b9\u6cd5\u540d\u7528\u9017\u53f7\u5206\u9694 +RouteClusterTip=\u53ef\u901a\u8fc7\u83dc\u5355"\u670d\u52a1\u63a7\u5236"->"\u670d\u52a1\u5668\u96c6\u7fa4"\u7ba1\u7406 +RouteMatchTip=\u5f53\u6d88\u8d39\u8005\u6ee1\u8db3\u5339\u914d\u6761\u4ef6\u65f6\u4f7f\u7528\u5f53\u524d\u89c4\u5219\u8fdb\u884c\u8fc7\u6ee4 +RouteFilterTip=\u6ee1\u8db3\u8fc7\u6ee4\u89c4\u5219\u7684\u63d0\u4f9b\u8005\u5730\u5740\u5c06\u88ab\u63a8\u9001\u7ed9\u6d88\u8d39\u8005 +RouteHostTip=\u591a\u4e2a\u503c\u7528\u9017\u53f7\u5206\u9694\uff0c\u4ee5\u661f\u53f7\u7ed3\u5c3e\u8868\u793a\u901a\u914d\u5730\u5740\u6bb5 +RouteApplicationTip=\u591a\u4e2a\u503c\u7528\u9017\u53f7\u5206\u9694 +RouteResult=\u8def\u7531\u7ed3\u679c +preview=\u9884\u89c8 +ConsumerApplication=\u6d88\u8d39\u8005\u5e94\u7528\u540d +ConsumerCluster=\u6d88\u8d39\u8005\u96c6\u7fa4 +ConsumerHost=\u6d88\u8d39\u8005IP\u5730\u5740 +ConsumerVersion=\u6d88\u8d39\u8005\u7248\u672c\u53f7 +ConsumerGroup=\u6d88\u8d39\u8005\u540d\u79f0\u7a7a\u95f4 +ProviderApplication=\u63d0\u4f9b\u8005\u5e94\u7528 +ProviderCluster=\u63d0\u4f9b\u8005\u96c6\u7fa4 +ProviderProtocol=\u63d0\u4f9b\u8005\u534f\u8bae +ProviderHost=\u63d0\u4f9b\u8005IP\u5730\u5740 +ProviderPort=\u63d0\u4f9b\u8005\u7aef\u53e3 +ProviderVersion=\u63d0\u4f9b\u8005\u7248\u672c\u53f7 +ProviderGroup=\u63d0\u4f9b\u8005\u540d\u79f0\u7a7a\u95f4 +MatchRule=\u5339\u914d\u6761\u4ef6 +FilterRule=\u8fc7\u6ee4\u89c4\u5219 +routeName=\u8DEF\u7531\u540D\u79F0 +routeRule=\u8def\u7531\u89c4\u5219 +Match=\u5339\u914d +Mismatch=\u4e0d\u5339\u914d +GetMethods=\u83b7\u53d6\u670d\u52a1\u65b9\u6cd5 +FeatureName=\u529f\u80fd\u540d +Features=\u7cfb\u7edf\u529f\u80fd +Disable=\u7981\u7528 +Enable=\u542f\u7528 +Enabled=\u5df2\u542f\u7528 +Disabled=\u5df2\u7981\u7528 +Unknown=\u672a\u77e5 +Users=\u7528\u6237\u7ba1\u7406 +UsersDescription=\u7528\u6237\u4fe1\u606f\u7ba1\u7406 +StatusList=\u6ce8\u518c\u4e2d\u5fc3\u72b6\u6001 +StatusListDescription=\u6ce8\u518c\u4e2d\u5fc3\u7cfb\u7edf\u72b6\u6001 +Operations=\u64cd\u4f5c\u8bb0\u5f55 +OperationsDescription=\u8bb0\u5f55\u6240\u6709\u4eba\u4e3a\u7684\u64cd\u4f5c +Accesses=\u670d\u52a1\u9ed1\u767d\u540d\u5355 +AccessesDescription=\u670d\u52a1\u9ed1\u767d\u540d\u5355 +Configs=\u7cfb\u7edf\u914d\u7f6e +Clusters=\u670d\u52a1\u5668\u96c6\u7fa4 +ClustersDescription=\u7ba1\u7406\u670d\u52a1\u96c6\u7fa4\u4fe1\u606f +Weights=\u63d0\u4f9b\u8005\u6743\u91cd +WeightsDescription=\u7ba1\u7406\u63d0\u4f9b\u8005\u6743\u91cd\u4fe1\u606f +Agreements=\u670d\u52a1\u7b49\u7ea7\u534f\u5b9a +AgreementsDescription=\u670d\u52a1\u7b49\u7ea7\u534f\u5b9a +ConfigsDescription=\u7cfb\u7edf\u914d\u7f6e\u4fe1\u606f +LoadBalances=\u8d1f\u8f7d\u5747\u8861 +LoadBalancesDescription=\u8d1f\u8f7d\u5747\u8861 +CachedList=\u5185\u5b58\u7f13\u5b58 +CachedListDescription=\u6ce8\u518c\u4e2d\u5fc3\u5185\u5b58\u7f13\u5b58\u8bb0\u5f55 +FailedList=\u5931\u8d25\u8bb0\u5f55 +Registries=\u6ce8\u518c\u4e2d\u5fc3\u96c6\u7fa4 +FailedListDescription=\u5931\u8d25\u8bb0\u5f55\u5217\u8868 +registryAddress=\u6ce8\u518c\u4e2d\u5fc3\u5217\u8868 +RegistriesDescription=\u67e5\u770b\u5df2\u77e5\u7684\u6ce8\u518c\u4e2d\u5fc3 +Help=\u5e2e\u52a9 +HelpDescription=\u5e2e\u52a9 +Providers=\u670d\u52a1\u63d0\u4f9b\u8005 +ProvidersDescription=\u67e5\u770b\u6240\u6709\u670d\u52a1\u63d0\u4f9b\u8005 +Log=\u65e5\u5fd7\u6587\u4ef6 +LogDescription=\u67e5\u770b\u6ce8\u518c\u4e2d\u5fc3Log4J\u65e5\u5fd7 +Services=\u670d\u52a1\u4fe1\u606f +ServicesDescription=\u67e5\u770b\u670d\u52a1\u5df2\u6ce8\u518c\u7684\u6240\u6709\u670d\u52a1 +Owned=\u670d\u52a1\u5f52\u5c5e +OwnedDescription=\u670d\u52a1\u5f52\u5c5e +Tests=\u670d\u52a1\u6d4b\u8bd5 +TestsDescription=\u670d\u52a1\u6d4b\u8bd5\u7528\u4f8b +Documents=\u670d\u52a1\u6587\u6863 +DocumentsDescription=\u6587\u6863 +Applications=\u670d\u52a1\u5e94\u7528 +ApplicationsDescription=\u670d\u52a1\u5e94\u7528 +Consumers=\u670d\u52a1\u6d88\u8d39\u8005 +ConsumersDescription=\u67e5\u770b\u6240\u6709\u670d\u52a1\u6d88\u8d39\u8005 +System=\u7cfb\u7edf\u73af\u5883 +SystemDescription=\u7cfb\u7edf\u73af\u5883\u4fe1\u606f +Routes=\u670d\u52a1\u8def\u7531 +Route=\u8def\u7531 +RoutesDescription=\u7ba1\u7406\u670d\u52a1\u8def\u7531\u89c4\u5219 +Connections=\u5957\u63a5\u5b57\u8fde\u63a5 +ConnectionsDescription=\u8fde\u63a5 +RegistryAddress=\u6ce8\u518c\u4e2d\u5fc3\u5730\u5740 +RegisterUsername=\u6ce8\u518c\u7528\u6237\u540d +RegisterDate=\u6ce8\u518c\u65f6\u95f4 +subscribeDate=\u8ba2\u9605\u65f6\u95f4 +Statistics=\u670d\u52a1\u5b9e\u65f6\u7edf\u8ba1 +CheckConnection=\u68c0\u67e5\u8fde\u63a5 +CheckDatabase=\u68c0\u67e5\u6570\u636e\u5e93 +queryUrl=\u8ba2\u9605\u53c2\u6570 +Status=\u72b6\u6001 +notify=\u901A\u77E5 +notified=\u5df2\u901a\u77e5 +unnotified=\u672A\u901A\u77E5 +Unuse=\u672a\u4f7f\u7528 +NoProvider=\u6ca1\u6709\u63d0\u4f9b\u8005 +NoConsumer=\u6ca1\u6709\u6d88\u8d39\u8005 +route.consumer.not.match=\u672cRoute\u4e0d\u5339\u914d\u6b64\u670d\u52a1\u6d88\u8d39\u8005\uff08\u4f1a\u8fd4\u56de\u6240\u6709\u7684\u670d\u52a1\u63d0\u4f9b\u8005\uff09 +#labels +all=\u6240\u6709 +service=\u670d\u52a1\u540d +application=\u5e94\u7528\u540d +recursive=\u5faa\u73af +layer=\u670d\u52a1\u5206\u5c42 +address=\u673a\u5668IP +dubbo=\u4f7f\u7528dubbo\u7248\u672c +version=\u670d\u52a1\u7248\u672c +group=\u670d\u52a1\u5206\u7ec4 +url=\u670d\u52a1\u5730\u5740 +parameters=\u670d\u52a1\u53c2\u6570 +provider=\u63d0\u4f9b\u8005\u5730\u5740 +consumer=\u6d88\u8d39\u8005\u5730\u5740 +registry=\u6ce8\u518c\u4e2d\u5fc3\u5730\u5740 +username=\u7528\u6237\u540d +created=\u521b\u5efa\u65f6\u95f4 +modified=\u4fee\u6539\u65f6\u95f4 +register.date=\u6ce8\u518c\u65f6\u95f4 +type=\u7c7b\u578b +static=\u9759\u6001 +dynamic=\u52a8\u6001 +status=\u72b6\u6001 +enabled=\u5df2\u542f\u7528 +disabled=\u5df2\u7981\u7528 +check=\u68c0\u67e5 +operation=\u64cd\u4f5c +role=\u89d2\u8272 +provider=\u63d0\u4f9b\u8005 +consumer=\u6d88\u8d39\u8005 +consumer.address=\u6d88\u8d39\u8005\u5730\u5740 +no.provider=\u6ca1\u6709\u63d0\u4f9b\u8005 +no.consumer=\u6ca1\u6709\u6d88\u8d39\u8005 +ok=\u6b63\u5e38 +warn=\u8b66\u544a +error=\u51fa\u9519 +success=\u6210\u529f +failure=\u5931\u8d25 +update=\u66f4\u65b0 +operation.success=\u64cd\u4f5c\u6210\u529f\uff01 +operation.failure=\u64cd\u4f5c\u5931\u8d25\uff01 +isRegistered=\u6ce8\u518c\u7f13\u5b58 +isCached=\u670d\u52a1\u7f13\u5b58 +isCached.true=\u670d\u52a1\u5728\u7f13\u5b58\u4e2d +isCached.false=\u670d\u52a1\u672a\u540c\u6b65\u5230\u7f13\u5b58 +isSubscribed=\u8ba2\u9605\u7f13\u5b58 +isSubscribed.true=\u6b64\u6d88\u8d39\u8005\u5728\u5f53\u524d\u6ce8\u518c\u4e2d\u5fc3\u8ba2\u9605 +isSubscribed.false=\u6b64\u6d88\u8d39\u8005\u5728\u5176\u4ed6\u6ce8\u518c\u4e2d\u5fc3\u8ba2\u9605 +isSubscribed.unmatch=\u6b64\u6d88\u8d39\u8005\u5728\u6570\u636e\u5e93\u548c\u7f13\u5b58\u4e2d\u7684\u6ce8\u518c\u4e2d\u5fc3\u5730\u5740\u4e0d\u4e00\u81f4 +#operations +search=\u641c\u7d22 +search=\u641c\u7d22 +query=\u67e5\u8be2 +show=\u67e5\u770b +add=\u65b0\u589e +addMock=\u65b0\u589eMock +multiadd=\u6279\u91cf\u65b0\u589e +edit=\u7f16\u8f91 +save=\u4fdd\u5b58 +delete=\u5220\u9664 +enable=\u542f\u7528 +disable=\u7981\u7528 +recover=\u6062\u590d +reload=\u91cd\u8f7d\u7f13\u5b58 +reconnect=\u91cd\u8fde +renotify=\u91cd\u65b0\u901a\u77e5 +tostatic=\u8f6c\u4e3a\u9759\u6001 +todynamic=\u8f6c\u4e3a\u52a8\u6001 +favorite=\u6536\u85cf +register=\u7533\u8bf7\u6ce8\u518c +subscribe=\u7533\u8bf7\u8c03\u7528 +logout=\u9000\u51fa +back=\u8fd4\u56de +cancel=\u53d6\u6d88 +confirm=\u786e\u5b9a +batch.add=\u6279\u91cf\u65b0\u589e +batch.multiservices.add=\u591a\u670d\u52a1\u65b0\u589e +batch.delete=\u6279\u91cf\u5220\u9664 +batch.enable=\u6279\u91cf\u542f\u7528 +batch.disable=\u6279\u91cf\u7981\u7528 +batch.recover=\u6279\u91cf\u6062\u590d +batch.reconnect=\u6279\u91cf\u91cd\u8fde +batch.renotify=\u6279\u91cf\u91cd\u65b0\u901a\u77e5 +batch.tostatic=\u6279\u91cf\u9759\u6001 +batch.todynamic=\u6279\u91cf\u52a8\u6001 +batch.favorite=\u6279\u91cf\u6536\u85cf +batch.reload=\u6279\u91cf\u91cd\u8f7d +confirm.batch.disable=\u786e\u8ba4\u6279\u91cf\u7981\u7528 +confirm.batch.enable=\u786e\u8ba4\u6279\u91cf\u542f\u7528 +#prompts +please.input.service=\u8bf7\u8f93\u5165\u670d\u52a1\u540d +please.input.application=\u8bf7\u8f93\u5165\u5e94\u7528\u540d +please.input.address=\u8bf7\u8f93\u5165\u673a\u5668IP +please.input.layer=\u8bf7\u8f93\u5165\u670d\u52a1\u5206\u5c42 +please.input=\u8bf7\u8f93\u5165\u8981\u64cd\u4f5c\u7684\u5185\u5bb9 +please.select=\u8bf7\u9009\u62e9\u8981\u64cd\u4f5c\u7684\u9879 +empty.list=\u6ca1\u6709\u6570\u636e\u53ef\u4ee5\u64cd\u4f5c +not.found=\u6ca1\u6709\u641c\u5230\u5339\u914d\u7684\u7ed3\u679c +show.all=\u663e\u793a\u5168\u90e8 +confirm.logout=\u786e\u5b9a\u9000\u51fa\u767b\u5f55? +confirm.delete=\u786e\u5b9a\u5220\u9664?
\u5220\u9664\u540E\u5C06\u4E0D\u53EF\u8FD8\u539F\u3002 +confirm.enable=\u786e\u5b9a\u542f\u7528? +confirm.disable=\u786e\u5b9a\u7981\u7528? +confirm.recover=\u786e\u5b9a\u6062\u590d? +confirm.reconnect=\u786e\u5b9a\u91cd\u8fde? +confirm.renotify=\u786e\u5b9a\u901a\u77e5? +confirm.tostatic=\u786e\u5b9a\u8f6c\u4e3a\u9759\u6001? +confirm.todynamic=\u786e\u5b9a\u8f6c\u4e3a\u52a8\u6001? +confirm.batch.delete=\u786e\u5b9a\u5220\u9664\u6240\u9009\u9879?
\u5220\u9664\u540E\u5C06\u4E0D\u53EF\u8FD8\u539F\u3002 +confirm.batch.enable=\u786e\u5b9a\u542f\u7528\u6240\u9009\u9879? +confirm.batch.disable=\u786e\u5b9a\u7981\u7528\u6240\u9009\u9879? +confirm.batch.recover=\u786e\u5b9a\u6062\u590d\u6240\u9009\u9879? +confirm.batch.reload=\u786e\u5b9a\u91cd\u8f7d\u5f53\u524d\u670d\u52a1? +confirm.batch.reconnect=\u786e\u5b9a\u91cd\u8fde\u6240\u9009\u9879? +confirm.batch.renotify=\u786e\u5b9a\u91cd\u65b0\u901a\u77e5\u6240\u9009\u9879? +confirm.batch.tostatic=\u786e\u5b9a\u8f6c\u4e3a\u9759\u6001\u6240\u9009\u9879? +confirm.batch.todynamic=\u786e\u5b9a\u8f6c\u4e3a\u52a8\u6001\u6240\u9009\u9879? +current.user=\u5f53\u524d\u7528\u6237 +CheckProviderLocalAddress={0}\u4E0D\u662F\u6709\u6548\u7684\u8FDC\u7A0B\u670D\u52A1\u5730\u5740\uFF0C\u8BF7\u68C0\u67E5\u63D0\u4F9B\u65B9/etc/hosts\u6620\u5C04\u662F\u5426\u6B63\u786E\u3002 +CheckProviderApplicationDifferent=\u591a\u4e2a\u4e0d\u540c\u5e94\u7528\u6ce8\u518c\u4e86\u76f8\u540c\u670d\u52a1\uff0c\u8bf7\u68c0\u67e5{0}\u4e2d\u662f\u5426\u6709\u8bef\u66b4\u9732\u3002 +CheckProviderAddressMismatch=\u670d\u52a1URL\u4e0a\u7684IP\u4e0e\u8fde\u63a5\u6ce8\u518c\u4e2d\u5fc3\u7684IP\u4e0d\u76f8\u540c +CheckConnectionDisconnected=\u8be5\u8fde\u63a5\u5df2\u65ad\u5f00\uff0c\u6570\u636e\u5e93\u810f\u6570\u636e\uff0c\u8bf7\u70b9\u51fb\u201c\u91cd\u8fde\u201d +CheckConnectionExpired=\u8be5\u8fde\u63a5\u6240\u5728\u6ce8\u518c\u4e2d\u5fc3\u5df2\u4e0d\u5b58\u5728\uff08\u6570\u636e\u4f1a\u81ea\u52a8\u5b9a\u671f\u6e05\u7406\uff09 +CheckDatabaseMiss=\u6570\u636e\u5e93\u6570\u636e\u610f\u5916\u4e22\u5931\u6b64\u6570\u636e\uff0c\u8bf7\u70b9\u51fb\u201c\u6062\u590d\u201d +CheckDatabaseMismatch=\u6570\u636e\u5e93\u4e0e\u6ce8\u518c\u7f13\u5b58\u6570\u636e\u6ce8\u518c\u5730\u5740\u4e0d\u4e00\u81f4 +CheckDatabaseDirty2Registered=\u6570\u636e\u5e93\u6bd4\u6ce8\u518c\u7f13\u5b58\u591a\u6b64\u810f\u6570\u636e\uff0c\u8bf7\u70b9\u51fb\u201c\u91cd\u8fde\u201d +CheckDatabaseDirty2Subscribed=\u6570\u636e\u5e93\u6bd4\u8ba2\u9605\u7f13\u5b58\u591a\u6b64\u810f\u6570\u636e\uff0c\u8bf7\u70b9\u51fb\u201c\u91cd\u8fde\u201d +CheckCacheRegistered=\u6ce8\u518c\u7f13\u5b58\u4e0d\u5b58\u5728\uff0c\u8bf7\u70b9\u51fb\u201c\u91cd\u8fde\u201d +CheckCacheConsumer=\u65e0\u6b64\u670d\u52a1\u7684\u670d\u52a1\u7f13\u5b58\uff0c\u4f46\u6709\u6d88\u8d39\u8005\uff01\u8bf7\u70b9\u51fb\u201c\u91cd\u8f7d\u201d +CheckCacheProvider=\u670d\u52a1\u7f13\u5b58\u65e0\u6b64\u63d0\u4f9b\u8005\uff0c\u8bf7\u70b9\u51fb\u201c\u91cd\u8f7d\u201d +CheckCacheSubscribed=\u8ba2\u9605\u7f13\u5b58\u4e0d\u5b58\u5728\uff0c\u8bf7\u70b9\u51fb\u201c\u91cd\u8fde\u201d +CheckCacheService=\u65e0\u6b64\u670d\u52a1\u7684\u670d\u52a1\u7f13\u5b58\uff0c\u8bf7\u70b9\u51fb\u63d0\u4f9b\u8005\u7684\u201c\u91cd\u8f7d\u201d +select.all=\u5168\u9009 +ip.address=IP\u5730\u5740 +registry.newservice=\u6ce8\u518c\u65b0\u670d\u52a1 +add.new.provider=\u6dfb\u52a0\u63d0\u4f9b\u8005 +add.new.route=\u6dfb\u52a0\u8def\u7531 +message.search.noresult=\u6ca1\u6709\u7b26\u5408\u7684\u67e5\u8be2\uff0c\u8bf7\u4ece\u63d0\u793a\u5217\u8868\u4e2d\u9009\u62e9\u67e5\u8be2\u6761\u4ef6\uff01 +provide.service=\u63d0\u4f9b\u7684\u670d\u52a1 +service.method=\u670d\u52a1\u65b9\u6cd5 +service.filter=\u670d\u52a1filter +default.service.filter=\u9ed8\u8ba4\u670d\u52a1filter +startegy=\u7b56\u7565 +route.name=\u8def\u7531\u540d\u79f0 +rule.match=\u5339\u914d\u89c4\u5219 +rule.filtrate=\u8fc7\u6ee4\u89c4\u5219 +priority=\u4f18\u5148\u7ea7 +routed=\u5df2\u8def\u7531 +unrouted=\u672A\u8DEF\u7531 +page.total=\u5171 +page.records=\u6761\u8bb0\u5f55 +page.ordinal=\u7b2c +page.page=\u9875 +default.lazy=\u9ed8\u8ba4\u61d2\u542f\u52a8 +page.next=\u4e0b\u4e00\u9875 +page.prev=\u4e0a\u4e00\u9875 +page.first=\u9996\u9875 +page.last=\u5c3e\u9875 +page.line=\u6761 +methodName=\u65b9\u6cd5\u540d +proview=\u9884\u89c8 +cluster.name=\u96c6\u7fa4\u540d +cluster.address=\u96c6\u7fa4\u673a\u5668\u5730\u5740 +sameserviceadd=\u540c\u670d\u52a1\u6dfb\u52a0 +whitelist=\u5141\u8BB8 +blacklist=\u7981\u6B62 +toWhiteAndBlackList=\u8f6c\u5165\u767d\u540d\u5355/\u8f6c\u5165\u9ed1\u540d\u5355 +obtainProviderAddress=\u83b7\u53d6\u63d0\u4f9b\u8005\u5730\u5740 +towhitelist=\u52a0\u5165\u767d\u540d\u5355 +toblacklist=\u52a0\u5165\u9ed1\u540d\u5355 +enable=\u542f\u7528 +disable=\u7981\u7528 +copy=\u590d\u5236 +batch.enable=\u6279\u91cf\u542f\u7528 +batch.disable=\u6279\u91cf\u7981\u7528 +batch.towhitelist=\u52a0\u5165\u767d\u540d\u5355 +batch.toblacklist=\u52a0\u5165\u9ed1\u540d\u5355 +confirm.favorites=\u786e\u8ba4\u6536\u85cf\u5417 +confirm.batch.towhitelist=\u786e\u8ba4\u52a0\u5165\u767d\u540d\u5355?
\u5c06\u7981\u6b62\u4e0d\u5728\u767d\u540d\u5355\u5185\u7684\u6240\u6709\u6d88\u8d39\u8005\u8bbf\u95ee\uff0c\u9ed1\u540d\u5355\u5931\u6548\u3002 +confirm.batch.toblacklist=\u786e\u8ba4\u52a0\u5165\u9ed1\u540d\u5355?
\u5982\u679c\u6ca1\u6709\u767d\u540d\u5355\uff0c\u5c06\u7981\u6b62\u5728\u9ed1\u540d\u5355\u5185\u7684\u6240\u6709\u5176\u5b83\u6d88\u8d39\u8005\u8bbf\u95ee\u3002 +confirm.enable=\u786e\u8ba4\u542f\u7528 +confirm.disable=\u786e\u8ba4\u7981\u7528 +confirm.edit=\u786e\u8ba4\u7f16\u8f91 +confirm.disableFeature=\u786e\u8ba4\u7981\u7528\u529f\u80fd +confirm.enableFeature=\u786e\u8ba4\u542f\u7528\u529f\u80fd +confirmDeleteOwner=\u786e\u8ba4\u5220\u9664\u8d1f\u8d23\u4eba +welcome=\u60a8\u597d +approve=\u5f85\u5ba1\u6279 +chinese.simple=\u7b80\u4f53\u4e2d\u6587 +chinese.tradition=\u7e41\u9ad4\u4e2d\u6587 +register.service=\u6ce8\u518c\u65b0\u670d\u52a1 +erratum.guide=\u6392\u9519\u5411\u5bfc +preview.guide=\u9884\u89c8\u5411\u5bfc +sysinfo.status=\u6ce8\u518c\u4e2d\u5fc3\u72b6\u6001 +sysinfo.registries=\u6ce8\u518c\u4e2d\u5fc3\u96c6\u7fa4 +sysinfo.connections=\u5957\u63a5\u5b57\u8fde\u63a5 +sysinfo.cached=\u5185\u5b58\u7f13\u5b58 +sysinfo.failed=\u5931\u8d25\u8bb0\u5f55 +sysinfo.operations=\u64cd\u4f5c\u8bb0\u5f55 +sysinfo.logs=\u7cfb\u7edf\u65e5\u5fd7 +sysinfo.versions=Dubbo\u7248\u672c +sysinfo.dumps=\u7cfb\u7edf\u5feb\u7167 +sysinfo.envs=\u7cfb\u7edf\u73af\u5883 +sysinfo.helps=\u5e2e\u52a9\u6587\u6863 +system.management=\u7cfb\u7edf\u7ba1\u7406 +sysmanage.users=\u7528\u6237\u7ba1\u7406 +sysmanage.configs=\u7cfb\u7edf\u53c2\u6570\u8bbe\u7f6e +sysmanage.features=\u7cfb\u7edf\u529f\u80fd\u5f00\u5173 +system.function.control=\u7cfb\u7edf\u529f\u80fd\u5f00\u5173 +personal.set=\u4e2a\u4eba\u8bbe\u7f6e +modify.personalinfo=\u4fee\u6539\u4e2a\u4eba\u4fe1\u606f +modify.personal.password=\u4fee\u6539\u4e2a\u4eba\u5bc6\u7801 +operation.operateaddress=\u64cd\u4f5c\u8005\u5730\u5740 +operation.operatetype=\u64cd\u4f5c\u7c7b\u578b +operation.datatype=\u6570\u636e\u7c7b\u578b +operation.data=\u64cd\u4f5c\u5185\u5bb9 +operation.createtime=\u64cd\u4f5c\u65f6\u95f4 +operation.clean=\u6e05\u7406 +passwd.oldwrong=\u65e7\u5bc6\u7801\u9519\u8bef +failed=\u5931\u8d25\u8bb0\u5f55 +failed_type=\u7c7b\u578b +failed_data=\u6570\u636e +failed_sync=\u540c\u6b65\u5730\u5740\u5931\u8d25\u8bb0\u5f55 +failed_subscribe=\u8ba2\u9605\u5931\u8d25\u8bb0\u5f55 +failed_notify=\u901a\u77e5\u5931\u8d25\u8bb0\u5f55 +failed_collect=\u7edf\u8ba1\u5931\u8d25\u8bb0\u5f55 +failed_register=\u6ce8\u518c\u5931\u8d25\u8bb0\u5f55 +failed_redirect=\u91cd\u5b9a\u5411\u5931\u8d25\u8bb0\u5f55 +failed_disconnect=\u65ad\u5f00\u6e05\u7406\u5931\u8d25\u8bb0\u5f55 +clientAddress=\u5ba2\u6237\u7aef\u5730\u5740 +overrideAddress=\u8986\u76d6\u5730\u5740 +serviceInfo=\u670d\u52a1\u4fe1\u606f +consumerAddress=\u6d88\u8d39\u8005\u5730\u5740 +providerAddress=\u63d0\u4f9b\u8005\u5730\u5740 +registryAddress=\u6ce8\u518c\u4e2d\u5fc3\u5730\u5740 +serviceName=\u670d\u52a1\u540d +serviceUrl=\u670d\u52a1\u5730\u5740 +overrideConsumerAddress=\u53ea\u63a8\u9001\u7ed9\u6307\u5b9a\u6d88\u8d39\u8005\u5730\u5740 +overrideProviderAddress=\u53ea\u5728\u8c03\u7528\u6307\u5b9a\u63d0\u4f9b\u8005\u5730\u5740\u65f6\u751f\u6548 +tipConsumerAddress=\u4e0d\u586b\u8868\u793a\u5bf9\u6d88\u8d39\u8005\u5e94\u7528\u7684\u6240\u6709\u673a\u5668\u751f\u6548 +tipProviderAddress=\u4e0d\u586b\u8868\u793a\u5bf9\u670d\u52a1\u7684\u6240\u6709\u63d0\u4f9b\u8005\u673a\u5668\u751f\u6548 +tipProviderAddress=\u4e0d\u586b\u8868\u793a\u5bf9\u670d\u52a1\u7684\u6240\u6709\u63d0\u4f9b\u8005\u673a\u5668\u751f\u6548 +logs=\u7cfb\u7edf\u65e5\u5fd7 +logs.file=\u65e5\u5fd7\u6587\u4ef6 +logs.size=\u6587\u4ef6\u5927\u5c0f +logs.modify=\u4fee\u6539\u65f6\u95f4 +logs.level=\u65e5\u5fd7\u7ea7\u522b +change.log.level=\u4fee\u6539\u65e5\u5fd7\u7ea7\u522b +logs.confirmChangeLogLevel=\u786e\u8ba4\u4fee\u6539\u65e5\u5fd7\u7ea7\u522b +cached=\u5185\u5b58\u7f13\u5b58 +cached.type=\u7c7b\u578b +cached.data=\u6570\u636e +cached.reload=\u91cd\u65b0\u52a0\u8f7d +batch.cached.reload=\u6279\u91cf\u91cd\u65b0\u52a0\u8f7d +cached.recover=\u6062\u590d +batch.cached.recover=\u6279\u91cf\u6062\u590d +servicePrivilege=\u670d\u52a1\u6743\u9650 +creator=\u521b\u5efa\u8005 +name=\u540d\u79f0 +department=\u90e8\u95e8 +email=\u90ae\u7bb1 +phone=\u7535\u8bdd +alitalk=\u963f\u91cc\u65fa\u65fa +password=\u5bc6\u7801 +roleR=\u8d85\u7ea7\u7ba1\u7406\u5458 +roleA=\u7ba1\u7406\u5458 +roleG=\u6e38\u5ba2 +roleDescR=\u7ba1\u7406\u6240\u6709 +roleDescA=\u7ba1\u7406\u81ea\u5df1\u521b\u5efa\u7684\u7528\u6237\u548c\u670d\u52a1 +roleDescG=\u53ea\u67e5\u770b +oldPassword=\u65e7\u5bc6\u7801 +newPassword=\u65b0\u5bc6\u7801 +reset=\u91cd\u7f6e +restPassword=\u91cd\u7f6e\u5bc6\u7801 +confirmNewPassword=\u786e\u8ba4\u65b0\u5bc6\u7801 +owns=\u8d1f\u8d23\u7684\u670d\u52a1 +confirmPassword=\u786e\u8ba4\u5bc6\u7801 +generatePassword=\u751f\u6210\u5bc6\u7801 +displayName=\u59d3\u540d +locale=\u4f7f\u7528\u8bed\u8a00 +privilegeTip=\u591a\u4e2a\u503c\u7528\u9017\u53f7(,)\u5206\u9694\uff0c\u901a\u914d\u7b26\u7528\u661f\u53f7(*)\u8868\u793a\uff0c\u53ea\u80fd\u5728\u6bcf\u4e2a\u503c\u7684\u672a\u5c3e\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u88ab\u6388\u4e0e\u7684\u6743\u9650\u4e0d\u80fd\u8d85\u51fa\u5f53\u524d\u7ba1\u7406\u4eba\u5458\u7684\u6743\u9650 +displayNameTip=\u7528\u6237\u59d3\u540d\uff0c\u53ef\u4f7f\u7528\u4e2d\u6587\uff0c\u75311-50\u4e2a\u5b57\u7b26\u7ec4\u6210 +emailTip=\u7528\u4e8e\u63a5\u6536\u7cfb\u7edf\u90ae\u4ef6\uff0c\u53ef\u4ee5\u8f93\u5165\u591a\u4e2a\u90ae\u4ef6\u5730\u5740\uff0c\u4f7f\u7528\u82f1\u6587\u5206\u53f7\u5206\u9694(;)\uff0c \u5f62\u5982 foo1@163.comj;foo2@gmail.com +userLocaleTip=\u53d1\u9001\u7cfb\u7edf\u90ae\u4ef6\u65f6\uff0c\u5c06\u6839\u636e\u7528\u6237\u4f7f\u7528\u7684\u8bed\u8a00\u53d1\u9001\u4e0d\u540c\u8bed\u8a00\u7684\u90ae\u4ef6\u5185\u5bb9 +DisplayNameTip +EmailTip +UserLocaleTip +missRequestParameters=\u4e22\u5931\u8bf7\u6c42\u53c2\u6570 +haveNoRootPrivilege=\u6ca1\u6709root\u6743\u9650 +confirmReloadCache=\u786e\u8ba4\u91cd\u65b0\u52a0\u8f7d\u7f13\u5b58 +confirmDeleteRegistry=\u786e\u8ba4\u5220\u9664\u6ce8\u518c\u4e2d\u5fc3 +confirmAutoRedirectRegistry=\u786e\u8ba4\u91cd\u5b9a\u5411\u6ce8\u518c\u4e2d\u5fc3 +confirmDeleteExpiredRegistry=\u786e\u8ba4\u5220\u9664\u8fc7\u671f\u6ce8\u518c\u4e2d\u5fc3 +confirmSyncRegistry=\u786e\u8ba4\u540c\u6b65\u6ce8\u518c\u4e2d\u5fc3\u5730\u5740\u5217\u8868\u5230\u5ba2\u6237\u7aef +confirm.toblacklist=\u786e\u8ba4\u52a0\u5165\u9ed1\u540d\u5355?
\u5982\u679c\u6ca1\u6709\u767d\u540d\u5355\uff0c\u5c06\u7981\u6b62\u5728\u9ed1\u540d\u5355\u5185\u7684\u6240\u6709\u6d88\u8d39\u8005\u8bbf\u95ee\u3002 +confirm.towhitelist=\u786e\u8ba4\u52a0\u5165\u767d\u540d\u5355?
\u5c06\u7981\u6b62\u4e0d\u5728\u767d\u540d\u5355\u5185\u7684\u6240\u6709\u5176\u5b83\u6d88\u8d39\u8005\u8bbf\u95ee\uff0c\u9ed1\u540d\u5355\u5931\u6548\u3002 +confirm.clean.operation=\u786e\u8ba4\u6e05\u9664\u64cd\u4f5c\u8bb0\u5f55 +autoRedirect=\u81ea\u52a8\u91cd\u5b9a\u5411 +deleteExpired=\u5220\u9664\u6240\u6709\u5df2\u8fc7\u671f +sync=\u540c\u6b65 +legacies=1.0\u9057\u7559\u5ba2\u6237\u7aef +logined=\u5df2\u767b\u5f55\u5ba2\u6237\u7aef +dumps=\u7cfb\u7edf\u5feb\u7167 +Registry=\u6ce8\u518c\u4e2d\u5fc3\u7248\u672c +Java=JDK\u7248\u672c +Locale=\u8bed\u8a00 +OS=\u64cd\u4f5c\u7cfb\u7edf +Uptime=\u8fd0\u884c\u65f6\u95f4 +Host=\u57df\u540d +CPU=\u0043\u0050\u0055 +confirmEnableUser=\u786e\u8ba4\u542f\u52a8\u7528\u6237 +confirmDisableUser=\u786e\u8ba4\u7981\u7528\u7528\u6237 +documentTitle=\u6587\u6863\u6807\u9898 +documentLink/documentPage=\u94fe\u63a5\u5730\u5740/\u9875\u9762\u5185\u5bb9 +documentInternal=\u9875\u9762 +documentExternal=\u94fe\u63a5 +documentApi=API +documentType=\u6587\u6863\u7c7b\u578b +documentContent=\u6587\u6863\u5185\u5bb9 +Yes=\u662f +No=\u5426 +returnValue=\u8fd4\u56de\u503c +throwException=\u629b\u51fa\u5f02\u5e38 +#BatchAddressTip=\u591a\u4e2a\u5730\u5740\u7528\u6362\u884c\u7b26\u5206\u9694\uff0c\u5730\u5740\u5fc5\u9700\u662f0.0.0.0\u5230255.255.255.255\u7684IP\u5730\u5740 +#AccessControlTip=\u767d\u540d\u5355\u4f18\u5148\uff0c\u53ea\u8981\u6709\u767d\u540d\u5355\uff0c\u5219\u767d\u540d\u5355\u751f\u6548\uff0c\u5426\u5219\u9ed1\u540d\u5355\u751f\u6548 +#RouteNameTip=\u53ef\u4f7f\u7528\u4e2d\u6587\uff0c\u75311-200\u4e2a\u5b57\u7b26\u7ec4\u6210 +#RoutePriorityTip=\u6570\u5b57\u8d8a\u5927\u8d8a\u4f18\u5148 +#RouteMethodTip=\u53ea\u6709Dubbo2.0.0\u4ee5\u4e0a\u7248\u672c\u7684\u670d\u52a1\u6d88\u8d39\u7aef\u652f\u6301\u6309\u65b9\u6cd5\u8def\u7531\uff0c\u591a\u4e2a\u65b9\u6cd5\u540d\u7528\u9017\u53f7\u5206\u9694 +#Choose=\u8bf7\u9009\u62e9 +#RouteMatchTip=\u5f53\u6d88\u8d39\u8005\u6ee1\u8db3\u5339\u914d\u6761\u4ef6\u65f6\u4f7f\u7528\u5f53\u524d\u89c4\u5219\u8fdb\u884c\u8fc7\u6ee4 +#RouteHostTip=\u591a\u4e2a\u503c\u7528\u9017\u53f7\u5206\u9694\uff0c\u4ee5\u661f\u53f7\u7ed3\u5c3e\u8868\u793a\u901a\u914d\u5730\u5740\u6bb5 +#RouteClusterTip=\u53ef\u901a\u8fc7\u83dc\u5355"\u670d\u52a1\u63a7\u5236"->"\u670d\u52a1\u5668\u96c6\u7fa4"\u7ba1\u7406 +#RouteFilterTip=\u6ee1\u8db3\u8fc7\u6ee4\u89c4\u5219\u7684\u63d0\u4f9b\u8005\u5730\u5740\u5c06\u88ab\u63a8\u9001\u7ed9\u6d88\u8d39\u8005 +testMethodTip=\u5982\u679c\u6709\u65b9\u6cd5\u91cd\u8f7d\u6216\u4f7f\u7528Dubbo1.0.x\u7248\u672c\u7684\u670d\u52a1\u63d0\u4f9b\u8005\uff0c\u9700\u5199\u5168\u65b9\u6cd5\u7b7e\u540d\uff0c\u5982\uff1afindBy(int,java.lang.String)\uff0c\u5426\u5219\u53ea\u9700\u65b9\u6cd5\u540d\uff0c\u5982\uff1afindBy +testJsonTip=JSON\u683c\u5f0f\uff1a\u5b57\u7b26\u4e32\u7528\u53cc\u5f15\u53f7\u8868\u793a\uff0c\u5982\uff1a"\u5b57\u7b26\u4e32"\uff0c\u6570\u5b57\u548cBoolean\u503c\u4e0d\u7528\u5f15\u53f7\uff0c\u5982\uff1a123 \u548c true \u6216 false\uff0cPOJO\u5bf9\u8c61\u6216Map\u7528\u5927\u62ec\u53f7\u8868\u793a\uff0c\u5982\uff1a{"\u5c5e\u6027\u540d1": "\u5c5e\u6027\u503c1", "\u5c5e\u6027\u540d2": "\u5c5e\u6027\u503c2"}\uff0c\u6570\u7ec4\u6216List\u6216Set\u7528\u65b9\u62ec\u53f7\u8868\u793a\uff0c\u5982\uff1a["\u503c1", "\u503c2"] +testParametersTip=\u5f53\u4e3a\u65e0\u53c2\u6570\u65b9\u6cd5\u65f6\u53c2\u6570\u503c\u53ef\u4ee5\u4e0d\u586b\uff0c\u53c2\u6570\u503c\u4f7f\u7528JSON\u683c\u5f0f\u8868\u793a +testResultTip=\u5f53\u4e3avoid\u65b9\u6cd5\u65f6\u7ed3\u679c\u53ef\u4ee5\u4e0d\u586b\uff0c\u629b\u51fa\u5f02\u5e38\u4f7f\u7528\u5f02\u5e38\u7c7b\u5168\u540d\u8868\u793a\uff0c\u8fd4\u56de\u503c\u4f7f\u7528JSON\u683c\u5f0f\u8868\u793a +testAutoRunTip=\u5982\u679c\u8bbe\u7f6e\u4e3a\u81ea\u52a8\u8fd0\u884c\uff0c\u82e5\u8be5\u670d\u52a1\u5df2\u6ce8\u518c\u6216\u65b0\u6ce8\u518c\uff0c\u5219\u81ea\u52a8\u8fd0\u884c\u6b64\u6d4b\u8bd5\u7528\u4f8b\uff0c\u8fd0\u884c\u5931\u8d25\uff0c\u5c06\u53d1\u9001\u90ae\u4ef6 +confirmRunTest=\u786e\u8ba4\u8fd0\u884c\u6d4b\u8bd5 +confirm.runAll=\u786e\u8ba4\u5bf9\u6240\u6709\u63d0\u4f9b\u8005\u8fd0\u884c\u6d4b\u8bd5 +# +#anonymous=\u533f\u540d +#Unuse=\u672a\u4f7f\u7528 +#RouteName=\u8def\u7531\u540d +#Priority=\u4f18\u5148\u7ea7 +#MatchRule=\u5339\u914d\u6761\u4ef6 +#ConsumerHost=\u6d88\u8d39\u8005IP\u5730\u5740 +#ConsumerCluster=\u6d88\u8d39\u8005\u96c6\u7fa4 +#FilterRule=\u8fc7\u6ee4\u89c4\u5219 +#ProviderHost=\u63d0\u4f9b\u8005IP\u5730\u5740 +#ProviderCluster=\u63d0\u4f9b\u8005\u96c6\u7fa4 +#ProviderProtocol=\u63d0\u4f9b\u8005\u534f\u8bae +#ProviderPort=\u63d0\u4f9b\u8005\u7aef\u53e3 +#Match=\u5339\u914d +#Mismatch=\u4e0d\u5339\u914d +#ConsumerAddress=\u6d88\u8d39\u8005\u5730\u5740 +generic=\u6cdb\u5316 +doubling=\u500d\u6743 +loadBalanceStrategy=\u8d1f\u8f7d\u5747\u8861\u7b56\u7565 +random=\u968f\u673a +roundrobin=\u8f6e\u8be2 +leastactive=\u6700\u5c11\u5e76\u53d1 +testName=\u6d4b\u8bd5\u7528\u4f8b\u540d\u79f0 +operator=\u64cd\u4f5c +dataFormat=\u6570\u636e\u683c\u5f0f +resultType=\u7ed3\u679c\u7c7b\u578b +resultController=\u8fd4\u56de\u503c/\u5f02\u5e38\u7c7b\u578b +autoRun=\u81ea\u52a8\u8fd0\u884c +manualRun=\u624b\u52a8\u8fd0\u884c +run=\u8fd0\u884c +runAll=\u8fd0\u884c\u6240\u6709\u63d0\u4f9b\u8005 +expected=\u671f\u671b\u7ed3\u679c +actual=\u5b9e\u9645\u7ed3\u679c +reRun=\u91cd\u65b0\u8fd0\u884c +#Username=\u7528\u6237\u540d +#DisplayName=\u663e\u793a\u540d +#Department=\u90e8\u95e8 +#Email=\u90ae\u7bb1 +#Phone=\u624b\u673a +#Alitalk=\u65fa\u65fa +startDate=\u542f\u52a8\u65f6\u95f4 +console=\u63a7\u5236\u53f0 +total=\u603b\u6570 +delta=\u504f\u5dee +expired=\u8fc7\u671f +alived=\u5b58\u6d3b +redirect=\u91cd\u5b9a\u5411 +current=\u5f53\u524d +#overrides +override.config=\u52a8\u6001\u914d\u7f6e +override.mock=\u670d\u52a1\u964d\u7ea7 +parameter=\u53c2\u6570 +parameter.key=\u53c2\u6570\u540d +parameter.value=\u53c2\u6570\u503c +parameter.tip=\u65b9\u6cd5\u7ea7\u914d\u7f6e\u5982\uff1afindPerson.timeout=1000 +mock.all.method=\u6240\u6709\u65b9\u6cd5\u7684Mock\u503c +mock.method=\u65b9\u6cd5 +mock.value=\u7684Mock\u503c +mock.tip=\u793a\u4f8b\uff1areturn null/empty/JSON\u6216throw com.foo.BarException +protocol=\u534F\u8BAE +host=\u4E3B\u673A\u540D +port=\u7AEF\u53E3 +interface=\u63A5\u53E3\u540D +version=\u7248\u672C +group=\u5206\u7EC4 +methods=\u65B9\u6CD5\u5217\u8868 +category=\u6570\u636E\u7C7B\u578B +application=\u5E94\u7528\u540D +owner=\u8D1F\u8D23\u4EBA +cluster=\u96C6\u7FA4 +loadbalance=\u8D1F\u8F7D\u5747\u8861 +timeout=\u8D85\u65F6 +retries=\u91CD\u8BD5\u6B21\u6570 +threads=\u7EBF\u7A0B\u6570 +connections=\u8FDE\u63A5\u6570 +accepts=\u63A5\u6536\u8FDE\u63A5\u6570 +actives=\u5BA2\u6237\u7AEF\u5E76\u53D1\u8BF7\u6C42\u9650\u5236 +executes=\u7EBF\u7A0B\u6C60\u5E76\u53D1\u6267\u884C\u9650\u5236 +check=\u68C0\u67E5 +side=\u6240\u5C5E\u7AEF +pid=\u8FDB\u7A0B\u53F7 +timestamp=\u65F6\u95F4\u6233 +dubbo=Dubbo\u7248\u672C +anyhost=\u7ED1\u5B9A\u6240\u6709IP +weight=\u6743\u91CD +weight.doubling=\u500D\u6743 +weight.halving=\u534A\u6743 +confirm.weight.doubling=\u786E\u8BA4\u6743\u91CD\u52A0\u500D? +confirm.weight.halving=\u786E\u8BA4\u6743\u91CD\u51CF\u534A? +batch.weight.doubling=\u6279\u91CF\u500D\u6743 +batch.weight.halving=\u6279\u91CF\u534A\u6743 +confirm.batch.weight.doubling=\u786E\u8BA4\u6240\u9009\u9879\u6743\u91CD\u52A0\u500D? +confirm.batch.weight.halving=\u786E\u8BA4\u6240\u9009\u9879\u6743\u91CD\u51CF\u534A? +NoSuchOperationData=\u64CD\u4F5C\u7684\u6570\u636E\u4E0D\u5B58\u5728\u3002 +CanNotDeleteDynamicData=\u4E0D\u80FD\u5220\u9664\u52A8\u6001\u6570\u636E\u3002 +HaveNoServicePrivilege=\u60A8\u6CA1\u6709\u8BE5\u670D\u52A1\u7684\u6743\u9650\u3002 +dynamic.parameters.tip=\u52A8\u6001URL\u4E0D\u80FD\u76F4\u63A5\u4FEE\u6539\uFF0C\u9700\u901A\u8FC7\u52A8\u6001\u914D\u7F6E\u8FDB\u884C\u8986\u76D6\uFF0C\u683C\u5F0F\u4E0EURL\u53C2\u6570\u76F8\u540C\u3002 +default.owner=\u8d1f\u8d23\u4eba +logger=\u65e5\u5fd7 +default.server=\u9ed8\u8ba4\u670d\u52a1\u7aef +default.actives=\u5e76\u53d1\u8c03\u7528\u6570 +default.client=\u9ed8\u8ba4\u5ba2\u6237\u7aef +default.connections=\u6700\u5927\u8fde\u63a5\u6570 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_zh_CN.properties b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_zh_CN.properties new file mode 100644 index 0000000..83e8753 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_zh_CN.properties @@ -0,0 +1,802 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +#menus +home=\u9996\u9875 +stat=\u7edf\u8ba1 +revision=\u4fee\u8ba2\u7248\u672c +connectionNum=\u8fde\u63a5\u6570 +serviceNum=\u670d\u52a1\u6570 +providerNum=\u63d0\u4f9b\u8005\u6570 +consumerNum=\u6d88\u8d39\u8005\u6570 +applicationNum=\u5e94\u7528\u6570 +about=\u5173\u4e8e +help=\u5e2e\u52a9 +favorites=\u6536\u85cf\u5939 +histories=\u5386\u53f2\u8bb0\u5f55 +governance=\u670d\u52a1\u6cbb\u7406 +applications=\u5e94\u7528 +efferents=\u4f9d\u8d56 +afferents=\u88ab\u4f9d\u8d56 +services=\u670d\u52a1 +references=\u5f15\u7528\u670d\u52a1 +addresses=\u673a\u5668 +providers=\u63d0\u4f9b\u8005 +dependencies=\u4f9d\u8d56\u5173\u7cfb +layers=\u5206\u5c42 +clusters=\u96c6\u7fa4 +consumers=\u6d88\u8d39\u8005 +accesses=\u8BBF\u95EE\u63A7\u5236 +routes=\u8def\u7531\u89C4\u5219 +weights=\u6743\u91cd\u8C03\u8282 +loadbalances=\u8d1f\u8f7d\u5747\u8861 +tests=\u6d4b\u8bd5 +mocks=\u6a21\u62df +overrides=\u52a8\u6001\u914d\u7f6e +documents=\u6587\u6863 +owners=\u8d1f\u8d23\u4eba +agreements=\u534f\u5b9a +approvals=\u4e0a\u7ebf\u5ba1\u6279 +operations=\u64cd\u4f5c\u65e5\u5fd7 +users=\u7528\u6237 +envs=\u7cfb\u7edf\u73af\u5883 +helps=\u5e2e\u52a9\u6587\u6863 +registries=\u6ce8\u518c\u4e2d\u5fc3 +configs=\u7cfb\u7edf\u53c2\u6570 +features=\u7cfb\u7edf\u529f\u80fd +connections=\u8fde\u63a5 +statuses=\u7CFB\u7EDF\u72B6\u6001 +failed=\u5931\u8d25\u8bb0\u5f55 +cached=\u7f13\u5b58\u8bb0\u5f55 +dumps=\u5feb\u7167 +InvalidIp=\u65e0\u6548\u0069\u0070\u5730\u5740 +versions=Dubbo\u7248\u672c +logs=\u65e5\u5fd7 +infos=\u4fee\u6539\u4e2a\u4eba\u4fe1\u606f +passwds=\u4fee\u6539\u4e2a\u4eba\u5bc6\u7801 +dependency.list=\u5217\u8868 +dependency.tree=\u6811\u72b6 +dependency.graph=\u56fe\u5f62 +dependency.efferent=\u4f9d\u8d56 +dependency.afferent=\u88ab\u4f9d\u8d56 +provided=\u63d0\u4f9b\u670d\u52a1 +consumed=\u6d88\u8d39\u670d\u52a1 +select=\u9009\u62e9 +clean=\u6e05\u9664 +information=\u4fe1\u606f +control=\u63a7\u5236 +summary=\u6c47\u603b +consumer.application=\u6d88\u8d39\u8005\u5e94\u7528 +response.time=\u54cd\u5e94\u65f6\u95f4 +sysinfo.infos=\u7cfb\u7edf\u4fe1\u606f +helps.document=\u6587\u6863 +helps.requirement=\u9700\u6c42 +helps.source=\u6e90\u4ee3\u7801 +connections=\u5957\u63a5\u5b57\u8fde\u63a5 +ReconnectUnkwown=\u91cd\u8fde\u6240\u6709\u672a\u77e5\u8fde\u63a5 +confirmReconnectConnection=\u786e\u8ba4\u91cd\u5efa\u8fde\u63a5 +confirmRedirectRegistry=\u786e\u8ba4\u91cd\u5b9a\u5411\u6ce8\u518c\u4e2d\u5fc3 +confirmReconnectUnknownConnection=\u786e\u8ba4\u91cd\u8fde\u672a\u77e5\u7684\u8fde\u63a5 +status.resourcename=\u8d44\u6e90\u540d\u79f0 +status.status=\u72b6\u6001 +status.message=\u4fe1\u606f +status.description=\u63cf\u8ff0 +status.memoryStatus=\u5185\u5b58 +status.memoryStatusDesc=\u53ea\u76d1\u63a7Heap\u5185\u5b58\uff0c\u5982\u679c\u7a7a\u95f2\u5185\u5b58\u4e0d\u8db31M\u5219\u8b66\u544a\uff0c\u5426\u5219\u6b63\u5e38 +status.threadpoolStatus=\u7ebf\u7a0b\u6c60 +status.threadpoolStatusDesc=\u53ea\u76d1\u63a7\u6ce8\u518c\u8ba2\u9605\u4e3b\u4e1a\u52a1\u7ebf\u7a0b\u6c60\uff0c\u5982\u679c\u7a7a\u95f2\u7ebf\u7a0b\u5c11\u4e8e1\u4e2a\uff0c\u5219\u8b66\u544a\uff0c\u5426\u5219\u6b63\u5e38 +status.failureStatus=\u5931\u8d25\u8bb0\u5f55 +status.failureStatusDesc=\u5f53\u6709\u4efb\u4f55\u5931\u8d25\u8bb0\u5f55\u5219\u8b66\u544a\uff0c\u5426\u5219\u6b63\u5e38 +status.cacheStatus=\u7f13\u5b58 +status.cacheStatusDesc=\u5982\u679c\u7f13\u5b58\u4e0e\u6570\u636e\u5e93\u4e0d\u4e00\u81f4\u5219\u8b66\u544a\uff0c\u5426\u5219\u6b63\u5e38 +status.timerStatus=\u5b9a\u65f6\u5668 +status.timerStatusDesc=\u5f53\u5b9a\u65f6\u5668\u672a\u6b63\u786e\u542f\u52a8\uff0c\u6216\u88ab\u4e0d\u6b63\u5e38\u53d6\u6d88\uff0c\u5219\u62a5\u9519\uff0c\u5426\u5219\u6b63\u5e38 +status.socketStatus=\u5957\u63a5\u5b57 +status.socketStatusDesc=\u5f53\u5957\u63a5\u53e3\u5f00\u542f\u4e0d\u4e86\u6216\u5df2\u88ab\u5360\u7528\u65f6\u62a5\u9519\uff0c\u5f53\u8fde\u63a5\u6570\u7b49\u4e8e\u6700\u5927\u503c\u65f6\u8b66\u544a\uff0c\u5426\u5219\u6b63\u5e38 +status.loadStatus=\u8d1f\u8f7d +status.loadStatusDesc=\u5982\u679c\u8d1f\u8f7d\u5927\u4e8eCPU\u4e2a\u6570\u5219\u8b66\u544a\uff0c\u5982\u679c\u7cfb\u7edf\u4e0d\u652f\u6301\u67e5\u8be2\u8d1f\u8f7d\u5219\u4e0d\u542f\u7528\uff0c\u5426\u5219\u6b63\u5e38 +status.datasourceStatus=\u6570\u636e\u5e93 +status.datasourceStatusDesc=\u53d1\u9001\u4e00\u6761\u7b80\u5355\u67e5\u8be2SQL\uff0c\u6267\u884c\u6210\u529f\u5219\u6b63\u5e38\uff0c\u5426\u5219\u62a5\u9519 +status.registryStatus=\u6CE8\u518C\u4E2D\u5FC3 +status.registryStatusDesc=\u5982\u679C\u8FDE\u4E0D\u4E0A\u6CE8\u518C\u4E2D\u5FC3\u5219\u62A5\u9519\uFF0C\u5426\u5219\u6B63\u5E38 +status.monitorStatus=\u76d1\u89c6\u5668 +status.monitorStatusDesc=\u76d1\u89c6\u5668 +status.summaryStatus=\u6c47\u603b +status.summaryStatusDesc=\u6709\u72b6\u6001\u6c47\u603b\uff0c\u5ffd\u7565\u672a\u542f\u7528\u7684\u72b6\u6001\uff0c\u53ea\u8981\u6709\u4e00\u4e2a\u62a5\u9519\uff0c\u5219\u62a5\u9519\uff0c\u53ea\u8981\u6709\u4e00\u4e2a\u8b66\u544a\uff0c\u5219\u8b66\u544a\uff0c\u5168\u90e8\u6b63\u5e38\u5219\u6b63\u5e38 +status.warmupStatus=\u8fd0\u884c\u72b6\u6001 +status.warmupStatusDesc=\u5904\u4e8ewarmup\u72b6\u6001\u65f6\uff0c\u810f\u6570\u636e\u68c0\u6d4b\u3001\u91cd\u5b9a\u5411\u3001\u4e8b\u4ef6\u53d8\u66f4\u5b9a\u65f6\u5668\u5747\u4e0d\u5de5\u4f5c,\u4e0d\u63a8\u9001\u53d8\u66f4 +status.OK=\u6b63\u5e38 +status.WARN=\u8b66\u544a +status.ERROR=\u9519\u8bef +status.UNKNOWN=\u672a\u77e5 +Status0=Unknow +Status1=OK +Status2=OK +Status3=ERROR +Status4=FATAL +Status5=UNKNOW +mock=\u964d\u7ea7 +force.mocked=\u5DF2\u5C4F\u853D +fail.mocked=\u5DF2\u5BB9\u9519 +no.mocked=\u672A\u964D\u7EA7 +force.mock=\u5c4f\u853d +fail.mock=\u5bb9\u9519 +cancel.mock=\u6062\u590d +confirm.force.mock=\u786e\u8ba4\u5c4f\u853d\u8be5\u670d\u52a1\u7684\u8c03\u7528\uff1f
\u5C4F\u853D\u540E\uFF0C\u5c06\u4e0d\u53d1\u8d77\u8fdc\u7a0b\u8c03\u7528\uff0c\u76f4\u63a5\u5728\u5BA2\u6237\u7AEF\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.fail.mock=\u786e\u8ba4\u5bf9\u8be5\u670d\u52a1\u5bb9\u9519\uff1f
\u5BB9\u9519\u540E\uFF0C\u5f53\u8FDC\u7A0B\u8c03\u7528\u5931\u8d25\u65f6\uff0c\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.cancel.mock=\u786e\u8ba4\u6062\u590d\u8be5\u670d\u52a1\u6b63\u5e38\u8bbf\u95ee\uff1f
\u5c06\u53d6\u6d88\u670d\u52a1\u7684\u5c4f\u853d\u548c\u5bb9\u9519\u884c\u4e3a\u3002 +batch.force.mock=\u6279\u91cf\u5c4f\u853d +batch.fail.mock=\u6279\u91cf\u5bb9\u9519 +batch.cancel.mock=\u6279\u91cf\u6062\u590d +confirm.batch.force.mock=\u786e\u8ba4\u6279\u91cf\u5c4f\u853d\u670d\u52a1\u7684\u8c03\u7528\uff1f
\u5C4F\u853D\u540E\uFF0C\u5c06\u4e0d\u53d1\u8d77\u8fdc\u7a0b\u8c03\u7528\uff0c\u76f4\u63a5\u5728\u5BA2\u6237\u7AEF\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.batch.fail.mock=\u786e\u8ba4\u6279\u91cf\u5bf9\u670d\u52a1\u5bb9\u9519\uff1f
\u5BB9\u9519\u540E\uFF0C\u5f53\u8FDC\u7A0B\u8c03\u7528\u5931\u8d25\u65f6\uff0c\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.batch.cancel.mock=\u786e\u8ba4\u6279\u91cf\u6062\u590d\u670d\u52a1\u6b63\u5e38\u8bbf\u95ee\uff1f
\u5c06\u53d6\u6d88\u670d\u52a1\u7684\u5c4f\u853d\u548c\u5bb9\u9519\u884c\u4e3a\u3002 +all.force.mock=\u7F3A\u7701\u5c4f\u853d +all.fail.mock=\u7F3A\u7701\u5bb9\u9519 +all.cancel.mock=\u7F3A\u7701\u6062\u590d +confirm.all.force.mock=\u786e\u8ba4\u7F3A\u7701\u5c4f\u853d\u8be5\u670d\u52a1\u7684\u8c03\u7528\uff1f
\u8BBE\u7F6E\u964D\u7EA7\u7F3A\u7701\u503C\uFF0C\u5C06\u5F71\u54CD\u672A\u964D\u7EA7\u4EE5\u53CA\u65B0\u7684\u6D88\u8D39\u8005\u3002
\u5C4F\u853D\u540E\uFF0C\u5c06\u4e0d\u53d1\u8d77\u8fdc\u7a0b\u8c03\u7528\uff0c\u76f4\u63a5\u5728\u5BA2\u6237\u7AEF\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.all.fail.mock=\u786e\u8ba4\u7F3A\u7701\u5bf9\u8be5\u670d\u52a1\u5bb9\u9519\uff1f
\u8BBE\u7F6E\u964D\u7EA7\u7F3A\u7701\u503C\uFF0C\u5C06\u5F71\u54CD\u672A\u964D\u7EA7\u4EE5\u53CA\u65B0\u7684\u6D88\u8D39\u8005\u3002
\u5BB9\u9519\u540E\uFF0C\u5f53\u8FDC\u7A0B\u8c03\u7528\u5931\u8d25\u65f6\uff0c\u8fd4\u56de\u7a7a\u5bf9\u8c61\u3002 +confirm.all.cancel.mock=\u786e\u8ba4\u7F3A\u7701\u6062\u590d\u8be5\u670d\u52a1\u6b63\u5e38\u8bbf\u95ee\uff1f
\u8BBE\u7F6E\u964D\u7EA7\u7F3A\u7701\u503C\uFF0C\u5C06\u5F71\u54CD\u672A\u964D\u7EA7\u4EE5\u53CA\u65B0\u7684\u6D88\u8D39\u8005\u3002
\u5c06\u53d6\u6d88\u670d\u52a1\u7684\u5c4f\u853d\u548c\u5bb9\u9519\u884c\u4e3a\u3002 +agreement.invocation.quantity=\u4e00\u5929\u8c03\u7528\u91cf +agreement.tps=TPS\u4e0a\u9650 +response.time=\u54cd\u5e94\u65f6\u95f4 +agreement.availability=\u53ef\u7528\u7387 +layer.name=\u5206\u5c42\u540d\u79f0 +layer.value=\u6570\u5b57\u7b49\u7ea7 +layer.arch=\u5206\u5c42\u67b6\u6784 +loadBalanceStrategy=\u8d1f\u8f7d\u5747\u8861\u7b56\u7565 +ServiceName=\u670d\u52a1\u540d +cluster.name=\u96c6\u7fa4\u540d +cluster.address=\u96c6\u7fa4\u673a\u5668\u5730\u5740 +property.name=\u5c5e\u6027\u540d +property.value=\u5c5e\u6027\u503c +property.count=\u5c5e\u6027\u6570\u91cf +getMethods=\u83b7\u53d6\u670d\u52a1\u65b9\u6cd5 +getAddresses=\u83b7\u53d6\u63d0\u4f9b\u8005\u5730\u5740 +Edit=\u7f16\u8f91 +Username=\u7528\u6237\u540d +Priority=\u4f18\u5148\u7ea7 +ConnectionAddress=\u8fde\u63a5\u5730\u5740 +Role=\u89d2\u8272 +Reconnect=\u91cd\u8fde +Redirect=\u91cd\u5b9a\u5411 +staff.query=\u5185\u7f51\u67e5\u8be2 +configKey=\u914d\u7f6e\u9879 +configValue=\u914d\u7f6e\u9879\u503c +Preview=\u9884\u89c8 +routeselect=\u8def\u7531\u9884\u89c8\uff08\u9009\u62e9\u6d88\u8d39\u8005\uff09 +AllOperations=\u6240\u6709\u64cd\u4f5c\u8bb0\u5f55 +BeforeOneMonthOperations=\u4e00\u4e2a\u6708\u4ee5\u524d\u7684\u6240\u6709\u64cd\u4f5c\u8bb0\u5f55 +BeforeThreeMonthOperations=\u4e09\u4e2a\u6708\u4ee5\u524d\u7684\u6240\u6709\u64cd\u4f5c\u8bb0\u5f55 +BeforeHalfYearOperations=\u534a\u5e74\u4ee5\u524d\u7684\u6240\u6709\u64cd\u4f5c\u8bb0\u5f55 +BeforeOneYearOperations=\u4e00\u5e74\u4ee5\u524d\u7684\u6240\u6709\u64cd\u4f5c\u8bb0\u5f55 +PleaseInput=\u8bf7\u8f93\u5165 +BulletinConfig=\u516c\u544a\u914d\u7f6e +BulletinMessage=\u516c\u544a\u4fe1\u606f +MailConfig=\u90ae\u7bb1\u914d\u7f6e +MailEnabled=\u662f\u5426\u542f\u7528\u90ae\u7bb1 +MailHost=\u90ae\u4ef6\u670d\u52a1\u5668\u4e3b\u673a +MailPort=\u90ae\u4ef6\u670d\u52a1\u5668\u7aef\u53e3 +MailFrom=\u90ae\u4ef6\u53d1\u4ef6\u4eba\u5730\u5740 +MailAuth=\u90ae\u7bb1\u662f\u5426\u9700\u8981\u767b\u5f55 +MailUsername=\u90ae\u7bb1\u767b\u5f55\u7528\u6237\u540d +MailPassword=\u90ae\u7bb1\u767b\u5f55\u5bc6\u7801 +LoginConfig=\u767b\u5f55\u914d\u7f6e +AllowAnonymousLogin=\u5141\u8bb8\u533f\u540d\u767b\u5f55 +AllowLegacyLogin=\u5141\u8bb8\u9057\u7559\u7cfb\u7edf\u767b\u5f55 +RouteEnabled=\u662f\u5426\u5f00\u542f\u8def\u7531\u529f\u80fd +WarmupEnabled=\u662f\u5426\u8fdb\u5165\u9884\u70ed\u72b6\u6001 +LogConfig=\u65e5\u5fd7\u914d\u7f6e +LogLevel=\u65e5\u5fd7\u7ea7\u522b +RedirectConfig=\u91cd\u5b9a\u5411\u914d\u7f6e +AutoRedirectInterval=\u81ea\u52a8\u91cd\u5b9a\u5411\u68c0\u67e5\u95f4\u9694(\u6beb\u79d2) +AutoRedirectThreshold=\u80fd\u591f\u81ea\u52a8\u91cd\u5b9a\u5411\u7684\u8fde\u63a5\u4e0b\u754c +AutoRedirectToleratePercent=\u81ea\u52a8\u91cd\u5b9a\u5411\u65f6\u8fde\u63a5\u6570\u504f\u5dee\u5bb9\u5fcd\u767e\u5206\u6bd4 +ManualRedirect=\u91cd\u5b9a\u5411{0}\u4e2a +LimitConfig=\u8d44\u6e90\u9650\u5236\u914d\u7f6e +MaxThreadSize=\u6700\u5927\u7ebf\u7a0b\u6570 +MaxConnectionSize=\u6700\u5927\u8fde\u63a5\u6570 +MaxCacheSize=\u6700\u5927\u7f13\u5b58\u6570 +MaxMailSize=\u6700\u5927\u90ae\u4ef6\u961f\u5217\u6570 +TimerConfig=\u5b9a\u65f6\u5668\u914d\u7f6e +AlivedCheckInterval=\u6ce8\u518c\u4e2d\u5fc3\u5b58\u6d3b\u72b6\u6001\u68c0\u67e5\u95f4\u9694(\u6beb\u79d2) +ChangedCheckInterval=\u6570\u636e\u53d8\u66f4\u68c0\u67e5\u95f4\u9694(\u6beb\u79d2) +FailedRetryInterval=\u5931\u8d25\u91cd\u8bd5\u95f4\u9694(\u6beb\u79d2) +DirtyCheckInterval=\u810f\u6570\u636e\u68c0\u67e5\u95f4\u9694(\u6beb\u79d2) +HeartbeatConfig=\u5fc3\u8df3\u914d\u7f6e +HeartbeatCheckInterval=\u4e0e\u5ba2\u6237\u7aef\u8fde\u63a5\u5fc3\u8df3\u68c0\u67e5\u95f4\u9694(\u6beb\u79d2) +HeartbeatCheckTimeout=\u5fc3\u8df3\u8d85\u65f6\u65f6\u95f4(\u6beb\u79d2) +TimeoutConfig=\u8d85\u65f6\u914d\u7f6e +NotifyTimeout=\u4e8b\u4ef6\u63a8\u9001\u8d85\u65f6(\u6beb\u79d2) +WarmupWaitTime=\u542f\u52a8\u9884\u70ed\u65f6\u95f4(\u6beb\u79d2) +UrlConfig=URL\u914d\u7f6e +BucServiceAddress=BUC\u670d\u52a1\u5730\u5740 +HelpDocumentUrl=\u5e2e\u52a9\u6587\u6863URL +HomepageDomain=\u663e\u793a\u4e3b\u9875\u57df\u540d +HomepageUrl=\u4e3b\u9875\u5730\u5740 +parametersConfig=\u53c2\u6570\u914d\u7f6e +DefaultServiceParameters=\u7f3a\u7701\u53c2\u6570\u914d\u7f6e +BatchAddressTip=\u591a\u4e2a\u5730\u5740\u7528\u6362\u884c\u7b26\u5206\u9694\uff0c\u5730\u5740\u5fc5\u9700\u662f0.0.0.0\u5230255.255.255.255\u7684IP\u5730\u5740 +ConsumerAddress=\u6d88\u8d39\u8005\u5730\u5740 +AccessControlTip=\u767d\u540d\u5355\u4f18\u5148\uff0c\u53ea\u8981\u6709\u767d\u540d\u5355\uff0c\u5219\u767d\u540d\u5355\u751f\u6548\uff0c\u5426\u5219\u9ed1\u540d\u5355\u751f\u6548 +access=\u8BBF\u95EE +Allowed=\u5DF2\u5141\u8BB8 +Forbidden=\u5DF2\u7981\u6B62 +allow=\u5141\u8BB8 +forbid=\u7981\u6B62 +confirm.allow=\u786E\u8BA4\u5141\u8BB8\u8BBF\u95EE? +confirm.forbid=\u786E\u8BA4\u7981\u6B62\u8BBF\u95EE?
\u88AB\u7981\u6B62\u7684\u5BA2\u6237\u7AEF\u5C06\u6536\u5230\u7981\u6B62\u8BBF\u95EE\u5F02\u5E38\u3002 +batch.allow=\u6279\u91CF\u5141\u8BB8 +batch.forbid=\u6279\u91CF\u7981\u6B62 +confirm.batch.allow=\u786E\u8BA4\u5141\u8BB8\u6240\u9009\u9879\u8BBF\u95EE? +confirm.batch.forbid=\u786E\u8BA4\u7981\u6B62\u6240\u9009\u9879\u8BBF\u95EE?
\u88AB\u7981\u6B62\u7684\u5BA2\u6237\u7AEF\u5C06\u6536\u5230\u7981\u6B62\u8BBF\u95EE\u5F02\u5E38\u3002 +only.allow=\u53EA\u5141\u8BB8 +only.forbid=\u53EA\u7981\u6B62 +confirm.only.allow=\u786E\u8BA4\u53EA\u5141\u8BB8\u9009\u4E2D\u9879\u8BBF\u95EE?
\u5176\u5B83\u672A\u9009\u4E2D\u9879\u53CA\u4EE5\u540E\u65B0\u589E\u9879\u5C06\u5168\u90E8\u53D8\u4E3A\u7981\u6B62\u8BBF\u95EE\u3002
\u88AB\u7981\u6B62\u7684\u5BA2\u6237\u7AEF\u5C06\u6536\u5230\u7981\u6B62\u8BBF\u95EE\u5F02\u5E38\u3002 +confirm.only.forbid=\u786E\u8BA4\u53EA\u7981\u6B62\u9009\u4E2D\u9879\u8BBF\u95EE?
\u5176\u5B83\u672A\u9009\u4E2D\u9879\u53CA\u4EE5\u540E\u65B0\u589E\u9879\u5C06\u5168\u90E8\u53D8\u4E3A\u5141\u8BB8\u8BBF\u95EE\u3002
\u88AB\u7981\u6B62\u7684\u5BA2\u6237\u7AEF\u5C06\u6536\u5230\u7981\u6B62\u8BBF\u95EE\u5F02\u5E38\u3002 +Choose=\u8bf7\u9009\u62e9 +userown=\u8d1f\u8d23\u7684\u670d\u52a1 +sysmanage.userown=\u8d1f\u8d23\u7684\u670d\u52a1 +SingleServiceTip=\u4e00\u4e2a\u8def\u7531\u53ea\u80fd\u5e94\u7528\u4e8e\u4e00\u4e2a\u670d\u52a1\uff0c\u4e0d\u652f\u6301\u591a\u670d\u52a1\u53ca\u901a\u914d\u7b26 +MultiServiceTip=\u670d\u52a1\u63a5\u53e3\u540d\u53ef\u4ee5\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u53ea\u652f\u6301\u4e00\u4e2a*\u7b26\u4e14\u8981\u5728\u63a5\u53e3\u672b\u5c3e\uff08\u5206\u7ec4\u3001\u7248\u672c\u4e0d\u652f\u6301\u901a\u914d\u7b26\uff09 +RouteNameTip=\u53ef\u4f7f\u7528\u4e2d\u6587\uff0c\u75311-200\u4e2a\u5b57\u7b26\u7ec4\u6210 +RoutePriorityTip=\u6570\u5b57\u8d8a\u5927\u8d8a\u4f18\u5148 +RouteServiceTip=\u4e00\u4e2a\u8def\u7531\u53ea\u80fd\u5e94\u7528\u4e8e\u4e00\u4e2a\u670d\u52a1\uff0c\u4e0d\u652f\u6301\u591a\u670d\u52a1\u53ca\u901a\u914d\u7b26 +#RouteServiceTip=\u670d\u52a1\u63a5\u53e3\u540d\u53ef\u4ee5\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u53ea\u652f\u6301\u4e00\u4e2a*\u7b26\u4e14\u8981\u5728\u63a5\u53e3\u672b\u5c3e\uff08\u5206\u7ec4\u3001\u7248\u672c\u4e0d\u652f\u6301\u901a\u914d\u7b26\uff09 +RouteMethodTip=\u53ea\u6709Dubbo2.0.0\u4ee5\u4e0a\u7248\u672c\u7684\u670d\u52a1\u6d88\u8d39\u7aef\u652f\u6301\u6309\u65b9\u6cd5\u8def\u7531\uff0c\u591a\u4e2a\u65b9\u6cd5\u540d\u7528\u9017\u53f7\u5206\u9694 +RouteClusterTip=\u53ef\u901a\u8fc7\u83dc\u5355"\u670d\u52a1\u63a7\u5236"->"\u670d\u52a1\u5668\u96c6\u7fa4"\u7ba1\u7406 +RouteMatchTip=\u5f53\u6d88\u8d39\u8005\u6ee1\u8db3\u5339\u914d\u6761\u4ef6\u65f6\u4f7f\u7528\u5f53\u524d\u89c4\u5219\u8fdb\u884c\u8fc7\u6ee4 +RouteFilterTip=\u6ee1\u8db3\u8fc7\u6ee4\u89c4\u5219\u7684\u63d0\u4f9b\u8005\u5730\u5740\u5c06\u88ab\u63a8\u9001\u7ed9\u6d88\u8d39\u8005 +RouteHostTip=\u591a\u4e2a\u503c\u7528\u9017\u53f7\u5206\u9694\uff0c\u4ee5\u661f\u53f7\u7ed3\u5c3e\u8868\u793a\u901a\u914d\u5730\u5740\u6bb5 +RouteApplicationTip=\u591a\u4e2a\u503c\u7528\u9017\u53f7\u5206\u9694 +RouteResult=\u8def\u7531\u7ed3\u679c +preview=\u9884\u89c8 +ConsumerApplication=\u6d88\u8d39\u8005\u5e94\u7528\u540d +ConsumerCluster=\u6d88\u8d39\u8005\u96c6\u7fa4 +ConsumerHost=\u6d88\u8d39\u8005IP\u5730\u5740 +ConsumerVersion=\u6d88\u8d39\u8005\u7248\u672c\u53f7 +ConsumerGroup=\u6d88\u8d39\u8005\u540d\u79f0\u7a7a\u95f4 +ProviderApplication=\u63d0\u4f9b\u8005\u5e94\u7528 +ProviderCluster=\u63d0\u4f9b\u8005\u96c6\u7fa4 +ProviderProtocol=\u63d0\u4f9b\u8005\u534f\u8bae +ProviderHost=\u63d0\u4f9b\u8005IP\u5730\u5740 +ProviderPort=\u63d0\u4f9b\u8005\u7aef\u53e3 +ProviderVersion=\u63d0\u4f9b\u8005\u7248\u672c\u53f7 +ProviderGroup=\u63d0\u4f9b\u8005\u540d\u79f0\u7a7a\u95f4 +MatchRule=\u5339\u914d\u6761\u4ef6 +FilterRule=\u8fc7\u6ee4\u89c4\u5219 +routeName=\u8DEF\u7531\u540D\u79F0 +routeRule=\u8def\u7531\u89c4\u5219 +Match=\u5339\u914d +Mismatch=\u4e0d\u5339\u914d +GetMethods=\u83b7\u53d6\u670d\u52a1\u65b9\u6cd5 +FeatureName=\u529f\u80fd\u540d +Features=\u7cfb\u7edf\u529f\u80fd +Disable=\u7981\u7528 +Enable=\u542f\u7528 +Enabled=\u5df2\u542f\u7528 +Disabled=\u5df2\u7981\u7528 +Unknown=\u672a\u77e5 +Users=\u7528\u6237\u7ba1\u7406 +UsersDescription=\u7528\u6237\u4fe1\u606f\u7ba1\u7406 +StatusList=\u6ce8\u518c\u4e2d\u5fc3\u72b6\u6001 +StatusListDescription=\u6ce8\u518c\u4e2d\u5fc3\u7cfb\u7edf\u72b6\u6001 +Operations=\u64cd\u4f5c\u8bb0\u5f55 +OperationsDescription=\u8bb0\u5f55\u6240\u6709\u4eba\u4e3a\u7684\u64cd\u4f5c +Accesses=\u670d\u52a1\u9ed1\u767d\u540d\u5355 +AccessesDescription=\u670d\u52a1\u9ed1\u767d\u540d\u5355 +Configs=\u7cfb\u7edf\u914d\u7f6e +Clusters=\u670d\u52a1\u5668\u96c6\u7fa4 +ClustersDescription=\u7ba1\u7406\u670d\u52a1\u96c6\u7fa4\u4fe1\u606f +Weights=\u63d0\u4f9b\u8005\u6743\u91cd +WeightsDescription=\u7ba1\u7406\u63d0\u4f9b\u8005\u6743\u91cd\u4fe1\u606f +Agreements=\u670d\u52a1\u7b49\u7ea7\u534f\u5b9a +AgreementsDescription=\u670d\u52a1\u7b49\u7ea7\u534f\u5b9a +ConfigsDescription=\u7cfb\u7edf\u914d\u7f6e\u4fe1\u606f +LoadBalances=\u8d1f\u8f7d\u5747\u8861 +LoadBalancesDescription=\u8d1f\u8f7d\u5747\u8861 +CachedList=\u5185\u5b58\u7f13\u5b58 +CachedListDescription=\u6ce8\u518c\u4e2d\u5fc3\u5185\u5b58\u7f13\u5b58\u8bb0\u5f55 +FailedList=\u5931\u8d25\u8bb0\u5f55 +Registries=\u6ce8\u518c\u4e2d\u5fc3\u96c6\u7fa4 +FailedListDescription=\u5931\u8d25\u8bb0\u5f55\u5217\u8868 +registryAddress=\u6ce8\u518c\u4e2d\u5fc3\u5217\u8868 +RegistriesDescription=\u67e5\u770b\u5df2\u77e5\u7684\u6ce8\u518c\u4e2d\u5fc3 +Help=\u5e2e\u52a9 +HelpDescription=\u5e2e\u52a9 +Providers=\u670d\u52a1\u63d0\u4f9b\u8005 +ProvidersDescription=\u67e5\u770b\u6240\u6709\u670d\u52a1\u63d0\u4f9b\u8005 +Log=\u65e5\u5fd7\u6587\u4ef6 +LogDescription=\u67e5\u770b\u6ce8\u518c\u4e2d\u5fc3Log4J\u65e5\u5fd7 +Services=\u670d\u52a1\u4fe1\u606f +ServicesDescription=\u67e5\u770b\u670d\u52a1\u5df2\u6ce8\u518c\u7684\u6240\u6709\u670d\u52a1 +Owned=\u670d\u52a1\u5f52\u5c5e +OwnedDescription=\u670d\u52a1\u5f52\u5c5e +Tests=\u670d\u52a1\u6d4b\u8bd5 +TestsDescription=\u670d\u52a1\u6d4b\u8bd5\u7528\u4f8b +Documents=\u670d\u52a1\u6587\u6863 +DocumentsDescription=\u6587\u6863 +Applications=\u670d\u52a1\u5e94\u7528 +ApplicationsDescription=\u670d\u52a1\u5e94\u7528 +Consumers=\u670d\u52a1\u6d88\u8d39\u8005 +ConsumersDescription=\u67e5\u770b\u6240\u6709\u670d\u52a1\u6d88\u8d39\u8005 +System=\u7cfb\u7edf\u73af\u5883 +SystemDescription=\u7cfb\u7edf\u73af\u5883\u4fe1\u606f +Routes=\u670d\u52a1\u8def\u7531 +Route=\u8def\u7531 +RoutesDescription=\u7ba1\u7406\u670d\u52a1\u8def\u7531\u89c4\u5219 +Connections=\u5957\u63a5\u5b57\u8fde\u63a5 +ConnectionsDescription=\u8fde\u63a5 +RegistryAddress=\u6ce8\u518c\u4e2d\u5fc3\u5730\u5740 +RegisterUsername=\u6ce8\u518c\u7528\u6237\u540d +RegisterDate=\u6ce8\u518c\u65f6\u95f4 +subscribeDate=\u8ba2\u9605\u65f6\u95f4 +Statistics=\u670d\u52a1\u5b9e\u65f6\u7edf\u8ba1 +CheckConnection=\u68c0\u67e5\u8fde\u63a5 +CheckDatabase=\u68c0\u67e5\u6570\u636e\u5e93 +queryUrl=\u8ba2\u9605\u53c2\u6570 +Status=\u72b6\u6001 +notify=\u901A\u77E5 +notified=\u5df2\u901a\u77e5 +unnotified=\u672A\u901A\u77E5 +Unuse=\u672a\u4f7f\u7528 +NoProvider=\u6ca1\u6709\u63d0\u4f9b\u8005 +NoConsumer=\u6ca1\u6709\u6d88\u8d39\u8005 +route.consumer.not.match=\u672cRoute\u4e0d\u5339\u914d\u6b64\u670d\u52a1\u6d88\u8d39\u8005\uff08\u4f1a\u8fd4\u56de\u6240\u6709\u7684\u670d\u52a1\u63d0\u4f9b\u8005\uff09 +#labels +all=\u6240\u6709 +service=\u670d\u52a1\u540d +application=\u5e94\u7528\u540d +recursive=\u5faa\u73af +layer=\u670d\u52a1\u5206\u5c42 +address=\u673a\u5668IP +dubbo=\u4f7f\u7528dubbo\u7248\u672c +version=\u670d\u52a1\u7248\u672c +group=\u670d\u52a1\u5206\u7ec4 +url=\u670d\u52a1\u5730\u5740 +parameters=\u670d\u52a1\u53c2\u6570 +provider=\u63d0\u4f9b\u8005\u5730\u5740 +consumer=\u6d88\u8d39\u8005\u5730\u5740 +registry=\u6ce8\u518c\u4e2d\u5fc3\u5730\u5740 +username=\u7528\u6237\u540d +created=\u521b\u5efa\u65f6\u95f4 +modified=\u4fee\u6539\u65f6\u95f4 +register.date=\u6ce8\u518c\u65f6\u95f4 +type=\u7c7b\u578b +static=\u9759\u6001 +dynamic=\u52a8\u6001 +status=\u72b6\u6001 +enabled=\u5df2\u542f\u7528 +disabled=\u5df2\u7981\u7528 +check=\u68c0\u67e5 +operation=\u64cd\u4f5c +role=\u89d2\u8272 +provider=\u63d0\u4f9b\u8005 +consumer=\u6d88\u8d39\u8005 +consumer.address=\u6d88\u8d39\u8005\u5730\u5740 +no.provider=\u6ca1\u6709\u63d0\u4f9b\u8005 +no.consumer=\u6ca1\u6709\u6d88\u8d39\u8005 +ok=\u6b63\u5e38 +warn=\u8b66\u544a +error=\u51fa\u9519 +success=\u6210\u529f +failure=\u5931\u8d25 +update=\u66f4\u65b0 +operation.success=\u64cd\u4f5c\u6210\u529f\uff01 +operation.failure=\u64cd\u4f5c\u5931\u8d25\uff01 +isRegistered=\u6ce8\u518c\u7f13\u5b58 +isCached=\u670d\u52a1\u7f13\u5b58 +isCached.true=\u670d\u52a1\u5728\u7f13\u5b58\u4e2d +isCached.false=\u670d\u52a1\u672a\u540c\u6b65\u5230\u7f13\u5b58 +isSubscribed=\u8ba2\u9605\u7f13\u5b58 +isSubscribed.true=\u6b64\u6d88\u8d39\u8005\u5728\u5f53\u524d\u6ce8\u518c\u4e2d\u5fc3\u8ba2\u9605 +isSubscribed.false=\u6b64\u6d88\u8d39\u8005\u5728\u5176\u4ed6\u6ce8\u518c\u4e2d\u5fc3\u8ba2\u9605 +isSubscribed.unmatch=\u6b64\u6d88\u8d39\u8005\u5728\u6570\u636e\u5e93\u548c\u7f13\u5b58\u4e2d\u7684\u6ce8\u518c\u4e2d\u5fc3\u5730\u5740\u4e0d\u4e00\u81f4 +#operations +search=\u641c\u7d22 +search=\u641c\u7d22 +query=\u67e5\u8be2 +show=\u67e5\u770b +add=\u65b0\u589e +addMock=\u65b0\u589eMock +multiadd=\u6279\u91cf\u65b0\u589e +edit=\u7f16\u8f91 +save=\u4fdd\u5b58 +delete=\u5220\u9664 +enable=\u542f\u7528 +disable=\u7981\u7528 +recover=\u6062\u590d +reload=\u91cd\u8f7d\u7f13\u5b58 +reconnect=\u91cd\u8fde +renotify=\u91cd\u65b0\u901a\u77e5 +tostatic=\u8f6c\u4e3a\u9759\u6001 +todynamic=\u8f6c\u4e3a\u52a8\u6001 +favorite=\u6536\u85cf +register=\u7533\u8bf7\u6ce8\u518c +subscribe=\u7533\u8bf7\u8c03\u7528 +logout=\u9000\u51fa +back=\u8fd4\u56de +cancel=\u53d6\u6d88 +confirm=\u786e\u5b9a +batch.add=\u6279\u91cf\u65b0\u589e +batch.multiservices.add=\u591a\u670d\u52a1\u65b0\u589e +batch.delete=\u6279\u91cf\u5220\u9664 +batch.enable=\u6279\u91cf\u542f\u7528 +batch.disable=\u6279\u91cf\u7981\u7528 +batch.recover=\u6279\u91cf\u6062\u590d +batch.reconnect=\u6279\u91cf\u91cd\u8fde +batch.renotify=\u6279\u91cf\u91cd\u65b0\u901a\u77e5 +batch.tostatic=\u6279\u91cf\u9759\u6001 +batch.todynamic=\u6279\u91cf\u52a8\u6001 +batch.favorite=\u6279\u91cf\u6536\u85cf +batch.reload=\u6279\u91cf\u91cd\u8f7d +confirm.batch.disable=\u786e\u8ba4\u6279\u91cf\u7981\u7528 +confirm.batch.enable=\u786e\u8ba4\u6279\u91cf\u542f\u7528 +#prompts +please.input.service=\u8bf7\u8f93\u5165\u670d\u52a1\u540d +please.input.application=\u8bf7\u8f93\u5165\u5e94\u7528\u540d +please.input.address=\u8bf7\u8f93\u5165\u673a\u5668IP +please.input.layer=\u8bf7\u8f93\u5165\u670d\u52a1\u5206\u5c42 +please.input=\u8bf7\u8f93\u5165\u8981\u64cd\u4f5c\u7684\u5185\u5bb9 +please.select=\u8bf7\u9009\u62e9\u8981\u64cd\u4f5c\u7684\u9879 +empty.list=\u6ca1\u6709\u6570\u636e\u53ef\u4ee5\u64cd\u4f5c +not.found=\u6ca1\u6709\u641c\u5230\u5339\u914d\u7684\u7ed3\u679c +show.all=\u663e\u793a\u5168\u90e8 +confirm.logout=\u786e\u5b9a\u9000\u51fa\u767b\u5f55? +confirm.delete=\u786e\u5b9a\u5220\u9664?
\u5220\u9664\u540E\u5C06\u4E0D\u53EF\u8FD8\u539F\u3002 +confirm.enable=\u786e\u5b9a\u542f\u7528? +confirm.disable=\u786e\u5b9a\u7981\u7528? +confirm.recover=\u786e\u5b9a\u6062\u590d? +confirm.reconnect=\u786e\u5b9a\u91cd\u8fde? +confirm.renotify=\u786e\u5b9a\u901a\u77e5? +confirm.tostatic=\u786e\u5b9a\u8f6c\u4e3a\u9759\u6001? +confirm.todynamic=\u786e\u5b9a\u8f6c\u4e3a\u52a8\u6001? +confirm.batch.delete=\u786e\u5b9a\u5220\u9664\u6240\u9009\u9879?
\u5220\u9664\u540E\u5C06\u4E0D\u53EF\u8FD8\u539F\u3002 +confirm.batch.enable=\u786e\u5b9a\u542f\u7528\u6240\u9009\u9879? +confirm.batch.disable=\u786e\u5b9a\u7981\u7528\u6240\u9009\u9879? +confirm.batch.recover=\u786e\u5b9a\u6062\u590d\u6240\u9009\u9879? +confirm.batch.reload=\u786e\u5b9a\u91cd\u8f7d\u5f53\u524d\u670d\u52a1? +confirm.batch.reconnect=\u786e\u5b9a\u91cd\u8fde\u6240\u9009\u9879? +confirm.batch.renotify=\u786e\u5b9a\u91cd\u65b0\u901a\u77e5\u6240\u9009\u9879? +confirm.batch.tostatic=\u786e\u5b9a\u8f6c\u4e3a\u9759\u6001\u6240\u9009\u9879? +confirm.batch.todynamic=\u786e\u5b9a\u8f6c\u4e3a\u52a8\u6001\u6240\u9009\u9879? +current.user=\u5f53\u524d\u7528\u6237 +CheckProviderLocalAddress={0}\u4E0D\u662F\u6709\u6548\u7684\u8FDC\u7A0B\u670D\u52A1\u5730\u5740\uFF0C\u8BF7\u68C0\u67E5\u63D0\u4F9B\u65B9/etc/hosts\u6620\u5C04\u662F\u5426\u6B63\u786E\u3002 +CheckProviderApplicationDifferent=\u591a\u4e2a\u4e0d\u540c\u5e94\u7528\u6ce8\u518c\u4e86\u76f8\u540c\u670d\u52a1\uff0c\u8bf7\u68c0\u67e5{0}\u4e2d\u662f\u5426\u6709\u8bef\u66b4\u9732\u3002 +CheckProviderAddressMismatch=\u670d\u52a1URL\u4e0a\u7684IP\u4e0e\u8fde\u63a5\u6ce8\u518c\u4e2d\u5fc3\u7684IP\u4e0d\u76f8\u540c +CheckConnectionDisconnected=\u8be5\u8fde\u63a5\u5df2\u65ad\u5f00\uff0c\u6570\u636e\u5e93\u810f\u6570\u636e\uff0c\u8bf7\u70b9\u51fb\u201c\u91cd\u8fde\u201d +CheckConnectionExpired=\u8be5\u8fde\u63a5\u6240\u5728\u6ce8\u518c\u4e2d\u5fc3\u5df2\u4e0d\u5b58\u5728\uff08\u6570\u636e\u4f1a\u81ea\u52a8\u5b9a\u671f\u6e05\u7406\uff09 +CheckDatabaseMiss=\u6570\u636e\u5e93\u6570\u636e\u610f\u5916\u4e22\u5931\u6b64\u6570\u636e\uff0c\u8bf7\u70b9\u51fb\u201c\u6062\u590d\u201d +CheckDatabaseMismatch=\u6570\u636e\u5e93\u4e0e\u6ce8\u518c\u7f13\u5b58\u6570\u636e\u6ce8\u518c\u5730\u5740\u4e0d\u4e00\u81f4 +CheckDatabaseDirty2Registered=\u6570\u636e\u5e93\u6bd4\u6ce8\u518c\u7f13\u5b58\u591a\u6b64\u810f\u6570\u636e\uff0c\u8bf7\u70b9\u51fb\u201c\u91cd\u8fde\u201d +CheckDatabaseDirty2Subscribed=\u6570\u636e\u5e93\u6bd4\u8ba2\u9605\u7f13\u5b58\u591a\u6b64\u810f\u6570\u636e\uff0c\u8bf7\u70b9\u51fb\u201c\u91cd\u8fde\u201d +CheckCacheRegistered=\u6ce8\u518c\u7f13\u5b58\u4e0d\u5b58\u5728\uff0c\u8bf7\u70b9\u51fb\u201c\u91cd\u8fde\u201d +CheckCacheConsumer=\u65e0\u6b64\u670d\u52a1\u7684\u670d\u52a1\u7f13\u5b58\uff0c\u4f46\u6709\u6d88\u8d39\u8005\uff01\u8bf7\u70b9\u51fb\u201c\u91cd\u8f7d\u201d +CheckCacheProvider=\u670d\u52a1\u7f13\u5b58\u65e0\u6b64\u63d0\u4f9b\u8005\uff0c\u8bf7\u70b9\u51fb\u201c\u91cd\u8f7d\u201d +CheckCacheSubscribed=\u8ba2\u9605\u7f13\u5b58\u4e0d\u5b58\u5728\uff0c\u8bf7\u70b9\u51fb\u201c\u91cd\u8fde\u201d +CheckCacheService=\u65e0\u6b64\u670d\u52a1\u7684\u670d\u52a1\u7f13\u5b58\uff0c\u8bf7\u70b9\u51fb\u63d0\u4f9b\u8005\u7684\u201c\u91cd\u8f7d\u201d +select.all=\u5168\u9009 +ip.address=IP\u5730\u5740 +registry.newservice=\u6ce8\u518c\u65b0\u670d\u52a1 +add.new.provider=\u6dfb\u52a0\u63d0\u4f9b\u8005 +add.new.route=\u6dfb\u52a0\u8def\u7531 +message.search.noresult=\u6ca1\u6709\u7b26\u5408\u7684\u67e5\u8be2\uff0c\u8bf7\u4ece\u63d0\u793a\u5217\u8868\u4e2d\u9009\u62e9\u67e5\u8be2\u6761\u4ef6\uff01 +provide.service=\u63d0\u4f9b\u7684\u670d\u52a1 +service.method=\u670d\u52a1\u65b9\u6cd5 +service.filter=\u670d\u52a1filter +default.service.filter=\u9ed8\u8ba4\u670d\u52a1filter +startegy=\u7b56\u7565 +route.name=\u8def\u7531\u540d\u79f0 +rule.match=\u5339\u914d\u89c4\u5219 +rule.filtrate=\u8fc7\u6ee4\u89c4\u5219 +priority=\u4f18\u5148\u7ea7 +routed=\u5df2\u8def\u7531 +unrouted=\u672A\u8DEF\u7531 +page.total=\u5171 +page.records=\u6761\u8bb0\u5f55 +page.ordinal=\u7b2c +page.page=\u9875 +default.lazy=\u9ed8\u8ba4\u61d2\u542f\u52a8 +page.next=\u4e0b\u4e00\u9875 +page.prev=\u4e0a\u4e00\u9875 +page.first=\u9996\u9875 +page.last=\u5c3e\u9875 +page.line=\u6761 +methodName=\u65b9\u6cd5\u540d +proview=\u9884\u89c8 +cluster.name=\u96c6\u7fa4\u540d +cluster.address=\u96c6\u7fa4\u673a\u5668\u5730\u5740 +sameserviceadd=\u540c\u670d\u52a1\u6dfb\u52a0 +whitelist=\u5141\u8BB8 +blacklist=\u7981\u6B62 +toWhiteAndBlackList=\u8f6c\u5165\u767d\u540d\u5355/\u8f6c\u5165\u9ed1\u540d\u5355 +obtainProviderAddress=\u83b7\u53d6\u63d0\u4f9b\u8005\u5730\u5740 +towhitelist=\u52a0\u5165\u767d\u540d\u5355 +toblacklist=\u52a0\u5165\u9ed1\u540d\u5355 +enable=\u542f\u7528 +disable=\u7981\u7528 +copy=\u590d\u5236 +batch.enable=\u6279\u91cf\u542f\u7528 +batch.disable=\u6279\u91cf\u7981\u7528 +batch.towhitelist=\u52a0\u5165\u767d\u540d\u5355 +batch.toblacklist=\u52a0\u5165\u9ed1\u540d\u5355 +confirm.favorites=\u786e\u8ba4\u6536\u85cf\u5417 +confirm.batch.towhitelist=\u786e\u8ba4\u52a0\u5165\u767d\u540d\u5355?
\u5c06\u7981\u6b62\u4e0d\u5728\u767d\u540d\u5355\u5185\u7684\u6240\u6709\u6d88\u8d39\u8005\u8bbf\u95ee\uff0c\u9ed1\u540d\u5355\u5931\u6548\u3002 +confirm.batch.toblacklist=\u786e\u8ba4\u52a0\u5165\u9ed1\u540d\u5355?
\u5982\u679c\u6ca1\u6709\u767d\u540d\u5355\uff0c\u5c06\u7981\u6b62\u5728\u9ed1\u540d\u5355\u5185\u7684\u6240\u6709\u5176\u5b83\u6d88\u8d39\u8005\u8bbf\u95ee\u3002 +confirm.enable=\u786e\u8ba4\u542f\u7528 +confirm.disable=\u786e\u8ba4\u7981\u7528 +confirm.edit=\u786e\u8ba4\u7f16\u8f91 +confirm.disableFeature=\u786e\u8ba4\u7981\u7528\u529f\u80fd +confirm.enableFeature=\u786e\u8ba4\u542f\u7528\u529f\u80fd +confirmDeleteOwner=\u786e\u8ba4\u5220\u9664\u8d1f\u8d23\u4eba +welcome=\u60a8\u597d +approve=\u5f85\u5ba1\u6279 +chinese.simple=\u7b80\u4f53\u4e2d\u6587 +chinese.tradition=\u7e41\u9ad4\u4e2d\u6587 +register.service=\u6ce8\u518c\u65b0\u670d\u52a1 +erratum.guide=\u6392\u9519\u5411\u5bfc +preview.guide=\u9884\u89c8\u5411\u5bfc +sysinfo.status=\u6ce8\u518c\u4e2d\u5fc3\u72b6\u6001 +sysinfo.registries=\u6ce8\u518c\u4e2d\u5fc3\u96c6\u7fa4 +sysinfo.connections=\u5957\u63a5\u5b57\u8fde\u63a5 +sysinfo.cached=\u5185\u5b58\u7f13\u5b58 +sysinfo.failed=\u5931\u8d25\u8bb0\u5f55 +sysinfo.operations=\u64cd\u4f5c\u8bb0\u5f55 +sysinfo.logs=\u7cfb\u7edf\u65e5\u5fd7 +sysinfo.versions=Dubbo\u7248\u672c +sysinfo.dumps=\u7cfb\u7edf\u5feb\u7167 +sysinfo.envs=\u7cfb\u7edf\u73af\u5883 +sysinfo.helps=\u5e2e\u52a9\u6587\u6863 +system.management=\u7cfb\u7edf\u7ba1\u7406 +sysmanage.users=\u7528\u6237\u7ba1\u7406 +sysmanage.configs=\u7cfb\u7edf\u53c2\u6570\u8bbe\u7f6e +sysmanage.features=\u7cfb\u7edf\u529f\u80fd\u5f00\u5173 +system.function.control=\u7cfb\u7edf\u529f\u80fd\u5f00\u5173 +personal.set=\u4e2a\u4eba\u8bbe\u7f6e +modify.personalinfo=\u4fee\u6539\u4e2a\u4eba\u4fe1\u606f +modify.personal.password=\u4fee\u6539\u4e2a\u4eba\u5bc6\u7801 +operation.operateaddress=\u64cd\u4f5c\u8005\u5730\u5740 +operation.operatetype=\u64cd\u4f5c\u7c7b\u578b +operation.datatype=\u6570\u636e\u7c7b\u578b +operation.data=\u64cd\u4f5c\u5185\u5bb9 +operation.createtime=\u64cd\u4f5c\u65f6\u95f4 +operation.clean=\u6e05\u7406 +passwd.oldwrong=\u65e7\u5bc6\u7801\u9519\u8bef +failed=\u5931\u8d25\u8bb0\u5f55 +failed_type=\u7c7b\u578b +failed_data=\u6570\u636e +failed_sync=\u540c\u6b65\u5730\u5740\u5931\u8d25\u8bb0\u5f55 +failed_subscribe=\u8ba2\u9605\u5931\u8d25\u8bb0\u5f55 +failed_notify=\u901a\u77e5\u5931\u8d25\u8bb0\u5f55 +failed_collect=\u7edf\u8ba1\u5931\u8d25\u8bb0\u5f55 +failed_register=\u6ce8\u518c\u5931\u8d25\u8bb0\u5f55 +failed_redirect=\u91cd\u5b9a\u5411\u5931\u8d25\u8bb0\u5f55 +failed_disconnect=\u65ad\u5f00\u6e05\u7406\u5931\u8d25\u8bb0\u5f55 +clientAddress=\u5ba2\u6237\u7aef\u5730\u5740 +overrideAddress=\u8986\u76d6\u5730\u5740 +serviceInfo=\u670d\u52a1\u4fe1\u606f +consumerAddress=\u6d88\u8d39\u8005\u5730\u5740 +providerAddress=\u63d0\u4f9b\u8005\u5730\u5740 +registryAddress=\u6ce8\u518c\u4e2d\u5fc3\u5730\u5740 +serviceName=\u670d\u52a1\u540d +serviceUrl=\u670d\u52a1\u5730\u5740 +overrideConsumerAddress=\u53ea\u63a8\u9001\u7ed9\u6307\u5b9a\u6d88\u8d39\u8005\u5730\u5740 +overrideProviderAddress=\u53ea\u5728\u8c03\u7528\u6307\u5b9a\u63d0\u4f9b\u8005\u5730\u5740\u65f6\u751f\u6548 +tipConsumerAddress=\u4e0d\u586b\u8868\u793a\u5bf9\u6d88\u8d39\u8005\u5e94\u7528\u7684\u6240\u6709\u673a\u5668\u751f\u6548 +tipProviderAddress=\u4e0d\u586b\u8868\u793a\u5bf9\u670d\u52a1\u7684\u6240\u6709\u63d0\u4f9b\u8005\u673a\u5668\u751f\u6548 +tipProviderAddress=\u4e0d\u586b\u8868\u793a\u5bf9\u670d\u52a1\u7684\u6240\u6709\u63d0\u4f9b\u8005\u673a\u5668\u751f\u6548 +logs=\u7cfb\u7edf\u65e5\u5fd7 +logs.file=\u65e5\u5fd7\u6587\u4ef6 +logs.size=\u6587\u4ef6\u5927\u5c0f +logs.modify=\u4fee\u6539\u65f6\u95f4 +logs.level=\u65e5\u5fd7\u7ea7\u522b +change.log.level=\u4fee\u6539\u65e5\u5fd7\u7ea7\u522b +logs.confirmChangeLogLevel=\u786e\u8ba4\u4fee\u6539\u65e5\u5fd7\u7ea7\u522b +cached=\u5185\u5b58\u7f13\u5b58 +cached.type=\u7c7b\u578b +cached.data=\u6570\u636e +cached.reload=\u91cd\u65b0\u52a0\u8f7d +batch.cached.reload=\u6279\u91cf\u91cd\u65b0\u52a0\u8f7d +cached.recover=\u6062\u590d +batch.cached.recover=\u6279\u91cf\u6062\u590d +servicePrivilege=\u670d\u52a1\u6743\u9650 +creator=\u521b\u5efa\u8005 +name=\u540d\u79f0 +department=\u90e8\u95e8 +email=\u90ae\u7bb1 +phone=\u7535\u8bdd +alitalk=\u963f\u91cc\u65fa\u65fa +password=\u5bc6\u7801 +roleR=\u8d85\u7ea7\u7ba1\u7406\u5458 +roleA=\u7ba1\u7406\u5458 +roleG=\u6e38\u5ba2 +roleDescR=\u7ba1\u7406\u6240\u6709 +roleDescA=\u7ba1\u7406\u81ea\u5df1\u521b\u5efa\u7684\u7528\u6237\u548c\u670d\u52a1 +roleDescG=\u53ea\u67e5\u770b +oldPassword=\u65e7\u5bc6\u7801 +newPassword=\u65b0\u5bc6\u7801 +reset=\u91cd\u7f6e +restPassword=\u91cd\u7f6e\u5bc6\u7801 +confirmNewPassword=\u786e\u8ba4\u65b0\u5bc6\u7801 +owns=\u8d1f\u8d23\u7684\u670d\u52a1 +confirmPassword=\u786e\u8ba4\u5bc6\u7801 +generatePassword=\u751f\u6210\u5bc6\u7801 +displayName=\u59d3\u540d +locale=\u4f7f\u7528\u8bed\u8a00 +privilegeTip=\u591a\u4e2a\u503c\u7528\u9017\u53f7(,)\u5206\u9694\uff0c\u901a\u914d\u7b26\u7528\u661f\u53f7(*)\u8868\u793a\uff0c\u53ea\u80fd\u5728\u6bcf\u4e2a\u503c\u7684\u672a\u5c3e\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u88ab\u6388\u4e0e\u7684\u6743\u9650\u4e0d\u80fd\u8d85\u51fa\u5f53\u524d\u7ba1\u7406\u4eba\u5458\u7684\u6743\u9650 +displayNameTip=\u7528\u6237\u59d3\u540d\uff0c\u53ef\u4f7f\u7528\u4e2d\u6587\uff0c\u75311-50\u4e2a\u5b57\u7b26\u7ec4\u6210 +emailTip=\u7528\u4e8e\u63a5\u6536\u7cfb\u7edf\u90ae\u4ef6\uff0c\u53ef\u4ee5\u8f93\u5165\u591a\u4e2a\u90ae\u4ef6\u5730\u5740\uff0c\u4f7f\u7528\u82f1\u6587\u5206\u53f7\u5206\u9694(;)\uff0c \u5f62\u5982 foo1@163.comj;foo2@gmail.com +userLocaleTip=\u53d1\u9001\u7cfb\u7edf\u90ae\u4ef6\u65f6\uff0c\u5c06\u6839\u636e\u7528\u6237\u4f7f\u7528\u7684\u8bed\u8a00\u53d1\u9001\u4e0d\u540c\u8bed\u8a00\u7684\u90ae\u4ef6\u5185\u5bb9 +DisplayNameTip +EmailTip +UserLocaleTip +missRequestParameters=\u4e22\u5931\u8bf7\u6c42\u53c2\u6570 +haveNoRootPrivilege=\u6ca1\u6709root\u6743\u9650 +confirmReloadCache=\u786e\u8ba4\u91cd\u65b0\u52a0\u8f7d\u7f13\u5b58 +confirmDeleteRegistry=\u786e\u8ba4\u5220\u9664\u6ce8\u518c\u4e2d\u5fc3 +confirmAutoRedirectRegistry=\u786e\u8ba4\u91cd\u5b9a\u5411\u6ce8\u518c\u4e2d\u5fc3 +confirmDeleteExpiredRegistry=\u786e\u8ba4\u5220\u9664\u8fc7\u671f\u6ce8\u518c\u4e2d\u5fc3 +confirmSyncRegistry=\u786e\u8ba4\u540c\u6b65\u6ce8\u518c\u4e2d\u5fc3\u5730\u5740\u5217\u8868\u5230\u5ba2\u6237\u7aef +confirm.toblacklist=\u786e\u8ba4\u52a0\u5165\u9ed1\u540d\u5355?
\u5982\u679c\u6ca1\u6709\u767d\u540d\u5355\uff0c\u5c06\u7981\u6b62\u5728\u9ed1\u540d\u5355\u5185\u7684\u6240\u6709\u6d88\u8d39\u8005\u8bbf\u95ee\u3002 +confirm.towhitelist=\u786e\u8ba4\u52a0\u5165\u767d\u540d\u5355?
\u5c06\u7981\u6b62\u4e0d\u5728\u767d\u540d\u5355\u5185\u7684\u6240\u6709\u5176\u5b83\u6d88\u8d39\u8005\u8bbf\u95ee\uff0c\u9ed1\u540d\u5355\u5931\u6548\u3002 +confirm.clean.operation=\u786e\u8ba4\u6e05\u9664\u64cd\u4f5c\u8bb0\u5f55 +autoRedirect=\u81ea\u52a8\u91cd\u5b9a\u5411 +deleteExpired=\u5220\u9664\u6240\u6709\u5df2\u8fc7\u671f +sync=\u540c\u6b65 +legacies=1.0\u9057\u7559\u5ba2\u6237\u7aef +logined=\u5df2\u767b\u5f55\u5ba2\u6237\u7aef +dumps=\u7cfb\u7edf\u5feb\u7167 +Registry=\u6ce8\u518c\u4e2d\u5fc3\u7248\u672c +Java=JDK\u7248\u672c +Locale=\u8bed\u8a00 +OS=\u64cd\u4f5c\u7cfb\u7edf +Uptime=\u8fd0\u884c\u65f6\u95f4 +Host=\u57df\u540d +CPU=\u0043\u0050\u0055 +confirmEnableUser=\u786e\u8ba4\u542f\u52a8\u7528\u6237 +confirmDisableUser=\u786e\u8ba4\u7981\u7528\u7528\u6237 +documentTitle=\u6587\u6863\u6807\u9898 +documentLink/documentPage=\u94fe\u63a5\u5730\u5740/\u9875\u9762\u5185\u5bb9 +documentInternal=\u9875\u9762 +documentExternal=\u94fe\u63a5 +documentApi=API +documentType=\u6587\u6863\u7c7b\u578b +documentContent=\u6587\u6863\u5185\u5bb9 +Yes=\u662f +No=\u5426 +returnValue=\u8fd4\u56de\u503c +throwException=\u629b\u51fa\u5f02\u5e38 +#BatchAddressTip=\u591a\u4e2a\u5730\u5740\u7528\u6362\u884c\u7b26\u5206\u9694\uff0c\u5730\u5740\u5fc5\u9700\u662f0.0.0.0\u5230255.255.255.255\u7684IP\u5730\u5740 +#AccessControlTip=\u767d\u540d\u5355\u4f18\u5148\uff0c\u53ea\u8981\u6709\u767d\u540d\u5355\uff0c\u5219\u767d\u540d\u5355\u751f\u6548\uff0c\u5426\u5219\u9ed1\u540d\u5355\u751f\u6548 +#RouteNameTip=\u53ef\u4f7f\u7528\u4e2d\u6587\uff0c\u75311-200\u4e2a\u5b57\u7b26\u7ec4\u6210 +#RoutePriorityTip=\u6570\u5b57\u8d8a\u5927\u8d8a\u4f18\u5148 +#RouteMethodTip=\u53ea\u6709Dubbo2.0.0\u4ee5\u4e0a\u7248\u672c\u7684\u670d\u52a1\u6d88\u8d39\u7aef\u652f\u6301\u6309\u65b9\u6cd5\u8def\u7531\uff0c\u591a\u4e2a\u65b9\u6cd5\u540d\u7528\u9017\u53f7\u5206\u9694 +#Choose=\u8bf7\u9009\u62e9 +#RouteMatchTip=\u5f53\u6d88\u8d39\u8005\u6ee1\u8db3\u5339\u914d\u6761\u4ef6\u65f6\u4f7f\u7528\u5f53\u524d\u89c4\u5219\u8fdb\u884c\u8fc7\u6ee4 +#RouteHostTip=\u591a\u4e2a\u503c\u7528\u9017\u53f7\u5206\u9694\uff0c\u4ee5\u661f\u53f7\u7ed3\u5c3e\u8868\u793a\u901a\u914d\u5730\u5740\u6bb5 +#RouteClusterTip=\u53ef\u901a\u8fc7\u83dc\u5355"\u670d\u52a1\u63a7\u5236"->"\u670d\u52a1\u5668\u96c6\u7fa4"\u7ba1\u7406 +#RouteFilterTip=\u6ee1\u8db3\u8fc7\u6ee4\u89c4\u5219\u7684\u63d0\u4f9b\u8005\u5730\u5740\u5c06\u88ab\u63a8\u9001\u7ed9\u6d88\u8d39\u8005 +testMethodTip=\u5982\u679c\u6709\u65b9\u6cd5\u91cd\u8f7d\u6216\u4f7f\u7528Dubbo1.0.x\u7248\u672c\u7684\u670d\u52a1\u63d0\u4f9b\u8005\uff0c\u9700\u5199\u5168\u65b9\u6cd5\u7b7e\u540d\uff0c\u5982\uff1afindBy(int,java.lang.String)\uff0c\u5426\u5219\u53ea\u9700\u65b9\u6cd5\u540d\uff0c\u5982\uff1afindBy +testJsonTip=JSON\u683c\u5f0f\uff1a\u5b57\u7b26\u4e32\u7528\u53cc\u5f15\u53f7\u8868\u793a\uff0c\u5982\uff1a"\u5b57\u7b26\u4e32"\uff0c\u6570\u5b57\u548cBoolean\u503c\u4e0d\u7528\u5f15\u53f7\uff0c\u5982\uff1a123 \u548c true \u6216 false\uff0cPOJO\u5bf9\u8c61\u6216Map\u7528\u5927\u62ec\u53f7\u8868\u793a\uff0c\u5982\uff1a{"\u5c5e\u6027\u540d1": "\u5c5e\u6027\u503c1", "\u5c5e\u6027\u540d2": "\u5c5e\u6027\u503c2"}\uff0c\u6570\u7ec4\u6216List\u6216Set\u7528\u65b9\u62ec\u53f7\u8868\u793a\uff0c\u5982\uff1a["\u503c1", "\u503c2"] +testParametersTip=\u5f53\u4e3a\u65e0\u53c2\u6570\u65b9\u6cd5\u65f6\u53c2\u6570\u503c\u53ef\u4ee5\u4e0d\u586b\uff0c\u53c2\u6570\u503c\u4f7f\u7528JSON\u683c\u5f0f\u8868\u793a +testResultTip=\u5f53\u4e3avoid\u65b9\u6cd5\u65f6\u7ed3\u679c\u53ef\u4ee5\u4e0d\u586b\uff0c\u629b\u51fa\u5f02\u5e38\u4f7f\u7528\u5f02\u5e38\u7c7b\u5168\u540d\u8868\u793a\uff0c\u8fd4\u56de\u503c\u4f7f\u7528JSON\u683c\u5f0f\u8868\u793a +testAutoRunTip=\u5982\u679c\u8bbe\u7f6e\u4e3a\u81ea\u52a8\u8fd0\u884c\uff0c\u82e5\u8be5\u670d\u52a1\u5df2\u6ce8\u518c\u6216\u65b0\u6ce8\u518c\uff0c\u5219\u81ea\u52a8\u8fd0\u884c\u6b64\u6d4b\u8bd5\u7528\u4f8b\uff0c\u8fd0\u884c\u5931\u8d25\uff0c\u5c06\u53d1\u9001\u90ae\u4ef6 +confirmRunTest=\u786e\u8ba4\u8fd0\u884c\u6d4b\u8bd5 +confirm.runAll=\u786e\u8ba4\u5bf9\u6240\u6709\u63d0\u4f9b\u8005\u8fd0\u884c\u6d4b\u8bd5 +# +#anonymous=\u533f\u540d +#Unuse=\u672a\u4f7f\u7528 +#RouteName=\u8def\u7531\u540d +#Priority=\u4f18\u5148\u7ea7 +#MatchRule=\u5339\u914d\u6761\u4ef6 +#ConsumerHost=\u6d88\u8d39\u8005IP\u5730\u5740 +#ConsumerCluster=\u6d88\u8d39\u8005\u96c6\u7fa4 +#FilterRule=\u8fc7\u6ee4\u89c4\u5219 +#ProviderHost=\u63d0\u4f9b\u8005IP\u5730\u5740 +#ProviderCluster=\u63d0\u4f9b\u8005\u96c6\u7fa4 +#ProviderProtocol=\u63d0\u4f9b\u8005\u534f\u8bae +#ProviderPort=\u63d0\u4f9b\u8005\u7aef\u53e3 +#Match=\u5339\u914d +#Mismatch=\u4e0d\u5339\u914d +#ConsumerAddress=\u6d88\u8d39\u8005\u5730\u5740 +generic=\u6cdb\u5316 +doubling=\u500d\u6743 +loadBalanceStrategy=\u8d1f\u8f7d\u5747\u8861\u7b56\u7565 +random=\u968f\u673a +roundrobin=\u8f6e\u8be2 +leastactive=\u6700\u5c11\u5e76\u53d1 +testName=\u6d4b\u8bd5\u7528\u4f8b\u540d\u79f0 +operator=\u64cd\u4f5c +dataFormat=\u6570\u636e\u683c\u5f0f +resultType=\u7ed3\u679c\u7c7b\u578b +resultController=\u8fd4\u56de\u503c/\u5f02\u5e38\u7c7b\u578b +autoRun=\u81ea\u52a8\u8fd0\u884c +manualRun=\u624b\u52a8\u8fd0\u884c +run=\u8fd0\u884c +runAll=\u8fd0\u884c\u6240\u6709\u63d0\u4f9b\u8005 +expected=\u671f\u671b\u7ed3\u679c +actual=\u5b9e\u9645\u7ed3\u679c +reRun=\u91cd\u65b0\u8fd0\u884c +#Username=\u7528\u6237\u540d +#DisplayName=\u663e\u793a\u540d +#Department=\u90e8\u95e8 +#Email=\u90ae\u7bb1 +#Phone=\u624b\u673a +#Alitalk=\u65fa\u65fa +startDate=\u542f\u52a8\u65f6\u95f4 +console=\u63a7\u5236\u53f0 +total=\u603b\u6570 +delta=\u504f\u5dee +expired=\u8fc7\u671f +alived=\u5b58\u6d3b +redirect=\u91cd\u5b9a\u5411 +current=\u5f53\u524d +#overrides +override.config=\u52a8\u6001\u914d\u7f6e +override.mock=\u670d\u52a1\u964d\u7ea7 +parameter=\u53c2\u6570 +parameter.key=\u53c2\u6570\u540d +parameter.value=\u53c2\u6570\u503c +parameter.tip=\u65b9\u6cd5\u7ea7\u914d\u7f6e\u5982\uff1afindPerson.timeout=1000 +mock.all.method=\u6240\u6709\u65b9\u6cd5\u7684Mock\u503c +mock.method=\u65b9\u6cd5 +mock.value=\u7684Mock\u503c +mock.tip=\u793a\u4f8b\uff1areturn null/empty/JSON\u6216throw com.foo.BarException +protocol=\u534F\u8BAE +host=\u4E3B\u673A\u540D +port=\u7AEF\u53E3 +interface=\u63A5\u53E3\u540D +version=\u7248\u672C +group=\u5206\u7EC4 +methods=\u65B9\u6CD5\u5217\u8868 +category=\u6570\u636E\u7C7B\u578B +application=\u5E94\u7528\u540D +owner=\u8D1F\u8D23\u4EBA +cluster=\u96C6\u7FA4 +loadbalance=\u8D1F\u8F7D\u5747\u8861 +timeout=\u8D85\u65F6 +retries=\u91CD\u8BD5\u6B21\u6570 +threads=\u7EBF\u7A0B\u6570 +connections=\u8FDE\u63A5\u6570 +accepts=\u63A5\u6536\u8FDE\u63A5\u6570 +actives=\u5BA2\u6237\u7AEF\u5E76\u53D1\u8BF7\u6C42\u9650\u5236 +executes=\u7EBF\u7A0B\u6C60\u5E76\u53D1\u6267\u884C\u9650\u5236 +check=\u68C0\u67E5 +side=\u6240\u5C5E\u7AEF +pid=\u8FDB\u7A0B\u53F7 +timestamp=\u65F6\u95F4\u6233 +dubbo=Dubbo\u7248\u672C +anyhost=\u7ED1\u5B9A\u6240\u6709IP +weight=\u6743\u91CD +weight.doubling=\u500D\u6743 +weight.halving=\u534A\u6743 +confirm.weight.doubling=\u786E\u8BA4\u6743\u91CD\u52A0\u500D? +confirm.weight.halving=\u786E\u8BA4\u6743\u91CD\u51CF\u534A? +batch.weight.doubling=\u6279\u91CF\u500D\u6743 +batch.weight.halving=\u6279\u91CF\u534A\u6743 +confirm.batch.weight.doubling=\u786E\u8BA4\u6240\u9009\u9879\u6743\u91CD\u52A0\u500D? +confirm.batch.weight.halving=\u786E\u8BA4\u6240\u9009\u9879\u6743\u91CD\u51CF\u534A? +NoSuchOperationData=\u64CD\u4F5C\u7684\u6570\u636E\u4E0D\u5B58\u5728\u3002 +CanNotDeleteDynamicData=\u4E0D\u80FD\u5220\u9664\u52A8\u6001\u6570\u636E\u3002 +HaveNoServicePrivilege=\u60A8\u6CA1\u6709\u8BE5\u670D\u52A1\u7684\u6743\u9650\u3002 +dynamic.parameters.tip=\u52A8\u6001URL\u4E0D\u80FD\u76F4\u63A5\u4FEE\u6539\uFF0C\u9700\u901A\u8FC7\u52A8\u6001\u914D\u7F6E\u8FDB\u884C\u8986\u76D6\uFF0C\u683C\u5F0F\u4E0EURL\u53C2\u6570\u76F8\u540C\u3002 +default.owner=\u8d1f\u8d23\u4eba +logger=\u65e5\u5fd7 +default.server=\u9ed8\u8ba4\u670d\u52a1\u7aef +default.actives=\u5e76\u53d1\u8c03\u7528\u6570 +default.client=\u9ed8\u8ba4\u5ba2\u6237\u7aef +default.connections=\u6700\u5927\u8fde\u63a5\u6570 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_zh_TW.properties b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_zh_TW.properties new file mode 100644 index 0000000..56ae82e --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/i18n/message_zh_TW.properties @@ -0,0 +1,726 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +#menus +home=\u9996\u9801 +about=\u95dc\u65bc +help=\u5e6b\u52a9 +revision=\u4fee\u8a02 +favorites=\u6211\u7684\u6700\u611b +histories=\u6b77\u53f2\u8a18\u9304 +governance=\u670d\u52d9\u6cbb\u7406 +applications=\u61c9\u7528 +efferents=\u4f9d\u8cf4 +afferents=\u88ab\u4f9d\u8cf4 +services=\u670d\u52d9 +references=\u5f15\u7528\u670d\u52d9 +addresses=\u6a5f\u5668 +providers=\u63d0\u4f9b\u8005 +dependencies=\u4f9d\u8cf4\u95dc\u4fc2 +layers=\u5206\u5c64 +clusters=\u96c6\u7fa4 +consumers=\u6d88\u8cbb\u8005 +accesses=\u9ed1\u767d\u540d\u55ae +routes=\u8def\u7531 +weights=\u6b0a\u91cd +InvalidIP=\u7121\u6548\u0069\u0070\u5730\u5740 +loadbalances=\u8ca0\u8f09\u5747\u8861 +tests=\u6e2c\u8a66 +mocks=\u6a21\u64ec +overrides=\u52d5\u614b\u914d\u7f6e +documents=\u6587\u6a94 +owners=\u8ca0\u8cac\u4eba +agreements=\u5354\u5b9a +approvals=\u4e0a\u7dda\u5be9\u6279 +operations=\u64cd\u4f5c\u65e5\u8a8c +users=\u7528\u6236 +envs=\u7cfb\u7d71\u74b0\u5883 +helps=\u5e6b\u52a9\u6587\u6a94 +registries=\u8a3b\u518a\u4e2d\u5fc3 +configs=\u7cfb\u7d71\u53c3\u6578 +features=\u7cfb\u7d71\u529f\u80fd +connections=\u9023\u63a5 +statuses=\u72c0\u614b\u6e05\u55ae +failed=\u5931\u6557\u8a18\u9304 +cached=\u7de9\u5b58\u8a18\u9304 +dumps=\u5feb\u7167 +default.lazy=\u9ed8\u8a8d\u61f6\u555f\u52d5 +versions=Dubbo\u7248\u672c +service.filter=\u670d\u52d9filter +default.service.filter=\u9ed8\u8a8d\u670d\u52d9filter +logs=\u65e5\u8a8c +infos=\u4fee\u6539\u500b\u4eba\u8cc7\u8a0a +passwds=\u4fee\u6539\u500b\u4eba\u5bc6\u78bc +dependency.list=\u5217\u8868 +dependency.tree=\u6a39\u72c0 +dependency.graph=\u5716\u5f62 +dependency.efferent=\u4f9d\u8cf4 +dependency.afferent=\u88ab\u4f9d\u8cf4 +provided=\u63d0\u4f9b\u670d\u52d9 +consumed=\u6d88\u8cbb\u670d\u52d9 +select=\u9078\u64c7 +clean=\u6e05\u9664 +information=\u4fe1\u606f +control=\u63a7\u5236 +summary=\u532f\u7e3d +consumer.application=\u6d88\u8cbb\u8005\u61c9\u7528 +response.time=\u56de\u61c9\u6642\u9593 +sysinfo.infos=\u7cfb\u7d71\u8cc7\u8a0a +helps.document=\u6587\u6a94 +helps.requirement=\u9700\u6c42 +helps.source=\u539f\u59cb\u7a0b\u5f0f\u78bc +connections=\u901a\u8a0a\u7aef\u9023\u63a5 +ReconnectUnkwown=\u91cd\u9023\u6240\u6709\u672a\u77e5\u9023\u63a5 +confirmReconnectConnection=\u78ba\u8a8d\u91cd\u5efa\u9023\u63a5 +confirmRedirectRegistry=\u78ba\u8a8d\u91cd\u5b9a\u5411\u8a3b\u518a\u4e2d\u5fc3 +confirmReconnectUnknownConnection=\u78ba\u8a8d\u91cd\u9023\u672a\u77e5\u7684\u9023\u63a5 +status.resourcename=\u8cc7\u6e90\u540d\u7a31 +status.status=\u72c0\u614b +status.message=\u4fe1\u606f +status.description=\u63cf\u8ff0 +status.memoryStatus=\u8a18\u61b6\u9ad4 +status.memoryStatusDesc=\u53ea\u76e3\u63a7Heap\u8a18\u61b6\u9ad4\uff0c\u5982\u679c\u7a7a\u9592\u8a18\u61b6\u9ad4\u4e0d\u8db31M\u5247\u8b66\u544a\uff0c\u5426\u5247\u6b63\u5e38 +status.threadpoolStatus=\u57f7\u884c\u7dd2\u6c60 +status.threadpoolStatusDesc=\u53ea\u76e3\u63a7\u8a3b\u518a\u8a02\u95b1\u4e3b\u696d\u52d9\u57f7\u884c\u7dd2\u6c60\uff0c\u5982\u679c\u7a7a\u9592\u57f7\u884c\u7dd2\u5c11\u65bc1\u500b\uff0c\u5247\u8b66\u544a\uff0c\u5426\u5247\u6b63\u5e38 +status.failureStatus=\u5931\u6557\u8a18\u9304 +status.failureStatusDesc=\u7576\u6709\u4efb\u4f55\u5931\u6557\u8a18\u9304\u5247\u8b66\u544a\uff0c\u5426\u5247\u6b63\u5e38 +status.cacheStatus=\u7de9\u5b58 +status.cacheStatusDesc=\u5982\u679c\u7de9\u5b58\u8207\u8cc7\u6599\u5eab\u4e0d\u4e00\u81f4\u5247\u8b66\u544a\uff0c\u5426\u5247\u6b63\u5e38 +status.timerStatus=\u8a08\u6642\u5668 +status.timerStatusDesc=\u7576\u8a08\u6642\u5668\u672a\u6b63\u78ba\u555f\u52d5\uff0c\u6216\u88ab\u4e0d\u6b63\u5e38\u53d6\u6d88\uff0c\u5247\u5831\u932f\uff0c\u5426\u5247\u6b63\u5e38 +status.socketStatus=\u901a\u8a0a\u7aef +status.socketStatusDesc=\u7576\u5957\u4ecb\u9762\u958b\u555f\u4e0d\u4e86\u6216\u5df2\u88ab\u4f54\u7528\u6642\u5831\u932f\uff0c\u7576\u9023\u63a5\u6578\u7b49\u65bc\u6700\u5927\u503c\u6642\u8b66\u544a\uff0c\u5426\u5247\u6b63\u5e38 +status.loadStatus=\u8ca0\u8f09 +status.loadStatusDesc=\u5982\u679c\u8ca0\u8f09\u5927\u65bcCPU\u500b\u6578\u5247\u8b66\u544a\uff0c\u5982\u679c\u7cfb\u7d71\u4e0d\u652f\u63f4\u67e5\u8a62\u8ca0\u8f09\u5247\u4e0d\u555f\u7528\uff0c\u5426\u5247\u6b63\u5e38 +status.databaseStatus=\u8cc7\u6599\u5eab +status.databaseStatusDesc=\u767c\u9001\u4e00\u689d\u7c21\u55ae\u67e5\u8a62SQL\uff0c\u57f7\u884c\u6210\u529f\u5247\u6b63\u5e38\uff0c\u5426\u5247\u5831\u932f +status.threadPool=\u9032\u7a0b\u57f7\u884c\u7dd2 +status.threadPoolStatusDesc=\u76e3\u63a7\u9032\u7a0b\u7684\u57f7\u884c\u7dd2\u6c60 +status.monitorStatus=\u76e3\u8996\u5668 +status.monitorStatusDesc=\u76e3\u8996\u5668 +status.summaryStatus=\u532f\u7e3d +status.summaryStatusDesc=\u6709\u72c0\u614b\u532f\u7e3d\uff0c\u5ffd\u7565\u672a\u555f\u7528\u7684\u72c0\u614b\uff0c\u53ea\u8981\u6709\u4e00\u500b\u5831\u932f\uff0c\u5247\u5831\u932f\uff0c\u53ea\u8981\u6709\u4e00\u500b\u8b66\u544a\uff0c\u5247\u8b66\u544a\uff0c\u5168\u90e8\u6b63\u5e38\u5247\u6b63\u5e38 +status.warmupStatus=\u904b\u884c\u72c0\u614b +status.warmupStatusDesc=\u8655\u65bcwarmup\u72c0\u614b\u6642\uff0c\u9ad2\u8cc7\u6599\u6aa2\u6e2c\u3001\u91cd\u5b9a\u5411\u3001\u4e8b\u4ef6\u8b8a\u66f4\u8a08\u6642\u5668\u5747\u4e0d\u5de5\u4f5c,\u4e0d\u63a8\u9001\u8b8a\u66f4 +status.OK=\u6b63\u5e38 +status.WARN=\u8b66\u544a +status.ERROR=\u932f\u8aa4 +status.UNKNOWN=\u672a\u77e5 +Status0=Unknow +Status1=OK +Status2=OK +Status3=ERROR +Status4=FATAL +Status5=UNKNOW +mock=\u964d\u7d1a +force.mock=\u906e\u7f69 +fail.mock=\u5bb9\u932f +cancel.mock=\u6062\u5fa9 +confirm.force.mock=\u78ba\u8a8d\u906e\u7f69\u8a72\u670d\u52d9\u7684\u8abf\u7528\uff1f
\u5c07\u4e0d\u767c\u8d77\u9060\u7aef\u8abf\u7528\uff0c\u76f4\u63a5\u8fd4\u56de\u7a7a\u7269\u4ef6\u3002(\u53ef\u5728\u52d5\u614b\u914d\u7f6e\u9801\u9762\u4fee\u6539\u8fd4\u56de\u8cc7\u6599) +confirm.fail.mock=\u78ba\u8a8d\u5c0d\u8a72\u670d\u52d9\u5bb9\u932f\uff1f
\u7576\u8abf\u7528\u5931\u6557\u6642\uff0c\u8fd4\u56de\u7a7a\u7269\u4ef6\u3002(\u53ef\u5728\u52d5\u614b\u914d\u7f6e\u9801\u9762\u4fee\u6539\u8fd4\u56de\u8cc7\u6599) +confirm.cancel.mock=\u78ba\u8a8d\u6062\u5fa9\u8a72\u670d\u52d9\u6b63\u5e38\u8a2a\u554f\uff1f
\u5c07\u53d6\u6d88\u670d\u52d9\u7684\u906e\u7f69\u548c\u5bb9\u932f\u884c\u70ba\u3002 +batch.force.mock=\u6279\u91cf\u906e\u7f69 +batch.fail.mock=\u6279\u91cf\u5bb9\u932f +batch.cancel.mock=\u6279\u91cf\u6062\u5fa9 +confirm.batch.force.mock=\u78ba\u8a8d\u6279\u91cf\u906e\u7f69\u670d\u52d9\u7684\u8abf\u7528\uff1f
\u5c07\u4e0d\u767c\u8d77\u9060\u7aef\u8abf\u7528\uff0c\u76f4\u63a5\u8fd4\u56de\u7a7a\u7269\u4ef6\u3002(\u53ef\u5728\u52d5\u614b\u914d\u7f6e\u9801\u9762\u4fee\u6539\u8fd4\u56de\u8cc7\u6599) +confirm.batch.fail.mock=\u78ba\u8a8d\u6279\u91cf\u5c0d\u670d\u52d9\u5bb9\u932f\uff1f
\u7576\u8abf\u7528\u5931\u6557\u6642\uff0c\u8fd4\u56de\u7a7a\u7269\u4ef6\u3002(\u53ef\u5728\u52d5\u614b\u914d\u7f6e\u9801\u9762\u4fee\u6539\u8fd4\u56de\u8cc7\u6599) +confirm.batch.cancel.mock=\u78ba\u8a8d\u6279\u91cf\u6062\u5fa9\u670d\u52d9\u6b63\u5e38\u8a2a\u554f\uff1f
\u5c07\u53d6\u6d88\u670d\u52d9\u7684\u906e\u7f69\u548c\u5bb9\u932f\u884c\u70ba\u3002 +agreement.invocation.quantity=\u4e00\u5929\u8abf\u7528\u91cf +agreement.tps=TPS\u4e0a\u9650 +response.time=\u56de\u61c9\u6642\u9593 +agreement.availability=\u53ef\u7528\u7387 +layer.name=\u5206\u5c64\u540d\u7a31 +layer.value=\u6578\u4f4d\u7b49\u7d1a +layer.arch=\u5206\u5c64\u67b6\u69cb +loadBalanceStrategy=\u8ca0\u8f09\u5747\u8861\u7b56\u7565 +ServiceName=\u670d\u52d9\u540d +cluster.name=\u96c6\u7fa4\u540d +cluster.address=\u96c6\u7fa4\u6a5f\u5668\u5730\u5740 +property.name=\u5c6c\u6027\u540d +property.value=\u5c6c\u6027\u503c +property.count=\u5c6c\u6027\u6578\u91cf +getMethods=\u7372\u53d6\u670d\u52d9\u65b9\u6cd5 +getAddresses=\u7372\u53d6\u63d0\u4f9b\u8005\u5730\u5740 +Edit=\u7de8\u8f2f +Username=\u7528\u6236\u540d +Priority=\u512a\u5148\u9806\u5e8f +ConnectionAddress=\u9023\u63a5\u4f4d\u5740 +Role=\u89d2\u8272 +Reconnect=\u91cd\u9023 +Redirect=\u91cd\u5b9a\u5411 +staff.query=\u5167\u7db2\u67e5\u8a62 +configKey=\u914d\u7f6e\u9805 +configValue=\u914d\u7f6e\u9805\u503c +Preview=\u9810\u89bd +routeselect=\u8def\u7531\u9810\u89bd\uff08\u9078\u64c7\u6d88\u8cbb\u8005\uff09 +AllOperations=\u6240\u6709\u64cd\u4f5c\u8a18\u9304 +BeforeOneMonthOperations=\u4e00\u500b\u6708\u4ee5\u524d\u7684\u6240\u6709\u64cd\u4f5c\u8a18\u9304 +BeforeThreeMonthOperations=\u4e09\u500b\u6708\u4ee5\u524d\u7684\u6240\u6709\u64cd\u4f5c\u8a18\u9304 +BeforeHalfYearOperations=\u534a\u5e74\u4ee5\u524d\u7684\u6240\u6709\u64cd\u4f5c\u8a18\u9304 +BeforeOneYearOperations=\u4e00\u5e74\u4ee5\u524d\u7684\u6240\u6709\u64cd\u4f5c\u8a18\u9304 +PleaseInput=\u8acb\u8f38\u5165 +BulletinConfig=\u516c\u544a\u914d\u7f6e +BulletinMessage=\u516c\u544a\u8cc7\u8a0a +MailConfig=\u90f5\u7bb1\u914d\u7f6e +MailEnabled=\u662f\u5426\u555f\u7528\u90f5\u7bb1 +MailHost=\u90f5\u4ef6\u4f3a\u670d\u5668\u4e3b\u6a5f +MailPort=\u90f5\u4ef6\u4f3a\u670d\u5668\u57e0 +MailFrom=\u90f5\u4ef6\u5bc4\u4ef6\u8005\u5730\u5740 +MailAuth=\u90f5\u7bb1\u662f\u5426\u9700\u8981\u767b\u9304 +MailUsername=\u90f5\u7bb1\u767b\u9304\u7528\u6236\u540d +MailPassword=\u90f5\u7bb1\u767b\u9304\u5bc6\u78bc +LoginConfig=\u767b\u9304\u914d\u7f6e +AllowAnonymousLogin=\u5141\u8a31\u533f\u540d\u767b\u5165 +AllowLegacyLogin=\u5141\u8a31\u907a\u7559\u7cfb\u7d71\u767b\u9304 +RouteEnabled=\u662f\u5426\u958b\u555f\u8def\u7531\u529f\u80fd +WarmupEnabled=\u662f\u5426\u9032\u5165\u9810\u71b1\u72c0\u614b +LogConfig=\u65e5\u8a8c\u914d\u7f6e +LogLevel=\u65e5\u8a8c\u7d1a\u5225 +RedirectConfig=\u91cd\u5b9a\u5411\u914d\u7f6e +AutoRedirectInterval=\u81ea\u52d5\u91cd\u5b9a\u5411\u6aa2\u67e5\u9593\u9694(\u6beb\u79d2) +AutoRedirectThreshold=\u80fd\u5920\u81ea\u52d5\u91cd\u5b9a\u5411\u7684\u9023\u63a5\u4e0b\u754c +AutoRedirectToleratePercent=\u81ea\u52d5\u91cd\u5b9a\u5411\u6642\u9023\u63a5\u6578\u504f\u5dee\u5bb9\u5fcd\u767e\u5206\u6bd4 +ManualRedirect=\u91cd\u5b9a\u5411{0}\u500b +LimitConfig=\u8cc7\u6e90\u9650\u5236\u914d\u7f6e +MaxThreadSize=\u6700\u5927\u57f7\u884c\u7dd2\u6578 +MaxConnectionSize=\u6700\u5927\u9023\u63a5\u6578 +MaxCacheSize=\u6700\u5927\u7de9\u5b58\u6578 +MaxMailSize=\u6700\u5927\u90f5\u4ef6\u4f47\u5217\u6578 +TimerConfig=\u8a08\u6642\u5668\u914d\u7f6e +AlivedCheckInterval=\u8a3b\u518a\u4e2d\u5fc3\u5b58\u6d3b\u72c0\u614b\u6aa2\u67e5\u9593\u9694(\u6beb\u79d2) +ChangedCheckInterval=\u8cc7\u6599\u8b8a\u66f4\u6aa2\u67e5\u9593\u9694(\u6beb\u79d2) +FailedRetryInterval=\u5931\u6557\u91cd\u8a66\u9593\u9694(\u6beb\u79d2) +DirtyCheckInterval=\u9ad2\u8cc7\u6599\u6aa2\u67e5\u9593\u9694(\u6beb\u79d2) +HeartbeatConfig=\u5fc3\u8df3\u914d\u7f6e +HeartbeatCheckInterval=\u8207\u7528\u6236\u7aef\u9023\u63a5\u5fc3\u8df3\u6aa2\u67e5\u9593\u9694(\u6beb\u79d2) +HeartbeatCheckTimeout=\u5fc3\u8df3\u8d85\u6642\u6642\u9593(\u6beb\u79d2) +TimeoutConfig=\u8d85\u6642\u914d\u7f6e +NotifyTimeout=\u4e8b\u4ef6\u63a8\u9001\u8d85\u6642(\u6beb\u79d2) +WarmupWaitTime=\u555f\u52d5\u9810\u71b1\u6642\u9593(\u6beb\u79d2) +UrlConfig=URL\u914d\u7f6e +BucServiceAddress=BUC\u670d\u52d9\u4f4d\u5740 +HelpDocumentUrl=\u5e6b\u52a9\u6587\u6a94URL +HomepageDomain=\u986f\u793a\u4e3b\u9801\u529f\u80fd\u8b8a\u6578\u540d\u7a31 +HomepageUrl=\u4e3b\u9801\u5730\u5740 +parametersConfig=\u53c3\u6578\u914d\u7f6e +DefaultServiceParameters=\u7f3a\u7701\u53c3\u6578\u914d\u7f6e +BatchAddressTip=\u591a\u500b\u4f4d\u5740\u7528\u5206\u884c\u7b26\u865f\u5206\u9694\uff0c\u4f4d\u5740\u5fc5\u9700\u662f0.0.0.0\u5230255.255.255.255\u7684IP\u5730\u5740 +ConsumerAddress=\u6d88\u8cbb\u8005\u5730\u5740 +AccessControlTip=\u767d\u540d\u55ae\u512a\u5148\uff0c\u53ea\u8981\u6709\u767d\u540d\u55ae\uff0c\u5247\u767d\u540d\u55ae\u751f\u6548\uff0c\u5426\u5247\u9ed1\u540d\u55ae\u751f\u6548 +Allowed=\u767d\u540d\u55ae +Forbidden=\u9ed1\u540d\u55ae +Choose=\u8acb\u9078\u64c7 +userown=\u8ca0\u8cac\u7684\u670d\u52d9 +sysmanage.userown=\u8ca0\u8cac\u7684\u670d\u52d9 +SingleServiceTip=\u4e00\u500b\u8def\u7531\u53ea\u80fd\u61c9\u7528\u65bc\u4e00\u500b\u670d\u52d9\uff0c\u4e0d\u652f\u63f4\u591a\u670d\u52d9\u53ca\u842c\u7528\u5b57\u5143 +MultiServiceTip=\u670d\u52d9\u4ecb\u9762\u540d\u53ef\u4ee5\u4f7f\u7528\u842c\u7528\u5b57\u5143\uff0c\u53ea\u652f\u63f4\u4e00\u500b*\u7b26\u4e14\u8981\u5728\u4ecb\u9762\u672b\u5c3e\uff08\u5206\u7d44\u3001\u7248\u672c\u4e0d\u652f\u63f4\u842c\u7528\u5b57\u5143\uff09 +RouteNameTip=\u53ef\u4f7f\u7528\u4e2d\u6587\uff0c\u75311-200\u500b\u5b57\u5143\u7d44\u6210 +RoutePriorityTip=\u6578\u5b57\u8d8a\u5927\u8d8a\u512a\u5148 +RouteServiceTip=\u4e00\u500b\u8def\u7531\u53ea\u80fd\u61c9\u7528\u65bc\u4e00\u500b\u670d\u52d9\uff0c\u4e0d\u652f\u63f4\u591a\u670d\u52d9\u53ca\u842c\u7528\u5b57\u5143 +#RouteServiceTip=\u670d\u52d9\u4ecb\u9762\u540d\u53ef\u4ee5\u4f7f\u7528\u842c\u7528\u5b57\u5143\uff0c\u53ea\u652f\u63f4\u4e00\u500b*\u7b26\u4e14\u8981\u5728\u4ecb\u9762\u672b\u5c3e\uff08\u5206\u7d44\u3001\u7248\u672c\u4e0d\u652f\u63f4\u842c\u7528\u5b57\u5143\uff09 +RouteMethodTip=\u53ea\u6709Dubbo2.0.0\u4ee5\u4e0a\u7248\u672c\u7684\u670d\u52d9\u6d88\u8cbb\u7aef\u652f\u63f4\u6309\u65b9\u6cd5\u8def\u7531\uff0c\u591a\u500b\u65b9\u6cd5\u540d\u7528\u9017\u865f\u5206\u9694 +RouteClusterTip=\u53ef\u901a\u904e\u529f\u80fd\u8868"\u670d\u52d9\u63a7\u5236"->"\u4f3a\u670d\u5668\u96c6\u7fa4"\u7ba1\u7406 +RouteMatchTip=\u7576\u6d88\u8cbb\u8005\u6eff\u8db3\u5339\u914d\u689d\u4ef6\u6642\u4f7f\u7528\u7576\u524d\u898f\u5247\u9032\u884c\u904e\u6ffe +RouteFilterTip=\u6eff\u8db3\u904e\u6ffe\u898f\u5247\u7684\u63d0\u4f9b\u8005\u4f4d\u5740\u5c07\u88ab\u63a8\u9001\u7d66\u6d88\u8cbb\u8005 +RouteHostTip=\u591a\u500b\u503c\u7528\u9017\u865f\u5206\u9694\uff0c\u4ee5\u661f\u865f\u7d50\u5c3e\u8868\u793a\u901a\u914d\u4f4d\u5740\u6bb5 +RouteApplicationTip=\u591a\u500b\u503c\u7528\u9017\u865f\u5206\u9694 +RouteResult=\u8def\u7531\u7d50\u679c +preview=\u9810\u89bd +ConsumerApplication=\u6d88\u8cbb\u8005\u61c9\u7528\u540d +ConsumerCluster=\u6d88\u8cbb\u8005\u96c6\u7fa4 +ConsumerHost=\u6d88\u8cbb\u8005IP\u5730\u5740 +ConsumerVersion=\u6d88\u8cbb\u8005\u7248\u672c\u865f +ConsumerGroup=\u6d88\u8cbb\u8005\u540d\u7a31\u7a7a\u9593 +ProviderApplication=\u63d0\u4f9b\u8005\u61c9\u7528 +ProviderCluster=\u63d0\u4f9b\u8005\u96c6\u7fa4 +ProviderProtocol=\u63d0\u4f9b\u8005\u5354\u5b9a +ProviderHost=\u63d0\u4f9b\u8005IP\u5730\u5740 +ProviderPort=\u63d0\u4f9b\u8005\u57e0 +ProviderVersion=\u63d0\u4f9b\u8005\u7248\u672c\u865f +ProviderGroup=\u63d0\u4f9b\u8005\u540d\u7a31\u7a7a\u9593 +MatchRule=\u5339\u914d\u689d\u4ef6 +FilterRule=\u904e\u6ffe\u898f\u5247 +routeRule=\u8def\u7531\u898f\u5247 +Match=\u5339\u914d +Mismatch=\u4e0d\u5339\u914d +GetMethods=\u7372\u53d6\u670d\u52d9\u65b9\u6cd5 +FeatureName=\u529f\u80fd\u540d +Features=\u7cfb\u7d71\u529f\u80fd +Disable=\u7981\u7528 +Enable=\u555f\u7528 +Enabled=\u5df2\u555f\u7528 +Disabled=\u5df2\u7981\u7528 +Unknown=\u672a\u77e5 +Users=\u7528\u6236\u7ba1\u7406 +UsersDescription=\u4f7f\u7528\u8005\u8cc7\u8a0a\u7ba1\u7406 +StatusList=\u8a3b\u518a\u4e2d\u5fc3\u72c0\u614b +StatusListDescription=\u8a3b\u518a\u4e2d\u5fc3\u7cfb\u7d71\u72c0\u614b +Operations=\u64cd\u4f5c\u8a18\u9304 +OperationsDescription=\u8a18\u9304\u6240\u6709\u4eba\u70ba\u7684\u64cd\u4f5c +Accesses=\u670d\u52d9\u9ed1\u767d\u540d\u55ae +AccessesDescription=\u670d\u52d9\u9ed1\u767d\u540d\u55ae +Configs=\u7cfb\u7d71\u7d44\u614b +Clusters=\u4f3a\u670d\u5668\u96c6\u7fa4 +ClustersDescription=\u7ba1\u7406\u670d\u52d9\u96c6\u7fa4\u8cc7\u8a0a +Weights=\u63d0\u4f9b\u8005\u6b0a\u91cd +WeightsDescription=\u7ba1\u7406\u63d0\u4f9b\u8005\u6b0a\u91cd\u8cc7\u8a0a +Agreements=\u670d\u52d9\u7b49\u7d1a\u5354\u5b9a +AgreementsDescription=\u670d\u52d9\u7b49\u7d1a\u5354\u5b9a +ConfigsDescription=\u7cfb\u7d71\u7d44\u614b\u4fe1\u606f +LoadBalances=\u8ca0\u8f09\u5747\u8861 +LoadBalancesDescription=\u8ca0\u8f09\u5747\u8861 +CachedList=\u8a18\u61b6\u9ad4\u7de9\u5b58 +CachedListDescription=\u8a3b\u518a\u4e2d\u5fc3\u8a18\u61b6\u9ad4\u7de9\u5b58\u8a18\u9304 +FailedList=\u5931\u6557\u8a18\u9304 +Registries=\u8a3b\u518a\u4e2d\u5fc3\u96c6\u7fa4 +FailedListDescription=\u5931\u6557\u8a18\u9304\u6e05\u55ae +registryAddress=\u8a3b\u518a\u4e2d\u5fc3\u5217\u8868 +RegistriesDescription=\u67e5\u770b\u5df2\u77e5\u7684\u8a3b\u518a\u4e2d\u5fc3 +Help=\u5e6b\u52a9 +HelpDescription=\u5e6b\u52a9 +Providers=\u670d\u52d9\u63d0\u4f9b\u8005 +ProvidersDescription=\u67e5\u770b\u6240\u6709\u670d\u52d9\u63d0\u4f9b\u8005 +Log=\u65e5\u8a8c\u6a94 +LogDescription=\u67e5\u770b\u8a3b\u518a\u4e2d\u5fc3Log4J\u65e5\u8a8c +Services=\u670d\u52d9\u8cc7\u8a0a +ServicesDescription=\u67e5\u770b\u670d\u52d9\u5df2\u8a3b\u518a\u7684\u6240\u6709\u670d\u52d9 +Owned=\u670d\u52d9\u6b78\u5c6c +OwnedDescription=\u670d\u52d9\u6b78\u5c6c +Tests=\u670d\u52d9\u6e2c\u8a66 +TestsDescription=\u670d\u52d9\u6e2c\u8a66\u7528\u4f8b +Documents=\u670d\u52d9\u6587\u6a94 +DocumentsDescription=\u6587\u6a94 +Applications=\u670d\u52d9\u61c9\u7528 +ApplicationsDescription=\u670d\u52d9\u61c9\u7528 +Consumers=\u670d\u52d9\u6d88\u8cbb\u8005 +ConsumersDescription=\u67e5\u770b\u6240\u6709\u670d\u52d9\u6d88\u8cbb\u8005 +System=\u7cfb\u7d71\u74b0\u5883 +SystemDescription=\u7cfb\u7d71\u74b0\u5883\u8cc7\u8a0a +Routes=\u670d\u52d9\u8def\u7531 +Route=\u8def\u7531 +RoutesDescription=\u7ba1\u7406\u670d\u52d9\u8def\u7531\u898f\u5247 +Connections=\u901a\u8a0a\u7aef\u9023\u63a5 +ConnectionsDescription=\u9023\u63a5 +RegistryAddress=\u8a3b\u518a\u4e2d\u5fc3\u5730\u5740 +RegisterUsername=\u8a3b\u518a\u7528\u6236\u540d +RegisterDate=\u8a3b\u518a\u6642\u9593 +subscribeDate=\u8a02\u95b1\u6642\u9593 +Statistics=\u670d\u52d9\u5373\u6642\u7d71\u8a08 +CheckConnection=\u6aa2\u67e5\u9023\u63a5 +CheckDatabase=\u6aa2\u67e5\u8cc7\u6599\u5eab +queryUrl=\u8a02\u95b1\u53c3\u6578 +Status=\u72c0\u614b +notified=\u5df2\u901a\u77e5 +Unuse=\u672a\u4f7f\u7528 +NoProvider=\u6c92\u6709\u63d0\u4f9b\u8005 +NoConsumer=\u6c92\u6709\u6d88\u8cbb\u8005 +route.consumer.not.match=\u672cRoute\u4e0d\u5339\u914d\u6b64\u670d\u52d9\u6d88\u8cbb\u8005\uff08\u6703\u8fd4\u56de\u6240\u6709\u7684\u670d\u52d9\u63d0\u4f9b\u8005\uff09 +#labels +all=\u6240\u6709 +service=\u670d\u52d9\u540d +application=\u61c9\u7528\u540d +recursive=\u8ff4\u5708 +layer=\u670d\u52d9\u5206\u5c64 +address=\u6a5f\u5668IP +dubbo=\u4f7f\u7528dubbo\u7248\u672c +version=\u670d\u52d9\u7248\u672c +group=\u670d\u52d9\u5206\u7d44 +url=\u670d\u52d9\u4f4d\u5740 +parameters=\u670d\u52d9\u53c3\u6578 +provider=\u63d0\u4f9b\u8005\u5730\u5740 +consumer=\u6d88\u8cbb\u8005\u5730\u5740 +registry=\u8a3b\u518a\u4e2d\u5fc3\u5730\u5740 +username=\u7528\u6236\u540d +created=\u5275\u5efa\u6642\u9593 +modified=\u4fee\u6539\u6642\u9593 +register.date=\u8a3b\u518a\u6642\u9593 +type=\u985e\u578b +static=\u975c\u614b +dynamic=\u52d5\u614b +status=\u72c0\u614b +enabled=\u5df2\u555f\u7528 +disabled=\u5df2\u7981\u7528 +check=\u6aa2\u67e5 +operation=\u64cd\u4f5c +role=\u89d2\u8272 +provider=\u63d0\u4f9b\u8005 +consumer=\u6d88\u8cbb\u8005 +no.provider=\u6c92\u6709\u63d0\u4f9b\u8005 +no.consumer=\u6c92\u6709\u6d88\u8cbb\u8005 +ok=\u6b63\u5e38 +warn=\u8b66\u544a +error=\u51fa\u932f +success=\u6210\u529f +failure=\u5931\u6557 +operation.success=\u64cd\u4f5c\u6210\u529f\uff01 +operation.failure=\u64cd\u4f5c\u5931\u6557\uff01 +isRegistered=\u8a3b\u518a\u7de9\u5b58 +isCached=\u670d\u52d9\u7de9\u5b58 +isCached.true=\u670d\u52d9\u5728\u7de9\u5b58\u4e2d +isCached.false=\u670d\u52d9\u672a\u540c\u6b65\u5230\u7de9\u5b58 +isSubscribed=\u8a02\u95b1\u7de9\u5b58 +isSubscribed.true=\u6b64\u6d88\u8cbb\u8005\u5728\u7576\u524d\u8a3b\u518a\u4e2d\u5fc3\u8a02\u95b1 +isSubscribed.false=\u6b64\u6d88\u8cbb\u8005\u5728\u5176\u4ed6\u8a3b\u518a\u4e2d\u5fc3\u8a02\u95b1 +isSubscribed.unmatch=\u6b64\u6d88\u8cbb\u8005\u5728\u8cc7\u6599\u5eab\u548c\u7de9\u5b58\u4e2d\u7684\u8a3b\u518a\u4e2d\u5fc3\u5730\u5740\u4e0d\u4e00\u81f4 +#operations +search=\u641c\u7d22 +search=\u641c\u7d22 +query=\u67e5\u8a62 +show=\u67e5\u770b +add=\u65b0\u589e +addMock=\u65b0\u589eMock +multiadd=\u6279\u91cf\u65b0\u589e +edit=\u7de8\u8f2f +save=\u4fdd\u5b58 +delete=\u522a\u9664 +enable=\u555f\u7528 +disable=\u7981\u7528 +recover=\u6062\u5fa9 +reload=\u91cd\u8f09\u7de9\u5b58 +reconnect=\u91cd\u9023 +renotify=\u91cd\u65b0\u901a\u77e5 +tostatic=\u8f49\u70ba\u975c\u614b +todynamic=\u8f49\u70ba\u52d5\u614b +favorite=\u6536\u85cf +register=\u7533\u8acb\u8a3b\u518a +subscribe=\u7533\u8acb\u8abf\u7528 +logout=\u9000\u51fa +back=\u8fd4\u56de +cancel=\u53d6\u6d88 +confirm=\u78ba\u5b9a +batch.add=\u6279\u91cf\u65b0\u589e +batch.multiservices.add=\u591a\u670d\u52d9\u65b0\u589e +batch.delete=\u6279\u91cf\u522a\u9664 +batch.enable=\u6279\u91cf\u555f\u7528 +batch.disable=\u6279\u91cf\u7981\u7528 +batch.recover=\u6279\u91cf\u6062\u5fa9 +batch.reconnect=\u6279\u91cf\u91cd\u9023 +batch.renotify=\u6279\u91cf\u91cd\u65b0\u901a\u77e5 +batch.tostatic=\u6279\u91cf\u975c\u614b +batch.todynamic=\u6279\u91cf\u52d5\u614b +batch.favorite=\u6279\u91cf\u6536\u85cf +batch.reload=\u6279\u91cf\u91cd\u8f09 +confirm.batch.disable=\u78ba\u8a8d\u6279\u91cf\u7981\u7528 +confirm.batch.enable=\u78ba\u8a8d\u6279\u91cf\u555f\u7528 +#prompts +please.input.service=\u8acb\u8f38\u5165\u670d\u52d9\u540d +please.input.application=\u8acb\u8f38\u5165\u61c9\u7528\u540d +please.input.address=\u8acb\u8f38\u5165\u6a5f\u5668IP +please.input.layer=\u8acb\u8f38\u5165\u670d\u52d9\u5206\u5c64 +please.input=\u8acb\u8f38\u5165\u8981\u64cd\u4f5c\u7684\u5167\u5bb9 +please.select=\u8acb\u9078\u64c7\u8981\u64cd\u4f5c\u7684\u9805 +empty.list=\u6c92\u6709\u8cc7\u6599\u53ef\u4ee5\u64cd\u4f5c +not.found=\u6c92\u6709\u641c\u5230\u5339\u914d\u7684\u7d50\u679c +show.all=\u986f\u793a\u5168\u90e8 +confirm.logout=\u78ba\u5b9a\u9000\u51fa\u767b\u9304? +confirm.delete=\u78ba\u5b9a\u522a\u9664? +confirm.enable=\u78ba\u5b9a\u555f\u7528? +confirm.disable=\u78ba\u5b9a\u7981\u7528? +confirm.recover=\u78ba\u5b9a\u6062\u5fa9 +confirm.reconnect=\u78ba\u5b9a\u91cd\u9023? +confirm.renotify=\u78ba\u5b9a\u901a\u77e5? +confirm.tostatic=\u78ba\u5b9a\u8f49\u70ba\u975c\u614b? +confirm.todynamic=\u78ba\u5b9a\u8f49\u70ba\u52d5\u614b? +confirm.batch.delete=\u78ba\u5b9a\u522a\u9664\u6240\u9078\u9805? +confirm.batch.enable=\u78ba\u5b9a\u555f\u7528\u6240\u9078\u9805? +confirm.batch.disable=\u78ba\u5b9a\u7981\u7528\u6240\u9078\u9805? +confirm.batch.recover=\u78ba\u5b9a\u6062\u5fa9\u6240\u9078\u9805? +confirm.batch.reload=\u78ba\u5b9a\u91cd\u8f09\u7576\u524d\u670d\u52d9? +confirm.batch.reconnect=\u78ba\u5b9a\u91cd\u9023\u6240\u9078\u9805? +confirm.batch.renotify=\u78ba\u5b9a\u91cd\u65b0\u901a\u77e5\u6240\u9078\u9805? +confirm.batch.tostatic=\u78ba\u5b9a\u8f49\u70ba\u975c\u614b\u6240\u9078\u9805? +confirm.batch.todynamic=\u78ba\u5b9a\u8f49\u70ba\u52d5\u614b\u6240\u9078\u9805? +current.user=\u7576\u524d\u7528\u6236 +CheckProviderAddressMismatch=\u670d\u52d9URL\u4e0a\u7684IP\u8207\u9023\u63a5\u8a3b\u518a\u4e2d\u5fc3\u7684IP\u4e0d\u76f8\u540c +CheckProviderApplicationDifferent=\u591a\u500b\u4e0d\u540c\u61c9\u7528\u8a3b\u518a\u4e86\u76f8\u540c\u670d\u52d9\uff0c\u8acb\u6aa2\u67e5{0}\u4e2d\u662f\u5426\u6709\u8aa4\u66b4\u9732\u3002 +CheckConnectionDisconnected=\u8a72\u9023\u63a5\u5df2\u65b7\u958b\uff0c\u8cc7\u6599\u5eab\u9ad2\u8cc7\u6599\uff0c\u8acb\u9ede\u64ca\u201c\u91cd\u9023\u201d +CheckConnectionExpired=\u8a72\u9023\u63a5\u6240\u5728\u8a3b\u518a\u4e2d\u5fc3\u5df2\u4e0d\u5b58\u5728\uff08\u8cc7\u6599\u6703\u81ea\u52d5\u5b9a\u671f\u6e05\u7406\uff09 +CheckDatabaseMiss=\u8cc7\u6599\u5eab\u8cc7\u6599\u610f\u5916\u4e1f\u5931\u6b64\u8cc7\u6599\uff0c\u8acb\u9ede\u64ca\u201c\u6062\u5fa9\u201d +CheckDatabaseMismatch=\u8cc7\u6599\u5eab\u8207\u8a3b\u518a\u7de9\u5b58\u8cc7\u6599\u8a3b\u518a\u4f4d\u5740\u4e0d\u4e00\u81f4 +CheckDatabaseDirty2Registered=\u8cc7\u6599\u5eab\u6bd4\u8a3b\u518a\u7de9\u5b58\u591a\u6b64\u9ad2\u8cc7\u6599\uff0c\u8acb\u9ede\u64ca\u201c\u91cd\u9023\u201d +CheckDatabaseDirty2Subscribed=\u8cc7\u6599\u5eab\u6bd4\u8a02\u95b1\u7de9\u5b58\u591a\u6b64\u9ad2\u8cc7\u6599\uff0c\u8acb\u9ede\u64ca\u201c\u91cd\u9023\u201d +CheckCacheRegistered=\u8a3b\u518a\u7de9\u5b58\u4e0d\u5b58\u5728\uff0c\u8acb\u9ede\u64ca\u201c\u91cd\u9023\u201d +CheckCacheConsumer=\u7121\u6b64\u670d\u52d9\u7684\u670d\u52d9\u7de9\u5b58\uff0c\u4f46\u6709\u6d88\u8cbb\u8005\uff01\u8acb\u9ede\u64ca\u201c\u91cd\u8f09\u201d +CheckCacheProvider=\u670d\u52d9\u7de9\u5b58\u7121\u6b64\u63d0\u4f9b\u8005\uff0c\u8acb\u9ede\u64ca\u201c\u91cd\u8f09\u201d +CheckCacheSubscribed=\u8a02\u95b1\u7de9\u5b58\u4e0d\u5b58\u5728\uff0c\u8acb\u9ede\u64ca\u201c\u91cd\u9023\u201d +CheckCacheService=\u7121\u6b64\u670d\u52d9\u7684\u670d\u52d9\u7de9\u5b58\uff0c\u8acb\u9ede\u64ca\u63d0\u4f9b\u8005\u7684\u201c\u91cd\u8f09\u201d +select.all=\u5168\u9078 +ip.address=IP\u5730\u5740 +registry.newservice=\u8a3b\u518a\u65b0\u670d\u52d9 +add.new.provider=\u6dfb\u52a0\u63d0\u4f9b\u8005 +add.new.route=\u6dfb\u52a0\u8def\u7531 +message.search.noresult=\u6c92\u6709\u7b26\u5408\u7684\u67e5\u8a62\uff0c\u8acb\u5f9e\u63d0\u793a\u5217\u8868\u4e2d\u9078\u64c7\u67e5\u8a62\u6e96\u5247\uff01 +provide.service=\u63d0\u4f9b\u7684\u670d\u52d9 +service.method=\u670d\u52d9\u65b9\u6cd5 +startegy=\u7b56\u7565 +route.name=\u8def\u7531\u540d\u7a31 +rule.match=\u5339\u914d\u898f\u5247 +rule.filtrate=\u904e\u6ffe\u898f\u5247 +priority=\u512a\u5148\u9806\u5e8f +routed=\u5df2\u8def\u7531 +page.total=\u5171 +page.records=\u689d\u8a18\u9304 +page.ordinal=\u7b2c +page.page=\u9801 +page.next=\u4e0b\u4e00\u9801 +page.prev=\u4e0a\u4e00\u9801 +page.first=\u9996\u9801 +page.last=\u5c3e\u9801 +page.line=\u689d +methodName=\u65b9\u6cd5\u540d +proview=\u9810\u89bd +cluster.name=\u96c6\u7fa4\u540d +cluster.address=\u96c6\u7fa4\u6a5f\u5668\u5730\u5740 +sameserviceadd=\u540c\u670d\u52d9\u6dfb\u52a0 +whitelist=\u767d\u540d\u55ae +blacklist=\u9ed1\u540d\u55ae +toWhiteAndBlackList=\u8f49\u5165\u767d\u540d\u55ae/\u8f49\u5165\u9ed1\u540d\u55ae +obtainProviderAddress=\u7372\u53d6\u63d0\u4f9b\u8005\u5730\u5740 +towhitelist=\u52a0\u5165\u767d\u540d\u55ae +toblacklist=\u52a0\u5165\u9ed1\u540d\u55ae +enable=\u555f\u7528 +disable=\u7981\u7528 +copy=\u8907\u88fd +batch.enable=\u6279\u91cf\u555f\u7528 +batch.disable=\u6279\u91cf\u7981\u7528 +batch.towhitelist=\u52a0\u5165\u767d\u540d\u55ae +batch.toblacklist=\u52a0\u5165\u9ed1\u540d\u55ae +confirm.favorites=\u78ba\u8a8d\u6536\u85cf\u55ce +confirm.batch.towhitelist=\u78ba\u8a8d\u52a0\u5165\u767d\u540d\u55ae?
\u5c07\u7981\u6b62\u4e0d\u5728\u767d\u540d\u55ae\u5167\u7684\u6240\u6709\u6d88\u8cbb\u8005\u8a2a\u554f\uff0c\u9ed1\u540d\u55ae\u5931\u6548\u3002 +confirm.batch.toblacklist=\u78ba\u8a8d\u52a0\u5165\u9ed1\u540d\u55ae?
\u5982\u679c\u6c92\u6709\u767d\u540d\u55ae\uff0c\u5c07\u7981\u6b62\u5728\u9ed1\u540d\u55ae\u5167\u7684\u6240\u6709\u5176\u5b83\u6d88\u8cbb\u8005\u8a2a\u554f\u3002 +confirm.enable=\u78ba\u8a8d\u555f\u7528 +confirm.disable=\u78ba\u8a8d\u7981\u7528 +confirm.edit=\u78ba\u8a8d\u7de8\u8f2f +confirm.disableFeature=\u78ba\u8a8d\u7981\u7528\u529f\u80fd +confirm.enableFeature=\u78ba\u8a8d\u555f\u7528\u529f\u80fd +confirmDeleteOwner=\u78ba\u8a8d\u522a\u9664\u8ca0\u8cac\u4eba +welcome=\u60a8\u597d +approve=\u5f85\u5be9\u6279 +chinese.simple=\u7c21\u9ad4\u4e2d\u6587 +chinese.tradition=\u7e41\u9ad4\u4e2d\u6587 +register.service=\u8a3b\u518a\u65b0\u670d\u52d9 +erratum.guide=\u6392\u932f\u56ae\u5c0e +preview.guide=\u9810\u89bd\u56ae\u5c0e +sysinfo.status=\u8a3b\u518a\u4e2d\u5fc3\u72c0\u614b +sysinfo.registries=\u8a3b\u518a\u4e2d\u5fc3\u96c6\u7fa4 +sysinfo.connections=\u901a\u8a0a\u7aef\u9023\u63a5 +sysinfo.cached=\u8a18\u61b6\u9ad4\u7de9\u5b58 +sysinfo.failed=\u5931\u6557\u8a18\u9304 +sysinfo.operations=\u64cd\u4f5c\u8a18\u9304 +sysinfo.logs=\u7cfb\u7d71\u65e5\u8a8c +sysinfo.versions=Dubbo\u7248\u672c +sysinfo.dumps=\u7cfb\u7d71\u5feb\u7167 +sysinfo.envs=\u7cfb\u7d71\u74b0\u5883 +sysinfo.helps=\u5e6b\u52a9\u6587\u6a94 +system.management=\u7cfb\u7d71\u7ba1\u7406 +sysmanage.users=\u7528\u6236\u7ba1\u7406 +sysmanage.configs=\u7cfb\u7d71\u53c3\u6578\u8a2d\u7f6e +sysmanage.features=\u7cfb\u7d71\u529f\u80fd\u958b\u95dc +system.function.control=\u7cfb\u7d71\u529f\u80fd\u958b\u95dc +personal.set=\u500b\u4eba\u8a2d\u7f6e +modify.personalinfo=\u4fee\u6539\u500b\u4eba\u8cc7\u8a0a +modify.personal.password=\u4fee\u6539\u500b\u4eba\u5bc6\u78bc +operation.operateaddress=\u64cd\u4f5c\u8005\u4f4d\u5740 +operation.operatetype=\u64cd\u4f5c\u985e\u578b +operation.datatype=\u8cc7\u6599\u985e\u578b +operation.data=\u64cd\u4f5c\u5167\u5bb9 +operation.createtime=\u64cd\u4f5c\u6642\u9593 +operation.clean=\u6e05\u7406 +passwd.oldwrong=\u820a\u5bc6\u78bc\u932f\u8aa4 +failed=\u5931\u6557\u8a18\u9304 +failed_type=\u985e\u578b +failed_data=\u6578\u64da +failed_sync=\u540c\u6b65\u4f4d\u5740\u5931\u6557\u8a18\u9304 +failed_subscribe=\u8a02\u95b1\u5931\u6557\u8a18\u9304 +failed_notify=\u901a\u77e5\u5931\u6557\u8a18\u9304 +failed_collect=\u7d71\u8a08\u5931\u6557\u8a18\u9304 +failed_register=\u8a3b\u518a\u5931\u6557\u8a18\u9304 +failed_redirect=\u91cd\u5b9a\u5411\u5931\u6557\u8a18\u9304 +failed_disconnect=\u65b7\u958b\u6e05\u7406\u5931\u6557\u8a18\u9304 +clientAddress=\u7528\u6236\u7aef\u5730\u5740 +overrideAddress=\u8986\u84cb\u4f4d\u5740 +serviceInfo=\u670d\u52d9\u8cc7\u8a0a +consumerAddress=\u6d88\u8cbb\u8005\u5730\u5740 +providerAddress=\u63d0\u4f9b\u8005\u5730\u5740 +registryAddress=\u8a3b\u518a\u4e2d\u5fc3\u5730\u5740 +serviceName=\u670d\u52d9\u540d +serviceUrl=\u670d\u52d9\u4f4d\u5740 +overrideConsumerAddress=\u53ea\u63a8\u9001\u7d66\u6307\u5b9a\u6d88\u8cbb\u8005\u5730\u5740 +overrideProviderAddress=\u53ea\u8986\u84cb\u6307\u5b9a\u63d0\u4f9b\u8005\u5730\u5740 +tipConsumerAddress=\u53ef\u4e0d\u586b\uff0c\u8868\u793a\u5c0d\u6d88\u8cbb\u8005\u61c9\u7528\u7684\u6240\u6709\u6a5f\u5668\u751f\u6548 +tipProviderAddress=\u53ef\u4e0d\u586b\uff0c\u8868\u793a\u5c0d\u670d\u52d9\u7684\u6240\u6709\u63d0\u4f9b\u8005\u6a5f\u5668\u751f\u6548 +logs=\u7cfb\u7d71\u65e5\u8a8c +logs.file=\u65e5\u8a8c\u6a94 +logs.size=\u6587\u4ef6\u5927\u5c0f +logs.modify=\u4fee\u6539\u6642\u9593 +logs.level=\u65e5\u8a8c\u7d1a\u5225 +change.log.level=\u4fee\u6539\u65e5\u8a8c\u7d1a\u5225 +logs.confirmChangeLogLevel=\u78ba\u8a8d\u4fee\u6539\u65e5\u8a8c\u7d1a\u5225 +cached=\u8a18\u61b6\u9ad4\u7de9\u5b58 +cached.type=\u985e\u578b +cached.data=\u6578\u64da +cached.reload=\u91cd\u65b0\u8f09\u5165 +batch.cached.reload=\u6279\u91cf\u91cd\u65b0\u8f09\u5165 +cached.recover=\u6062\u5fa9 +batch.cached.recover=\u6279\u91cf\u6062\u5fa9 +servicePrivilege=\u670d\u52d9\u8a31\u53ef\u6b0a +creator=\u5275\u5efa\u8005 +name=\u540d\u7a31 +department=\u90e8\u9580 +email=\u90f5\u7bb1 +phone=\u96fb\u8a71 +alitalk=\u963f\u88e1\u65fa\u65fa +password=\u5bc6\u78bc +roleR=\u8d85\u7d1a\u7ba1\u7406\u54e1 +roleA=\u7ba1\u7406\u54e1 +roleG=\u904a\u5ba2 +roleDescR=\u7ba1\u7406\u6240\u6709 +roleDescA=\u7ba1\u7406\u81ea\u5df1\u5275\u5efa\u7684\u4f7f\u7528\u8005\u548c\u670d\u52d9 +roleDescG=\u53ea\u67e5\u770b +oldPassword=\u820a\u5bc6\u78bc +newPassword=\u65b0\u5bc6\u78bc +reset=\u91cd\u7f6e +restPassword=\u91cd\u7f6e\u5bc6\u78bc +confirmNewPassword=\u78ba\u8a8d\u65b0\u5bc6\u78bc +owns=\u8ca0\u8cac\u7684\u670d\u52d9 +confirmPassword=\u78ba\u8a8d\u5bc6\u78bc +generatePassword=\u751f\u6210\u5bc6\u78bc +displayName=\u59d3\u540d +locale=\u4f7f\u7528\u8a9e\u8a00 +privilegeTip=\u591a\u500b\u503c\u7528\u9017\u865f(,)\u5206\u9694\uff0c\u842c\u7528\u5b57\u5143\u7528\u661f\u865f(*)\u8868\u793a\uff0c\u53ea\u80fd\u5728\u6bcf\u500b\u503c\u7684\u672a\u5c3e\u4f7f\u7528\u842c\u7528\u5b57\u5143\uff0c\u88ab\u6388\u8207\u7684\u8a31\u53ef\u6b0a\u4e0d\u80fd\u8d85\u51fa\u7576\u524d\u7ba1\u7406\u4eba\u54e1\u7684\u8a31\u53ef\u6b0a +displayNameTip=\u7528\u6236\u59d3\u540d\uff0c\u53ef\u4f7f\u7528\u4e2d\u6587\uff0c\u75311-50\u500b\u5b57\u5143\u7d44\u6210 +emailTip=\u7528\u65bc\u63a5\u6536\u7cfb\u7d71\u90f5\u4ef6\uff0c\u53ef\u4ee5\u8f38\u5165\u591a\u500b\u90f5\u5bc4\u5730\u5740\uff0c\u4f7f\u7528\u82f1\u6587\u5206\u865f\u5206\u9694(;)\uff0c \u5f62\u5982 foo1@163.comj;foo2@gmail.com +userLocaleTip=\u767c\u9001\u7cfb\u7d71\u90f5\u4ef6\u6642\uff0c\u5c07\u6839\u64da\u4f7f\u7528\u8005\u4f7f\u7528\u7684\u8a9e\u8a00\u767c\u9001\u4e0d\u540c\u8a9e\u8a00\u7684\u90f5\u4ef6\u5167\u5bb9 +DisplayNameTip +EmailTip +UserLocaleTip +missRequestParameters=\u4e1f\u5931\u8acb\u6c42\u53c3\u6578 +haveNoRootPrivilege=\u6c92\u6709root\u8a31\u53ef\u6b0a +confirmReloadCache=\u78ba\u8a8d\u91cd\u65b0\u8f09\u5165\u7de9\u5b58 +confirmDeleteRegistry=\u78ba\u8a8d\u522a\u9664\u8a3b\u518a\u4e2d\u5fc3 +confirmAutoRedirectRegistry=\u78ba\u8a8d\u91cd\u5b9a\u5411\u8a3b\u518a\u4e2d\u5fc3 +confirmDeleteExpiredRegistry=\u78ba\u8a8d\u522a\u9664\u904e\u671f\u8a3b\u518a\u4e2d\u5fc3 +confirmSyncRegistry=\u78ba\u8a8d\u540c\u6b65\u8a3b\u518a\u4e2d\u5fc3\u5730\u5740\u6e05\u55ae\u5230\u7528\u6236\u7aef +confirm.toblacklist=\u78ba\u8a8d\u52a0\u5165\u9ed1\u540d\u55ae?
\u5982\u679c\u6c92\u6709\u767d\u540d\u55ae\uff0c\u5c07\u7981\u6b62\u5728\u9ed1\u540d\u55ae\u5167\u7684\u6240\u6709\u6d88\u8cbb\u8005\u8a2a\u554f\u3002 +confirm.towhitelist=\u78ba\u8a8d\u52a0\u5165\u767d\u540d\u55ae?
\u5c07\u7981\u6b62\u4e0d\u5728\u767d\u540d\u55ae\u5167\u7684\u6240\u6709\u5176\u5b83\u6d88\u8cbb\u8005\u8a2a\u554f\uff0c\u9ed1\u540d\u55ae\u5931\u6548\u3002 +confirm.clean.operation=\u78ba\u8a8d\u6e05\u9664\u64cd\u4f5c\u8a18\u9304 +autoRedirect=\u81ea\u52d5\u91cd\u5b9a\u5411 +deleteExpired=\u522a\u9664\u6240\u6709\u5df2\u904e\u671f +sync=\u540c\u6b65 +legacies=1.0\u907a\u7559\u7528\u6236\u7aef +logined=\u5df2\u767b\u9304\u7528\u6236\u7aef +dumps=\u7cfb\u7d71\u5feb\u7167 +update=\u66f4\u65b0 +generic=\u6cdb\u5316 +Registry=\u8a3b\u518a\u4e2d\u5fc3\u7248\u672c +Java=JDK\u7248\u672c +Locale=\u8a9e\u8a00 +CPU=\u0043\u0050\u0055 +OS=\u4f5c\u696d\u7cfb\u7d71 +Uptime=\u57f7\u884c\u6642\u9593 +Host=\u529f\u80fd\u8b8a\u6578\u540d\u7a31 +confirmEnableUser=\u78ba\u8a8d\u555f\u52d5\u7528\u6236 +confirmDisableUser=\u78ba\u8a8d\u7981\u7528\u7528\u6236 +documentTitle=\u6587\u6a94\u6a19\u984c +documentLink/documentPage=\u9023\u7d50\u4f4d\u5740/\u9801\u9762\u5167\u5bb9 +documentInternal=\u9801\u9762 +documentExternal=\u9023\u7d50 +documentApi=API +documentType=\u6587\u6a94\u985e\u578b +documentContent=\u6587\u6a94\u5167\u5bb9 +Yes=\u662f +No=\u5426 +returnValue=\u8fd4\u56de\u503c +throwException=\u62cb\u51fa\u7570\u5e38 +#BatchAddressTip=\u591a\u500b\u4f4d\u5740\u7528\u5206\u884c\u7b26\u865f\u5206\u9694\uff0c\u4f4d\u5740\u5fc5\u9700\u662f0.0.0.0\u5230255.255.255.255\u7684IP\u5730\u5740 +#AccessControlTip=\u767d\u540d\u55ae\u512a\u5148\uff0c\u53ea\u8981\u6709\u767d\u540d\u55ae\uff0c\u5247\u767d\u540d\u55ae\u751f\u6548\uff0c\u5426\u5247\u9ed1\u540d\u55ae\u751f\u6548 +#RouteNameTip=\u53ef\u4f7f\u7528\u4e2d\u6587\uff0c\u75311-200\u500b\u5b57\u5143\u7d44\u6210 +#RoutePriorityTip=\u6578\u5b57\u8d8a\u5927\u8d8a\u512a\u5148 +#RouteMethodTip=\u53ea\u6709Dubbo2.0.0\u4ee5\u4e0a\u7248\u672c\u7684\u670d\u52d9\u6d88\u8cbb\u7aef\u652f\u63f4\u6309\u65b9\u6cd5\u8def\u7531\uff0c\u591a\u500b\u65b9\u6cd5\u540d\u7528\u9017\u865f\u5206\u9694 +#Choose=\u8acb\u9078\u64c7 +#RouteMatchTip=\u7576\u6d88\u8cbb\u8005\u6eff\u8db3\u5339\u914d\u689d\u4ef6\u6642\u4f7f\u7528\u7576\u524d\u898f\u5247\u9032\u884c\u904e\u6ffe +#RouteHostTip=\u591a\u500b\u503c\u7528\u9017\u865f\u5206\u9694\uff0c\u4ee5\u661f\u865f\u7d50\u5c3e\u8868\u793a\u901a\u914d\u4f4d\u5740\u6bb5 +#RouteClusterTip=\u53ef\u901a\u904e\u529f\u80fd\u8868"\u670d\u52d9\u63a7\u5236"->"\u4f3a\u670d\u5668\u96c6\u7fa4"\u7ba1\u7406 +#RouteFilterTip=\u6eff\u8db3\u904e\u6ffe\u898f\u5247\u7684\u63d0\u4f9b\u8005\u4f4d\u5740\u5c07\u88ab\u63a8\u9001\u7d66\u6d88\u8cbb\u8005 +testMethodTip=\u5982\u679c\u6709\u65b9\u6cd5\u91cd\u8f09\u6216\u4f7f\u7528Dubbo1.0.x\u7248\u672c\u7684\u670d\u52d9\u63d0\u4f9b\u8005\uff0c\u9700\u5beb\u5168\u65b9\u6cd5\u7c3d\u540d\uff0c\u5982\uff1afindBy(int,java.lang.String)\uff0c\u5426\u5247\u53ea\u9700\u65b9\u6cd5\u540d\uff0c\u5982\uff1afindBy +testJsonTip=JSON\u683c\u5f0f\uff1a\u5b57\u4e32\u7528\u96d9\u5f15\u865f\u8868\u793a\uff0c\u5982\uff1a"\u5b57\u4e32"\uff0c\u6578\u4f4d\u548cBoolean\u503c\u4e0d\u7528\u5f15\u865f\uff0c\u5982\uff1a123 \u548c true \u6216 false\uff0cPOJO\u7269\u4ef6\u6216Map\u7528\u5927\u62ec\u5f27\u8868\u793a\uff0c\u5982\uff1a{"\u5c6c\u6027\u540d1": "\u5c6c\u6027\u503c1", "\u5c6c\u6027\u540d2": "\u5c6c\u6027\u503c2"}\uff0c\u9663\u5217\u6216List\u6216Set\u7528\u65b9\u62ec\u865f\u8868\u793a\uff0c\u5982\uff1a["\u503c1", "\u503c2"] +testParametersTip=\u7576\u70ba\u7121\u53c3\u6578\u65b9\u6cd5\u6642\u53c3\u6578\u503c\u53ef\u4ee5\u4e0d\u586b\uff0c\u53c3\u6578\u503c\u4f7f\u7528JSON\u683c\u5f0f\u8868\u793a +testResultTip=\u7576\u70bavoid\u65b9\u6cd5\u6642\u7d50\u679c\u53ef\u4ee5\u4e0d\u586b\uff0c\u62cb\u51fa\u7570\u5e38\u4f7f\u7528\u7570\u5e38\u985e\u5168\u540d\u8868\u793a\uff0c\u8fd4\u56de\u503c\u4f7f\u7528JSON\u683c\u5f0f\u8868\u793a +testAutoRunTip=\u5982\u679c\u8a2d\u7f6e\u70ba\u81ea\u52d5\u904b\u884c\uff0c\u82e5\u8a72\u670d\u52d9\u5df2\u8a3b\u518a\u6216\u65b0\u8a3b\u518a\uff0c\u5247\u81ea\u52d5\u904b\u884c\u6b64\u6e2c\u8a66\u7528\u4f8b\uff0c\u904b\u884c\u5931\u6557\uff0c\u5c07\u767c\u9001\u90f5\u4ef6 +confirmRunTest=\u78ba\u8a8d\u904b\u884c\u6e2c\u8a66 +confirm.runAll=\u78ba\u8a8d\u5c0d\u6240\u6709\u63d0\u4f9b\u8005\u904b\u884c\u6e2c\u8a66 +# +#anonymous=\u533f\u540d +#Unuse=\u672a\u4f7f\u7528 +#RouteName=\u8def\u7531\u540d +#Priority=\u512a\u5148\u9806\u5e8f +#MatchRule=\u5339\u914d\u689d\u4ef6 +#ConsumerHost=\u6d88\u8cbb\u8005IP\u5730\u5740 +#ConsumerCluster=\u6d88\u8cbb\u8005\u96c6\u7fa4 +#FilterRule=\u904e\u6ffe\u898f\u5247 +#ProviderHost=\u63d0\u4f9b\u8005IP\u5730\u5740 +#ProviderCluster=\u63d0\u4f9b\u8005\u96c6\u7fa4 +#ProviderProtocol=\u63d0\u4f9b\u8005\u5354\u5b9a +#ProviderPort=\u63d0\u4f9b\u8005\u57e0 +#Match=\u5339\u914d +#Mismatch=\u4e0d\u5339\u914d +#ConsumerAddress=\u6d88\u8cbb\u8005\u5730\u5740 +loadBalanceStrategy=\u8ca0\u8f09\u5747\u8861\u7b56\u7565 +random=\u96a8\u6a5f +roundrobin=\u8f2a\u8a62 +leastactive=\u6700\u5c11\u4f75\u767c +testName=\u6e2c\u8a66\u7528\u4f8b\u540d\u7a31 +operator=\u64cd\u4f5c +dataFormat=\u8cc7\u6599\u683c\u5f0f +resultType=\u7d50\u679c\u985e\u578b +resultController=\u8fd4\u56de\u503c/\u7570\u5e38\u985e\u578b +autoRun=\u81ea\u52d5\u904b\u884c +manualRun=\u624b\u52d5\u904b\u884c +run=\u904b\u884c +runAll=\u904b\u884c\u6240\u6709\u63d0\u4f9b\u8005 +expected=\u671f\u671b\u7d50\u679c +actual=\u5be6\u969b\u7d50\u679c +reRun=\u91cd\u65b0\u904b\u884c +#Username=\u7528\u6236\u540d +#DisplayName=\u986f\u793a\u540d +#Department=\u90e8\u9580 +#Email=\u90f5\u7bb1 +#Phone=\u624b\u6a5f +#Alitalk=\u65fa\u65fa +startDate=\u555f\u52d5\u6642\u9593 +console=\u63a7\u5236\u53f0 +total=\u7e3d\u6578 +delta=\u504f\u5dee +expired=\u904e\u671f +alived=\u5b58\u6d3b +redirect=\u91cd\u5b9a\u5411 +current=\u7576\u524d +#overrides +override.config=\u52d5\u614b\u914d\u7f6e +override.mock=\u670d\u52d9\u964d\u7d1a +parameter=\u53c3\u6578 +parameter.key=\u53c3\u6578\u540d +parameter.value=\u53c3\u6578\u503c +mock.all.method=\u6240\u6709\u65b9\u6cd5\u7684Mock\u503c +mock.method=\u65b9\u6cd5 +mock.value=\u7684Mock\u503c +default.owner=\u8ca0\u8cac\u4eba +logger=\u65e5\u8a8c +default.server=\u9ed8\u8a8d\u670d\u52d9\u7aef +default.actives=\u4e26\u767c\u8abf\u7528\u6578 +default.client=\u9ed8\u8a8d\u5ba2\u6236\u7aef +default.connections=\u6700\u5927\u9023\u63a5\u6578 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/log4j.properties b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/log4j.properties new file mode 100644 index 0000000..5be84a2 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/log4j.properties @@ -0,0 +1,37 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +log4j.rootCategory=INFO, stdout, file +log4j.logger.org.apache=ERROR + + +# 控制台输出 +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.target=System.out +log4j.appender.stdout.Threshold=INFO +log4j.appender.stdout.encoding=GBK +log4j.appender.stdout.layout.ConversionPattern=%5p %c{2} - %m%n + +# 文件输出 +log4j.appender.file=org.apache.log4j.RollingFileAppender +log4j.appender.file.file=dubbo-governance.log +log4j.appender.file.Threshold=INFO +log4j.appender.file.append=true +log4j.appender.file.maxFileSize=10MB +log4j.appender.file.maxBackupIndex=100 +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=%d [%t] %-5p %C{6} (%F:%L) - %m%n \ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/css/common.css b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/css/common.css new file mode 100644 index 0000000..e5fb2bf --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/css/common.css @@ -0,0 +1,689 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@charset "utf-8"; +/* CSS Document */ +html, body, div, p, ul, li, dl, dt, dd, h1, h2, h3, h4, h5, h6, form, input, select, button, textarea, iframe, table, th, td { + margin: 0; + padding: 0; +} + +select, textarea, input { + border: #b3b3b3 1px solid; +} + +input.radio, input.checkbox { + border: none; +} + +img { + border: none; +} + +ul, li { + list-style-type: none; +} + +body { + margin: 0; + font-family: Arial, Helvetica, sans-serif; + font-size: 12px; + color: #586573; + min-width: 1150px; + word-wrap: break-word; + word-break: break-all; +} + +body.pop { + background-color: transparent; +} + +body.pop_del { + min-width: 750px; +} + +a { + color: #2f7ed3; + cursor: pointer; +} + +a.fontlink { + color: #2f7ed3; + text-decoration: underline; +} + +.none { + display: none; +} + +.left { + float: left; +} + +.right { + float: right; +} + +/*head*/ +.head_right { + float: right; + padding-top: 45px; + margin: 0 10px 0 0; + color: #FFF; +} + +.head_right span { + color: #fff; + line-height: 30px; + float: right; + margin-right: 15px; +} + +.head_right span a { + color: #fff; +} + +.exit { + float: right; + padding-top: 3px; +} + +/*menu*/ +.nav ul li { + float: left; + height: 31px; + line-height: 24px; +} + +.nav ul li a { + padding-top: 5px; + height: 26px; + color: #FFF; + display: block; + width: 157px; + text-decoration: none; + text-align: center; +} + +.nav ul li.current a { + color: #000; + display: block; + width: 157px; + text-decoration: none; + text-align: center; +} + +.nav ul li.current ul li a { + color: #fff; + display: block; + width: 157px; + text-decoration: none; + text-align: center; +} + +.nav li:hover ul { + display: block; +} + +.nav ul li ul { + position: absolute; + display: none; + list-style-type: none; + text-align: left; +} + +.nav ul li ul li { + display: block; + text-decoration: none; + height: 28; + clear: both; +} + +.nav ul li ul li a { + color: #fff; + display: block; + text-decoration: none; +} + +.nav ul li ul li a:hover { + background-image: none; +} + +.nav ul li.sub_nav a { + color: #fff; + display: block; + width: 157px; + text-decoration: none; + text-align: center; + line-height: 26px; +} + +.nav ul li.sub_nav ul li a { + color: #fff; + display: block; + width: 157px; + text-decoration: none; + text-align: center; +} + +.nav ul li.current_nosub a { + color: #000; + display: block; + width: 157px; + text-decoration: none; + text-align: center; + line-height: 26px; +} + +.about { + clear: right; + float: right; + line-height: 28px; + margin-right: 20px; +} + +.about a { + color: #fff; +} + +/*全局搜索*/ +.search_o { + clear: left; + width: 500px; + margin-bottom: 10px; +} + +.search_btn { + margin-top: 5px; + *margin: 0; +} + +.btn_search { + background: url(../images/btn_service.png); + width: 132px; + height: 20px; + text-align: center; + line-height: 20px; + margin-top: 10px; +} + +.btn_search a, .btn_info a { + text-decoration: none; + color: #666; + display: block; +} + +.search { + width: 500px; + margin: 150px auto; +} + +.search_categories { + height: 18px; +} + +.search_categories ul li { + float: left; + width: 60px; + line-height: 10px; + *line-height: 15px; + text-align: center; +} + +.search_categories ul li a { + color: #586573; + text-decoration: none; +} + +.search_categories ul li span.search_line { + margin-left: 10px; + color: #CCC; +} + +.search_categories ul li span.search_line_end { + margin-left: 10px; + color: #fff; +} + +/*main*/ +.main { + background: url(../images/main_bg.png) repeat-x; + min-height: 229px; + padding: 15px 20px 20px 20px; + *padding-bottom: 0; + /* min-height:593px; */ + height: 100%; +} + +.title { + font-family: "微软雅黑"; + font-weight: 200; + color: #696969; + font-size: 16px; + float: left; + margin-bottom: 10px; +} + +.title_num { + font-size: 14px; + float: left; + padding: 13px 0 0 10px; + padding-top: 9px \0; + *padding-top: 9px; +} + +.crumbs { + float: left; + padding-top: 15px; + padding-left: 20px; + color: #999; +} + +.num_o { + clear: left; + padding-top: 10px; + *padding-top: 0; +} + +.num_t { + clear: left; + padding-top: 10px; +} + +/*table_search*/ +.search_list { + overflow: hidden; + margin-bottom: 10px; +} + +.search_list table th { + font-weight: normal; + padding-right: 10px; +} + +.search_list table td { + font-weight: normal; + padding-right: 15px; +} + +/*table_ico_btn*/ +.ico_btn { + clear: both; +} + +.ico_btn a, table.list td a { + text-decoration: none; +} + +.ico_btn span.ico_font, table.list td span.ico_font { + margin-left: 5px; +} + +.ico_btn span.ico_line, table.list td span.ico_line { + margin: 0 10px 0 10px; + color: #CCC; +} + +/*table*/ +table.list { + color: #586573; + clear: left; + width: 100%; + border: #dedede 1px solid; + margin-bottom: 10px; +} + +table.list th { + height: 29px; + color: #fff; + line-height: 29px; + text-align: left; + padding-left: 8px; + font-weight: bold; +} + +table.list td { + text-align: left; + padding-left: 10px; + line-height: 34px; + border-top: #d4d4d4 1px dashed; +} + +/*footer*/ +.footer span { + color: #fff; + line-height: 26px; + margin-left: 20px; +} + +/*button*/ +.btn a, .login_btn a { + text-decoration: none; + color: #586573; + display: block; +} + +span.star { + color: #F00; +} + +/*pop*/ +table.pop_top td.pop_lefttop_small h1 { + font-size: 24px; + color: #000; + padding-left: 90px; + padding-top: 20px; +} + +table.pop_top td.pop_midtop_small { + background: url(../images/pop_midtop_small.png); + height: 105px; +} + +table.pop_top td.pop_righttop_small { + background: url(../images/pop_righttop_small.png); + width: 46px; + height: 105px; +} + +table.pop_mid td.pop_left { + background: url(../images/pop_left.png); + width: 19px; +} + +table.pop_mid td.pop_content { + background: #f7f7f7; +} + +table.pop_mid td.pop_right { + background: url(../images/pop_right.png); + width: 19px; +} + +table.pop_mid td.pop_leftbottom_small { + background: url(../images/pop_leftbottom.png); + width: 19px; + height: 22px; +} + +table.pop_mid td.pop_midbottom_small { + background: url(../images/pop_midbottom.png); + height: 22px; +} + +table.pop_mid td.pop_rightbottom_small { + background: url(../images/pop_rightbottom.png); + width: 19px; + height: 22px; +} + +table.pop_box { + border-top: #cdcdcd 1px dashed; + border-bottom: #cdcdcd 1px dashed; + margin: 0px auto 20px auto; + padding: 0; +} + +table.pop_box th { + text-align: right; + height: 30px; +} + +table.pop_box th.space { + height: 15px; +} + +.pop_close { + background: url(../images/pop_close.png); + width: 20px; + height: 20px; + margin: 10px 0 0 13px; + cursor: pointer; +} + +.tip_close { + margin: 13px 14px 0 0; + float: right; +} + +.pop_tipmessage table, .pop_tipmessage_del table, .pop_tipmessage_succeed table, .pop_tipmessage_choose table { + padding: 100px 60px 0 0; + float: right; + *margin: 100px 60px 0 0; +} + +.pop_tipmessage table th, .pop_tipmessage_del table th, .pop_tipmessage_succeed table th, .pop_tipmessage_choose table th { + font-size: 30px; + font-weight: 500; + color: #333; + text-align: right; +} + +.pop_tipmessage table td, .pop_tipmessage_del table td, .pop_tipmessage_succeed table td, .pop_tipmessage_choose table td { + line-height: 60px; + text-align: right; +} + +.pop_tipmessage table td.pop_tip_btn, .pop_tipmessage_del table td.pop_tip_btn, .pop_tipmessage_succeed table td.pop_tip_btn, .pop_tipmessage_choose table td.pop_tip_btn { + padding-top: 30px; +} + +/*翻页*/ +span.go a { + font-weight: bold; + margin-left: 5px; + text-decoration: none; + font-size: 14px; +} + +.prev, .num { + padding: 0 5px 0 5px; +} + +/*login*/ +.user { + color: #fff; + float: right; + width: 400px; + margin-top: 80px; + margin-right: 50px; +} + +.user table td { + line-height: 42px; + padding-left: 10px; +} + +input.login_input { + border: #989898 1px solid; + padding: 2px 0 0 4px; + width: 220px; + height: 17px; +} + +/*横向tab*/ +.contentbox_tab { + clear: both; + background: #fff; + padding: 15px 15px 8px 15px; + overflow: hidden; + margin-right: -10px; + margin-bottom: 8px; +} + +.menubox ul li { + float: left; + display: block; + cursor: pointer; + width: 90px; + text-align: center; + line-height: 28px; + line-height: 28px \0; +} + +.menubox ul li a { + text-decoration: none; + color: #fff; +} + +.menubox ul li.active { + background: url(../images/tab_active.png); + width: 90px; + height: 29px; +} + +.menubox ul li.active a { + color: #666; +} + +.tab { + clear: left; + *margin-top: -10px; +} + +.box_tab { + background: #f5f5f5; + border: #ccc 1px solid; +} + +/*纵向tab*/ +.favorite { + width: 291px; + clear: left; + float: left; + *margin-top: 10px; +} + +.fav_tab { + float: right; +} + +.fav_tab ul li { + background: url(../images/fav_tab_normal.png); + width: 20px; + height: 70px; +} + +.fav_tab ul li.active { + background: url(../images/fav_tab_active.png); + width: 20px; + height: 70px; +} + +.fav_tab ul li a, .fav_tab ul li.active a { + text-decoration: none; + padding: 6px 0 0 4px; + display: block; + line-height: 15px; +} + +.fav_box { + float: left; + width: 269px; + min-height: 150px; + background: #f5f5f5; + border: #ccc 1px solid; +} + +.fav_box_title { + background: url(../images/fav_title.png); + height: 30px; + line-height: 30px; + padding-left: 15px; +} + +.fav_box_title span { + padding-left: 5px; +} + +.fav_box_title img { + margin-left: 20px; +} + +.fav_title_left { + float: left; +} + +.fav_content { + margin: 10px 0 10px 15px; +} + +.fav_content table td { + line-height: 23px; +} + +.fav_tips { + width: 210px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.fav_tips a { + text-decoration: none; +} + +/*setting*/ +.setting_box { + background: #f0f2f4; + border: #ccc 1px solid; + clear: both; + padding: 20px 20px 25px 20px; + *padding-top: 10px; + margin-bottom: 10px; +} + +.setting_box table.setting th { + font-weight: normal; + text-align: right; + line-height: 32px; + width: 100px; +} + +.setting_box table.setting td { + padding-left: 10px; +} + +span.red { + color: #F00; + margin-left: 10px; +} + +input.setting_input { + width: 200px; + height: 18px; +} + +select.setting_select { + width: 202px; + height: 18px; +} + +.setting_box_page { + padding-bottom: 30px; +} + +/*pop_tips*/ +.pop_tips { + width: 300px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + + + diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/css/dubbo.css b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/css/dubbo.css new file mode 100644 index 0000000..3a462d9 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/css/dubbo.css @@ -0,0 +1,335 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@charset "utf-8"; +/* CSS Document */ +/*head*/ +.head_right_dubbo { + float: right; +} + +.head_right_dubbo span { + color: #fff; + line-height: 30px; + float: right; + margin-right: 15px; +} + +.head_right_dubbo span a { + color: #fff; +} + +.exit { + float: right; + padding-top: 3px; +} + +.head_right_dubbotop { + margin-top: 0px; + margin-right: 0px; + color: white; +} + +.head_right_dubbobottom { + margin-top: 30px; + margin-right: 10px; + text-align: right; + color: white; +} + +.head_right_dubbobottom td { + margin-left: 50px; +} + +/*title*/ +.title_search { + margin-bottom: 20px; + *margin-bottom: 10px; +} + +.dubbo_search { + background: url(../images/main_bg.png) repeat-x; + padding: 15px 20px 0 20px; + height: 120px; + *height: 100px; +} + +.dubbo_search_nobox { + height: 40px; +} + +.dubbo_main { + height: 100%; + clear: left; +} + +.dubbo_content { + margin: 0 20px 20px 20px; + background: #f3f5f5; + border: #cccccc 1px solid; + padding: 15px 25px 10px 15px; +} + +/*search*/ +.search { + width: 500px; + margin: 150px auto; +} + +.search_o { + clear: left; + width: 500px; +} + +.search_categories { + height: 18px; +} + +.search_categories ul li { + float: left; + width: 60px; + line-height: 10px; + *line-height: 15px; + text-align: center; +} + +.search_categories ul li a { + color: #586573; + text-decoration: none; +} + +.search_categories ul li span.search_line { + margin-left: 10px; + color: #CCC; +} + +.search_categories ul li span.search_line_end { + margin-left: 10px; + color: #fff; +} + +.active { + background: url(../images/search_active.png); + width: 52px; + height: 20px; + display: block; +} + +.search_input { + background: url(../images/search_input.png); + width: 438px; + height: 31px; + float: left; +} + +.search_input input { + border: none; + background: url(../images/input.png); + width: 350px; + height: 21px; + margin: 5px 0 0 80px; + *margin: 4px 0 0 80px; + color: #7d8a98; + line-height: 20px; +} + +.search_btn { + margin-top: 5px; + *margin: 0; +} + +.btn_search { + background: url(../images/btn_service.png); + width: 132px; + height: 20px; + text-align: center; + line-height: 20px; + margin-top: 10px; +} + +.btn_search a, .btn_info a { + text-decoration: none; + color: #666; + display: block; +} + +/*table*/ +table.info { + width: 100%; +} + +table.info th { + font-weight: bold; + text-align: left; + padding-top: 10px; +} + +table.info td { + font-weight: normal; + text-align: left; + padding-top: 10px; + padding-left: 10px; +} + +.btn_info { + background: url(../images/btn_info.png); + width: 78px; + height: 20px; + text-align: center; + line-height: 20px; + float: left; + margin: 5px 5px 10px 0; +} + +.search_list input { + width: 200px; + float: left; + margin-right: 10px; + height: 17px; +} + +table.list_dubbo th { + background: url(../images/dubbo_list_th.png); + height: 29px; + color: #586573; + font-weight: normal; + padding-left: 10px; +} + +table.list_dubbo th.checkbox { + width: 50px; +} + +table.list_dubbo th.operate, table.list_system th.operate { + width: 190px; +} + +table.list_system { + width: 700px; +} + +table.list_system th { + text-align: left; +} + +table.list_system th.operate_system { + width: 180px; +} + +table.list_system td span.radio_font { + padding: 0 40px 0 5px; +} + +span.rule_green { + color: #390; +} + +span.rule_orange { + color: #F60; +} + +/*setting*/ +span.state { + color: #390; +} + +/*favorite*/ +.favorite { + width: 291px; + clear: left; + float: left; + *margin-top: 10px; +} + +.fav_tab { + float: right; +} + +.fav_tab ul li { + background: url(../images/fav_tab_normal.png); + width: 20px; + height: 70px; +} + +.fav_tab ul li.active { + background: url(../images/fav_tab_active.png); + width: 20px; + height: 70px; +} + +.fav_tab ul li a, .fav_tab ul li.active a { + text-decoration: none; + padding: 6px 0 0 4px; + display: block; + line-height: 15px; +} + +.fav_box { + float: left; + width: 269px; + min-height: 150px; + background: #f5f5f5; + border: #ccc 1px solid; +} + +.fav_box_title { + background: url(../images/fav_title.png); + height: 30px; + line-height: 30px; + padding-left: 15px; +} + +.fav_box_title span { + padding-left: 5px; +} + +.fav_box_title img { + margin-left: 20px; +} + +.fav_title_left { + float: left; +} + +.fav_content { + margin: 10px 0 10px 15px; +} + +.fav_content table td { + line-height: 23px; +} + +.fav_tips { + width: 210px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.fav_tips a { + text-decoration: none; +} + +.fav_content_checkbox { + margin-right: 10px; +} + +.fav_arrow { + float: right; + padding-top: 7px; + padding-right: 10px; +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/css/skin.css b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/css/skin.css new file mode 100644 index 0000000..d0e0794 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/css/skin.css @@ -0,0 +1,275 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@charset "utf-8"; +/* CSS Document */ +/*head*/ +.head { + min-width: 1150px; + height: 78px; + background-image: url(../images/head_bg.png); +} + +/*menu*/ +.nav, .nav_harbor { + color: #FFF; + background-image: url(../images/nav_bg.png); + min-width: 1150px; + height: 31px; + clear: right; +} + +.nav ul li a:hover, .nav_harbor ul li a:hover, .nav_harbor ul li:hover a { + background-image: url(../images/nav_pass.png); +} + +.nav ul li ul, .nav ul li ul li { + background-color: #3d8efa; +} + +.nav ul li ul li a:hover { + background-color: #64a6fd; +} + +.nav ul li.sub_nav { + background: url(../images/nav_btn_bg22.png) no-repeat; +} + +.nav ul li.sub_nav:hover { + color: #fff; + background: url(../images/nav_btn_bg22.png) no-repeat 0 -31px; +} + +.nav ul li.sub_nav a:hover { + color: #fff; + background: url(../images/nav_btn_bg22.png) no-repeat 0 -31px; +} + +.nav ul li.sub_nav ul li a:hover { + background-color: #64a6fd; + background-image: none; +} + +.nav ul li.current_nosub { + background: url(../images/nav_btn_bg44.png) no-repeat; +} + +.nav ul li.current_nosub :hover { + background: url(../images/nav_btn_bg44.png) no-repeat; +} + +.nav ul li.current:hover > a { + background: url(../images/nav_btn_bg22.png) no-repeat 0 -31px; + color: #fff; +} + +.nav ul li.current, .nav_harbor ul li.current { + background-image: url(../images/nav_btn_bg3.png); + background-position: right; +} + +.nav ul li.current a:hover { + background: url(../images/nav_btn_bg22.png) no-repeat 0 -31px; +} + +.nav ul li.current ul li a:hover { + background-color: #64a6fd; + background-image: none; +} + +.nav_harbor li .sub { + background-color: #3d8efa; +} + +.nav_harbor .sub ul li a:hover { + background-color: #64a5fc; +} + +li.sub_font { + color: #fff82d; + font-weight: bold; +} + +/*全局搜索*/ +.search_input { + background: url(../images/search_input.png); + width: 438px; + height: 31px; + float: left; +} + +.search_input input { + border: none; + background: url(../images/input.png); + width: 350px; + height: 21px; + margin: 5px 0 0 80px; + *margin: 4px 0 0 80px; + color: #7d8a98; + line-height: 20px; +} + +.active { + background: url(../images/search_active.png); + width: 52px; + height: 20px; + display: block; +} + +/*table*/ +table.list th { + background: url(../images/table_title_bg.png) repeat-x; +} + +table.list th.head_title { + background: url(../images/table_title_bg.png); + width: 10px; + height: 29px; +} + +/*pop*/ +table.pop_top td.pop_lefttop_small { + background: url(../images/pop_lefttop_small.png); + width: 300px; + height: 105px; +} + +.pop_tipmessage { + background: url(../images/tip_warning.png); +} + +.pop_tipmessage_choose { + background: url(../images/tip_choose.png); +} + +.pop_tipmessage_del { + background: url(../images/tip_del.png); +} + +.pop_tipmessage_succeed { + background: url(../images/tip_succeed.png); +} + +.pop_tipmessage, .pop_tipmessage_choose, .pop_tipmessage_del, .pop_tipmessage_succeed { + width: 720px; + height: 300px; +} + +/*button*/ +.btn { + width: 65px; + height: 20px; + background: url(../images/button_normal.png); + text-align: center; + float: left; + margin-right: 5px; + line-height: 20px; + display: block; +} + +.btn a:hover { + color: #C60; + width: 65px; + height: 20px; + background: url(../images/button_hover.png); + text-align: center; + float: left; + margin-right: 5px; + display: block; +} + +.login_btn { + width: 65px; + height: 20px; + background: url(../images/login_btn_normal.png); + text-align: center; + margin-right: 5px; + line-height: 20px; + display: block; +} + +.login_btn a:hover { + color: #C60; + width: 65px; + height: 20px; + background: url(../images/login_btn_hover.png); + text-align: center; + float: left; + margin-right: 5px; + display: block; +} + +/*footer*/ +.footer { + margin-top: 10px; + *margin: 0; + min-width: 1150px; + background: #808080; + height: 28px; +} + +/*翻页*/ +.page { + color: #2a7ec5; + float: right; + padding-bottom: 5px; +} + +.page a { + color: #2a7ec5; +} + +a.current_num { + color: #f09a3e; +} + +/*login*/ +.login { + background-image: url(../images/login_bg.png); + background-repeat: no-repeat; + background-color: #1a4f89; +} + +.login_container { + width: 100%; + margin-top: 200px; + background-image: url(../images/login_shadow.png); + height: 231px; +} + +.login_box { + margin: 0 auto; + background-image: url(../images/login_box.png); + width: 804px; + height: 231px; +} + +/*tab*/ +.menubox { + background: #8ebdec; + height: 29px; + width: 100%; + padding-left: 10px; +} + +/*可伸缩区块*/ +a.title_o { + font-size: 14px; + font-weight: bold; + text-decoration: none; + color: #2f7ed3; +} diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/404error.gif b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/404error.gif new file mode 100644 index 0000000000000000000000000000000000000000..bb0a0d4d72031a2c4c506ad6c7d0d98c0bd15d31 GIT binary patch literal 2131 zcmV-Z2(0%RsQtd z{pq{=)OP>?00000A^8LZ6afDKEC2ui0FVJf000I5ASRAvX`X1Ru59bRa4gSsZQppV z?|kq7z@TtQEEJZuf4v%Ck%Q54Q|66q-+)#7Hpot(9x_L!?MQ>xXgO1(%s&M z$!rZ6v;xg+3FiVG-|g;p)Wa5;$rI|P@A>*z91I+CB82Igpn=T+Z0qzixU{dK!zb~? zX;_Bgz_4TpCm?J90nPwL4?~I+a;sVc1{)Cn0uo2eBC!PFa*doxQ-{lH#29QGhA=}x zg%D~A9XeydPn;`}BGtf>^+ zZ3nSr!NKqAN&GfQ@Y5$cT8-1eAOHY>i2~)*19%`^MS$`Ou*)an_W%S$ z==5ypJ|jZ<68@>DUVA7!0N;EF{@|Ja9v#rd;5p+6G)@ff{Wn5|0K|tu02GvWK?)rn zh(Z7clxX6KCRRZriY6*h02C!skU|9pQ~(2kC9KHei4h2~VmICKu>e8`ERc*R@iYd* z1?rJN9sn;oSzeDOAfTRxCrBXRmgQBUC702u5lv1vOC=s{67HB=Djq$8l0;Rzv@;6Qp$I!eNqp>~1m2~SeFgnELSiKYvqmayv* z#d;$UMHnbkLx2E~*rf<-0+1{J3DsUZDFI*FI>NEKmUk@) zKrp~+0VVeWhA;X#!jsmS5TLJ5irFoq?ygWG2C4!;!NCbrU|j@$UO+&<7(g6B08Czh zKn&mtn<)ke_z8f-6l37PlNZECqpui9>Y zWv<*ZlM0U;!K4%f0B>AKYpCze>>4YgmD3K~T)`^9w`H|mPAVXkYbIRY#xMjug1Q)P z*`BMw8mJ-0T+$3^h7|@&^~YkX*W=e#Tf0KrmeveF1$~znrQrf%J(!;|Qq3mgTfb^( zds=fk?g{BpAVC4pdJg*kwgpIl0Majl9f5N)sBQ9rNF%Tu&I*f=p6p8>iUFC+onAG$ zuU1>8&7_--x&pN-Fs|z(%vxRr%b9JR$lOYh@P`PO8~vYpRjc>Zlye$idcJ1f?s_|x z*q(>LV_)%3BgOgKgV2m%X*1nbnNp3|@Uaczhv7~-00*t#luYlR9x8Vv0wHzR(kJSCGM zma2s|b-~dDLwuSUJr$|fMau-vla{T-MIIH7z;SW`TNMpZExU2BiUQgk^MH3PuHA2e z&lwg9c0@BsF-mrYB7n%$^RzQ550sm`A_kB)y*uDav0alazNOrY+|fvn?&pnk6t>dP*d&DcbT&=~LeU%Y;tDrOBG-EaNB@ zdCVAQbD6g)BUB)kzH!!wg#>(N`X+S&bq$gh)Ab^`F_*5WANkuftu3tFp zpb6xr$Zk6SDq$h>B>)(jNO^*DLx6;22l1KB4#A8BuAC=DozfezhtUtKz6^9}^RLK)MZB0w6G(&ST>T1$}>Z7K-@WVlIMYfbJOLBeEO zwI}^_QX52L<#dY8Y+h2MB#4zzXF$|5y;KAkYT54qSX3{P0Fyg~su`d8Nt(q9t0(Pi zSfg4ymdda?T9u(NH*-Sgp=ou#Q)T7uXhzvB=d+--4o`tMQoQnYu60x>3VKyUO-fdF z1rS+$Ds%xVIiOm1y_>hpmMQX?_CT(qs1Bo4fJrgOv0TJJtwd0O9+Gvk&=SxV)ygS5 zCfBXd7Xp(3QOmK!I&w=1V-Ddwguv*Yafx?CTBgQZuDj{djBE`dn5cx@f+g;7`rOM2 zf2*FK;siVJHjwh|KoIoytI`K6Da#ak37B?rxEr9V2mXn~ttS7C`!*P#?EC?-9 z%mJ(-vXUhMw;hTttxJybAj~^5C`9!RaXYp;5nM|_VWSDfDCg~<%(lyDl5iIoX%uO<8{`SsY zGQ0LcEV8VXvJ`Zs-GV>$L8PUiBGuydK`q*1wGS%wZBa|HP?TbQkm8-0Og6#Y62ZPD zkeu8(=ljmR-#zy*cVRp~w#C20@ALV#WHYG(v3c_C?|X>+4z6r|m6+`~UB*Sdf*Sxq zUqaHSAeB`?6&4_nW~aY`0s-%lOJ!WnJVrmLjWi3wM z`gDb+WGPNh4(HgMk%TolGlyVtE?*Mo>S9cyM|b-Lizfss#DKC?MKgITPCL9j`ENgF zXvzt}^*HTLs+=3Ak~)G^B*+E1fXI%7so`)iJj{)7ks*p>*(k&AV!~`76y-x4ABs}V z553z@2}r8&h19-gIx>pWHH;0OVH%A_un`XGsLF(5u^7X0495jXM8KTYFt7reIcQV3 z94TmuNH(ynYn06irt}#cr)lD+n>$;x=ZG;xJ1h0~M%34Vz3T7-HJvi4q05TEk`w zrkPEZiQbF_3<6;piv!)yCBU^3<-<~pSU@=1S+Jd&QWL2UwSrbc4dxQgb z_Q}oOnlPUOs1C_q?*obnodj#XNjO!+06U9r3e=hqpP0cl9hu|0Dce#KzpXGONFwj9 z(;2#wClu_C+@T`dI`az9s&U#1NU#EC6ihQs1Y_@t2N9S~LYrSi5MUj(B`Ct_&IBD? zp4Z`O2is&=#tLks@)9?z69%u>_H7{$H6kM$zF>*peX$u1hdB@=2{-lg&H})1t=WuFZ1NL!Imq?kq1-uS9MjMfrpfaf=(nHq8 zrd1%{%RhlUuTv0$Q(A2efb53*j5HR~)0kFMYgSXU|J*O*sCB={J>FgtPl>Km?W7D0`?A2-OQ=dAz2NpfNOA)88+ ztZO&l2>B21=})bkIJ>y_^L*c_4?eo>J2$^Lvh?UNZd>Mrd2=h;v~%Z^Cx3izbN%kv zZ|R|{(i4}jjaHsrzA%uy{IdDW&kr6tAKU*;{mR((i@yhQ#aG_$dtSf?mL?}&`&fOU zaP`BXOO(24HS^p;cAY$*~VikM>_*KKyXxkyT^jyXcEw zzBOHYe8-(#tH;5>(Q@Yd(9w4e9Y63)|NLjSu7H7Kg}<)f0jJ;n7%Q6m~-dkx{@xt&~^P1~5&IHef}}?2 z+UH-;lq5#!nSoRwrN?1W8m}TaT}|hNYDpLp>HYh>yvY#)1!6#%imV!(8KrGrj{LVC zvovLg;8K)!CN-PNP;m`GD#C=AkY5Pw4O0VQCOi<@8;bN(p+I1e4Lr++1ODJ37YuR1 zL8|_t_jxHEiFq!Y7_FxxqbOa(Sm#)_TrM-^Fr%RY8yp%MVgn&I6!Mb@zfn;!F#W3W zlttliB%mQ6Nyn0=QWhsz)Ru9Sriq`blZ!%wTVF=9%`6Hml%WDuY_LHl$Tr6lC9+bX zh>ZqJHR>u8y;&3J1QKA89n*r;iyGF9qNZ<-Y`ATFbIPQSg$T)O3EIGtRSEWF4J@+F z5jNc3CntMj!dwcV5+r*)3S{CJ%dm;cO*|2)?XK7K>Vg9bT|IfxYF|H`x_H{ZPPT-=c=u90&f z;G~+@>@shSkzyhmF)e|*t3+G2BUf88xj`MdTqWAF9l6?)$ql-fT;7dq5md?hahY6tE_%N_LoQ6W zl8IQ(T>o|bIqw@8-^veD7f#+>^*wWgnwwmgzdC+AdNUvW7Cznm;-x=!Jmi0D{LIgP zKl#$9yB{4pvUCcbICm~hqxo;97CyRNUG2ZNJ3V)*()Z?#J;^;iU8BN>S8AV}Fa7e_ zogZHfe=I%U*MGJ)AO2wO`hl;n)WSQi{kHSy%cHMNc6Yt<_WYld4^Y0lPaLhh|894& z$Jg`wnx}W$uC53fT=(5QM4bkGk6i6L3ob1^{@3?K@9JfxHnsiO?aIW};qM}Ar?(yM sfA8=L^NzB@YnO-1haL`irtahx-nun*!nzqIN79M&!wawf1Ba3up#T5? literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/button_hover.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/button_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..7349fa6823abad5458a8167ae9fbf277a2a8ec05 GIT binary patch literal 3084 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 Zu;j@;^my%xn53RlPXeu$Fex)w0|4|0IokjL literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/co_02.gif b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/co_02.gif new file mode 100644 index 0000000000000000000000000000000000000000..a8859085e85ef9c32a04ca9c7249ce88e5fd2860 GIT binary patch literal 141 zcmZ?wbhEHb6l4%&*v!E2@87>4KYqM^{rb4KYqM^{rbguN9(XC_VyEwA;|sG6@iDeL&WYuuX;|KV(1%jzb`pcmv& cpdr=0WJ%kC5T;q4M;Lx>WSDWqg@wTy0KYprZ2$lO literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/co_04.gif b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/co_04.gif new file mode 100644 index 0000000000000000000000000000000000000000..cae50cd9274fb127be4434899e5c98da06344414 GIT binary patch literal 142 zcmZ?wbhEHb6l4%&*v!E2@87>4KYqM^{rb3+9}fCCSzQz+iof;tnYRk+z0c d4mv`tPE(6crU=c_Vz^@L;3Le^pu)sp4FE1`Ir0Di literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/dog.gif b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/dog.gif new file mode 100644 index 0000000000000000000000000000000000000000..65a7ad81a81ee9c796890a2c30665c5923d87d95 GIT binary patch literal 1908 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 UZGT3a7QMsT%d5*i-P?HhANjb5lK=n! literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/fav_tab_active.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/fav_tab_active.png new file mode 100644 index 0000000000000000000000000000000000000000..e81be9c4a77f9f50cbc55eca86182ff142613ad6 GIT binary patch literal 2889 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 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/fav_tab_normal.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/fav_tab_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..52cbe0960f903f0dae95f89676088c0ffcd6e915 GIT binary patch literal 2867 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 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/fav_title.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/fav_title.png new file mode 100644 index 0000000000000000000000000000000000000000..56c110391df94ec8779a5fa9fc42470705697c07 GIT binary patch literal 3553 zcmeHKzi-n(6gDsvMeS4;K&mV=un=G3w573}wjpV0q^63}R1F&!`;u6-eeU_HxD^Ai zvGost0sa8Q&cKhtz(2sif&>y9LSjL5Dd)4DCZef=M7KmrUe51*-@E(n-IMQ8W$pGv z;z~jggo)BhvC8Z@_MN(Tp8Ym{ecfl~GF__Eb=;&KNRW^>a07`Y8@5mtL1TCO1JW3H z(X7>Jy}YXG*p^`sBm1_?(1M^X_%7795EUD!WjZny)ef8&N3ww&i%LpOZMR%KitBfh6(}x|Nf{N!800v49B@r)5P} zl6q=3BhF;x%#1RtOy3ZdRB8^SZh}lInVwVAikhAiqmMM75H(^n)oO7$O2#l2Hv4LNn(C6 zA~*Cdx4T0u&TQxaS;$5X^*~xqgWh-$UZgV98~D&=kQ5+1rVr`1F~wdR zyC);NZjSFwS#qg9&GH6*T{w^1MaEQ8={BKxfs0PAez*NdqCXgaN-!5Tuy&Bv?n={R#TGVlU_F1qWo*q!#L-iW5iG^3QWU=F^Uq z-0;|WtRZ51|0~l#ZmoCU)j}v$0kdLL-REM28q4AAT(ZDJq>{EM)-_17S_{1 zx2Z+d6!o98GF+{*B9D1TNn$02vLm^Mk|_=v$rURxlpV=6luU8ZNUm6kq3lSmp=64K zPLnHfd@Vu_dq3{5OV5kM>nH5ObhA{<*Zfb7!^7`aC&$LdCJ&B|R>#N3SC1Y{k01ON x4?izl%0B+GnBKp0wEynSx5f8Q@7)(J2vgS=em?v7wisNxN=s|S=eO=Y`~wYK)f4~# literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/head_bg.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/head_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..3613f89188eb17e526da6782b10769bc36de561f GIT binary patch literal 2836 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 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_balance.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_balance.png new file mode 100644 index 0000000000000000000000000000000000000000..94fba84330ca6ca2b253e3ef47a78b78f490ef83 GIT binary patch literal 3090 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 N002ovPDHLkV1mcyq}Bic literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_delete.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..33a2eedea3fa621d0a7faba989ac78a2aced317b GIT binary patch literal 3223 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 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_down.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_down.png new file mode 100644 index 0000000000000000000000000000000000000000..229a1856001c0edc977bb3fe5a319c873c322b87 GIT binary patch literal 318 zcmV-E0m1%>P)NklL>{q30v`a6W?7hj4HaaS(Jq z`~ZbR?z9+(*3;5f16jYhl*SQgmw|xllkr=eimrE`R zkT)w2X9!V9n5knNsoT;aX`&<)^uv=mW;3B(593Ik#uFmWN@wx8XSzgfpp5%v9H~~9 z5Q=3Q1G!$W(3nQ&D3_}Q-btoKiQu>~4?6)5h#yEljqU&7qcM);`dELnJDYo03i&ok Q`Tzg`07*qoM6N<$g4)c0hyVZp literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_edit.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..aca3e860f1dbea8cc7cd415b86614f601ff44c1b GIT binary patch literal 3053 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 m&Kspw;eQwa*k!--uK@sA)8HM>HHxDE0000~qnH

K!L+~?akP-|Bv6M`|#?yEG@pM_K)K# zyON7a1yewiCVQM;%Ck3O#TPu<3t3i~t$X6kv?uZG)xGhmXS6ome*aphJMfKaMs~jG zq8siXN_V?AT6LBdq_G&!ojCKYc8Q49+|#xWGuGTSUN8JaZPR_Xcoox6f(Z=Ej#_ma T8AbgEx`n~h)z4*}Q$iB}VQf>Y literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_favorite.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_favorite.png new file mode 100644 index 0000000000000000000000000000000000000000..8c5972edab653a551dbb7f171295a0b3c114f09c GIT binary patch literal 3287 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 VJ8FRKlBfUx002ovPDHLkV1n|iK^Xu5 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_forb.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_forb.png new file mode 100644 index 0000000000000000000000000000000000000000..19bba76d39abe486ef20f542908309062bf374f8 GIT binary patch literal 3924 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5n9Wp~AN+NuHtdjF{^%6m9^eS=-fVvqNZ0suv5|gu2OB9k) z(=+pImEP~(ucVNfVyhHx>TBRz;GCL~=}}db8eHWUl3bOYY?-2DZ^va*VFffGH?<^D zp&~aYuh^=>Rtapb6_5=Q)>l#hD=EpgRf0Gw!Z$#{Ilm}X!9>qU&qz1fz|2^|)L75h z)X2=pL`T8Mz`#P^z+B(hK-bX1%FxKl&_V$UlHCStb$zJpw*7iAWdWaj57 zfXqxx$}cUkRZ;@VD?klTNrszUP+F7&HaR6(KQ$*cH#M)MSl>|3P#;-6FeHL9(=$qn z;o96Z~cnI0-zQH{UWd$6rBYb`6cI@QE<80UxFoRz>}hBK!5w7f zSXz>iUsN2BUz`aFN}xO_gcWR3lC2>A1al!l?wC^o;X$}LnV@jC%1O*iw^gdpO-W5l zEX^rV(ueBM2gM3Zi;X_2fgtmfi&7Iy@{5ox2u>|TwE)E|m@L>VWX&MMN-|4wQjv^; zSqx1rB)b)1o(&=-LyLj=F(kDpx0qTs;WXO@Io_?DAwlJw56lP2C7yX{`QT)ZswUGh zrO36SBr&B3mJKlFoij@+amxk)OAc@vz+rkoa()UhnL-jU7Q;)5a2XzwniHO11S~_a z>UGUc%)}=jS_G2?CkPvG(n2Z#fUyA)0~Rd6GEE;|s6kT`wEUqJ1r9A*84fdd)Dl=o z5Jis$7g50kQ#2Y}u#g~%9t|#{f(fQ*G`L_PK@>e2Tto#EOcB1|;zD$bQuBcA<8ol9 zX9L%PxeN@9t2|vCLn>~iO!W4U4istoZ@t)rUpGXyP>{8gyV<%m$k~Nc@6M5<5ncMP zR_zjcqJMFLPeIfsvS<6J5EG+>25Sly71u8@iTX3XTN7PuX+$K zvycDWLzzo9^V>BRKUH!u3ont8Z95sNci{9Ell%-XrAxUls;Ay>ac;@EQv3e-WnsgJ z?O!XR^lj86<@#UmmlA&R=7&W{2k*I$w`c!)G%4tYa&p1XzY5PIEncrqSZOQJe?8>U zX89`_YsFGu%1>0v=d^ep5ELJH?Yo?wZ?p9crr+^w-~2Z-^~7p_`@ ziVvc1vu(|pIk_(^V)=4`n2N4jB0gPe`}Z_BHJ-kb^X|aHZ9Zum{7)SU-V@8rrd>93 zdh~0H*?%}*pU=0vXFi#sR3_s4cc8XU=e$i<{_FO?D6xNcWm)>8Z?mSxFMDJ=Goi_* zuHfm{`vG-@Zu@WF=iGcc#zFV`rFZ7JC&TwTAKT45|IdSF24)7k?YEEAl&dTU^>aO4 L{an^LB{Ts5eSU}G literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_graph.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_graph.png new file mode 100644 index 0000000000000000000000000000000000000000..265510c11a4300d74c62d9cf5de0c89acff04171 GIT binary patch literal 280 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 M07*qoM6N<$g0nTaL;wH) literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_recover.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_recover.png new file mode 100644 index 0000000000000000000000000000000000000000..a1664ea1946e0634e3e4d94f700ccf9c19b38e92 GIT binary patch literal 3371 zcmV+`4b<|9P)KLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z0$52zK~#9!jM7g?lW`o!@%QtmC5{QA9UO}c3d+Nn2s=n2Xw8d(k*4GzYP-x1!3sNQ z)Si-He*f^LLZ+!&%>T)PZu4Iod z!cVYmn{+zO!bY9Vf380Nkq`=n0FZ%7@z{MY9*+k>5OBF%)YjIbX&Q!MVB0o|qVVQJ zo`sD%I}}0y5Kq-k-!{j`$C##xWm!m)1b`@tSeAupny9Ku*Tr8|Y2?#`-|uH>(*v9O z$xV@b%`%JGQ2=^d-qLxYpJ1?tuRD7cpprn-G&(Qs(brnyM%xa<-SxCxJ`X@F8fP&( z%8}*<&Q{y}e4>Pv(4BNJy0Yy0ICo}lk^PfJ5Ci~JRRv&uecc%d1Oi0A3=xaQ(RH0zG)~V<7pd>5N&|p3)|`P- zsl?vfM3!ZG+Ilby15ML_{eJ;n z*Eu{qL=Xf9t_%KLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z0v$<2K~#9!jFV4D(_t9LKkx7No25w|N}09YQcFw_lMV}{9RndMW?=15SSkjB3?d{f zf--|#lzItaAayA+4}q6j2%h>wAV|eUpAXOTeR!3K z5Q#)aW>#yuD6)=Mei;o0gWUj#2pvPSlFep|J{?1|A|i+gR-w85#dj>jV5b7hWnh|$ z5(S1549lbhi(4nkwQlkP5kWF3vM7>b;Bs>8FibM0P+}@fTj8J(+4XM$fN3WHg&~3{ zunh~-1ci_>4FEn*Jf^G4Wb)AzZsv4B_+-_8!&{uXM_p?x&dLCM^vJi38l?#a2M0AE z6bk);U)`bM)M=cB%SdV-x2J`4A|+Y|eSLkJAeYMlu<-IWjc42Pa3Wbtd~q*US*1S0 z^z`($wh#WCp{eac0bI?>LLHK`s1Nk(Bl!J(L?nM-dVYhZ_KSbP^<*7rIR8-Hy!$|3 zV>len!>#*&a5T_KCf={XPCCQ5eVwu06{OQ?eT1H#9z+CJYK`?zQk}guc^Ki$!}$=9LLc!@Or%fyp7HA?#X@1_Iar|?886shQfDSW!pAN uMCk499oh7pEBZT^Ek7F_9vKLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z0QE^kK~#9!oKiaq!axvx8zK?G7#1ReYz%B+VY8*3C-5>JB!{uE_XfFupa?b*i8g)+ zj8!0J$4?yCYTtYFX5I)QLbY@v2>>>WlfVz<)X7FGG$~O!D9Iu$uwHH9OV0vxt^^Ui zkk7j|+sW?~NH=>+#H|AZKLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z0g_2XK~#9!q>?{N13?hQe{)7fv=I~w8%2~Lq_yxvh?Q7N%J@Mng>(iR3&CEo5NtyH z16rtPq68bUQEb$^WbblgakrO?r&u_!%#qfyyA9hxip$ds z4-I4q02(8s8SvrOsTNC%0948~eHx#T+4nabkt{*b0VQfCz|r^&iA6U!(0g%5Maco4iLyDlCT(Dki64b|v8(U$ z2G4|eenixYJAV}BEm*CI4#4{A94({K@|D+oUPf+iXKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0009sNklZkf`X8&BA5ZIbTUZ6ZEan<)^`0^dE1x1e{VLNhUelj6C6yh!+HbT?R}NET#ki z&vqG*1;h&izel3UVI9fm^G9_iTSg0D@7brRR@c2ob8DZ^rDtVDaPr&&Kb`v_a&v^&y$tp=<8xcNpOVQZ3lMN>V8Vb=e9D~)67t}7lYL?rc-KFy((1d3djmH8Y%{}qZ$fFc4nbB%HzBk|@ zo?PShQh~X}EOQ^fJ*uU$qNL7Gd|ufRYTLE5vs*}JI=5T+bG39x2t2^6T8(saxVIho zp`Pl4b$-5d`J32>`}R{wWh8*kL!Wutg3qPi80_N4QkfkNBQ16f+0p}4Rp547SS_oh zOEvmC?0k9U4vE-r-tABI|D^#~oH&>+WYcGgl?p+RnL@cpERm-uOO)#xVu?J3a*?3N zOtDg-kWHUioH&>U&^}_?*C+q6l=CL4y7p_AzQ5@0eA3_Qv|!RpBIl-!=eZ$pXI~-Md?IcbG*cngDX4 zaJ2THUkHVxTz{`m+Q@X0#piF?f8;R0>gi)AL@jj>cnFA4I4U;h{uuzV>Rwi8>}E9p O0000KLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z0Xa!TK~#9!q?0{M13?gmpNl!7QCtXwE7DoSF4$S860FimYI_S?e}G__-dgOe0#*@! zfdmx1!pg?RyU4O+Z||}e@eE8FJ6#zt|vDc&JH%FsCEdUIYu~%j}Ak}67D$e>v_FFRnXcMp8 zLaNQqAc_FE==#fN@T1KDj4^ngx6=BIG4m@p-QQqu*O{64_GP(#P4W*Zr7ESUm3BD1 z>;dq2-pq(=B^V4O<#Ks8AP54KDjKLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z0xL;GK~#9!jFL}ClW`cwzx!?P`?^)Hwk^c5g*p%&s1e<|dNRC76rv=O2pu|TbO}$H z*9Bb$L&$?*9lRDq7~KLlVKQ|~8_2|e+tT@Nd*}N;@B8Z%K75})HqJQ! zAiB8d1uza^5I`q@bpRg#%uNgpl~G4F&N(6r3&V`DNKYsvwgv)1qb#$NV$sa(?C8l< zO5>c5JsTNWvIM-FpKoT2Z9VAgb9vovdu_vEE@ymRUaoM?{m(~7PiyOph@N(LbxAjy zn(T&YqSjuI#~$kF5Q%8qDgo1pp0u^L3S^q7=U{ugpc9Q*0UU;5_(Vyvk!jZ36GTa3 zMATxLK-2X-rBvcp@&8&Wl}w#z-x5GX^T||7``-x3%}t$%-dm19L~|>#*ejpU=eXtd zUbw=+!GRH5UDdMP{jta2cbgw|`wlPs!OPj%Va8bGPH(Rm3{+s$&hobfA@p~Tvn zW>=IOrH3z6oj5O?s*}Y;K6(xS08=wF@;{&010W7yDH|G0%5u}EfJbiVynW5~b^WMP zIIT{W)4!wV0QEHRam(LeXFs(g)fu`MKu_Cse2MQ@@EUQErF40+5*;N#68nUD& z=L3HR0Ka}p!?Yu*D*ylh07*qo IM6N<$g3Ovz-T(jq literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_show.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_show.png new file mode 100644 index 0000000000000000000000000000000000000000..c2fe42cb1f615bedfd2257854815706b32062479 GIT binary patch literal 3195 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 g7jm&g{+8f*08b_LCrg{fHq)$ literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_tree.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_tree.png new file mode 100644 index 0000000000000000000000000000000000000000..9eede1d9ad5d5c4667ce68e1f914a0e09825b192 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5i=O^K@|xskoK&=l_3u=i^&c|4SA$ zbghwaW3ypUXozq)(l38s(rdGjfy(aXx(Ny_3``t32d4Yamyp~4t3#1fNF5}S1Qg*B zR`X3$U}smFFRy;QKM-rz(!v?8< zyOy%9%-Y)A=OUOm6xOh92~C-)@VWbS^|=RKsz8+o1vhBao!3}-T+*9?(IrIU%$r=J zgR1NT4la@x>`FgM#uNdCOBBSG98Fp=+aTMJ*@0oB0GC6Af?f4*$!rBC76D}w)kmxc s9FDByP-y5dYM40jqQrC=hXzK52)mZZgdWRNzz|^YboFyt=akR{0IYs@=l}o! literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_up.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_up.png new file mode 100644 index 0000000000000000000000000000000000000000..2524ad3f0f9d6409219abdbef4cd12be3c80ee52 GIT binary patch literal 1499 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 IM6N<$f}H=(_W%F@ literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_warn.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/ico_warn.png new file mode 100644 index 0000000000000000000000000000000000000000..c27aa4e6adfab76e2a9db0a66548baea54e6435c GIT binary patch literal 644 zcmWkpYfO>>6umrTN;pwhB1IumOBagNR{EpNa6Xpw`H2n8lG4)L+S2UBmMe3W`lDu# zX|397b4i=aN2dHRrfsJ7@C67yKn(<}EX@=%Z(l#|x##TeoZVAFD3biyd^Q01rzFcs zYIFaOFN4DEl7I{VS_yGbnTP;%@ffK_Ce4vaH8Ihey1Le?s+UAk`kVpmEilyz zt9{_mgRL2?jo|v2uTm%$-vin?Xr#40J{01Un-<4I3k^*)v@mB4;2Fq~$Zq2IjcA6; zN5cR@#i4;{0yF|nbDaiwQW5cY7;rumt$<$vM*%I=$#1Ej?&)yL50L?23*>JlYm~TP$8~SUOWrIUxM)lpGNxEO`&!WbdfplqUo?LrLRgip^5GsWR+h=q4 zXx~tmp!4Fn^FuKB@_%Br4<$37WEhQWh&X literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/input.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/input.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f0751cd7d2af758a96d98c17e3d18df0e8c66d GIT binary patch literal 3586 zcmeHK&ubGw6y92q655l9s37ZBFJdyAO{?v)QDYKq#FUUk8*ff`r^(XI&USV}w)GUZ0+ojnH zW3huVK@i3YGr2OeL+rb6WEcA#k@r@ZIY9F@TEPpn4G9u52A)S^p$Y4#jG(c+w1zYW zK5JHMv{t;N>bRMJeoVq^It(oc+8NJ*`XZv@JgS>^TKfLtr6ih0TAG_I%0(xO8s^Lj zL6w!+s=l(QPaD#i(=p9c89@_KD0)rHc2zGeabA`E_a6gEwr6v_MIVFZ4>2yrgh_RrSbLYc!Y?PK7 zlsYN^?RGoSP9-p@gXHw|G>{dbC~+1Mcb9Dny}0d;`xF634!Jrp9cp4*^f}=?Zqc+P zF~1m+8+wP^X%UMv8#+K1Y9gDuAel&l?s%p|*{nCH+kx3`s4~+Vc+g=G84w=RgLE30 zVz+^v?U5Zf$9JbJI8>itd3`}UShgyiPu8Ud=#JoUzE45+&VB#Vgc^?7Kyh$qtkOd>BY2#uFkR|8so|t_I})Em!7AwSNGV3saD8ks^0t2*K1=pL}B-Qf4d^pGQk~_rKeG^lWHl?DO**AM>NvUw_`aJ`OjB j9=~|-b?wK8`@*nrC3Eb~#^}dy{;jN#pUpivcWw0-*%RW1 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/login_bg.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/login_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..0e1facd1e6ad0e0f929ca53e2104e37964aa4240 GIT binary patch literal 145515 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

d1tC`(BkhU2KUNkcgy&FsgzG7!U@Z7Up=fu^M4i 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 P$094KBvC46^6`HF;oC;1 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/login_btn_hover.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/login_btn_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..54cd6f132e4e512013afe61006c1f685431e0079 GIT binary patch literal 2983 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

)?)o_s4Zt5y>)z^DfM0I(Y%A!$}2$ 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 O0000BXq3* literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_bg.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..6ced2784d2931d00d7b277fef007f79dc7cfff0c GIT binary patch literal 2857 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 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_btn_bg3.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_btn_bg3.png new file mode 100644 index 0000000000000000000000000000000000000000..d5742a2f8dd26f574dcf2a2c6a42ddb03a5b2eaf GIT binary patch literal 1996 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 eYnSUO{|^Af)I@C;#CoCt0000w literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_btn_bg44.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_btn_bg44.png new file mode 100644 index 0000000000000000000000000000000000000000..5f034436683a78ae04c3167511b92bf01b772984 GIT binary patch literal 4594 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 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_pass.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_pass.png new file mode 100644 index 0000000000000000000000000000000000000000..3561328533db8da00c983414fb4d334f9d98d0bb GIT binary patch literal 3662 zcmeHKUuYaf7{9g(@gOQzK`Yi})d$hr+1pEEZrM$}-X-l7FC2Fl5>RU!^aDzHs0Zq%iPQ*R6LmxScpQ-vrOBSJ(Ul5W%l2H z40tXGp>rx9PHL)D=JJ>zZa|O(DW!=+8E!BmWCo=nY2bcN62)O4J^(UeDm^TxB{@CJ zMIU}7$tgsil`Dm@C>}-r|xdVKA%A!NH0hZSnw1s7>(t^plR0r)50X*2J zFneplatV?-#P)g&nl1_wtotU>OqD_!EIJaXH6b}SPaBxHW$YThl+5od%qhAihwBW6 zq2xJ}hNEz38oti53GKSddnp~w!g-VOAVL6tS7L|)IthJ#jUY%dX-iN=2RajUaK+w$ zs~zl#>pGvZuH=Nv&SMP`%l*GHZOW~*@4K82rOIP=4m4V{XK_&G zoiRpEC!-#PI*E_Lzx{cGE^O|tu+9H}u{S6PB`B@72EcYBe8w6J>uI3X)S_yN`p?xefm&CKJm&2siIwQe_T=hHrZ}i4 zSFA)=wkKCtGQ~kXxnd={vOT%Fk|_?ll3dC4YZ0>9`*D+9dR|MOdWl__R*HpO&HMK5 z7vA5pHP^Ro`%2%#tM?rHt$yF{=T=WY{rB6)?zn0B^P~2b69>;uJbCKOAJ6Lh_U$g` zKmGE9vcg-35+{w}%m;JYub oK6YsO^!c?{F8}!bEq`7oCTz6y!#6^GkAK4}j*b^j?w&sM58|8+WB>pF literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_selected.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/nav_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..9ece20b43985f3eceb4fc049282a68d8533114c0 GIT binary patch literal 3652 zcmeHKUx*V&7!MWc8T6%Ci@vzs1EJFFB%AxYY}8zGo}tZoCOPilq&V4~OV(_5*4YW! zyFS=I6uBp{QV^l`p$~0QPkkwcRRU`*f6OG0tE1OC4{J;lhEVW2!a%owgg3VtTRCeSLo$j z?O>0L8q`E>RAJ(vS{`|>t9#R)u0$zihlJ&?-$eh81^^i5O<8^2} z%s)*+FE0p{msVQ?V7uWzV~vING|*~lK{W;a=Sdl^){`O+d3#AhCAzXbxw?`m4C=`h zD$$kg$<>uiVNg%5P>HT=Pp+-c++>%Y%hBuavJ2DMTsB>DR|Za| zpBYQ^Wj5VBbmw?_So-X>_qCTc-@U&)_V&b_dJZJ}xBvV5#jWa3?_Jt@CM})65xM%# z#LCg~?zc+kPHj9^vj;y>H2y!qb?{U0Cs_WECQUmjgrI{nEv*Vxst YyzlV$Umw2L@a}cF@yYD+*pWB>2SsfIxc~qF literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_close.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_close.png new file mode 100644 index 0000000000000000000000000000000000000000..14dcdaae8afa32f68d659277115bfade145f5ec4 GIT binary patch literal 3950 zcmeHKeM}Q)7;goXwMEe}qMM87kqk^|uOFarwgQ$Ss3oOTZNf6W-o3zuws+jU*aH&< zwsjJtfn;$e&Nx|yGg}t61v8zShVq9*{6IqD=H~qPWBP|93r1(==H9!0P%<$rng7wG zefr+>{C>~-{@&+(a&MQbdP9chRgFre%BZR=cO#o6f79oq-~C;$XCSi-I=rx!tA`;< z0ID*E^8u_XKs5k2pqSR?VPHkzQr6>zUgu_#<^l#vjxk699-&n#Yl*~DbQ6G>4>Yhr z8$R*vSsY^-8@{d3X>{^-(8yM{381#E+C#TB(Zvj2vQA@_NJJ0-kiw*ZKPZxt4Oe(c z^k05V;FuBun{0S=QeLMEvvUH#3Jhk0Sx*~RTd+cl!BS{mZ7#^i%tm7oVO&F4jCxZM zX)=?hA}sd7*J&`Tz|@oO@`_kGG_v815b`8JghC-h$YS7x2EtTaTud0vgxRb|5qhyT z2q{S)6mw*XC`UOEX@TV-%LOr+lk#yb(1zp4kHyFtI>F7i2!4f`p$Xsz0T6^DVKSJA zVgeQvV=5!P35ntn#7GEA%rqq5$U#nQ9 zRnf|1MaU4z5ei({r)c)Xgh?kQGy$~N6_j5DN`fihHsGs;6jT-+6DTnuvaAI*a)RjM zL{^p(`DKMMD?^jfbt=QCBRC{TF+%(p{M&D5Ve8CZH|iWp4a~sqqB#bY zX|#Z!K@NqP$UVTnjT2B0c_!8opxEd6w+L~sQV>?9w2~SC+KuQl)L2kYBN9z5R!y<~ z^P-HR){7#K^UfuSD={lOC)ccGiU-Zf6<1%tu?P)m6>+?yHcxj`}RG#>d5+bDNU=ruz1(5KP#D+n3TG9uXgAg>G$5l zJw2oAtYLkc?_|lIzxkg|i4CSJE%UGG^1BZn+?{df!?mGHi}xMlBc;nJiVBa6Y_7+? zo_Dz8myWl_yL)7k|J@lwX_a5zeG_KD5Sw+eN~J6!hr+t2R4cp(4b{p)MO zZ!cK%eFQ8`@4sohyy*Q)J8m#OpYM-H6Dz#FN5B2Np1X182OV>I$JqIIBK_m%sjYQ& z7e4Cid$^$Q=99;hm%`!juDzzrh|zUO9TAQW3=Ev<>>OOn*fVsxop&smpHb)1RiD_8 zKA!xwWbEoyw`28#!FRQWyJ7sby!{u9-qd#A3g*+^-rIGD-dMPB;RjtW=WeAe{OJ=X z?k#yUyfSx{)9EbiK9-%Gt*fc2(T$9ZOne!>b#LrAy=mjdulQx*VBVGfzs_ZKr+L;K hd6`X1NOaj?=Jh*DsT3gc}R;*TE}fVgapNM25upt)Q25ZL(n)p_=YqF&YF!T zZI*Xb9rq>Z$4Fk^VQ5CP={ZpEAu6;`$Fwuz`KJ?6FpZ43w_29VP9Am5?IVKfN0o+t z)YH?3xVaJ6Je3jj5ru-+w`^DSG9u?y*?<2r5CtAWdl@m9RI^+a@|YlDMN%Xsq04J2 zVKpVCR+TknWm!;Uc^$})K}t>}*VUw=Cf9}VBW}b6jTmjUR@e&Du~A0sQtGGx42MH$ zn36E*fMhzI2C@PaCBY&R?x9Vgm$2O>pCaHWAXg`*LrrW8J|}G90nLaa^9v!lp^vzo z0kJrkB%69 zG@6i_8_+H$ZWX(xFD3K)3JaQ{tHCU}h+e`#Z8)%~2tow# zcO`;oV4Be9*9n3YlZga%bTFM@iYxMRu1T;@Mons=392Y@SS|lN*D;?qR&v*6=dpoE z-~C^iuH@Dx_g&2gQspr_2Rbd;ZOqGjI>yWyr07v-kmwlv?a!O^@M>?3bq-zwSFl%g zY_Kv73iuLoO0FVrAZrg3)e=&c90{FE0p!!#f-g%NpiJ9zNu9;+tg648XO3Y;Ea?K=D6f~DBQeq}Mmun`OqM+;KijS{F z$Y$@yLw4!;5dZR)U6|xjA=mJ}w|-w-Y%WOm@9bpHZlC_jo-Ll<&MwDKmF%&Ce|-LU h{`2JG6?_p}h`l>rDjz)C|LWhiO2tay{gdY}{{XC-&(;6{ literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_leftbottom.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_leftbottom.png new file mode 100644 index 0000000000000000000000000000000000000000..5c8a5bf192fd97ad1e1d79982e12924adabd5f94 GIT binary patch literal 3693 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 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_midtop_small.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_midtop_small.png new file mode 100644 index 0000000000000000000000000000000000000000..d03681477806b6177610620e88263568e6fb8d26 GIT binary patch literal 3549 zcmeHKPj3=I6sM_CLej)P7xlDRj|#Iat-`vrMWB{M8Ui%s=&(D$hGl0vJA`d-dTZiG z(8QBRV?3A`6Rk)435+Mdfghl;b#``_Ke05J*c&A9n0@c}do#az^RjbL*?PPbyB&)} zB1@&sLY3JC_BEoH+3)fD(r0FF(PD$vaElHgL6Mw}n@A}2U>j8t)c1D3A(esGje3JN z%1;yx_Y%;HNw__mp(7D>&9$M{MO0{_wqa$(U!T5+f}v-{ot3gww)3cCZ0-|O+uy2d z`&})gi)*Vf)m0cl4^b$%J=1a&H!E^ph5h#)15w~1w3`+ENj1t9A&&_XmJ@P9j%(8W zl(3RYq*mnn^71`FmZUV09)Oe-Po|ZmtR&My@DW#If=cw3QY~x*>DVYMb||$K00x6W zVvtH;(gw*)CIciH$a0)T#GO5hLN{(XcRUK8qktTZ7&bMqC3u{$iTgAwip(zrI`9)6R6De1}?N2L;{4zOd#zJrr7CV`)uUU z&GF+YOE%S(Szb@jA(pL5&WZ`Gc2;!bI%>hbNktGK zfVV3lL>OycWVJ9a^T`+^r<0;fp-#eM@V7s2(7oy2D(f7)2BxrA zG_12S^$Yk6a!RI=*O9q{3F{$eVv9X!oaf&rp_dng%1djk0kGZhpRvZmdKwruwV;}U z{&P`=t94Q2A@4j%sKiWmF4s&lg+X(Yj1 zB4n}m;{m($yo(*aVi%@VsgSF?Kbj|}r)!Hh7O%d(CLBha$!F14`fE)5zJBT9%b)tm l$?xO4=9?GS^9PZr6j|85a`fTo<4y0vRVr>3-adNz{0})G&`kgU literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_right.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_right.png new file mode 100644 index 0000000000000000000000000000000000000000..1bbbb320b9766fe64ebb889b9bbae6a63345ba2d GIT binary patch literal 3547 zcmeHKJ#W)M7*3IhP^3;sh>wAjSxGK&`W4G*2}w$WNE9Whnt`Eb`;u63eD3+8xE(-Z z;|Cxn{sLlW05KqS;Ri4=AvRVd1m%3T^C8+QNOVi27(~OMGC*D2z{of}IL0am-!ofn z)~-HMbTUXGKPKf39FFERTb_gTK4w6}UDM7>-`~EIfNA8Vz13>E>J)L$+&QASc~ooZ zM}0kKNL!l;)l)dZ05b%*u9lQtfIT6bZ#(B_*fiq@G^O zg4Jv)yDG2AD|dmMPH({UI?Se%nGGc)E13-tex%I=P^r;T8l~+p9UtYT9%GII;b=5U zjj}01yD*c>uqGYSR|PE_ORAuh>1mq z0*xo66o#xvs9Ptl=}XD|zQRB?bR}4)7zUCTEEbG{p=J6yD;Bc5dC5x}xPyiklVFH| z{;ot270wd+{5r*m5jvHii4SHI%y30s!8Hx`$(YG3JVg~H4y)y#=Q`n2Cra+R{5-ZW z9k~B1)0y1r^u8;_K&m3)=Rju_yF)~o&&HSqgO)vp3>qDSzx_p%9iHuN@XjG>;0*S< zP7GeAK>?pa&gfa>Eo|)(%6rJE*zy3G=lOSOiqe{D0DL!sXS}iSo(9KFEv%-n z|6G(2YF!k0#JflmDKVE_$TgQtQP4uJNQt@ZLaw=Fih>q$MM}(N7jn%dQxtTbT#3oG z2;2Pqc*HL~ZxZic@e5O?QYy5(&)SdQzkWWw{^|Jm0PpYD<^tE&n5r> literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_rightbottom.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_rightbottom.png new file mode 100644 index 0000000000000000000000000000000000000000..5c32a9f146e237e73471bbd9781ecc40ec9cedbc GIT binary patch literal 2973 zcmV;O3u5$%P)KLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z0Ln>3K~#9!+>|j6!ypVrUkMRImoDA9wdd;5a?Pksz+FIc(?9~sRHQGn_~~PR!8neR zGz`NNcmOxx3S59Q-~bC45g{kTfoBUQs!A2i7$Yl+Q<6I4X9U<sa8ehP`}d zRa6p8R<_vWY>M}wpwf~xtB1QHYJeI>AzM|>D1@_WX3fn%p)F+a@Xzs2V4nd181I!C TuF3dM00000NkvXXu0mjfVa26d literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_righttop_small.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/pop_righttop_small.png new file mode 100644 index 0000000000000000000000000000000000000000..983ecc4a3c12d73e23aed97ff8c0957c9b240faf GIT binary patch literal 5186 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 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/search_active.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/search_active.png new file mode 100644 index 0000000000000000000000000000000000000000..4bf1d32d675d393b434b0b1515cff70c63244756 GIT binary patch literal 2866 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 QLjV8(07*qoM6N<$f|AB`F#rGn literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/search_btn.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/search_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..844d01614f40a5d5019abe563a78bd24fb4ee05e GIT binary patch literal 654 zcmV;90&)F`P)*zzG0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!FiAu~RCwC#m(ObxQ4q)HCA&#>H(9n@ z+omy1t0_e);zhlQP`p^AdX$3TL4}-D5JXQNJct+3lNZtdz#kW{;!#8t578<}F)1eN zuKBS)vb!%CgI-kX?&cLELgu<}zMq-*-puUdYI*~PYeF(X5OK)Vy3vfmzpxQ?ME%LI z=X&iA%v6q{a{9>1vtzuNORD?F=1W7$6?>G#xa_{GNDaMw!)v`An2JpH-Bnk29ZD(r z+RO9pPY(w2<${Cyx^~N~KHel)P6TKJ8d7#LDPPjw+@)?^DV~j(E1{GIe6Bn_JiBxc zd$r&87@z~#1aSKb{mzOwX1ses;;OWLg_m{&BlV`qg`c8V1^O{?iA#t*KEGtv*Xu7z z%ECEm`pA~=ut&jj!(wxR*lAf!?zy0?-S2vhOyR`VsICuAC)#njJU=T>m=N@q5F6(|r?Q0I!}+PK8)a0RR9107*qoM6N<$f&}0;vH$=8 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/search_global_m.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/search_global_m.png new file mode 100644 index 0000000000000000000000000000000000000000..7c00491caa0d62c8888a8da7d0029fcd5c35f06b GIT binary patch literal 3579 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 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/table_title_bg.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/table_title_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..2586d23c56ee6d2c369a08fa450c3e216ab5c3ba GIT binary patch literal 3595 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 literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tip_confirm.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tip_confirm.png new file mode 100644 index 0000000000000000000000000000000000000000..83a03b16eb5a252245f14b73c30b01fb3e8280ba GIT binary patch literal 11185 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 z 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

p}BUAi4=Iw1|@Rtb}t z@3xhG-=(J%((SQbI2$C^;3)p;(4!g)rn_&MCtHET%i!eaRX_i;GqjlXtNZ->ybz?! M)78&qol`;+05!(iJOBUy literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tip_succeed.png b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tip_succeed.png new file mode 100644 index 0000000000000000000000000000000000000000..bfb298a60d019400ab4570b03e8a88a1a933ca6a GIT binary patch literal 19527 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 S#EL`!0000b-4Aua`h8GtA literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-down-left.gif b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-down-left.gif new file mode 100644 index 0000000000000000000000000000000000000000..1131c008fb64a7223fe472aab015ed1b1e983aee GIT binary patch literal 100 zcmZ?wbhEHblwgoxn8?8JABez!fq_BsCkrDx0~3P|kPVcTU|?V}ozl-V;q8ujK83fk yRL^zIt<7D))_3laqvp=K+-AFFUDrx8o?9IM^yy6Z&jbg*!VVv;>1Prd8LR=$>nA7x literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-down.gif b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-down.gif new file mode 100644 index 0000000000000000000000000000000000000000..84d38c2126396f02c0ad051ef214fe990ad9a345 GIT binary patch literal 103 zcmZ?wbhEHblwgoxn8?8JABez!fq_BsCkrDx0~3P|kPVcTU|?Xfn9|QQ;q8ujK83fk zRL|uVpQ?$~Xi9xNH*;s#+wVn%X7NjE@;^Ey?U7yeCu3sL+XLSB3QkU5sHw@oU=09L C1Ss|Z literal 0 HcmV?d00001 diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-left-up.gif b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/images/tree-left-up.gif new file mode 100644 index 0000000000000000000000000000000000000000..f69e7196faadd016aedc222fc4bfe9b64e63d24d GIT binary patch literal 98 zcmZ?wbhEHblwgoxn8*ME|G@yrQ2fcl$j-pTpaT*G$ulq+Pw8LK@OI~w*=laDrcICv t-)Xqeqx4~--2?W@v#(aA%sE?9ef`?Iw{?6xT- t-dwlf_xr*J92s*X)0WTjTK$o0qtKz;yH~W|wW#Y$g| -1 +|| navigator.userAgent.toLowerCase().indexOf(" msie 6.") > -1)); +String.prototype.trim = function () { + return this.replace(/(^\\s*)|(\\s*$)/g, ""); +} +function checkNumber() { + if (event.keyCode == 8 || event.keyCode == 46 + || (event.keyCode >= 37 && event.keyCode <= 40) + || (event.keyCode >= 48 && event.keyCode <= 57) + || (event.keyCode >= 96 && event.keyCode <= 105)) + return true; + return false; +} +function randPassword() { + var text = ['ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz', '1234567890', '~_-+=']; + var rand = function (min, max) { + return Math.floor(Math.max(min, Math.random() * (max + 1))); + } + var len = 16 + rand(0, 16); + var pwd = ''; + for (i = 0; i < len; ++i) { + var part = text[rand(0, 3)]; + pwd += part.charAt(rand(0, part.length)); + } + return pwd; +} +function byId(x) { + if (typeof x == "string") + return document.getElementById(x); + return x; +} + +function addParameter(address, value) { + var url = new URL(address) + url.searchParams.set("lang", value) + window.location.href = url.href +} + +// ==== cookie ==== +function setCookie(key, value) { + var date = new Date(); + date.setTime(date.getTime() + (365 * 24 * 60 * 60 * 1000)); + document.cookie = key + "=" + escape(value) + "; path=/; expires=" + date.toGMTString(); +} +function getCookie(objName) { + var arrStr = document.cookie.split("; "); + for (var i = 0; i < arrStr.length; i++) { + var temp = arrStr[i].split("="); + if (temp[0] == objName) { + return unescape(temp[1]); + } + } +} +function addCookie(objName, objValue, objHours) { + var str = objName + "=" + escape(objValue); + if (objHours > 0) { + var date = new Date(); + var ms = objHours * 3600 * 1000; + date.setTime(date.getTime() + ms); + str += ";path=/;expires=" + date.toGMTString(); + } + document.cookie = str; +} +// ==== search table ==== +var lastSequence = 0; +function searchTable(id, column, keyword) { + var table = byId(id); + if (table) { + lastSequence++; + var sequence = lastSequence; + for (var i = 1; i < table.rows.length && sequence == lastSequence; i++) { + var row = table.rows[i]; + var cell = row.cells[column]; + if (keyword == null || keyword.length == 0 + || cell.innerHTML.toLowerCase().indexOf(keyword.toLowerCase()) >= 0) { + row.style.display = ''; + } else { + row.style.display = 'none'; + } + } + } +} +function addChangeRowEvent() { + var content = document.getElementById('table_o'); + if (content) { + for (var i = 0; i < content.rows.length; i++) { + var cell = content.rows[i].cells[0]; + if (cell.nodeName != "TH" && cell.nodeName != "th") { + var moveFunc = function (ii) { + return function () { + content.rows[ii].style.background = "#F8F8F8"; + } + }(i); + var outFunc = function (ii) { + return function () { + content.rows[ii].style.background = "#FFFFFF"; + } + }(i); + if (isIE) { + content.rows[i].onmousemove = moveFunc; + content.rows[i].onmouseout = outFunc; + } else { + content.rows[i].addEventListener("mousemove", moveFunc, false); + content.rows[i].addEventListener("mouseout", outFunc, false); + } + } + } + } +} +// ==== tab ==== +function setTab(name, cursel, n) { + for (i = 1; i <= n; i++) { + var menu = byId(name + i); + var con = byId("con_" + name + "_" + i); + menu.className = i == cursel ? "active" : ""; + con.style.display = i == cursel ? "block" : "none"; + } +} +function setActiveTab(i) { + if (i == 1) { + document.getElementById("unique_tab" + i).className = "current_nosub"; + } else { + document.getElementById("unique_tab" + i).className = "current"; + } +} + +// ==== check box ==== +function checkAll(tableId, checkboxName, checked) { + var checkboxs = document.getElementsByName(checkboxName); + var checktable = document.getElementById(tableId); + for (var i = 0; i < checkboxs.length; i++) { + if (checktable && checktable.rows.length > i + 1 && checktable.rows[i + 1].style.display == 'none') { + checkboxs[i].checked = false; + } else { + checkboxs[i].checked = checked; + } + } +} +function hasCheckbox(name) { + var checkboxs = document.getElementsByName(name); + return checkboxs && checkboxs.length > 0; +} +function hasChecked(name) { + var checkboxs = document.getElementsByName(name); + if (checkboxs && checkboxs.length > 0) { + for (var i = 0; i < checkboxs.length; i++) { + if (checkboxs[i].checked) { + return true; + } + } + } + return false; +} +function getChecked(name) { + var result = ""; + var checkboxs = document.getElementsByName(name); + for (var i = 0; i < checkboxs.length; i++) { + if (checkboxs[i].checked) { + if (result.length > 0) { + result = result + ","; + } + result = result + checkboxs[i].value; + } + } + return result; +} +// ==== show box ==== +var confirmUrl = ""; +function confirmRedirect(msg, data, url) { + showConfirm(msg, data, url); +} +function showConfirm(msg, data, url) { + if (!url) { + url = data; + data = ""; + } + if (url == null || url == "") { + return; + } + if (msg == null || msg == "") { + msg = "Confirm?"; + } + confirmUrl = url; + byId("confirmText").innerHTML = msg; + byId("confirmData").innerHTML = data; + Box.show("confirmBox"); +} +function confirmOK() { + Box.hide("confirmBox"); + if (confirmUrl == null || confirmUrl == "") { + return; + } + window.location.href = confirmUrl; +} +function confirmCancel() { + Box.hide("confirmBox"); +} +var alertId = ""; +function showAlert(msg, data, id) { + if (id) { + alertId = id; + } else { + alertId = ""; + } + if (msg == null || msg == "") { + msg = "Please input!"; + } + if (data == null) { + data = ""; + } + byId("alertText").innerHTML = msg; + byId("alertData").innerHTML = data; + Box.show("alertBox"); +} +function alertOK() { + Box.hide("alertBox"); + if (alertId == null || alertId == "") { + return; + } + byId(alertId).focus(); +} +// ==== scroll bar ==== +var marqueeInterval = null; +function moveScroll() { + var marqueeBox = document.getElementById("marqueeBox"); + var marqueeText = document.getElementById("marqueeText"); + if (marqueeBox.scrollLeft >= marqueeText.offsetWidth - 3000) { + marqueeBox.scrollLeft = 0; + } else { + marqueeBox.scrollLeft = marqueeBox.scrollLeft + 1; + } +} +function startScroll() { + marqueeInterval = window.setInterval(moveScroll, 30) +} +function stopScroll() { + window.clearInterval(marqueeInterval) +} +function initScroll() { + var marqueeText = document.getElementById("marqueeText"); + if (marqueeText == null) { + return; + } + var str = marqueeText.innerHTML; + var i = str.indexOf(">"); + if (i > 0) { + str = str.substring(i + 1); + } + var len = str.length + str.replace(/\x00-\x7f/g, '').length; + marqueeText.style.width = (len * 6 + 30) + "px"; + startScroll(); +} +// ==== show modal ==== +$(function () { + function showModal(src, height, width) { + jQuery.modal('') + .css($.extend(s.o.iframeCss, { + display: 'none', + opacity: 0, + position: 'fixed', + height: w[0], + width: w[1], + zIndex: s.o.zIndex, + top: 0, + left: 0 + })) + .appendTo(s.o.appendTo); + } + + // create the overlay + s.d.overlay = $('

') + .attr('id', s.o.overlayId) + .addClass('simplemodal-overlay') + .css($.extend(s.o.overlayCss, { + display: 'none', + opacity: s.o.opacity / 100, + height: s.o.modal ? w[0] : 0, + width: s.o.modal ? w[1] : 0, + position: 'fixed', + left: 0, + top: 0, + zIndex: s.o.zIndex + 1 + })) + .appendTo(s.o.appendTo); + + // create the container + s.d.container = $('
') + .attr('id', s.o.containerId) + .addClass('simplemodal-container') + .css($.extend(s.o.containerCss, { + display: 'none', + position: 'fixed', + zIndex: s.o.zIndex + 2 + })) + .append(s.o.close && s.o.closeHTML + ? $(s.o.closeHTML).addClass(s.o.closeClass) + : '') + .appendTo(s.o.appendTo); + + s.d.wrap = $('
') + .attr('tabIndex', -1) + .addClass('simplemodal-wrap') + .css({height: '100%', outline: 0, width: '100%'}) + .appendTo(s.d.container); + + // add styling and attributes to the data + // append to body to get correct dimensions, then move to wrap + s.d.data = data + .attr('id', data.attr('id') || s.o.dataId) + .addClass('simplemodal-data') + .css($.extend(s.o.dataCss, { + display: 'none' + })) + .appendTo('body'); + data = null; + + s.setContainerDimensions(); + s.d.data.appendTo(s.d.wrap); + + // fix issues with IE + if (ie6 || ieQuirks) { + s.fixIE(); + } + }, + /* + * Bind events + */ + bindEvents: function () { + var s = this; + + // bind the close event to any element with the closeClass class + $('.' + s.o.closeClass).bind('click.simplemodal', function (e) { + e.preventDefault(); + s.close(); + }); + + // bind the overlay click to the close function, if enabled + if (s.o.modal && s.o.close && s.o.overlayClose) { + s.d.overlay.bind('click.simplemodal', function (e) { + e.preventDefault(); + s.close(); + }); + } + + // bind keydown events + $(document).bind('keydown.simplemodal', function (e) { + if (s.o.modal && e.keyCode === 9) { // TAB + s.watchTab(e); + } + else if ((s.o.close && s.o.escClose) && e.keyCode === 27) { // ESC + e.preventDefault(); + s.close(); + } + }); + + // update window size + $(window).bind('resize.simplemodal', function () { + // redetermine the window width/height + w = s.getDimensions(); + + // reposition the dialog + s.o.autoResize ? s.setContainerDimensions() : s.o.autoPosition && s.setPosition(); + + if (ie6 || ieQuirks) { + s.fixIE(); + } + else if (s.o.modal) { + // update the iframe & overlay + s.d.iframe && s.d.iframe.css({height: w[0], width: w[1]}); + s.d.overlay.css({height: w[0], width: w[1]}); + } + }); + }, + /* + * Unbind events + */ + unbindEvents: function () { + $('.' + this.o.closeClass).unbind('click.simplemodal'); + $(document).unbind('keydown.simplemodal'); + $(window).unbind('resize.simplemodal'); + this.d.overlay.unbind('click.simplemodal'); + }, + /* + * Fix issues in IE6 and IE7 in quirks mode + */ + fixIE: function () { + var s = this, p = s.o.position; + + // simulate fixed position - adapted from BlockUI + $.each([s.d.iframe || null, !s.o.modal ? null : s.d.overlay, s.d.container], function (i, el) { + if (el) { + var bch = 'document.body.clientHeight', bcw = 'document.body.clientWidth', + bsh = 'document.body.scrollHeight', bsl = 'document.body.scrollLeft', + bst = 'document.body.scrollTop', bsw = 'document.body.scrollWidth', + ch = 'document.documentElement.clientHeight', cw = 'document.documentElement.clientWidth', + sl = 'document.documentElement.scrollLeft', st = 'document.documentElement.scrollTop', + s = el[0].style; + + s.position = 'absolute'; + if (i < 2) { + s.removeExpression('height'); + s.removeExpression('width'); + s.setExpression('height', '' + bsh + ' > ' + bch + ' ? ' + bsh + ' : ' + bch + ' + "px"'); + s.setExpression('width', '' + bsw + ' > ' + bcw + ' ? ' + bsw + ' : ' + bcw + ' + "px"'); + } + else { + var te, le; + if (p && p.constructor === Array) { + var top = p[0] + ? typeof p[0] === 'number' ? p[0].toString() : p[0].replace(/px/, '') + : el.css('top').replace(/px/, ''); + te = top.indexOf('%') === -1 + ? top + ' + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"' + : parseInt(top.replace(/%/, '')) + ' * ((' + ch + ' || ' + bch + ') / 100) + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"'; + + if (p[1]) { + var left = typeof p[1] === 'number' ? p[1].toString() : p[1].replace(/px/, ''); + le = left.indexOf('%') === -1 + ? left + ' + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"' + : parseInt(left.replace(/%/, '')) + ' * ((' + cw + ' || ' + bcw + ') / 100) + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"'; + } + } + else { + te = '(' + ch + ' || ' + bch + ') / 2 - (this.offsetHeight / 2) + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"'; + le = '(' + cw + ' || ' + bcw + ') / 2 - (this.offsetWidth / 2) + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"'; + } + s.removeExpression('top'); + s.removeExpression('left'); + s.setExpression('top', te); + s.setExpression('left', le); + } + } + }); + }, + /* + * Place focus on the first or last visible input + */ + focus: function (pos) { + var s = this, p = pos && $.inArray(pos, ['first', 'last']) !== -1 ? pos : 'first'; + + // focus on dialog or the first visible/enabled input element + var input = $(':input:enabled:visible:' + p, s.d.wrap); + setTimeout(function () { + input.length > 0 ? input.focus() : s.d.wrap.focus(); + }, 10); + }, + getDimensions: function () { + var el = $(window); + + // fix a jQuery/Opera bug with determining the window height + var h = $.browser.opera && $.browser.version > '9.5' && $.fn.jquery < '1.3' + || $.browser.opera && $.browser.version < '9.5' && $.fn.jquery > '1.2.6' + ? el[0].innerHeight : el.height(); + + return [h, el.width()]; + }, + getVal: function (v, d) { + return v ? (typeof v === 'number' ? v + : v === 'auto' ? 0 + : v.indexOf('%') > 0 ? ((parseInt(v.replace(/%/, '')) / 100) * (d === 'h' ? w[0] : w[1])) + : parseInt(v.replace(/px/, ''))) + : null; + }, + /* + * Update the container. Set new dimensions, if provided. + * Focus, if enabled. Re-bind events. + */ + update: function (height, width) { + var s = this; + + // prevent update if dialog does not exist + if (!s.d.data) { + return false; + } + + // reset orig values + s.d.origHeight = s.getVal(height, 'h'); + s.d.origWidth = s.getVal(width, 'w'); + + // hide data to prevent screen flicker + s.d.data.hide(); + height && s.d.container.css('height', height); + width && s.d.container.css('width', width); + s.setContainerDimensions(); + s.d.data.show(); + s.o.focus && s.focus(); + + // rebind events + s.unbindEvents(); + s.bindEvents(); + }, + setContainerDimensions: function () { + var s = this; + + // get the dimensions for the container and data + var ch = s.d.origHeight ? s.d.origHeight : $.browser.opera ? s.d.container.height() : s.getVal(s.d.container.css('height'), 'h'), + cw = s.d.origWidth ? s.d.origWidth : $.browser.opera ? s.d.container.width() : s.getVal(s.d.container.css('width'), 'w'), + dh = s.d.data.outerHeight(true), dw = s.d.data.outerWidth(true); + + s.d.origHeight = s.d.origHeight || ch; + s.d.origWidth = s.d.origWidth || cw; + + // mxoh = max option height, mxow = max option width + var mxoh = s.o.maxHeight ? s.getVal(s.o.maxHeight, 'h') : null, + mxow = s.o.maxWidth ? s.getVal(s.o.maxWidth, 'w') : null, + mh = mxoh && mxoh < w[0] ? mxoh : w[0], + mw = mxow && mxow < w[1] ? mxow : w[1]; + + // moh = min option height + var moh = s.o.minHeight ? s.getVal(s.o.minHeight, 'h') : 'auto'; + if (!ch) { + if (!dh) { + ch = moh; + } + else { + if (dh > mh) { + ch = mh; + } + else if (s.o.minHeight && moh !== 'auto' && dh < moh) { + ch = moh; + } + else { + ch = dh; + } + } + } + else { + ch = s.o.autoResize && ch > mh ? mh : ch; + } + + // mow = min option width + var mow = s.o.minWidth ? s.getVal(s.o.minWidth, 'w') : 'auto'; + if (!cw) { + if (!dw) { + cw = mow; + } + else { + if (dw > mw) { + cw = mw; + } + else if (s.o.minWidth && mow !== 'auto' && dw < mow) { + cw = mow; + } + else { + cw = dw; + } + } + } + else { + cw = s.o.autoResize && cw > mw ? mw : cw; + } + + s.d.container.css({height: ch, width: cw}); + s.d.wrap.css({overflow: (dh > ch || dw > cw) ? 'auto' : 'visible'}); + s.o.autoPosition && s.setPosition(); + }, + setPosition: function () { + var s = this, top, left, + hc = (w[0] / 2) - (s.d.container.outerHeight(true) / 2), + vc = (w[1] / 2) - (s.d.container.outerWidth(true) / 2); + + if (s.o.position && Object.prototype.toString.call(s.o.position) === '[object Array]') { + top = s.o.position[0] || hc; + left = s.o.position[1] || vc; + } else { + top = hc; + left = vc; + } + s.d.container.css({left: left, top: top}); + }, + watchTab: function (e) { + var s = this; + + if ($(e.target).parents('.simplemodal-container').length > 0) { + // save the list of inputs + s.inputs = $(':input:enabled:visible:first, :input:enabled:visible:last', s.d.data[0]); + + // if it's the first or last tabbable element, refocus + if ((!e.shiftKey && e.target === s.inputs[s.inputs.length - 1]) || + (e.shiftKey && e.target === s.inputs[0]) || + s.inputs.length === 0) { + e.preventDefault(); + var pos = e.shiftKey ? 'last' : 'first'; + s.focus(pos); + } + } + else { + // might be necessary when custom onShow callback is used + e.preventDefault(); + s.focus(); + } + }, + /* + * Open the modal dialog elements + * - Note: If you use the onOpen callback, you must "show" the + * overlay and container elements manually + * (the iframe will be handled by SimpleModal) + */ + open: function () { + var s = this; + // display the iframe + s.d.iframe && s.d.iframe.show(); + + if ($.isFunction(s.o.onOpen)) { + // execute the onOpen callback + s.o.onOpen.apply(s, [s.d]); + } + else { + // display the remaining elements + s.d.overlay.show(); + s.d.container.show(); + s.d.data.show(); + } + + s.o.focus && s.focus(); + + // bind default events + s.bindEvents(); + }, + /* + * Close the modal dialog + * - Note: If you use an onClose callback, you must remove the + * overlay, container and iframe elements manually + * + * @param {boolean} external Indicates whether the call to this + * function was internal or external. If it was external, the + * onClose callback will be ignored + */ + close: function () { + var s = this; + + // prevent close when dialog does not exist + if (!s.d.data) { + return false; + } + + // remove the default events + s.unbindEvents(); + + if ($.isFunction(s.o.onClose) && !s.occb) { + // set the onClose callback flag + s.occb = true; + + // execute the onClose callback + s.o.onClose.apply(s, [s.d]); + } + else { + // if the data came from the DOM, put it back + if (s.d.placeholder) { + var ph = $('#simplemodal-placeholder'); + // save changes to the data? + if (s.o.persist) { + // insert the (possibly) modified data back into the DOM + ph.replaceWith(s.d.data.removeClass('simplemodal-data').css('display', s.display)); + } + else { + // remove the current and insert the original, + // unmodified data back into the DOM + s.d.data.hide().remove(); + ph.replaceWith(s.d.orig); + } + } + else { + // otherwise, remove it + s.d.data.hide().remove(); + } + + // remove the remaining elements + s.d.container.hide().remove(); + s.d.overlay.hide(); + s.d.iframe && s.d.iframe.hide().remove(); + setTimeout(function () { + // opera work-around + s.d.overlay.remove(); + + // reset the dialog object + s.d = {}; + }, 10); + } + } + }; +})(jQuery); diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/menu.js b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/menu.js new file mode 100644 index 0000000..5ae496b --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/menu.js @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// JavaScript Document + +$(function () { + function megaHoverOver() { + $(this).find(".sub").stop().fadeTo('fast', 1).show(); + //Calculate width of all ul's + (function ($) { + jQuery.fn.calcSubWidth = function () { + rowWidth = 0; + //Calculate row + $(this).find("ul").each(function () { + rowWidth += $(this).width(); + }); + }; + })(jQuery); + + if ($(this).find(".row").length > 0) { //If row exists... + var biggestRow = 0; + //Calculate each row + $(this).find(".row").each(function () { + $(this).calcSubWidth(); + //Find biggest row + if (rowWidth > biggestRow) { + biggestRow = rowWidth; + } + }); + //Set width + $(this).find(".sub").css({'width': biggestRow}); + $(this).find(".row:last").css({'margin': '0'}); + } else { //If row does not exist... + $(this).calcSubWidth(); + //Set Width + $(this).find(".sub").css({'width': rowWidth}); + } + } + + function megaHoverOut() { + $(this).find(".sub").stop().fadeTo('fast', 0, function () { + $(this).hide(); + }); + } + + var config = { + sensitivity: 1, // number = sensitivity threshold (must be 1 or higher) + interval: 100, // number = milliseconds for onMouseOver polling interval + over: megaHoverOver, // function = onMouseOver callback (REQUIRED) + timeout: 200, // number = milliseconds delay before onMouseOut + out: megaHoverOut // function = onMouseOut callback (REQUIRED) + }; + $("ul#topnav li .sub").css({'opacity': '0'}); + $("ul#topnav li").hoverIntent(config); +}); diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/pop.js b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/pop.js new file mode 100644 index 0000000..247b368 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/static/js/pop.js @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// JavaScript Document +$(function () { + + function showModal(src, height, width) { + jQuery.modal(' + + + #else + + + + + #parse("/templates/home/control/menu.vm") +## $control.setTemplate("home:menu.vm") + + + + + +
+ + + + #end + \ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/home/screen/services.vm b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/home/screen/services.vm new file mode 100644 index 0000000..63192d7 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/home/screen/services.vm @@ -0,0 +1,26 @@ +##Licensed to the Apache Software Foundation (ASF) under one or more +##contributor license agreements. See the NOTICE file distributed with +##this work for additional information regarding copyright ownership. +##The ASF licenses this file to You under the Apache License, Version 2.0 +##(the "License"); you may not use this file except in compliance with +##the License. You may obtain a copy of the License at +## +##http://www.apache.org/licenses/LICENSE-2.0 +## +##Unless required by applicable law or agreed to in writing, software +##distributed under the License is distributed on an "AS IS" BASIS, +##WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +##See the License for the specific language governing permissions and +##limitations under the License. + + + + + Dubbo Registry + + + + + \ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/layout/default.vm b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/layout/default.vm new file mode 100644 index 0000000..5e18d04 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/layout/default.vm @@ -0,0 +1,148 @@ +##Licensed to the Apache Software Foundation (ASF) under one or more +##contributor license agreements. See the NOTICE file distributed with +##this work for additional information regarding copyright ownership. +##The ASF licenses this file to You under the Apache License, Version 2.0 +##(the "License"); you may not use this file except in compliance with +##the License. You may obtain a copy of the License at +## +##http://www.apache.org/licenses/LICENSE-2.0 +## +##Unless required by applicable law or agreed to in writing, software +##distributed under the License is distributed on an "AS IS" BASIS, +##WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +##See the License for the specific language governing permissions and +##limitations under the License. + + + + + Dubbo Admin + + + + + + #if($_method == "index") + + #end + + + + + +## $control.setTemplate("home:menu.vm") + #parse("/templates/home/control/menu.vm") + + +
+
+ +
+
+ $screen_content +
+
+
+
+ + + + \ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/layout/redirect.vm b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/layout/redirect.vm new file mode 100644 index 0000000..91700d2 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/layout/redirect.vm @@ -0,0 +1,29 @@ +##Licensed to the Apache Software Foundation (ASF) under one or more +##contributor license agreements. See the NOTICE file distributed with +##this work for additional information regarding copyright ownership. +##The ASF licenses this file to You under the Apache License, Version 2.0 +##(the "License"); you may not use this file except in compliance with +##the License. You may obtain a copy of the License at +## +##http://www.apache.org/licenses/LICENSE-2.0 +## +##Unless required by applicable law or agreed to in writing, software +##distributed under the License is distributed on an "AS IS" BASIS, +##WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +##See the License for the specific language governing permissions and +##limitations under the License. + + + + + dubbo + + + + + + + $screen_placeholder + + \ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/layout/search.vm b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/layout/search.vm new file mode 100644 index 0000000..30c0a04 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/layout/search.vm @@ -0,0 +1,15 @@ +##Licensed to the Apache Software Foundation (ASF) under one or more +##contributor license agreements. See the NOTICE file distributed with +##this work for additional information regarding copyright ownership. +##The ASF licenses this file to You under the Apache License, Version 2.0 +##(the "License"); you may not use this file except in compliance with +##the License. You may obtain a copy of the License at +## +##http://www.apache.org/licenses/LICENSE-2.0 +## +##Unless required by applicable law or agreed to in writing, software +##distributed under the License is distributed on an "AS IS" BASIS, +##WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +##See the License for the specific language governing permissions and +##limitations under the License. +$screen_placeholder \ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/dumps/index.vm b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/dumps/index.vm new file mode 100644 index 0000000..8648ff9 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/dumps/index.vm @@ -0,0 +1,76 @@ +##Licensed to the Apache Software Foundation (ASF) under one or more +##contributor license agreements. See the NOTICE file distributed with +##this work for additional information regarding copyright ownership. +##The ASF licenses this file to You under the Apache License, Version 2.0 +##(the "License"); you may not use this file except in compliance with +##the License. You may obtain a copy of the License at +## +##http://www.apache.org/licenses/LICENSE-2.0 +## +##Unless required by applicable law or agreed to in writing, software +##distributed under the License is distributed on an "AS IS" BASIS, +##WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +##See the License for the specific language governing permissions and +##limitations under the License. +#set($layout = "/templates/sysinfo/layout/default.vm") +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
#springMessageText("property.name", "property.name"):  #springMessageText("property.count", "property.count")
+ #springMessageText("noProvider", "noProvider") + + #springMessageText( + "property.count","property.count") + ($noProviderServices.size()) +
+ #springMessageText("services", "services") + + #springMessageText( + "property.count","property.count") + ($services.size()) +
+ #springMessageText("providers", "providers") + + #springMessageText( + "property.count","property.count") + ($providers.size()) +
+ #springMessageText("consumers", "consumers") + + #springMessageText( + "property.count","property.count") + ($consumers.size()) +
+ #springMessageText("versions", "versions") + + #set ($client=$providers.size()+$consumers.size()) + #springMessageText( + "property.count","property.count")($client) +
\ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/envs/index.vm b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/envs/index.vm new file mode 100644 index 0000000..fb78d32 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/envs/index.vm @@ -0,0 +1,35 @@ +##Licensed to the Apache Software Foundation (ASF) under one or more +##contributor license agreements. See the NOTICE file distributed with +##this work for additional information regarding copyright ownership. +##The ASF licenses this file to You under the Apache License, Version 2.0 +##(the "License"); you may not use this file except in compliance with +##the License. You may obtain a copy of the License at +## +##http://www.apache.org/licenses/LICENSE-2.0 +## +##Unless required by applicable law or agreed to in writing, software +##distributed under the License is distributed on an "AS IS" BASIS, +##WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +##See the License for the specific language governing permissions and +##limitations under the License. +#set($layout = "/templates/sysinfo/layout/default.vm") +
+
+
+ + + + + + #foreach($entry in $properties.entrySet()) + + + + + #end +
#springMessageText("property.name", "property.name"):  #springMessageText("property.value", "property.value"):  
#springMessageText($entry.key, $entry.key)$entry.value
\ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/logs/index.vm b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/logs/index.vm new file mode 100644 index 0000000..4a00104 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/logs/index.vm @@ -0,0 +1,55 @@ +##Licensed to the Apache Software Foundation (ASF) under one or more +##contributor license agreements. See the NOTICE file distributed with +##this work for additional information regarding copyright ownership. +##The ASF licenses this file to You under the Apache License, Version 2.0 +##(the "License"); you may not use this file except in compliance with +##the License. You may obtain a copy of the License at +## +##http://www.apache.org/licenses/LICENSE-2.0 +## +##Unless required by applicable law or agreed to in writing, software +##distributed under the License is distributed on an "AS IS" BASIS, +##WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +##See the License for the specific language governing permissions and +##limitations under the License. +#set($layout = "/templates/sysinfo/layout/default.vm") +
+ #if($currentUser.role == "R") + + + #springMessageText("change.log.level", "change.log.level") + + #end +
+
+ + + + + + + + + #if($paginatorBar) + + #end + +
+ #springMessageText("logs.file", "logs.file"): $name (#springMessageText("logs.size", "logs.size"): $size / #springMessageText( + "logs.modify","logs.modify"): $modified) #springMessageText("logs.level", "logs.level"): $level + :   +
$tool.unescape($!content.replaceAll("\n", "
"))
+ $tool.unescape($!paginatorBar) +
\ No newline at end of file diff --git a/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/redirect.vm b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/redirect.vm new file mode 100644 index 0000000..f9352f8 --- /dev/null +++ b/52.Dubbo-OPS-Mointor/dubbo-admin/src/main/resources/templates/sysinfo/screen/redirect.vm @@ -0,0 +1,71 @@ +##Licensed to the Apache Software Foundation (ASF) under one or more +##contributor license agreements. See the NOTICE file distributed with +##this work for additional information regarding copyright ownership. +##The ASF licenses this file to You under the Apache License, Version 2.0 +##(the "License"); you may not use this file except in compliance with +##the License. You may obtain a copy of the License at +## +##http://www.apache.org/licenses/LICENSE-2.0 +## +##Unless required by applicable law or agreed to in writing, software +##distributed under the License is distributed on an "AS IS" BASIS, +##WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +##See the License for the specific language governing permissions and +##limitations under the License. +
+

#springMessageText("addresses", "addresses")

+
#springMessageText("home", "home") > #springMessageText("addresses", "addresses")
+ + +
+