##### Coverage Report - org.seasar.cubby.routing.impl.PathResolverImpl

Classes in this File | Line Coverage | Branch Coverage | Complexity
PathResolverImpl |
90% | 81/90
81% | 36/44
| 4.9523809523809526;4.952
PathResolverImpl$1 |
100% | 3/3
N/A | N/A
| 4.9523809523809526;4.952
PathResolverImpl$2 |
100% | 7/7
100% | 4/4
| 4.9523809523809526;4.952
PathResolverImpl$ResolvedPathInfo |
88% | 8/9
75% | 3/4
| 4.9523809523809526;4.952
PathResolverImpl$RoutingKey |
34% | 23/66
16% | 9/54
| 4.9523809523809526;4.952

1 |  |
     /*
2 |  |
      * Copyright 2004-2009 the Seasar Foundation and the Others.
3 |  |
      *
4 |  |
      * Licensed under the Apache License, Version 2.0 (the "License");
5 |  |
      * you may not use this file except in compliance with the License.
6 |  |
      * You may obtain a copy of the License at
7 |  |
      *
8 |  |
      *     http://www.apache.org/licenses/LICENSE-2.0
9 |  |
      *
10 |  |
      * Unless required by applicable law or agreed to in writing, software
11 |  |
      * distributed under the License is distributed on an "AS IS" BASIS,
12 |  |
      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 |  |
      * either express or implied. See the License for the specific language
14 |  |
      * governing permissions and limitations under the License.
15 |  |
      */
16 |  |
     package org.seasar.cubby.routing.impl;
17 |  |
18 |  |
     import static org.seasar.cubby.internal.util.LogMessages.format;
19 |  |
20 |  |
     import java.io.UnsupportedEncodingException;
21 |  |
     import java.lang.reflect.Method;
22 |  |
     import java.util.ArrayList;
23 |  |
     import java.util.Collection;
24 |  |
     import java.util.HashMap;
25 |  |
     import java.util.Iterator;
26 |  |
     import java.util.List;
27 |  |
     import java.util.Map;
28 |  |
     import java.util.TreeMap;
29 |  |
     import java.util.Map.Entry;
30 |  |
     import java.util.regex.Matcher;
31 |  |
     import java.util.regex.Pattern;
32 |  |
33 |  |
     import org.seasar.cubby.action.Path;
34 |  |
     import org.seasar.cubby.action.RequestMethod;
35 |  |
     import org.seasar.cubby.internal.util.MetaUtils;
36 |  |
     import org.seasar.cubby.internal.util.QueryStringBuilder;
37 |  |
     import org.seasar.cubby.internal.util.URLBodyEncoder;
38 |  |
     import org.seasar.cubby.routing.PathInfo;
39 |  |
     import org.seasar.cubby.routing.PathResolver;
40 |  |
     import org.seasar.cubby.routing.PathTemplateParser;
41 |  |
     import org.seasar.cubby.routing.Routing;
42 |  |
     import org.seasar.cubby.routing.RoutingException;
43 |  |
     import org.seasar.cubby.util.ActionUtils;
44 |  |
     import org.slf4j.Logger;
45 |  |
     import org.slf4j.LoggerFactory;
46 |  |
47 |  |
     /**
48 |  |
      * パスに対応するアクションメソッドを解決するためのクラスの実装です。
49 |  |
      *
50 |  |
      * @author baba
51 |  |
      */
