001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.util.bridges.alloy;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.portlet.LiferayPortletConfig;
020    import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
021    import com.liferay.portal.kernel.servlet.SessionMessages;
022    import com.liferay.portal.kernel.util.GetterUtil;
023    import com.liferay.portal.kernel.util.JavaConstants;
024    import com.liferay.portal.kernel.util.ParamUtil;
025    import com.liferay.portal.kernel.util.StringBundler;
026    import com.liferay.portal.kernel.util.StringPool;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.model.Portlet;
029    import com.liferay.portal.util.PortalUtil;
030    
031    import java.lang.reflect.Method;
032    
033    import java.util.HashMap;
034    import java.util.Map;
035    
036    import javax.portlet.ActionRequest;
037    import javax.portlet.ActionResponse;
038    import javax.portlet.EventRequest;
039    import javax.portlet.EventResponse;
040    import javax.portlet.PortletContext;
041    import javax.portlet.PortletRequest;
042    import javax.portlet.PortletRequestDispatcher;
043    import javax.portlet.PortletResponse;
044    import javax.portlet.PortletURL;
045    import javax.portlet.RenderRequest;
046    import javax.portlet.RenderResponse;
047    import javax.portlet.ResourceRequest;
048    import javax.portlet.ResourceResponse;
049    
050    import javax.servlet.ServletConfig;
051    import javax.servlet.ServletContext;
052    import javax.servlet.http.HttpServletRequest;
053    import javax.servlet.http.HttpServletResponse;
054    import javax.servlet.jsp.PageContext;
055    
056    /**
057     * @author Brian Wing Shun Chan
058     */
059    public abstract class BaseAlloyControllerImpl implements AlloyController {
060    
061            public void afterPropertiesSet() {
062                    initClass();
063                    initServletVariables();
064                    initPortletVariables();
065                    initMethods();
066                    initPaths();
067            }
068    
069            public void execute() throws Exception {
070                    Method method = getMethod(actionPath);
071    
072                    if (method == null) {
073                            if (log.isDebugEnabled()) {
074                                    log.debug("No method found for action " + actionPath);
075                            }
076                    }
077    
078                    if (lifecycle.equals(PortletRequest.ACTION_PHASE)) {
079                            executeAction(method);
080                    }
081                    else if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
082                            executeRender(method);
083                    }
084            }
085    
086            public void setPageContext(PageContext pageContext) {
087                    this.pageContext = pageContext;
088            }
089    
090            protected void addSuccessMessage() {
091                    String successMessage = ParamUtil.getString(
092                            portletRequest, "successMessage");
093    
094                    SessionMessages.add(
095                            portletRequest, "request_processed", successMessage);
096            }
097    
098            protected String buildIncludePath(String viewPath) {
099                    StringBundler sb = new StringBundler(5);
100    
101                    sb.append("/WEB-INF/jsp/views/");
102                    sb.append(controllerPath);
103                    sb.append(StringPool.SLASH);
104                    sb.append(viewPath);
105                    sb.append(".jsp");
106    
107                    return sb.toString();
108            }
109    
110            protected void executeAction(Method method) throws Exception {
111                    if (method != null) {
112                            method.invoke(this);
113                    }
114    
115                    actionRequest.setAttribute(
116                            CALLED_PROCESS_ACTION, Boolean.TRUE.toString());
117    
118                    if (Validator.isNotNull(viewPath)) {
119                            actionRequest.setAttribute(VIEW_PATH, viewPath);
120    
121                            PortalUtil.copyRequestParameters(actionRequest, actionResponse);
122                    }
123                    else if (Validator.isNotNull(redirect)) {
124                            actionResponse.sendRedirect(redirect);
125                    }
126            }
127    
128            protected void executeRender(Method method) throws Exception {
129                    boolean calledProcessAction = GetterUtil.getBoolean(
130                            (String)request.getAttribute(CALLED_PROCESS_ACTION));
131    
132                    if (!calledProcessAction) {
133                            if (method != null) {
134                                    method.invoke(this);
135                            }
136                    }
137    
138                    if (Validator.isNull(viewPath)) {
139                            viewPath = actionPath;
140                    }
141    
142                    String includePath = buildIncludePath(viewPath);
143    
144                    PortletRequestDispatcher portletRequestDispatcher =
145                            portletContext.getRequestDispatcher(includePath);
146    
147                    if (portletRequestDispatcher == null) {
148                            log.error(includePath + " is not a valid include");
149                    }
150                    else {
151                            portletRequestDispatcher.include(
152                                    portletRequest, portletResponse);
153                    }
154            }
155    
156            protected Method getMethod(String methodName, Class<?>... parameterTypes) {
157                    String methodKey = getMethodKey(methodName, parameterTypes);
158    
159                    return methodsMap.get(methodKey);
160            }
161    
162            protected String getMethodKey(
163                    String methodName, Class<?>... parameterTypes) {
164    
165                    StringBundler sb = new StringBundler(parameterTypes.length * 2 + 2);
166    
167                    sb.append(methodName);
168                    sb.append(StringPool.POUND);
169    
170                    for (Class<?> parameterType : parameterTypes) {
171                            sb.append(parameterType.getName());
172                            sb.append(StringPool.POUND);
173                    }
174    
175                    return sb.toString();
176            }
177    
178            protected void initClass() {
179                    classObject = getClass();
180                    classLoader = classObject.getClassLoader();
181            }
182    
183            protected void initMethods() {
184                    methodsMap = new HashMap<String, Method>();
185    
186                    Method[] methods = classObject.getMethods();
187    
188                    for (Method method : methods) {
189                            String methodKey = getMethodKey(
190                                    method.getName(), method.getParameterTypes());
191    
192                            methodsMap.put(methodKey, method);
193                    }
194            }
195    
196            protected void initPaths() {
197                    controllerPath = ParamUtil.getString(request, "controller");
198    
199                    if (Validator.isNull(controllerPath)) {
200                            Map<String, String> defaultRouteParameters =
201                                    alloyPortlet.getDefaultRouteParameters();
202    
203                            controllerPath = defaultRouteParameters.get("controller");
204                    }
205    
206                    if (log.isDebugEnabled()) {
207                            log.debug("Controller path " + controllerPath);
208                    }
209    
210                    actionPath = ParamUtil.getString(request, "action");
211    
212                    if (Validator.isNull(actionPath)) {
213                            Map<String, String> defaultRouteParameters =
214                                    alloyPortlet.getDefaultRouteParameters();
215    
216                            actionPath = defaultRouteParameters.get("action");
217                    }
218    
219                    if (log.isDebugEnabled()) {
220                            log.debug("Action path " + actionPath);
221                    }
222    
223                    viewPath = GetterUtil.getString(
224                            (String)request.getAttribute(VIEW_PATH));
225    
226                    request.removeAttribute(VIEW_PATH);
227    
228                    if (log.isDebugEnabled()) {
229                            log.debug("View path " + viewPath);
230                    }
231            }
232    
233            protected void initPortletVariables() {
234                    liferayPortletConfig = (LiferayPortletConfig)request.getAttribute(
235                            JavaConstants.JAVAX_PORTLET_CONFIG);
236    
237                    portletContext = liferayPortletConfig.getPortletContext();
238    
239                    portlet = liferayPortletConfig.getPortlet();
240    
241                    alloyPortlet = (AlloyPortlet)request.getAttribute(
242                            JavaConstants.JAVAX_PORTLET_PORTLET);
243    
244                    portletRequest = (PortletRequest)request.getAttribute(
245                            JavaConstants.JAVAX_PORTLET_REQUEST);
246                    portletResponse = (PortletResponse)request.getAttribute(
247                            JavaConstants.JAVAX_PORTLET_RESPONSE);
248    
249                    liferayPortletResponse = (LiferayPortletResponse)portletResponse;
250    
251                    lifecycle = GetterUtil.getString(
252                            (String)request.getAttribute(PortletRequest.LIFECYCLE_PHASE));
253    
254                    if (log.isDebugEnabled()) {
255                            log.debug("Lifecycle " + lifecycle);
256                    }
257    
258                    if (lifecycle.equals(PortletRequest.ACTION_PHASE)) {
259                            actionRequest = (ActionRequest)portletRequest;
260                            actionResponse = (ActionResponse)portletResponse;
261                    }
262                    else if (lifecycle.equals(PortletRequest.EVENT_PHASE)) {
263                            eventRequest = (EventRequest)portletRequest;
264                            eventResponse = (EventResponse)portletResponse;
265                    }
266                    else if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
267                            renderRequest = (RenderRequest)portletRequest;
268                            renderResponse = (RenderResponse)portletResponse;
269                    }
270                    else if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
271                            resourceRequest = (ResourceRequest)portletRequest;
272                            resourceResponse = (ResourceResponse)portletResponse;
273                    }
274            }
275    
276            protected void initServletVariables() {
277                    servletConfig = pageContext.getServletConfig();
278                    servletContext = pageContext.getServletContext();
279                    request = (HttpServletRequest)pageContext.getRequest();
280                    response = (HttpServletResponse)pageContext.getResponse();
281            }
282    
283            protected void redirectTo(PortletURL portletURL) {
284                    redirectTo(portletURL.toString());
285            }
286    
287            protected void redirectTo(String redirect) {
288                    if (!lifecycle.equals(PortletRequest.ACTION_PHASE)) {
289                            throw new IllegalArgumentException(
290                                    "redirectTo can only be called during the action phase");
291                    }
292    
293                    if (Validator.isNotNull(viewPath)) {
294                            throw new IllegalArgumentException(
295                                    "redirectTo cannot be called if render has been called");
296                    }
297    
298                    this.redirect = redirect;
299            }
300    
301            protected void render(String actionPath) {
302                    if (Validator.isNotNull(redirect)) {
303                            throw new IllegalArgumentException(
304                                    "render cannot be called if redirectTo has been called");
305                    }
306    
307                    viewPath = actionPath;
308            }
309    
310            protected static final String CALLED_PROCESS_ACTION =
311                    "CALLED_PROCESS_ACTION";
312    
313            protected static final String VIEW_PATH = "VIEW_PATH";
314    
315            protected static Log log = LogFactoryUtil.getLog(
316                    BaseAlloyControllerImpl.class);
317    
318            protected String actionPath;
319            protected ActionRequest actionRequest;
320            protected ActionResponse actionResponse;
321            protected AlloyPortlet alloyPortlet;
322            protected ClassLoader classLoader;
323            protected Class<?> classObject;
324            protected String controllerPath;
325            protected EventRequest eventRequest;
326            protected EventResponse eventResponse;
327            protected String lifecycle;
328            protected LiferayPortletConfig liferayPortletConfig;
329            protected LiferayPortletResponse liferayPortletResponse;
330            protected Map<String, Method> methodsMap;
331            protected PageContext pageContext;
332            protected Portlet portlet;
333            protected PortletContext portletContext;
334            protected PortletRequest portletRequest;
335            protected PortletResponse portletResponse;
336            protected String redirect;
337            protected RenderRequest renderRequest;
338            protected RenderResponse renderResponse;
339            protected HttpServletRequest request;
340            protected ResourceRequest resourceRequest;
341            protected ResourceResponse resourceResponse;
342            protected HttpServletResponse response;
343            protected ServletConfig servletConfig;
344            protected ServletContext servletContext;
345            protected String viewPath;
346    
347    }