View Javadoc

1   /*
2    * Copyright 2003,2004 The Apache Software Foundation.
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, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  /* 
17  
18   */
19  
20  package org.apache.pluto.portalImpl.aggregation;
21  
22  import java.io.IOException;
23  import java.io.PrintWriter;
24  import java.io.StringWriter;
25  import java.util.ArrayList;
26  import java.util.Iterator;
27  import java.util.List;
28  
29  import javax.portlet.PortletMode;
30  import javax.portlet.UnavailableException;
31  import javax.portlet.WindowState;
32  import javax.servlet.RequestDispatcher;
33  import javax.servlet.ServletConfig;
34  import javax.servlet.ServletException;
35  import javax.servlet.http.HttpServletRequest;
36  import javax.servlet.http.HttpServletResponse;
37  
38  import org.apache.pluto.PortletContainerException;
39  import org.apache.pluto.om.ControllerObjectAccess;
40  import org.apache.pluto.om.common.Language;
41  import org.apache.pluto.om.common.LanguageSet;
42  import org.apache.pluto.om.entity.PortletEntity;
43  import org.apache.pluto.om.portlet.ContentType;
44  import org.apache.pluto.om.portlet.PortletDefinition;
45  import org.apache.pluto.om.servlet.ServletDefinition;
46  import org.apache.pluto.om.servlet.ServletDefinitionCtrl;
47  import org.apache.pluto.om.window.PortletWindow;
48  import org.apache.pluto.om.window.PortletWindowCtrl;
49  import org.apache.pluto.om.window.PortletWindowList;
50  import org.apache.pluto.om.window.PortletWindowListCtrl;
51  import org.apache.pluto.portalImpl.core.DynamicTitleServiceImpl;
52  import org.apache.pluto.portalImpl.core.PortalControlParameter;
53  import org.apache.pluto.portalImpl.core.PortalEnvironment;
54  import org.apache.pluto.portalImpl.core.PortalURL;
55  import org.apache.pluto.portalImpl.core.PortletContainerFactory;
56  import org.apache.pluto.portalImpl.factory.FactoryAccess;
57  import org.apache.pluto.portalImpl.om.window.impl.PortletWindowImpl;
58  import org.apache.pluto.portalImpl.services.log.Log;
59  import org.apache.pluto.portalImpl.services.portletentityregistry.PortletEntityRegistry;
60  import org.apache.pluto.portalImpl.servlet.ServletObjectAccess;
61  import org.apache.pluto.portalImpl.servlet.ServletResponseImpl;
62  import org.apache.pluto.portalImpl.util.ObjectID;
63  import org.apache.pluto.services.information.DynamicInformationProvider;
64  import org.apache.pluto.services.information.PortalContextProvider;
65  import org.apache.pluto.services.log.Logger;
66  
67  /***
68   * <p>Responsible for rendering a single Portlet.<p>
69   *
70   * <p>Requires two JSP files to exist, PortletFragmentHeader.jsp
71   * and PortletFragmentFooter.jsp. These pages define the header
72   * and footer of the portlet.</p>
73   *
74   * <p>A PortletFragment.PortletInfo object is added to the request
75   * attributes and makes information about the Portlet available to the
76   * header and footer JSP pages.</p>
77   *
78   * @author Stephan Hesmer
79   * @author Nick Lothian
80   *
81   */
82  public class PortletFragment extends AbstractFragmentSingle {
83      
84      private PortletWindow portletWindow = null;
85      private Logger log = null;
86  
87      public static final String PORTLET_ERROR_MSG = "Error occurred in portlet!";
88  
89      public PortletFragment(String id,
90                             ServletConfig config,
91                             org.apache.pluto.portalImpl.aggregation.Fragment parent,
92                             org.apache.pluto.portalImpl.om.page.Fragment fragDesc,
93                             org.apache.pluto.portalImpl.aggregation.navigation.Navigation navigation)
94              throws Exception
95      {
96  		super(id, config, parent, fragDesc, navigation);
97          log = Log.getService().getLogger(getClass());
98  		String portletEntityId = getInitParameters().getString("portlet");
99  		PortletEntity portletEntity = PortletEntityRegistry.getPortletEntity(ObjectID.createFromString(portletEntityId));
100 		portletWindow = new PortletWindowImpl(getId());
101 		((PortletWindowCtrl) portletWindow).setPortletEntity(portletEntity);
102 		PortletWindowList windowList = portletEntity.getPortletWindowList();
103 		((PortletWindowListCtrl) windowList).add(portletWindow);
104 	}
105 
106 	public void service(HttpServletRequest request, HttpServletResponse response)
107             throws ServletException, IOException
108     {
109 		HttpServletRequest wrappedRequest = ServletObjectAccess.getServletRequest(request, portletWindow);
110 		ServletResponseImpl wrappedResponse = (ServletResponseImpl)ServletObjectAccess.getServletResponse(response);
111 		PrintWriter responseWriter = response.getWriter();
112 		StringWriter storedWriter = new StringWriter();
113 
114 		// load the Portlet
115 		// If there is an error loading, then we will save the error message and attempt
116 		// to render it inside the Portlet, so the Portal has a chance of still looking
117 		// okay
118 		String errorMsg = null;
119 		try {
120 			PortletContainerFactory.getPortletContainer().portletLoad(portletWindow, wrappedRequest, response);
121 		} catch (PortletContainerException e) {
122 			log.error("Error in Portlet", e);
123 			errorMsg = getErrorMsg();
124 		} catch (Throwable t) {
125 			// If we catch any throwable, we want to try to continue
126 			// so that the rest of the portal renders correctly
127 			log.error("Error in Portlet", t);
128 			if (t instanceof VirtualMachineError) {
129 				// if the Throwable is a VirtualMachineError then
130 				// it is very unlikely (!) that the portal is going
131 				// to render correctly.
132 				throw (Error) t;
133 			} else {
134 				errorMsg = getErrorMsg();
135 			}
136 
137 		}
138 
139 		PortalEnvironment env = (PortalEnvironment) request.getAttribute(PortalEnvironment.REQUEST_PORTALENV);
140 		PortalURL thisURL = env.getRequestedPortalURL();
141 
142 		PortalControlParameter thisControl = new PortalControlParameter(thisURL);
143 		if (thisControl.isOnePortletWindowMaximized()) {
144 			WindowState currentState = thisControl.getState(portletWindow);
145 			if (!WindowState.MAXIMIZED.equals(currentState)) {
146 				return;
147 			}
148 		}
149 
150 		PortletDefinition portletDefinition = portletWindow.getPortletEntity().getPortletDefinition();
151 		LanguageSet languageSet = portletDefinition.getLanguageSet();
152 		Language lang = languageSet.get(request.getLocale());
153 		String title = lang != null ? lang.getTitle() : "no title available";
154 
155 		// create a PortletInfo object. This is used to communicate with
156 		// the header and footer JSP pages for this portlet
157 		PortletInfo portletInfo = new PortletInfo();
158 		
159         ServletDefinition servletDefinition = portletWindow.getPortletEntity().getPortletDefinition().getServletDefinition();
160         if (servletDefinition != null && !servletDefinition.isUnavailable()) {
161 			PrintWriter writer2 = new PrintWriter(storedWriter);
162 
163 			// create a wrapped response which the Portlet will be rendered to
164 			wrappedResponse = (ServletResponseImpl)ServletObjectAccess.getStoredServletResponse(response, writer2);
165 
166 			try {
167 				// render the Portlet to the wrapped response, to be output later.
168 				PortletContainerFactory.getPortletContainer().renderPortlet(portletWindow, wrappedRequest, wrappedResponse);
169 			} catch (UnavailableException e) {
170 				log.error("Portlet is Unavailable", e);
171 				writer2.println("the portlet is currently unavailable!");
172 
173 				ServletDefinitionCtrl servletDefinitionCtrl = (ServletDefinitionCtrl) ControllerObjectAccess.get(portletWindow.getPortletEntity().getPortletDefinition().getServletDefinition());
174 				if (e.isPermanent()) {
175 					servletDefinitionCtrl.setAvailable(Long.MAX_VALUE);
176 				} else {
177 					int unavailableSeconds = e.getUnavailableSeconds();
178 					if (unavailableSeconds <= 0) {
179 						unavailableSeconds = 60; // arbitrary default
180 					}
181 					servletDefinitionCtrl.setAvailable(System.currentTimeMillis() + unavailableSeconds * 1000);
182 				}
183 			} catch (Exception e) {
184 				log.error("Error in Portlet", e);
185 				writer2.println(getErrorMsg());
186 			}
187 			String dyn_title = ((DynamicTitleServiceImpl) FactoryAccess.getDynamicTitleContainerService()).getDynamicTitle(portletWindow, request);
188 			if (dyn_title != null) {
189 				title = dyn_title;
190 			}
191 
192 		}
193 		// set the title, so the header JSP page can use it when rendering
194 		portletInfo.setTitle(title);
195 
196 		DynamicInformationProvider provider = FactoryAccess.getDynamicProvider(request);
197 		ContentType supported = portletDefinition.getContentTypeSet().get(wrappedResponse.getContentType());
198 		PortalContextProvider portalContextProvider = FactoryAccess.getStaticProvider().getPortalContextProvider();
199 
200 		// get the list of modes this Portlet supports
201 		if (supported != null && portalContextProvider != null) {
202 			// if portlet supports portlet modes
203 			Iterator modes = supported.getPortletModes();
204 			while (modes.hasNext()) {
205 				PortletMode mode = (PortletMode) modes.next();
206 
207 				// check whether portal also supports portlet mode
208 				boolean portalSupport = false;
209 				Iterator portalSupportedModes = portalContextProvider.getSupportedPortletModes().iterator();
210 				while (portalSupportedModes.hasNext()) {
211 					PortletMode portalSupportedMode = (PortletMode) portalSupportedModes.next();
212 					if (mode.equals(portalSupportedMode)) {
213 						portalSupport = true;
214 						break;
215 					}
216 				}
217 
218 				// create links for portlet modes in portlet header
219 				if (portalSupport) {
220 					env = (PortalEnvironment) request.getAttribute(PortalEnvironment.REQUEST_PORTALENV);
221 					PortalURL modeURL = env.getRequestedPortalURL();
222 
223 					PortalControlParameter control = new PortalControlParameter(modeURL);
224 					PortletMode currentMode = control.getMode(portletWindow);
225 					control.setMode(portletWindow, mode);
226 
227 					portletInfo.addPortletMode(mode, modeURL.toString(control, new Boolean(request.isSecure())), mode.equals(currentMode));
228 				}
229 			}
230 
231 			// get the list of window states this Portlet supports
232 			Iterator states = portalContextProvider.getSupportedWindowStates().iterator();
233 			while (states.hasNext()) {
234 				WindowState state = (WindowState) states.next();
235 				env = (PortalEnvironment) request.getAttribute(PortalEnvironment.REQUEST_PORTALENV);
236 				PortalURL stateURL = env.getRequestedPortalURL();
237 				PortalControlParameter control = new PortalControlParameter(stateURL);
238 				WindowState currentState = control.getState(portletWindow);
239 
240 				control.setState(portletWindow, state);
241 				portletInfo.addPortletWindowState(state.toString().substring(0, 3), stateURL.toString(control, new Boolean(request.isSecure())), state.equals(currentState));
242 			}
243 		}
244 		// output the header JSP page
245 		request.setAttribute("portletInfo", portletInfo);
246 		RequestDispatcher rd = getServletConfig().getServletContext().getRequestDispatcher(BASE_ROOT + "PortletFragmentHeader.jsp");
247 		rd.include(request, response);
248 		try {
249 			// output the Portlet
250 			// check if there is an error message
251 			if (errorMsg == null) {
252 				// no error message, so output the Portlet
253 				if (portletWindow.getPortletEntity().getPortletDefinition().getServletDefinition().isUnavailable()) {
254 					// the portlet is unavailable
255 					responseWriter.println("the portlet is currently unavailable!");
256 				} else {
257 					responseWriter.println(storedWriter.toString());
258 				}
259 			} else {
260 				// output the errror message
261 				responseWriter.println(errorMsg);
262 			}
263 		} finally {
264 			// output the footer JSP page
265 			RequestDispatcher rdFooter = getServletConfig().getServletContext().getRequestDispatcher(BASE_ROOT + "PortletFragmentFooter.jsp");
266 			rdFooter.include(request, response);
267 			request.removeAttribute("portletInfo");
268 		}
269 
270 	}
271 
272 	public void createURL(PortalURL url) {
273 		getParent().createURL(url);
274 		url.addLocalNavigation(getId());
275 	}
276 
277 	public boolean isPartOfURL(PortalURL url) {
278 		return true;
279 	}
280 
281 	public PortletWindow getPortletWindow() {
282 		return portletWindow;
283 	}
284 
285 	public static class PortletInfo {
286 		private String title;
287 		private List availablePortletModes = new ArrayList();
288 		private List availablePortletWindowStates = new ArrayList();
289 
290 		/***
291 		 * @return portlet title.
292 		 */
293 		public String getTitle() {
294 			return title;
295 		}
296 
297 		/***
298 		 * @param string representing the new title.
299 		 */
300 		public void setTitle(String string) {
301 			title = string;
302 		}
303 
304 		/***
305 		 * @return available modes
306 		 */
307 		public List getAvailablePortletModes() {
308 			return availablePortletModes;
309 		}
310 
311 		public void addPortletMode(PortletMode mode, String activationURL, boolean isCurrent) {
312 		    PortletModeInfo pmi = new PortletModeInfo(mode.toString(), activationURL, isCurrent);
313 			availablePortletModes.add(pmi);
314 		}
315 
316 		/***
317 		 * @return list of all available portlet states.
318 		 */
319 		public List getAvailablePortletWindowStates() {
320 			return availablePortletWindowStates;
321 		}
322 
323 		public void addPortletWindowState(String stateLabel, String activationURL, boolean isCurrent) {
324 			PortletWindowStateInfo pwsi = new PortletWindowStateInfo(stateLabel, activationURL, isCurrent);
325 			availablePortletWindowStates.add(pwsi);
326 		}
327 
328 	}
329 
330 	public static class PortletWindowStateInfo implements Comparable {
331 		private String label;
332 		private String url;
333 		private boolean isCurrent;
334 
335 		/***
336 		 * @see java.lang.Comparable#compareTo(java.lang.Object)
337 		 */
338 		public int compareTo(Object compare) {
339 			if (!(compare instanceof PortletWindowStateInfo)) {
340 				throw new ClassCastException(compare + " is not a " + PortletWindowStateInfo.class.getName());
341 			} else {
342 				PortletWindowStateInfo other = (PortletWindowStateInfo) compare;
343 				return this.getLabel().compareTo(other.getLabel());
344 			}
345 		}
346 		/***
347 		 * @param stateLabel
348 		 * @param activationURL
349 		 * @param isCurrent
350 		 */
351 		public PortletWindowStateInfo(String stateLabel, String activationURL, boolean isCurrent) {
352 			this.label = stateLabel;
353 			this.url = activationURL;
354 			this.isCurrent = isCurrent;
355 		}
356 		/***
357 		 * @return the label.
358 		 */
359 		public String getLabel() {
360 			return label;
361 		}
362 
363 		/***
364 		 * @param string
365 		 */
366 		public void setLabel(String string) {
367 			label = string;
368 		}
369 
370 		/***
371 		 * @return current indicator.
372 		 */
373 		public boolean isCurrent() {
374 			return isCurrent;
375 		}
376 
377 		/***
378 		 * @return url
379 		 */
380 		public String getUrl() {
381 			return url;
382 		}
383 
384 		/***
385 		 * @param b
386 		 */
387 		public void setCurrent(boolean b) {
388 			isCurrent = b;
389 		}
390 
391 		/***
392 		 * @param string
393 		 */
394 		public void setUrl(String string) {
395 			url = string;
396 		}
397 
398 		public String toString() {
399 			return getLabel();
400 		}
401 
402 	}
403 
404 	public static class PortletModeInfo implements Comparable {
405 		private String name;
406 		private String url;
407 		private boolean isCurrent;
408 
409 		public PortletModeInfo(String name, String url, boolean isCurrent) {
410 			this.name = name;
411 			this.url = url;
412 			this.isCurrent = isCurrent;
413 		}
414 
415 		/***
416 		 * @return current flag
417 		 */
418 		public boolean isCurrent() {
419 			return isCurrent;
420 		}
421 
422 		/***
423 		 * @return name
424 		 */
425 		public String getName() {
426 			return name;
427 		}
428 
429 		/***
430 		 * @return url
431 		 */
432 		public String getUrl() {
433 			return url;
434 		}
435 
436 		/***
437 		 * @param b
438 		 */
439 		public void setCurrent(boolean b) {
440 			isCurrent = b;
441 		}
442 
443 		/***
444 		 * @param string
445 		 */
446 		public void setName(String string) {
447 			name = string;
448 		}
449 
450 		/***
451 		 * @param string
452 		 */
453 		public void setUrl(String string) {
454 			url = string;
455 		}
456 
457 		/***
458 		 * @see java.lang.Comparable#compareTo(java.lang.Object)
459 		 */
460 		public int compareTo(Object compare) {
461 			if (!(compare instanceof PortletModeInfo)) {
462 				throw new ClassCastException(compare + " is not a " + PortletModeInfo.class.getName());
463 			} else {
464 				PortletModeInfo other = (PortletModeInfo) compare;
465 				return this.getName().compareTo(other.getName());
466 			}
467 		}
468 
469 		public String toString() {
470 			return getName();
471 		}
472 	}
473 
474     protected String getErrorMsg() {
475         return PORTLET_ERROR_MSG;
476     }
477 
478 
479 
480 }