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