// // ERXDirectActionRequestHandler.java // Project ERExtensions // // Created by tatsuya on Thu Aug 15 2002 // package er.extensions.appserver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.webobjects.appserver.WOApplication; import com.webobjects.appserver.WOContext; import com.webobjects.appserver.WORequest; import com.webobjects.appserver.WOResponse; import com.webobjects.appserver.WOSession; import com.webobjects.appserver._private.WODirectActionRequestHandler; import com.webobjects.appserver._private.WOServerSessionStore; import er.extensions.foundation.ERXProperties; /** * Improved direct action request handler. Will automatically handle * character encodings and checks the {@link ERXWOResponseCache} before * actually calling the action. * * NOTE: This class is multi thread safe. * * @property er.extensions.ERXMessageEncoding.Enabled */ public class ERXDirectActionRequestHandler extends WODirectActionRequestHandler { private static final Logger log = LoggerFactory.getLogger(ERXDirectActionRequestHandler.class); /** caches if automatic message encoding is enabled, defaults to true */ protected static Boolean automaticMessageEncodingEnabled; /** * Allows the disabling of automatic message encoding. Useful for * backend services where you want to just use the default encoding. * @return if automatic message encoding is enabled. */ public static boolean automaticMessageEncodingEnabled() { if (automaticMessageEncodingEnabled == null) { automaticMessageEncodingEnabled = ERXProperties.booleanForKeyWithDefault("er.extensions.ERXMessageEncoding.Enabled", true) ? Boolean.TRUE : Boolean.FALSE; } return automaticMessageEncodingEnabled.booleanValue(); } public ERXDirectActionRequestHandler() { super(); } public ERXDirectActionRequestHandler(String actionClassName, String defaultActionName, boolean shouldAddToStatistics) { super(actionClassName, defaultActionName, shouldAddToStatistics); } /** * Return true if you want to handle the request even though the app is refusing new sessions. * Currently, this includes all urls with "stats" in them * @param request */ protected boolean isSystemRequest(WORequest request) { return request.requestHandlerPath() != null && request.requestHandlerPath().toLowerCase().indexOf("stats") >= 0; } @Override public WOResponse handleRequest(WORequest request) { WOResponse response = null; String actionName = null; Class actionClass = null; boolean shouldCacheResult = false; if (ERXWOResponseCache.sharedInstance().isEnabled()) { try { // Caching scheme for 5.2 applications. Will uncomment once we are building 5.2 only ERExtensions // CHECKME Object[] actionClassAndName = getRequestActionClassAndNameForPath(getRequestHandlerPathForRequest(request)); //Object[] actionClassAndName = null; if (actionClassAndName != null && actionClassAndName.length == 3) { actionName = (String)actionClassAndName[1]; actionClass = (Class)actionClassAndName[2]; if (ERXWOResponseCache.Cacheable.class.isAssignableFrom(actionClass)) { response = ERXWOResponseCache.sharedInstance().cachedResponseForRequest(actionClass, actionName, request); // we need to cache only when there was no previous response in the cache shouldCacheResult = (response == null); } } } catch (Exception e) { log.error("Caught exception checking for cache. Leaving it up to the regular exception handler to cache. Request: {}", request, e); } } if (response == null) { // ak: when addressed with a DA link with this instance's ID (and // an expired session) and the app is refusing new sessions, the // default implementation will create a session anyway, which will // wreak havoc if the app is memory starved. // Search engines are a nuisance in that regard WOApplication app = WOApplication.application(); if (app.isRefusingNewSessions() && request.isUsingWebServer() && !isSystemRequest(request)) { if (isSessionIDInRequest(request)) { // we know the imp of the server session store simply // looks up the ID in the registered sessions, // so we don't need to do the check-out/check-in // yadda-yadda. if (app.sessionStore().getClass() == WOServerSessionStore.class) { if (app.sessionStore().restoreSessionWithID(request.sessionID(), request) == null) { response = generateRequestRefusal(request); // AK: should be a permanent redirect, as the session is gone for good. // However, the adaptor checks explicitly on 302 so we return that... // It shouldn't matter which instance we go to now. response.setStatus(302); } } } else { // if no session was supplied, what are we doing here in the // first place? The adaptor shouldn't have linked to us as // we are refusing new sessions. response = generateRequestRefusal(request); } } if(response == null) { response = super.handleRequest(request); } } else { registerWillHandleActionRequest(); registerDidHandleActionRequestWithActionNamed(actionName); } if (shouldCacheResult && response != null) { try { ERXWOResponseCache.sharedInstance().cacheResponseForRequest(actionClass, actionName, request, response); } catch (Exception e) { log.error("Caught exception when caching response. Request: {}", request, e); } } if (automaticMessageEncodingEnabled()) { ERXMessageEncoding messageEncoding = null; // This should retrieve the session object belonging to the same // worker thread that's been calling the current handleRequest method. WOSession session; if(false) { // ak only enable when fixed // as we will create deadlocks checking out the session this early. WOContext context = ERXWOContext.currentContext(); session = context != null ? context.session() : null; } else { session = ERXSession.anySession(); // get it from the thread specific storage } if (session != null && session instanceof ERXSession) { ERXSession erxSession = (ERXSession)session; messageEncoding = erxSession.messageEncoding(); erxSession.lastActionWasDA = true; } else if (request instanceof ERXRequest) { ERXBrowser browser = ((ERXRequest)request).browser(); messageEncoding = browser.messageEncodingForRequest(request); } else { messageEncoding = new ERXMessageEncoding(request.browserLanguages()); } messageEncoding.setEncodingToResponse(response); } return response; } }