/*
* Copyright 2001 Sun Microsystems, Inc. All rights reserved.
* PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
*/
package com.sun.portal.desktop;
import com.sun.portal.desktop.context.ContextError;
import com.sun.portal.desktop.context.DesktopAppContext;
import com.sun.portal.desktop.context.DesktopContext;
import com.sun.portal.desktop.context.DesktopContextFactory;
import com.sun.portal.desktop.context.DesktopContextThreadLocalizer;
import com.sun.portal.desktop.context.PSDesktopContextFactoryManager;
import com.sun.portal.desktop.context.PropertiesConfigContext;
import com.sun.portal.desktop.dp.DPHelper;
import com.sun.portal.desktop.dp.FQCN;
import com.sun.portal.desktop.monitoring.DesktopRequestStatistic;
import com.sun.portal.desktop.monitoring.MonitoringSubsystem;
import com.sun.portal.desktop.monitoring.MonitoringSubsystemWrapper;
import com.sun.portal.desktop.ubt.DesktopEvents;
import com.sun.portal.desktop.ubt.ProviderLogRecord;
import com.sun.portal.desktop.util.I18n;
import com.sun.portal.log.common.PortalLogger;
import com.sun.portal.monitoring.MonitoringException;
import com.sun.portal.monitoring.utilities.ActivityTime;
import com.sun.portal.providers.InvalidEditFormDataException;
import com.sun.portal.providers.Provider;
import com.sun.portal.providers.ProviderEditTypes;
import com.sun.portal.providers.containers.jsp.tab.JSPTabContainerProvider;
import com.sun.portal.providers.error.ErrorProvider;
import com.sun.portal.providers.util.ProviderProperties;
import com.sun.portal.ubt.UBTEvent;
import com.sun.portal.ubt.UBTLogField;
import com.sun.portal.ubt.UBTLogManager;
import com.sun.portal.desktop.context.DSAMEMultiPortalConstants;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
/**
* The Desktop Servlet is a router of request. It catches request for content
* and processing and passes them on to the specific provider object.
* <p/>
* Desktop Servlet understands several actions. Every action has an associated
* channel name to perform the action on. Actions understood by the Desktop
* servlet are:
* <ul>
* <li>content - get the named channel's main content
* <li>edit - get the named channel's edit content
* <li>process - allow the named channel to process form data
* <li>logout - end the user session
* </ul>
* <p/>
* Actions are passed to the servlet via GET or POST parameters. The
* associated channel name is also passed as a parameter. For example,
* to perform the <i>content</i> action on the channel name <i>foo</i>,
* pass in the following parameters to the servlet:<br><br>
* <code>[url to servlet]?action=content&provider=foo</code><br><br>
* <p/>
* The content, edit, and process actions map directly to method calls into
* the Provider API (PAPI). For example, for an action equal to <i>process</i>
* and a channel name equal to <i>foo</i>, the Desktop servlet will
* get a handle to the provider object associated with the channel name <i>foo</i>,
* and call the <i>Provider.processEdit()</i> method.<br><br>
* <p/>
* For such desktop actions that map to PAPI method calls,
* the servlet passes an HTTP request and response object to the respective
* Provider method. These objects are not the same objects passed into
* the servlet. The request and response objects passed to provider
* objects from the servlet
* are wrappers around the original request and response
* passed into the servlet. This is because there is certain functionality
* that is available from request and response objects that is not
* applicable to a provider. See the Javadocs for the class
* <code>Provider</code> for more
* information.<br><br>
* <p/>
* The HTTP parameters in the original request object are processed
* before they are copied to the "wrapper" servlet request and response
* objects.
* As part of this processing, the parameters
* are decoded from the character set encoding used to represent the page
* into Unicode that is used in Java String objects. Therefore, the
* parameters that are passed to the providers are all
* stored as Unicode, and the provider does not have to do any decoding of
* its own related to the character encoding for the page.However, the Unicode
* Strings passed into a query string have to be encoded by the
* provider using <i>ProviderContext.encodeURLParameter()</i> method.<br><br>
* <p/>
* The servlet also keeps track of the last top-level container/channel that is
* accessed. It does it as following: <br>
* If the "provider" parameter is absent in the request, the servlet assumes it
* is equal to the value of the last request where the "action" parameter's
* value was "content". If there is no such last request, then a default
* channel is assumed. Specifying the parameter "action=content" causes the
* servlet to set the last accessed channel name to the value of the "provider"
* parameter. This can be overriden by additionally specifying the parameter
* "last" in the request. When set to false, the servlet will not set the last
* channel to the value of the "provider" parameter. If not specified, the
* default setting is "last=true", and the last accessed channel is set to the
* value of the "provider" parameter. Note: This only applies when the "action"
* parameter is equal to "content"; the last accessed channel is only set when
* the "action" parameter is equal to "content". <br><br>
* <p/>
* Various scenarios: <br><br>
* <ol>
* <li> <desktopURL> (= <desktopURL>?provider=<default channel>) <br>
* <p/>
* No last accessed channel set. The "provider" parameter is assumed to be
* the default channel. The last accessed channel is set to the name of the
* default channel. <br>
* <p/>
* <li> <desktopURL> (= <desktopURL>?provider=<last acccessed channel>) <br>
* <p/>
* The "provider" parameter is absent, so it is assumed to be the value of the
* last accecssed channel set in step #1.
* <p/>
* <li> <desktopURL>?action=content&provider=foo <br>
* <p/>
* The last accessed channel is set to <i>foo</i>.
* <p/>
* <li> <desktopURL> <br>
* <p/>
* The "provider" parameter is absent, so it is assumed to be the value of the
* last accessed channel set in step #3 (<i>foo</i>). <br>
* <p/>
* <li> <desktopURL>?action=edit&provider=bar <br>
* <p/>
* Last accessed channel is NOT set to <i>bar</i>, since the "action" was "edit".
* <br>
* <p/>
* <li> <desktopURL>?action=process OR <desktopURL>?action=edit <br>
* <p/>
* Invalid, must specify a "provider" parameter. Default or last accessed
* channel is not assumed when "action" equals "edit" or "process".
* <br><br>
* </ol>
* This class also creates a single instance of error provider object, that is
* used by all the providers.
* Whenever a provider throws an exception it is populated all the way up to
* the DesktopServlet which in turn invokes the error provider which displays
* a generic error template. The stack trace can also be viewed by looking at
* the source of the error template (it is defined as a markup but commented
* out so that it does not appear on the browser).<br><br>
*
* @see com.sun.portal.providers.Provider
*/
public class DesktopServlet extends HttpServlet implements ProviderEditTypes {
private static Provider errorProvider = new ErrorProvider();
private static DesktopAppContext appContext = null;
private static DesktopContextFactory dcFactory = null;
private static final String LIBERTY_SSO_FAILED_QUERY_PARAM = "libertySSOFailed";
private static Logger logger = PortalLogger.getLogger(DesktopServlet.class);
private LogRecord getLogRecord(Level level, String message, Object[] parameters, Throwable t) {
LogRecord result = new LogRecord(level, message);
result.setLoggerName(logger.getName());
result.setParameters(parameters);
result.setThrown(t);
return result;
}
private static void printSystemProperties() {
Properties envProps = System.getProperties();
if (logger.isLoggable(Level.CONFIG)) {
logger.log(Level.CONFIG, "PSDT_CSPD0002");
for (Enumeration e = envProps.propertyNames(); e.hasMoreElements();) {
String prop = (String) e.nextElement();
// no localized key here as the entire message is coming
// from environment
logger.log(Level.CONFIG, prop + " : " + envProps.getProperty(prop));
}
logger.log(Level.CONFIG, "PSDT_CSPD0003");
}
}
protected static DesktopContextFactory getDesktopContextFactory(ServletConfig sc) {
if (dcFactory == null) {
dcFactory = PSDesktopContextFactoryManager.getFactory(sc.getServletContext());
}
return dcFactory;
}
private void printConfigAttributes() {
printConfigAttributes(getServletConfig().getServletContext());
}
public static void printConfigAttributes(ServletContext sc) {
if (logger.isLoggable(Level.CONFIG)) {
logger.log(Level.CONFIG, "PSDT_CSPD0004");
for (Enumeration e = sc.getAttributeNames(); e.hasMoreElements();) {
String name = (String) e.nextElement();
Object val = sc.getAttribute(name);
logger.log(Level.CONFIG, name + "=" + val);
}
logger.log(Level.CONFIG, "PSDT_CSPD0005");
}
}
private void printInitParameters() {
if (logger.isLoggable(Level.CONFIG)) {
logger.log(Level.CONFIG, "PSDT_CSPD0006");
for (Enumeration e = getServletConfig().getInitParameterNames();
e.hasMoreElements();) {
String name = (String) e.nextElement();
String val = getServletConfig().getInitParameter(name);
logger.log(Level.CONFIG, name + "=" + val);
}
logger.log(Level.CONFIG, "PSDT_CSPD0007");
}
}
private String urlencode(String s) {
try {
return URLEncoder.encode(s, "UTF-8");
} catch (Exception wonthappen) {}
return s;
}
public void init(ServletConfig config)
throws ServletException {
super.init(config);
getDesktopContextFactory(config);
appContext = dcFactory.getDesktopAppContext();
UBTLogManager.getInstance();
}
public void destroy() {
synchronized (MonitoringSubsystemWrapper.class) {
if (MonitoringSubsystemWrapper.gearedUp()) {
try {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().destroy();
MonitoringSubsystemWrapper.setDesktopMonitoringSubsystem(null);
} catch (MonitoringException e) {
if (logger.isLoggable(Level.SEVERE)) {
logger.log(getLogRecord(Level.SEVERE, "PSDT_CSPD0026", new Object[] {e.getLocalizedMessage()}, e));
}
}
}
}
}
private void setUBTSesID(HttpServletRequest req) {
HttpSession sess = req.getSession(false);
sess = (sess != null) ? sess : req.getSession(true);
req.setAttribute(UBTLogManager.UBT_SESSION_ID_ATTRIBUTE, sess.getId());
}
private void handleFederation(boolean authlessEnabled, HttpServletRequest req, HttpServletResponse res, DesktopRequest dreq,
DesktopResponse dres, Writer out, String clientType, String contentType, String charset)
throws DesktopException, IOException, ServletException
{
/*
* Check for the query param libertySSOFailed=true. If this is
* true, then it means that the liberty route has been
* traversed once and no need to invoke preLogin again.
* If this param is not found, then this is a fresh request, and
* since the federation is enabled, preLogin should do the work.
*/
String libSSOFailedParam = dreq.getParameter(LIBERTY_SSO_FAILED_QUERY_PARAM);
if ("true".equalsIgnoreCase(libSSOFailedParam)) {
if (authlessEnabled && appContext.validateAuthlessSession(dreq)) {
doGetPost(req, res);
} else {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_LOCALAUTH);
showLocalAuth(req, res, dreq, out, clientType, contentType, charset);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_LOCALAUTH);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getDesktopRequestStatistic().measure(DesktopRequestStatistic.DESKTOP_REQUEST_LOCALAUTH);
}
} else {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_PRELOGIN);
invokePreLogin(req, res, dreq, out, clientType, contentType, charset);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_PRELOGIN);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getDesktopRequestStatistic().measure(DesktopRequestStatistic.DESKTOP_REQUEST_PRELOGIN);
}
}
private void handleNoSessionRequest(boolean authlessEnabled, boolean federationEnabled, HttpServletRequest req,
HttpServletResponse res, DesktopRequest dreq, DesktopResponse dres, Writer out,
String clientType, String contentType, String charset)
throws DesktopException, IOException, ServletException
{
// Currently, only authenticated users can access a community
// because most cty features do not support authless (yet)
String community = req.getParameter(DesktopParameters.COMMUNITY_ACCESS);
boolean communityrequest = community != null && community.length() > 0;
if (!federationEnabled && authlessEnabled) {
if (!communityrequest && appContext.validateAuthlessSession(dreq)) {
doGetPost(req, res); //show authless desktop
} else {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_LOCALAUTH);
showLocalAuth(req, res, dreq, out, clientType, contentType, charset);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_LOCALAUTH);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getDesktopRequestStatistic().measure(DesktopRequestStatistic.DESKTOP_REQUEST_LOCALAUTH);
}
} else if (federationEnabled) {
handleFederation(authlessEnabled && !communityrequest, req, res, dreq, dres, out, clientType, contentType, charset);
} else {
//neither federation nor authless enabled
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_LOCALAUTH);
showLocalAuth(req, res, dreq, out, clientType, contentType, charset);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_LOCALAUTH);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getDesktopRequestStatistic().measure(DesktopRequestStatistic.DESKTOP_REQUEST_LOCALAUTH);
}
}
/**
* handle community access
* - set default community provider type if not specified
* - go to the named community, or to the community home page if community is ""
* - redirect to login page if user is not logged in and is trying to access a named community
*/
public void handleCommunity(HttpServletRequest request, HttpServletResponse response)
throws DesktopException, IOException, ServletException
{
String defaultCommunityType = "jdo";
DesktopContext dc = getDesktopContext(request);
String communityName = request.getParameter(DesktopParameters.COMMUNITY_ACCESS);
boolean namedCommunity = communityName != null && communityName.length() > 0;
// set the default community type if not specified
DesktopRequest dreq = (DesktopRequest)request;
String communityId = null;
if (namedCommunity) {
if (communityName.indexOf("__") == -1) {
communityId = defaultCommunityType + "__" + communityName;
dreq.setDesktopParameter(DesktopParameters.COMMUNITY_ACCESS, communityId);
} else {
communityId = communityName;
communityName = communityName.substring(communityName.indexOf("__") + 2);
}
}
// insert desktop parameters to select the community container and to make it visible
DSAMEMultiPortalConstants dmpc = DSAMEMultiPortalConstants.getInstance();
String communityParentContainerArg = dc.getStringAttribute(dmpc.MP_ATTR_COMMUNITY_PARENT_CONTAINER_URL_PARAMETER);
String communityContainer;
if (namedCommunity) {
communityContainer = communityId + "_Container";
} else {
communityContainer = dc.getStringAttribute(dmpc.MP_ATTR_COMMUNITY_HOME_CONTAINER_NAME);
}
String urlargs = communityParentContainerArg + "=" + communityContainer;
// there might be several visibility args - add all of them to the request
String[] argarray = urlargs.split("&");
for (int i = 0; i < argarray.length; ++i) {
String[] nameval = argarray[i].split("=");
dreq.setDesktopParameter(nameval[0], nameval[1]); // these names and values should not need url decoding...
}
return;
}
/**
* Overriden to check for valid session.
*/
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
String charset = I18n.DEFAULT_CHARSET;
String contentType = null;
Writer out = null;
try {
if (appContext == null) {
if (logger.isLoggable(Level.SEVERE)) {
logger.log(Level.SEVERE, "PSDT_CSPD0008", "DesktopServlet.service()");
}
throw new DesktopException("DesktopServlet.service(): app context was null");
}
/*
* parse and make parameters available to doGet/Post() methods. they should be
* responsible for calling decodeParams() (with the charset) before they use
*/
DesktopRequest dreq = new DesktopRequest(req, appContext, false);
DesktopResponse dres = new DesktopResponse(res);
DesktopThreadLocalManager.init(appContext, dreq, dres, req, res, getServletConfig(), getServletConfig().getServletContext());
if (!MonitoringSubsystemWrapper.gearedUp()) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem(appContext.getDesktopURL(req)).startDesktopServiceAccessURITransaction();
} else {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startDesktopServiceAccessURITransaction();
}
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getDesktopRequestStatistic().mark();
setUBTSesID(req);
String clientType = appContext.getClientType(req);
contentType = appContext.getContentType(clientType);
String action = req.getParameter("action");
if ((action != null) && action.equalsIgnoreCase("logout")) {
doGetPost(req, res);
return;
}
boolean authlessEnabled = appContext.isAuthlessEnabled();
boolean federationEnabled = appContext.isFederationEnabled();
boolean isValidSession = false;
try {
isValidSession = appContext.validateSession(dreq);
} catch (DesktopError e) {
// A valid session has become invalid for time-out or explicit termination on AMConsole.
if (e.getType().equals(TypedException.SESSION_TIMED_OUT)) {
// if reqest was from ajax, we want to return error msg
// instead of redirect to login
String requestType = dreq.getParameter("requestType");
if ((requestType != null) &&
requestType.equalsIgnoreCase("ajax")) {
if (out == null) {
out = getWriter(res, contentType, charset);
}
handleException(req, res, out, e);
return;
} else {
// AM handles timeout correctly
if (federationEnabled) {
handleFederation(false, req, res, dreq, dres, out, clientType, contentType, charset);
return;
} else {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_LOCALAUTH);
showLocalAuth(req, res, dreq, out, clientType, contentType, charset);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_LOCALAUTH);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getDesktopRequestStatistic().measure(DesktopRequestStatistic.DESKTOP_REQUEST_LOCALAUTH);
return;
}
}
}
if ("true".equals(getCookieValue(req,"auth")) ) {
Cookie authCookie = new Cookie("auth", "false");
res.addCookie(authCookie);
throw e;
} else {
// let it go to handleNoSessionRequest
isValidSession = false;
}
}
if (isValidSession) {
if ( authCookieNotSet(req) ) {
Cookie authCookie = new Cookie("auth", "true");
res.addCookie(authCookie);
}
doGetPost(req, res);
} else {
handleNoSessionRequest(authlessEnabled, federationEnabled, req, res, dreq, dres, out, clientType, contentType, charset);
}
} catch (IOException ioe) {
// do nothing
} catch (Throwable t) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_EXCEPTION);
if (out == null) {
out = getWriter(res, contentType, charset);
}
handleException(req, res, out, t);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_EXCEPTION);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getDesktopRequestStatistic().measure(DesktopRequestStatistic.DESKTOP_REQUEST_EXCEPTION);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ioe) {
// nothing
}
}
DesktopThreadLocalManager.release();
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopDesktopServiceAccessURITransaction();
}
}
/**
* Invokes preLogin servlet of IS by redirecting to the preLogin URL returned
* by the appContext.
*/
private void invokePreLogin(HttpServletRequest req, HttpServletResponse res,
DesktopRequest dreq, Writer out, String clientType, String contentType,
String charset)
throws IOException, DesktopException {
StringBuffer returnURL = new StringBuffer(getAbsURL(dreq, appContext, dreq.getRequestURI()));
boolean queryExists = false;
if (dreq.getParameterMap().size() > 0) {
String query = dreq.getQueryString();
returnURL.append("?")
.append(query);
queryExists = true;
}
String preLoginURL = appContext.getPreLoginURL(returnURL.toString(),
LIBERTY_SSO_FAILED_QUERY_PARAM);
if (preLoginURL == null) {
/* This is liberty misconfiguration. So fail gracefully by
* treating liberty sign on as failed and log error. So the user
* will either see authless desktop or the local auth page.
*/
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, "PSDT_CSPD0009");
}
if (queryExists) {
returnURL.append("&");
} else {
returnURL.append("?");
}
returnURL.append(LIBERTY_SSO_FAILED_QUERY_PARAM)
.append("=true");
preLoginURL = returnURL.toString();
}
if (logger.isLoggable(Level.CONFIG)) {
logger.log(Level.CONFIG, "PSDT_CSPD0010", preLoginURL);
}
out = getWriter(res, contentType, charset);
sendRedirect(req, res, out, preLoginURL);
}
private void showLocalAuth(HttpServletRequest req, HttpServletResponse res, DesktopRequest dreq, Writer out,
String clientType, String contentType, String charset)
throws IOException, DesktopException {
String noSessionURL = appContext.getNoSessionURL();
if (noSessionURL == null) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, "PSDT_CSPD0011");
}
noSessionURL = "/";
}
StringBuffer redirectURL = new StringBuffer(noSessionURL);
// Attach return URL as query string
String returnParam = appContext.getSessionReturnURLParamName();
if (returnParam != null && returnParam.length() > 0) {
StringBuffer returnURL = new StringBuffer(getAbsURL(dreq, appContext, dreq.getRequestURI()));
if (dreq.getParameterMap().size() > 0) {
//
// avoid evaluating the query string until
// we know we need it
//
String query = dreq.getQueryString();
returnURL.append("?").append(query);
}
redirectURL.append(noSessionURL.indexOf('?') < 0 ? "?" : "&");
redirectURL.append(returnParam).append("=").append(URLEncoder.encode(returnURL.toString()));
}
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "PSDT_CSPD0012", redirectURL);
}
out = getWriter(res, contentType, charset);
sendRedirect(req, res, out, redirectURL.toString());
}
private static Writer getWriter(HttpServletResponse res, String contentType, String charset)
throws IOException {
if (contentType != null) {
if (charset != null) {
res.setContentType(contentType + "; charset=" + charset);
} else {
res.setContentType(contentType);
}
}
return new OutputStreamWriter(res.getOutputStream(), charset);
}
protected DesktopContext getDesktopContext(HttpServletRequest req)
throws DesktopException {
return dcFactory.getDesktopContext(req);
}
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doGetPost(req, res);
}
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doGetPost(req, res);
}
private void addLBCookie(DesktopResponse dres) {
if ((appContext.getLBCookieName() != null)
&& (appContext.getLBCookieName().length() != 0)) {
dres.addCookie(new Cookie(appContext.getLBCookieName(), appContext.getPortalId() + "." + appContext.getInstanceId()));
}
}
private void doGetPost(HttpServletRequest req, HttpServletResponse res)
throws IOException {
Writer out = null;
String charset = I18n.DEFAULT_CHARSET;
String contentType = null;
DesktopContext context = null;
String name = null;
FQCN fqcn = null;
String action = null;
try {
setCacheHeaders(res);
context = getDesktopContext(req);
context.refresh();
charset = getCharset(req);
if (context == null) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_EXCEPTION);
out = getWriter(res, contentType, charset);
handleException(req, res, out, new Exception());
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_EXCEPTION);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getDesktopRequestStatistic().measure(DesktopRequestStatistic.DESKTOP_REQUEST_EXCEPTION);
return;
}
//
// request is a desktop request from the service method
// get charset and decode the parameters
//
DesktopRequest dreq = (DesktopRequest) DesktopRequestThreadLocalizer.getRequest();
String reqEncoding = req.getCharacterEncoding();
if (reqEncoding != null) {
dreq.decodeParams(reqEncoding);
} else {
dreq.decodeParams(charset);
}
String clientType = appContext.getClientType(req);
contentType = appContext.getContentType(clientType);
DesktopResponse dres = (DesktopResponse) DesktopRequestThreadLocalizer.getResponse();
if (!appContext.isAuthless(req)) {
addLBCookie(dres);
}
// handle a community access
if (dreq.getParameter(DesktopParameters.COMMUNITY_ACCESS) != null) {
handleCommunity(dreq, res);
}
//
// default action is content
//
action = dreq.getParameter("action");
if ((action == null) || (action.length() == 0)) {
action = "content";
}
StringBuffer outBuffer = null;
res.setContentType(context.getContentType() + "; charset=" + charset);
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "PSDT_CSPD0012", "action");
logger.log(Level.FINEST, "PSDT_CSPD0013", "name");
}
name = getChannelName(dreq, true);
if (name == null) {
throw new DesktopException("DesktopServlet.doGetPost(): no privilege to execute desktop", TypedException.NO_PRIVILEGE_TYPE);
}
// set top channel name in the request
context.setTopChannelName(dreq, name);
//
// ptr for redirect url, if this is a post
//
URL next = null;
//
// handle main actions
//
if (action.equalsIgnoreCase("content")) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_CONTENT);
Provider p = context.getProvider(dreq, name);
if (p == null) {
throw new DesktopException("attempt to reference unknown channel=" + name, TypedException.UNKNOWN_CHANNEL_TYPE);
}
if (p.isPresentable(dreq)) {
String last = dreq.getParameter("last");
// Set the lastChannelName property
if ((last == null) || (last.equalsIgnoreCase("true"))) {
context.setDefaultChannelName(name);
}
outBuffer = context.getContent(dreq, dres, name);
} else {
res.sendError(406);
}
} else if (action.equalsIgnoreCase("edit")) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_EDIT);
name = getChannelName(dreq, false);
Provider p = context.getProvider(dreq, name);
if (p == null) {
throw new DesktopException("attempt to reference unknown channel=" + name, TypedException.UNKNOWN_CHANNEL_TYPE);
}
if (!p.isEditable()) {
throw new DesktopException("attempt to edit non-editable channel=" + name, TypedException.NON_EDITABLE_TYPE);
}
ActivityTime activityTime = new ActivityTime();
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getEditChannelActionStatistic().mark(activityTime);
if (dreq.getParameter("targetprovider") == null) {
fqcn = DPHelper.getFQCN(context.getDPRoot(), name);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startProviderServiceTransaction(fqcn.encoded(), MonitoringSubsystem.CHANNEL_ACTION_EDIT);
} else {
fqcn = DPHelper.getFQCN(context.getDPRoot(), dreq.getParameter("targetprovider"));
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startProviderServiceTransaction(fqcn.encoded(), MonitoringSubsystem.CHANNEL_ACTION_EDIT);
}
if (p.getEditType() == EDIT_SUBSET) {
String containerName = context.getEditProviderContainerName();
Provider editProvider = context.getProvider(dreq, containerName);
dreq.getParameterMap().put("targetprovider", new String[]{p.getName()});
outBuffer = editProvider.getEdit(dreq, dres);
} else {
outBuffer = p.getEdit(dreq, dres);
}
if (dreq.getParameter("targetprovider") == null) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopProviderServiceTransaction(fqcn.encoded(), MonitoringSubsystem.CHANNEL_ACTION_EDIT);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getEditChannelActionStatistic().measure(activityTime, fqcn.plain());
} else {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopProviderServiceTransaction(fqcn.encoded(), MonitoringSubsystem.CHANNEL_ACTION_EDIT);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getEditChannelActionStatistic().measure(activityTime, fqcn.plain());
}
} else if (action.equalsIgnoreCase("process")) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_PROCESS);
name = getChannelName(dreq, false);
Provider p = context.getProvider(dreq, name);
if (p == null) {
throw new DesktopException("attempt to reference unknown channel=" + name, TypedException.UNKNOWN_CHANNEL_TYPE);
}
if (isSetTabRequest(req, p) || p.isEditable()) {
ActivityTime activityTime = new ActivityTime();
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getProcessChannelActionStatistic().mark(activityTime);
if (dreq.getParameter("targetprovider") != null) {
fqcn = DPHelper.getFQCN(context.getDPRoot(), dreq.getParameter("targetprovider"));
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startProviderServiceTransaction(fqcn.encoded(), MonitoringSubsystem.CHANNEL_ACTION_PROCESS);
} else if (dreq.getParameter("windowProvider.targetPortletChannel") != null) {
fqcn = DPHelper.getFQCN(context.getDPRoot(), dreq.getParameter("windowProvider.targetPortletChannel"));
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startProviderServiceTransaction(fqcn.encoded(), MonitoringSubsystem.CHANNEL_ACTION_PROCESS);
} else {
fqcn = DPHelper.getFQCN(context.getDPRoot(), name);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startProviderServiceTransaction(fqcn.encoded(), MonitoringSubsystem.CHANNEL_ACTION_PROCESS);
}
try {
next = p.processEdit(dreq, dres);
} catch (InvalidEditFormDataException e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, "PSDT_CSPD0015", e);
}
String error = I18n.IURLEncode(e.getMessage());
StringBuffer args = new StringBuffer(64);
args.append("?action=edit&provider=")
.append(name)
.append("&error=")
.append(error);
next = new URL(context.getDesktopURL(dreq) + args.toString());
}
if (dreq.getParameter("targetprovider") != null) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopProviderServiceTransaction(fqcn.encoded(), MonitoringSubsystem.CHANNEL_ACTION_PROCESS);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getProcessChannelActionStatistic().measure(activityTime, fqcn.plain());
} else if (dreq.getParameter("windowProvider.targetPortletChannel") != null) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopProviderServiceTransaction(fqcn.encoded(), MonitoringSubsystem.CHANNEL_ACTION_PROCESS);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getProcessChannelActionStatistic().measure(activityTime, fqcn.plain());
} else {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopProviderServiceTransaction(fqcn.encoded(), MonitoringSubsystem.CHANNEL_ACTION_PROCESS);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getProcessChannelActionStatistic().measure(activityTime, fqcn.plain());
}
} else {
throw new DesktopException("attempt to process non-editable channel=" + name, TypedException.NON_EDITABLE_TYPE);
}
} else if (action.equalsIgnoreCase("ubt")) {
String url = dreq.getParameter("url");
out = getWriter(res, contentType, charset);
sendRedirect(req, res, out, url);
//UBT code - start
try {
UBTLogManager manager = UBTLogManager.getInstance();
if (manager.isUBTEnabled()) {
UBTEvent prov_ren = UBTEvent.getInstance(DesktopEvents.USER_CLICK_EX_LINK);
prov_ren.put(UBTLogField.ACTION, "ExLink");
prov_ren.put(UBTLogField.EX_PORTAL_LINK, url);
manager.logEvent(new ProviderLogRecord(prov_ren, req, res, context.getContainerProviderContext().getUserID()));
}
} catch (Exception e) {
//ubt exception
}
//UBT code - end
return;
} else if (action.equalsIgnoreCase("logout")) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().startDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_LOGOUT);
context.store();
Cookie authCookie = new Cookie("auth", "false");
res.addCookie(authCookie);
out = getWriter(res, contentType, charset);
sendRedirect(req, res, out, context.getLogoutURL() + "?goto=" + context.getDesktopURL(req));
return;
} else {
throw new DesktopException("DestopServlet.doGetPost(): unknown action=" + action +
", channel name=" + name);
}
//
// if action was a process, redirect to url (next) returned from
// provider's processEdit method
//
out = getWriter(res, contentType, charset);
Cookie clientProperties = context.getClientProperties();
if (clientProperties != null) {
res.addCookie(clientProperties);
}
if (action.equalsIgnoreCase("process")) {
if (next == null) {
StringBuffer nextString = new StringBuffer(context.getDesktopURL(dreq));
if (nextString.indexOf("?")!=-1)
nextString.append("&");
else
nextString.append("?");
nextString.append("action=content&provider=")
.append(context.getDefaultChannelName());
String newargs = dreq.getParameter("dt.newargs");
if (newargs != null)
nextString.append("&" + newargs);
sendRedirect(req, res, out, nextString.toString());
} else {
if (logger.isLoggable(Level.FINER)) {
String[] param = {"DesktopServlet.doPost()", next.toString()};
logger.log(Level.FINER, "PSDT_CSPD0016", param);
}
sendRedirect(req, res, out, next.toString());
}
} else {
if (outBuffer != null) {
out.write(outBuffer.toString());
} else {
throw new DesktopException("Channel content is empty for " + name);
}
}
//
// for testing!!!
//
/*
appContext.debugError("DesktopServlet.doGetPost(): dpRoot=" +
context.getDPRoot().toString(false));
*/
context.store();
} catch (IOException ioe) {
// nothing
} catch (Throwable e) {
// If the exception is wrapped in DesktopError get the wrapped exception
if (e instanceof DesktopError) {
logger.log(Level.SEVERE, "PSDT_CSPD0017", e.getCause());
}
if (res.isCommitted()) {
//
// just log an error, we can't
// write to the stream to return
// an error message
//
if (logger.isLoggable(Level.SEVERE)) {
logger.log(Level.SEVERE, "PSDT_CSPD0017", e);
}
} else {
res.reset();
try {
setCacheHeaders(res);
} catch (Throwable t) {
// nothing we can do, root cause will
// be reported in handleException()
}
out = getWriter(res, contentType, charset);
handleException(req, res, out, e);
}
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ioe) {
// nothing
}
}
if (action != null) {
if (action.equalsIgnoreCase("content")) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_CONTENT);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getDesktopRequestStatistic().measure(DesktopRequestStatistic.DESKTOP_REQUEST_CONTENT);
} else if (action.equalsIgnoreCase("edit")) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_EDIT);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getDesktopRequestStatistic().measure(DesktopRequestStatistic.DESKTOP_REQUEST_EDIT);
} else if (action.equalsIgnoreCase("process")) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_PROCESS);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getDesktopRequestStatistic().measure(DesktopRequestStatistic.DESKTOP_REQUEST_PROCESS);
} else if (action.equalsIgnoreCase("logout")) {
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().stopDesktopServiceTransaction(DesktopRequestStatistic.DESKTOP_REQUEST_LOGOUT);
MonitoringSubsystemWrapper.getDesktopMonitoringSubsystem().getDesktopRequestStatistic().measure(DesktopRequestStatistic.DESKTOP_REQUEST_LOGOUT);
}
}
}
}
private static void sendRedirect(HttpServletRequest req, HttpServletResponse res, Writer out, String u)
throws IOException, DesktopException {
DesktopContext dc = null;
try {
dc = DesktopContextThreadLocalizer.get();
} catch (ContextError c) {
if (logger.isLoggable(Level.FINER)) {
logger.log(Level.FINER, "PSDT_CSPD0018", "DesktopServlet.sendRedirect ()");
}
}
u = getAbsURL(req, appContext, u);
/*
* HTTP 1.0 spec states that when sending a 302 response code "Unless it
* was a HEAD request, the Entity-Body of the response should contain
* a short note with a hyperlink to the new URI(s)."
* (see RFC1945 Section 9.3 302)
*
* Some WAP gateway implementations of HTTP expect this body and will
* fail without it (see 4452980).
*/
if (!req.getMethod().equalsIgnoreCase("head")) {
String clientType = appContext.getClientType(req);
String clientPath = appContext.getClientPath(clientType);
StringBuffer redirect = null;
if (clientType != null) {
String contentType = appContext.getContentType(clientType);
String charset = getCharset(req);
String type = appContext.getDefaultDesktopType();
if (dc != null) {
u = dc.encodeURL(u);
type = dc.getDesktopType();
}
Hashtable tags = new Hashtable();
tags.put("url", u);
redirect = appContext.getTemplate(type, Locale.getDefault().toString(), null, null, clientPath, "redirect.template", tags, appContext.getTemplateBaseDir());
if (logger.isLoggable(Level.FINER)) {
logger.log(Level.FINER, "PSDT_CSPD0019", redirect);
}
if (redirect != null) {
out.write(redirect.toString());
} else {
//
// log error, but fail gracefully because the spec says "should"
//
if (logger.isLoggable(Level.SEVERE)) {
logger.log(Level.SEVERE, "PSDT_CSPD0019", "DesktopServlet.sendRedirect ()");
}
}
}
}
// Use setStatus() and setHeader() in lieu of sendRedirect() to get
// around web server bug 4874475.
// See bug 4891570.
// res.sendRedirect(u);
res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
res.setHeader("Location", u);
}
private static String getAbsURL(HttpServletRequest req, DesktopAppContext appContext, String u)
throws IOException {
if (!u.regionMatches(true, 0, "http://", 0, 7)
&& !u.regionMatches(true, 0, "https://", 0, 7)) {
StringBuffer ru = appContext.getRequestServer(req);
URL requestURL = new URL(ru.toString());
String scheme = requestURL.getProtocol();
StringBuffer absURL = new StringBuffer()
.append(scheme)
.append("://")
.append(requestURL.getHost())
.append(":");
int port = requestURL.getPort();
// default port schemes need to fill in port
if (scheme.equals("http") && port <= 0) {
port = 80;
} else if (scheme.equals("https") && port <= 0) {
port = 443;
}
absURL.append(port)
.append(u);
return absURL.toString();
} else {
return u;
}
}
/**
* this method handles exceptions in the desktop, throwing up a standard
* error page and logging the exception.
*/
private void handleException(HttpServletRequest req, HttpServletResponse res, Writer out, Throwable e) {
DesktopContext dc = null;
String lastChannelName = null;
try {
if (out == null) {
throw new DesktopException(e);
}
try {
lastChannelName = getChannelName(req, true);
} catch (DesktopError derr) {
// nothing, we want to avoid "server error" in the simple
// case where we cannot get the last channel name. last
// channel name is not required for error provider
}
if (DesktopContextThreadLocalizer.exists()) {
dc = DesktopContextThreadLocalizer.get();
} else {
if (appContext.isAuthlessEnabled()) {
// Show errors with authless locale, look-n-feel, etc.
dc = dcFactory.getDesktopContext(req);
// we don't want to refresh context at this point.
}
}
if (dc != null) {
req.setAttribute(errorProvider.getName() + ".desktopContext", dc);
}
if (appContext != null) {
req.setAttribute(errorProvider.getName() + ".desktopAppContext", appContext);
}
if (lastChannelName != null) {
req.setAttribute(errorProvider.getName() + ".lastChannelName", lastChannelName);
}
if (e != null) {
req.setAttribute(errorProvider.getName() + ".exception", e);
}
if (e instanceof TypedException) {
String propertiesFile = PropertiesConfigContext.DESKTOP_CONFIG_FILE;
req.setAttribute(errorProvider.getName() + ".propertiesFile", propertiesFile);
req.setAttribute(errorProvider.getName() + ".response", RequestThreadLocalizer.getResponse());
}
// Get the Contents from the Error Provider
StringBuffer content = errorProvider.getContent(req, res);
if (content != null) {
out.write(content.toString());
}
boolean logException = true;
if (e instanceof TypedException) {
TypedException te = (TypedException) e;
if (te.getType().equals(TypedException.SESSION_TIMED_OUT)) {
logException = false;
}
}
if (logger.isLoggable(Level.SEVERE) && logException) {
logger.log(Level.SEVERE, "PSDT_CSPD0021", e);
}
} catch (Throwable e2) {
//
// this means we weren't able to return the error
// page to the user. make sure the error appears
// in the webserver log
//
if (logger.isLoggable(Level.SEVERE)) {
String[] param = {e.getMessage(), e2.getMessage()};
logger.log(Level.SEVERE, "PSDT_CSPD0022", param);
logger.log(Level.SEVERE, "PSDT_CSPD0023", e2);
logger.log(Level.SEVERE, "PSDT_CSPD0024", e);
}
try {
res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} catch (IOException ioe) {
if (logger.isLoggable(Level.SEVERE)) {
logger.log(Level.SEVERE, "PSDT_CSPD0025", e);
}
}
}
}
protected static void setCacheHeaders(HttpServletResponse res) {
int cacheTime = appContext.getBrowserCacheInterval();
if (cacheTime > 0) {
res.setDateHeader("Expires", System.currentTimeMillis() + (1000 * cacheTime));
res.setHeader("Cache-Control", "max-age=" + cacheTime);
} else {
res.setHeader("Pragma", "no-cache");
res.setDateHeader("Expires", 0);
res.setHeader("Cache-Control", "no-cache, must-revalidate, max-age=0");
}
}
protected static String getCharset(HttpServletRequest req) {
DesktopContext context = null;
String charset = null;
if (DesktopContextThreadLocalizer.exists()) {
context = DesktopContextThreadLocalizer.get();
charset = context.getCharset();
} else {
Locale locale = Locale.getDefault();
charset = appContext.getCharset(appContext.getClientType(req), locale);
}
return charset;
}
private String getChannelName(HttpServletRequest req, boolean useDefaults) {
//
// we always take the url param over anything else
// if the url param is absent, and we have been
// instructed to use defaults, check and see
// if there's a desktop context. if there is,
// use the dc to get the channel name
// from the session property. if it's not there
// read it from the desktop context defaults.
//
String name = req.getParameter("provider");
if (name == null && useDefaults) {
if (DesktopContextThreadLocalizer.exists()) {
DesktopContext dc = DesktopContextThreadLocalizer.get();
name = dc.getDefaultChannelName();
}
}
return name;
}
private boolean authCookieNotSet(HttpServletRequest req) {
return !("true".equals(getCookieValue(req,"auth")));
}
private String getCookieValue(HttpServletRequest req, String name) {
if (name == null) {
return null;
}
Cookie[] cookies = req.getCookies();
for(int loopIndex = 0; loopIndex < cookies.length; loopIndex++) {
if (name.equals(cookies[loopIndex].getName())) {
return cookies[loopIndex].getValue();
}
}
return null;
}
private boolean isSetTabRequest(HttpServletRequest req, Provider p) {
if (p instanceof JSPTabContainerProvider) {
return ((JSPTabContainerProvider)p).isSetTabRequest(req);
}
return false;
}
}
|