package se.unlogic.eagledns.zoneproviders.file; import org.apache.log4j.Logger; import org.xbill.DNS.Name; import org.xbill.DNS.TextParseException; import org.xbill.DNS.Zone; import se.unlogic.eagledns.SecondaryZone; import se.unlogic.eagledns.ZoneChangeCallback; import se.unlogic.eagledns.ZoneProvider; import se.unlogic.eagledns.ZoneProviderUpdatable; import se.unlogic.standardutils.numbers.NumberUtils; import se.unlogic.standardutils.timer.RunnableTimerTask; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Timer; /** * This class loads primary zones from zone files in the file system. * The zone files have to formated accordingly to RFC 1035 (http://tools.ietf.org/html/rfc1035) * and RFC 1034 (http://tools.ietf.org/html/rfc1034). * * @author Robert "Unlogic" Olofsson * @author Michael Neale, Red Hat (JBoss division) * */ public class FileZoneProvider implements ZoneProvider, ZoneProviderUpdatable, Runnable { private final Logger log = Logger.getLogger(this.getClass()); private String name; private String zoneFileDirectory; private boolean autoReloadZones; private Long pollingInterval; private Map<String, Long> lastFileList = new HashMap<String, Long>(); private ZoneChangeCallback changeCallback; private Timer watcher; public void init(String name) { this.name = name; if(autoReloadZones && pollingInterval != null){ watcher = new Timer(true); watcher.schedule(new RunnableTimerTask(this), 5000, pollingInterval); } } public void run() { if (changeCallback != null && hasDirectoryChanged()){ log.info("Changes in directory " + zoneFileDirectory + " detected"); changeCallback.zoneDataChanged(); } } private boolean hasDirectoryChanged() { File folder = new File(this.zoneFileDirectory); File[] files = folder.listFiles(); if (files.length != lastFileList.size()) { return true; } for (File f : folder.listFiles()) { if (!lastFileList.containsKey(f.getName())) { return true; } if (f.lastModified() > lastFileList.get(f.getName())) { return true; } } return false; } /** Refresh our list of zone files for watching */ private void updateZoneFiles(File[] files) { lastFileList = new HashMap<String, Long>(); for (File f : files) { lastFileList.put(f.getName(), f.lastModified()); } } public Collection<Zone> getPrimaryZones() { File zoneDir = new File(this.zoneFileDirectory); if(!zoneDir.exists() || !zoneDir.isDirectory()){ log.error("Zone file directory specified for FileZoneProvider " + name + " does not exist!"); return null; }else if(!zoneDir.canRead()){ log.error("Zone file directory specified for FileZoneProvider " + name + " is not readable!"); return null; } File[] files = zoneDir.listFiles(); updateZoneFiles(files); if(files == null || files.length == 0){ log.info("No zone files found for FileZoneProvider " + name + " in directory " + zoneDir.getPath()); return null; } ArrayList<Zone> zones = new ArrayList<Zone>(files.length); for(File zoneFile : files){ if(!zoneFile.canRead()){ log.error("FileZoneProvider " + name + " unable to access zone file " + zoneFile ); continue; } Name origin; try { origin = Name.fromString(zoneFile.getName(), Name.root); Zone zone = new Zone(origin, zoneFile.getPath()); log.debug("FileZoneProvider " + name + " successfully parsed zone file " + zoneFile.getName()); zones.add(zone); } catch (TextParseException e) { log.error("FileZoneProvider " + name + " unable to parse zone file " + zoneFile.getName(),e); } catch (IOException e) { log.error("Unable to parse zone file " + zoneFile + " in FileZoneProvider " + name,e); } } if(!zones.isEmpty()){ return zones; } return null; } public void unload() { } public String getZoneFileDirectory() { return zoneFileDirectory; } public void setZoneFileDirectory(String zoneFileDirectory) { this.zoneFileDirectory = zoneFileDirectory; log.debug("zoneFileDirectory set to " + zoneFileDirectory); } public Collection<SecondaryZone> getSecondaryZones() { //Not supported return null; } public void zoneUpdated(SecondaryZone secondaryZone) { //Not supported } public void zoneChecked(SecondaryZone secondaryZone) { //Not supported } public void setChangeListener(ZoneChangeCallback ev) { this.changeCallback = ev; } public void setAutoReloadZones(String autoReloadZones) { this.autoReloadZones = Boolean.parseBoolean(autoReloadZones); } public void setPollingInterval(String pollingInterval) { Long value = NumberUtils.toLong(pollingInterval); if(value != null && value > 0){ this.pollingInterval = value; }else{ log.warn("Invalid polling interval specified: " + pollingInterval); } } }