Search in sources :

Example 11 with WOContext

use of com.webobjects.appserver.WOContext in project wonder-slim by undur.

the class JSONRequestHandler method handleRequest.

@SuppressWarnings("unchecked")
@Override
public WOResponse handleRequest(WORequest request) {
    WOApplication application = WOApplication.application();
    application.awake();
    try {
        WOContext context = application.createContextForRequest(request);
        WOResponse response = application.createResponseInContext(context);
        Object output;
        try {
            String inputString = request.contentString();
            JSONObject input = new JSONObject(inputString);
            String sessionIdKey = WOApplication.application().sessionIdKey();
            String sessionId = request.cookieValueForKey(sessionIdKey);
            if (sessionId == null) {
                ERXMutableURL url = new ERXMutableURL();
                url.setQueryParameters(request.queryString());
                sessionId = url.queryParameter(sessionIdKey);
                if (sessionId == null && input.has(sessionIdKey)) {
                    sessionId = input.getString(sessionIdKey);
                }
            }
            context._setRequestSessionID(sessionId);
            WOSession session = null;
            if (context._requestSessionID() != null) {
                session = WOApplication.application().restoreSessionWithID(sessionId, context);
            }
            if (session != null) {
                session.awake();
            }
            try {
                JSONComponentCallback componentCallback = null;
                WODynamicURL url = request._uriDecomposed();
                String requestHandlerPath = url.requestHandlerPath();
                JSONRPCBridge jsonBridge;
                if (requestHandlerPath != null && requestHandlerPath.length() > 0) {
                    String componentNameAndInstance = requestHandlerPath;
                    String componentInstance;
                    String componentName;
                    int slashIndex = componentNameAndInstance.indexOf('/');
                    if (slashIndex == -1) {
                        componentName = componentNameAndInstance;
                        componentInstance = null;
                    } else {
                        componentName = componentNameAndInstance.substring(0, slashIndex);
                        componentInstance = componentNameAndInstance.substring(slashIndex + 1);
                    }
                    if (session == null) {
                        session = context.session();
                    }
                    String bridgesKey = (componentInstance == null) ? "_JSONGlobalBridges" : "_JSONInstanceBridges";
                    Map<String, JSONRPCBridge> componentBridges = (Map<String, JSONRPCBridge>) session.objectForKey(bridgesKey);
                    if (componentBridges == null) {
                        int limit = ERXProperties.intForKeyWithDefault((componentInstance == null) ? "er.ajax.json.globalBacktrackCacheSize" : "er.ajax.json.backtrackCacheSize", WOApplication.application().pageCacheSize());
                        componentBridges = new LRUMap<>(limit);
                        session.setObjectForKey(componentBridges, bridgesKey);
                    }
                    jsonBridge = componentBridges.get(componentNameAndInstance);
                    if (jsonBridge == null) {
                        Class componentClass = _NSUtilities.classWithName(componentName);
                        JSONComponent component;
                        if (JSONComponent.class.isAssignableFrom(componentClass)) {
                            component = (JSONComponent) _NSUtilities.instantiateObject(componentClass, new Class[] { WOContext.class }, new Object[] { context }, true, false);
                        } else {
                            throw new SecurityException("There is no JSON component named '" + componentName + "'.");
                        }
                        jsonBridge = createBridgeForComponent(component, componentName, componentInstance, componentBridges);
                    }
                    componentCallback = new JSONComponentCallback(context);
                    jsonBridge.registerCallback(componentCallback, WOContext.class);
                } else {
                    jsonBridge = _sharedBridge;
                }
                try {
                    output = jsonBridge.call(new Object[] { request, response, context }, input);
                } finally {
                    if (componentCallback != null) {
                        jsonBridge.unregisterCallback(componentCallback, WOContext.class);
                    }
                }
                if (context._session() != null) {
                    WOSession contextSession = context._session();
                    // If this is a new session, then we have to force it to be a cookie session
                    if (sessionId == null) {
                        boolean storesIDsInCookies = contextSession.storesIDsInCookies();
                        try {
                            contextSession.setStoresIDsInCookies(true);
                            contextSession._appendCookieToResponse(response);
                        } finally {
                            contextSession.setStoresIDsInCookies(storesIDsInCookies);
                        }
                    } else {
                        contextSession._appendCookieToResponse(response);
                    }
                }
                response.appendContentString(output.toString());
                response._finalizeInContext(context);
                response.disableClientCaching();
            } finally {
                try {
                    if (session != null) {
                        session.sleep();
                    }
                } finally {
                    if (context._session() != null) {
                        WOApplication.application().saveSessionForContext(context);
                    }
                }
            }
        } catch (NoSuchElementException e) {
            e.printStackTrace();
            output = new JSONRPCResult(JSONRPCResult.CODE_ERR_NOMETHOD, null, JSONRPCResult.MSG_ERR_NOMETHOD);
        } catch (JSONException e) {
            e.printStackTrace();
            output = new JSONRPCResult(JSONRPCResult.CODE_ERR_PARSE, null, JSONRPCResult.MSG_ERR_PARSE);
        } catch (Throwable t) {
            t.printStackTrace();
            output = new JSONRPCResult(JSONRPCResult.CODE_ERR_PARSE, null, t.getMessage());
        }
        return response;
    } finally {
        application.sleep();
    }
}
Also used : ERXMutableURL(er.extensions.foundation.ERXMutableURL) WODynamicURL(com.webobjects.appserver.WODynamicURL) JSONRPCBridge(org.jabsorb.JSONRPCBridge) JSONException(org.json.JSONException) JSONRPCResult(org.jabsorb.JSONRPCResult) JSONObject(org.json.JSONObject) WOContext(com.webobjects.appserver.WOContext) WOSession(com.webobjects.appserver.WOSession) JSONObject(org.json.JSONObject) WOResponse(com.webobjects.appserver.WOResponse) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) WOApplication(com.webobjects.appserver.WOApplication) NoSuchElementException(java.util.NoSuchElementException)

