/** * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * @author Gabriel Roldan (OpenGeo) 2010 * */ package org.geowebcache.georss; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.geowebcache.grid.GridSubset; import org.geowebcache.layer.TileLayer; import org.geowebcache.layer.updatesource.GeoRSSFeedDefinition; import org.geowebcache.layer.updatesource.UpdateSourceDefinition; import org.geowebcache.seed.TileBreeder; import org.springframework.scheduling.concurrent.CustomizableThreadFactory; /** * * @author groldan * @version $Id$ */ public class GeoRSSPoller { private static final Log logger = LogFactory.getLog(GeoRSSPoller.class); private final TileBreeder seeder; private final ScheduledExecutorService schedulingPollExecutorService; private final List<PollDef> scheduledPolls; private final List<GeoRSSPollTask> scheduledTasks; /** * Upon instantiation, spawns out a thread after #{@code startUpDelaySecs} seconds that * periodically (at least every each layer's {@link GeoRSSFeedDefinition#getPollInterval() poll * interval} polls the layers feed for change sets and if changes are found spawns a reseed * process on the tiles affected by the change set. * * @param seeder * @param startUpDelaySecs * seconds to wait before start polling the layers */ public GeoRSSPoller(final TileBreeder seeder, final int startUpDelaySecs) { this.seeder = seeder; this.scheduledPolls = new ArrayList<PollDef>(); this.scheduledTasks = new ArrayList<GeoRSSPollTask>(); final int corePoolSize = 1; CustomizableThreadFactory tf = new CustomizableThreadFactory("GWC GeoRSS Poll Tasks-"); tf.setDaemon(true); tf.setThreadPriority(Thread.MIN_PRIORITY + 1); schedulingPollExecutorService = Executors.newScheduledThreadPool(corePoolSize, tf); schedulingPollExecutorService.submit(new Runnable() { public void run() { logger.info("Initializing GeoRSS poller in a background job..."); findEnabledPolls(); if (pollCount() > 0) { final TimeUnit seconds = TimeUnit.SECONDS; for (PollDef poll : scheduledPolls) { GeoRSSPollTask command = new GeoRSSPollTask(poll, seeder); GeoRSSFeedDefinition pollDef = poll.getPollDef(); long period = pollDef.getPollInterval(); logger.info("Scheduling layer " + poll.getLayer().getName() + " to poll the GeoRSS feed " + pollDef.getFeedUrl() + " every " + pollDef.getPollIntervalStr()); schedulingPollExecutorService.scheduleAtFixedRate(command, startUpDelaySecs, period, seconds); scheduledTasks.add(command); } logger.info("Will wait " + startUpDelaySecs + " seconds before launching the " + pollCount() + " GeoRSS polls found"); } else { logger.info("No enabled GeoRSS feeds found, poller will not run."); } } }); } private void findEnabledPolls() { final Iterable<TileLayer> layers = seeder.getLayers(); for (TileLayer layer : layers) { if (layer.getUpdateSources().size() == 0) { continue; } if (!layer.isEnabled()) { logger.info("Ignoring polling GeoRSS update sources for layer '" + layer.getName() + "' as the layer is disabled"); } for (UpdateSourceDefinition usd : layer.getUpdateSources()) { if (usd instanceof GeoRSSFeedDefinition) { final GeoRSSFeedDefinition georssDef = (GeoRSSFeedDefinition) usd; final String gridSetId = georssDef.getGridSetId(); final GridSubset gridSubset = layer.getGridSubset(gridSetId); if (gridSubset == null) { throw new IllegalStateException("Layer " + layer.getName() + " has no grid subset " + gridSetId + " as configured by its GeoRSS seeding feed " + georssDef); } if (georssDef.getPollInterval() > 0) { logger.info("Scheduling GeoRSS feed for layer " + layer.getName() + ":" + georssDef); scheduledPolls.add(new PollDef(layer, georssDef)); } else { logger.info("Feed disabled for layer " + layer.getName() + ", ignoring: " + georssDef); } } } } } /** * @return number of scheduled polls */ public int pollCount() { return scheduledPolls.size(); } /** * Destroy method for Spring */ public void destroy() { logger.info("destroy() invoked"); if (schedulingPollExecutorService != null) { schedulingPollExecutorService.shutdown(); } for (GeoRSSPollTask task : scheduledTasks) { task.stopSeeding(false); } // And that's all we can do... } }