View Javadoc

1   /*
2    * Copyright 2004-2008 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.controller.impl;
17  
18  import static org.seasar.cubby.CubbyConstants.ATTR_ACTION;
19  import static org.seasar.cubby.CubbyConstants.ATTR_PARAMS;
20  import static org.seasar.cubby.CubbyConstants.ATTR_ROUTINGS;
21  
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import java.util.Map;
25  
26  import javax.servlet.http.HttpServletRequest;
27  import javax.servlet.http.HttpServletResponse;
28  
29  import org.seasar.cubby.action.Action;
30  import org.seasar.cubby.action.ActionResult;
31  import org.seasar.cubby.controller.ActionProcessor;
32  import org.seasar.cubby.controller.ActionResultWrapper;
33  import org.seasar.cubby.controller.RequestParser;
34  import org.seasar.cubby.controller.RequestParserSelector;
35  import org.seasar.cubby.controller.RoutingsDispatcher;
36  import org.seasar.cubby.exception.ActionRuntimeException;
37  import org.seasar.cubby.routing.Routing;
38  import org.seasar.cubby.util.CubbyUtils;
39  import org.seasar.framework.container.S2Container;
40  import org.seasar.framework.container.factory.SingletonS2ContainerFactory;
41  import org.seasar.framework.log.Logger;
42  
43  /**
44   * リクエストのパスを元にアクションメソッドを決定して実行するクラスの実装です。
45   * 
46   * @author baba
47   * @since 1.0.0
48   */
49  public class ActionProcessorImpl implements ActionProcessor {
50  
51  	/** ロガー。 */
52  	private static final Logger logger = Logger
53  			.getLogger(ActionProcessorImpl.class);
54  
55  	/** 空の引数。 */
56  	private static final Object[] EMPTY_ARGS = new Object[0];
57  
58  	/** リクエストパラメータに応じたルーティングを割り当てるためのクラス。 */
59  	private RoutingsDispatcher routingsDispatcher;
60  
61  	/** リクエスト解析器。 */
62  	private RequestParserSelector requestParserSelector;
63  
64  	/**
65  	 * リクエストパラメータに応じたルーティングを割り当てるためのクラスを設定します。
66  	 * 
67  	 * @param routingsDispatcher
68  	 *            リクエストパラメータに応じたルーティングを割り当てるためのクラス
69  	 */
70  	public void setRoutingsDispatcher(
71  			final RoutingsDispatcher routingsDispatcher) {
72  		this.routingsDispatcher = routingsDispatcher;
73  	}
74  
75  	/**
76  	 * リクエスト解析器セレクタを設定します。
77  	 * 
78  	 * @param requestParserSelector
79  	 *            リクエスト解析器
80  	 */
81  	public void setRequestParserSelector(
82  			final RequestParserSelector requestParserSelector) {
83  		this.requestParserSelector = requestParserSelector;
84  	}
85  
86  	/**
87  	 * {@inheritDoc}
88  	 */
89  	public ActionResultWrapper process(final HttpServletRequest request,
90  			final HttpServletResponse response) throws Exception {
91  		final Map<String, Routing> routings = CubbyUtils.getAttribute(request,
92  				ATTR_ROUTINGS);
93  		if (routings == null) {
94  			return null;
95  		}
96  
97  		request.removeAttribute(ATTR_ROUTINGS);
98  		final Map<String, Object[]> parameterMap = parseRequest(request);
99  		request.setAttribute(ATTR_PARAMS, parameterMap);
100 
101 		final Routing routing = routingsDispatcher.dispatch(routings,
102 				parameterMap);
103 		if (routing == null) {
104 			return null;
105 		}
106 
107 		final Class<? extends Action> actionClass = routing.getActionClass();
108 		final Method method = routing.getMethod();
109 		if (logger.isDebugEnabled()) {
110 			logger.log("DCUB0004", new Object[] { request.getRequestURI() });
111 			logger.log("DCUB0005", new Object[] { method });
112 		}
113 		final S2Container container = SingletonS2ContainerFactory
114 				.getContainer();
115 		final Action action = (Action) container.getComponent(actionClass);
116 		request.setAttribute(ATTR_ACTION, action);
117 		final ActionResult actionResult = invoke(action, method);
118 		if (actionResult == null) {
119 			throw new ActionRuntimeException("ECUB0101",
120 					new Object[] { method });
121 		}
122 		final ActionResultWrapper actionResultWrapper = new ActionResultWrapperImpl(
123 				actionResult, action, actionClass, method);
124 		return actionResultWrapper;
125 	}
126 
127 	/**
128 	 * 指定されたアクションのメソッドを実行します。
129 	 * 
130 	 * @param action
131 	 *            アクション
132 	 * @param method
133 	 *            アクションメソッド
134 	 * @return アクションメソッドの実行結果
135 	 */
136 	private ActionResult invoke(final Action action, final Method method)
137 			throws Exception {
138 		try {
139 			final ActionResult result = (ActionResult) method.invoke(action,
140 					EMPTY_ARGS);
141 			return result;
142 		} catch (final InvocationTargetException ex) {
143 			logger.log(ex);
144 			final Throwable target = ex.getTargetException();
145 			if (target instanceof Error) {
146 				throw (Error) target;
147 			} else if (target instanceof RuntimeException) {
148 				throw (RuntimeException) target;
149 			} else {
150 				throw (Exception) target;
151 			}
152 		}
153 	}
154 
155 	/**
156 	 * リクエストをパースしてパラメータを取り出し、{@link Map}に変換して返します。
157 	 * 
158 	 * @param request
159 	 *            リクエスト
160 	 * @return リクエストパラメータの{@link Map}
161 	 */
162 	private Map<String, Object[]> parseRequest(final HttpServletRequest request) {
163 		final RequestParser requestParser = requestParserSelector
164 				.select(request);
165 		if (requestParser == null) {
166 			throw new NullPointerException("requestParser");
167 		}
168 		if (logger.isDebugEnabled()) {
169 			logger.log("DCUB0016", new Object[] { requestParser });
170 		}
171 		final Map<String, Object[]> parameterMap = requestParser
172 				.getParameterMap(request);
173 		return parameterMap;
174 	}
175 
176 }