Example 12 with WOContext

use of com.webobjects.appserver.WOContext in project wonder-slim by undur.

the class ERXResourceManager method urlForResourceNamed.

@Override
public String urlForResourceNamed(String name, String bundleName, NSArray<String> languages, WORequest request) {
    String completeURL = null;
    if (request == null || request.isUsingWebServer() && !WOApplication.application()._rapidTurnaroundActiveForAnyProject()) {
        completeURL = _cachedURLForResource(name, bundleName, languages, request);
    } else {
        URL url = pathURLForResourceNamed(name, bundleName, languages);
        String fileURL = null;
        if (url == null) {
            fileURL = "ERROR_NOT_FOUND_framework_" + (bundleName == null ? "*null*" : bundleName) + "_filename_" + (name == null ? "*null*" : name);
        } else {
            fileURL = url.toString();
            cacheDataIfNotInCache(fileURL);
        }
        String encoded = WOURLEncoder.encode(fileURL);
        String key = WOApplication.application().resourceRequestHandlerKey();
        if (WOApplication.application()._rapidTurnaroundActiveForAnyProject() && WOApplication.application().isDirectConnectEnabled()) {
            key = "_wr_";
        }
        WOContext context = (WOContext) request.valueForKey("context");
        String wodata = _NSStringUtilities.concat("wodata", "=", encoded);
        if (context != null) {
            completeURL = context.urlWithRequestHandlerKey(key, null, wodata);
        } else {
            StringBuilder sb = new StringBuilder(request.applicationURLPrefix());
            sb.append('/');
            sb.append(key);
            sb.append('?');
            sb.append(wodata);
            completeURL = sb.toString();
        }
        // AK: TODO get rid of regex
        int offset = completeURL.indexOf("?wodata=file%3A");
        if (offset >= 0) {
            completeURL = completeURL.replaceFirst("\\?wodata=file%3A", "/wodata=");
            if (completeURL.indexOf("/wodata=") > 0) {
                completeURL = completeURL.replaceAll("%2F", "/");
                // SWK: On Windows we have /C%3A/ changed to /C:
                completeURL = completeURL.replaceAll("%3A", ":");
            }
        }
    }
    completeURL = _versionManager.versionedUrlForResourceNamed(completeURL, name, bundleName, languages, request);
    completeURL = _postprocessURL(completeURL, bundleName);
    return completeURL;
}
Also used : WOContext(com.webobjects.appserver.WOContext) URL(java.net.URL) ERXMutableURL(er.extensions.foundation.ERXMutableURL)

Example 13 with WOContext

use of com.webobjects.appserver.WOContext in project wonder-slim by undur.

the class ERXAjaxSession method savePage.

