/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wms; import java.awt.Font; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.io.FileUtils; import org.geoserver.config.GeoServerDataDirectory; import org.geoserver.config.impl.GeoServerLifecycleHandler; import org.geoserver.platform.resource.Resource; import org.geoserver.platform.resource.Resources; import org.geotools.renderer.style.FontCache; import org.geotools.renderer.style.ImageGraphicFactory; import org.geotools.renderer.style.SVGGraphicFactory; import org.geotools.util.logging.Logging; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; /** * Drops imaging caches * * @author Andrea Aime - OpenGeo */ public class WMSLifecycleHandler implements GeoServerLifecycleHandler, ApplicationListener { static final Logger LOGGER = Logging.getLogger(WMSLifecycleHandler.class); GeoServerDataDirectory data; WMS wmsConfig; public WMSLifecycleHandler(GeoServerDataDirectory data, WMS wmsConfig) { this.data = data; this.wmsConfig = wmsConfig; } public void onDispose() { // dispose the WMS Animator Executor Service shutdownAnimatorExecutorService(); } public void beforeReload() { // nothing to do } public void onReload() { // clear the caches for good measure onReset(); } public void onReset() { // kill the image caches ImageGraphicFactory.resetCache(); SVGGraphicFactory.resetCache(); // reloads the font cache reloadFontCache(); // reset WMS Animator Executor Service resetAnimatorExecutorService(); } /** * Shutting down pending tasks and resetting the executor service * timeout. */ private void resetAnimatorExecutorService() { shutdownAnimatorExecutorService(); Long framesTimeout = this.wmsConfig.getMaxAnimatorRenderingTime() != null ? this.wmsConfig.getMaxAnimatorRenderingTime() : Long.MAX_VALUE; ExecutorService animatorExecutorService = new ThreadPoolExecutor(4, 20, framesTimeout, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); this.wmsConfig.setAnimatorExecutorService(animatorExecutorService); } /** * Suddenly shuts down the Animator Executor Service */ private void shutdownAnimatorExecutorService() { final ExecutorService animatorExecutorService = this.wmsConfig.getAnimatorExecutorService(); if (animatorExecutorService != null && !animatorExecutorService.isShutdown()) { animatorExecutorService.shutdownNow(); } } void reloadFontCache() { List<Font> fonts = loadFontsFromDataDirectory(); final FontCache cache = FontCache.getDefaultInstance(); cache.resetCache(); for (Font font : fonts) { cache.registerFont(font); } } List<Font> loadFontsFromDataDirectory() { List<Font> result = new ArrayList<Font>(); for (Resource file : Resources.list(data.getStyles(), new Resources.ExtensionFilter("TTF"), true)) { try { final Font font = Font.createFont(Font.TRUETYPE_FONT, file.file()); result.add(font); LOGGER.log(Level.INFO, "Loaded font file " + file + ", loaded font '" + font.getName() + "' in family '" + font.getFamily() + "'"); } catch (Exception e) { LOGGER.log(Level.WARNING, "Failed to load font file " + file, e); } } return result; } public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ContextRefreshedEvent) { reloadFontCache(); // reset WMS Animator Executor Service resetAnimatorExecutorService(); } } }