/* * This file is part of the Wayback archival access software * (http://archive-access.sourceforge.net/projects/wayback/). * * Licensed to the Internet Archive (IA) by one or more individual * contributors. * * The IA licenses this file to You 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 org.archive.wayback.accesscontrol.staticmap; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import org.apache.commons.httpclient.URIException; import org.archive.util.iterator.CloseableIterator; import org.archive.wayback.UrlCanonicalizer; import org.archive.wayback.accesscontrol.ExclusionFilterFactory; import org.archive.wayback.resourceindex.filters.ExclusionFilter; import org.archive.wayback.surt.SURTTokenizer; import org.archive.wayback.util.flatfile.FlatFile; import org.archive.wayback.util.url.AggressiveUrlCanonicalizer; /** * * * @author brad * @version $Date$, $Revision$ */ public class StaticMapExclusionFilterFactory implements ExclusionFilterFactory { private static final Logger LOGGER = Logger.getLogger(StaticMapExclusionFilterFactory.class.getName()); private int checkInterval = 0; private Map<String,Object> currentMap = null; private File file = null; long lastUpdated = 0; private UrlCanonicalizer canonicalizer = new AggressiveUrlCanonicalizer(); public UrlCanonicalizer getCanonicalizer() { return canonicalizer; } public void setCanonicalizer(UrlCanonicalizer canonicalizer) { this.canonicalizer = canonicalizer; } /** * Thread object of update thread -- also is flag indicating if the thread * has already been started -- static, and access to it is synchronized. */ private static Thread updateThread = null; /** * load exclusion file and startup polling thread to check for updates * @throws IOException if the exclusion file could not be read. */ public void init() throws IOException { reloadFile(); if(checkInterval > 0) { startUpdateThread(); } } protected void reloadFile() throws IOException { long currentMod = file.lastModified(); if(currentMod == lastUpdated) { if(currentMod == 0) { LOGGER.severe("No exclude file at " + file.getAbsolutePath()); } return; } LOGGER.info("Reloading exclusion file " + file.getAbsolutePath()); try { currentMap = loadFile(file.getAbsolutePath()); lastUpdated = currentMod; LOGGER.info("Reload " + file.getAbsolutePath() + " OK"); } catch(IOException e) { lastUpdated = -1; currentMap = null; e.printStackTrace(); LOGGER.severe("Reload " + file.getAbsolutePath() + " FAILED:" + e.getLocalizedMessage()); } } protected Map<String,Object> loadFile(String path) throws IOException { Map<String, Object> newMap = new HashMap<String, Object>(); FlatFile ff = new FlatFile(path); CloseableIterator<String> itr = ff.getSequentialIterator(); while(itr.hasNext()) { String line = (String) itr.next(); line = line.trim(); if (line.length() == 0) { continue; } try { line = canonicalizer.urlStringToKey(line); } catch (URIException exc) { continue; } String surt; if (canonicalizer.isSurtForm()) { surt = line; } else { surt = line.startsWith("(") ? line : SURTTokenizer.prefixKey(line); } LOGGER.fine("EXCLUSION-MAP: adding " + surt); newMap.put(surt, null); } itr.close(); return newMap; } /** * @return ObjectFilter which blocks CaptureSearchResults in the * exclusion file. */ public ExclusionFilter get() { if(currentMap == null) { return null; } return new StaticMapExclusionFilter(currentMap, canonicalizer); } private synchronized void startUpdateThread() { if (updateThread != null) { return; } updateThread = new CacheUpdaterThread(this,checkInterval); updateThread.start(); } private synchronized void stopUpdateThread() { if (updateThread == null) { return; } updateThread.interrupt(); } private class CacheUpdaterThread extends Thread { /** * object which merges CDX files with the BDBResourceIndex */ private StaticMapExclusionFilterFactory service = null; private int runInterval; /** * @param service ExclusionFactory which will be reloaded * @param runInterval int number of seconds between reloads */ public CacheUpdaterThread(StaticMapExclusionFilterFactory service, int runInterval) { super("CacheUpdaterThread"); super.setDaemon(true); this.service = service; this.runInterval = runInterval; LOGGER.info("CacheUpdaterThread is alive."); } public void run() { int sleepInterval = runInterval; while (true) { try { try { service.reloadFile(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } Thread.sleep(sleepInterval * 1000); } catch (InterruptedException e) { e.printStackTrace(); return; } } } } /** * @return the checkInterval in seconds */ public int getCheckInterval() { return checkInterval; } /** * @param checkInterval the checkInterval in seconds to set */ public void setCheckInterval(int checkInterval) { this.checkInterval = checkInterval; } /** * @return the path */ public String getFile() { return file.getAbsolutePath(); } /** * @param path the file to set */ public void setFile(String path) { this.file = new File(path); } /* (non-Javadoc) * @see org.archive.wayback.accesscontrol.ExclusionFilterFactory#shutdown() */ public void shutdown() { stopUpdateThread(); } }