001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Sam
027: */
028:
029: package com.caucho.portal;
030:
031: import com.caucho.util.L10N;
032:
033: import javax.portlet.*;
034: import java.io.File;
035: import java.io.IOException;
036: import java.lang.reflect.InvocationTargetException;
037: import java.lang.reflect.Method;
038: import java.util.Collections;
039: import java.util.HashMap;
040: import java.util.Iterator;
041: import java.util.Map;
042: import java.util.NoSuchElementException;
043: import java.util.logging.Level;
044: import java.util.logging.Logger;
045:
046: public class PortletSupport extends GenericPortlet {
047: private static final L10N L = new L10N(PortletSupport.class);
048:
049: static protected final Logger log = Logger
050: .getLogger(PortletSupport.class.getName());
051:
052: private static final Class[] _actionMethodParams = new Class[] {
053: ActionRequest.class, ActionResponse.class };
054:
055: private static final Class[] _renderMethodParams = new Class[] {
056: RenderRequest.class, RenderResponse.class };
057:
058: private Map<PortletMode, ActionProxy> _actionProxyCache = Collections
059: .synchronizedMap(new HashMap<PortletMode, ActionProxy>());
060:
061: private Map<PortletMode, RenderProxy> _renderProxyCache = Collections
062: .synchronizedMap(new HashMap<PortletMode, RenderProxy>());
063:
064: private interface ActionProxy {
065: public void processAction(ActionRequest request,
066: ActionResponse response) throws PortletException,
067: IOException;
068: }
069:
070: private interface RenderProxy {
071: public void render(RenderRequest request,
072: RenderResponse response) throws PortletException,
073: IOException;
074: }
075:
076: public void init() throws PortletException {
077: }
078:
079: protected <T> T useBean(PortletRequest request, String name,
080: Class<T> c) {
081: return useBean(request, name, c, true);
082: }
083:
084: protected <T> T useBean(PortletRequest request, String name,
085: Class<T> c, boolean create) {
086: T bean = (T) request.getAttribute(name);
087:
088: if (bean == null && create) {
089: try {
090: bean = c.newInstance();
091: } catch (Exception ex) {
092: throw new RuntimeException(ex);
093: }
094:
095: request.setAttribute(name, bean);
096: }
097:
098: return bean;
099: }
100:
101: protected boolean isEmpty(String s) {
102: return s == null || s.length() == 0;
103: }
104:
105: protected static <S extends PortletMediator> S createMediator(
106: RenderRequest request, RenderResponse response,
107: Class<S> mediatorClass) throws PortletException {
108: String namespace = response.getNamespace();
109:
110: return createMediator(request, response, mediatorClass,
111: namespace);
112: }
113:
114: protected static <S extends PortletMediator> S createMediator(
115: RenderRequest request, RenderResponse response,
116: Class<S> mediatorClass, String namespace)
117: throws PortletException {
118: String attributeName = mediatorClass.getName();
119:
120: if (namespace != null)
121: attributeName = attributeName + namespace;
122:
123: S mediator = (S) request.getAttribute(attributeName);
124:
125: if (mediator == null) {
126: try {
127: mediator = (S) mediatorClass.newInstance();
128: } catch (Exception ex) {
129: throw new PortletException(ex);
130: }
131:
132: request.setAttribute(attributeName, mediator);
133: }
134:
135: mediator.setNamespace(namespace);
136: mediator.setRequest(request);
137: mediator.setResponse(response);
138:
139: return mediator;
140: }
141:
142: /**
143: * Prepare is called once for each request, either before the action method
144: * appropriate for the mode is invoked, or if there is no action then
145: * before a render appropriate for the mode is invoked.
146: */
147: protected void prepare(PortletRequest request,
148: PortletResponse response) throws PortletException {
149: }
150:
151: protected void checkPrepare(PortletRequest request,
152: PortletResponse response) throws PortletException {
153:
154: String attributeName = "__prepared__"
155: + System.identityHashCode(this );
156:
157: if (request.getAttribute(attributeName) == null) {
158: request.setAttribute(attributeName, Boolean.TRUE);
159:
160: if (log.isLoggable(Level.FINEST))
161: log.finest(L.l("prepare for mode `{0}'", request
162: .getPortletMode()));
163:
164: prepare(request, response);
165: }
166: }
167:
168: private ActionProxy findActionProxy(ActionRequest request,
169: ActionResponse response) {
170: PortletMode mode = request.getPortletMode();
171: ActionProxy proxy = _actionProxyCache.get(mode);
172:
173: if (proxy != null)
174: return proxy;
175:
176: // try to find a method named "action" + mode
177:
178: try {
179: String methodName = new StringBuffer().append("action")
180: .append(
181: Character.toUpperCase(mode.toString()
182: .charAt(0))).append(
183: mode.toString().substring(1)).toString();
184:
185: if (log.isLoggable(Level.FINER))
186: log.log(Level.FINER, "looking for method `"
187: + methodName + "'");
188:
189: final Method method = getClass().getMethod(methodName,
190: _actionMethodParams);
191:
192: if (method != null) {
193: proxy = new ActionProxy() {
194: public void processAction(ActionRequest request,
195: ActionResponse response)
196: throws PortletException, IOException {
197: try {
198: if (log.isLoggable(Level.FINEST))
199: log.log(Level.FINER, "invoking method "
200: + method);
201:
202: method.invoke(PortletSupport.this ,
203: new Object[] { request, response });
204: } catch (IllegalAccessException ex) {
205: throw new PortletException(ex);
206: } catch (InvocationTargetException ex) {
207: throw new PortletException(ex);
208: }
209: }
210: };
211: }
212: } catch (NoSuchMethodException ex) {
213: if (log.isLoggable(Level.FINE))
214: log.log(Level.FINE, ex.toString(), ex);
215: }
216:
217: if (proxy != null)
218: _actionProxyCache.put(mode, proxy);
219:
220: return proxy;
221: }
222:
223: public void processAction(ActionRequest request,
224: ActionResponse response) throws PortletException,
225: IOException {
226: PortletMode mode = request.getPortletMode();
227:
228: if (log.isLoggable(Level.FINEST))
229: log.finest(L.l("processAction for mode `{0}'", mode));
230:
231: ActionProxy proxy = findActionProxy(request, response);
232:
233: if (proxy == null)
234: throw new PortletModeException(L.l(
235: "No action for mode `{0}'", mode), mode);
236:
237: checkPrepare(request, response);
238:
239: proxy.processAction(request, response);
240: }
241:
242: private RenderProxy findRenderProxy(RenderRequest request,
243: RenderResponse response) {
244: PortletMode mode = request.getPortletMode();
245:
246: RenderProxy proxy = _renderProxyCache.get(mode);
247:
248: if (proxy != null)
249: return proxy;
250:
251: // try to find a .xtp/.jsp/.jspx file
252:
253: Iterator<String> candidates = getViewCandidates(request,
254: response);
255:
256: while (candidates.hasNext()) {
257: String candidate = candidates.next();
258:
259: if (log.isLoggable(Level.FINER))
260: log.finer(L.l("view candidate `{0}'", candidate));
261:
262: if (new File(getPortletContext().getRealPath(candidate))
263: .exists()) {
264: final String target = candidate;
265:
266: proxy = new RenderProxy() {
267: public void render(RenderRequest request,
268: RenderResponse response)
269: throws PortletException, IOException {
270: dispatchView(request, response, target);
271: }
272: };
273:
274: break;
275: }
276: }
277:
278: if (proxy != null) {
279: _renderProxyCache.put(mode, proxy);
280:
281: return proxy;
282: }
283:
284: // try to find a method named "do" + mode
285:
286: String methodName = new StringBuffer().append("do").append(
287: Character.toUpperCase(mode.toString().charAt(0)))
288: .append(mode.toString().substring(1)).toString();
289:
290: if (log.isLoggable(Level.FINER))
291: log.log(Level.FINER, "looking for method `" + methodName
292: + "'");
293:
294: try {
295: final Method method = getClass().getMethod(methodName,
296: _renderMethodParams);
297:
298: if (method != null) {
299: proxy = new RenderProxy() {
300: public void render(RenderRequest request,
301: RenderResponse response)
302: throws PortletException, IOException {
303: try {
304: if (log.isLoggable(Level.FINER))
305: log.log(Level.FINER, "invoking method "
306: + method);
307:
308: if (log.isLoggable(Level.FINER))
309: log.log(Level.FINER, "with " + request
310: + " " + response);
311:
312: method.invoke(PortletSupport.this ,
313: new Object[] { request, response });
314: } catch (IllegalAccessException ex) {
315: throw new PortletException(ex);
316: } catch (InvocationTargetException ex) {
317: throw new PortletException(ex);
318: }
319: }
320: };
321: }
322: } catch (NoSuchMethodException ex) {
323: if (log.isLoggable(Level.FINEST))
324: log.log(Level.FINEST, ex.toString(), ex);
325: }
326:
327: if (proxy != null)
328: _renderProxyCache.put(mode, proxy);
329:
330: return proxy;
331: }
332:
333: protected Iterator<String> getViewCandidates(RenderRequest request,
334: RenderResponse response) {
335: final String path = new StringBuffer().append(getPortletName())
336: .append('/')
337: .append(request.getPortletMode().toString()).toString();
338:
339: return new Iterator<String>() {
340: int i = 0;
341:
342: public boolean hasNext() {
343: return i < 3;
344: }
345:
346: public String next() {
347: switch (i++) {
348: case 0:
349: return path + ".xtp";
350: case 1:
351: return path + ".jsp";
352: case 2:
353: return path + ".jspx";
354: default:
355: throw new NoSuchElementException();
356: }
357: }
358:
359: public void remove() {
360: throw new UnsupportedOperationException();
361: }
362: };
363: }
364:
365: public void render(RenderRequest request, RenderResponse response)
366: throws PortletException, IOException {
367: WindowState windowState = request.getWindowState();
368:
369: if (windowState.equals(WindowState.MINIMIZED))
370: return;
371:
372: RenderProxy proxy = findRenderProxy(request, response);
373:
374: PortletMode mode = request.getPortletMode();
375:
376: if (log.isLoggable(Level.FINEST))
377: log.finest(L.l("render for mode `{0}'", mode));
378:
379: if (proxy == null)
380: throw new PortletModeException(L.l(
381: "No render for mode `{0}'", mode), mode);
382:
383: checkPrepare(request, response);
384:
385: if (response.getContentType() == null)
386: response.setContentType("text/html");
387:
388: proxy.render(request, response);
389:
390: }
391:
392: protected void dispatchView(RenderRequest request,
393: RenderResponse response, String path)
394: throws PortletException, IOException {
395: if (log.isLoggable(Level.FINEST))
396: log.finest(L.l("dispatching view to `{0}'", path));
397:
398: PortletRequestDispatcher dispatcher = getPortletContext()
399: .getRequestDispatcher(path);
400:
401: dispatcher.include(request, response);
402: }
403: }
|