View Javadoc

    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 org.seasar.cubby.routing.PathTemplateException;
    21  import org.seasar.cubby.routing.PathTemplateParser;
    22
    23  /**
    24   * パステンプレートのパーサーの実装です。
    25   *
    26   * @author baba
    27   */
    28  public class PathTemplateParserImpl implements PathTemplateParser {
    29
    30  	/** プレースホルダの開始文字。 */
    31  	private static final char OPEN_PLACE_HOLDER = '{';
    32
    33  	/** プレースホルダの終了文字。 */
    34  	private static final char CLOSE_PLACE_HOLDER = '}';
    35
    36  	/** プレースホルダ中のパラメータ名と正規表現の区切り文字。 */
    37  	private static final char PLACE_HOLDER_SEPARATOR = ',';
    38
    39  	/** 正規表現のエスケープ文字。 */
    40  	private static final char REGEXP_ESCAPE = '\\';
    41
    42  	/**
    43  	 * パース中の状態。
    44  	 *
    45  	 * @author baba
    46  	 */
    47  	private enum State {
    48  		NORMAL, PARAM_NAME, PARAM_REGEX, PARAM_REGEX_ESCAPE;
    49  	}
    50
    51  	/**
    52  	 * {@inheritDoc}
    53  	 */
    54  	public String parse(final String template, final Handler handler) {
    55  		final StringBuilder pathRegex = new StringBuilder(100);
    56  		final StringBuilder paramName = new StringBuilder(10);
    57  		final StringBuilder paramRegex = new StringBuilder(10);
    58
    59  		State state = State.NORMAL;
    60  		int braceDepth = 0;
    61
    62  		for (int i = 0; i < template.length(); i++) {
    63  			final char c = template.charAt(i);
    64  			switch (state) {
    65  			case NORMAL: {
    66  				if (c == OPEN_PLACE_HOLDER) {
    67  					state = State.PARAM_NAME;
    68  				} else {
    69  					pathRegex.append(c);
    70  				}
    71  				break;
    72  			}
    73  			case PARAM_NAME: {
    74  				if (c == CLOSE_PLACE_HOLDER) {
    75  					if (paramName.length() == 0) {
    76  						throw new PathTemplateException(format("ECUB0108",
    77  								template, i));
    78  					}
    79  					final String replacement = handler.handle(paramName
    80  							.toString(), DEFAULT_URI_PARAMETER_REGEX);
    81  					pathRegex.append(replacement);
    82
    83  					paramName.setLength(0);
    84  					state = State.NORMAL;
    85  				} else if (c == PLACE_HOLDER_SEPARATOR) {
    86  					state = State.PARAM_REGEX;
    87  				} else {
    88  					paramName.append(c);
    89  				}
    90  				break;
    91  			}
    92  			case PARAM_REGEX: {
    93  				if (c == REGEXP_ESCAPE) {
    94  					paramRegex.append(c);
    95  					state = State.PARAM_REGEX_ESCAPE;
    96  				} else if (c == CLOSE_PLACE_HOLDER && braceDepth == 0) {
    97  					if (paramName.length() == 0) {
    98  						throw new PathTemplateException(format("ECUB0108",
    99  								template, i));
    100 					}
    101 					if (paramRegex.length() == 0) {
    102 						throw new PathTemplateException(format("ECUB0109",
    103 								template, i));
    104 					}
    105 					final String replacement = handler.handle(paramName
    106 							.toString(), paramRegex.toString());
    107 					pathRegex.append(replacement);
    108
    109 					paramName.setLength(0);
    110 					paramRegex.setLength(0);
    111 					braceDepth = 0;
    112 					state = State.NORMAL;
    113 				} else {
    114 					if (c == OPEN_PLACE_HOLDER) {
    115 						braceDepth++;
    116 					} else if (c == CLOSE_PLACE_HOLDER) {
    117 						braceDepth--;
    118 					}
    119 					paramRegex.append(c);
    120 				}
    121 				break;
    122 			}
    123 			case PARAM_REGEX_ESCAPE: {
    124 				paramRegex.append(c);
    125 				state = State.PARAM_REGEX;
    126 				break;
    127 			}
    128 			default:
    129 				throw new IllegalStateException();
    130 			}
    131 		}
    132 		if (state != State.NORMAL) {
    133 			throw new PathTemplateException(format("ECUB0107", template));
    134 		}
    135 		return pathRegex.toString();
    136 	}
    137
    138 }