| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.cocoon.portlet; |
| |
| import org.apache.avalon.excalibur.logger.LogKitLoggerManager; |
| import org.apache.avalon.framework.configuration.Configuration; |
| import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; |
| import org.apache.avalon.framework.context.DefaultContext; |
| import org.apache.avalon.framework.logger.LogKitLogger; |
| import org.apache.avalon.framework.logger.Logger; |
| |
| import org.apache.cocoon.Cocoon; |
| import org.apache.cocoon.CocoonAccess; |
| import org.apache.cocoon.ConnectionResetException; |
| import org.apache.cocoon.Constants; |
| import org.apache.cocoon.ResourceNotFoundException; |
| import org.apache.cocoon.components.notification.DefaultNotifyingBuilder; |
| import org.apache.cocoon.components.notification.Notifier; |
| import org.apache.cocoon.components.notification.Notifying; |
| import org.apache.cocoon.environment.Environment; |
| import org.apache.cocoon.environment.portlet.PortletContext; |
| import org.apache.cocoon.environment.portlet.PortletEnvironment; |
| import org.apache.cocoon.portlet.multipart.MultipartActionRequest; |
| import org.apache.cocoon.portlet.multipart.RequestFactory; |
| |
| import org.apache.commons.lang.BooleanUtils; |
| import org.apache.log.ContextMap; |
| import org.apache.log.Hierarchy; |
| import org.apache.pluto.core.impl.PortletContextImpl; |
| |
| import javax.portlet.ActionRequest; |
| import javax.portlet.ActionResponse; |
| import javax.portlet.GenericPortlet; |
| import javax.portlet.PortletConfig; |
| import javax.portlet.PortletException; |
| import javax.portlet.PortletSession; |
| import javax.portlet.RenderRequest; |
| import javax.portlet.RenderResponse; |
| import javax.portlet.PortletRequest; |
| import javax.portlet.PortletPreferences; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.PrintStream; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.HashMap; |
| |
| /** |
| * This is the entry point for Cocoon execution as an JSR-168 Portlet. |
| * |
| * <p>This implementation of the Portlet interface requires that someone will |
| * first create and initialize an instance of the Cocoon object, and this |
| * Portlet will use this instance to process requests.</p> |
| * |
| * @version CVS $Id$ |
| */ |
| public class ManagedCocoonPortlet extends GenericPortlet { |
| |
| // Processing time message |
| protected static final String PROCESSED_BY = "Processed by " |
| + Constants.COMPLETE_NAME + " in "; |
| |
| // Used by "show-time" |
| static final float SECOND = 1000; |
| static final float MINUTE = 60 * SECOND; |
| static final float HOUR = 60 * MINUTE; |
| |
| private Logger log; |
| |
| /** |
| * Holds exception happened during initialization (if any) |
| */ |
| protected Exception exception; |
| |
| |
| /** |
| * Allow adding processing time to the response |
| */ |
| protected boolean showTime; |
| |
| /** |
| * If true, processing time will be added as an HTML comment |
| */ |
| protected boolean hiddenShowTime; |
| |
| |
| /** |
| * Default value for {@link #enableUploads} parameter (false) |
| */ |
| private static final boolean ENABLE_UPLOADS = false; |
| private static final boolean SAVE_UPLOADS_TO_DISK = true; |
| private static final int MAX_UPLOAD_SIZE = 10000000; // 10Mb |
| |
| /** |
| * Allow processing of upload requests (mime/multipart) |
| */ |
| private boolean enableUploads; |
| private boolean autoSaveUploads; |
| private boolean allowOverwrite; |
| private boolean silentlyRename; |
| private int maxUploadSize; |
| |
| private File uploadDir; |
| private File workDir; |
| |
| private String containerEncoding; |
| private String defaultFormEncoding; |
| |
| protected javax.portlet.PortletContext portletContext; |
| protected PortletContext envPortletContext; |
| |
| |
| /** |
| * If true or not set, this class will try to catch and handle all Cocoon exceptions. |
| * If false, it will rethrow them to the portlet container. |
| */ |
| private boolean manageExceptions; |
| |
| /** |
| * This is the path to the portlet context (or the result |
| * of calling getRealPath('/') on the PortletContext. |
| * Note, that this can be null. |
| */ |
| protected String portletContextPath; |
| |
| /** |
| * This is the url to the portlet context directory |
| */ |
| protected String portletContextURL; |
| |
| /** |
| * The RequestFactory is responsible for wrapping multipart-encoded |
| * forms and for handing the file payload of incoming requests |
| */ |
| protected RequestFactory requestFactory; |
| |
| /** |
| * Value to be used as servletPath in the request. |
| * Provided via configuration parameter, if missing, defaults to the |
| * '/portlets/' + portletName. |
| */ |
| protected String servletPath; |
| |
| /** |
| * Default scope for the session attributes, either |
| * {@link javax.portlet.PortletSession#PORTLET_SCOPE} or |
| * {@link javax.portlet.PortletSession#APPLICATION_SCOPE}. |
| * This corresponds to <code>default-session-scope</code> |
| * parameter, with default value <code>portlet</code>. |
| * |
| * @see org.apache.cocoon.environment.portlet.PortletSession |
| */ |
| protected int defaultSessionScope; |
| |
| /** |
| * Store pathInfo in session |
| */ |
| protected boolean storeSessionPath; |
| |
| /** |
| * Allow overriding servletPath by request or preferences. |
| */ |
| private boolean servletPathOverriding = true; |
| |
| /** |
| * Initialize this <code>CocoonPortlet</code> instance. |
| * |
| * <p>Uses the following parameters: |
| * portlet-logger |
| * enable-uploads |
| * autosave-uploads |
| * overwrite-uploads |
| * upload-max-size |
| * show-time |
| * container-encoding |
| * form-encoding |
| * manage-exceptions |
| * servlet-path |
| * |
| * @param conf The PortletConfig object from the portlet container. |
| * @throws PortletException |
| */ |
| public void init(PortletConfig conf) throws PortletException { |
| |
| super.init(conf); |
| |
| String value; |
| |
| this.portletContext = conf.getPortletContext(); |
| this.envPortletContext = new PortletContext(this.portletContext); |
| this.portletContextPath = this.portletContext.getRealPath("/"); |
| |
| // first init the work-directory for the logger. |
| // this is required if we are running inside a war file! |
| final String workDirParam = getInitParameter("work-directory"); |
| if (workDirParam != null) { |
| if (this.portletContextPath == null) { |
| // No context path : consider work-directory as absolute |
| this.workDir = new File(workDirParam); |
| } else { |
| // Context path exists : is work-directory absolute ? |
| File workDirParamFile = new File(workDirParam); |
| if (workDirParamFile.isAbsolute()) { |
| // Yes : keep it as is |
| this.workDir = workDirParamFile; |
| } else { |
| // No : consider it relative to context path |
| this.workDir = new File(portletContextPath, workDirParam); |
| } |
| } |
| } else { |
| // TODO: Check portlet specification |
| this.workDir = (File) this.portletContext.getAttribute("javax.servlet.context.tempdir"); |
| if (this.workDir == null) { |
| this.workDir = new File(this.portletContext.getRealPath("/WEB-INF/work")); |
| } |
| this.workDir = new File(workDir, "cocoon-files"); |
| } |
| this.workDir.mkdirs(); |
| |
| // Init logger |
| initLogger(); |
| |
| String path = this.portletContextPath; |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("getRealPath for /: " + path); |
| } |
| if (path == null) { |
| // Try to figure out the path of the root from that of WEB-INF |
| try { |
| path = this.portletContext.getResource("/WEB-INF").toString(); |
| } catch (MalformedURLException me) { |
| throw new PortletException("Unable to get resource 'WEB-INF'.", me); |
| } |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("getResource for /WEB-INF: " + path); |
| } |
| path = path.substring(0, path.length() - "WEB-INF".length()); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("Path for Root: " + path); |
| } |
| } |
| |
| try { |
| if (path.indexOf(':') > 1) { |
| this.portletContextURL = path; |
| } else { |
| this.portletContextURL = new File(path).toURL().toExternalForm(); |
| } |
| } catch (MalformedURLException me) { |
| // VG: Novell has absolute file names starting with the |
| // volume name which is easily more then one letter. |
| // Examples: sys:/apache/cocoon or sys:\apache\cocoon |
| try { |
| this.portletContextURL = new File(path).toURL().toExternalForm(); |
| } catch (MalformedURLException ignored) { |
| throw new PortletException("Unable to determine portlet context URL.", me); |
| } |
| } |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("URL for Root: " + this.portletContextURL); |
| } |
| |
| final String uploadDirParam = conf.getInitParameter("upload-directory"); |
| if (uploadDirParam != null) { |
| if (this.portletContextPath == null) { |
| this.uploadDir = new File(uploadDirParam); |
| } else { |
| // Context path exists : is upload-directory absolute ? |
| File uploadDirParamFile = new File(uploadDirParam); |
| if (uploadDirParamFile.isAbsolute()) { |
| // Yes : keep it as is |
| this.uploadDir = uploadDirParamFile; |
| } else { |
| // No : consider it relative to context path |
| this.uploadDir = new File(portletContextPath, uploadDirParam); |
| } |
| } |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("Using upload-directory " + this.uploadDir); |
| } |
| } else { |
| this.uploadDir = new File(workDir, "upload-dir" + File.separator); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("upload-directory was not set - defaulting to " + this.uploadDir); |
| } |
| } |
| this.uploadDir.mkdirs(); |
| |
| this.enableUploads = getInitParameterAsBoolean("enable-uploads", ENABLE_UPLOADS); |
| this.autoSaveUploads = getInitParameterAsBoolean("autosave-uploads", SAVE_UPLOADS_TO_DISK); |
| |
| String overwriteParam = getInitParameter("overwrite-uploads", "rename"); |
| // accepted values are deny|allow|rename - rename is default. |
| if ("deny".equalsIgnoreCase(overwriteParam)) { |
| this.allowOverwrite = false; |
| this.silentlyRename = false; |
| } else if ("allow".equalsIgnoreCase(overwriteParam)) { |
| this.allowOverwrite = true; |
| this.silentlyRename = false; // ignored in this case |
| } else { |
| // either rename is specified or unsupported value - default to rename. |
| this.allowOverwrite = false; |
| this.silentlyRename = true; |
| } |
| |
| this.maxUploadSize = getInitParameterAsInteger("upload-max-size", MAX_UPLOAD_SIZE); |
| |
| value = conf.getInitParameter("show-time"); |
| this.showTime = BooleanUtils.toBoolean(value) || (this.hiddenShowTime = "hide".equals(value)); |
| if (value == null) { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("show-time was not set - defaulting to false"); |
| } |
| } |
| |
| this.containerEncoding = getInitParameter("container-encoding", "ISO-8859-1"); |
| this.defaultFormEncoding = getInitParameter("form-encoding", "ISO-8859-1"); |
| |
| this.manageExceptions = getInitParameterAsBoolean("manage-exceptions", true); |
| |
| this.requestFactory = new RequestFactory(this.autoSaveUploads, |
| this.uploadDir, |
| this.allowOverwrite, |
| this.silentlyRename, |
| this.maxUploadSize, |
| this.defaultFormEncoding); |
| |
| this.servletPath = getInitParameter("servlet-path", null); |
| if (this.servletPath != null) { |
| if (this.servletPath.startsWith("/")) { |
| this.servletPath = this.servletPath.substring(1); |
| } |
| if (this.servletPath.endsWith("/")) { |
| this.servletPath = servletPath.substring(0, servletPath.length() - 1); |
| } |
| } |
| |
| final String sessionScopeParam = getInitParameter("default-session-scope", "portlet"); |
| if ("application".equalsIgnoreCase(sessionScopeParam)) { |
| this.defaultSessionScope = javax.portlet.PortletSession.APPLICATION_SCOPE; |
| } else { |
| this.defaultSessionScope = javax.portlet.PortletSession.PORTLET_SCOPE; |
| } |
| |
| this.storeSessionPath = getInitParameterAsBoolean("store-session-path", false); |
| |
| this.servletPathOverriding = getInitParameterAsBoolean("servlet-path-overriding", true); |
| } |
| |
| public void processAction(ActionRequest req, ActionResponse res) |
| throws PortletException, IOException { |
| |
| // remember when we started (used for timing the processing) |
| long start = System.currentTimeMillis(); |
| |
| // add the cocoon header timestamp |
| res.setProperty("X-Cocoon-Version", Constants.VERSION); |
| |
| // get the request (wrapped if contains multipart-form data) |
| ActionRequest request; |
| try { |
| if (this.enableUploads) { |
| request = requestFactory.getServletRequest(req); |
| } else { |
| request = req; |
| } |
| } catch (Exception e) { |
| if (getLogger().isErrorEnabled()) { |
| getLogger().error("Problem with Cocoon portlet", e); |
| } |
| |
| manageException(req, res, null, null, |
| "Problem in creating the Request", null, null, e); |
| return; |
| } |
| |
| // Get the cocoon engine instance |
| Cocoon cocoon = getCocoon(); |
| |
| // Check if cocoon was initialized |
| if (cocoon == null) { |
| manageException(request, res, null, null, |
| "Initialization Problem", |
| null /* "Cocoon was not initialized" */, |
| null /* "Cocoon was not initialized, cannot process request" */, |
| this.exception); |
| return; |
| } |
| |
| // We got it... Process the request |
| String uri = this.servletPath; |
| if (uri == null) { |
| uri = "portlets/" + getPortletConfig().getPortletName(); |
| } |
| |
| // override servlet-path by the request |
| if (servletPathOverriding) { |
| String reqServletPath = (String) request.getAttribute("servlet-path"); |
| |
| if (reqServletPath != null) { |
| uri = reqServletPath; |
| } else { |
| PortletPreferences prefs = request.getPreferences(); |
| |
| if (prefs != null) { |
| uri = prefs.getValue("servlet-path", uri); |
| } |
| } |
| } |
| |
| if (uri.startsWith("/")) { |
| uri = uri.substring(1); |
| } |
| if (uri.endsWith("/")) { |
| uri = uri.substring(0, uri.length() - 1); |
| } |
| |
| String pathInfo = getPathInfo(request); |
| |
| if (pathInfo != null) { |
| uri += pathInfo; |
| } |
| |
| ContextMap ctxMap = null; |
| |
| Environment env; |
| try { |
| if (uri.charAt(0) == '/') { |
| uri = uri.substring(1); |
| } |
| env = getEnvironment(servletPath, pathInfo, uri, request, res); |
| } catch (Exception e) { |
| if (getLogger().isErrorEnabled()) { |
| getLogger().error("Problem with Cocoon portlet", e); |
| } |
| |
| manageException(request, res, null, uri, |
| "Problem in creating the Environment", null, null, e); |
| return; |
| } |
| |
| try { |
| try { |
| // Initialize a fresh log context containing the object model: it |
| // will be used by the CocoonLogFormatter |
| ctxMap = ContextMap.getCurrentContext(); |
| // Add thread name (default content for empty context) |
| String threadName = Thread.currentThread().getName(); |
| ctxMap.set("threadName", threadName); |
| // Add the object model |
| ctxMap.set("objectModel", env.getObjectModel()); |
| // Add a unique request id (threadName + currentTime |
| ctxMap.set("request-id", threadName + System.currentTimeMillis()); |
| |
| if (cocoon.process(env)) { |
| } else { |
| // We reach this when there is nothing in the processing change that matches |
| // the request. For example, no matcher matches. |
| getLogger().fatalError("The Cocoon engine failed to process the request."); |
| manageException(request, res, env, uri, |
| "Request Processing Failed", |
| "Cocoon engine failed in process the request", |
| "The processing engine failed to process the request. This could be due to lack of matching or bugs in the pipeline engine.", |
| null); |
| return; |
| } |
| } catch (ResourceNotFoundException e) { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().warn(e.getMessage(), e); |
| } else if (getLogger().isWarnEnabled()) { |
| getLogger().warn(e.getMessage()); |
| } |
| |
| manageException(request, res, env, uri, |
| "Resource Not Found", |
| "Resource Not Found", |
| "The requested portlet could not be found", |
| e); |
| return; |
| |
| } catch (ConnectionResetException e) { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug(e.getMessage(), e); |
| } else if (getLogger().isWarnEnabled()) { |
| getLogger().warn(e.getMessage()); |
| } |
| |
| } catch (IOException e) { |
| // Tomcat5 wraps SocketException into ClientAbortException which extends IOException. |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug(e.getMessage(), e); |
| } else if (getLogger().isWarnEnabled()) { |
| getLogger().warn(e.getMessage()); |
| } |
| |
| } catch (Exception e) { |
| if (getLogger().isErrorEnabled()) { |
| getLogger().error("Internal Cocoon Problem", e); |
| } |
| |
| manageException(request, res, env, uri, |
| "Internal Server Error", null, null, e); |
| return; |
| } |
| |
| long end = System.currentTimeMillis(); |
| String timeString = processTime(end - start); |
| if (getLogger().isInfoEnabled()) { |
| getLogger().info("'" + uri + "' " + timeString); |
| } |
| res.setProperty("X-Cocoon-Time", timeString); |
| } finally { |
| if (ctxMap != null) { |
| ctxMap.clear(); |
| } |
| |
| try { |
| if (request instanceof MultipartActionRequest) { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("Deleting uploaded file(s)."); |
| } |
| ((MultipartActionRequest) request).cleanup(); |
| } |
| } catch (IOException e) { |
| getLogger().error("Cocoon got an Exception while trying to cleanup the uploaded files.", e); |
| } |
| } |
| } |
| |
| /** |
| * Process the specified <code>RenderRequest</code> producing output |
| * on the specified <code>RenderResponse</code>. |
| */ |
| public void render(RenderRequest req, RenderResponse res) |
| throws PortletException, IOException { |
| |
| // remember when we started (used for timing the processing) |
| long start = System.currentTimeMillis(); |
| |
| // add the cocoon header timestamp |
| res.setProperty("X-Cocoon-Version", Constants.VERSION); |
| |
| // get the request (wrapped if contains multipart-form data) |
| RenderRequest request = req; |
| |
| // Get the cocoon engine instance |
| Cocoon cocoon = getCocoon(); |
| |
| // Check if cocoon was initialized |
| if (cocoon == null) { |
| manageException(request, res, null, null, |
| "Initialization Problem", |
| null /* "Cocoon was not initialized" */, |
| null /* "Cocoon was not initialized, cannot process request" */, |
| this.exception); |
| return; |
| } |
| |
| // We got it... Process the request |
| String uri = this.servletPath; |
| if (servletPath == null) { |
| uri = "portlets/" + getPortletConfig().getPortletName(); |
| } |
| |
| // allow servlet-path override by request or preferences |
| if (servletPathOverriding) { |
| String reqServletPath = (String) request.getAttribute("servlet-path"); |
| |
| if (reqServletPath != null) { |
| uri = reqServletPath; |
| } else { |
| PortletPreferences prefs = request.getPreferences(); |
| |
| if (prefs != null) { |
| uri = prefs.getValue("servlet-path", uri); |
| } |
| } |
| } |
| |
| if (uri.startsWith("/")) { |
| uri = uri.substring(1); |
| } |
| if (uri.endsWith("/")) { |
| uri = uri.substring(0, uri.length() - 1); |
| } |
| |
| String pathInfo = getPathInfo(request); |
| |
| if (pathInfo != null) { |
| uri += pathInfo; |
| } |
| |
| String contentType = null; |
| ContextMap ctxMap = null; |
| |
| Environment env; |
| try { |
| if (uri.charAt(0) == '/') { |
| uri = uri.substring(1); |
| } |
| env = getEnvironment(servletPath, pathInfo, uri, request, res); |
| } catch (Exception e) { |
| if (getLogger().isErrorEnabled()) { |
| getLogger().error("Problem with Cocoon portlet", e); |
| } |
| |
| manageException(request, res, null, uri, |
| "Problem in creating the Environment", null, null, e); |
| return; |
| } |
| |
| try { |
| try { |
| // Initialize a fresh log context containing the object model: it |
| // will be used by the CocoonLogFormatter |
| ctxMap = ContextMap.getCurrentContext(); |
| // Add thread name (default content for empty context) |
| String threadName = Thread.currentThread().getName(); |
| ctxMap.set("threadName", threadName); |
| // Add the object model |
| ctxMap.set("objectModel", env.getObjectModel()); |
| // Add a unique request id (threadName + currentTime |
| ctxMap.set("request-id", threadName + System.currentTimeMillis()); |
| |
| if (cocoon.process(env)) { |
| } else { |
| // We reach this when there is nothing in the processing change that matches |
| // the request. For example, no matcher matches. |
| getLogger().fatalError("The Cocoon engine failed to process the request."); |
| manageException(request, res, env, uri, |
| "Request Processing Failed", |
| "Cocoon engine failed in process the request", |
| "The processing engine failed to process the request. This could be due to lack of matching or bugs in the pipeline engine.", |
| null); |
| return; |
| } |
| } catch (ResourceNotFoundException rse) { |
| if (getLogger().isWarnEnabled()) { |
| getLogger().warn("The resource was not found", rse); |
| } |
| |
| manageException(request, res, env, uri, |
| "Resource Not Found", |
| "Resource Not Found", |
| "The requested portlet could not be found", |
| rse); |
| return; |
| |
| } catch (ConnectionResetException e) { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug(e.getMessage(), e); |
| } else if (getLogger().isWarnEnabled()) { |
| getLogger().warn(e.getMessage()); |
| } |
| |
| } catch (IOException e) { |
| // Tomcat5 wraps SocketException into ClientAbortException which extends IOException. |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug(e.getMessage(), e); |
| } else if (getLogger().isWarnEnabled()) { |
| getLogger().warn(e.getMessage()); |
| } |
| |
| } catch (Exception e) { |
| if (getLogger().isErrorEnabled()) { |
| getLogger().error("Internal Cocoon Problem", e); |
| } |
| |
| manageException(request, res, env, uri, |
| "Internal Server Error", null, null, e); |
| return; |
| } |
| |
| long end = System.currentTimeMillis(); |
| String timeString = processTime(end - start); |
| if (getLogger().isInfoEnabled()) { |
| getLogger().info("'" + uri + "' " + timeString); |
| } |
| res.setProperty("X-Cocoon-Time", timeString); |
| |
| // FIXME: contentType is always null (see line 556) |
| if (contentType != null && contentType.equals("text/html")) { |
| String showTime = request.getParameter(Constants.SHOWTIME_PARAM); |
| boolean show = this.showTime; |
| if (showTime != null) { |
| show = !showTime.equalsIgnoreCase("no"); |
| } |
| if (show) { |
| boolean hide = this.hiddenShowTime; |
| if (showTime != null) { |
| hide = showTime.equalsIgnoreCase("hide"); |
| } |
| PrintStream out = new PrintStream(res.getPortletOutputStream()); |
| out.print((hide) ? "<!-- " : "<p>"); |
| out.print(timeString); |
| out.println((hide) ? " -->" : "</p>\n"); |
| } |
| } |
| } finally { |
| if (ctxMap != null) { |
| ctxMap.clear(); |
| } |
| |
| /* |
| * Portlet Specification 1.0, PLT.12.3.2 Output Stream and Writer Objects: |
| * The termination of the render method of the portlet indicates |
| * that the portlet has satisfied the request and that the output |
| * object is to be closed. |
| * |
| * Portlet container will close the stream, no need to close it here. |
| */ |
| } |
| } |
| |
| private String getPathInfo(PortletRequest request) { |
| PortletSession session = null; |
| |
| String pathInfo = request.getParameter(PortletEnvironment.PARAMETER_PATH_INFO); |
| if (storeSessionPath) { |
| session = request.getPortletSession(true); |
| if (pathInfo == null) { |
| pathInfo = (String)session.getAttribute(PortletEnvironment.PARAMETER_PATH_INFO); |
| } |
| } |
| |
| // Make sure it starts with or equals to '/' |
| if (pathInfo == null) { |
| pathInfo = "/"; |
| } else if (!pathInfo.startsWith("/")) { |
| pathInfo = '/' + pathInfo; |
| } |
| |
| if (storeSessionPath) { |
| session.setAttribute(PortletEnvironment.PARAMETER_PATH_INFO, pathInfo); |
| } |
| return pathInfo; |
| } |
| |
| protected void manageException(ActionRequest req, ActionResponse res, Environment env, |
| String uri, String title, String message, String description, |
| Exception e) |
| throws PortletException { |
| throw new PortletException("Exception in CocoonPortlet", e); |
| } |
| |
| protected void manageException(RenderRequest req, RenderResponse res, Environment env, |
| String uri, String title, String message, String description, |
| Exception e) |
| throws IOException, PortletException { |
| if (this.manageExceptions) { |
| if (env != null) { |
| env.tryResetResponse(); |
| } else { |
| res.reset(); |
| } |
| |
| String type = Notifying.FATAL_NOTIFICATION; |
| HashMap extraDescriptions = null; |
| |
| extraDescriptions = new HashMap(2); |
| extraDescriptions.put(Notifying.EXTRA_REQUESTURI, getPortletConfig().getPortletName()); |
| if (uri != null) { |
| extraDescriptions.put("Request URI", uri); |
| } |
| |
| // Do not show exception stack trace when log level is WARN or above. Show only message. |
| if (!getLogger().isInfoEnabled()) { |
| Throwable t = DefaultNotifyingBuilder.getRootCause(e); |
| if (t != null) extraDescriptions.put(Notifying.EXTRA_CAUSE, t.getMessage()); |
| e = null; |
| } |
| |
| Notifying n = new DefaultNotifyingBuilder().build(this, |
| e, |
| type, |
| title, |
| "Cocoon Portlet", |
| message, |
| description, |
| extraDescriptions); |
| |
| res.setContentType("text/html"); |
| Notifier.notify(n, res.getPortletOutputStream(), "text/html"); |
| } else { |
| res.flushBuffer(); |
| throw new PortletException("Exception in CocoonPortlet", e); |
| } |
| } |
| |
| /** |
| * Create the environment for the request |
| */ |
| protected Environment getEnvironment(String servletPath, |
| String pathInfo, |
| String uri, |
| ActionRequest req, |
| ActionResponse res) |
| throws Exception { |
| PortletEnvironment env; |
| |
| String formEncoding = req.getParameter("cocoon-form-encoding"); |
| if (formEncoding == null) { |
| formEncoding = this.defaultFormEncoding; |
| } |
| env = new PortletEnvironment(servletPath, |
| pathInfo, |
| uri, |
| this.portletContextURL, |
| req, |
| res, |
| this.portletContext, |
| this.envPortletContext, |
| this.containerEncoding, |
| formEncoding, |
| this.defaultSessionScope); |
| env.enableLogging(getLogger()); |
| return env; |
| } |
| |
| /** |
| * Create the environment for the request |
| */ |
| protected Environment getEnvironment(String servletPath, |
| String pathInfo, |
| String uri, |
| RenderRequest req, |
| RenderResponse res) |
| throws Exception { |
| PortletEnvironment env; |
| |
| String formEncoding = req.getParameter("cocoon-form-encoding"); |
| if (formEncoding == null) { |
| formEncoding = this.defaultFormEncoding; |
| } |
| env = new PortletEnvironment(servletPath, |
| pathInfo, |
| uri, |
| this.portletContextURL, |
| req, |
| res, |
| this.portletContext, |
| this.envPortletContext, |
| this.containerEncoding, |
| formEncoding, |
| this.defaultSessionScope); |
| env.enableLogging(getLogger()); |
| return env; |
| } |
| |
| private String processTime(long time) { |
| StringBuffer out = new StringBuffer(PROCESSED_BY); |
| if (time <= SECOND) { |
| out.append(time); |
| out.append(" milliseconds."); |
| } else if (time <= MINUTE) { |
| out.append(time / SECOND); |
| out.append(" seconds."); |
| } else if (time <= HOUR) { |
| out.append(time / MINUTE); |
| out.append(" minutes."); |
| } else { |
| out.append(time / HOUR); |
| out.append(" hours."); |
| } |
| return out.toString(); |
| } |
| |
| /** |
| * Gets the current cocoon object. |
| * Reload cocoon if configuration changed or we are reloading. |
| */ |
| private Cocoon getCocoon() { |
| return new CocoonAccess() { |
| final Cocoon instance() { |
| return super.getCocoon(); |
| } |
| }.instance(); |
| } |
| |
| /** |
| * Get an initialisation parameter. The value is trimmed, and null is returned if the trimmed value |
| * is empty. |
| */ |
| public String getInitParameter(String name) { |
| String result = super.getInitParameter(name); |
| if (result != null) { |
| result = result.trim(); |
| if (result.length() == 0) { |
| result = null; |
| } |
| } |
| |
| return result; |
| } |
| |
| /** Convenience method to access portlet parameters */ |
| protected String getInitParameter(String name, String defaultValue) { |
| String result = getInitParameter(name); |
| if (result == null) { |
| if (getLogger() != null && getLogger().isDebugEnabled()) { |
| getLogger().debug(name + " was not set - defaulting to '" + defaultValue + "'"); |
| } |
| return defaultValue; |
| } else { |
| return result; |
| } |
| } |
| |
| /** Convenience method to access boolean portlet parameters */ |
| protected boolean getInitParameterAsBoolean(String name, boolean defaultValue) { |
| String value = getInitParameter(name); |
| if (value == null) { |
| if (getLogger() != null && getLogger().isDebugEnabled()) { |
| getLogger().debug(name + " was not set - defaulting to '" + defaultValue + "'"); |
| } |
| return defaultValue; |
| } |
| |
| return BooleanUtils.toBoolean(value); |
| } |
| |
| protected int getInitParameterAsInteger(String name, int defaultValue) { |
| String value = getInitParameter(name); |
| if (value == null) { |
| if (getLogger() != null && getLogger().isDebugEnabled()) { |
| getLogger().debug(name + " was not set - defaulting to '" + defaultValue + "'"); |
| } |
| return defaultValue; |
| } else { |
| return Integer.parseInt(value); |
| } |
| } |
| |
| protected void initLogger() { |
| final String accesslogger = getInitParameter("portlet-logger", "cocoon"); |
| |
| final Hierarchy defaultHierarchy = Hierarchy.getDefaultHierarchy(); |
| |
| final Logger logger = new LogKitLogger(Hierarchy.getDefaultHierarchy().getLoggerFor("")); |
| |
| final LogKitLoggerManager logKitLoggerManager = new LogKitLoggerManager(defaultHierarchy); |
| logKitLoggerManager.enableLogging(logger); |
| |
| final DefaultContext subcontext = new DefaultContext(); |
| subcontext.put(Constants.CONTEXT_WORK_DIR, workDir); |
| subcontext.put("portlet-context", this.portletContext); |
| if (this.portletContextPath == null) { |
| File logSCDir = new File(this.workDir, "log"); |
| logSCDir.mkdirs(); |
| if (getLogger().isWarnEnabled()) { |
| getLogger().warn("Setting context-root for LogKit to " + logSCDir); |
| } |
| subcontext.put("context-root", logSCDir.toString()); |
| } else { |
| subcontext.put("context-root", this.portletContextPath); |
| } |
| if ( this.portletContext instanceof PortletContextImpl ) { |
| subcontext.put("servlet-context", ((PortletContextImpl)this.portletContext).getServletContext()); |
| } |
| |
| try { |
| logKitLoggerManager.contextualize(subcontext); |
| |
| //Configure the logkit management |
| String logkitConfig = getInitParameter("logkit-config", "/WEB-INF/logkit.xconf"); |
| |
| // test if this is a qualified url |
| InputStream is = null; |
| if (logkitConfig.indexOf(':') == -1) { |
| is = this.portletContext.getResourceAsStream(logkitConfig); |
| if (is == null) is = new FileInputStream(logkitConfig); |
| } else { |
| URL logkitURL = new URL(logkitConfig); |
| is = logkitURL.openStream(); |
| } |
| final DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); |
| final Configuration conf = builder.build(is); |
| logKitLoggerManager.configure(conf); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| |
| if (accesslogger != null) { |
| this.log = logKitLoggerManager.getLoggerForCategory(accesslogger); |
| } else { |
| this.log = logKitLoggerManager.getLoggerForCategory("cocoon"); |
| } |
| } |
| |
| protected Logger getLogger() { |
| return this.log; |
| } |
| } |