52 | 403 |
     public class PathResolverImpl implements PathResolver {
53 |  |
54 |  |
             /** ロガー */
55 | 1 |
             private static final Logger logger = LoggerFactory
56 |  |
                             .getLogger(PathResolverImpl.class);
57 |  |
58 |  |
             /** 登録されたルーティングのマップ。 */
59 | 57 |
             private final Map<RoutingKey, Routing> routings = new TreeMap<RoutingKey, Routing>();
60 |  |
61 |  |
             /** パステンプレートのパーサー。 */
62 |  |
             private final PathTemplateParser pathTemplateParser;
63 |  |
64 |  |
             /**
65 |  |
              * インスタンス化します。
66 |  |
              *
67 |  |
              * @param pathTemplateParser
68 |  |
              *            パステンプレートのパーサー
69 |  |
              */
70 | 57 |
             public PathResolverImpl(final PathTemplateParser pathTemplateParser) {
71 | 57 |
                     this.pathTemplateParser = pathTemplateParser;
72 | 57 |
             }
73 |  |
74 |  |
             /**
75 |  |
              * ルーティング情報を取得します。
76 |  |
              *
77 |  |
              * @return ルーティング情報
78 |  |
              */
79 |  |
             public Collection<Routing> getRoutings() {
80 | 43 |
                     return routings.values();
81 |  |
             }
82 |  |
83 |  |
             /**
84 |  |
              * {@inheritDoc}
85 |  |
              */
86 |  |
             public void add(final Class<?> actionClass) {
87 | 1576 |
                     for (final Method method : actionClass.getMethods()) {
88 | 1499 |
                             if (ActionUtils.isActionMethod(method)) {
89 | 288 |
                                     final String actionPath = MetaUtils.getActionPath(actionClass,
90 |  |
                                                     method);
91 | 288 |
                                     final RequestMethod[] acceptableRequestMethods = MetaUtils
92 |  |
                                                     .getAcceptableRequestMethods(actionClass, method);
93 | 834 |
                                     for (final RequestMethod requestMethod : acceptableRequestMethods) {
94 | 546 |
                                             final String onSubmit = MetaUtils.getOnSubmit(method);
95 | 546 |
                                             final int priority = MetaUtils.getPriority(method);
96 | 546 |
                                             this.add(actionPath, actionClass, method, requestMethod,
97 |  |
                                                             onSubmit, priority);
98 |  |
                                     }
99 |  |
                             }
100 |  |
                     }
101 | 77 |
             }
102 |  |
103 |  |
             /**
104 |  |
              * {@inheritDoc}
105 |  |
              */
106 |  |
             public void addAll(final Collection<Class<?>> actionClasses) {
107 | 44 |
                     for (final Class<?> actionClass : actionClasses) {
108 | 74 |
                             add(actionClass);
109 |  |
                     }
110 | 44 |
             }
111 |  |
112 |  |
             /**
113 |  |
              * {@inheritDoc}
114 |  |
              */
115 |  |
             public void clear() {
116 | 1 |
                     routings.clear();
117 | 1 |
             }
118 |  |
119 |  |
             /**
120 |  |
              * {@inheritDoc}
121 |  |
              */
122 |  |
             public void add(final String actionPath, final Class<?> actionClass,
123 |  |
                             final String methodName, final RequestMethod requestMethod,
124 |  |
                             final String onSubmit, final int priority) {
125 |  |
                     try {
126 | 24 |
                             final Method method = actionClass.getMethod(methodName);
127 | 24 |
                             this.add(actionPath, actionClass, method, requestMethod, onSubmit,
128 |  |
                                             priority);
129 | 0 |
                     } catch (final NoSuchMethodException e) {
130 | 0 |
                             throw new RoutingException(e);
131 | 24 |
                     }
132 | 24 |
             }
133 |  |
134 |  |
             /**
135 |  |
              * ルーティング情報を登録します。
136 |  |
              *
137 |  |
              * @param actionPath
138 |  |
              *            アクションのパス
139 |  |
              * @param actionClass
140 |  |
              *            アクションクラス
141 |  |
              * @param method
142 |  |
              *            アクションメソッド
143 |  |
              * @param requestMethods
144 |  |
              *            要求メソッド
145 |  |
              * @param onSubmit
146 |  |
              *            アクションメソッドへ振り分けるための要求パラメータ名
147 |  |
              * @param priority
148 |  |
              *            プライオリティ
149 |  |
              */
150 |  |
             private void add(final String actionPath, final Class<?> actionClass,
151 |  |
                             final Method method, final RequestMethod requestMethod,
152 |  |
                             final String onSubmit, final int priority) {
153 | 570 |
                     if (!ActionUtils.isActionMethod(method)) {
154 | 0 |
                             throw new RoutingException(format("ECUB0003", method));
155 |  |
                     }
156 |  |
157 | 570 |
                     final List<String> uriParameterNames = new ArrayList<String>();
158 | 570 |
                     final String uriRegex = pathTemplateParser.parse(actionPath,
159 | 570 |
                                     new PathTemplateParser.Handler() {
160 |  |
161 |  |
                                             public String handle(final String name, final String regex) {
162 | 385 |
                                                     uriParameterNames.add(name);
163 | 385 |
                                                     return regexGroup(regex);
164 |  |
                                             }
165 |  |
166 |  |
                                     });
167 | 570 |
                     final Pattern pattern = Pattern.compile("^" + uriRegex + "$");
168 |  |
169 | 570 |
                     final Routing routing = new RoutingImpl(actionClass, method,
170 |  |
                                     actionPath, uriParameterNames, pattern, requestMethod,
171 |  |
                                     onSubmit, priority);
172 | 570 |
                     final RoutingKey key = new RoutingKey(routing);
173 |  |
174 | 570 |
                     if (logger.isDebugEnabled()) {
175 | 570 |
                             logger.debug(format("DCUB0007", routing));
176 |  |
                     }
177 | 570 |
                     if (routings.containsKey(key)) {
178 | 0 |
                             final Routing duplication = routings.get(key);
179 | 0 |
                             throw new RoutingException(format("ECUB0001", routing, duplication));
180 |  |
                     }
181 | 570 |
                     routings.put(key, routing);
182 | 570 |
             }
183 |  |
184 |  |
             /**
185 |  |
              * {@inheritDoc}
186 |  |
              */
187 |  |
             public PathInfo getPathInfo(final String path, final String requestMethod,
188 |  |
                             final String characterEncoding) {
189 | 13 |
                     final Iterator<Routing> iterator = getRoutings().iterator();
190 | 177 |
                     while (iterator.hasNext()) {
191 | 175 |
                             final Routing routing = iterator.next();
192 | 175 |
                             final Matcher matcher = routing.getPattern().matcher(path);
193 | 175 |
                             if (matcher.find()) {
194 | 11 |
                                     if (routing.isAcceptable(requestMethod)) {
195 | 11 |
                                             final Map<String, Routing> onSubmitRoutings = new HashMap<String, Routing>();
196 | 11 |
                                             onSubmitRoutings.put(routing.getOnSubmit(), routing);
197 | 128 |
                                             while (iterator.hasNext()) {
198 | 117 |
                                                     final Routing anotherRouting = iterator.next();
199 | 117 |
                                                     if (routing.getPattern().pattern().equals(
200 |  |
                                                                     anotherRouting.getPattern().pattern())
201 |  |
                                                                     && routing.getRequestMethod().equals(
202 |  |
                                                                                     anotherRouting.getRequestMethod())) {
203 | 0 |
                                                             onSubmitRoutings.put(anotherRouting.getOnSubmit(),
204 |  |
                                                                             anotherRouting);
205 |  |
                                                     }
206 | 117 |
                                             }
207 |  |
208 | 11 |
                                             final Map<String, String[]> uriParameters = new HashMap<String, String[]>();
209 | 19 |
                                             for (int i = 0; i < matcher.groupCount(); i++) {
210 | 8 |
                                                     final String name = routing.getUriParameterNames().get(
211 |  |
                                                                     i);
212 | 8 |
                                                     final String value = matcher.group(i + 1);
213 | 8 |
                                                     uriParameters.put(name, new String[] { value });
214 |  |
                                             }
215 |  |
216 | 11 |
                                             final PathInfo pathInfo = new ResolvedPathInfo(
217 |  |
                                                             uriParameters, onSubmitRoutings);
218 |  |
219 | 11 |
                                             return pathInfo;
220 |  |
                                     }
221 |  |
                             }
222 | 164 |
                     }
223 |  |
224 | 2 |
                     return null;
225 |  |
             }
226 |  |
227 |  |
             /**
228 |  |
              * 指定された正規表現を括弧「()」で囲んで正規表現のグループにします。
229 |  |
              *
230 |  |
              * @param regex
231 |  |
              *            正規表現
232 |  |
              * @return 正規表現のグループ
233 |  |
              */
234 |  |
             private static String regexGroup(final String regex) {
235 | 385 |
                     return "(" + regex + ")";
236 |  |
             }
237 |  |
238 |  |
             /**
239 |  |
              * {@inheritDoc}
240 |  |
              */
241 |  |
             public String reverseLookup(final Class<?> actionClass,
242 |  |
                             final String methodName, final Map<String, String[]> parameters,
243 |  |
                             final String characterEncoding) {
244 | 26 |
                     final Collection<Routing> routings = getRoutings();
245 | 26 |
                     final Routing routing = findRouting(routings, actionClass, methodName);
246 | 25 |
                     final String actionPath = routing.getActionPath();
247 | 25 |
                     final Map<String, String[]> copyOfParameters = new HashMap<String, String[]>(
248 |  |
                                     parameters);
249 | 25 |
                     final StringBuilder path = new StringBuilder(100);
250 | 25 |
                     path.append(pathTemplateParser.parse(actionPath,
251 | 25 |
                                     new PathTemplateParser.Handler() {
252 |  |
253 |  |
                                             public String handle(final String name, final String regex) {
254 | 20 |
                                                     if (!copyOfParameters.containsKey(name)) {
255 | 1 |
                                                             throw new RoutingException(format("ECUB0104",
256 |  |
                                                                             actionPath, name));
257 |  |
                                                     }
258 | 19 |
                                                     final String value = copyOfParameters.remove(name)[0];
259 | 19 |
                                                     if (!value.matches(regex)) {
260 | 1 |
                                                             throw new RoutingException(format("ECUB0105",
261 |  |
                                                                             actionPath, name, value, regex));
262 |  |
                                                     }
263 | 18 |
                                                     return encode(value, characterEncoding);
264 |  |
                                             }
265 |  |
266 |  |
                                     }));
267 |  |
268 | 23 |
                     if (!copyOfParameters.isEmpty()) {
269 | 8 |
                             final QueryStringBuilder builder = new QueryStringBuilder();
270 | 8 |
                             if (characterEncoding != null) {
271 | 8 |
                                     builder.setEncode(characterEncoding);
272 |  |
                             }
273 | 8 |
                             for (final Entry<String, String[]> entry : copyOfParameters
274 |  |
                                             .entrySet()) {
275 | 22 |
                                     for (final String value : entry.getValue()) {
276 | 11 |
                                             builder.addParam(entry.getKey(), value);
277 |  |
                                     }
278 |  |
                             }
279 | 8 |
                             path.append('?');
280 | 8 |
                             path.append(builder.toString());
281 |  |
                     }
282 |  |
283 | 23 |
                     return path.toString();
284 |  |
             }
285 |  |
286 |  |
             /**
287 |  |
              * 指定されたクラス、メソッドに対応するルーティング情報を検索します。
288 |  |
              *
289 |  |
              * @param routings
290 |  |
              *            ルーティング情報
291 |  |
              * @param actionClass
292 |  |
              *            クラス
293 |  |
              * @param methodName
294 |  |
              *            メソッド
295 |  |
              * @return ルーティング情報
296 |  |
              * @throws RoutingException
297 |  |
              *             ルーティング情報が見つからなかった場合
298 |  |
              */
299 |  |
             private static Routing findRouting(final Collection<Routing> routings,
300 |  |
                             final Class<?> actionClass, final String methodName) {
301 | 26 |
                     for (final Routing routing : routings) {
302 | 79 |
                             if (actionClass.getCanonicalName().equals(
303 |  |
                                             routing.getActionClass().getCanonicalName())) {
304 | 79 |
                                     if (methodName.equals(routing.getActionMethod().getName())) {
305 | 25 |
                                             return routing;
306 |  |
                                     }
307 |  |
                             }
308 |  |
                     }
309 | 1 |
                     throw new RoutingException(format("ECUB0103", actionClass, methodName));
310 |  |
             }
311 |  |
312 |  |
             /**
313 |  |
              * 指定された文字列を URL エンコードします。
314 |  |
              *
315 |  |
              * @param str
316 |  |
              *            文字列
317 |  |
              * @param characterEncoding
318 |  |
              *            エンコーディング
319 |  |
              * @return エンコードされた文字列
320 |  |
              */
321 |  |
             private static String encode(final String str,
322 |  |
                             final String characterEncoding) {
323 | 18 |
                     if (characterEncoding == null) {
324 | 0 |
                             return str;
325 |  |
                     }
326 |  |
                     try {
327 | 18 |
                             return URLBodyEncoder.encode(str, characterEncoding);
328 | 0 |
                     } catch (final UnsupportedEncodingException e) {
329 | 0 |
                             throw new RoutingException(e);
330 |  |
                     }
331 |  |
             }
332 |  |
333 |  |
             /**
334 |  |
              * ルーティングのキーです。
335 |  |
              *
336 |  |
              * @author baba
337 |  |
              */
338 | 3535 |
             static class RoutingKey implements Comparable<RoutingKey> {
339 |  |
340 |  |
                     private final int priority;
341 |  |
342 |  |
                     private final List<String> uriParameterNames;
343 |  |
344 |  |
                     private final Pattern pattern;
345 |  |
346 |  |
                     private final RequestMethod requestMethod;
347 |  |
348 |  |
                     private final String onSubmit;
349 |  |
350 | 586 |
                     public RoutingKey(final Routing routing) {
351 | 586 |
                             this.priority = routing.getPriority();
352 | 586 |
                             this.uriParameterNames = routing.getUriParameterNames();
353 | 586 |
                             this.pattern = routing.getPattern();
354 | 586 |
                             this.requestMethod = routing.getRequestMethod();
355 | 586 |
                             this.onSubmit = routing.getOnSubmit();
356 | 586 |
                     }
357 |  |
358 |  |
                     /**
359 |  |
                      * このキーと指定されたキーを比較します。
360 |  |
                      * <p>
361 |  |
                      * 正規表現パターンと HTTP メソッドが同じ場合は同値とみなします。
362 |  |
                      * </p>
363 |  |
                      * <p>
364 |  |
                      * また、大小関係は以下のようになります。
365 |  |
                      * <ul>
366 |  |
                      * <li>優先度(@link {@link Path#priority()})が小さい順</li>
367 |  |
                      * <li>URI 埋め込みパラメータが少ない順</li>
368 |  |
                      * <li>正規表現の順(@link {@link String#compareTo(String)})</li>
369 |  |
                      * </ul>
370 |  |
                      * </p>
371 |  |
                      *
372 |  |
                      * @param another
373 |  |
                      *            比較対象のキー
374 |  |
                      * @return 比較結果
375 |  |
                      */
376 |  |
                     public int compareTo(final RoutingKey another) {
377 | 3537 |
                             int compare = this.priority - another.priority;
378 | 3537 |
                             if (compare != 0) {
379 | 45 |
                                     return compare;
380 |  |
                             }
381 | 3492 |
                             compare = this.uriParameterNames.size()
382 |  |
                                             - another.uriParameterNames.size();
383 | 3492 |
                             if (compare != 0) {
384 | 1186 |
                                     return compare;
385 |  |
                             }
386 | 2306 |
                             compare = this.pattern.pattern().compareTo(
387 |  |
                                             another.pattern.pattern());
388 | 2306 |
                             if (compare != 0) {
389 | 1636 |
                                     return compare;
390 |  |
                             }
391 | 670 |
                             compare = this.requestMethod.compareTo(another.requestMethod);
392 | 670 |
                             if (compare != 0) {
393 | 668 |
                                     return compare;
394 |  |
                             }
395 | 2 |
                             if (this.onSubmit == another.onSubmit) {
396 | 2 |
                                     compare = 0;
397 | 0 |
                             } else if (this.onSubmit == null) {
398 | 0 |
                                     compare = -1;
399 | 0 |
                             } else if (another.onSubmit == null) {
400 | 0 |
                                     compare = 1;
401 |  |
                             } else {
402 | 0 |
                                     compare = this.onSubmit.compareTo(another.onSubmit);
403 |  |
                             }
404 | 2 |
                             return compare;
405 |  |
                     }
406 |  |
407 |  |
                     /**
408 |  |
                      * {@inheritDoc}
409 |  |
                      */
410 |  |
                     @Override
411 |  |
                     public int hashCode() {
412 | 0 |
                             final int prime = 31;
413 | 0 |
                             int result = 1;
414 | 0 |
                             result = prime * result
415 |  |
                                             + ((onSubmit == null) ? 0 : onSubmit.hashCode());
416 | 0 |
                             result = prime
417 |  |
                                             * result
418 |  |
                                             + ((pattern.pattern() == null) ? 0 : pattern.pattern()
419 |  |
                                                             .hashCode());
420 | 0 |
                             result = prime * result + priority;
421 | 0 |
                             result = prime * result
422 |  |
                                             + ((requestMethod == null) ? 0 : requestMethod.hashCode());
423 | 0 |
                             result = prime
424 |  |
                                             * result
425 |  |
                                             + ((uriParameterNames == null) ? 0 : uriParameterNames
426 |  |
                                                             .hashCode());
427 | 0 |
                             return result;
428 |  |
                     }
429 |  |
430 |  |
                     /**
431 |  |
                      * {@inheritDoc}
432 |  |
                      */
433 |  |
                     @Override
434 |  |
                     public boolean equals(final Object obj) {
435 | 0 |
                             if (this == obj) {
436 | 0 |
                                     return true;
437 |  |
                             }
438 | 0 |
                             if (obj == null) {
439 | 0 |
                                     return false;
440 |  |
                             }
441 | 0 |
                             if (getClass() != obj.getClass()) {
442 | 0 |
                                     return false;
443 |  |
                             }
444 | 0 |
                             final RoutingKey other = (RoutingKey) obj;
445 | 0 |
                             if (onSubmit == null) {
446 | 0 |
                                     if (other.onSubmit != null) {
447 | 0 |
                                             return false;
448 |  |
                                     }
449 | 0 |
                             } else if (!onSubmit.equals(other.onSubmit)) {
450 | 0 |
                                     return false;
451 |  |
                             }
452 | 0 |
                             if (pattern == null) {
453 | 0 |
                                     if (other.pattern != null) {
454 | 0 |
                                             return false;
455 |  |
                                     }
456 | 0 |
                             } else if (!pattern.pattern().equals(other.pattern.pattern())) {
457 | 0 |
                                     return false;
458 |  |
                             }
459 | 0 |
                             if (priority != other.priority) {
460 | 0 |
                                     return false;
461 |  |
                             }
462 | 0 |
                             if (requestMethod == null) {
463 | 0 |
                                     if (other.requestMethod != null) {
464 | 0 |
                                             return false;
465 |  |
                                     }
466 | 0 |
                             } else if (!requestMethod.equals(other.requestMethod)) {
467 | 0 |
                                     return false;
468 |  |
                             }
469 | 0 |
                             if (uriParameterNames == null) {
470 | 0 |
                                     if (other.uriParameterNames != null) {
471 | 0 |
                                             return false;
472 |  |
                                     }
473 | 0 |
                             } else if (!uriParameterNames.equals(other.uriParameterNames)) {
474 | 0 |
                                     return false;
475 |  |
                             }
476 | 0 |
                             return true;
477 |  |
                     }
478 |  |
479 |  |
             }
480 |  |
481 |  |
             /**
482 |  |
              * パスから取得した情報の実装です。
483 |  |
              *
484 |  |
              * @author baba
485 |  |
              */
486 |  |
             static class ResolvedPathInfo implements PathInfo {
487 |  |
488 |  |
                     /** URI から抽出したパラメータ。 */
489 |  |
                     private final Map<String, String[]> uriParameters;
490 |  |
491 |  |
                     /** 要求パラメータ名と対応するルーティングのマッピング。 */
492 |  |
                     private final Map<String, Routing> routings;
493 |  |
494 |  |
                     /**
495 |  |
                      * インスタンス化します。
496 |  |
                      *
497 |  |
                      * @param uriParameters
498 |  |
                      *            URI から抽出したパラメータ
499 |  |
                      * @param routings
500 |  |
                      *            要求パラメータ名とルーティングのマッピング
501 |  |
                      */
502 |  |
                     public ResolvedPathInfo(final Map<String, String[]> uriParameters,
503 | 11 |
                                     final Map<String, Routing> routings) {
504 | 11 |
                             this.uriParameters = uriParameters;
505 | 11 |
                             this.routings = routings;
506 | 11 |
                     }
507 |  |
508 |  |
                     /**
509 |  |
                      * {@inheritDoc}
510 |  |
                      */
511 |  |
                     public Map<String, String[]> getURIParameters() {
512 | 10 |
                             return uriParameters;
513 |  |
                     }
514 |  |
515 |  |
                     /**
516 |  |
                      * {@inheritDoc}
517 |  |
                      */
518 |  |
                     public Routing dispatch(final Map<String, Object[]> parameterMap) {
519 | 11 |
                             for (final Entry<String, Routing> entry : routings.entrySet()) {
520 | 11 |
                                     if (parameterMap.containsKey(entry.getKey())) {
521 | 0 |
                                             return entry.getValue();
522 |  |
                                     }
523 |  |
                             }
524 | 11 |
                             return routings.get(null);
525 |  |
                     }
526 |  |
527 |  |
             }
528 |  |
529 |  |
     }