package org.jboss.seam.wicket.web;
import static org.jboss.seam.annotations.Install.BUILT_IN;
import static org.jboss.seam.util.Resources.getRealFile;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.NotFoundException;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import org.apache.wicket.protocol.http.WicketFilter;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Unwrap;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.jboss.seam.servlet.ServletApplicationMap;
import org.jboss.seam.web.FilterConfigWrapper;
import org.jboss.seam.wicket.WebApplication;
import org.jboss.seam.wicket.ioc.WicketClassLoader;
/**
* This component wraps the WicketFilter, encapsulates the class dependencies
* upon the wicket library, and propogates the configuration from seam's own
* WicketFilter, specified with web:wicket-wilter. It also sets up the WicketClassLoader
* to instrument wicket components on the fly, if necessary.
*
*/
@Name("org.jboss.seam.wicket.web.wicketFilterInstantiator")
@Install(precedence = BUILT_IN, classDependencies={"org.apache.wicket.Application"})
@BypassInterceptors
@Scope(ScopeType.STATELESS)
public class WicketFilterInstantiator
{
public static String DEFAULT_WICKET_COMPONENT_DIRECTORY_PATH = "WEB-INF/wicket";
private static LogProvider log = Logging.getLogProvider(WicketFilterInstantiator.class);
@Unwrap
public Filter unrwap()
{
return new WicketFilter()
{
private ClassLoader classLoader;
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
try
{
// We need the Application context active in order to lookup the WebApplication component
Lifecycle.setupApplication(new ServletApplicationMap(filterConfig.getServletContext()));
Map<String, String> parameters = new HashMap<String, String>();
try
{
ClassLoader parent = Thread.currentThread().getContextClassLoader();
/* if there is a directory specified for which we should instrument wicket components,
* create a WicketClassLoader to do that. Otherwise, just use the contextClassLoader
*/
File dir = getRealFile(filterConfig.getServletContext(), DEFAULT_WICKET_COMPONENT_DIRECTORY_PATH);
if (dir == null)
{
log.warn("No wicket components directory specified to give Seam super powers to");
this.classLoader = parent;
}
else
{
this.classLoader = new WicketClassLoader(Thread.currentThread().getContextClassLoader(), new ClassPool(), dir).instrument();
}
}
catch (NotFoundException e)
{
throw new ServletException(e);
}
catch (CannotCompileException e)
{
throw new ServletException(e);
}
catch (ClassNotFoundException e)
{
throw new ServletException(e);
}
/*
* If no applicationClassName has been specified on the filter, use the name specified with
* <wicket:web-application/> in components.xml
*/
if (filterConfig.getInitParameter("applicationClassName") == null)
{
String applicationClass = WebApplication.instance().getApplicationClass();
if (applicationClass != null)
{
parameters.put("applicationClassName", applicationClass);
}
else
{
throw new IllegalStateException("Must set application-class using <wicket:web-application /> in components.xml");
}
}
super.init(new FilterConfigWrapper(filterConfig, parameters));
}
finally
{
Lifecycle.cleanupApplication();
}
}
@Override
protected ClassLoader getClassLoader()
{
return classLoader;
}
};
}
}