/**
 * Overridden so that Ajax requests are not saved in the page cache.  Checks both the
 * response userInfo and the response headers if the DONT_STORE_PAGE key is present. The value doesn't matter.
 * <p>
 * Page Replacement cache is specifically designed to support component actions in Ajax updates.  The problem with
 * component actions in Ajax is that if you let them use the normal page cache, then after only 30 (or whatever your backtrack
 * cache is set to) updates from Ajax, you will fill your backtrack cache.  Unfortunately for the user, though, the backtrack cache
 * filled up with background ajax requests, so when the user clicks on a component action on the FOREGROUND page, the
 * foreground page has fallen out of the cache, and the request cannot be fulfilled (because its context is gone).  If you simply
 * turn off backtrack cache entirely for a request, then you can't have component actions inside of an Ajax updated area, because
 * the context of the Ajax update that generated the link will never get stored, and so you will ALWAYS get a backtrack error.
 * <p>
 * Enter page replacement cache.  If you look at the behavior of Ajax, it turns out that what you REALLY want is a hybrid page cache.  You
 * want to keep the backtrack of just the LAST update for a particular ajax component -- you don't care about its previous 29 states
 * because the user can't use the back button to get to them anyway, but if you have the MOST RECENT cached version of the page
 * then you can click on links in Ajax updated areas.  Page Replacement cache implements this logic.  For each Ajax component on
 * your page that is updating, it keeps a cache entry of its most recent backtrack state (note the difference between this and the
 * normal page cache.  The normal page cache contains one entry per user-backtrackable-request.  The replacement cache contains
 * one entry per Ajax component*, allowing up to replacement_page_cache_size many components per page). Each time the Ajax area
 * refreshes, the most recent state is replaced*.  When a restorePage request comes in, the replacement cache is checked first.  If
 * the replacement cache can service the page, then it does so.  If the replacement cache doesn't contain the context, then it
 * passes up to the standard page cache.  If you are not using Ajax, no replacement cache will exist in your session, and all the code
 * related to it will be skipped, so it should be minimally invasive under those conditions.
 * <p>
 * <b>*</b> It turns out that we have to keep the last TWO states, because of a race condition in the scenario where the replacement page
 * cache replaces context 2 with the context 3 update, but the user's browser hasn't been updated yet with the HTML from
 * context 3.  When the user clicks, they are clicking the context 2 link, which has now been removed from the replacement cache.
 * By keeping the last two states, you allow for the brief period where that transition occurs.
 * <p>
 * Random note (that I will find useful in 2 weeks when I forget this again): The first time through savePage, the request is saved
 * in the main cache.  It's only on a subsequent Ajax update that it uses page replacement cache.  So even though the cache
 * is keyed off of context ID, the explanation of the cache being components-per-page-sized works out because each component
 * is requesting in its own thread and generating their own non-overlapping context ids.
 */
@Override
public void savePage(WOComponent page) {
    WOContext context = context();
    if (ERXAjaxApplication.shouldNotStorePage(context)) {
        if (log.isDebugEnabled())
            log.debug("Considering pageReplacementCache for {} with contextID {}", context.request().uri(), context.contextID());
        WORequest request = context.request();
        WOResponse response = context.response();
        String pageCacheKey = null;
        if (response != null) {
            pageCacheKey = response.headerForKey(ERXAjaxSession.PAGE_REPLACEMENT_CACHE_LOOKUP_KEY);
        }
        if (pageCacheKey == null && request != null) {
            pageCacheKey = request.headerForKey(ERXAjaxSession.PAGE_REPLACEMENT_CACHE_LOOKUP_KEY);
        }
        // A null pageCacheKey should mean an Ajax request that is not returning a content update or an expliclty not cached non-Ajax request
        if (pageCacheKey != null) {
            log.debug("Will use pageCacheKey {}", pageCacheKey);
            String originalContextID = context.request().headerForKey(ERXAjaxSession.ORIGINAL_CONTEXT_ID_KEY);
            pageCacheKey = originalContextID + "_" + pageCacheKey;
            LinkedHashMap pageReplacementCache = (LinkedHashMap) objectForKey(ERXAjaxSession.PAGE_REPLACEMENT_CACHE_KEY);
            if (pageReplacementCache == null) {
                pageReplacementCache = new LinkedHashMap();
                setObjectForKey(pageReplacementCache, ERXAjaxSession.PAGE_REPLACEMENT_CACHE_KEY);
            }
            // Remove the oldest entry if we're about to add a new one and that would put us over the cache size ...
            // We do a CACHE_SIZE*2 here because for every page, we have to potentially store its previous contextid to prevent
            // race conditions, so there technically can be 2x cache size many pages in the cache.
            boolean removedCacheEntry = cleanPageReplacementCacheIfNecessary(pageCacheKey);
            if (!removedCacheEntry && pageReplacementCache.size() >= ERXAjaxSession.MAX_PAGE_REPLACEMENT_CACHE_SIZE * 2) {
                Iterator entryIterator = pageReplacementCache.entrySet().iterator();
                Map.Entry oldestEntry = (Map.Entry) entryIterator.next();
                entryIterator.remove();
                if (log.isDebugEnabled())
                    log.debug("{} pageReplacementCache too large, removing oldest entry = {}", pageCacheKey, ((TransactionRecord) oldestEntry.getValue()).key());
            }
            TransactionRecord pageRecord = new TransactionRecord(page, context, pageCacheKey);
            pageReplacementCache.put(context.contextID(), pageRecord);
            log.debug("{} new context = {}", pageCacheKey, context.contextID());
            log.debug("{} = {}", pageCacheKey, pageReplacementCache.keySet());
            ERXAjaxApplication.cleanUpHeaders(response);
        } else {
            // A null pageCacheKey should mean an Ajax request that is not returning a content update or an explicitly not cached non-Ajax request
            log.debug("Not caching as no pageCacheKey found");
        }
    } else {
        log.debug("Calling super.savePage for contextID {}", context.contextID());
        super.savePage(page);
    }
}
Also used : WORequest(com.webobjects.appserver.WORequest) Iterator(java.util.Iterator) WOContext(com.webobjects.appserver.WOContext) WOResponse(com.webobjects.appserver.WOResponse) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap)

