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.internal.routing.impl;
17  
18  import static org.seasar.cubby.CubbyConstants.ATTR_ROUTING;
19  import static org.seasar.cubby.internal.util.LogMessages.format;
20  
21  import java.util.Collections;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.regex.Matcher;
26  import java.util.regex.Pattern;
27  
28  import javax.servlet.http.HttpServletRequest;
29  import javax.servlet.http.HttpServletResponse;
30  
31  import org.seasar.cubby.internal.routing.Router;
32  import org.seasar.cubby.internal.util.RequestUtils;
33  import org.seasar.cubby.plugin.Plugin;
34  import org.seasar.cubby.plugin.PluginRegistry;
35  import org.seasar.cubby.plugin.RoutingInvocation;
36  import org.seasar.cubby.routing.PathInfo;
37  import org.seasar.cubby.routing.PathResolver;
38  import org.seasar.cubby.routing.Routing;
39  import org.seasar.cubby.spi.PathResolverProvider;
40  import org.seasar.cubby.spi.ProviderFactory;
41  import org.slf4j.Logger;
42  import org.slf4j.LoggerFactory;
43  
44  /**
45   * ルーターの実装です。
46   * 
47   * @author baba
48   */
49  public class RouterImpl implements Router {
50  
51  	/** ロガー */
52  	private static final Logger logger = LoggerFactory
53  			.getLogger(RouterImpl.class);
54  
55  	/** 空の対象外パターンのリスト */
56  	private static final List<Pattern> EMPTY_IGNORE_PATH_PATTERNS = Collections
57  			.emptyList();
58  
59  	/**
60  	 * {@inheritDoc}
61  	 */
62  	public PathInfo routing(final HttpServletRequest request,
63  			final HttpServletResponse response) {
64  		return routing(request, response, EMPTY_IGNORE_PATH_PATTERNS);
65  	}
66  
67  	/**
68  	 * {@inheritDoc}
69  	 */
70  	public PathInfo routing(final HttpServletRequest request,
71  			final HttpServletResponse response,
72  			final List<Pattern> ignorePathPatterns) {
73  		final String path = RequestUtils.getPath(request);
74  		if (logger.isDebugEnabled()) {
75  			logger.debug(format("DCUB0006", path));
76  		}
77  
78  		final Routing routing = RequestUtils
79  				.getAttribute(request, ATTR_ROUTING);
80  		if (routing != null) {
81  			request.removeAttribute(ATTR_ROUTING);
82  			final PathInfo pathInfo = new ForwardFromActionPathInfo(routing);
83  			return pathInfo;
84  		}
85  
86  		if (isIgnorePath(path, ignorePathPatterns)) {
87  			return null;
88  		}
89  
90  		final PathResolverProvider pathResolverProvider = ProviderFactory
91  				.get(PathResolverProvider.class);
92  		final PathResolver pathResolver = pathResolverProvider
93  				.getPathResolver();
94  		final RoutingInvocation routingInvocation = new RoutingInvocationImpl(
95  				path, pathResolver, request, response);
96  		try {
97  			return routingInvocation.proceed();
98  		} catch (final Exception e) {
99  			logger.warn("routing failed.", e);
100 			return null;
101 		}
102 	}
103 
104 	/**
105 	 * 要求処理の実行情報の実装です。
106 	 * 
107 	 * @author baba
108 	 */
109 	static class RoutingInvocationImpl implements RoutingInvocation {
110 
111 		/** パス。 */
112 		private final String path;
113 
114 		/** パスのリゾルバ。 */
115 		private final PathResolver pathResolver;
116 
117 		/** 要求。 */
118 		private final HttpServletRequest request;
119 
120 		/** 応答。 */
121 		private final HttpServletResponse response;
122 
123 		/** プラグインのイテレータ。 */
124 		private final Iterator<Plugin> pluginsIterator;
125 
126 		/**
127 		 * インスタンス化します。
128 		 * 
129 		 * @param path
130 		 *            パス
131 		 * @param pathResolver
132 		 *            パスのリゾルバ
133 		 * @param request
134 		 *            要求
135 		 * @param response
136 		 *            応答
137 		 */
138 		public RoutingInvocationImpl(final String path,
139 				final PathResolver pathResolver,
140 				final HttpServletRequest request,
141 				final HttpServletResponse response) {
142 			this.path = path;
143 			this.pathResolver = pathResolver;
144 			this.request = request;
145 			this.response = response;
146 
147 			final PluginRegistry pluginRegistry = PluginRegistry.getInstance();
148 			this.pluginsIterator = pluginRegistry.getPlugins().iterator();
149 		}
150 
151 		/**
152 		 * {@inheritDoc}
153 		 */
154 		public PathInfo proceed() throws Exception {
155 			if (pluginsIterator.hasNext()) {
156 				final Plugin plugin = pluginsIterator.next();
157 				return plugin.invokeRouting(this);
158 			} else {
159 				final PathInfo pathInfo = pathResolver.getPathInfo(path,
160 						request.getMethod(), request.getCharacterEncoding());
161 				return pathInfo;
162 			}
163 		}
164 
165 		/**
166 		 * {@inheritDoc}
167 		 */
168 		public String getPath() {
169 			return path;
170 		}
171 
172 		/**
173 		 * {@inheritDoc}
174 		 */
175 		public PathResolver getPathResolver() {
176 			return pathResolver;
177 		}
178 
179 		/**
180 		 * {@inheritDoc}
181 		 */
182 		public HttpServletRequest getRequest() {
183 			return request;
184 		}
185 
186 		/**
187 		 * {@inheritDoc}
188 		 */
189 		public HttpServletResponse getResponse() {
190 			return response;
191 		}
192 
193 	}
194 
195 	/**
196 	 * 指定された path が ignorePathPatterns にマッチするかを示します。
197 	 * 
198 	 * @param path
199 	 *            パス
200 	 * @param ignorePathPatterns
201 	 *            対象外パターンのリスト
202 	 * @return path が ignorePathPatterns にマッチする場合は <code>true</code>、そうでない場合は
203 	 *         <code>false</code>
204 	 */
205 	private boolean isIgnorePath(final String path,
206 			final List<Pattern> ignorePathPatterns) {
207 		for (final Pattern pattern : ignorePathPatterns) {
208 			final Matcher matcher = pattern.matcher(path);
209 			if (matcher.matches()) {
210 				return true;
211 			}
212 		}
213 		return false;
214 	}
215 
216 	static class ForwardFromActionPathInfo implements PathInfo {
217 
218 		private final Routing routing;
219 
220 		private final Map<String, String[]> uriParameters = Collections
221 				.emptyMap();
222 
223 		public ForwardFromActionPathInfo(final Routing routing) {
224 			this.routing = routing;
225 		}
226 
227 		public Map<String, String[]> getURIParameters() {
228 			return uriParameters;
229 		}
230 
231 		public Routing dispatch(final Map<String, Object[]> parameterMap) {
232 			return routing;
233 		}
234 
235 	}
236 
237 }