1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.jetspeed.portal.portlets;
17
18 import java.io.IOException;
19 import java.io.PrintWriter;
20 import java.io.UnsupportedEncodingException;
21 import java.net.URLEncoder;
22
23 import javax.servlet.http.HttpServletRequest;
24
25 import org.apache.ecs.ConcreteElement;
26 import org.apache.jetspeed.om.profile.Profile;
27 import org.apache.jetspeed.portal.PortletException;
28 import org.apache.jetspeed.portal.portlets.viewprocessor.ViewProcessor;
29 import org.apache.jetspeed.portal.portlets.viewprocessor.ViewProcessorFactory;
30 import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
31 import org.apache.jetspeed.services.logging.JetspeedLogger;
32 import org.apache.jetspeed.services.rundata.JetspeedRunData;
33 import org.apache.jetspeed.util.PortletSessionState;
34 import org.apache.jetspeed.util.template.JetspeedLink;
35 import org.apache.jetspeed.util.template.JetspeedTemplateLink;
36 import org.apache.jetspeed.util.template.JspTemplate;
37 import org.apache.turbine.modules.ActionLoader;
38 import org.apache.turbine.services.pull.TurbinePull;
39 import org.apache.turbine.util.RunData;
40
41 /***
42 * Provides the basic MVC Portlet functionality independant of any
43 * specific view technology (ie jsp, velocity, xslt, etc). It handles
44 * the views via a ViewProcessor, which is a pluggable, factory
45 * created, run time module for which ever view technology your portlet
46 * uses.
47 *
48 * There is no need to extend this portlet class, just define your porlet
49 * entry in the registy as a child of this class and provide your template
50 * and action class (extened from GenericMVCAction of course) and you
51 * are good to go.
52 *
53 * Example .xreg entry:
54 *
55 * <portlet-entry name="GenericMVCPortlet" hidden="false"
56 * type="abstract" application="false">
57 * <security-ref parent="default"/>
58 * <classname>com.cisco.it.psf.portal.portlets.GenericMVCPortlet</classname>
59 * <media-type ref="html"/>
60 * <url cachedOnURL="true"/>
61 * </portlet-entry>
62 * <portlet-entry name="VelocityMVCExample" hidden="false" type="ref"
63 * parent="GenericMVCPortlet" application="false">
64 * <meta-info>
65 * <title>Velocity MVC Portlet</title>
66 * <description>Velocity Generic MVC Portlet</description>
67 * </meta-info>
68 * <classname>com.cisco.it.psf.portal.portlets.GenericMVCPortlet</classname>
69 * <parameter name="template" value="mvc-example" hidden="true"
70 * cachedOnName="true" cachedOnValue="true"/>
71 * <parameter name="viewtype" value="Velocity" hidden="true"
72 * cachedOnName="true" cachedOnValue="true"/>
73 * <parameter name="action"
74 * value="portlets.ExampleGenericMVCAction" hidden="true"
75 * cachedOnName="true" cachedOnValue="true"/>
76 * <url cachedOnURL="true"/>
77 * </portlet-entry>
78 *
79 * See the Velocity and JSP MVC Portlet examples for template and action class clues.
80 *
81 * To add new view processor types, simply implement the ViewProcessor
82 * interface and add your type into the <b>viewprocessor.properties</b> file as
83 * shown in the example below:
84 *
85 * mvc.viewprocessor.Velocity = org.apache.jetspeedportlets.viewprocessors.VelocityViewProcessor
86 * mvc.viewprocessor.JSP = org.apache.jetspeedportlets.viewprocessors.JSPViewProcessor
87 * mvc.viewprocessor.XSL = org.apache.jetspeedportlets.viewprocessors.XSLViewProcessor
88 *
89 * @stereotype role
90 * @author tkuebler
91 * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
92 * @version $Id: GenericMVCPortlet.java,v 1.11 2003/02/11 23:09:18 tkuebler Exp $
93 */
94 public class GenericMVCPortlet extends AbstractInstancePortlet
95 {
96
97 /***
98 * Static initialization of the logger for this class
99 */
100 private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(GenericMVCPortlet.class.getName());
101
102
103 public static final String PORTLET = "portlet";
104 public static final String TEMPLATE = "template";
105 public static final String RUNDATA = "data";
106 public static final String PORTLET_CONFIG = "conf";
107 public static final String SKIN = "skin";
108 public static final String VIEW_TYPE = "viewType";
109 public static final String IS_CACHEABLE = "_IsCacheable";
110
111
112 private String viewType = "ERROR: not set in config";
113 private String actionName = "ERROR: not set in config";
114 private String template = "ERROR: not set in config";
115 private String configureTemplate;
116 private String maximizedTemplate;
117 private ViewProcessor processor = null;
118 private boolean providesCustomization;
119
120 public static final String RENDERING_DELAYED = "renderingDelayed";
121 public static final String SIMULATE_DELAY = "simulateDelay";
122 public static final String PORTLET_ID = "__portletId";
123 public static final String DOC_URL = "__docUrl";
124
125 public void init() throws PortletException
126 {
127
128
129 String provConf = getPortletConfig().getInitParameter("provides.customization", "false");
130 providesCustomization = new Boolean(provConf).booleanValue();
131
132
133 actionName = getPortletConfig().getInitParameter("action");
134
135 if (getPortletConfig().getInitParameter("viewtype") != null)
136 {
137 viewType = getPortletConfig().getInitParameter("viewtype");
138 }
139
140 template = getPortletConfig().getInitParameter("template");
141
142
143 logger.info(
144 "GenericMVCPortlet - creating view processor for viewtype = "
145 + viewType
146 + ", template = "
147 + template);
148 processor = ViewProcessorFactory.getViewProcessor(viewType);
149
150
151 processor.init(this);
152
153
154
155
156
157 }
158
159 /***
160 * By default MVCPortlets are cacheable. This can be overriden by specifying
161 * "_IsCacheable" parameter.
162 *
163 * @return
164 */
165 public boolean isCacheable()
166 {
167 return getPortletConfig().getInitParameter(IS_CACHEABLE, "true").equalsIgnoreCase("true");
168 }
169
170 /***
171 * Whether or not this portlet provides it's own customizer.
172 * This can be set at the registry level by adding a
173 * boolean paramter "provides.customization"
174 * Defaults to "false"
175 */
176 public boolean providesCustomization()
177 {
178 return providesCustomization;
179 }
180
181 public ConcreteElement getContent(RunData rundata)
182 {
183 if (useDelayedRendering(rundata))
184 {
185 Profile profile = ((JetspeedRunData) rundata).getProfile();
186 String path = profile.getPath();
187 String portletId = getID();
188
189
190 String docUrl = "portal/" + path + "/js_peid/" + portletId + "?action=controls.Print";
191 docUrl = URLEncoder.encode(docUrl);
192
193
194 HttpServletRequest request = rundata.getRequest();
195 request.setAttribute(PORTLET_ID, portletId);
196 request.setAttribute(DOC_URL, docUrl);
197
198
199 return renderJspTemplate(rundata, "delayedContent.jsp");
200 }
201
202 simulateDelay();
203
204
205 if (!isCacheable() || null == getExpirationMillis())
206 {
207 return buildContent(rundata);
208 }
209
210
211 if (getExpirationMillis().longValue() <= System.currentTimeMillis())
212 {
213 return buildContent(rundata);
214 }
215
216
217 return getContent(rundata, null, true);
218
219 }
220
221 protected ConcreteElement buildContent(RunData rundata)
222 {
223
224
225 GenericMVCContext context = new GenericMVCContext(TurbinePull.getGlobalContext());
226 context.put(RUNDATA, rundata);
227 context.put(PORTLET, this);
228 context.put(PORTLET_CONFIG, this.getPortletConfig());
229 context.put(SKIN, this.getPortletConfig().getPortletSkin());
230 context.put(TEMPLATE, getCurrentTemplate(rundata));
231 context.put(VIEW_TYPE, viewType);
232 populateRequest(rundata);
233
234
235 TurbinePull.populateContext(context, rundata);
236
237
238 Object jlink = context.get("jlink");
239
240 if (jlink instanceof JetspeedTemplateLink)
241 {
242 ((JetspeedTemplateLink) jlink).setPortlet(this);
243 }
244
245 Object jslink = context.get("jslink");
246
247 if (jslink instanceof JetspeedLink)
248 {
249 ((JetspeedLink) jslink).setPortlet(this);
250 }
251
252
253 if (actionName != null)
254 {
255
256 try
257 {
258
259
260
261
262
263
264 rundata.getTemplateInfo().setTemplateContext("VelocityPortletContext", context);
265
266 if (logger.isDebugEnabled())
267 {
268 logger.debug(
269 "GenericMVCPortlet: Executing action ["
270 + actionName
271 + "] for portlet ["
272 + this.getName()
273 + "]");
274 }
275
276 ActionLoader.getInstance().exec(rundata, actionName);
277 }
278 catch (Exception e)
279 {
280 logger.error("GenericMVCPortlet - error executing action", e);
281 }
282 }
283
284
285
286 logger.info("GenericMVCPortlet - calling processView on processor");
287
288 ConcreteElement result = (ConcreteElement) processor.processView(context);
289 logger.info("GenericMVCPortlet - setting this portlet's content");
290 clearContent();
291 setContent(result);
292
293
294 return result;
295 }
296 /***
297 * @see setViewType()
298 * @return String
299 */
300 protected String getViewType()
301 {
302 return viewType;
303 }
304
305 /***
306 * STW: Added for backward compatibility when using this
307 * class to subclass the existing Jsp and Velocity portlets
308 * so they can set their view prior to super.init();
309 * @param viewType The viewType to set
310 */
311 protected void setViewType(String viewType)
312 {
313 this.viewType = viewType;
314 }
315
316 /***
317 * This is called before any action execution happens.
318 * This provides backward compatibility to JspPortletActions
319 * who retreive information, like Portlet, from the request
320 * BEFORE the ViewProcessor.processView() is called
321 * which normally populates the request with Context objects.
322 * @author <a href="mailto:sweaver@rippe.com">Scott Weaver</a>
323 */
324 protected void populateRequest(RunData rundata)
325 {
326 HttpServletRequest request = rundata.getRequest();
327 request.setAttribute("data", rundata);
328 request.setAttribute("portlet", this);
329 request.setAttribute("conf", this.getPortletConfig());
330 request.setAttribute("skin", this.getPortletConfig().getPortletSkin());
331 request.setAttribute("template", getCurrentTemplate(rundata));
332 request.setAttribute("viewType", viewType);
333 }
334
335 /***
336 *
337 */
338 protected String getCurrentTemplate( RunData data)
339 {
340 String useTemplate = (String) PortletSessionState.getAttribute(this, data, TEMPLATE);
341 if(useTemplate == null)
342 {
343 useTemplate = this.template;
344 }
345
346 return useTemplate;
347 }
348
349 protected boolean useDelayedRendering(RunData rundata)
350 {
351 String renderingDelayedString = getPortletConfig().getInitParameter(RENDERING_DELAYED);
352 boolean renderingDelayed = false;
353 if (renderingDelayedString != null)
354 {
355 renderingDelayed = (Boolean.valueOf(renderingDelayedString) == Boolean.TRUE);
356 }
357
358 HttpServletRequest request = rundata.getRequest();
359 String action = rundata.getAction();
360
361 return renderingDelayed && (action == null || action.length() == 0 || "controls.Restore".equals(action));
362 }
363
364 protected ConcreteElement renderJspTemplate(RunData rundata, String templateName)
365 {
366 JspTemplate t = new JspTemplate(rundata, "/portlets/html/" + templateName);
367 PrintWriter out = null;
368 try
369 {
370 out = rundata.getOut();
371 out.println(t.getContent());
372 }
373 catch (IOException ioe)
374 {
375 logger.error(ioe);
376 }
377
378 return null;
379 }
380
381 private void simulateDelay()
382 {
383 String simulateDelayString = getPortletConfig().getInitParameter(SIMULATE_DELAY);
384 int simulateDelay = 0;
385 if (simulateDelayString != null)
386 {
387 simulateDelay = Integer.parseInt(simulateDelayString);
388 }
389
390 if (simulateDelay > 0)
391 {
392 long delayInMilliseconds = simulateDelay * 1000;
393 try
394 {
395 Thread.sleep(delayInMilliseconds);
396 }
397 catch (InterruptedException e)
398 {
399 }
400 }
401
402 }
403 }