package com.metrink.croquet.wicket;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.wicket.IInitializer;
import org.apache.wicket.IPageFactory;
import org.apache.wicket.Page;
import org.apache.wicket.RuntimeConfigurationType;
import org.apache.wicket.authroles.authentication.AbstractAuthenticatedWebSession;
import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication;
import org.apache.wicket.authroles.authorization.strategies.role.Roles;
import org.apache.wicket.core.request.handler.PageProvider;
import org.apache.wicket.core.request.handler.RenderPageRequestHandler;
import org.apache.wicket.devutils.debugbar.DebugBar;
import org.apache.wicket.devutils.debugbar.InspectorDebugPanel;
import org.apache.wicket.devutils.debugbar.PageSizeDebugPanel;
import org.apache.wicket.devutils.debugbar.SessionSizeDebugPanel;
import org.apache.wicket.devutils.debugbar.VersionDebugContributor;
import org.apache.wicket.devutils.stateless.StatelessChecker;
import org.apache.wicket.extensions.Initializer;
import org.apache.wicket.markup.head.CssReferenceHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptReferenceHeaderItem;
import org.apache.wicket.markup.html.IHeaderContributor;
import org.apache.wicket.markup.html.IPackageResourceGuard;
import org.apache.wicket.markup.html.SecurePackageResourceGuard;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.cycle.AbstractRequestCycleListener;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.resource.CssResourceReference;
import org.apache.wicket.request.resource.IResource;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
import org.apache.wicket.request.resource.ResourceReference;
import org.apache.wicket.request.resource.UrlResourceReference;
import org.apache.wicket.resource.loader.InitializerStringResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.metrink.croquet.WicketSettings;
/**
* An AuthenticatedWebApplication class that implements sane defaults.
*
* You should extend this class if you wish to actually use authentication as
* this class simply allows anyone to hit any page. To implement authentication
* follow the directions found on the <a href="http://wicket.apache.org/learn/projects/authroles.html">Wicket site</a>.
*
*/
public class CroquetApplication extends AuthenticatedWebApplication {
private static final Logger LOG = LoggerFactory.getLogger(CroquetApplication.class);
private final IPageFactory pageFactory;
private final WicketSettings wicketSettings;
/**
* Constructs the CroquetApplication.
*
* Settings are injected via Guice and this application is run
* by Jetty & Wicket.
* @param pageFactory the page factory to use when constructing pages.
* @param wicketSettings settings for the application.
*/
@Inject
public CroquetApplication(final IPageFactory pageFactory, final WicketSettings wicketSettings) {
this.pageFactory = pageFactory;
this.wicketSettings = wicketSettings;
}
@Override
public void init() {
super.init();
// this is a bit of a hack to get the DebugToolbar working in deployment mode
if(wicketSettings.getWicketDebugToolbar() && wicketSettings.getDevelopment()) {
getDebugSettings().setDevelopmentUtilitiesEnabled(wicketSettings.getWicketDebugToolbar());
DebugBar.registerContributor(VersionDebugContributor.DEBUG_BAR_CONTRIB, this);
DebugBar.registerContributor(InspectorDebugPanel.DEBUG_BAR_CONTRIB, this);
DebugBar.registerContributor(SessionSizeDebugPanel.DEBUG_BAR_CONTRIB, this);
DebugBar.registerContributor(PageSizeDebugPanel.DEBUG_BAR_CONTRIB, this);
}
// check the mode we're running in and configure a few things
if(wicketSettings.getStatelessChecker()) {
LOG.debug("Statless checker added to application...");
// add stateless checks if we're in dev mode
this.getComponentPostOnBeforeRenderListeners().add(new StatelessChecker());
}
// set the render strategy for the application
this.getRequestCycleSettings().setRenderStrategy(wicketSettings.getRenderStrategy());
// Total hack to get wicket extensions properties to load
final List<IInitializer> initList = new ArrayList<IInitializer>();
initList.add(new Initializer());
this.getResourceSettings().getStringResourceLoaders().add(new InitializerStringResourceLoader(initList));
// mount all of the pages
for(final Map.Entry<String, Class<? extends WebPage>> page:wicketSettings.getPageMountClasses().entrySet()) {
this.mountPage(page.getKey(), page.getValue());
}
// mount all of the resources
for(final Map.Entry<String, Class<? extends IResource>> page:wicketSettings.getResourceMountClasses().entrySet()) {
this.mountResource(page.getKey(), new ResourceReference(page.getKey()) {
private static final long serialVersionUID = 1L;
@Override
public IResource getResource() {
try {
return page.getValue().newInstance();
} catch (final InstantiationException | IllegalAccessException e) {
LOG.error("Exception: {}", e.getMessage());
return null;
}
}
});
}
// set the exception page if we're in deployment and it's set
if(!wicketSettings.getDevelopment() && wicketSettings.getExceptionPage() != null) {
this.getRequestCycleListeners().add(new AbstractRequestCycleListener() {
@Override
public IRequestHandler onException(final RequestCycle cycle, final Exception e) {
LOG.error("Returning 500: {}", e.getMessage());
return new RenderPageRequestHandler(new PageProvider(wicketSettings.getExceptionPage()));
}
});
}
// should we strip wicket tags?
getMarkupSettings().setStripWicketTags(wicketSettings.getStripWicketTags());
// Wicket bootstrap is serving a JQuery map file, which is used to debug
// minified JavaScript. This results in a 500 when trying to access the
// resource as that file type is not permitted. Until we can figure out
// how to tell Wicket to not load that resource, this hack is needed.
final IPackageResourceGuard packageResourceGuard = getResourceSettings().getPackageResourceGuard();
if (packageResourceGuard instanceof SecurePackageResourceGuard) {
final SecurePackageResourceGuard guard = (SecurePackageResourceGuard)packageResourceGuard;
guard.addPattern("+*.map");
}
if(wicketSettings.getMinifyResources()) {
getResourceBundles().addCssBundle(
wicketSettings.getHomePageClass(),
"css-bundle.css",
wicketSettings.getCssResourceReferences());
getResourceBundles().addJavaScriptBundle(
wicketSettings.getHomePageClass(),
"js-bundle.js",
wicketSettings.getJavaScriptResourceReferences());
}
getHeaderContributorListenerCollection().add(new IHeaderContributor() {
private static final long serialVersionUID = 1L;
@Override
public void renderHead(final IHeaderResponse response) {
for (final JavaScriptResourceReference resource : wicketSettings.getJavaScriptResourceReferences()) {
response.render(JavaScriptReferenceHeaderItem.forReference(resource));
}
for (final UrlResourceReference resource : wicketSettings.getExternalJavaScriptResourceReferences()) {
response.render(JavaScriptReferenceHeaderItem.forReference(resource));
}
for (final CssResourceReference resource : wicketSettings.getCssResourceReferences()) {
response.render(CssReferenceHeaderItem.forReference(resource));
}
for (final UrlResourceReference resource : wicketSettings.getExternalCssResourceReferences()) {
response.render(CssReferenceHeaderItem.forReference(resource));
}
}
});
LOG.debug("Done calling CroquetApplication.init()");
}
@Override
public RuntimeConfigurationType getConfigurationType() {
return wicketSettings.getDevelopment() ? RuntimeConfigurationType.DEVELOPMENT : RuntimeConfigurationType.DEPLOYMENT;
}
@Override
protected IPageFactory newPageFactory() {
return pageFactory;
}
@Override
protected Class<? extends AbstractAuthenticatedWebSession> getWebSessionClass() {
// Wicket needs to be fixed: https://issues.apache.org/jira/browse/WICKET-5557
//return settings.getWicketSessionClass();
return UnauthenticatedWebSession.class;
}
@Override
protected Class<? extends WebPage> getSignInPageClass() {
// return the homepage here, should never be called
return wicketSettings.getLoginPageClass();
}
@Override
public Class<? extends Page> getHomePage() {
return wicketSettings.getHomePageClass();
}
// CHECKSTYLE:OFF because the link line is too long
/**
* An AbstractAuthenticatedWebSession that states everyone is logged in as Roles.USER.
*
* @see http://ci.apache.org/projects/wicket/apidocs/6.0.x/org/apache/wicket/authroles/authentication/AbstractAuthenticatedWebSession.html
*/
// CHECKSTYLE:ON
public static class UnauthenticatedWebSession extends AbstractAuthenticatedWebSession {
private static final long serialVersionUID = -1099204714854141425L;
/**
* Constructs an UnauthenticatedWebSession given the request.
* @param request the request for the session.
*/
public UnauthenticatedWebSession(final Request request) {
super(request);
}
@Override
public Roles getRoles() {
// everyone is just a user
return new Roles(Roles.USER);
}
@Override
public boolean isSignedIn() {
// everyone is signed in
return true;
}
}
}