package fr.openwide.core.wicket.more.application;
import static fr.openwide.core.spring.property.SpringPropertyIds.CONFIGURATION_TYPE;
import static fr.openwide.core.wicket.more.property.WicketMorePropertyIds.WICKET_DISK_DATA_STORE_IN_MEMORY_CACHE_SIZE;
import static fr.openwide.core.wicket.more.property.WicketMorePropertyIds.WICKET_DISK_DATA_STORE_MAX_SIZE_PER_SESSION;
import static fr.openwide.core.wicket.more.property.WicketMorePropertyIds.WICKET_DISK_DATA_STORE_PATH;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import org.apache.commons.io.FileUtils;
import org.apache.wicket.Application;
import org.apache.wicket.Page;
import org.apache.wicket.RuntimeConfigurationType;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.markup.head.PriorityFirstComparator;
import org.apache.wicket.markup.html.SecurePackageResourceGuard;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.request.resource.PackageResource;
import org.apache.wicket.request.resource.ResourceReference;
import org.apache.wicket.request.resource.caching.FilenameWithVersionResourceCachingStrategy;
import org.apache.wicket.request.resource.caching.version.LastModifiedResourceVersion;
import org.apache.wicket.resource.NoOpTextCompressor;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
import org.apache.wicket.util.lang.Bytes;
import org.apache.wicket.util.resource.IResourceStream;
import org.apache.wicket.util.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.wicketstuff.wiquery.ui.themes.WiQueryCoreThemeResourceReference;
import fr.openwide.core.spring.property.service.IPropertyService;
import fr.openwide.core.spring.util.StringUtils;
import fr.openwide.core.wicket.more.console.template.style.CoreConsoleCssScope;
import fr.openwide.core.wicket.more.css.lesscss.service.ILessCssService;
import fr.openwide.core.wicket.more.link.descriptor.IPageLinkDescriptor;
import fr.openwide.core.wicket.more.link.descriptor.builder.LinkDescriptorBuilder;
import fr.openwide.core.wicket.more.markup.html.template.AbstractWebPageTemplate;
import fr.openwide.core.wicket.more.markup.html.template.css.bootstrap2.CoreBootstrap2CssScope;
import fr.openwide.core.wicket.more.markup.html.template.css.bootstrap2.jqueryui.JQueryUiCssResourceReference;
import fr.openwide.core.wicket.more.markup.html.template.css.bootstrap3.CoreBootstrap3CssScope;
import fr.openwide.core.wicket.more.markup.html.template.css.bootstrap3.fontawesome.CoreFontAwesomeCssScope;
import fr.openwide.core.wicket.request.mapper.NoVersionMountedMapper;
import fr.openwide.core.wicket.request.mapper.PageParameterAwareMountedMapper;
import fr.openwide.core.wicket.request.mapper.StaticResourceMapper;
public abstract class CoreWicketApplication extends WebApplication {
private static final Logger LOGGER = LoggerFactory.getLogger(CoreWicketApplication.class);
@Autowired
private IPropertyService propertyService;
@Autowired
private ApplicationContext applicationContext;
@Autowired
protected ILessCssService lessCssService;
// TODO SCSS
// @Autowired
// protected IScssService scssService;
/**
* Déclaré au démarrage de l'application ; ne doit pas être modifié par la suite
*/
private Locale numberFormatLocale = Locale.FRENCH;
private static final Duration DEFAULT_TIMEOUT = Duration.minutes(10);
public static CoreWicketApplication get() {
final Application application = Application.get();
if (application instanceof CoreWicketApplication) {
return (CoreWicketApplication) application;
}
throw new WicketRuntimeException("There is no CoreWicketApplication attached to current thread " +
Thread.currentThread().getName());
}
public CoreWicketApplication() {
super();
}
@Override
public void init() {
super.init();
// injection Spring
getComponentInstantiationListeners().add(new SpringComponentInjector(this, applicationContext));
// nettoyage des tags Wicket
getMarkupSettings().setStripWicketTags(true);
// mise en place d'un timeout plus élevé histoire d'éviter les timeouts lors des téléchargements
getRequestCycleSettings().setTimeout(DEFAULT_TIMEOUT);
// configuration des ressources
// depuis Wicket 1.5, il faut ajouter les patterns sur les ressources qu'on souhaite rendre accessible
// on ajoute globalement l'accès aux ressources less et aux joyeusetés liés aux polices.
SecurePackageResourceGuard packageResourceGuard = (SecurePackageResourceGuard) getResourceSettings().getPackageResourceGuard();
packageResourceGuard.addPattern("+*.less");
packageResourceGuard.addPattern("+*.scss");
packageResourceGuard.addPattern("+*.woff");
packageResourceGuard.addPattern("+*.eot");
packageResourceGuard.addPattern("+*.svg");
packageResourceGuard.addPattern("+*.ttf");
packageResourceGuard.addPattern("+*.css.map");
// la compression se fait au build quand c'est nécessaire ; on n'utilise pas la compression Wicket
getResourceSettings().setJavaScriptCompressor(new NoOpTextCompressor());
// utilisation des ressources minifiées que si on est en mode DEPLOYMENT
getResourceSettings().setUseMinifiedResources(RuntimeConfigurationType.DEPLOYMENT.equals(getConfigurationType()));
// gestion du cache sur les ressources
getResourceSettings().setCachingStrategy(new FilenameWithVersionResourceCachingStrategy(new LastModifiedResourceVersion()));
// surcharge des ressources jQuery et jQuery UI
addResourceReplacement(WiQueryCoreThemeResourceReference.get(), JQueryUiCssResourceReference.get());
// on place les éléments présents dans le wicket:head en premier
getResourceSettings().setHeaderItemComparator(new PriorityFirstComparator(true));
// configuration du disk data store de Wicket
getStoreSettings().setInmemoryCacheSize(propertyService.get(WICKET_DISK_DATA_STORE_IN_MEMORY_CACHE_SIZE));
getStoreSettings().setMaxSizePerSession(Bytes.megabytes(propertyService.get(WICKET_DISK_DATA_STORE_MAX_SIZE_PER_SESSION)));
String wicketDiskDataStorePath = propertyService.get(WICKET_DISK_DATA_STORE_PATH);
if (StringUtils.hasText(wicketDiskDataStorePath)) {
try {
File wicketDiskDataStoreFolder = new File(wicketDiskDataStorePath);
FileUtils.forceMkdir(wicketDiskDataStoreFolder);
getStoreSettings().setFileStoreFolder(wicketDiskDataStoreFolder);
} catch (RuntimeException | IOException e) {
LOGGER.error(String.format("Unable to define a specific path (%1$s) for wicket data store. Using the default one.",
wicketDiskDataStorePath), e);
}
}
mountCommonResources();
mountCommonPages();
mountApplicationResources();
mountApplicationPages();
registerLessImportScopes();
// TODO SCSS
// registerScssImportScopes();
}
protected void registerLessImportScopes() {
lessCssService.registerImportScope("core", CoreBootstrap2CssScope.class);
lessCssService.registerImportScope("core-bs3", CoreBootstrap3CssScope.class);
lessCssService.registerImportScope("core-console", CoreConsoleCssScope.class);
lessCssService.registerImportScope("core-font-awesome", CoreFontAwesomeCssScope.class);
}
// TODO SCSS
// protected void registerScssImportScopes() {
// scssService.registerImportScope("core-bs4", CoreBootstrap4CssScope.class);
// }
protected void mountCommonPages() {
}
protected void mountCommonResources() {
mountStaticResourceDirectory("/common", AbstractWebPageTemplate.class);
mountStaticResourceDirectory("/font-awesome", CoreFontAwesomeCssScope.class);
}
protected abstract void mountApplicationPages();
protected abstract void mountApplicationResources();
protected final void mountStaticResourceDirectory(final String path, final Class<?> clazz) {
mount(new StaticResourceMapper("/static" + path, clazz));
}
public final <T extends Page> void mountUnversionedPage(final String path, final Class<T> pageClass) {
mount(new NoVersionMountedMapper(path, pageClass));
}
public final <T extends Page> void mountParameterizedPage(final String path, final Class<T> pageClass) {
mount(new PageParameterAwareMountedMapper(path, pageClass));
}
protected void preloadStyleSheets(ResourceReference... resourcesReferences) {
for (ResourceReference resourceReference : resourcesReferences) {
LOGGER.info("Preloading stylesheet '{}/{}'...", resourceReference.getScope().getName(),
resourceReference.getName());
IResourceStream resourceStream = null;
try {
// Just initialize the underlying cache, whatever the content is.
resourceStream = ((PackageResource) resourceReference.getResource()).getResourceStream();
} finally {
if (resourceStream != null) {
try {
resourceStream.close();
} catch (IOException e) {
LOGGER.error("Error when closing a stream while trying to preload stylesheets.", e);
}
}
}
}
}
/**
* Overriden to integrate configurationType via bean injection and
* properties file in place of web.xml or system properties definition
*/
@Override
public RuntimeConfigurationType getConfigurationType() {
return RuntimeConfigurationType.valueOf(propertyService.get(CONFIGURATION_TYPE).toUpperCase(Locale.ROOT));
}
public final IPageLinkDescriptor getHomePageLinkDescriptor() {
return LinkDescriptorBuilder.start().page(getHomePage());
}
public Locale getNumberFormatLocale() {
return numberFormatLocale;
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
}