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