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 }