View Javadoc

1   /*
2    * Copyright 2004-2010 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  
17  package org.seasar.cubby.routing.impl;
18  
19  import static org.seasar.cubby.internal.util.LogMessages.format;
20  
21  import org.seasar.cubby.routing.PathTemplateException;
22  import org.seasar.cubby.routing.PathTemplateParser;
23  
24  /**
25   * パステンプレートのパーサーの実装です。
26   * 
27   * @author baba
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  	 */
48  	private enum State {
49  		NORMAL, PARAM_NAME, PARAM_REGEX, PARAM_REGEX_ESCAPE;
50  	}
51  
52  	/**
53  	 * {@inheritDoc}
54  	 */
55  	public String parse(final String template, final Handler handler) {
56  		final StringBuilder pathRegex = new StringBuilder(100);
57  		final StringBuilder paramName = new StringBuilder(10);
58  		final StringBuilder paramRegex = new StringBuilder(10);
59  
60  		State state = State.NORMAL;
61  		int braceDepth = 0;
62  
63  		for (int i = 0; i < template.length(); i++) {
64  			final char c = template.charAt(i);
65  			switch (state) {
66  			case NORMAL: {
67  				if (c == OPEN_PLACE_HOLDER) {
68  					state = State.PARAM_NAME;
69  				} else {
70  					pathRegex.append(c);
71  				}
72  				break;
73  			}
74  			case PARAM_NAME: {
75  				if (c == CLOSE_PLACE_HOLDER) {
76  					if (paramName.length() == 0) {
77  						throw new PathTemplateException(format("ECUB0108",
78  								template, i));
79  					}
80  					final String replacement = handler.handle(paramName
81  							.toString(), DEFAULT_URI_PARAMETER_REGEX);
82  					pathRegex.append(replacement);
83  
84  					paramName.setLength(0);
85  					state = State.NORMAL;
86  				} else if (c == PLACE_HOLDER_SEPARATOR) {
87  					state = State.PARAM_REGEX;
88  				} else {
89  					paramName.append(c);
90  				}
91  				break;
92  			}
93  			case PARAM_REGEX: {
94  				if (c == REGEXP_ESCAPE) {
95  					paramRegex.append(c);
96  					state = State.PARAM_REGEX_ESCAPE;
97  				} else if (c == CLOSE_PLACE_HOLDER && braceDepth == 0) {
98  					if (paramName.length() == 0) {
99  						throw new PathTemplateException(format("ECUB0108",
100 								template, i));
101 					}
102 					if (paramRegex.length() == 0) {
103 						throw new PathTemplateException(format("ECUB0109",
104 								template, i));
105 					}
106 					final String replacement = handler.handle(paramName
107 							.toString(), paramRegex.toString());
108 					pathRegex.append(replacement);
109 
110 					paramName.setLength(0);
111 					paramRegex.setLength(0);
112 					braceDepth = 0;
113 					state = State.NORMAL;
114 				} else {
115 					if (c == OPEN_PLACE_HOLDER) {
116 						braceDepth++;
117 					} else if (c == CLOSE_PLACE_HOLDER) {
118 						braceDepth--;
119 					}
120 					paramRegex.append(c);
121 				}
122 				break;
123 			}
124 			case PARAM_REGEX_ESCAPE: {
125 				paramRegex.append(c);
126 				state = State.PARAM_REGEX;
127 				break;
128 			}
129 			default:
130 				throw new IllegalStateException();
131 			}
132 		}
133 		if (state != State.NORMAL) {
134 			throw new PathTemplateException(format("ECUB0107", template));
135 		}
136 		return pathRegex.toString();
137 	}
138 
139 }