0001: /*******************************************************************************
0002: * Licensed to the Apache Software Foundation (ASF) under one
0003: * or more contributor license agreements. See the NOTICE file
0004: * distributed with this work for additional information
0005: * regarding copyright ownership. The ASF licenses this file
0006: * to you under the Apache License, Version 2.0 (the
0007: * "License"); you may not use this file except in compliance
0008: * with the License. You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing,
0013: * software distributed under the License is distributed on an
0014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015: * KIND, either express or implied. See the License for the
0016: * specific language governing permissions and limitations
0017: * under the License.
0018: *******************************************************************************/package org.ofbiz.webapp.control;
0019:
0020: import java.io.IOException;
0021: import java.io.Serializable;
0022: import java.io.UnsupportedEncodingException;
0023: import java.util.*;
0024: import java.security.cert.X509Certificate;
0025: import java.security.KeyStore;
0026: import java.security.GeneralSecurityException;
0027: import java.security.KeyStoreException;
0028: import java.net.URL;
0029: import javax.servlet.ServletContext;
0030: import javax.servlet.http.HttpServletRequest;
0031: import javax.servlet.http.HttpServletResponse;
0032: import javax.servlet.http.HttpSession;
0033:
0034: import javolution.util.FastMap;
0035:
0036: import org.ofbiz.base.util.*;
0037: import org.ofbiz.entity.GenericDelegator;
0038: import org.ofbiz.entity.GenericEntityException;
0039: import org.ofbiz.entity.GenericValue;
0040: import org.ofbiz.webapp.event.EventFactory;
0041: import org.ofbiz.webapp.event.EventHandler;
0042: import org.ofbiz.webapp.event.EventHandlerException;
0043: import org.ofbiz.webapp.stats.ServerHitBin;
0044: import org.ofbiz.webapp.stats.VisitHandler;
0045: import org.ofbiz.webapp.view.ViewFactory;
0046: import org.ofbiz.webapp.view.ViewHandler;
0047: import org.ofbiz.webapp.view.ViewHandlerException;
0048: import org.ofbiz.webapp.website.WebSiteWorker;
0049:
0050: /**
0051: * RequestHandler - Request Processor Object
0052: */
0053: public class RequestHandler implements Serializable {
0054:
0055: public static final String module = RequestHandler.class.getName();
0056: public static final String err_resource = "WebappUiLabels";
0057:
0058: public static RequestHandler getRequestHandler(
0059: ServletContext servletContext) {
0060: RequestHandler rh = (RequestHandler) servletContext
0061: .getAttribute("_REQUEST_HANDLER_");
0062: if (rh == null) {
0063: rh = new RequestHandler();
0064: servletContext.setAttribute("_REQUEST_HANDLER_", rh);
0065: rh.init(servletContext);
0066: }
0067: return rh;
0068: }
0069:
0070: private ServletContext context = null;
0071: private RequestManager requestManager = null;
0072: private ViewFactory viewFactory = null;
0073: private EventFactory eventFactory = null;
0074:
0075: public void init(ServletContext context) {
0076: Debug.logInfo("[RequestHandler Loading...]", module);
0077: this .context = context;
0078: this .requestManager = new RequestManager(context);
0079: this .viewFactory = new ViewFactory(this );
0080: this .eventFactory = new EventFactory(this );
0081: }
0082:
0083: public void doRequest(HttpServletRequest request,
0084: HttpServletResponse response, String chain,
0085: GenericValue userLogin, GenericDelegator delegator)
0086: throws RequestHandlerException {
0087:
0088: HttpSession session = request.getSession();
0089: String eventType;
0090: String eventPath;
0091: String eventMethod;
0092:
0093: // workaraound if we are in the root webapp
0094: String cname = UtilHttp.getApplicationName(request);
0095:
0096: // Grab data from request object to process
0097: String requestUri = RequestHandler.getRequestUri(request
0098: .getPathInfo());
0099: String nextView = RequestHandler.getNextPageUri(request
0100: .getPathInfo());
0101: if (request.getAttribute("targetRequestUri") == null) {
0102: if (request.getSession().getAttribute("_PREVIOUS_REQUEST_") != null) {
0103: request.setAttribute("targetRequestUri", request
0104: .getSession()
0105: .getAttribute("_PREVIOUS_REQUEST_"));
0106: } else {
0107: request.setAttribute("targetRequestUri", "/"
0108: + requestUri);
0109: }
0110: }
0111:
0112: // Check for chained request.
0113: if (chain != null) {
0114: requestUri = RequestHandler.getRequestUri(chain);
0115: if (request.getAttribute("_POST_CHAIN_VIEW_") != null) {
0116: nextView = (String) request
0117: .getAttribute("_POST_CHAIN_VIEW_");
0118: } else {
0119: nextView = RequestHandler.getNextPageUri(chain);
0120: }
0121: if (Debug.infoOn())
0122: Debug.logInfo(
0123: "[RequestHandler]: Chain in place: requestUri="
0124: + requestUri + " nextView=" + nextView
0125: + " sessionId="
0126: + UtilHttp.getSessionId(request),
0127: module);
0128: } else {
0129: // Check to make sure we are allowed to access this request directly. (Also checks if this request is defined.)
0130: // If the request cannot be called, or is not defined, check and see if there is a default-request we an process
0131: if (!requestManager.allowDirectRequest(requestUri)) {
0132: if (!requestManager.allowDirectRequest(requestManager
0133: .getDefaultRequest())) {
0134: throw new RequestHandlerException(
0135: "Unknown request ["
0136: + requestUri
0137: + "]; this request does not exist or cannot be called directly.");
0138: } else {
0139: requestUri = requestManager.getDefaultRequest();
0140: }
0141: }
0142:
0143: // Check if we SHOULD be secure and are not. If we are posting let it pass to not lose data. (too late now anyway)
0144: if (!request.isSecure()
0145: && requestManager.requiresHttps(requestUri)
0146: && !request.getMethod().equalsIgnoreCase("POST")) {
0147: StringBuffer urlBuf = new StringBuffer();
0148: urlBuf.append(request.getPathInfo());
0149: if (request.getQueryString() != null) {
0150: urlBuf.append("?").append(request.getQueryString());
0151: }
0152: String newUrl = RequestHandler.makeUrl(request,
0153: response, urlBuf.toString());
0154: if (newUrl.toUpperCase().startsWith("HTTPS")) {
0155: // if we are supposed to be secure, redirect secure.
0156: callRedirect(newUrl, response, request);
0157: }
0158: }
0159:
0160: // Check if X509 is required and we are not secure; throw exception
0161: if (!request.isSecure()
0162: && requestManager
0163: .requiresHttpsClientCert(requestUri)) {
0164: throw new RequestHandlerException(
0165: "Unknown request ["
0166: + requestUri
0167: + "]; this request does not exist or cannot be called directly.");
0168: }
0169:
0170: // Check for HTTPS client (x.509) security
0171: if (request.isSecure()
0172: && requestManager
0173: .requiresHttpsClientCert(requestUri)) {
0174: X509Certificate[] clientCerts = (X509Certificate[]) request
0175: .getAttribute("javax.servlet.request.X509Certificate"); // 2.2 spec
0176: if (clientCerts == null) {
0177: clientCerts = (X509Certificate[]) request
0178: .getAttribute("javax.net.ssl.peer_certificates"); // 2.1 spec
0179: }
0180: if (clientCerts == null) {
0181: Debug
0182: .logWarning(
0183: "Received no client certificates from browser",
0184: module);
0185: }
0186:
0187: // check if the client has a valid certificate (in our db store)
0188: boolean foundTrustedCert = false;
0189:
0190: if (clientCerts == null) {
0191: throw new RequestHandlerException(
0192: "Unknown request ["
0193: + requestUri
0194: + "]; this request does not exist or cannot be called directly.");
0195: } else {
0196: for (int i = 0; i < clientCerts.length; i++) {
0197: Debug.log(clientCerts[i]
0198: .getSubjectX500Principal().getName(),
0199: module);
0200: }
0201:
0202: // check if this is a trusted cert
0203: if (SSLUtil.isClientTrusted(clientCerts, null)) {
0204: foundTrustedCert = true;
0205: }
0206: }
0207:
0208: if (!foundTrustedCert) {
0209: Debug.logWarning(
0210: "No trusted certificate found for request ["
0211: + requestUri + "]", module);
0212: throw new RequestHandlerException(
0213: "Unknown request ["
0214: + requestUri
0215: + "]; this request does not exist or cannot be called directly.");
0216: }
0217: }
0218:
0219: // If its the first visit run the first visit events.
0220: if (session.getAttribute("visit") == null) {
0221: Debug.logInfo(
0222: "This is the first request in this visit."
0223: + " sessionId="
0224: + UtilHttp.getSessionId(request),
0225: module);
0226: // This isn't an event because it is required to run. We do not want to make it optional.
0227: VisitHandler.setInitialVisit(request, response);
0228: Collection events = requestManager
0229: .getFirstVisitEvents();
0230:
0231: if (events != null) {
0232: Iterator i = events.iterator();
0233:
0234: while (i.hasNext()) {
0235: Map eventMap = (Map) i.next();
0236: String eType = (String) eventMap
0237: .get(ConfigXMLReader.EVENT_TYPE);
0238: String ePath = (String) eventMap
0239: .get(ConfigXMLReader.EVENT_PATH);
0240: String eMeth = (String) eventMap
0241: .get(ConfigXMLReader.EVENT_METHOD);
0242:
0243: try {
0244: String returnString = this .runEvent(
0245: request, response, eType, ePath,
0246: eMeth);
0247: if (returnString != null
0248: && !returnString
0249: .equalsIgnoreCase("success")) {
0250: throw new EventHandlerException(
0251: "First-Visit event did not return 'success'.");
0252: } else if (returnString == null) {
0253: nextView = "none:";
0254: }
0255: } catch (EventHandlerException e) {
0256: Debug.logError(e, module);
0257: }
0258: }
0259: }
0260: }
0261:
0262: // Invoke the pre-processor (but NOT in a chain)
0263: Collection preProcEvents = requestManager.getPreProcessor();
0264: if (preProcEvents != null) {
0265: Iterator i = preProcEvents.iterator();
0266:
0267: while (i.hasNext()) {
0268: Map eventMap = (Map) i.next();
0269: String eType = (String) eventMap
0270: .get(ConfigXMLReader.EVENT_TYPE);
0271: String ePath = (String) eventMap
0272: .get(ConfigXMLReader.EVENT_PATH);
0273: String eMeth = (String) eventMap
0274: .get(ConfigXMLReader.EVENT_METHOD);
0275: try {
0276: String returnString = this .runEvent(request,
0277: response, eType, ePath, eMeth);
0278: if (returnString != null
0279: && !returnString
0280: .equalsIgnoreCase("success")) {
0281: throw new EventHandlerException(
0282: "Pre-Processor event did not return 'success'.");
0283: } else if (returnString == null) {
0284: nextView = "none:";
0285: }
0286: } catch (EventHandlerException e) {
0287: Debug.logError(e, module);
0288: }
0289: }
0290: }
0291: }
0292:
0293: // Pre-Processor/First-Visit event(s) can interrupt the flow by returning null.
0294: // Warning: this could cause problems if more then one event attempts to return a response.
0295: if ("none:".equals(nextView)) {
0296: if (Debug.infoOn())
0297: Debug.logInfo(
0298: "[Pre-Processor Interrupted Request, not running: "
0299: + requestUri + " sessionId="
0300: + UtilHttp.getSessionId(request),
0301: module);
0302: return;
0303: }
0304:
0305: if (Debug.infoOn())
0306: Debug.logInfo("[Processing Request]: " + requestUri
0307: + " sessionId=" + UtilHttp.getSessionId(request),
0308: module);
0309: request.setAttribute("thisRequestUri", requestUri); // store the actual request URI
0310:
0311: String eventReturnString = null;
0312:
0313: // Perform security check.
0314: if (requestManager.requiresAuth(requestUri)) {
0315: // Invoke the security handler
0316: // catch exceptions and throw RequestHandlerException if failed.
0317: Debug.logVerbose(
0318: "[RequestHandler]: AuthRequired. Running security check."
0319: + " sessionId="
0320: + UtilHttp.getSessionId(request), module);
0321: String checkLoginType = requestManager
0322: .getEventType("checkLogin");
0323: String checkLoginPath = requestManager
0324: .getEventPath("checkLogin");
0325: String checkLoginMethod = requestManager
0326: .getEventMethod("checkLogin");
0327: String checkLoginReturnString;
0328:
0329: try {
0330: checkLoginReturnString = this .runEvent(request,
0331: response, checkLoginType, checkLoginPath,
0332: checkLoginMethod);
0333: } catch (EventHandlerException e) {
0334: throw new RequestHandlerException(e.getMessage(), e);
0335: }
0336: if (!"success".equalsIgnoreCase(checkLoginReturnString)) {
0337: // previous URL already saved by event, so just do as the return says...
0338: eventReturnString = checkLoginReturnString;
0339: requestUri = "checkLogin";
0340: }
0341: }
0342:
0343: // Invoke the defined event (unless login failed)
0344: if (eventReturnString == null) {
0345: eventType = requestManager.getEventType(requestUri);
0346: eventPath = requestManager.getEventPath(requestUri);
0347: eventMethod = requestManager.getEventMethod(requestUri);
0348: if (eventType != null && eventPath != null
0349: && eventMethod != null) {
0350: try {
0351: long eventStartTime = System.currentTimeMillis();
0352:
0353: // run the event
0354: eventReturnString = this
0355: .runEvent(request, response, eventType,
0356: eventPath, eventMethod);
0357:
0358: // save the server hit
0359: ServerHitBin.countEvent(cname + "." + eventMethod,
0360: request, eventStartTime, System
0361: .currentTimeMillis()
0362: - eventStartTime, userLogin,
0363: delegator);
0364:
0365: // set the default event return
0366: if (eventReturnString == null) {
0367: nextView = "none:";
0368: }
0369: } catch (EventHandlerException e) {
0370: // check to see if there is an "error" response, if so go there and make an request error message
0371: String tryErrorMsg = requestManager
0372: .getRequestAttribute(requestUri, "error");
0373:
0374: if (tryErrorMsg != null) {
0375: eventReturnString = "error";
0376: Locale locale = UtilHttp.getLocale(request);
0377: String errMsg = UtilProperties.getMessage(
0378: RequestHandler.err_resource,
0379: "requestHandler.error_call_event",
0380: locale);
0381: request.setAttribute("_ERROR_MESSAGE_", errMsg
0382: + ": " + e.toString());
0383: } else {
0384: throw new RequestHandlerException(
0385: "Error calling event and no error repsonse was specified",
0386: e);
0387: }
0388: }
0389: }
0390: }
0391:
0392: // If error, then display more error messages:
0393: if ("error".equals(eventReturnString)) {
0394: if (Debug.errorOn()) {
0395: String errorMessageHeader = "Request "
0396: + requestUri
0397: + " caused an error with the following message: ";
0398: if (request.getAttribute("_ERROR_MESSAGE_") != null) {
0399: Debug.logError(errorMessageHeader
0400: + request.getAttribute("_ERROR_MESSAGE_"),
0401: module);
0402: }
0403: if (request.getAttribute("_ERROR_MESSAGE_LIST_") != null) {
0404: Debug
0405: .logError(
0406: errorMessageHeader
0407: + request
0408: .getAttribute("_ERROR_MESSAGE_LIST_"),
0409: module);
0410: }
0411: }
0412: }
0413:
0414: // Process the eventReturn.
0415: String eventReturn = requestManager.getRequestAttribute(
0416: requestUri, eventReturnString);
0417: if (Debug.verboseOn())
0418: Debug.logVerbose("[Response Qualified]: " + eventReturn
0419: + " sessionId=" + UtilHttp.getSessionId(request),
0420: module);
0421:
0422: // Set the next view (don't use event return if success, default to nextView (which is set to eventReturn later if null); also even if success if it is a type "none" response ignore the nextView, ie use the eventReturn)
0423: if (eventReturn != null
0424: && (!"success".equals(eventReturnString) || eventReturn
0425: .startsWith("none:")))
0426: nextView = eventReturn;
0427: if (Debug.verboseOn())
0428: Debug.logVerbose("[Event Response Mapping]: " + nextView
0429: + " sessionId=" + UtilHttp.getSessionId(request),
0430: module);
0431:
0432: // get the previous request info
0433: String previousRequest = (String) request.getSession()
0434: .getAttribute("_PREVIOUS_REQUEST_");
0435: String loginPass = (String) request
0436: .getAttribute("_LOGIN_PASSED_");
0437:
0438: // restore previous redirected request's attribute, so redirected page can display previous request's error msg etc.
0439: String preReqAttStr = (String) request.getSession()
0440: .getAttribute("_REQ_ATTR_MAP_");
0441: if (preReqAttStr != null) {
0442: request.getSession().removeAttribute("_REQ_ATTR_MAP_");
0443: byte[] reqAttrMapBytes = StringUtil
0444: .fromHexString(preReqAttStr);
0445: Map preRequestMap = (Map) UtilObject
0446: .getObject(reqAttrMapBytes);
0447: if (preRequestMap != null && preRequestMap.size() > 0) {
0448: Iterator keys = preRequestMap.keySet().iterator();
0449: while (keys.hasNext()) {
0450: String key = (String) keys.next();
0451: if ("_ERROR_MESSAGE_LIST_".equals(key)
0452: || "_ERROR_MESSAGE_MAP_".equals(key)
0453: || "_ERROR_MESSAGE_".equals(key)
0454: || "_EVENT_MESSAGE_LIST_".equals(key)
0455: || "_EVENT_MESSAGE_".equals(key)) {
0456: Object value = preRequestMap.get(key);
0457: request.setAttribute(key, value);
0458: }
0459: }
0460: }
0461: }
0462:
0463: if (Debug.verboseOn())
0464: Debug.logVerbose("[RequestHandler]: previousRequest - "
0465: + previousRequest + " (" + loginPass + ")"
0466: + " sessionId=" + UtilHttp.getSessionId(request),
0467: module);
0468:
0469: // if previous request exists, and a login just succeeded, do that now.
0470: if (previousRequest != null && loginPass != null
0471: && loginPass.equalsIgnoreCase("TRUE")) {
0472: request.getSession().removeAttribute("_PREVIOUS_REQUEST_");
0473: // special case to avoid login/logout looping: if request was "logout" before the login, change to null for default success view; do the same for "login" to avoid going back to the same page
0474: if ("logout".equals(previousRequest)
0475: || "/logout".equals(previousRequest)
0476: || "login".equals(previousRequest)
0477: || "/login".equals(previousRequest)
0478: || "checkLogin".equals(previousRequest)
0479: || "/checkLogin".equals(previousRequest)
0480: || "/checkLogin/login".equals(previousRequest)) {
0481: Debug
0482: .logWarning(
0483: "Found special _PREVIOUS_REQUEST_ of ["
0484: + previousRequest
0485: + "], setting to null to avoid problems, not running request again",
0486: module);
0487: previousRequest = null;
0488: } else {
0489: if (Debug.infoOn())
0490: Debug.logInfo("[Doing Previous Request]: "
0491: + previousRequest + " sessionId="
0492: + UtilHttp.getSessionId(request), module);
0493: doRequest(request, response, previousRequest,
0494: userLogin, delegator);
0495: return; // this is needed or else we will run the view twice
0496: }
0497: }
0498:
0499: String successView = requestManager.getViewName(requestUri);
0500: if ("success".equals(eventReturnString)
0501: && successView.startsWith("request:")) {
0502: // chains will override any url defined views; but we will save the view for the very end
0503: if (nextView != null) {
0504: request.setAttribute("_POST_CHAIN_VIEW_", nextView);
0505: }
0506: nextView = successView;
0507: }
0508:
0509: // Make sure we have some sort of response to go to
0510: if (nextView == null)
0511: nextView = successView;
0512: if (Debug.verboseOn())
0513: Debug.logVerbose("[Current View]: " + nextView
0514: + " sessionId=" + UtilHttp.getSessionId(request),
0515: module);
0516:
0517: // Handle the responses - chains/views
0518: if (nextView != null && nextView.startsWith("request:")) {
0519: // chained request
0520: Debug.logInfo(
0521: "[RequestHandler.doRequest]: Response is a chained request."
0522: + " sessionId="
0523: + UtilHttp.getSessionId(request), module);
0524: nextView = nextView.substring(8);
0525: doRequest(request, response, nextView, userLogin, delegator);
0526: } else { // handle views
0527: // first invoke the post-processor events.
0528: Collection postProcEvents = requestManager
0529: .getPostProcessor();
0530: if (chain == null && postProcEvents != null) { // don't run post-proc events on chained requests
0531: Iterator i = postProcEvents.iterator();
0532:
0533: while (i.hasNext()) {
0534: Map eventMap = (Map) i.next();
0535: String eType = (String) eventMap
0536: .get(ConfigXMLReader.EVENT_TYPE);
0537: String ePath = (String) eventMap
0538: .get(ConfigXMLReader.EVENT_PATH);
0539: String eMeth = (String) eventMap
0540: .get(ConfigXMLReader.EVENT_METHOD);
0541: try {
0542: String returnString = this .runEvent(request,
0543: response, eType, ePath, eMeth);
0544: if (returnString != null
0545: && !returnString
0546: .equalsIgnoreCase("success"))
0547: throw new EventHandlerException(
0548: "Post-Processor event did not return 'success'.");
0549: else if (returnString == null)
0550: nextView = "none:";
0551: } catch (EventHandlerException e) {
0552: Debug.logError(e, module);
0553: }
0554: }
0555: }
0556:
0557: if (nextView != null && nextView.startsWith("url:")) {
0558: // check for a url for redirection
0559: Debug.logInfo(
0560: "[RequestHandler.doRequest]: Response is a URL redirect."
0561: + " sessionId="
0562: + UtilHttp.getSessionId(request),
0563: module);
0564: nextView = nextView.substring(4);
0565: callRedirect(nextView, response, request);
0566: } else if (nextView != null
0567: && nextView.startsWith("cross-redirect:")) {
0568: // check for a cross-application redirect
0569: Debug.logInfo(
0570: "[RequestHandler.doRequest]: Response is a Cross-Application redirect."
0571: + " sessionId="
0572: + UtilHttp.getSessionId(request),
0573: module);
0574: nextView = nextView.substring(15);
0575: String url = nextView.startsWith("/") ? nextView : "/"
0576: + nextView;
0577: callRedirect(url + this .makeQueryString(request),
0578: response, request);
0579: } else if (nextView != null
0580: && nextView.startsWith("request-redirect:")) {
0581: // check for a Request redirect
0582: Debug.logInfo(
0583: "[RequestHandler.doRequest]: Response is a Request redirect."
0584: + " sessionId="
0585: + UtilHttp.getSessionId(request),
0586: module);
0587: nextView = nextView.substring(17);
0588: callRedirect(makeLinkWithQueryString(request, response,
0589: "/" + nextView), response, request);
0590: } else if (nextView != null
0591: && nextView.startsWith("request-redirect-noparam:")) {
0592: // check for a Request redirect
0593: Debug
0594: .logInfo(
0595: "[RequestHandler.doRequest]: Response is a Request redirect with no parameters."
0596: + " sessionId="
0597: + UtilHttp
0598: .getSessionId(request),
0599: module);
0600: nextView = nextView.substring(25);
0601: callRedirect(makeLink(request, response, nextView),
0602: response, request);
0603: } else if (nextView != null && nextView.startsWith("view:")) {
0604: // check for a View
0605: Debug.logInfo(
0606: "[RequestHandler.doRequest]: Response is a view."
0607: + " sessionId="
0608: + UtilHttp.getSessionId(request),
0609: module);
0610: nextView = nextView.substring(5);
0611: renderView(nextView, requestManager
0612: .allowExtView(requestUri), request, response);
0613: } else if (nextView != null && nextView.startsWith("none:")) {
0614: // check for a no dispatch return (meaning the return was processed by the event
0615: Debug.logInfo(
0616: "[RequestHandler.doRequest]: Response is handled by the event."
0617: + " sessionId="
0618: + UtilHttp.getSessionId(request),
0619: module);
0620: } else if (nextView != null) {
0621: // a page request
0622: Debug.logInfo(
0623: "[RequestHandler.doRequest]: Response is a page ["
0624: + nextView + "]" + " sessionId="
0625: + UtilHttp.getSessionId(request),
0626: module);
0627: renderView(nextView, requestManager
0628: .allowExtView(requestUri), request, response);
0629: } else {
0630: // unknown request
0631: throw new RequestHandlerException(
0632: "Illegal response; handler could not process ["
0633: + eventReturnString + "].");
0634: }
0635: }
0636: }
0637:
0638: /** Find the event handler and invoke an event. */
0639: public String runEvent(HttpServletRequest request,
0640: HttpServletResponse response, String type, String path,
0641: String method) throws EventHandlerException {
0642: EventHandler eventHandler = eventFactory.getEventHandler(type);
0643: return eventHandler.invoke(path, method, request, response);
0644: }
0645:
0646: /** Returns the default error page for this request. */
0647: public String getDefaultErrorPage(HttpServletRequest request) {
0648: //String requestUri = RequestHandler.getRequestUri(request.getPathInfo());
0649: //return requestManager.getErrorPage(requestUri);
0650: return requestManager.getDefaultErrorPage();
0651: }
0652:
0653: public String makeQueryString(HttpServletRequest request) {
0654: Map paramMap = UtilHttp.getParameterMap(request);
0655: StringBuffer queryString = new StringBuffer();
0656: if (paramMap != null && paramMap.size() > 0) {
0657: queryString.append("?");
0658: Iterator i = paramMap.keySet().iterator();
0659: while (i.hasNext()) {
0660: String name = (String) i.next();
0661: Object value = paramMap.get(name);
0662: if (value instanceof String) {
0663: if (queryString.length() > 1) {
0664: queryString.append("&");
0665: }
0666: queryString.append(name);
0667: queryString.append("=");
0668: queryString.append(value);
0669: }
0670: }
0671: }
0672: return queryString.toString();
0673: }
0674:
0675: /** Returns the RequestManager Object. */
0676: public RequestManager getRequestManager() {
0677: return requestManager;
0678: }
0679:
0680: /** Returns the ServletContext Object. */
0681: public ServletContext getServletContext() {
0682: return context;
0683: }
0684:
0685: /** Returns the ViewFactory Object. */
0686: public ViewFactory getViewFactory() {
0687: return viewFactory;
0688: }
0689:
0690: /** Returns the EventFactory Object. */
0691: public EventFactory getEventFactory() {
0692: return eventFactory;
0693: }
0694:
0695: public static String getRequestUri(String path) {
0696: List pathInfo = StringUtil.split(path, "/");
0697: if (pathInfo == null || pathInfo.size() == 0) {
0698: Debug.logWarning("Got nothing when splitting URI: " + path,
0699: module);
0700: return null;
0701: }
0702: if (((String) pathInfo.get(0)).indexOf('?') > -1) {
0703: return ((String) pathInfo.get(0)).substring(0,
0704: ((String) pathInfo.get(0)).indexOf('?'));
0705: } else {
0706: return (String) pathInfo.get(0);
0707: }
0708: }
0709:
0710: public static String getNextPageUri(String path) {
0711: List pathInfo = StringUtil.split(path, "/");
0712: String nextPage = null;
0713: if (pathInfo == null) {
0714: return nextPage;
0715: }
0716:
0717: for (int i = 1; i < pathInfo.size(); i++) {
0718: String element = (String) pathInfo.get(i);
0719: if (element.indexOf('~') != 0) {
0720: if (element.indexOf('?') > -1) {
0721: element = element
0722: .substring(0, element.indexOf('?'));
0723: }
0724: if (i == 1) {
0725: nextPage = element;
0726: } else {
0727: nextPage = (nextPage == null ? element : nextPage
0728: + "/" + element);
0729: }
0730: }
0731: }
0732: return nextPage;
0733: }
0734:
0735: private void callRedirect(String url, HttpServletResponse resp,
0736: HttpServletRequest req) throws RequestHandlerException {
0737: if (Debug.infoOn())
0738: Debug.logInfo("[Sending redirect]: " + url + " sessionId="
0739: + UtilHttp.getSessionId(req), module);
0740: // set the attributes in the session so we can access it.
0741: java.util.Enumeration attributeNameEnum = req
0742: .getAttributeNames();
0743: Map reqAttrMap = FastMap.newInstance();
0744: while (attributeNameEnum.hasMoreElements()) {
0745: String name = (String) attributeNameEnum.nextElement();
0746: Object obj = req.getAttribute(name);
0747: if (obj instanceof Serializable) {
0748: reqAttrMap.put(name, obj);
0749: }
0750: }
0751: if (reqAttrMap.size() > 0) {
0752: reqAttrMap.remove("_REQUEST_HANDLER_"); // RequestHandler is not serializable and must be removed first. See http://issues.apache.org/jira/browse/OFBIZ-750
0753: byte[] reqAttrMapBytes = UtilObject.getBytes(reqAttrMap);
0754: if (reqAttrMapBytes != null) {
0755: req.getSession().setAttribute("_REQ_ATTR_MAP_",
0756: StringUtil.toHexString(reqAttrMapBytes));
0757: }
0758: }
0759:
0760: // send the redirect
0761: try {
0762: resp.sendRedirect(url);
0763: } catch (IOException ioe) {
0764: throw new RequestHandlerException(ioe.getMessage(), ioe);
0765: } catch (IllegalStateException ise) {
0766: throw new RequestHandlerException(ise.getMessage(), ise);
0767: }
0768: }
0769:
0770: private void renderView(String view, boolean allowExtView,
0771: HttpServletRequest req, HttpServletResponse resp)
0772: throws RequestHandlerException {
0773: GenericValue userLogin = (GenericValue) req.getSession()
0774: .getAttribute("userLogin");
0775: GenericDelegator delegator = (GenericDelegator) req
0776: .getAttribute("delegator");
0777: // workaraound if we are in the root webapp
0778: String cname = UtilHttp.getApplicationName(req);
0779: String oldView = view;
0780:
0781: if (view != null && view.length() > 0 && view.charAt(0) == '/')
0782: view = view.substring(1);
0783:
0784: // if the view name starts with the control servlet name and a /, then it was an
0785: // attempt to override the default view with a call back into the control servlet,
0786: // so just get the target view name and use that
0787: String servletName = req.getServletPath().substring(1);
0788:
0789: Debug.logInfo("servletName=" + servletName + ", view=" + view
0790: + " sessionId=" + UtilHttp.getSessionId(req), module);
0791: if (view.startsWith(servletName + "/")) {
0792: view = view.substring(servletName.length() + 1);
0793: Debug
0794: .logInfo(
0795: "a manual control servlet request was received, removing control servlet path resulting in: view="
0796: + view, module);
0797: }
0798:
0799: if (Debug.verboseOn())
0800: Debug.logVerbose("[Getting View Map]: " + view
0801: + " sessionId=" + UtilHttp.getSessionId(req),
0802: module);
0803:
0804: // before mapping the view, set a session attribute so we know where we are
0805: req.setAttribute("_CURRENT_VIEW_", view);
0806:
0807: String viewType = requestManager.getViewType(view);
0808: String tempView = requestManager.getViewPage(view);
0809: String nextPage;
0810:
0811: if (tempView == null) {
0812: if (!allowExtView) {
0813: throw new RequestHandlerException("No view to render.");
0814: } else {
0815: nextPage = "/" + oldView;
0816: }
0817: } else {
0818: nextPage = tempView;
0819: }
0820:
0821: if (Debug.verboseOn())
0822: Debug.logVerbose("[Mapped To]: " + nextPage + " sessionId="
0823: + UtilHttp.getSessionId(req), module);
0824:
0825: long viewStartTime = System.currentTimeMillis();
0826:
0827: // setup chararcter encoding and content type
0828: String charset = getServletContext()
0829: .getInitParameter("charset");
0830:
0831: if (charset == null || charset.length() == 0)
0832: charset = req.getCharacterEncoding();
0833: if (charset == null || charset.length() == 0)
0834: charset = "UTF-8";
0835:
0836: String viewCharset = requestManager.getViewEncoding(view);
0837: //NOTE: if the viewCharset is "none" then no charset will be used
0838: if (viewCharset != null && viewCharset.length() > 0)
0839: charset = viewCharset;
0840:
0841: if (!"none".equals(charset)) {
0842: try {
0843: req.setCharacterEncoding(charset);
0844: } catch (UnsupportedEncodingException e) {
0845: throw new RequestHandlerException(
0846: "Could not set character encoding to "
0847: + charset, e);
0848: } catch (IllegalStateException e) {
0849: Debug
0850: .logInfo(
0851: e,
0852: "Could not set character encoding to "
0853: + charset
0854: + ", something has probably already committed the stream",
0855: module);
0856: }
0857: }
0858:
0859: // setup content type
0860: String contentType = "text/html";
0861: String viewContentType = requestManager
0862: .getViewContentType(view);
0863: if (viewContentType != null && viewContentType.length() > 0)
0864: contentType = viewContentType;
0865:
0866: if (charset.length() > 0 && !"none".equals(charset)) {
0867: resp.setContentType(contentType + "; charset=" + charset);
0868: } else {
0869: resp.setContentType(contentType);
0870: }
0871:
0872: if (Debug.verboseOn())
0873: Debug.logVerbose("The ContentType for the " + view
0874: + " view is: " + contentType, module);
0875:
0876: try {
0877: if (Debug.verboseOn())
0878: Debug.logVerbose("Rendering view [" + nextPage
0879: + "] of type [" + viewType + "]", module);
0880: ViewHandler vh = viewFactory.getViewHandler(viewType);
0881: vh.render(view, nextPage, requestManager.getViewInfo(view),
0882: contentType, charset, req, resp);
0883: } catch (ViewHandlerException e) {
0884: Throwable throwable = e.getNested() != null ? e.getNested()
0885: : e;
0886:
0887: throw new RequestHandlerException(e.getNonNestedMessage(),
0888: throwable);
0889: }
0890:
0891: // before getting the view generation time flush the response output to get more consistent results
0892: try {
0893: resp.flushBuffer();
0894: } catch (java.io.IOException e) {
0895: throw new RequestHandlerException(
0896: "Error flushing response buffer", e);
0897: }
0898:
0899: String vname = (String) req.getAttribute("_CURRENT_VIEW_");
0900:
0901: if (vname != null) {
0902: ServerHitBin.countView(cname + "." + vname, req,
0903: viewStartTime, System.currentTimeMillis()
0904: - viewStartTime, userLogin, delegator);
0905: }
0906: }
0907:
0908: public static String getDefaultServerRootUrl(
0909: HttpServletRequest request, boolean secure) {
0910: String httpsPort = UtilProperties.getPropertyValue(
0911: "url.properties", "port.https", "443");
0912: String httpsServer = UtilProperties.getPropertyValue(
0913: "url.properties", "force.https.host");
0914: String httpPort = UtilProperties.getPropertyValue(
0915: "url.properties", "port.http", "80");
0916: String httpServer = UtilProperties.getPropertyValue(
0917: "url.properties", "force.http.host");
0918: boolean useHttps = UtilProperties
0919: .propertyValueEqualsIgnoreCase("url.properties",
0920: "port.https.enabled", "Y");
0921:
0922: StringBuffer newURL = new StringBuffer();
0923:
0924: if (secure && useHttps) {
0925: String server = httpsServer;
0926: if (server == null || server.length() == 0) {
0927: server = request.getServerName();
0928: }
0929:
0930: newURL.append("https://");
0931: newURL.append(server);
0932: if (!httpsPort.equals("443")) {
0933: newURL.append(":").append(httpsPort);
0934: }
0935:
0936: } else {
0937: String server = httpServer;
0938: if (server == null || server.length() == 0) {
0939: server = request.getServerName();
0940: }
0941:
0942: newURL.append("http://");
0943: newURL.append(server);
0944: if (!httpPort.equals("80")) {
0945: newURL.append(":").append(httpPort);
0946: }
0947: }
0948: return newURL.toString();
0949: }
0950:
0951: public String makeLinkWithQueryString(HttpServletRequest request,
0952: HttpServletResponse response, String url) {
0953: String initialLink = this .makeLink(request, response, url);
0954: String queryString = this .makeQueryString(request);
0955: return initialLink + queryString;
0956: }
0957:
0958: public String makeLink(HttpServletRequest request,
0959: HttpServletResponse response, String url) {
0960: return makeLink(request, response, url, false, false, true);
0961: }
0962:
0963: public String makeLink(HttpServletRequest request,
0964: HttpServletResponse response, String url, boolean fullPath,
0965: boolean secure, boolean encode) {
0966: GenericDelegator delegator = (GenericDelegator) request
0967: .getAttribute("delegator");
0968: String webSiteId = WebSiteWorker.getWebSiteId(request);
0969:
0970: String httpsPort = null;
0971: String httpsServer = null;
0972: String httpPort = null;
0973: String httpServer = null;
0974: Boolean enableHttps = null;
0975:
0976: // load the properties from the website entity
0977: GenericValue webSite;
0978: if (webSiteId != null) {
0979: try {
0980: webSite = delegator.findByPrimaryKeyCache("WebSite",
0981: UtilMisc.toMap("webSiteId", webSiteId));
0982: if (webSite != null) {
0983: httpsPort = webSite.getString("httpsPort");
0984: httpsServer = webSite.getString("httpsHost");
0985: httpPort = webSite.getString("httpPort");
0986: httpServer = webSite.getString("httpHost");
0987: enableHttps = webSite.getBoolean("enableHttps");
0988: }
0989: } catch (GenericEntityException e) {
0990: Debug
0991: .logWarning(
0992: e,
0993: "Problems with WebSite entity; using global defaults",
0994: module);
0995: }
0996: }
0997:
0998: // fill in any missing properties with fields from the global file
0999: if (UtilValidate.isEmpty(httpsPort)) {
1000: httpsPort = UtilProperties.getPropertyValue(
1001: "url.properties", "port.https", "443");
1002: }
1003: if (UtilValidate.isEmpty(httpServer)) {
1004: httpsServer = UtilProperties.getPropertyValue(
1005: "url.properties", "force.https.host");
1006: }
1007: if (UtilValidate.isEmpty(httpPort)) {
1008: httpPort = UtilProperties.getPropertyValue(
1009: "url.properties", "port.http", "80");
1010: }
1011: if (UtilValidate.isEmpty(httpServer)) {
1012: httpServer = UtilProperties.getPropertyValue(
1013: "url.properties", "force.http.host");
1014: }
1015: if (enableHttps == null) {
1016: enableHttps = Boolean.valueOf(UtilProperties
1017: .propertyValueEqualsIgnoreCase("url.properties",
1018: "port.https.enabled", "Y"));
1019: }
1020:
1021: // create the path the the control servlet
1022: String controlPath = (String) request
1023: .getAttribute("_CONTROL_PATH_");
1024:
1025: String requestUri = RequestHandler.getRequestUri(url);
1026: StringBuffer newURL = new StringBuffer();
1027:
1028: boolean useHttps = enableHttps.booleanValue();
1029: boolean didFullSecure = false;
1030: boolean didFullStandard = false;
1031: if (useHttps || fullPath || secure) {
1032: if (secure
1033: || (useHttps
1034: && requestManager.requiresHttps(requestUri) && !request
1035: .isSecure())) {
1036: String server = httpsServer;
1037: if (server == null || server.length() == 0) {
1038: server = request.getServerName();
1039: }
1040:
1041: newURL.append("https://");
1042: newURL.append(server);
1043: if (!httpsPort.equals("443")) {
1044: newURL.append(":").append(httpsPort);
1045: }
1046:
1047: didFullSecure = true;
1048: } else if (fullPath
1049: || (useHttps
1050: && !requestManager
1051: .requiresHttps(requestUri) && request
1052: .isSecure())) {
1053: String server = httpServer;
1054: if (server == null || server.length() == 0) {
1055: server = request.getServerName();
1056: }
1057:
1058: newURL.append("http://");
1059: newURL.append(server);
1060: if (!httpPort.equals("80")) {
1061: newURL.append(":").append(httpPort);
1062: }
1063:
1064: didFullStandard = true;
1065: }
1066: }
1067:
1068: newURL.append(controlPath);
1069:
1070: // now add the actual passed url, but if it doesn't start with a / add one first
1071: if (!url.startsWith("/")) {
1072: newURL.append("/");
1073: }
1074: newURL.append(url);
1075:
1076: String encodedUrl;
1077: if (encode) {
1078: boolean forceManualJsessionid = false;
1079:
1080: // if this isn't a secure page, but we made a secure URL, make sure we manually add the jsessionid since the response.encodeURL won't do that
1081: if (!request.isSecure() && didFullSecure) {
1082: forceManualJsessionid = true;
1083: }
1084:
1085: // if this is a secure page, but we made a standard URL, make sure we manually add the jsessionid since the response.encodeURL won't do that
1086: if (request.isSecure() && didFullStandard) {
1087: forceManualJsessionid = true;
1088: }
1089:
1090: if (response != null && !forceManualJsessionid) {
1091: encodedUrl = response.encodeURL(newURL.toString());
1092: } else {
1093: String sessionId = ";jsessionid="
1094: + request.getSession().getId();
1095: // this should be inserted just after the "?" for the parameters, if there is one, or at the end of the string
1096: int questionIndex = newURL.indexOf("?");
1097: if (questionIndex == -1) {
1098: newURL.append(sessionId);
1099: } else {
1100: newURL.insert(questionIndex, sessionId);
1101: }
1102: encodedUrl = newURL.toString();
1103: }
1104: } else {
1105: encodedUrl = newURL.toString();
1106: }
1107: //if (encodedUrl.indexOf("null") > 0) {
1108: //Debug.logError("in makeLink, controlPath:" + controlPath + " url:" + url, "");
1109: //throw new RuntimeException("in makeLink, controlPath:" + controlPath + " url:" + url);
1110: //}
1111:
1112: //Debug.logInfo("Making URL, encode=" + encode + " for URL: " + newURL + "\n encodedUrl: " + encodedUrl, module);
1113:
1114: return encodedUrl;
1115: }
1116:
1117: public static String makeUrl(HttpServletRequest request,
1118: HttpServletResponse response, String url) {
1119: return makeUrl(request, response, url, false, false, false);
1120: }
1121:
1122: public static String makeUrl(HttpServletRequest request,
1123: HttpServletResponse response, String url, boolean fullPath,
1124: boolean secure, boolean encode) {
1125: ServletContext ctx = (ServletContext) request
1126: .getAttribute("servletContext");
1127: RequestHandler rh = (RequestHandler) ctx
1128: .getAttribute("_REQUEST_HANDLER_");
1129: return rh.makeLink(request, response, url, fullPath, secure,
1130: encode);
1131: }
1132:
1133: public void runAfterLoginEvents(HttpServletRequest request,
1134: HttpServletResponse response) {
1135: List afterLoginEvents = requestManager.getAfterLoginEventList();
1136: if (afterLoginEvents != null) {
1137: Iterator i = afterLoginEvents.iterator();
1138: while (i.hasNext()) {
1139: Map eventMap = (Map) i.next();
1140: String eType = (String) eventMap
1141: .get(ConfigXMLReader.EVENT_TYPE);
1142: String ePath = (String) eventMap
1143: .get(ConfigXMLReader.EVENT_PATH);
1144: String eMeth = (String) eventMap
1145: .get(ConfigXMLReader.EVENT_METHOD);
1146: try {
1147: String returnString = this .runEvent(request,
1148: response, eType, ePath, eMeth);
1149: if (returnString != null
1150: && !returnString
1151: .equalsIgnoreCase("success")) {
1152: throw new EventHandlerException(
1153: "Pre-Processor event did not return 'success'.");
1154: }
1155: } catch (EventHandlerException e) {
1156: Debug.logError(e, module);
1157: }
1158: }
1159: }
1160: }
1161:
1162: public void runBeforeLogoutEvents(HttpServletRequest request,
1163: HttpServletResponse response) {
1164: List beforeLogoutEvents = requestManager
1165: .getBeforeLogoutEventList();
1166: if (beforeLogoutEvents != null) {
1167: Iterator i = beforeLogoutEvents.iterator();
1168: while (i.hasNext()) {
1169: Map eventMap = (Map) i.next();
1170: String eType = (String) eventMap
1171: .get(ConfigXMLReader.EVENT_TYPE);
1172: String ePath = (String) eventMap
1173: .get(ConfigXMLReader.EVENT_PATH);
1174: String eMeth = (String) eventMap
1175: .get(ConfigXMLReader.EVENT_METHOD);
1176: try {
1177: String returnString = this .runEvent(request,
1178: response, eType, ePath, eMeth);
1179: if (returnString != null
1180: && !returnString
1181: .equalsIgnoreCase("success")) {
1182: throw new EventHandlerException(
1183: "Pre-Processor event did not return 'success'.");
1184: }
1185: } catch (EventHandlerException e) {
1186: Debug.logError(e, module);
1187: }
1188: }
1189: }
1190: }
1191: }
|