0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: package org.apache.cocoon.portlet;
0018:
0019: import org.apache.avalon.excalibur.logger.LogKitLoggerManager;
0020: import org.apache.avalon.framework.configuration.Configuration;
0021: import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
0022: import org.apache.avalon.framework.context.DefaultContext;
0023: import org.apache.avalon.framework.logger.LogKitLogger;
0024: import org.apache.avalon.framework.logger.Logger;
0025:
0026: import org.apache.cocoon.Cocoon;
0027: import org.apache.cocoon.CocoonAccess;
0028: import org.apache.cocoon.ConnectionResetException;
0029: import org.apache.cocoon.Constants;
0030: import org.apache.cocoon.ResourceNotFoundException;
0031: import org.apache.cocoon.components.notification.DefaultNotifyingBuilder;
0032: import org.apache.cocoon.components.notification.Notifier;
0033: import org.apache.cocoon.components.notification.Notifying;
0034: import org.apache.cocoon.environment.Environment;
0035: import org.apache.cocoon.environment.portlet.PortletContext;
0036: import org.apache.cocoon.environment.portlet.PortletEnvironment;
0037: import org.apache.cocoon.portlet.multipart.MultipartActionRequest;
0038: import org.apache.cocoon.portlet.multipart.RequestFactory;
0039:
0040: import org.apache.commons.lang.BooleanUtils;
0041: import org.apache.log.ContextMap;
0042: import org.apache.log.Hierarchy;
0043: import org.apache.pluto.core.impl.PortletContextImpl;
0044:
0045: import javax.portlet.ActionRequest;
0046: import javax.portlet.ActionResponse;
0047: import javax.portlet.GenericPortlet;
0048: import javax.portlet.PortletConfig;
0049: import javax.portlet.PortletException;
0050: import javax.portlet.PortletSession;
0051: import javax.portlet.RenderRequest;
0052: import javax.portlet.RenderResponse;
0053: import javax.portlet.PortletRequest;
0054: import javax.portlet.PortletPreferences;
0055: import java.io.File;
0056: import java.io.FileInputStream;
0057: import java.io.IOException;
0058: import java.io.InputStream;
0059: import java.io.PrintStream;
0060: import java.net.MalformedURLException;
0061: import java.net.URL;
0062: import java.util.HashMap;
0063:
0064: /**
0065: * This is the entry point for Cocoon execution as an JSR-168 Portlet.
0066: *
0067: * <p>This implementation of the Portlet interface requires that someone will
0068: * first create and initialize an instance of the Cocoon object, and this
0069: * Portlet will use this instance to process requests.</p>
0070: *
0071: * @version CVS $Id: ManagedCocoonPortlet.java 503698 2007-02-05 14:30:30Z cziegeler $
0072: */
0073: public class ManagedCocoonPortlet extends GenericPortlet {
0074:
0075: // Processing time message
0076: protected static final String PROCESSED_BY = "Processed by "
0077: + Constants.COMPLETE_NAME + " in ";
0078:
0079: // Used by "show-time"
0080: static final float SECOND = 1000;
0081: static final float MINUTE = 60 * SECOND;
0082: static final float HOUR = 60 * MINUTE;
0083:
0084: private Logger log;
0085:
0086: /**
0087: * Holds exception happened during initialization (if any)
0088: */
0089: protected Exception exception;
0090:
0091: /**
0092: * Allow adding processing time to the response
0093: */
0094: protected boolean showTime;
0095:
0096: /**
0097: * If true, processing time will be added as an HTML comment
0098: */
0099: protected boolean hiddenShowTime;
0100:
0101: /**
0102: * Default value for {@link #enableUploads} parameter (false)
0103: */
0104: private static final boolean ENABLE_UPLOADS = false;
0105: private static final boolean SAVE_UPLOADS_TO_DISK = true;
0106: private static final int MAX_UPLOAD_SIZE = 10000000; // 10Mb
0107:
0108: /**
0109: * Allow processing of upload requests (mime/multipart)
0110: */
0111: private boolean enableUploads;
0112: private boolean autoSaveUploads;
0113: private boolean allowOverwrite;
0114: private boolean silentlyRename;
0115: private int maxUploadSize;
0116:
0117: private File uploadDir;
0118: private File workDir;
0119:
0120: private String containerEncoding;
0121: private String defaultFormEncoding;
0122:
0123: protected javax.portlet.PortletContext portletContext;
0124: protected PortletContext envPortletContext;
0125:
0126: /**
0127: * If true or not set, this class will try to catch and handle all Cocoon exceptions.
0128: * If false, it will rethrow them to the portlet container.
0129: */
0130: private boolean manageExceptions;
0131:
0132: /**
0133: * This is the path to the portlet context (or the result
0134: * of calling getRealPath('/') on the PortletContext.
0135: * Note, that this can be null.
0136: */
0137: protected String portletContextPath;
0138:
0139: /**
0140: * This is the url to the portlet context directory
0141: */
0142: protected String portletContextURL;
0143:
0144: /**
0145: * The RequestFactory is responsible for wrapping multipart-encoded
0146: * forms and for handing the file payload of incoming requests
0147: */
0148: protected RequestFactory requestFactory;
0149:
0150: /**
0151: * Value to be used as servletPath in the request.
0152: * Provided via configuration parameter, if missing, defaults to the
0153: * '/portlets/' + portletName.
0154: */
0155: protected String servletPath;
0156:
0157: /**
0158: * Default scope for the session attributes, either
0159: * {@link javax.portlet.PortletSession#PORTLET_SCOPE} or
0160: * {@link javax.portlet.PortletSession#APPLICATION_SCOPE}.
0161: * This corresponds to <code>default-session-scope</code>
0162: * parameter, with default value <code>portlet</code>.
0163: *
0164: * @see org.apache.cocoon.environment.portlet.PortletSession
0165: */
0166: protected int defaultSessionScope;
0167:
0168: /**
0169: * Store pathInfo in session
0170: */
0171: protected boolean storeSessionPath;
0172:
0173: /**
0174: * Allow overriding servletPath by request or preferences.
0175: */
0176: private boolean servletPathOverriding = true;
0177:
0178: /**
0179: * Initialize this <code>CocoonPortlet</code> instance.
0180: *
0181: * <p>Uses the following parameters:
0182: * portlet-logger
0183: * enable-uploads
0184: * autosave-uploads
0185: * overwrite-uploads
0186: * upload-max-size
0187: * show-time
0188: * container-encoding
0189: * form-encoding
0190: * manage-exceptions
0191: * servlet-path
0192: *
0193: * @param conf The PortletConfig object from the portlet container.
0194: * @throws PortletException
0195: */
0196: public void init(PortletConfig conf) throws PortletException {
0197:
0198: super .init(conf);
0199:
0200: String value;
0201:
0202: this .portletContext = conf.getPortletContext();
0203: this .envPortletContext = new PortletContext(this .portletContext);
0204: this .portletContextPath = this .portletContext.getRealPath("/");
0205:
0206: // first init the work-directory for the logger.
0207: // this is required if we are running inside a war file!
0208: final String workDirParam = getInitParameter("work-directory");
0209: if (workDirParam != null) {
0210: if (this .portletContextPath == null) {
0211: // No context path : consider work-directory as absolute
0212: this .workDir = new File(workDirParam);
0213: } else {
0214: // Context path exists : is work-directory absolute ?
0215: File workDirParamFile = new File(workDirParam);
0216: if (workDirParamFile.isAbsolute()) {
0217: // Yes : keep it as is
0218: this .workDir = workDirParamFile;
0219: } else {
0220: // No : consider it relative to context path
0221: this .workDir = new File(portletContextPath,
0222: workDirParam);
0223: }
0224: }
0225: } else {
0226: // TODO: Check portlet specification
0227: this .workDir = (File) this .portletContext
0228: .getAttribute("javax.servlet.context.tempdir");
0229: if (this .workDir == null) {
0230: this .workDir = new File(this .portletContext
0231: .getRealPath("/WEB-INF/work"));
0232: }
0233: this .workDir = new File(workDir, "cocoon-files");
0234: }
0235: this .workDir.mkdirs();
0236:
0237: // Init logger
0238: initLogger();
0239:
0240: String path = this .portletContextPath;
0241: if (getLogger().isDebugEnabled()) {
0242: getLogger().debug("getRealPath for /: " + path);
0243: }
0244: if (path == null) {
0245: // Try to figure out the path of the root from that of WEB-INF
0246: try {
0247: path = this .portletContext.getResource("/WEB-INF")
0248: .toString();
0249: } catch (MalformedURLException me) {
0250: throw new PortletException(
0251: "Unable to get resource 'WEB-INF'.", me);
0252: }
0253: if (getLogger().isDebugEnabled()) {
0254: getLogger().debug("getResource for /WEB-INF: " + path);
0255: }
0256: path = path
0257: .substring(0, path.length() - "WEB-INF".length());
0258: if (getLogger().isDebugEnabled()) {
0259: getLogger().debug("Path for Root: " + path);
0260: }
0261: }
0262:
0263: try {
0264: if (path.indexOf(':') > 1) {
0265: this .portletContextURL = path;
0266: } else {
0267: this .portletContextURL = new File(path).toURL()
0268: .toExternalForm();
0269: }
0270: } catch (MalformedURLException me) {
0271: // VG: Novell has absolute file names starting with the
0272: // volume name which is easily more then one letter.
0273: // Examples: sys:/apache/cocoon or sys:\apache\cocoon
0274: try {
0275: this .portletContextURL = new File(path).toURL()
0276: .toExternalForm();
0277: } catch (MalformedURLException ignored) {
0278: throw new PortletException(
0279: "Unable to determine portlet context URL.", me);
0280: }
0281: }
0282: if (getLogger().isDebugEnabled()) {
0283: getLogger()
0284: .debug("URL for Root: " + this .portletContextURL);
0285: }
0286:
0287: final String uploadDirParam = conf
0288: .getInitParameter("upload-directory");
0289: if (uploadDirParam != null) {
0290: if (this .portletContextPath == null) {
0291: this .uploadDir = new File(uploadDirParam);
0292: } else {
0293: // Context path exists : is upload-directory absolute ?
0294: File uploadDirParamFile = new File(uploadDirParam);
0295: if (uploadDirParamFile.isAbsolute()) {
0296: // Yes : keep it as is
0297: this .uploadDir = uploadDirParamFile;
0298: } else {
0299: // No : consider it relative to context path
0300: this .uploadDir = new File(portletContextPath,
0301: uploadDirParam);
0302: }
0303: }
0304: if (getLogger().isDebugEnabled()) {
0305: getLogger().debug(
0306: "Using upload-directory " + this .uploadDir);
0307: }
0308: } else {
0309: this .uploadDir = new File(workDir, "upload-dir"
0310: + File.separator);
0311: if (getLogger().isDebugEnabled()) {
0312: getLogger().debug(
0313: "upload-directory was not set - defaulting to "
0314: + this .uploadDir);
0315: }
0316: }
0317: this .uploadDir.mkdirs();
0318:
0319: this .enableUploads = getInitParameterAsBoolean(
0320: "enable-uploads", ENABLE_UPLOADS);
0321: this .autoSaveUploads = getInitParameterAsBoolean(
0322: "autosave-uploads", SAVE_UPLOADS_TO_DISK);
0323:
0324: String overwriteParam = getInitParameter("overwrite-uploads",
0325: "rename");
0326: // accepted values are deny|allow|rename - rename is default.
0327: if ("deny".equalsIgnoreCase(overwriteParam)) {
0328: this .allowOverwrite = false;
0329: this .silentlyRename = false;
0330: } else if ("allow".equalsIgnoreCase(overwriteParam)) {
0331: this .allowOverwrite = true;
0332: this .silentlyRename = false; // ignored in this case
0333: } else {
0334: // either rename is specified or unsupported value - default to rename.
0335: this .allowOverwrite = false;
0336: this .silentlyRename = true;
0337: }
0338:
0339: this .maxUploadSize = getInitParameterAsInteger(
0340: "upload-max-size", MAX_UPLOAD_SIZE);
0341:
0342: value = conf.getInitParameter("show-time");
0343: this .showTime = BooleanUtils.toBoolean(value)
0344: || (this .hiddenShowTime = "hide".equals(value));
0345: if (value == null) {
0346: if (getLogger().isDebugEnabled()) {
0347: getLogger().debug(
0348: "show-time was not set - defaulting to false");
0349: }
0350: }
0351:
0352: this .containerEncoding = getInitParameter("container-encoding",
0353: "ISO-8859-1");
0354: this .defaultFormEncoding = getInitParameter("form-encoding",
0355: "ISO-8859-1");
0356:
0357: this .manageExceptions = getInitParameterAsBoolean(
0358: "manage-exceptions", true);
0359:
0360: this .requestFactory = new RequestFactory(this .autoSaveUploads,
0361: this .uploadDir, this .allowOverwrite,
0362: this .silentlyRename, this .maxUploadSize,
0363: this .defaultFormEncoding);
0364:
0365: this .servletPath = getInitParameter("servlet-path", null);
0366: if (this .servletPath != null) {
0367: if (this .servletPath.startsWith("/")) {
0368: this .servletPath = this .servletPath.substring(1);
0369: }
0370: if (this .servletPath.endsWith("/")) {
0371: this .servletPath = servletPath.substring(0, servletPath
0372: .length() - 1);
0373: }
0374: }
0375:
0376: final String sessionScopeParam = getInitParameter(
0377: "default-session-scope", "portlet");
0378: if ("application".equalsIgnoreCase(sessionScopeParam)) {
0379: this .defaultSessionScope = javax.portlet.PortletSession.APPLICATION_SCOPE;
0380: } else {
0381: this .defaultSessionScope = javax.portlet.PortletSession.PORTLET_SCOPE;
0382: }
0383:
0384: this .storeSessionPath = getInitParameterAsBoolean(
0385: "store-session-path", false);
0386:
0387: this .servletPathOverriding = getInitParameterAsBoolean(
0388: "servlet-path-overriding", true);
0389: }
0390:
0391: public void processAction(ActionRequest req, ActionResponse res)
0392: throws PortletException, IOException {
0393:
0394: // remember when we started (used for timing the processing)
0395: long start = System.currentTimeMillis();
0396:
0397: // add the cocoon header timestamp
0398: res.setProperty("X-Cocoon-Version", Constants.VERSION);
0399:
0400: // get the request (wrapped if contains multipart-form data)
0401: ActionRequest request;
0402: try {
0403: if (this .enableUploads) {
0404: request = requestFactory.getServletRequest(req);
0405: } else {
0406: request = req;
0407: }
0408: } catch (Exception e) {
0409: if (getLogger().isErrorEnabled()) {
0410: getLogger().error("Problem with Cocoon portlet", e);
0411: }
0412:
0413: manageException(req, res, null, null,
0414: "Problem in creating the Request", null, null, e);
0415: return;
0416: }
0417:
0418: // Get the cocoon engine instance
0419: Cocoon cocoon = getCocoon();
0420:
0421: // Check if cocoon was initialized
0422: if (cocoon == null) {
0423: manageException(
0424: request,
0425: res,
0426: null,
0427: null,
0428: "Initialization Problem",
0429: null /* "Cocoon was not initialized" */,
0430: null /* "Cocoon was not initialized, cannot process request" */,
0431: this .exception);
0432: return;
0433: }
0434:
0435: // We got it... Process the request
0436: String uri = this .servletPath;
0437: if (uri == null) {
0438: uri = "portlets/" + getPortletConfig().getPortletName();
0439: }
0440:
0441: // override servlet-path by the request
0442: if (servletPathOverriding) {
0443: String reqServletPath = (String) request
0444: .getAttribute("servlet-path");
0445:
0446: if (reqServletPath != null) {
0447: uri = reqServletPath;
0448: } else {
0449: PortletPreferences prefs = request.getPreferences();
0450:
0451: if (prefs != null) {
0452: uri = prefs.getValue("servlet-path", uri);
0453: }
0454: }
0455: }
0456:
0457: if (uri.startsWith("/")) {
0458: uri = uri.substring(1);
0459: }
0460: if (uri.endsWith("/")) {
0461: uri = uri.substring(0, uri.length() - 1);
0462: }
0463:
0464: String pathInfo = getPathInfo(request);
0465:
0466: if (pathInfo != null) {
0467: uri += pathInfo;
0468: }
0469:
0470: ContextMap ctxMap = null;
0471:
0472: Environment env;
0473: try {
0474: if (uri.charAt(0) == '/') {
0475: uri = uri.substring(1);
0476: }
0477: env = getEnvironment(servletPath, pathInfo, uri, request,
0478: res);
0479: } catch (Exception e) {
0480: if (getLogger().isErrorEnabled()) {
0481: getLogger().error("Problem with Cocoon portlet", e);
0482: }
0483:
0484: manageException(request, res, null, uri,
0485: "Problem in creating the Environment", null, null,
0486: e);
0487: return;
0488: }
0489:
0490: try {
0491: try {
0492: // Initialize a fresh log context containing the object model: it
0493: // will be used by the CocoonLogFormatter
0494: ctxMap = ContextMap.getCurrentContext();
0495: // Add thread name (default content for empty context)
0496: String threadName = Thread.currentThread().getName();
0497: ctxMap.set("threadName", threadName);
0498: // Add the object model
0499: ctxMap.set("objectModel", env.getObjectModel());
0500: // Add a unique request id (threadName + currentTime
0501: ctxMap.set("request-id", threadName
0502: + System.currentTimeMillis());
0503:
0504: if (cocoon.process(env)) {
0505: } else {
0506: // We reach this when there is nothing in the processing change that matches
0507: // the request. For example, no matcher matches.
0508: getLogger()
0509: .fatalError(
0510: "The Cocoon engine failed to process the request.");
0511: manageException(
0512: request,
0513: res,
0514: env,
0515: uri,
0516: "Request Processing Failed",
0517: "Cocoon engine failed in process the request",
0518: "The processing engine failed to process the request. This could be due to lack of matching or bugs in the pipeline engine.",
0519: null);
0520: return;
0521: }
0522: } catch (ResourceNotFoundException e) {
0523: if (getLogger().isDebugEnabled()) {
0524: getLogger().warn(e.getMessage(), e);
0525: } else if (getLogger().isWarnEnabled()) {
0526: getLogger().warn(e.getMessage());
0527: }
0528:
0529: manageException(request, res, env, uri,
0530: "Resource Not Found", "Resource Not Found",
0531: "The requested portlet could not be found", e);
0532: return;
0533:
0534: } catch (ConnectionResetException e) {
0535: if (getLogger().isDebugEnabled()) {
0536: getLogger().debug(e.getMessage(), e);
0537: } else if (getLogger().isWarnEnabled()) {
0538: getLogger().warn(e.getMessage());
0539: }
0540:
0541: } catch (IOException e) {
0542: // Tomcat5 wraps SocketException into ClientAbortException which extends IOException.
0543: if (getLogger().isDebugEnabled()) {
0544: getLogger().debug(e.getMessage(), e);
0545: } else if (getLogger().isWarnEnabled()) {
0546: getLogger().warn(e.getMessage());
0547: }
0548:
0549: } catch (Exception e) {
0550: if (getLogger().isErrorEnabled()) {
0551: getLogger().error("Internal Cocoon Problem", e);
0552: }
0553:
0554: manageException(request, res, env, uri,
0555: "Internal Server Error", null, null, e);
0556: return;
0557: }
0558:
0559: long end = System.currentTimeMillis();
0560: String timeString = processTime(end - start);
0561: if (getLogger().isInfoEnabled()) {
0562: getLogger().info("'" + uri + "' " + timeString);
0563: }
0564: res.setProperty("X-Cocoon-Time", timeString);
0565: } finally {
0566: if (ctxMap != null) {
0567: ctxMap.clear();
0568: }
0569:
0570: try {
0571: if (request instanceof MultipartActionRequest) {
0572: if (getLogger().isDebugEnabled()) {
0573: getLogger().debug("Deleting uploaded file(s).");
0574: }
0575: ((MultipartActionRequest) request).cleanup();
0576: }
0577: } catch (IOException e) {
0578: getLogger()
0579: .error(
0580: "Cocoon got an Exception while trying to cleanup the uploaded files.",
0581: e);
0582: }
0583: }
0584: }
0585:
0586: /**
0587: * Process the specified <code>RenderRequest</code> producing output
0588: * on the specified <code>RenderResponse</code>.
0589: */
0590: public void render(RenderRequest req, RenderResponse res)
0591: throws PortletException, IOException {
0592:
0593: // remember when we started (used for timing the processing)
0594: long start = System.currentTimeMillis();
0595:
0596: // add the cocoon header timestamp
0597: res.setProperty("X-Cocoon-Version", Constants.VERSION);
0598:
0599: // get the request (wrapped if contains multipart-form data)
0600: RenderRequest request = req;
0601:
0602: // Get the cocoon engine instance
0603: Cocoon cocoon = getCocoon();
0604:
0605: // Check if cocoon was initialized
0606: if (cocoon == null) {
0607: manageException(
0608: request,
0609: res,
0610: null,
0611: null,
0612: "Initialization Problem",
0613: null /* "Cocoon was not initialized" */,
0614: null /* "Cocoon was not initialized, cannot process request" */,
0615: this .exception);
0616: return;
0617: }
0618:
0619: // We got it... Process the request
0620: String uri = this .servletPath;
0621: if (servletPath == null) {
0622: uri = "portlets/" + getPortletConfig().getPortletName();
0623: }
0624:
0625: // allow servlet-path override by request or preferences
0626: if (servletPathOverriding) {
0627: String reqServletPath = (String) request
0628: .getAttribute("servlet-path");
0629:
0630: if (reqServletPath != null) {
0631: uri = reqServletPath;
0632: } else {
0633: PortletPreferences prefs = request.getPreferences();
0634:
0635: if (prefs != null) {
0636: uri = prefs.getValue("servlet-path", uri);
0637: }
0638: }
0639: }
0640:
0641: if (uri.startsWith("/")) {
0642: uri = uri.substring(1);
0643: }
0644: if (uri.endsWith("/")) {
0645: uri = uri.substring(0, uri.length() - 1);
0646: }
0647:
0648: String pathInfo = getPathInfo(request);
0649:
0650: if (pathInfo != null) {
0651: uri += pathInfo;
0652: }
0653:
0654: String contentType = null;
0655: ContextMap ctxMap = null;
0656:
0657: Environment env;
0658: try {
0659: if (uri.charAt(0) == '/') {
0660: uri = uri.substring(1);
0661: }
0662: env = getEnvironment(servletPath, pathInfo, uri, request,
0663: res);
0664: } catch (Exception e) {
0665: if (getLogger().isErrorEnabled()) {
0666: getLogger().error("Problem with Cocoon portlet", e);
0667: }
0668:
0669: manageException(request, res, null, uri,
0670: "Problem in creating the Environment", null, null,
0671: e);
0672: return;
0673: }
0674:
0675: try {
0676: try {
0677: // Initialize a fresh log context containing the object model: it
0678: // will be used by the CocoonLogFormatter
0679: ctxMap = ContextMap.getCurrentContext();
0680: // Add thread name (default content for empty context)
0681: String threadName = Thread.currentThread().getName();
0682: ctxMap.set("threadName", threadName);
0683: // Add the object model
0684: ctxMap.set("objectModel", env.getObjectModel());
0685: // Add a unique request id (threadName + currentTime
0686: ctxMap.set("request-id", threadName
0687: + System.currentTimeMillis());
0688:
0689: if (cocoon.process(env)) {
0690: } else {
0691: // We reach this when there is nothing in the processing change that matches
0692: // the request. For example, no matcher matches.
0693: getLogger()
0694: .fatalError(
0695: "The Cocoon engine failed to process the request.");
0696: manageException(
0697: request,
0698: res,
0699: env,
0700: uri,
0701: "Request Processing Failed",
0702: "Cocoon engine failed in process the request",
0703: "The processing engine failed to process the request. This could be due to lack of matching or bugs in the pipeline engine.",
0704: null);
0705: return;
0706: }
0707: } catch (ResourceNotFoundException rse) {
0708: if (getLogger().isWarnEnabled()) {
0709: getLogger().warn("The resource was not found", rse);
0710: }
0711:
0712: manageException(request, res, env, uri,
0713: "Resource Not Found", "Resource Not Found",
0714: "The requested portlet could not be found", rse);
0715: return;
0716:
0717: } catch (ConnectionResetException e) {
0718: if (getLogger().isDebugEnabled()) {
0719: getLogger().debug(e.getMessage(), e);
0720: } else if (getLogger().isWarnEnabled()) {
0721: getLogger().warn(e.getMessage());
0722: }
0723:
0724: } catch (IOException e) {
0725: // Tomcat5 wraps SocketException into ClientAbortException which extends IOException.
0726: if (getLogger().isDebugEnabled()) {
0727: getLogger().debug(e.getMessage(), e);
0728: } else if (getLogger().isWarnEnabled()) {
0729: getLogger().warn(e.getMessage());
0730: }
0731:
0732: } catch (Exception e) {
0733: if (getLogger().isErrorEnabled()) {
0734: getLogger().error("Internal Cocoon Problem", e);
0735: }
0736:
0737: manageException(request, res, env, uri,
0738: "Internal Server Error", null, null, e);
0739: return;
0740: }
0741:
0742: long end = System.currentTimeMillis();
0743: String timeString = processTime(end - start);
0744: if (getLogger().isInfoEnabled()) {
0745: getLogger().info("'" + uri + "' " + timeString);
0746: }
0747: res.setProperty("X-Cocoon-Time", timeString);
0748:
0749: // FIXME: contentType is always null (see line 556)
0750: if (contentType != null && contentType.equals("text/html")) {
0751: String showTime = request
0752: .getParameter(Constants.SHOWTIME_PARAM);
0753: boolean show = this .showTime;
0754: if (showTime != null) {
0755: show = !showTime.equalsIgnoreCase("no");
0756: }
0757: if (show) {
0758: boolean hide = this .hiddenShowTime;
0759: if (showTime != null) {
0760: hide = showTime.equalsIgnoreCase("hide");
0761: }
0762: PrintStream out = new PrintStream(res
0763: .getPortletOutputStream());
0764: out.print((hide) ? "<!-- " : "<p>");
0765: out.print(timeString);
0766: out.println((hide) ? " -->" : "</p>\n");
0767: }
0768: }
0769: } finally {
0770: if (ctxMap != null) {
0771: ctxMap.clear();
0772: }
0773:
0774: /*
0775: * Portlet Specification 1.0, PLT.12.3.2 Output Stream and Writer Objects:
0776: * The termination of the render method of the portlet indicates
0777: * that the portlet has satisfied the request and that the output
0778: * object is to be closed.
0779: *
0780: * Portlet container will close the stream, no need to close it here.
0781: */
0782: }
0783: }
0784:
0785: private String getPathInfo(PortletRequest request) {
0786: PortletSession session = null;
0787:
0788: String pathInfo = request
0789: .getParameter(PortletEnvironment.PARAMETER_PATH_INFO);
0790: if (storeSessionPath) {
0791: session = request.getPortletSession(true);
0792: if (pathInfo == null) {
0793: pathInfo = (String) session
0794: .getAttribute(PortletEnvironment.PARAMETER_PATH_INFO);
0795: }
0796: }
0797:
0798: // Make sure it starts with or equals to '/'
0799: if (pathInfo == null) {
0800: pathInfo = "/";
0801: } else if (!pathInfo.startsWith("/")) {
0802: pathInfo = '/' + pathInfo;
0803: }
0804:
0805: if (storeSessionPath) {
0806: session.setAttribute(
0807: PortletEnvironment.PARAMETER_PATH_INFO, pathInfo);
0808: }
0809: return pathInfo;
0810: }
0811:
0812: protected void manageException(ActionRequest req,
0813: ActionResponse res, Environment env, String uri,
0814: String title, String message, String description,
0815: Exception e) throws PortletException {
0816: throw new PortletException("Exception in CocoonPortlet", e);
0817: }
0818:
0819: protected void manageException(RenderRequest req,
0820: RenderResponse res, Environment env, String uri,
0821: String title, String message, String description,
0822: Exception e) throws IOException, PortletException {
0823: if (this .manageExceptions) {
0824: if (env != null) {
0825: env.tryResetResponse();
0826: } else {
0827: res.reset();
0828: }
0829:
0830: String type = Notifying.FATAL_NOTIFICATION;
0831: HashMap extraDescriptions = null;
0832:
0833: extraDescriptions = new HashMap(2);
0834: extraDescriptions.put(Notifying.EXTRA_REQUESTURI,
0835: getPortletConfig().getPortletName());
0836: if (uri != null) {
0837: extraDescriptions.put("Request URI", uri);
0838: }
0839:
0840: // Do not show exception stack trace when log level is WARN or above. Show only message.
0841: if (!getLogger().isInfoEnabled()) {
0842: Throwable t = DefaultNotifyingBuilder.getRootCause(e);
0843: if (t != null)
0844: extraDescriptions.put(Notifying.EXTRA_CAUSE, t
0845: .getMessage());
0846: e = null;
0847: }
0848:
0849: Notifying n = new DefaultNotifyingBuilder().build(this , e,
0850: type, title, "Cocoon Portlet", message,
0851: description, extraDescriptions);
0852:
0853: res.setContentType("text/html");
0854: Notifier.notify(n, res.getPortletOutputStream(),
0855: "text/html");
0856: } else {
0857: res.flushBuffer();
0858: throw new PortletException("Exception in CocoonPortlet", e);
0859: }
0860: }
0861:
0862: /**
0863: * Create the environment for the request
0864: */
0865: protected Environment getEnvironment(String servletPath,
0866: String pathInfo, String uri, ActionRequest req,
0867: ActionResponse res) throws Exception {
0868: PortletEnvironment env;
0869:
0870: String formEncoding = req.getParameter("cocoon-form-encoding");
0871: if (formEncoding == null) {
0872: formEncoding = this .defaultFormEncoding;
0873: }
0874: env = new PortletEnvironment(servletPath, pathInfo, uri,
0875: this .portletContextURL, req, res, this .portletContext,
0876: this .envPortletContext, this .containerEncoding,
0877: formEncoding, this .defaultSessionScope);
0878: env.enableLogging(getLogger());
0879: return env;
0880: }
0881:
0882: /**
0883: * Create the environment for the request
0884: */
0885: protected Environment getEnvironment(String servletPath,
0886: String pathInfo, String uri, RenderRequest req,
0887: RenderResponse res) throws Exception {
0888: PortletEnvironment env;
0889:
0890: String formEncoding = req.getParameter("cocoon-form-encoding");
0891: if (formEncoding == null) {
0892: formEncoding = this .defaultFormEncoding;
0893: }
0894: env = new PortletEnvironment(servletPath, pathInfo, uri,
0895: this .portletContextURL, req, res, this .portletContext,
0896: this .envPortletContext, this .containerEncoding,
0897: formEncoding, this .defaultSessionScope);
0898: env.enableLogging(getLogger());
0899: return env;
0900: }
0901:
0902: private String processTime(long time) {
0903: StringBuffer out = new StringBuffer(PROCESSED_BY);
0904: if (time <= SECOND) {
0905: out.append(time);
0906: out.append(" milliseconds.");
0907: } else if (time <= MINUTE) {
0908: out.append(time / SECOND);
0909: out.append(" seconds.");
0910: } else if (time <= HOUR) {
0911: out.append(time / MINUTE);
0912: out.append(" minutes.");
0913: } else {
0914: out.append(time / HOUR);
0915: out.append(" hours.");
0916: }
0917: return out.toString();
0918: }
0919:
0920: /**
0921: * Gets the current cocoon object.
0922: * Reload cocoon if configuration changed or we are reloading.
0923: */
0924: private Cocoon getCocoon() {
0925: return new CocoonAccess() {
0926: final Cocoon instance() {
0927: return super .getCocoon();
0928: }
0929: }.instance();
0930: }
0931:
0932: /**
0933: * Get an initialisation parameter. The value is trimmed, and null is returned if the trimmed value
0934: * is empty.
0935: */
0936: public String getInitParameter(String name) {
0937: String result = super .getInitParameter(name);
0938: if (result != null) {
0939: result = result.trim();
0940: if (result.length() == 0) {
0941: result = null;
0942: }
0943: }
0944:
0945: return result;
0946: }
0947:
0948: /** Convenience method to access portlet parameters */
0949: protected String getInitParameter(String name, String defaultValue) {
0950: String result = getInitParameter(name);
0951: if (result == null) {
0952: if (getLogger() != null && getLogger().isDebugEnabled()) {
0953: getLogger().debug(
0954: name + " was not set - defaulting to '"
0955: + defaultValue + "'");
0956: }
0957: return defaultValue;
0958: } else {
0959: return result;
0960: }
0961: }
0962:
0963: /** Convenience method to access boolean portlet parameters */
0964: protected boolean getInitParameterAsBoolean(String name,
0965: boolean defaultValue) {
0966: String value = getInitParameter(name);
0967: if (value == null) {
0968: if (getLogger() != null && getLogger().isDebugEnabled()) {
0969: getLogger().debug(
0970: name + " was not set - defaulting to '"
0971: + defaultValue + "'");
0972: }
0973: return defaultValue;
0974: }
0975:
0976: return BooleanUtils.toBoolean(value);
0977: }
0978:
0979: protected int getInitParameterAsInteger(String name,
0980: int defaultValue) {
0981: String value = getInitParameter(name);
0982: if (value == null) {
0983: if (getLogger() != null && getLogger().isDebugEnabled()) {
0984: getLogger().debug(
0985: name + " was not set - defaulting to '"
0986: + defaultValue + "'");
0987: }
0988: return defaultValue;
0989: } else {
0990: return Integer.parseInt(value);
0991: }
0992: }
0993:
0994: protected void initLogger() {
0995: final String accesslogger = getInitParameter("portlet-logger",
0996: "cocoon");
0997:
0998: final Hierarchy defaultHierarchy = Hierarchy
0999: .getDefaultHierarchy();
1000:
1001: final Logger logger = new LogKitLogger(Hierarchy
1002: .getDefaultHierarchy().getLoggerFor(""));
1003:
1004: final LogKitLoggerManager logKitLoggerManager = new LogKitLoggerManager(
1005: defaultHierarchy);
1006: logKitLoggerManager.enableLogging(logger);
1007:
1008: final DefaultContext subcontext = new DefaultContext();
1009: subcontext.put(Constants.CONTEXT_WORK_DIR, workDir);
1010: subcontext.put("portlet-context", this .portletContext);
1011: if (this .portletContextPath == null) {
1012: File logSCDir = new File(this .workDir, "log");
1013: logSCDir.mkdirs();
1014: if (getLogger().isWarnEnabled()) {
1015: getLogger().warn(
1016: "Setting context-root for LogKit to "
1017: + logSCDir);
1018: }
1019: subcontext.put("context-root", logSCDir.toString());
1020: } else {
1021: subcontext.put("context-root", this .portletContextPath);
1022: }
1023: if (this .portletContext instanceof PortletContextImpl) {
1024: subcontext.put("servlet-context",
1025: ((PortletContextImpl) this .portletContext)
1026: .getServletContext());
1027: }
1028:
1029: try {
1030: logKitLoggerManager.contextualize(subcontext);
1031:
1032: //Configure the logkit management
1033: String logkitConfig = getInitParameter("logkit-config",
1034: "/WEB-INF/logkit.xconf");
1035:
1036: // test if this is a qualified url
1037: InputStream is = null;
1038: if (logkitConfig.indexOf(':') == -1) {
1039: is = this .portletContext
1040: .getResourceAsStream(logkitConfig);
1041: if (is == null)
1042: is = new FileInputStream(logkitConfig);
1043: } else {
1044: URL logkitURL = new URL(logkitConfig);
1045: is = logkitURL.openStream();
1046: }
1047: final DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
1048: final Configuration conf = builder.build(is);
1049: logKitLoggerManager.configure(conf);
1050: } catch (Exception e) {
1051: e.printStackTrace();
1052: }
1053:
1054: if (accesslogger != null) {
1055: this .log = logKitLoggerManager
1056: .getLoggerForCategory(accesslogger);
1057: } else {
1058: this .log = logKitLoggerManager
1059: .getLoggerForCategory("cocoon");
1060: }
1061: }
1062:
1063: protected Logger getLogger() {
1064: return this.log;
1065: }
1066: }
|