1+ /*---------------------------------------------------------------------------------------------
2+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
3+ * This file is a part of the ModelEngine Project.
4+ * Licensed under the MIT License. See License.txt in the project root for license information.
5+ *--------------------------------------------------------------------------------------------*/
6+
17package modelengine .fitframework .i18n ;
28
39import static modelengine .fitframework .inspection .Validation .notBlank ;
1521import modelengine .fitframework .plugin .Plugin ;
1622import modelengine .fitframework .plugin .PluginStartedObserver ;
1723import modelengine .fitframework .plugin .PluginStoppingObserver ;
24+
1825import java .util .List ;
1926import java .util .Map ;
2027import java .util .Optional ;
2128import java .util .concurrent .ConcurrentHashMap ;
2229import java .util .stream .Collectors ;
30+
2331import modelengine .fitframework .resource .UrlUtils ;
2432import modelengine .fitframework .util .OptionalUtils ;
2533import modelengine .fitframework .util .StringUtils ;
2634import modelengine .fitframework .util .wildcard .PathPattern ;
2735import modelengine .fitframework .util .wildcard .Pattern ;
2836
37+ /**
38+ * 地区解析器注册中心
39+ *
40+ * @author 阮睿
41+ * @since 2025-09-07
42+ */
2943@ Component
3044public class LocaleResolverRegistry implements PluginStartedObserver , PluginStoppingObserver {
3145 private static final char PATH_SEPARATOR = '/' ;
3246
33- // 参考DefaultHttpDispatcher的三层结构
47+ // 参考 DefaultHttpDispatcher 的三层结构
3448 private final Map <String , LocaleResolver > noPathVariableResolvers = new ConcurrentHashMap <>();
3549 private final Map <String , MappingTree <LocaleResolver >> pathVariableResolvers = new ConcurrentHashMap <>();
3650 private final Map <String , LocaleResolver > wildcardResolvers = new ConcurrentHashMap <>();
3751
3852 private final LocaleResolver defaultLocaleResolver = new DefualtLocaleResolver ();
3953
54+ /**
55+ * 构造函数。
56+ */
4057 public LocaleResolverRegistry () {
4158 // 与 DefaultHttpDispatcher 保持一致,使用 ConcurrentHashMap 提供线程安全。
4259 this .pathVariableResolvers .put (DefaultMappingTree .PATH_SEPARATOR , new DefaultMappingTree <>());
4360 }
4461
62+ /**
63+ * 注册地区解析器。
64+ *
65+ * @param resolver 表示将要被注册地区解析器的 {@link LocaleResolver}。
66+ */
4567 public void register (LocaleResolver resolver ) {
4668 notNull (resolver , "The locale resolver cannot be null." );
4769 String pathPattern = MappingTree .convertToMatchedPathPattern (resolver .getUrlPattern ());
4870 notBlank (pathPattern , "The path pattern cannot be blank." );
4971 LocaleResolver preResolver ;
5072 if (pathPattern .contains ("**" )) {
51- preResolver = wildcardResolvers .put (pathPattern , resolver );
73+ preResolver = this . wildcardResolvers .put (pathPattern , resolver );
5274 } else if (pathPattern .contains ("*" )) {
53- preResolver = pathVariableResolvers .get (DefaultMappingTree .PATH_SEPARATOR )
75+ preResolver = this . pathVariableResolvers .get (DefaultMappingTree .PATH_SEPARATOR )
5476 .register (pathPattern , resolver )
5577 .orElse (null );
56- ;
5778 } else {
58- preResolver = noPathVariableResolvers .put (pathPattern , resolver );
79+ preResolver = this . noPathVariableResolvers .put (pathPattern , resolver );
5980 }
6081 if (preResolver != null ) {
6182 String message = StringUtils .format ("Locale resolver has been registered. [pattern={0}]" , pathPattern );
6283 throw new RegisterLocaleResolverException (message );
6384 }
6485 }
6586
87+ /**
88+ * 取消注册地区解析器。
89+ *
90+ * @param resolver 表示待取消注册地区解析器的 {@link LocaleResolver}。
91+ */
6692 public void unregister (LocaleResolver resolver ) {
6793 notNull (resolver , "The locale resolver cannot be null." );
6894 String pathPattern = MappingTree .convertToMatchedPathPattern (resolver .getUrlPattern ());
6995 notBlank (pathPattern , "The path pattern cannot be blank." );
7096 if (pathPattern .contains ("**" )) {
71- wildcardResolvers .remove (pathPattern );
97+ this . wildcardResolvers .remove (pathPattern );
7298 } else if (pathPattern .contains ("*" )) {
73- pathVariableResolvers .get (DefaultMappingTree .PATH_SEPARATOR ).unregister (pathPattern );
99+ this . pathVariableResolvers .get (DefaultMappingTree .PATH_SEPARATOR ).unregister (pathPattern );
74100 ;
75101 } else {
76- noPathVariableResolvers .remove (pathPattern );
102+ this . noPathVariableResolvers .remove (pathPattern );
77103 }
78104 }
79105
106+ /**
107+ * 分派地区解析器。
108+ *
109+ * @param request 表示用于查找对应 {@link LocaleResolver} 请求的 {@link HttpClassicServerRequest}。
110+ * @return 返回匹配的 {@link LocaleResolver}。
111+ */
80112 public LocaleResolver dispatch (HttpClassicServerRequest request ) {
81113 String path = UrlUtils .decodePath (request .path ());
82114 return (LocaleResolver ) OptionalUtils .get (() -> selectFromNoPathVariableResolvers (path ))
83115 .orElse (() -> selectFromPathVariableResolvers (path ))
84- .orElse (() -> selectFromWildcardResolvers (path )).orDefault (this .defaultLocaleResolver );
116+ .orElse (() -> selectFromWildcardResolvers (path ))
117+ .orDefault (this .defaultLocaleResolver );
85118 }
86119
120+ /**
121+ * 从无路径参数的解析器中查找匹配的解析器。
122+ *
123+ * @param path 表示待匹配路径的 {@link String}。
124+ * @return 表示匹配对应路径解析器的 {@link Optional}{@code <}{@link LocaleResolver}{@code >}。。
125+ */
87126 private Optional <LocaleResolver > selectFromNoPathVariableResolvers (String path ) {
88- LocaleResolver resolver = noPathVariableResolvers .get (path );
127+ LocaleResolver resolver = this . noPathVariableResolvers .get (path );
89128 return Optional .ofNullable (resolver );
90129 }
91130
131+ /**
132+ * 从路径参数的解析器中查找匹配的解析器。
133+ *
134+ * @param path 待匹配路径的 {@link String}。
135+ * @return 匹配对应路径解析器的 {@link Optional}{@code <}{@link LocaleResolver}{@code >}。
136+ */
92137 private Optional <LocaleResolver > selectFromPathVariableResolvers (String path ) {
93- return pathVariableResolvers .get (DefaultMappingTree .PATH_SEPARATOR ).search (path );
138+ return this . pathVariableResolvers .get (DefaultMappingTree .PATH_SEPARATOR ).search (path );
94139 }
95140
141+ /**
142+ * 从通配符的解析器中查找匹配的解析器。
143+ *
144+ * @param path 待匹配路径的 {@link String}。
145+ * @return 匹配对应路径解析器的 {@link Optional}{@code <}{@link LocaleResolver}{@code >}。
146+ */
96147 private Optional <LocaleResolver > selectFromWildcardResolvers (String path ) {
97- for (Map .Entry <String , LocaleResolver > entry : wildcardResolvers .entrySet ()) {
148+ for (Map .Entry <String , LocaleResolver > entry : this . wildcardResolvers .entrySet ()) {
98149 PathPattern pattern = Pattern .forPath (entry .getKey (), PATH_SEPARATOR );
99150 if (pattern .matches (path )) {
100151 return Optional .of (entry .getValue ());
@@ -103,26 +154,36 @@ private Optional<LocaleResolver> selectFromWildcardResolvers(String path) {
103154 return Optional .empty ();
104155 }
105156
157+ /**
158+ * 当插件启动时,注册插件中的地区解析器。
159+ *
160+ * @param plugin 待注册插件的 {@link Plugin}。
161+ */
106162 @ Override
107163 public void onPluginStarted (Plugin plugin ) {
108164 BeanContainer container = plugin .container ();
109165 List <LocaleResolver > localeResolvers = container .all (LocaleResolver .class )
110166 .stream ()
111167 .map (BeanFactory ::<LocaleResolver >get )
112168 .collect (Collectors .toList ());
113- for (LocaleResolver localeResolver : localeResolvers ) {
169+ for (LocaleResolver localeResolver : localeResolvers ) {
114170 this .register (localeResolver );
115171 }
116172 }
117173
174+ /**
175+ * 当插件停止时,取消注册插件中的地区解析器。
176+ *
177+ * @param plugin 待取消注册插件的 {@link Plugin}。
178+ */
118179 @ Override
119180 public void onPluginStopping (Plugin plugin ) {
120181 BeanContainer container = plugin .container ();
121182 List <LocaleResolver > localeResolvers = container .all (LocaleResolver .class )
122183 .stream ()
123184 .map (BeanFactory ::<LocaleResolver >get )
124185 .collect (Collectors .toList ());
125- for (LocaleResolver localeResolver : localeResolvers ) {
186+ for (LocaleResolver localeResolver : localeResolvers ) {
126187 this .unregister (localeResolver );
127188 }
128189 }
0 commit comments