Coverage Report - org.seasar.cubby.util.CubbyUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
CubbyUtils
93%
86/92
81%
42/52
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.CubbyConstants.INTERNAL_FORWARD_DIRECTORY;
 19  
 
 20  
 import java.lang.reflect.Method;
 21  
 import java.util.Collection;
 22  
 
 23  
 import javax.servlet.http.HttpServletRequest;
 24  
 
 25  
 import org.seasar.cubby.action.Accept;
 26  
 import org.seasar.cubby.action.Action;
 27  
 import org.seasar.cubby.action.ActionResult;
 28  
 import org.seasar.cubby.action.Path;
 29  
 import org.seasar.cubby.action.RequestMethod;
 30  
 import org.seasar.framework.util.StringUtil;
 31  
 
 32  
 /**
 33  
  * Cubby内部で使用するユーティリティクラスです。
 34  
  * 
 35  
  * @author baba
 36  
  * @since 1.0.0
 37  
  */
 38  0
 public class CubbyUtils {
 39  
 
 40  
         /** インデックスのメソッド名。 */
 41  
         private static final String INDEX_METHOD_NAME = "index";
 42  
 
 43  
         /** デフォルトの{@link Accept}アノテーション。 */
 44  
         private static Accept DEFAULT_ACCEPT_ANNOTATION;
 45  
         static {
 46  
                 @Accept
 47  0
                 class AcceptDummy {
 48  
                 }
 49  1
                 DEFAULT_ACCEPT_ANNOTATION = AcceptDummy.class
 50  
                                 .getAnnotation(Accept.class);
 51  1
         }
 52  
 
 53  
         /**
 54  
          * 指定されたアクションクラスに対応するディレクトリを取得します。
 55  
          * 
 56  
          * @param actionClass
 57  
          *            アクションクラス
 58  
          * @return アクションクラスに対応するディレクトリ
 59  
          */
 60  
         public static String getActionDirectory(final Class<?> actionClass) {
 61  
                 final String actionName;
 62  173
                 final Path path = actionClass.getAnnotation(Path.class);
 63  173
                 if (path != null && !StringUtil.isEmpty(path.value())) {
 64  105
                         actionName = path.value();
 65  
                 } else {
 66  68
                         final String name = left(actionClass.getSimpleName(), "$");
 67  68
                         actionName = toFirstLower(name.replaceAll(
 68  
                                         "(.*[.])*([^.]+)(Action$)", "$2"));
 69  
                 }
 70  173
                 return actionName;
 71  
         }
 72  
 
 73  
         /**
 74  
          * 指定された文字列をセパレータで区切った左側の文字列を返します。
 75  
          * 
 76  
          * @param text
 77  
          *            文字列
 78  
          * @param sep
 79  
          *            セパレータ
 80  
          * @return セパレータで区切った左側の文字列
 81  
          */
 82  
         private static String left(final String text, final String sep) {
 83  68
                 final int pos = text.indexOf(sep);
 84  68
                 if (pos != -1) {
 85  0
                         return text.substring(0, pos);
 86  
                 }
 87  68
                 return text;
 88  
         }
 89  
 
 90  
         /**
 91  
          * 指定された文字列の先頭1文字を小文字に変換します。
 92  
          * 
 93  
          * @param text
 94  
          *            変換する文字列
 95  
          * @return 先頭1文字を小文字にした文字列
 96  
          */
 97  
         private static String toFirstLower(final String text) {
 98  68
                 if (StringUtil.isEmpty(text)) {
 99  0
                         throw new IllegalArgumentException("text is empty.");
 100  
                 }
 101  68
                 final StringBuilder sb = new StringBuilder();
 102  68
                 sb.append(text.substring(0, 1).toLowerCase());
 103  68
                 if (text.length() > 1) {
 104  68
                         sb.append(text.substring(1));
 105  
                 }
 106  68
                 return sb.toString();
 107  
         }
 108  
 
 109  
         /**
 110  
          * 指定されたアクションメソッドのパスを取得します。
 111  
          * 
 112  
          * @param actionClass
 113  
          *            アクションクラス
 114  
          * @param method
 115  
          *            アクションメソッド
 116  
          * @return アクションメソッドのパス
 117  
          */
 118  
         public static String getActionPath(final Class<?> actionClass,
 119  
                         final Method method) {
 120  
                 final String path;
 121  167
                 final String actionMethodName = getActionMethodName(method);
 122  167
                 if (actionMethodName.startsWith("/")) {
 123  2
                         return path = actionMethodName;
 124  
                 } else {
 125  165
                         final String actionDirectory = CubbyUtils
 126  
                                         .getActionDirectory(actionClass);
 127  165
                         if ("/".equals(actionDirectory)) {
 128  40
                                 path = "/" + actionMethodName;
 129  
                         } else {
 130  125
                                 path = "/" + actionDirectory + "/" + actionMethodName;
 131  
                         }
 132  
                 }
 133  165
                 return path;
 134  
         }
 135  
 
 136  
         /**
 137  
          * 指定されたアクションメソッドのアクションメソッド名を取得します。
 138  
          * 
 139  
          * @param method
 140  
          *            アクションメソッド
 141  
          * @return アクションメソッド名
 142  
          */
 143  
         private static String getActionMethodName(final Method method) {
 144  
                 final String actionName;
 145  167
                 final Path path = method.getAnnotation(Path.class);
 146  167
                 if (path != null && !StringUtil.isEmpty(path.value())) {
 147  112
                         actionName = path.value();
 148  
                 } else {
 149  55
                         final String methodName = method.getName();
 150  55
                         if (INDEX_METHOD_NAME.equals(methodName)) {
 151  14
                                 actionName = "";
 152  
                         } else {
 153  41
                                 actionName = methodName;
 154  
                         }
 155  
                 }
 156  167
                 return actionName;
 157  
         }
 158  
 
 159  
         /**
 160  
          * 指定されたアクションメソッドが受付可能なリクエストメソッドを取得します。
 161  
          * 
 162  
          * @param actionClass
 163  
          *            アクションクラス
 164  
          * @param method
 165  
          *            アクションメソッド
 166  
          * @return 受付可能なリクエストメソッド
 167  
          */
 168  
         public static RequestMethod[] getAcceptableRequestMethods(
 169  
                         final Class<?> actionClass, final Method method) {
 170  156
                 Accept accept = method.getAnnotation(Accept.class);
 171  156
                 if (accept == null) {
 172  120
                         accept = actionClass.getAnnotation(Accept.class);
 173  120
                         if (accept == null) {
 174  120
                                 accept = DEFAULT_ACCEPT_ANNOTATION;
 175  
                         }
 176  
                 }
 177  156
                 return accept.value();
 178  
         }
 179  
 
 180  
         /**
 181  
          * 指定されたオブジェクトのサイズを取得します。
 182  
          * 
 183  
          * @param value
 184  
          *            オブジェクト
 185  
          * @return オブジェクトのサイズ
 186  
          */
 187  
         public static int getObjectSize(final Object value) {
 188  
                 final int size;
 189  8
                 if (value == null) {
 190  1
                         size = 0;
 191  7
                 } else if (value.getClass().isArray()) {
 192  3
                         final Object[] array = (Object[]) value;
 193  3
                         size = array.length;
 194  3
                 } else if (value instanceof Collection) {
 195  3
                         final Collection<?> collection = (Collection<?>) value;
 196  3
                         size = collection.size();
 197  3
                 } else {
 198  1
                         size = 1;
 199  
                 }
 200  8
                 return size;
 201  
         }
 202  
 
 203  
         /**
 204  
          * リクエストのURIからコンテキストパスを除いたパスを返します。
 205  
          * 
 206  
          * @param request
 207  
          *            リクエスト
 208  
          * @return コンテキストパスを除いたパス
 209  
          */
 210  
         public static String getPath(final HttpServletRequest request) {
 211  5
                 final String uri = request.getRequestURI();
 212  5
                 final String contextPath = request.getContextPath();
 213  
                 final String path;
 214  5
                 if ("/".equals(contextPath)) {
 215  5
                         path = uri;
 216  
                 } else {
 217  0
                         path = uri.substring(contextPath.length());
 218  
                 }
 219  5
                 return path;
 220  
         }
 221  
 
 222  
         /**
 223  
          * アクションクラスとメソッド名から内部フォワードのパスへ変換します。
 224  
          * 
 225  
          * @param actionClass
 226  
          *            アクションクラス
 227  
          * @param methodName
 228  
          *            メソッド名
 229  
          * @return 内部フォワードパス
 230  
          */
 231  
         public static String getInternalForwardPath(
 232  
                         final Class<? extends Action> actionClass, final String methodName) {
 233  24
                 return "/" + INTERNAL_FORWARD_DIRECTORY + "/"
 234  
                                 + actionClass.getCanonicalName() + "/" + methodName;
 235  
         }
 236  
 
 237  
         /**
 238  
          * 指定されたクラスがアクションメソッドかを示します。
 239  
          * 
 240  
          * @param clazz
 241  
          *            クラス
 242  
          * @return 指定されたクラスがアクションクラスの場合は <code>true</code>、そうでない場合は
 243  
          *         <code>false</code>
 244  
          */
 245  
         public static boolean isActionClass(final Class<?> clazz) {
 246  36
                 return Action.class.isAssignableFrom(clazz);
 247  
         }
 248  
 
 249  
         /**
 250  
          * 指定されたメソッドがアクションメソッドかを示します。
 251  
          * 
 252  
          * @param method
 253  
          *            メソッド
 254  
          * @return 指定されたメソッドがアクションメソッドの場合は <code>true</code>、そうでない場合は
 255  
          *         <code>false</code>
 256  
          */
 257  
         public static boolean isActionMethod(final Method method) {
 258  732
                 return method.getReturnType().isAssignableFrom(ActionResult.class)
 259  
                                 && method.getParameterTypes().length == 0;
 260  
         }
 261  
 
 262  
         /**
 263  
          * 指定された文字列のなかで、最初に出現した置換対象を置換文字列で置き換えます。
 264  
          * 
 265  
          * @param text
 266  
          *            対象の文字列
 267  
          * @param replace
 268  
          *            置換対象
 269  
          * @param with
 270  
          *            置換文字列
 271  
          * @return 最初に出現した置換対象を置換文字列で置き換えた文字列
 272  
          */
 273  
         public static String replaceFirst(final String text, final String replace,
 274  
                         final String with) {
 275  12
                 if (text == null || replace == null || with == null) {
 276  6
                         return text;
 277  
                 }
 278  6
                 final int index = text.indexOf(replace);
 279  6
                 if (index == -1) {
 280  0
                         return text;
 281  
                 }
 282  6
                 final StringBuilder builder = new StringBuilder(100);
 283  6
                 builder.append(text.substring(0, index));
 284  6
                 builder.append(with);
 285  6
                 builder.append(text.substring(index + replace.length()));
 286  6
                 return builder.toString();
 287  
         }
 288  
 
 289  
         /**
 290  
          * 指定された文字列を区切り文字で区切った文字列の配列に変換します。
 291  
          * 
 292  
          * @param text
 293  
          *            対象の文字列
 294  
          * @param delim
 295  
          *            区切り文字
 296  
          * @return 指定された文字列を区切り文字で区切った文字列の配列
 297  
          */
 298  
         public static String[] split2(final String text, final char delim) {
 299  113
                 if (text == null) {
 300  1
                         return null;
 301  
                 }
 302  112
                 int index = text.indexOf(delim);
 303  112
                 if (index == -1) {
 304  86
                         return new String[] { text };
 305  
                 }
 306  26
                 String[] tokens = new String[2];
 307  26
                 tokens[0] = text.substring(0, index);
 308  26
                 tokens[1] = text.substring(index + 1);
 309  26
                 return tokens;
 310  
         }
 311  
 
 312  
         /**
 313  
          * 指定された文字列をHTMLとしてエスケープします。
 314  
          * <p>
 315  
          * <table> <thead>
 316  
          * <tr>
 317  
          * <th>変換前</th>
 318  
          * <th>変換後</th>
 319  
          * </tr>
 320  
          * </thead> <tbody>
 321  
          * <tr>
 322  
          * <td>&amp;</td>
 323  
          * <td>&amp;amp;</td>
 324  
          * </tr>
 325  
          * <tr>
 326  
          * <td>&lt;</td>
 327  
          * <td>&amp;lt;</td>
 328  
          * </tr>
 329  
          * <tr>
 330  
          * <td>&gt;</td>
 331  
          * <td>&amp;gt;</td>
 332  
          * </tr>
 333  
          * <tr>
 334  
          * <td>&quot;</td>
 335  
          * <td>&amp;quot;</td>
 336  
          * </tr>
 337  
          * <tr>
 338  
          * <td>&#39</td>
 339  
          * <td>&amp;#39</td>
 340  
          * </tr>
 341  
          * </tbody> </table>
 342  
          * </p>
 343  
          * 
 344  
          * @param str
 345  
          * @return エスケープされた文字列
 346  
          */
 347  
         public static String escapeHtml(final Object str) {
 348  108
                 if (str == null) {
 349  0
                         return "";
 350  
                 }
 351  
                 String text;
 352  108
                 if (str instanceof String) {
 353  107
                         text = (String) str;
 354  
                 } else {
 355  1
                         text = str.toString();
 356  
                 }
 357  108
                 text = StringUtil.replace(text, "&", "&amp;");
 358  108
                 text = StringUtil.replace(text, "<", "&lt;");
 359  108
                 text = StringUtil.replace(text, ">", "&gt;");
 360  108
                 text = StringUtil.replace(text, "\"", "&quot;");
 361  108
                 text = StringUtil.replace(text, "'", "&#39;");
 362  108
                 return text;
 363  
         }
 364  
 
 365  
 }