Coverage Report - org.seasar.cubby.routing.impl.PathResolverImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
PathResolverImpl
94%
135/144
84%
62/74
0
PathResolverImpl$ActionClassCollector
91%
20/22
88%
14/16
0
PathResolverImpl$RoutingComparator
76%
16/21
64%
9/14
0
 
 1  
 /*
 2  
  * Copyright 2004-2008 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.CubbyConstants.INTERNAL_FORWARD_DIRECTORY;
 19  
 
 20  
 import java.io.IOException;
 21  
 import java.io.UnsupportedEncodingException;
 22  
 import java.lang.reflect.Method;
 23  
 import java.net.URLDecoder;
 24  
 import java.net.URLEncoder;
 25  
 import java.util.ArrayList;
 26  
 import java.util.Collections;
 27  
 import java.util.Comparator;
 28  
 import java.util.HashMap;
 29  
 import java.util.Iterator;
 30  
 import java.util.List;
 31  
 import java.util.Map;
 32  
 import java.util.TreeMap;
 33  
 import java.util.Map.Entry;
 34  
 import java.util.regex.Matcher;
 35  
 import java.util.regex.Pattern;
 36  
 
 37  
 import org.seasar.cubby.action.Action;
 38  
 import org.seasar.cubby.action.RequestMethod;
 39  
 import org.seasar.cubby.exception.ActionRuntimeException;
 40  
 import org.seasar.cubby.exception.DuplicateRoutingRuntimeException;
 41  
 import org.seasar.cubby.routing.InternalForwardInfo;
 42  
 import org.seasar.cubby.routing.PathResolver;
 43  
 import org.seasar.cubby.routing.Routing;
 44  
 import org.seasar.cubby.util.CubbyUtils;
 45  
 import org.seasar.cubby.util.QueryStringBuilder;
 46  
 import org.seasar.framework.convention.NamingConvention;
 47  
 import org.seasar.framework.exception.IORuntimeException;
 48  
 import org.seasar.framework.log.Logger;
 49  
 import org.seasar.framework.util.ClassUtil;
 50  
 import org.seasar.framework.util.Disposable;
 51  
 import org.seasar.framework.util.DisposableUtil;
 52  
 import org.seasar.framework.util.StringUtil;
 53  
 
 54  
 /**
 55  
  * クラスパスから {@link Action} を検索し、クラス名やメソッド名、そのクラスやメソッドに指定された
 56  
  * {@link org.seasar.cubby.action.Path}
 57  
  * の情報からアクションのパスを抽出し、リクエストされたパスをどのメソッドに振り分けるかを決定します。
 58  
  * 
 59  
  * @author baba
 60  
  * @since 1.0.0
 61  
  */
 62  843
 public class PathResolverImpl implements PathResolver, Disposable {
 63  
 
 64  
         /** ロガー */
 65  1
         private static final Logger logger = Logger
 66  
                         .getLogger(PathResolverImpl.class);
 67  
 
 68  
         /** デフォルトの URI エンコーディング */
 69  
         private static final String DEFAULT_URI_ENCODING = "UTF-8";
 70  
 
 71  
         /** アクションのパスからパラメータを抽出するための正規表現パターン */
 72  1
         private static Pattern URI_PARAMETER_MATCHING_PATTERN = Pattern
 73  
                         .compile("([{]([^}]+)[}])([^{]*)");
 74  
 
 75  
         /** デフォルトの URI パラメータ正規表現 */
 76  
         private static final String DEFAULT_URI_PARAMETER_REGEX = "[a-zA-Z0-9]+";
 77  
 
 78  
         /** 初期化フラグ */
 79  
         private boolean initialized;
 80  
 
 81  
         /** 命名規約 */
 82  
         private NamingConvention namingConvention;
 83  
 
 84  
         /** ルーティングのコンパレータ */
 85  52
         private final Comparator<Routing> routingComparator = new RoutingComparator();
 86  
 
 87  
         /** 登録されたルーティングのマップ */
 88  52
         private final Map<Routing, Routing> routings = new TreeMap<Routing, Routing>(
 89  
                         routingComparator);
 90  
 
 91  
         /** URI のエンコーディング */
 92  52
         private String uriEncoding = DEFAULT_URI_ENCODING;
 93  
 
 94  
         /**
 95  
          * 手動登録用のプライオリティカウンタ
 96  
          */
 97  52
         private int priorityCounter = 0;
 98  
 
 99  
         /**
 100  
          * インスタンス化します。
 101  
          */
 102  52
         public PathResolverImpl() {
 103  52
         }
 104  
 
 105  
         /**
 106  
          * ルーティング情報を取得します。
 107  
          * 
 108  
          * @return ルーティング情報
 109  
          */
 110  
         public List<Routing> getRoutings() {
 111  2
                 initialize();
 112  2
                 return Collections.unmodifiableList(new ArrayList<Routing>(routings
 113  
                                 .values()));
 114  
         }
 115  
 
 116  
         /**
 117  
          * URI エンコーディングを設定します。
 118  
          * 
 119  
          * @param uriEncoding
 120  
          *            URI エンコーディング
 121  
          */
 122  
         public void setUriEncoding(final String uriEncoding) {
 123  52
                 this.uriEncoding = uriEncoding;
 124  52
         }
 125  
 
 126  
         /**
 127  
          * 初期化します。
 128  
          */
 129  
         public void initialize() {
 130  15
                 if (!initialized) {
 131  15
                         final ClassCollector classCollector = new ActionClassCollector();
 132  15
                         classCollector.collect();
 133  
 
 134  15
                         DisposableUtil.add(this);
 135  15
                         initialized = true;
 136  
                 }
 137  15
         }
 138  
 
 139  
         /**
 140  
          * {@inheritDoc}
 141  
          */
 142  
         public void dispose() {
 143  15
                 final List<Routing> removes = new ArrayList<Routing>();
 144  15
                 for (final Routing routing : routings.keySet()) {
 145  358
                         if (routing.isAuto()) {
 146  354
                                 removes.add(routing);
 147  
                         }
 148  
                 }
 149  15
                 for (final Routing routing : removes) {
 150  354
                         routings.remove(routing);
 151  
                 }
 152  15
                 initialized = false;
 153  15
         }
 154  
 
 155  
         /**
 156  
          * ルーティング情報を登録します。
 157  
          * <p>
 158  
          * クラスパスを検索して自動登録されるルーティング情報以外にも、このメソッドによって手動でルーティング情報を登録できます。
 159  
          * </p>
 160  
          * 
 161  
          * @param actionPath
 162  
          *            アクションのパス
 163  
          * @param actionClass
 164  
          *            アクションクラス
 165  
          * @param methodName
 166  
          *            アクションメソッド名
 167  
          */
 168  
         public void add(final String actionPath,
 169  
                         final Class<? extends Action> actionClass, final String methodName) {
 170  60
                 this.add(actionPath, actionClass, methodName, new RequestMethod[0]);
 171  60
         }
 172  
 
 173  
         /**
 174  
          * ルーティング情報を登録します。
 175  
          * <p>
 176  
          * クラスパスを検索して自動登録されるルーティング情報以外にも、このメソッドによって手動でルーティング情報を登録できます。
 177  
          * </p>
 178  
          * 
 179  
          * @param actionPath
 180  
          *            アクションのパス
 181  
          * @param actionClass
 182  
          *            アクションクラス
 183  
          * @param methodName
 184  
          *            アクションメソッド名
 185  
          * @param requestMethods
 186  
          *            リクエストメソッド
 187  
          */
 188  
         public void add(final String actionPath,
 189  
                         final Class<? extends Action> actionClass, final String methodName,
 190  
                         final RequestMethod... requestMethods) {
 191  
 
 192  63
                 final Method method = ClassUtil.getMethod(actionClass, methodName,
 193  
                                 new Class<?>[0]);
 194  63
                 if (requestMethods == null || requestMethods.length == 0) {
 195  183
                         for (final RequestMethod requestMethod : CubbyUtils.DEFAULT_ACCEPT_ANNOTATION
 196  
                                         .value()) {
 197  122
                                 this.add(actionPath, actionClass, method, requestMethod, false);
 198  
                         }
 199  
                 } else {
 200  4
                         for (final RequestMethod requestMethod : requestMethods) {
 201  2
                                 this.add(actionPath, actionClass, method, requestMethod, false);
 202  
                         }
 203  
                 }
 204  63
         }
 205  
 
 206  
         /**
 207  
          * ルーティング情報を登録します。
 208  
          * 
 209  
          * @param actionPath
 210  
          *            アクションのパス
 211  
          * @param actionClass
 212  
          *            アクションクラス
 213  
          * @param method
 214  
          *            アクションメソッド
 215  
          * @param requestMethods
 216  
          *            リクエストメソッド
 217  
          * @param auto
 218  
          *            自動登録かどうか
 219  
          */
 220  
         private void add(final String actionPath,
 221  
                         final Class<? extends Action> actionClass, final Method method,
 222  
                         final RequestMethod requestMethod, final boolean auto) {
 223  
 
 224  478
                 final Matcher matcher = URI_PARAMETER_MATCHING_PATTERN
 225  
                                 .matcher(actionPath);
 226  478
                 String uriRegex = actionPath;
 227  478
                 final List<String> uriParameterNames = new ArrayList<String>();
 228  820
                 while (matcher.find()) {
 229  342
                         final String holder = matcher.group(2);
 230  342
                         final String[] tokens = CubbyUtils.split2(holder, ',');
 231  342
                         uriParameterNames.add(tokens[0]);
 232  
                         final String uriParameterRegex;
 233  342
                         if (tokens.length == 1) {
 234  242
                                 uriParameterRegex = DEFAULT_URI_PARAMETER_REGEX;
 235  
                         } else {
 236  100
                                 uriParameterRegex = tokens[1];
 237  
                         }
 238  342
                         uriRegex = StringUtil.replace(uriRegex, matcher.group(1),
 239  
                                         regexGroup(uriParameterRegex));
 240  342
                 }
 241  478
                 uriRegex = "^" + uriRegex + "$";
 242  478
                 final Pattern pattern = Pattern.compile(uriRegex);
 243  
 
 244  478
                 final String onSubmit = CubbyUtils.getOnSubmit(method);
 245  
 
 246  478
                 final int priority = auto ? CubbyUtils.getPriority(method)
 247  
                                 : priorityCounter++;
 248  
 
 249  478
                 final Routing routing = new RoutingImpl(actionClass, method,
 250  
                                 actionPath, uriParameterNames, pattern, requestMethod,
 251  
                                 onSubmit, priority, auto);
 252  
 
 253  478
                 if (routings.containsKey(routing)) {
 254  0
                         final Routing duplication = routings.get(routing);
 255  0
                         if (!routing.getActionClass().equals(duplication.getActionClass())
 256  
                                         || !routing.getMethod().equals(duplication.getMethod())) {
 257  0
                                 throw new DuplicateRoutingRuntimeException("ECUB0001",
 258  
                                                 new Object[] { routing, duplication });
 259  
                         }
 260  0
                 } else {
 261  478
                         routings.put(routing, routing);
 262  478
                         if (logger.isDebugEnabled()) {
 263  478
                                 logger.log("DCUB0007", new Object[] { routing });
 264  
                         }
 265  
                 }
 266  478
         }
 267  
 
 268  
         /**
 269  
          * {@inheritDoc}
 270  
          */
 271  
         public InternalForwardInfo getInternalForwardInfo(final String path,
 272  
                         final String requestMethod) {
 273  13
                 initialize();
 274  
 
 275  
                 final String decodedPath;
 276  
                 try {
 277  13
                         decodedPath = URLDecoder.decode(path, uriEncoding);
 278  0
                 } catch (final IOException e) {
 279  0
                         throw new IORuntimeException(e);
 280  13
                 }
 281  
 
 282  13
                 final InternalForwardInfo internalForwardInfo = findInternalForwardInfo(
 283  
                                 decodedPath, requestMethod);
 284  13
                 return internalForwardInfo;
 285  
         }
 286  
 
 287  
         /**
 288  
          * 指定されたパス、メソッドに対応する内部フォワード情報を検索します。
 289  
          * 
 290  
          * @param path
 291  
          *            リクエストのパス
 292  
          * @param requestMethod
 293  
          *            リクエストのメソッド
 294  
          * @return 内部フォワード情報、対応する内部フォワード情報が登録されていない場合は <code>null</code>
 295  
          */
 296  
         private InternalForwardInfo findInternalForwardInfo(final String path,
 297  
                         final String requestMethod) {
 298  13
                 final Iterator<Routing> iterator = routings.values().iterator();
 299  190
                 while (iterator.hasNext()) {
 300  188
                         final Routing routing = iterator.next();
 301  188
                         final Matcher matcher = routing.getPattern().matcher(path);
 302  188
                         if (matcher.find()) {
 303  12
                                 if (routing.isAcceptable(requestMethod)) {
 304  11
                                         final Map<String, Routing> onSubmitRoutings = new HashMap<String, Routing>();
 305  11
                                         onSubmitRoutings.put(routing.getOnSubmit(), routing);
 306  127
                                         while (iterator.hasNext()) {
 307  116
                                                 final Routing anotherRouting = iterator.next();
 308  116
                                                 if (routing.getPattern().pattern().equals(
 309  
                                                                 anotherRouting.getPattern().pattern())
 310  
                                                                 && routing.getRequestMethod().equals(
 311  
                                                                                 anotherRouting.getRequestMethod())) {
 312  0
                                                         onSubmitRoutings.put(anotherRouting.getOnSubmit(),
 313  
                                                                         anotherRouting);
 314  
                                                 }
 315  116
                                         }
 316  
 
 317  11
                                         final Map<String, String[]> uriParameters = new HashMap<String, String[]>();
 318  19
                                         for (int i = 0; i < matcher.groupCount(); i++) {
 319  8
                                                 final String name = routing.getUriParameterNames().get(
 320  
                                                                 i);
 321  8
                                                 final String value = matcher.group(i + 1);
 322  8
                                                 uriParameters.put(name, new String[] { value });
 323  
                                         }
 324  11
                                         final String inernalFowardPath = buildInternalForwardPath(uriParameters);
 325  
 
 326  11
                                         final InternalForwardInfo internalForwardInfo = new InternalForwardInfoImpl(
 327  
                                                         inernalFowardPath, onSubmitRoutings);
 328  
 
 329  11
                                         return internalForwardInfo;
 330  
                                 }
 331  
                         }
 332  177
                 }
 333  
 
 334  2
                 return null;
 335  
         }
 336  
 
 337  
         /**
 338  
          * {@inheritDoc}
 339  
          */
 340  
         public String buildInternalForwardPath(
 341  
                         final Map<String, String[]> parameters) {
 342  15
                 final StringBuilder builder = new StringBuilder(100);
 343  15
                 builder.append(INTERNAL_FORWARD_DIRECTORY);
 344  15
                 if (parameters != null && !parameters.isEmpty()) {
 345  8
                         builder.append("?");
 346  8
                         final QueryStringBuilder query = new QueryStringBuilder();
 347  8
                         if (!StringUtil.isEmpty(uriEncoding)) {
 348  8
                                 query.setEncode(uriEncoding);
 349  
                         }
 350  8
                         for (final Entry<String, String[]> entry : parameters.entrySet()) {
 351  24
                                 for (final String parameter : entry.getValue()) {
 352  12
                                         query.addParam(entry.getKey(), parameter);
 353  
                                 }
 354  
                         }
 355  8
                         builder.append(query.toString());
 356  
                 }
 357  15
                 return builder.toString();
 358  
         }
 359  
 
 360  
         /**
 361  
          * 命名規約を設定します。
 362  
          * 
 363  
          * @param namingConvention
 364  
          *            命名規約
 365  
          */
 366  
         public void setNamingConvention(final NamingConvention namingConvention) {
 367  52
                 this.namingConvention = namingConvention;
 368  52
         }
 369  
 
 370  
         /**
 371  
          * 指定された正規表現を括弧「()」で囲んで正規表現のグループにします。
 372  
          * 
 373  
          * @param regex
 374  
          *            正規表現
 375  
          * @return 正規表現のグループ
 376  
          */
 377  
         private static String regexGroup(final String regex) {
 378  342
                 return "(" + regex + ")";
 379  
         }
 380  
 
 381  
         /**
 382  
          * ルーティングのコンパレータ。
 383  
          * 
 384  
          * @author baba
 385  
          */
 386  4251
         static class RoutingComparator implements Comparator<Routing> {
 387  
 
 388  
                 /**
 389  
                  * routing1 と routing2 を比較します。
 390  
                  * <p>
 391  
                  * 正規表現パターンと HTTP メソッドが同じ場合は同値とみなします。
 392  
                  * </p>
 393  
                  * <p>
 394  
                  * また、大小関係は以下のようになります。
 395  
                  * <ul>
 396  
                  * <li>URI 埋め込みパラメータが少ない順</li>
 397  
                  * <li>正規表現の順(@link {@link String#compareTo(String)})</li>
 398  
                  * </ul>
 399  
                  * </p>
 400  
                  * 
 401  
                  * @param routing1
 402  
                  *            比較対象1
 403  
                  * @param routing2
 404  
                  *            比較対象2
 405  
                  * @return 比較結果
 406  
                  */
 407  
                 public int compare(final Routing routing1, final Routing routing2) {
 408  4198
                         int compare = routing1.getPriority() - routing2.getPriority();
 409  4198
                         if (compare != 0) {
 410  538
                                 return compare;
 411  
                         }
 412  3660
                         compare = routing1.getUriParameterNames().size()
 413  
                                         - routing2.getUriParameterNames().size();
 414  3660
                         if (compare != 0) {
 415  966
                                 return compare;
 416  
                         }
 417  2694
                         compare = routing1.getPattern().pattern().compareTo(
 418  
                                         routing2.getPattern().pattern());
 419  2694
                         if (compare != 0) {
 420  1720
                                 return compare;
 421  
                         }
 422  974
                         compare = routing1.getRequestMethod().compareTo(
 423  
                                         routing2.getRequestMethod());
 424  974
                         if (compare != 0) {
 425  618
                                 return compare;
 426  
                         }
 427  356
                         if (routing1.getOnSubmit() == routing2.getOnSubmit()) {
 428  356
                                 compare = 0;
 429  0
                         } else if (routing1.getOnSubmit() == null) {
 430  0
                                 compare = -1;
 431  0
                         } else if (routing2.getOnSubmit() == null) {
 432  0
                                 compare = 1;
 433  
                         } else {
 434  0
                                 compare = routing1.getOnSubmit().compareTo(
 435  
                                                 routing2.getOnSubmit());
 436  
                         }
 437  356
                         return compare;
 438  
                 }
 439  
         }
 440  
 
 441  
         /**
 442  
          * クラスを収集します。
 443  
          * 
 444  
          * @author baba
 445  
          */
 446  
         class ActionClassCollector extends ClassCollector {
 447  
 
 448  
                 /**
 449  
                  * デフォルトコンストラクタ。
 450  
                  */
 451  15
                 public ActionClassCollector() {
 452  15
                         super(namingConvention);
 453  15
                 }
 454  
 
 455  
                 /**
 456  
                  * 指定されたパッケージとクラス名からクラスを検索し、アクションクラスであれば{@link PathResolverImpl}に登録します。
 457  
                  * 
 458  
                  * @param packageName
 459  
                  *            パッケージ名
 460  
                  * @param shortClassName
 461  
                  *            クラス名
 462  
                  */
 463  
                 public void processClass(final String packageName,
 464  
                                 final String shortClassName) {
 465  301
                         if (shortClassName.indexOf('$') != -1) {
 466  128
                                 return;
 467  
                         }
 468  173
                         final String className = ClassUtil.concatName(packageName,
 469  
                                         shortClassName);
 470  173
                         if (!namingConvention.isTargetClassName(className)) {
 471  0
                                 return;
 472  
                         }
 473  173
                         if (!className.endsWith(namingConvention.getActionSuffix())) {
 474  102
                                 return;
 475  
                         }
 476  71
                         final Class<? extends Action> clazz = classForName(className);
 477  71
                         if (!CubbyUtils.isActionClass(clazz)) {
 478  14
                                 return;
 479  
                         }
 480  57
                         if (namingConvention.isSkipClass(clazz)) {
 481  0
                                 return;
 482  
                         }
 483  
 
 484  1167
                         for (final Method method : clazz.getMethods()) {
 485  1110
                                 if (CubbyUtils.isActionMethod(method)) {
 486  198
                                         final String actionPath = CubbyUtils.getActionPath(clazz,
 487  
                                                         method);
 488  198
                                         final RequestMethod[] acceptableRequestMethods = CubbyUtils
 489  
                                                         .getAcceptableRequestMethods(clazz, method);
 490  552
                                         for (final RequestMethod requestMethod : acceptableRequestMethods) {
 491  354
                                                 add(actionPath, clazz, method, requestMethod, true);
 492  
                                         }
 493  
                                 }
 494  
                         }
 495  57
                 }
 496  
 
 497  
         }
 498  
 
 499  
         /**
 500  
          * クラスを取得します。
 501  
          * 
 502  
          * @param <T>
 503  
          *            型
 504  
          * @param className
 505  
          *            クラス名
 506  
          * @return クラス
 507  
          */
 508  
         @SuppressWarnings("unchecked")
 509  
         private static <T> Class<T> classForName(final String className) {
 510  71
                 return ClassUtil.forName(className);
 511  
         }
 512  
 
 513  
         /**
 514  
          * {@inheritDoc}
 515  
          */
 516  
         public String reverseLookup(final Class<? extends Action> actionClass,
 517  
                         final String methodName, final Map<String, String[]> parameters) {
 518  16
                 final Routing routing = findRouting(actionClass, methodName);
 519  15
                 final String actionPath = routing.getActionPath();
 520  
 
 521  15
                 final Matcher matcher = URI_PARAMETER_MATCHING_PATTERN
 522  
                                 .matcher(actionPath);
 523  15
                 final Map<String, String[]> copyOfParameters = new HashMap<String, String[]>(
 524  
                                 parameters);
 525  15
                 String redirectPath = actionPath;
 526  23
                 while (matcher.find()) {
 527  10
                         final String holder = matcher.group(2);
 528  10
                         final String[] tokens = CubbyUtils.split2(holder, ',');
 529  10
                         final String uriParameterName = tokens[0];
 530  10
                         if (!copyOfParameters.containsKey(uriParameterName)) {
 531  1
                                 throw new ActionRuntimeException("ECUB0104", new Object[] {
 532  
                                                 actionPath, uriParameterName });
 533  
                         }
 534  9
                         final String value = copyOfParameters.remove(uriParameterName)[0];
 535  
                         final String uriParameterRegex;
 536  9
                         if (tokens.length == 1) {
 537  6
                                 uriParameterRegex = DEFAULT_URI_PARAMETER_REGEX;
 538  
                         } else {
 539  3
                                 uriParameterRegex = tokens[1];
 540  
                         }
 541  9
                         if (!value.matches(uriParameterRegex)) {
 542  1
                                 throw new ActionRuntimeException("ECUB0105",
 543  
                                                 new Object[] { actionPath, uriParameterName, value,
 544  
                                                                 uriParameterRegex });
 545  
                         }
 546  
                         try {
 547  8
                                 final String encodedValue = URLEncoder.encode(value,
 548  
                                                 uriEncoding);
 549  8
                                 redirectPath = StringUtil.replace(redirectPath, matcher
 550  
                                                 .group(1), encodedValue);
 551  0
                         } catch (UnsupportedEncodingException e) {
 552  0
                                 throw new IORuntimeException(e);
 553  8
                         }
 554  8
                 }
 555  13
                 if (!copyOfParameters.isEmpty()) {
 556  8
                         final QueryStringBuilder builder = new QueryStringBuilder();
 557  8
                         builder.setEncode(uriEncoding);
 558  8
                         for (final Entry<String, String[]> entry : copyOfParameters
 559  
                                         .entrySet()) {
 560  22
                                 for (final String value : entry.getValue()) {
 561  11
                                         builder.addParam(entry.getKey(), value);
 562  
                                 }
 563  
                         }
 564  8
                         redirectPath += "?" + builder.toString();
 565  
                 }
 566  
 
 567  13
                 return redirectPath;
 568  
         }
 569  
 
 570  
         /**
 571  
          * 指定されたクラス、メソッドに対応するルーティング情報を検索します。
 572  
          * 
 573  
          * @param actionClass
 574  
          *            クラス
 575  
          * @param methodName
 576  
          *            メソッド
 577  
          * @return ルーティング情報
 578  
          * @throws ActionRuntimeException
 579  
          *             ルーティング情報が見つからなかった場合
 580  
          */
 581  
         private Routing findRouting(final Class<? extends Action> actionClass,
 582  
                         final String methodName) {
 583  16
                 for (final Routing routing : routings.values()) {
 584  35
                         if (actionClass.getCanonicalName().equals(
 585  
                                         routing.getActionClass().getCanonicalName())) {
 586  35
                                 if (methodName.equals(routing.getMethod().getName())) {
 587  15
                                         return routing;
 588  
                                 }
 589  
                         }
 590  
                 }
 591  1
                 throw new ActionRuntimeException("ECUB0103", new Object[] {
 592  
                                 actionClass, methodName });
 593  
         }
 594  
 
 595  
 }