package com.foundation.web;
import java.io.InputStream;
import java.net.URI;
import com.common.debug.Debug;
import com.common.io.StreamSupport;
import com.common.thread.IRunnable;
import com.common.util.IHashMap;
import com.common.util.LiteHashMap;
import com.foundation.web.WebApplication.PathSubstitution;
import com.foundation.web.interfaces.IConnectionContext;
import com.foundation.web.interfaces.IRequest;
import com.foundation.web.interfaces.IResponse;
import com.foundation.web.interfaces.ISession;
import com.foundation.web.interfaces.IWebApplication;
import com.foundation.web.SessionData;
import com.foundation.web.SecureSessionData;
/**
* Allows the application to specify special handling for access to static resources.
*/
public abstract class ResourceRequestHandler {
/** The framework.js source. */
private String frameworkJavascript;
/**
* ResourceRequestHandler constructor.
*/
public ResourceRequestHandler() {
try {
InputStream in = getClass().getClassLoader().getResourceAsStream("framework.js");
if(in != null) {
try {
frameworkJavascript = StreamSupport.readText(in, "UTF8");
}//try//
finally {
try {in.close();} catch(Throwable e) {}
}//finally//
}//if//
else {
Debug.log("Warning: framework.js not found!");
}//else//
}//try//
catch(Throwable e) {
Debug.log("Failed to read the framework.js file from the framework jar.", e);
}//catch//
}//ResourceRequestHandler()//
/**
* Allows the handler to substitute one path for another.
* @param path The path that was provided by the client.
* @param request The request object.
* @param response The response object.
* @return The path to be used when locating the resource. May be null if no furthor processing of the request should be performed.
*/
protected String performPathSubstitution(String path, IRequest request, IResponse response) {
return path;
}//performPathSubstitution()//
/**
* Gets a resource from the file system. The implementor can validate that the user has the rights to access the resource and can ensure that there is an SSL connection if needed.
*
A simple implementation will simply call: response.setContentResource(requestPath, request.getCacheDate());, a more complex implementation will test for an SSL connection for secure resources, and will ensure the user is logged in and has rights to access the resource for rights oriented resources.
WARNING: The caller of this method synchronizes on the internal web server session for the client. Because of this, all code handling the request that requires session access *MUST* ensure this thread exits the method AFTER all worker threads that might be created or used. This is also important because the Response object should never be modified outside the scope of this method call.
* @param requestPath The path to the requested resource. This is the request's URI already mapped to an actual resource (same as calling request.getUri()). * @param request The request object. * @param response The response object. * @param sessionData The non-secure session data or null if there is none for the application. * @param secureSessionData The secure session data, or null if the request was made over an insecure connection or no secure session data exists. * @param isSecure Whether the request was made over a secure connection and provided the correct secure id. * @param connectionContext The context object for the connection (socket) between the client (web browser) and server (web server). */ public void processRequest(final IRequest request, final IResponse response, final SessionData sessionData, final SecureSessionData secureSessionData, final boolean isSecure, final IConnectionContext connectionContext) { int requestType = request.getRequestType(); boolean isGetPostOrHead = requestType == IRequest.TYPE_GET || requestType == IRequest.TYPE_POST || requestType == IRequest.TYPE_HEAD; boolean isWebdav = requestType == IRequest.TYPE_WEBDAV_COPY || requestType == IRequest.TYPE_WEBDAV_LOCK || requestType == IRequest.TYPE_WEBDAV_MKCOL || requestType == IRequest.TYPE_WEBDAV_MOVE || requestType == IRequest.TYPE_WEBDAV_PROPFIND || requestType == IRequest.TYPE_WEBDAV_PROPPATCH || requestType == IRequest.TYPE_WEBDAV_UNLOCK; String path = request.getUri(); IWebApplication webApplication = request.getWebApplication(); while(path != null) { path = performPathSubstitution(path, request, response); if(path != null) { boolean isFrameworkController = path.equals("/Framework") || path.equals("/Framework.java") || path.equals("/FrameworkController") || path.equals("/FrameworkController.java"); boolean isFrameworkJavascript = path.equals("/framework.js"); //Verification of rights to access the resource are handled by the IResourceRequestHandler setup by the application. If an IResourceRequestHandler is provided then it can perform any validation it sees fit prior to allowing access to the requested resource.// if((path.endsWith(".java") || isFrameworkController) && isGetPostOrHead) { try { final IWebRequestHandler handler; Object instance = null; if(isFrameworkController) { instance = new FrameworkController(); }//if// else { String clsName = path.replace('/', '.').substring(0, path.length() - 5); Class cls = null; if(clsName.startsWith(".")) { clsName = clsName.substring(1); }//if// cls = Class.forName(webApplication.getDefaultPackageName() + clsName); instance = cls.newInstance(); }//else// if(instance instanceof IWebRequestHandler) { handler = (IWebRequestHandler) instance; }//if// else { Debug.log(new RuntimeException("Unexpected class called by the client: " + instance.getClass().getName())); handler = null; }//else// if(handler != null) { final String requestPath = path; IRunnable runnable = new IRunnable() { public Object run() { processRequest(handler, requestPath, request, response, sessionData, secureSessionData, isSecure, connectionContext); return null; }//run()// }; //Ensure the request is processed on the correct thread.// if(sessionData != null && sessionData.getRequestHandler() != null) { //Note: This is a synchronous call, so no need to increment/decrement the activity counter on the web application container.// sessionData.getRequestHandler().execute(runnable, true); }//if// else { runnable.run(); }//else// }//if// }//try// catch(Throwable e) { Debug.log(e); response.setError(response.ERROR_TYPE_RESOURCE_NOT_FOUND); }//catch// }//if// else if(isGetPostOrHead) { if(isFrameworkJavascript) { JavascriptContent content = new JavascriptContent(frameworkJavascript); //Attempt to tell the client not to cache.// content.setCacheLength(content.CACHE_LENGTH_NEVER_CACHE); content.setExpiresDirective(null); response.setContent(content); }//if// else { processRequest(path, request, response, sessionData, secureSessionData, isSecure, connectionContext); }//else// }//else if// else if(isWebdav) { processWebDavRequest(path, request, response, sessionData, secureSessionData, isSecure, connectionContext); }//else if// else { //The request type is PUT or OPTIONS.// //TODO: Provide a way for applications to provide support for these requests. response.setError(IResponse.ERROR_TYPE_INVALID_ACCESS); }//else// if(response.getRedirectUri() != null) { try { path = new URI(path).resolve(new URI(response.getRedirectUri())).getPath(); }//try// catch(Throwable e) { Debug.log(e); //TODO: Use a better error - internal error. response.setError(IResponse.ERROR_TYPE_RESOURCE_NOT_FOUND); path = null; }//catch// response.setRedirectUri(null); }//if// else { path = null; }//else// }//if// }//while// }//processRequest()// /** * Gets a resource from the file system. The implementor can validate that the user has the rights to access the resource and can ensure that there is an SSL connection if needed. *A simple implementation will simply call: response.setContentResource(requestPath, request.getCacheDate());, a more complex implementation will test for an SSL connection for secure resources, and will ensure the user is logged in and has rights to access the resource for rights oriented resources.
A simple implementation will simply call: response.setContentResource(requestPath, request.getCacheDate());, a more complex implementation will test for an SSL connection for secure resources, and will ensure the user is logged in and has rights to access the resource for rights oriented resources.