/*
* WebWork, Web Application Framework
*
* Distributable under Apache license.
* See terms of license at opensource.org
*/
package org.infoglue.deliver.portal.dispatcher;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.infoglue.cms.security.InfoGluePrincipal;
import org.infoglue.cms.util.CmsPropertyHandler;
import org.infoglue.deliver.util.Timer;
import webwork.action.Action;
import webwork.action.ActionContext;
import webwork.action.ServletActionContext;
import webwork.dispatcher.ActionResult;
import webwork.dispatcher.GenericDispatcher;
import webwork.dispatcher.ServletDispatcher;
import webwork.util.ServletValueStack;
/**
* Main dispatcher servlet. It works in three phases: first propagate all
* parameters to the command JavaBean. Second, call execute() to let the
* JavaBean create the result data. Third, delegate to the JSP that corresponds to
* the result state that was chosen by the JavaBean.
*
* The command JavaBeans can be found in a package prefixed with either
* of the package names in the comma-separated "packages" servlet init parameter.
*
* Modified by Raymond Lai (alpha2_valen@yahoo.com) on 1 Nov 2003:
* modified wrapRequest() to set the character encoding of HttpServletRequest
* using the parameter "webwork.i18n.encoding" in webwork.properties.
*
*/
public class DeliveryServletDispatcher extends ServletDispatcher
{
private String actionExtension = ".action";
private static URLClassLoader classLoader = null;
/**
* Service a request.
* The request is first checked to see if it is a multi-part. If it is, then the request
* is wrapped so WW will be able to work with the multi-part as if it was a normal request.
* Next, we will process all actions until an action returns a non-action which is usually
* a view. For each action in a chain, the action's context will be first set and then the
* action will be instantiated. Next, the previous action if this action isn't the first in
* the chain will have its attributes copied to the current action.
*
* @param aRequest
* @param aResponse
* @exception ServletException
*/
public void service(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletException
{
try
{
if(classLoader == null)
{
Timer t = new Timer();
//logger.info("Setting our own classloaders - smart for:" + CmsPropertyHandler.getContextRootPath());
String extensionBasePath = CmsPropertyHandler.getContextRootPath() + "WEB-INF" + File.separator + "libextensions";
File extensionBaseFile = new File(extensionBasePath);
extensionBaseFile.mkdirs();
File[] extensionFiles = extensionBaseFile.listFiles();
List<URL> urls = new ArrayList<URL>();
for(File extensionFile : extensionFiles)
{
if(extensionFile.getName().endsWith(".jar"))
{
//ClassLoaderUtil.addFile(extensionFile.getPath());
//logger.info("extensionFile:" + extensionFile.getPath());
URL url = extensionFile.toURL();
urls.add(url);
}
}
URL[] urlsArray = new URL[urls.size()];
int i = 0;
for(URL url : urls)
{
urlsArray[i] = url;
i++;
}
classLoader = new URLClassLoader(urlsArray, this.getClass().getClassLoader());
//t.printElapsedTime("Creating classloader took");
}
Thread.currentThread().setContextClassLoader(classLoader);
//logger.info("ClassLoader in context for thread:" + Thread.currentThread().getId() + ":" + Thread.currentThread().getContextClassLoader().getClass().getName());
}
catch (Throwable t)
{
t.printStackTrace();
}
//wrap request if needed
if(CmsPropertyHandler.getApplicationName().equalsIgnoreCase("cms"))
{
String servletPath = (String) aRequest.getAttribute("javax.servlet.include.servlet_path");
if (servletPath == null)
servletPath = aRequest.getServletPath();
//logger.info("servletPath:" + servletPath);
super.service(aRequest, aResponse);
return;
}
// Get action
String servletPath = (String) aRequest.getAttribute("javax.servlet.include.servlet_path");
if (servletPath == null)
servletPath = aRequest.getServletPath();
//logger.info("servletPath:" + servletPath);
String actionName = getActionName(servletPath);
GenericDispatcher gd = new GenericDispatcher(actionName, false);
ActionContext context = gd.prepareContext();
//logger.info("actionName:" + actionName);
InfoGluePrincipal principal = (InfoGluePrincipal)aRequest.getSession().getAttribute("infogluePrincipal");
if(principal != null)
aRequest.setAttribute("infoglueRemoteUser", principal.getName());
aRequest.setAttribute("webwork.request_url", aRequest.getRequestURL());
ServletActionContext.setContext(aRequest, aResponse, getServletContext(), actionName);
gd.prepareValueStack();
ActionResult ar = null;
try
{
gd.executeAction();
ar = gd.finish();
}
catch (Throwable e)
{
log.warn("Could not execute action:" + e.getMessage());
try
{
aResponse.sendError(404, "Could not execute action [" + actionName + "]:" + e.getMessage() + getHTMLErrorMessage(e));
}
catch (IOException e1)
{
}
}
if (ar != null && ar.getActionException() != null)
{
log.warn("Could not execute action:" + ar.getActionException().getMessage());
//log.error("Could not execute action", ar.getActionException());
try
{
aResponse.sendError(500, ar.getActionException().getMessage() + getHTMLErrorMessage(ar.getActionException()));
}
catch (IOException e1)
{
}
}
// check if no view exists
if (ar != null && ar.getResult() != null && ar.getView() == null && !ar.getResult().equals(Action.NONE)) {
try
{
aResponse.sendError(404, "No view for result [" + ar.getResult() + "] exists for action [" + actionName + "]");
}
catch (IOException e)
{
}
}
if (ar != null && ar.getView() != null && ar.getActionException() == null)
{
String view = ar.getView().toString();
log.debug("Result:" + view);
RequestDispatcher dispatcher = null;
try
{
dispatcher = aRequest.getRequestDispatcher(view);
}
catch (Throwable e)
{
// Ignore
}
if (dispatcher == null)
throw new ServletException("No presentation file with name '" + view + "' found!");
try
{
// If we're included, then include the view
// Otherwise do forward
// This allow the page to, for example, set content type
if (aRequest.getAttribute("javax.servlet.include.servlet_path") == null)
{
aRequest.setAttribute("webwork.view_uri", view);
aRequest.setAttribute("webwork.request_uri", aRequest.getRequestURI());
aRequest.setAttribute("webwork.request_url", aRequest.getRequestURL());
//aRequest.setAttribute("webwork.contextPath",aRequest.getContextPath());
dispatcher.forward(aRequest, aResponse);
}
else
{
//aRequest.setAttribute("webwork.request_uri",aRequest.getAttribute("javax.servlet.include.request_uri"));
//aRequest.setAttribute("webwork.contextPath",aRequest.getAttribute("javax.servlet.include.context_path"));
dispatcher.include(aRequest, aResponse);
}
}
catch (IOException e)
{
e.printStackTrace();
throw new ServletException(e);
}
catch (Exception e)
{
e.printStackTrace();
throw new ServletException(e);
}
finally
{
// Get last action from stack and and store it in request attribute STACK_HEAD
// It is then popped from the stack.
aRequest.setAttribute(STACK_HEAD, ServletValueStack.getStack(aRequest).popValue());
}
}
gd.finalizeContext();
}
/**
* Determine action name by extracting last string and removing
* extension. (/.../.../Foo.action -> Foo)
*/
private String getActionName(String name)
{
// Get action name ("Foo.action" -> "Foo" action)
int beginIdx = name.lastIndexOf("/");
int endIdx = name.lastIndexOf(actionExtension);
return name.substring((beginIdx == -1 ? 0 : beginIdx + 1),
endIdx == -1 ? name.length() : endIdx);
}
}