/** * Copyright 2014 55 Minutes (http://www.55minutes.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package fiftyfive.wicket; import java.util.Date; import fiftyfive.util.Version; import org.apache.wicket.protocol.http.RequestLogger; import org.apache.wicket.protocol.http.WebApplication; import org.apache.wicket.response.filter.AjaxServerAndClientTimeFilter; import org.apache.wicket.util.time.Duration; import org.apache.wicket.util.time.Time; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.apache.wicket.RuntimeConfigurationType.DEVELOPMENT; /** * Useful base class for Wicket applications that implements best practices * for Wicket configuration. * <ul> * <li>Provides a {@link #getStartupDate} method</li> * <li>Exposes version and build timestamp information</li> * <li>Removes Wicket tags, wicket:id attributes, and other cruft from * generated markup to ensure XHTML compliance</li> * <li>Enables Wicket's request logging facility if an appropriate SLF4J * logger is configured</li> * <li>In development mode, enable automatic reloading of HTML templates from * the source code directory ("hot deploy")</li> * <li>In development mode, turn off the ajax debugger (it is a browser * memory hog)</li> * </ul> * * @author Matt Brictson * @see #init */ public abstract class FoundationApplication extends WebApplication { private Date startupDate; private Version version; public FoundationApplication() { super(); } /** * Returns the version information for this application, including the * version number and the date and time when it was compiled. */ public Version getVersion() { return this.version; } /** * Returns the date and time when this application was initialized * by the Wicket framework. */ public Date getStartupDate() { return this.startupDate; } /** * Returns the amount of time elapsed since this application was * initialized by the Wicket framework. * * @since 2.0 */ public Duration getUptime() { Date start = getStartupDate(); if(null == start) { return Duration.milliseconds(0); } return Duration.elapsed(Time.valueOf(start)); } /** * Helper method that returns true if {@link #getConfigurationType} * is equal to DEVELOPMENT. * * @deprecated In Wicket 1.5, this has been superseded by * {@link #usesDevelopmentConfig}. */ public boolean isDevelopmentMode() { return usesDevelopmentConfig(); } /** * Initializes the application using best practices for Wicket * application development and deployment. * <ol> * <li>Sets the startupDate property to the current time.</li> * <li>Calls {@link WebApplication#init super.init()}.</li> * <li>Executes the following regardless of configuration mode:<ul> * <li>{@link #initVersionInformation}</li> * <li>{@link #initCleanMarkup}</li> * <li>{@link #initResources}</li> * <li>{@link #initRequestLogger}</li></ul></li> * <li>Executes the following only if the application is in * DEVELOPMENT mode:<ul> * <li>{@link #initHtmlHotDeploy}</li> * <li>{@link #initDebugInformation}</li></ul></li> * </ol> */ @Override protected void init() { this.startupDate = new Date(); super.init(); initVersionInformation(); initCleanMarkup(); initResources(); initRequestLogger(); if(usesDevelopmentConfig()) { initHtmlHotDeploy(); initDebugInformation(); } } /** * Enables automatic reloading of HTML templates from your source code * directory. This means that whenever you modify an HTML file the * changes will appear immediately in your browser without needing to * redeploy. However you will still need to redeploy if you recompile * a Java class. * <p> * This method assumes that you are running the webapp "in place"; for * example using <code>mvn jetty:run</code>. It * will not work if you are running from a WAR or exploded WAR. * <p> * You must also be using the * standard maven project structure for your Wicket project, like so: * <pre class="example"> * pom.xml * src/ * main/ * java/ * resources/ * webapp/</pre> * * @see <a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin">http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin</a> */ protected void initHtmlHotDeploy() { getResourceSettings().setResourcePollFrequency(Duration.ONE_SECOND); String htmlDir = getServletContext().getRealPath("/"); if(htmlDir != null && !htmlDir.endsWith("/")) { htmlDir += "/"; } getResourceSettings().addResourceFolder(htmlDir + "../java"); getResourceSettings().addResourceFolder(htmlDir + "../resources"); } /** * Turns off Wicket's non-standard markup and sets the default markup * encoding to UTF-8. By default, Wicket will add markup to disabled * links; for example, it may wrap them in an <em> element. We * prefer to control the markup and don't want Wicket adding elements, * so we turn this off. We also instruct Wicket to strip the wicket:id * attributes and wicket: elements from the markup. This ensures that * the markup will be valid (X)HTML. */ protected void initCleanMarkup() { getMarkupSettings().setDefaultBeforeDisabledLink(null); getMarkupSettings().setDefaultAfterDisabledLink(null); getMarkupSettings().setDefaultMarkupEncoding("UTF-8"); getMarkupSettings().setStripWicketTags(true); } /** * Disables ajaxDebugMode (the popup * panel in the browser that shows ajax request and response details). * It is disabled because it is a memory hog that can bog down the * browser. Finally, enables emitting HTML comments that show which Wicket * class created each section of HTML. */ protected void initDebugInformation() { getRequestCycleSettings().addResponseFilter( new AjaxServerAndClientTimeFilter() ); getDebugSettings().setOutputMarkupContainerClassName(true); // Turn this off explicity because it causes performance problems getDebugSettings().setAjaxDebugModeEnabled(false); } /** * Loads the version information from the manifest of this web * application. To access the version information, use {@link #getVersion}. * * @see Version */ protected void initVersionInformation() { this.version = Version.ofWebapp(getServletContext()); } /** * Set the cache duration for resources to zero if in development mode * (discouraging browser cache), or 1 year if in deployment mode. */ protected void initResources() { getResourceSettings().setDefaultCacheDuration( usesDevelopmentConfig() ? Duration.NONE : Duration.days(365) ); } /** * Enables Wicket's request logging facility if an SLF4J logger is * configured for {@code INFO} with the category * {@code org.apache.wicket.protocol.http.RequestLogger}. For example, * if using log4j properties configuration, this would cause the Wicket * request logger to be enabled: * <pre class="example"> * log4j.logger.org.apache.wicket.protocol.http.RequestLogger = INFO</pre> * * @since 2.0 */ protected void initRequestLogger() { Logger log = LoggerFactory.getLogger(RequestLogger.class); if(log.isInfoEnabled()) { getRequestLoggerSettings().setRequestLoggerEnabled(true); } } }