Coverage Report - org.seasar.cubby.util.CubbyUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
CubbyUtils
91%
108/119
81%
55/68
0
CubbyUtils$1AcceptDummy
0%
0/1
N/A
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.util;
 17  
 
 18  
 import java.lang.reflect.Method;
 19  
 import java.util.Collection;
 20  
 
 21  
 import static org.seasar.cubby.action.RequestParameterBindingType.*;
 22  
 import javax.servlet.http.HttpServletRequest;
 23  
 
 24  
 import org.seasar.cubby.action.Accept;
 25  
 import org.seasar.cubby.action.Action;
 26  
 import org.seasar.cubby.action.ActionResult;
 27  
 import org.seasar.cubby.action.Form;
 28  
 import org.seasar.cubby.action.OnSubmit;
 29  
 import org.seasar.cubby.action.Path;
 30  
 import org.seasar.cubby.action.RequestMethod;
 31  
 import org.seasar.cubby.exception.ActionRuntimeException;
 32  
 import org.seasar.framework.beans.BeanDesc;
 33  
 import org.seasar.framework.beans.PropertyDesc;
 34  
 import org.seasar.framework.beans.factory.BeanDescFactory;
 35  
 import org.seasar.framework.util.StringUtil;
 36  
 
 37  
 /**
 38  
  * Cubby内部で使用するユーティリティクラスです。
 39  
  * 
 40  
  * @author baba
 41  
  * @since 1.0.0
 42  
  */
 43  0
 public class CubbyUtils {
 44  
 
 45  
         /** インデックスのメソッド名。 */
 46  
         private static final String INDEX_METHOD_NAME = "index";
 47  
 
 48  
         /** デフォルトの{@link Accept}アノテーション。 */
 49  
         public static Accept DEFAULT_ACCEPT_ANNOTATION;
 50  
         static {
 51  
                 @Accept
 52  0
                 class AcceptDummy {
 53  
                 }
 54  1
                 DEFAULT_ACCEPT_ANNOTATION = AcceptDummy.class
 55  
                                 .getAnnotation(Accept.class);
 56  1
         }
 57  
 
 58  
         /**
 59  
          * 指定されたアクションクラスに対応するディレクトリを取得します。
 60  
          * 
 61  
          * @param actionClass
 62  
          *            アクションクラス
 63  
          * @return アクションクラスに対応するディレクトリ
 64  
          */
 65  
         public static String getActionDirectory(
 66  
                         final Class<? extends Action> actionClass) {
 67  
                 final String actionName;
 68  217
                 final Path path = actionClass.getAnnotation(Path.class);
 69  217
                 if (path != null && !StringUtil.isEmpty(path.value())) {
 70  123
                         actionName = path.value();
 71  
                 } else {
 72  94
                         final String name = left(actionClass.getSimpleName(), "$");
 73  94
                         actionName = toFirstLower(name.replaceAll(
 74  
                                         "(.*[.])*([^.]+)(Action$)", "$2"));
 75  
                 }
 76  217
                 return actionName;
 77  
         }
 78  
 
 79  
         /**
 80  
          * 指定された文字列をセパレータで区切った左側の文字列を返します。
 81  
          * 
 82  
          * @param text
 83  
          *            文字列
 84  
          * @param sep
 85  
          *            セパレータ
 86  
          * @return セパレータで区切った左側の文字列
 87  
          */
 88  
         private static String left(final String text, final String sep) {
 89  94
                 final int pos = text.indexOf(sep);
 90  94
                 if (pos != -1) {
 91  0
                         return text.substring(0, pos);
 92  
                 }
 93  94
                 return text;
 94  
         }
 95  
 
 96  
         /**
 97  
          * 指定された文字列の先頭1文字を小文字に変換します。
 98  
          * 
 99  
          * @param text
 100  
          *            変換する文字列
 101  
          * @return 先頭1文字を小文字にした文字列
 102  
          */
 103  
         private static String toFirstLower(final String text) {
 104  94
                 if (StringUtil.isEmpty(text)) {
 105  0
                         throw new IllegalArgumentException("text is empty.");
 106  
                 }
 107  94
                 final StringBuilder sb = new StringBuilder();
 108  94
                 sb.append(text.substring(0, 1).toLowerCase());
 109  94
                 if (text.length() > 1) {
 110  94
                         sb.append(text.substring(1));
 111  
                 }
 112  94
                 return sb.toString();
 113  
         }
 114  
 
 115  
         /**
 116  
          * 指定されたアクションメソッドのパスを取得します。
 117  
          * 
 118  
          * @param actionClass
 119  
          *            アクションクラス
 120  
          * @param method
 121  
          *            アクションメソッド
 122  
          * @return アクションメソッドのパス
 123  
          */
 124  
         public static String getActionPath(
 125  
                         final Class<? extends Action> actionClass, final Method method) {
 126  
                 final String path;
 127  209
                 final String actionMethodName = getActionMethodName(method);
 128  209
                 if (actionMethodName.startsWith("/")) {
 129  2
                         return path = actionMethodName;
 130  
                 } else {
 131  207
                         final String actionDirectory = CubbyUtils
 132  
                                         .getActionDirectory(actionClass);
 133  207
                         if ("/".equals(actionDirectory)) {
 134  46
                                 path = "/" + actionMethodName;
 135  
                         } else {
 136  161
                                 path = "/" + actionDirectory + "/" + actionMethodName;
 137  
                         }
 138  
                 }
 139  207
                 return path;
 140  
         }
 141  
 
 142  
         /**
 143  
          * 指定されたアクションメソッドのアクションメソッド名を取得します。
 144  
          * 
 145  
          * @param method
 146  
          *            アクションメソッド
 147  
          * @return アクションメソッド名
 148  
          */
 149  
         private static String getActionMethodName(final Method method) {
 150  
                 final String actionName;
 151  209
                 final Path path = method.getAnnotation(Path.class);
 152  209
                 if (path != null && !StringUtil.isEmpty(path.value())) {
 153  130
                         actionName = path.value();
 154  
                 } else {
 155  79
                         final String methodName = method.getName();
 156  79
                         if (INDEX_METHOD_NAME.equals(methodName)) {
 157  16
                                 actionName = "";
 158  
                         } else {
 159  63
                                 actionName = methodName;
 160  
                         }
 161  
                 }
 162  209
                 return actionName;
 163  
         }
 164  
 
 165  
         /**
 166  
          * 指定されたアクションメソッドが受付可能なリクエストメソッドを取得します。
 167  
          * 
 168  
          * @param actionClass
 169  
          *            アクションクラス
 170  
          * @param method
 171  
          *            アクションメソッド
 172  
          * @return 受付可能なリクエストメソッド
 173  
          */
 174  
         public static RequestMethod[] getAcceptableRequestMethods(
 175  
                         final Class<?> actionClass, final Method method) {
 176  
                 final Accept accept;
 177  198
                 if (method.isAnnotationPresent(Accept.class)) {
 178  56
                         accept = method.getAnnotation(Accept.class);
 179  142
                 } else if (actionClass.isAnnotationPresent(Accept.class)) {
 180  0
                         accept = actionClass.getAnnotation(Accept.class);
 181  
                 } else {
 182  142
                         accept = DEFAULT_ACCEPT_ANNOTATION;
 183  
                 }
 184  198
                 return accept.value();
 185  
         }
 186  
 
 187  
         /**
 188  
          * 指定されたオブジェクトのサイズを取得します。
 189  
          * 
 190  
          * @param value
 191  
          *            オブジェクト
 192  
          * @return オブジェクトのサイズ
 193  
          */
 194  
         public static int getObjectSize(final Object value) {
 195  
                 final int size;
 196  8
                 if (value == null) {
 197  1
                         size = 0;
 198  7
                 } else if (value.getClass().isArray()) {
 199  3
                         final Object[] array = (Object[]) value;
 200  3
                         size = array.length;
 201  3
                 } else if (value instanceof Collection) {
 202  3
                         final Collection<?> collection = (Collection<?>) value;
 203  3
                         size = collection.size();
 204  3
                 } else {
 205  1
                         size = 1;
 206  
                 }
 207  8
                 return size;
 208  
         }
 209  
 
 210  
         /**
 211  
          * リクエストの URI からコンテキストパスを除いたパスを返します。
 212  
          * 
 213  
          * @param request
 214  
          *            リクエスト
 215  
          * @return コンテキストパスを除いたパス
 216  
          */
 217  
         public static String getPath(final HttpServletRequest request) {
 218  1
                 final StringBuilder builder = new StringBuilder();
 219  1
                 builder.append(request.getServletPath());
 220  1
                 final String pathInfo = request.getPathInfo();
 221  1
                 if (pathInfo != null) {
 222  0
                         builder.append(pathInfo);
 223  
                 }
 224  1
                 return builder.toString();
 225  
         }
 226  
 
 227  
         /**
 228  
          * 指定されたクラスがアクションメソッドかを示します。
 229  
          * 
 230  
          * @param clazz
 231  
          *            クラス
 232  
          * @return 指定されたクラスがアクションクラスの場合は <code>true</code>、そうでない場合は
 233  
          *         <code>false</code>
 234  
          */
 235  
         public static boolean isActionClass(final Class<?> clazz) {
 236  71
                 return Action.class.isAssignableFrom(clazz);
 237  
         }
 238  
 
 239  
         /**
 240  
          * 指定されたメソッドがアクションメソッドかを示します。
 241  
          * 
 242  
          * @param method
 243  
          *            メソッド
 244  
          * @return 指定されたメソッドがアクションメソッドの場合は <code>true</code>、そうでない場合は
 245  
          *         <code>false</code>
 246  
          */
 247  
         public static boolean isActionMethod(final Method method) {
 248  1110
                 return method.getReturnType().isAssignableFrom(ActionResult.class)
 249  
                                 && method.getParameterTypes().length == 0;
 250  
         }
 251  
 
 252  
         /**
 253  
          * 指定された文字列のなかで、最初に出現した置換対象を置換文字列で置き換えます。
 254  
          * 
 255  
          * @param text
 256  
          *            対象の文字列
 257  
          * @param replace
 258  
          *            置換対象
 259  
          * @param with
 260  
          *            置換文字列
 261  
          * @return 最初に出現した置換対象を置換文字列で置き換えた文字列
 262  
          */
 263  
         public static String replaceFirst(final String text, final String replace,
 264  
                         final String with) {
 265  12
                 if (text == null || replace == null || with == null) {
 266  6
                         return text;
 267  
                 }
 268  6
                 final int index = text.indexOf(replace);
 269  6
                 if (index == -1) {
 270  0
                         return text;
 271  
                 }
 272  6
                 final StringBuilder builder = new StringBuilder(100);
 273  6
                 builder.append(text.substring(0, index));
 274  6
                 builder.append(with);
 275  6
                 builder.append(text.substring(index + replace.length()));
 276  6
                 return builder.toString();
 277  
         }
 278  
 
 279  
         /**
 280  
          * 指定された文字列を区切り文字で区切った文字列の配列に変換します。
 281  
          * 
 282  
          * @param text
 283  
          *            対象の文字列
 284  
          * @param delim
 285  
          *            区切り文字
 286  
          * @return 指定された文字列を区切り文字で区切った文字列の配列
 287  
          */
 288  
         public static String[] split2(final String text, final char delim) {
 289  357
                 if (text == null) {
 290  1
                         return null;
 291  
                 }
 292  356
                 final int index = text.indexOf(delim);
 293  356
                 if (index == -1) {
 294  250
                         return new String[] { text };
 295  
                 }
 296  106
                 final String[] tokens = new String[2];
 297  106
                 tokens[0] = text.substring(0, index);
 298  106
                 tokens[1] = text.substring(index + 1);
 299  106
                 return tokens;
 300  
         }
 301  
 
 302  
         /**
 303  
          * 指定された文字列をHTMLとしてエスケープします。
 304  
          * <p>
 305  
          * <table> <thead>
 306  
          * <tr>
 307  
          * <th>変換前</th>
 308  
          * <th>変換後</th>
 309  
          * </tr>
 310  
          * </thead> <tbody>
 311  
          * <tr>
 312  
          * <td>&amp;</td>
 313  
          * <td>&amp;amp;</td>
 314  
          * </tr>
 315  
          * <tr>
 316  
          * <td>&lt;</td>
 317  
          * <td>&amp;lt;</td>
 318  
          * </tr>
 319  
          * <tr>
 320  
          * <td>&gt;</td>
 321  
          * <td>&amp;gt;</td>
 322  
          * </tr>
 323  
          * <tr>
 324  
          * <td>&quot;</td>
 325  
          * <td>&amp;quot;</td>
 326  
          * </tr>
 327  
          * <tr>
 328  
          * <td>&#39</td>
 329  
          * <td>&amp;#39</td>
 330  
          * </tr>
 331  
          * </tbody> </table>
 332  
          * </p>
 333  
          * 
 334  
          * @param str
 335  
          * @return エスケープされた文字列
 336  
          */
 337  
         public static String escapeHtml(final Object str) {
 338  115
                 if (str == null) {
 339  0
                         return "";
 340  
                 }
 341  
                 String text;
 342  115
                 if (str instanceof String) {
 343  114
                         text = (String) str;
 344  
                 } else {
 345  1
                         text = str.toString();
 346  
                 }
 347  115
                 text = StringUtil.replace(text, "&", "&amp;");
 348  115
                 text = StringUtil.replace(text, "<", "&lt;");
 349  115
                 text = StringUtil.replace(text, ">", "&gt;");
 350  115
                 text = StringUtil.replace(text, "\"", "&quot;");
 351  115
                 text = StringUtil.replace(text, "'", "&#39;");
 352  115
                 return text;
 353  
         }
 354  
 
 355  
         /**
 356  
          * アクションメソッドの{@link Path}アノテーションから優先度を取得します。
 357  
          * 
 358  
          * @param method
 359  
          *            アクションメソッド
 360  
          * @return 優先度。メソッドに{@link Path}アノテーションが設定されていない場合{@link Integer#MAX_VALUE}
 361  
          */
 362  
         public static int getPriority(final Method method) {
 363  357
                 final Path path = method.getAnnotation(Path.class);
 364  357
                 return path != null ? path.priority() : Integer.MAX_VALUE;
 365  
         }
 366  
 
 367  
         /**
 368  
          * 指定されたアクションからアクションメソッドに対応するフォームオブジェクトを取得します。
 369  
          * 
 370  
          * @param action
 371  
          *            アクション
 372  
          * @param actionClass
 373  
          *            アクションクラス
 374  
          * @param method
 375  
          *            アクションメソッド
 376  
          * @return フォームオブジェクト
 377  
          * @throws ActionRuntimeException
 378  
          *             &#064;Formでフォームオブジェクトとなるプロパティを指定しているが、そのプロパティが
 379  
          *             <code>null</code> だった場合
 380  
          * @since 1.0.2
 381  
          */
 382  
         @SuppressWarnings("deprecation")
 383  
         public static Object getFormBean(final Action action,
 384  
                         final Class<?> actionClass, final Method method) {
 385  9
                 final Form form = getForm(actionClass, method);
 386  9
                 if (form == null) {
 387  7
                         return action;
 388  
                 }
 389  2
                 if (!form.binding()) {
 390  0
                         return null;
 391  
                 }
 392  2
                 if (form.bindingType() == NONE) {
 393  0
                         return null;
 394  
                 }
 395  2
                 if (Form.THIS.equals(form.value())) {
 396  0
                         return action;
 397  
                 }
 398  
 
 399  2
                 final String propertyName = form.value();
 400  2
                 final BeanDesc beanDesc = BeanDescFactory
 401  
                                 .getBeanDesc(action.getClass());
 402  2
                 final PropertyDesc propertyDesc = beanDesc
 403  
                                 .getPropertyDesc(propertyName);
 404  2
                 final Object formBean = propertyDesc.getValue(action);
 405  2
                 if (formBean == null) {
 406  1
                         throw new ActionRuntimeException("ECUB0102",
 407  
                                         new Object[] { propertyName });
 408  
                 }
 409  1
                 return formBean;
 410  
         }
 411  
 
 412  
         /**
 413  
          * 指定されたアクションメソッドを修飾する {@link Form} を取得します。
 414  
          * 
 415  
          * @param actionClass
 416  
          *            アクションクラス
 417  
          * @param method
 418  
          *            アクションメソッド
 419  
          * @return {@link Form}、修飾されていない場合はメソッドが定義されたクラスを修飾する {@link Form}、クラスも修飾されていない場合は
 420  
          *         <code>null</code>
 421  
          * @since 1.0.2
 422  
          */
 423  
         public static Form getForm(final Class<?> actionClass, final Method method) {
 424  
                 final Form form;
 425  80
                 if (method.isAnnotationPresent(Form.class)) {
 426  69
                         form = method.getAnnotation(Form.class);
 427  
                 } else {
 428  11
                         form = actionClass.getAnnotation(Form.class);
 429  
                 }
 430  80
                 return form;
 431  
         }
 432  
 
 433  
         /**
 434  
          * 指定されたアクションメソッドを使用することを判断するためのパラメータ名を取得します。
 435  
          * <p>
 436  
          * パラメータ名によらずに実行する場合は <code>null</code> を返します。
 437  
          * </p>
 438  
          * 
 439  
          * @param method
 440  
          *            アクションメソッド
 441  
          * @return パラメータ名
 442  
          */
 443  
         public static String getOnSubmit(final Method method) {
 444  478
                 final OnSubmit onSubmit = method.getAnnotation(OnSubmit.class);
 445  
                 final String parameterName;
 446  478
                 if (onSubmit == null) {
 447  478
                         parameterName = null;
 448  
                 } else {
 449  0
                         parameterName = onSubmit.value();
 450  
                 }
 451  478
                 return parameterName;
 452  
         }
 453  
 
 454  
         /**
 455  
          * リクエストから属性を取得します。
 456  
          * 
 457  
          * @param <T>
 458  
          *            取得する属性の型
 459  
          * @param request
 460  
          *            リクエスト
 461  
          * @param name
 462  
          *            属性名
 463  
          * @return 属性
 464  
          * @since 1.1.0
 465  
          */
 466  
         @SuppressWarnings("unchecked")
 467  
         public static <T> T getAttribute(final HttpServletRequest request,
 468  
                         final String name) {
 469  7
                 return (T) request.getAttribute(name);
 470  
         }
 471  
 
 472  
 }