Example 14 with WOContext

use of com.webobjects.appserver.WOContext in project wonder-slim by undur.

the class ERXWORepetition method appendToResponse.

@Override
public void appendToResponse(WOResponse woresponse, WOContext wocontext) {
    WOComponent wocomponent = wocontext.component();
    Context context = createContext(wocomponent);
    int count = _count(context, wocomponent);
    boolean checkHashCodes = checkHashCodes(wocomponent);
    log.debug("appendToResponse: {}", wocontext.elementID());
    for (int index = 0; index < count; index++) {
        _prepareForIterationWithIndex(context, index, wocontext, wocomponent, checkHashCodes);
        appendChildrenToResponse(woresponse, wocontext);
    }
    if (count > 0) {
        _cleanupAfterIteration(count, wocontext, wocomponent);
    }
}
Also used : WOContext(com.webobjects.appserver.WOContext) ERXWOContext(er.extensions.appserver.ERXWOContext) WOComponent(com.webobjects.appserver.WOComponent)

Example 15 with WOContext

use of com.webobjects.appserver.WOContext in project wonder-slim by undur.

the class ERXWORepetition method takeValuesFromRequest.

@Override
public void takeValuesFromRequest(WORequest worequest, WOContext wocontext) {
    WOComponent wocomponent = wocontext.component();
    Context context = createContext(wocomponent);
    int count = _count(context, wocomponent);
    boolean checkHashCodes = checkHashCodes(wocomponent);
    if (log.isDebugEnabled()) {
        log.debug("takeValuesFromRequest: {} - {}", wocontext.elementID(), wocontext.request().formValueKeys());
    }
    for (int index = 0; index < count; index++) {
        _prepareForIterationWithIndex(context, index, wocontext, wocomponent, checkHashCodes);
        super.takeValuesFromRequest(worequest, wocontext);
    }
    if (count > 0) {
        _cleanupAfterIteration(count, wocontext, wocomponent);
    }
}
Also used : WOContext(com.webobjects.appserver.WOContext) ERXWOContext(er.extensions.appserver.ERXWOContext) WOComponent(com.webobjects.appserver.WOComponent)

Aggregations

WOContext (com.webobjects.appserver.WOContext)15 WOComponent (com.webobjects.appserver.WOComponent)8 WOResponse (com.webobjects.appserver.WOResponse)5 ERXWOContext (er.extensions.appserver.ERXWOContext)5 WOApplication (com.webobjects.appserver.WOApplication)4 WOSession (com.webobjects.appserver.WOSession)3 LinkedHashMap (java.util.LinkedHashMap)3 WORequest (com.webobjects.appserver.WORequest)2 ERXMutableURL (er.extensions.foundation.ERXMutableURL)2 Map (java.util.Map)2 WOActionResults (com.webobjects.appserver.WOActionResults)1 WODynamicURL (com.webobjects.appserver.WODynamicURL)1 WOMultipartIterator (com.webobjects.appserver.WOMultipartIterator)1 WOStatisticsStore (com.webobjects.appserver.WOStatisticsStore)1 NSArray (com.webobjects.foundation.NSArray)1 NSDictionary (com.webobjects.foundation.NSDictionary)1 NSMutableArray (com.webobjects.foundation.NSMutableArray)1 NSMutableDictionary (com.webobjects.foundation.NSMutableDictionary)1 ERXRedirect (er.extensions.appserver.ERXRedirect)1 ERXUnitAwareDecimalFormat (er.extensions.formatters.ERXUnitAwareDecimalFormat)1