commit b2ad143c2a79e335f0ff7648b1dcd5fc157af63c
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Thu Feb 2 08:08:07 2012 +0100
Use a single interface for reading descriptors.
---
.../descriptor/BridgeDescriptorReader.java | 34 ---
.../descriptor/BridgePoolAssignmentReader.java | 34 ---
.../descriptor/DescriptorDownloader.java | 109 ++++++++
.../torproject/descriptor/DescriptorReader.java | 34 +++
.../descriptor/DescriptorSourceFactory.java | 28 +--
.../descriptor/RelayDescriptorDownloader.java | 109 --------
.../descriptor/RelayDescriptorReader.java | 35 ---
.../descriptor/impl/DescriptorDownloaderImpl.java | 265 ++++++++++++++++++++
.../descriptor/impl/DescriptorReaderImpl.java | 194 ++++++++++++++
.../impl/RelayDescriptorDownloaderImpl.java | 265 --------------------
.../impl/RelayOrBridgeDescriptorReaderImpl.java | 198 ---------------
11 files changed, 610 insertions(+), 695 deletions(-)
diff --git a/src/org/torproject/descriptor/BridgeDescriptorReader.java b/src/org/torproject/descriptor/BridgeDescriptorReader.java
deleted file mode 100644
index d827124..0000000
--- a/src/org/torproject/descriptor/BridgeDescriptorReader.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright 2011, 2012 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.descriptor;
-
-import java.io.File;
-import java.util.Iterator;
-
-/* Read bridge descriptors from one or more local directories. */
-public interface BridgeDescriptorReader {
-
- /* Add a local directory to read bridge descriptors from. */
- public void addDirectory(File directory);
-
- /* Exclude files that are contained in the given history file and that
- * haven't changed since they were last read. Add reads from the
- * current run to the history file. Remove files that don't exist
- * anymore from the history file. Lines in the history file contain the
- * last modified timestamp and the absolute path of a file. */
- public void setExcludeFiles(File historyFile);
-
- /* Fail descriptor parsing when encountering an unrecognized line. This
- * is not set by default, because the Tor specifications allow for new
- * lines to be added that shall be ignored by older Tor versions. But
- * some applications may want to handle unrecognized descriptor lines
- * explicitly. */
- public void setFailUnrecognizedDescriptorLines();
-
- /* Read the previously configured bridge descriptors and make them
- * available via the returned blocking iterator. Whenever the reader
- * runs out of descriptors and expects to provide more shortly after, it
- * blocks the caller. This method can only be run once. */
- public Iterator<DescriptorFile> readDescriptors();
-}
-
diff --git a/src/org/torproject/descriptor/BridgePoolAssignmentReader.java b/src/org/torproject/descriptor/BridgePoolAssignmentReader.java
deleted file mode 100644
index 13c8ae3..0000000
--- a/src/org/torproject/descriptor/BridgePoolAssignmentReader.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright 2011, 2012 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.descriptor;
-
-import java.io.File;
-import java.util.Iterator;
-
-/* Read bridge pool assignments from one or more local directories. */
-public interface BridgePoolAssignmentReader {
-
- /* Add a local directory to read bridge pool assignments from. */
- public void addDirectory(File directory);
-
- /* Exclude files that are contained in the given history file and that
- * haven't changed since they were last read. Add reads from the
- * current run to the history file. Remove files that don't exist
- * anymore from the history file. Lines in the history file contain the
- * last modified timestamp and the absolute path of a file. */
- public void setExcludeFiles(File historyFile);
-
- /* Fail descriptor parsing when encountering an unrecognized line. This
- * is not set by default, because the Tor specifications allow for new
- * lines to be added that shall be ignored by older Tor versions. But
- * some applications may want to handle unrecognized descriptor lines
- * explicitly. */
- public void setFailUnrecognizedDescriptorLines();
-
- /* Read the previously configured bridge pool assignments and make them
- * available via the returned blocking iterator. Whenever the reader
- * runs out of descriptors and expects to provide more shortly after, it
- * blocks the caller. This method can only be run once. */
- public Iterator<DescriptorFile> readDescriptors();
-}
-
diff --git a/src/org/torproject/descriptor/DescriptorDownloader.java b/src/org/torproject/descriptor/DescriptorDownloader.java
new file mode 100644
index 0000000..5665e1f
--- /dev/null
+++ b/src/org/torproject/descriptor/DescriptorDownloader.java
@@ -0,0 +1,109 @@
+/* Copyright 2011, 2012 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.descriptor;
+
+import java.util.Iterator;
+import java.util.Set;
+
+/* Download relay descriptors from directory mirrors or authorities. */
+public interface DescriptorDownloader {
+
+ /* Add a directory authority to download descriptors from. A directory
+ * authority is only required for downloading network status vote and
+ * will be used when no directory mirrors are available. */
+ public void addDirectoryAuthority(String nickname, String ip,
+ int dirPort);
+
+ /* Add a directory mirror to download descriptors from. Directory
+ * mirrors are preferred when downloading descriptors, except for
+ * network status votes which are only available on directory
+ * authorities. */
+ public void addDirectoryMirror(String nickname, String ip, int dirPort);
+
+ /* Include the current network status consensus in the downloads. */
+ public void setIncludeCurrentConsensus();
+
+ /* Include the current network status consensus in the downloads, and
+ * attempt to download it from all directory authorities. The primary
+ * purpose of doing this is to compare different consensuses and
+ * download characteristics to each other. Typically, downloading from
+ * a single directory mirror or authority is sufficient. */
+ public void setIncludeCurrentConsensusFromAllDirectoryAuthorities();
+
+ /* Include the current network status votes referenced from a previously
+ * downloaded consensus in the downloads. This requires downloading the
+ * current consensus from at least one directory mirror or authority. */
+ public void setIncludeCurrentReferencedVotes();
+
+ /* Include the current network status vote published by the given
+ * directory authority in the downloads. This requires downloading from
+ * at least one directory authority. */
+ public void setIncludeCurrentVote(String fingerprint);
+
+ /* Include the current network status votes published by the given
+ * directory authorities in the downloads. This requires downloading
+ * from at least one directory authority. */
+ public void setIncludeCurrentVotes(Set<String> fingerprints);
+
+ /* Include all server descriptors referenced from a previously
+ * downloaded network status consensus in the downloads. */
+ public void setIncludeReferencedServerDescriptors();
+
+ /* Exclude the server descriptor with the given identifier from the
+ * downloads even if it's referenced from a consensus and we're supposed
+ * to download all referenced server descriptors. */
+ public void setExcludeServerDescriptor(String identifier);
+
+ /* Exclude the server descriptors with the given identifiers from the
+ * downloads even if they are referenced from a consensus and we're
+ * supposed to download all referenced server descriptors. */
+ public void setExcludeServerDescriptors(Set<String> identifier);
+
+ /* Include all extra-info descriptors referenced from previously
+ * downloaded server descriptors in the downloads. */
+ public void setIncludeReferencedExtraInfoDescriptors();
+
+ /* Exclude the extra-info descriptor with the given identifier from the
+ * downloads even if it's referenced from a server descriptor and we're
+ * supposed to download all referenced extra-info descriptors. */
+ public void setExcludeExtraInfoDescriptor(String identifier);
+
+ /* Exclude the extra-info descriptors with the given identifiers from
+ * the downloads even if they are referenced from server descriptors
+ * and we're supposed to download all referenced extra-info
+ * descriptors. */
+ public void setExcludeExtraInfoDescriptors(Set<String> identifiers);
+
+ /* Define a connect timeout for a single request. If a timeout expires,
+ * no further requests will be sent to the directory authority or
+ * mirror. Setting this value to 0 disables the connect timeout.
+ * Default value is 1 minute (60 * 1000). */
+ public void setConnectTimeout(long connectTimeoutMillis);
+
+ /* Define a read timeout for a single request. If a timeout expires,
+ * no further requests will be sent to the directory authority or
+ * mirror. Setting this value to 0 disables the read timeout.
+ * Default value is 1 minute (60 * 1000). */
+ public void setReadTimeout(long readTimeoutMillis);
+
+ /* Define a global timeout for all requests. Once this timeout expires,
+ * all running requests are aborted and no further requests are made.
+ * Setting this value to 0 disables the global timeout. Default is 1
+ * hour (60 * 60 * 1000). */
+ public void setGlobalTimeout(long globalTimeoutMillis);
+
+ /* Fail descriptor parsing when encountering an unrecognized line. This
+ * is not set by default, because the Tor specifications allow for new
+ * lines to be added that shall be ignored by older Tor versions. But
+ * some applications may want to handle unrecognized descriptor lines
+ * explicitly. */
+ public void setFailUnrecognizedDescriptorLines();
+
+ /* Download the previously configured relay descriptors and make them
+ * available via the returned blocking iterator. Whenever the
+ * downloader runs out of descriptors and expects to provide more
+ * shortly after, it blocks the caller. This method can only be run
+ * once. */
+ public Iterator<DescriptorRequest> downloadDescriptors();
+}
+
diff --git a/src/org/torproject/descriptor/DescriptorReader.java b/src/org/torproject/descriptor/DescriptorReader.java
new file mode 100644
index 0000000..1d46a79
--- /dev/null
+++ b/src/org/torproject/descriptor/DescriptorReader.java
@@ -0,0 +1,34 @@
+/* Copyright 2011, 2012 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.descriptor;
+
+import java.io.File;
+import java.util.Iterator;
+
+/* Read descriptors from one or more local directories. */
+public interface DescriptorReader {
+
+ /* Add a local directory to read descriptors from. */
+ public void addDirectory(File directory);
+
+ /* Exclude files that are contained in the given history file and that
+ * haven't changed since they were last read. Add reads from the
+ * current run to the history file. Remove files that don't exist
+ * anymore from the history file. Lines in the history file contain the
+ * last modified timestamp and the absolute path of a file. */
+ public void setExcludeFiles(File historyFile);
+
+ /* Fail descriptor parsing when encountering an unrecognized line. This
+ * is not set by default, because the Tor specifications allow for new
+ * lines to be added that shall be ignored by older Tor versions. But
+ * some applications may want to handle unrecognized descriptor lines
+ * explicitly. */
+ public void setFailUnrecognizedDescriptorLines();
+
+ /* Read the previously configured descriptors and make them available
+ * via the returned blocking iterator. Whenever the reader runs out of
+ * descriptors and expects to provide more shortly after, it blocks the
+ * caller. This method can only be run once. */
+ public Iterator<DescriptorFile> readDescriptors();
+}
+
diff --git a/src/org/torproject/descriptor/DescriptorSourceFactory.java b/src/org/torproject/descriptor/DescriptorSourceFactory.java
index ed2790a..102bfce 100644
--- a/src/org/torproject/descriptor/DescriptorSourceFactory.java
+++ b/src/org/torproject/descriptor/DescriptorSourceFactory.java
@@ -2,32 +2,20 @@
* See LICENSE for licensing information */
package org.torproject.descriptor;
-import org.torproject.descriptor.impl.RelayDescriptorDownloaderImpl;
-import org.torproject.descriptor.impl.RelayOrBridgeDescriptorReaderImpl;
+import org.torproject.descriptor.impl.DescriptorDownloaderImpl;
+import org.torproject.descriptor.impl.DescriptorReaderImpl;
/* Create descriptor source instances. */
public class DescriptorSourceFactory {
- /* Create a relay descriptor reader. */
- public static RelayDescriptorReader createRelayDescriptorReader() {
- return new RelayOrBridgeDescriptorReaderImpl();
+ /* Create a descriptor reader. */
+ public static DescriptorReader createDescriptorReader() {
+ return new DescriptorReaderImpl();
}
- /* Create a relay descriptor downloader. */
- public static RelayDescriptorDownloader
- createRelayDescriptorDownloader() {
- return new RelayDescriptorDownloaderImpl();
- }
-
- /* Create a bridge descriptor reader. */
- public static BridgeDescriptorReader createBridgeDescriptorReader() {
- return new RelayOrBridgeDescriptorReaderImpl();
- }
-
- /* Create a bridge pool assignment reader. */
- public static BridgePoolAssignmentReader
- createBridgePoolAssignmentReader() {
- return new RelayOrBridgeDescriptorReaderImpl();
+ /* Create a descriptor downloader. */
+ public static DescriptorDownloader createDescriptorDownloader() {
+ return new DescriptorDownloaderImpl();
}
}
diff --git a/src/org/torproject/descriptor/RelayDescriptorDownloader.java b/src/org/torproject/descriptor/RelayDescriptorDownloader.java
deleted file mode 100644
index 29171d3..0000000
--- a/src/org/torproject/descriptor/RelayDescriptorDownloader.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/* Copyright 2011, 2012 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.descriptor;
-
-import java.util.Iterator;
-import java.util.Set;
-
-/* Download relay descriptors from directory mirrors or authorities. */
-public interface RelayDescriptorDownloader {
-
- /* Add a directory authority to download descriptors from. A directory
- * authority is only required for downloading network status vote and
- * will be used when no directory mirrors are available. */
- public void addDirectoryAuthority(String nickname, String ip,
- int dirPort);
-
- /* Add a directory mirror to download descriptors from. Directory
- * mirrors are preferred when downloading descriptors, except for
- * network status votes which are only available on directory
- * authorities. */
- public void addDirectoryMirror(String nickname, String ip, int dirPort);
-
- /* Include the current network status consensus in the downloads. */
- public void setIncludeCurrentConsensus();
-
- /* Include the current network status consensus in the downloads, and
- * attempt to download it from all directory authorities. The primary
- * purpose of doing this is to compare different consensuses and
- * download characteristics to each other. Typically, downloading from
- * a single directory mirror or authority is sufficient. */
- public void setIncludeCurrentConsensusFromAllDirectoryAuthorities();
-
- /* Include the current network status votes referenced from a previously
- * downloaded consensus in the downloads. This requires downloading the
- * current consensus from at least one directory mirror or authority. */
- public void setIncludeCurrentReferencedVotes();
-
- /* Include the current network status vote published by the given
- * directory authority in the downloads. This requires downloading from
- * at least one directory authority. */
- public void setIncludeCurrentVote(String fingerprint);
-
- /* Include the current network status votes published by the given
- * directory authorities in the downloads. This requires downloading
- * from at least one directory authority. */
- public void setIncludeCurrentVotes(Set<String> fingerprints);
-
- /* Include all server descriptors referenced from a previously
- * downloaded network status consensus in the downloads. */
- public void setIncludeReferencedServerDescriptors();
-
- /* Exclude the server descriptor with the given identifier from the
- * downloads even if it's referenced from a consensus and we're supposed
- * to download all referenced server descriptors. */
- public void setExcludeServerDescriptor(String identifier);
-
- /* Exclude the server descriptors with the given identifiers from the
- * downloads even if they are referenced from a consensus and we're
- * supposed to download all referenced server descriptors. */
- public void setExcludeServerDescriptors(Set<String> identifier);
-
- /* Include all extra-info descriptors referenced from previously
- * downloaded server descriptors in the downloads. */
- public void setIncludeReferencedExtraInfoDescriptors();
-
- /* Exclude the extra-info descriptor with the given identifier from the
- * downloads even if it's referenced from a server descriptor and we're
- * supposed to download all referenced extra-info descriptors. */
- public void setExcludeExtraInfoDescriptor(String identifier);
-
- /* Exclude the extra-info descriptors with the given identifiers from
- * the downloads even if they are referenced from server descriptors
- * and we're supposed to download all referenced extra-info
- * descriptors. */
- public void setExcludeExtraInfoDescriptors(Set<String> identifiers);
-
- /* Define a connect timeout for a single request. If a timeout expires,
- * no further requests will be sent to the directory authority or
- * mirror. Setting this value to 0 disables the connect timeout.
- * Default value is 1 minute (60 * 1000). */
- public void setConnectTimeout(long connectTimeoutMillis);
-
- /* Define a read timeout for a single request. If a timeout expires,
- * no further requests will be sent to the directory authority or
- * mirror. Setting this value to 0 disables the read timeout.
- * Default value is 1 minute (60 * 1000). */
- public void setReadTimeout(long readTimeoutMillis);
-
- /* Define a global timeout for all requests. Once this timeout expires,
- * all running requests are aborted and no further requests are made.
- * Setting this value to 0 disables the global timeout. Default is 1
- * hour (60 * 60 * 1000). */
- public void setGlobalTimeout(long globalTimeoutMillis);
-
- /* Fail descriptor parsing when encountering an unrecognized line. This
- * is not set by default, because the Tor specifications allow for new
- * lines to be added that shall be ignored by older Tor versions. But
- * some applications may want to handle unrecognized descriptor lines
- * explicitly. */
- public void setFailUnrecognizedDescriptorLines();
-
- /* Download the previously configured relay descriptors and make them
- * available via the returned blocking iterator. Whenever the
- * downloader runs out of descriptors and expects to provide more
- * shortly after, it blocks the caller. This method can only be run
- * once. */
- public Iterator<DescriptorRequest> downloadDescriptors();
-}
-
diff --git a/src/org/torproject/descriptor/RelayDescriptorReader.java b/src/org/torproject/descriptor/RelayDescriptorReader.java
deleted file mode 100644
index 142f79c..0000000
--- a/src/org/torproject/descriptor/RelayDescriptorReader.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright 2011, 2012 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.descriptor;
-
-import java.io.File;
-import java.util.Iterator;
-
-/* Read relay descriptors from one or more local directories. */
-public interface RelayDescriptorReader {
-
- /* Add a local directory to read relay descriptors from. */
- public void addDirectory(File directory);
-
- /* Exclude files that are contained in the given history file and that
- * haven't changed since they were last read. Add reads from the
- * current run to the history file. Remove files that don't exist
- * anymore from the history file. Lines in the history file contain the
- * last modified timestamp and the absolute path of a file. */
- public void setExcludeFiles(File historyFile);
-
- /* Fail descriptor parsing when encountering an unrecognized line. This
- * is not set by default, because the Tor specifications allow for new
- * lines to be added that shall be ignored by older Tor versions. But
- * some applications may want to handle unrecognized descriptor lines
- * explicitly. */
- public void setFailUnrecognizedDescriptorLines();
-
- /* Read the previously configured relay descriptors and make them
- * available via the returned blocking iterator. Whenever the reader
- * runs out of descriptors and expects to provide more shortly after, it
- * blocks the caller. This method can only be run once. */
- public Iterator<DescriptorFile> readDescriptors();
-
-}
-
diff --git a/src/org/torproject/descriptor/impl/DescriptorDownloaderImpl.java b/src/org/torproject/descriptor/impl/DescriptorDownloaderImpl.java
new file mode 100644
index 0000000..3c093d1
--- /dev/null
+++ b/src/org/torproject/descriptor/impl/DescriptorDownloaderImpl.java
@@ -0,0 +1,265 @@
+/* Copyright 2011, 2012 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.descriptor.impl;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.torproject.descriptor.DescriptorRequest;
+import org.torproject.descriptor.DescriptorDownloader;
+
+public class DescriptorDownloaderImpl
+ implements DescriptorDownloader {
+
+ private boolean hasStartedDownloading = false;
+
+ private SortedMap<String, DirectoryDownloader> directoryAuthorities =
+ new TreeMap<String, DirectoryDownloader>();
+ public void addDirectoryAuthority(String nickname, String ip,
+ int dirPort) {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ this.checkDirectoryParameters(nickname, ip, dirPort);
+ DirectoryDownloader directoryAuthority = new DirectoryDownloader(
+ nickname, ip, dirPort);
+ this.directoryAuthorities.put(nickname, directoryAuthority);
+ }
+
+ private SortedMap<String, DirectoryDownloader> directoryMirrors =
+ new TreeMap<String, DirectoryDownloader>();
+ public void addDirectoryMirror(String nickname, String ip,
+ int dirPort) {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ this.checkDirectoryParameters(nickname, ip, dirPort);
+ DirectoryDownloader directoryMirror = new DirectoryDownloader(
+ nickname, ip, dirPort);
+ this.directoryMirrors.put(nickname, directoryMirror);
+ /* TODO Implement prioritizing mirrors for non-vote downloads. */
+ throw new UnsupportedOperationException("Prioritizing directory "
+ + "mirrors over directory authorities is not implemented yet. "
+ + "Until it is, configuring directory mirrors is misleading and "
+ + "therefore not supported.");
+ }
+
+ private void checkDirectoryParameters(String nickname, String ip,
+ int dirPort) {
+ if (nickname == null || nickname.length() < 1) {
+ throw new IllegalArgumentException("'" + nickname + "' is not a "
+ + "valid nickname.");
+ }
+ if (ip == null || ip.length() < 7 || ip.split("\\.").length != 4) {
+ throw new IllegalArgumentException("'" + ip + "' is not a valid IP "
+ + "address.");
+ }
+ if (dirPort < 1 || dirPort > 65535) {
+ throw new IllegalArgumentException(String.valueOf(dirPort) + " is "
+ + "not a valid DirPort.");
+ }
+ /* TODO Relax the requirement for directory nicknames to be unique.
+ * In theory, we can identify them by ip+port. */
+ if (this.directoryAuthorities.containsKey(nickname) ||
+ this.directoryMirrors.containsKey(nickname)) {
+ throw new IllegalArgumentException("Directory nicknames must be "
+ + "unique.");
+ }
+ }
+
+ private boolean downloadConsensus = false;
+ public void setIncludeCurrentConsensus() {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ this.downloadConsensus = true;
+ }
+
+ private boolean downloadConsensusFromAllAuthorities = false;
+ public void setIncludeCurrentConsensusFromAllDirectoryAuthorities() {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ this.downloadConsensusFromAllAuthorities = true;
+ }
+
+ private boolean includeCurrentReferencedVotes = false;
+ public void setIncludeCurrentReferencedVotes() {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ this.includeCurrentReferencedVotes = true;
+ }
+
+ private Set<String> downloadVotes = new HashSet<String>();
+ public void setIncludeCurrentVote(String fingerprint) {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ this.checkVoteFingerprint(fingerprint);
+ this.downloadVotes.add(fingerprint);
+ }
+
+ public void setIncludeCurrentVotes(Set<String> fingerprints) {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ if (fingerprints == null) {
+ throw new IllegalArgumentException("Set of fingerprints must not "
+ + "be null.");
+ }
+ for (String fingerprint : fingerprints) {
+ this.checkVoteFingerprint(fingerprint);
+ }
+ for (String fingerprint : fingerprints) {
+ this.setIncludeCurrentVote(fingerprint);
+ }
+ }
+
+ private void checkVoteFingerprint(String fingerprint) {
+ if (fingerprint == null || fingerprint.length() != 40) {
+ throw new IllegalArgumentException("'" + fingerprint + "' is not a "
+ + "valid fingerprint.");
+ }
+ }
+
+ public void setIncludeReferencedServerDescriptors() {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ /* TODO Implement me. */
+ throw new UnsupportedOperationException("Downloading server "
+ + "descriptors is not implemented yet.");
+ }
+
+ public void setExcludeServerDescriptor(String identifier) {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ /* TODO Implement me. */
+ throw new UnsupportedOperationException("Downloading server "
+ + "descriptors is not implemented yet.");
+ }
+
+ public void setExcludeServerDescriptors(Set<String> identifier) {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ /* TODO Implement me. */
+ throw new UnsupportedOperationException("Downloading server "
+ + "descriptors is not implemented yet.");
+ }
+
+ public void setIncludeReferencedExtraInfoDescriptors() {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ /* TODO Implement me. */
+ throw new UnsupportedOperationException("Downloading extra-info "
+ + "descriptors is not implemented yet.");
+ }
+
+ public void setExcludeExtraInfoDescriptor(String identifier) {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ /* TODO Implement me. */
+ throw new UnsupportedOperationException("Downloading extra-info "
+ + "descriptors is not implemented yet.");
+ }
+
+ public void setExcludeExtraInfoDescriptors(Set<String> identifiers) {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ /* TODO Implement me. */
+ throw new UnsupportedOperationException("Downloading extra-info "
+ + "descriptors is not implemented yet.");
+ }
+
+ private long readTimeoutMillis = 60L * 1000L;
+ public void setReadTimeout(long readTimeoutMillis) {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ if (readTimeoutMillis < 0L) {
+ throw new IllegalArgumentException("Read timeout value "
+ + String.valueOf(readTimeoutMillis) + " may not be "
+ + "negative.");
+ }
+ this.readTimeoutMillis = readTimeoutMillis;
+ }
+
+ private long connectTimeoutMillis = 60L * 1000L;
+ public void setConnectTimeout(long connectTimeoutMillis) {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ if (connectTimeoutMillis < 0L) {
+ throw new IllegalArgumentException("Connect timeout value "
+ + String.valueOf(connectTimeoutMillis) + " may not be "
+ + "negative.");
+ }
+ this.connectTimeoutMillis = connectTimeoutMillis;
+ }
+
+ private long globalTimeoutMillis = 60L * 60L * 1000L;
+ public void setGlobalTimeout(long globalTimeoutMillis) {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ if (globalTimeoutMillis < 0L) {
+ throw new IllegalArgumentException("Global timeout value "
+ + String.valueOf(globalTimeoutMillis) + " may not be "
+ + "negative.");
+ }
+ this.globalTimeoutMillis = globalTimeoutMillis;
+ }
+
+ private boolean failUnrecognizedDescriptorLines = false;
+ public void setFailUnrecognizedDescriptorLines() {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to download.");
+ }
+ this.failUnrecognizedDescriptorLines = true;
+ }
+
+ public Iterator<DescriptorRequest> downloadDescriptors() {
+ if (this.hasStartedDownloading) {
+ throw new IllegalStateException("Initiating downloads is only "
+ + "permitted once.");
+ }
+ this.hasStartedDownloading = true;
+ DownloadCoordinatorImpl downloadCoordinator =
+ new DownloadCoordinatorImpl(this.directoryAuthorities,
+ this.directoryMirrors, this.downloadConsensus,
+ this.downloadConsensusFromAllAuthorities, this.downloadVotes,
+ this.includeCurrentReferencedVotes, this.connectTimeoutMillis,
+ this.readTimeoutMillis, this.globalTimeoutMillis,
+ this.failUnrecognizedDescriptorLines);
+ Iterator<DescriptorRequest> descriptorQueue = downloadCoordinator.
+ getDescriptorQueue();
+ return descriptorQueue;
+ }
+}
+
diff --git a/src/org/torproject/descriptor/impl/DescriptorReaderImpl.java b/src/org/torproject/descriptor/impl/DescriptorReaderImpl.java
new file mode 100644
index 0000000..c22cbe8
--- /dev/null
+++ b/src/org/torproject/descriptor/impl/DescriptorReaderImpl.java
@@ -0,0 +1,194 @@
+/* Copyright 2011, 2012 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.descriptor.impl;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.Stack;
+import java.util.TreeMap;
+
+import org.torproject.descriptor.Descriptor;
+import org.torproject.descriptor.DescriptorFile;
+import org.torproject.descriptor.DescriptorReader;
+
+public class DescriptorReaderImpl implements DescriptorReader {
+
+ private boolean hasStartedReading = false;
+
+ private List<File> directories = new ArrayList<File>();
+ public void addDirectory(File directory) {
+ if (this.hasStartedReading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to read.");
+ }
+ this.directories.add(directory);
+ }
+
+ private File historyFile;
+ public void setExcludeFiles(File historyFile) {
+ if (this.hasStartedReading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to read.");
+ }
+ this.historyFile = historyFile;
+ }
+
+ private boolean failUnrecognizedDescriptorLines = false;
+ public void setFailUnrecognizedDescriptorLines() {
+ if (this.hasStartedReading) {
+ throw new IllegalStateException("Reconfiguration is not permitted "
+ + "after starting to read.");
+ }
+ this.failUnrecognizedDescriptorLines = true;
+ }
+
+ public Iterator<DescriptorFile> readDescriptors() {
+ if (this.hasStartedReading) {
+ throw new IllegalStateException("Initiating reading is only "
+ + "permitted once.");
+ }
+ this.hasStartedReading = true;
+ BlockingIteratorImpl<DescriptorFile> descriptorQueue =
+ new BlockingIteratorImpl<DescriptorFile>();
+ DescriptorReaderRunnable reader = new DescriptorReaderRunnable(
+ this.directories, descriptorQueue, this.historyFile,
+ this.failUnrecognizedDescriptorLines);
+ new Thread(reader).start();
+ return descriptorQueue;
+ }
+
+ private static class DescriptorReaderRunnable implements Runnable {
+ private List<File> directories;
+ private BlockingIteratorImpl<DescriptorFile> descriptorQueue;
+ private File historyFile;
+ private boolean failUnrecognizedDescriptorLines;
+ private DescriptorReaderRunnable(List<File> directories,
+ BlockingIteratorImpl<DescriptorFile> descriptorQueue,
+ File historyFile, boolean failUnrecognizedDescriptorLines) {
+ this.directories = directories;
+ this.descriptorQueue = descriptorQueue;
+ this.historyFile = historyFile;
+ this.failUnrecognizedDescriptorLines =
+ failUnrecognizedDescriptorLines;
+ }
+ public void run() {
+ this.readOldHistory();
+ this.readDescriptors();
+ this.writeNewHistory();
+ }
+ private SortedMap<String, Long>
+ oldHistory = new TreeMap<String, Long>(),
+ newHistory = new TreeMap<String, Long>();
+ private void readOldHistory() {
+ if (this.historyFile == null) {
+ return;
+ }
+ try {
+ BufferedReader br = new BufferedReader(new FileReader(
+ this.historyFile));
+ String line;
+ while ((line = br.readLine()) != null) {
+ if (!line.contains(" ")) {
+ /* TODO Handle this problem? */
+ continue;
+ }
+ long lastModifiedMillis = Long.parseLong(line.substring(0,
+ line.indexOf(" ")));
+ String absolutePath = line.substring(line.indexOf(" ") + 1);
+ this.oldHistory.put(absolutePath, lastModifiedMillis);
+ }
+ br.close();
+ } catch (IOException e) {
+ /* TODO Handle this exception. */
+ } catch (NumberFormatException e) {
+ /* TODO Handle this exception. */
+ }
+ }
+ private void writeNewHistory() {
+ if (this.historyFile == null) {
+ return;
+ }
+ try {
+ if (this.historyFile.getParentFile() != null) {
+ this.historyFile.getParentFile().mkdirs();
+ }
+ BufferedWriter bw = new BufferedWriter(new FileWriter(
+ this.historyFile));
+ for (Map.Entry<String, Long> e : this.newHistory.entrySet()) {
+ String absolutePath = e.getKey();
+ long lastModifiedMillis = e.getValue();
+ bw.write(String.valueOf(lastModifiedMillis) + " " + absolutePath
+ + "\n");
+ }
+ bw.close();
+ } catch (IOException e) {
+ /* TODO Handle this exception. */
+ }
+ }
+ private void readDescriptors() {
+ for (File directory : this.directories) {
+ Stack<File> files = new Stack<File>();
+ files.add(directory);
+ boolean abortReading = false;
+ while (!abortReading && !files.isEmpty()) {
+ File file = files.pop();
+ if (file.isDirectory()) {
+ files.addAll(Arrays.asList(file.listFiles()));
+ } else {
+ String absolutePath = file.getAbsolutePath();
+ long lastModifiedMillis = file.lastModified();
+ this.newHistory.put(absolutePath, lastModifiedMillis);
+ if (this.oldHistory.containsKey(absolutePath) &&
+ this.oldHistory.get(absolutePath) == lastModifiedMillis) {
+ continue;
+ }
+ DescriptorFileImpl descriptorFile = new DescriptorFileImpl();
+ try {
+ descriptorFile.setDirectory(directory);
+ descriptorFile.setFile(file);
+ descriptorFile.setLastModified(lastModifiedMillis);
+ descriptorFile.setDescriptors(this.readFile(file));
+ } catch (DescriptorParseException e) {
+ descriptorFile.setException(e);
+ } catch (IOException e) {
+ descriptorFile.setException(e);
+ abortReading = true;
+ }
+ this.descriptorQueue.add(descriptorFile);
+ }
+ }
+ }
+ this.descriptorQueue.setOutOfDescriptors();
+ }
+ private List<Descriptor> readFile(File file) throws IOException,
+ DescriptorParseException {
+ FileInputStream fis = new FileInputStream(file);
+ BufferedInputStream bis = new BufferedInputStream(fis);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int len;
+ byte[] data = new byte[1024];
+ while ((len = bis.read(data, 0, 1024)) >= 0) {
+ baos.write(data, 0, len);
+ }
+ bis.close();
+ byte[] rawDescriptorBytes = baos.toByteArray();
+ return DescriptorImpl.parseRelayOrBridgeDescriptors(
+ rawDescriptorBytes, file.getName(),
+ this.failUnrecognizedDescriptorLines);
+ }
+ }
+}
+
diff --git a/src/org/torproject/descriptor/impl/RelayDescriptorDownloaderImpl.java b/src/org/torproject/descriptor/impl/RelayDescriptorDownloaderImpl.java
deleted file mode 100644
index 6993509..0000000
--- a/src/org/torproject/descriptor/impl/RelayDescriptorDownloaderImpl.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/* Copyright 2011, 2012 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.descriptor.impl;
-
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import org.torproject.descriptor.DescriptorRequest;
-import org.torproject.descriptor.RelayDescriptorDownloader;
-
-public class RelayDescriptorDownloaderImpl
- implements RelayDescriptorDownloader {
-
- private boolean hasStartedDownloading = false;
-
- private SortedMap<String, DirectoryDownloader> directoryAuthorities =
- new TreeMap<String, DirectoryDownloader>();
- public void addDirectoryAuthority(String nickname, String ip,
- int dirPort) {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- this.checkDirectoryParameters(nickname, ip, dirPort);
- DirectoryDownloader directoryAuthority = new DirectoryDownloader(
- nickname, ip, dirPort);
- this.directoryAuthorities.put(nickname, directoryAuthority);
- }
-
- private SortedMap<String, DirectoryDownloader> directoryMirrors =
- new TreeMap<String, DirectoryDownloader>();
- public void addDirectoryMirror(String nickname, String ip,
- int dirPort) {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- this.checkDirectoryParameters(nickname, ip, dirPort);
- DirectoryDownloader directoryMirror = new DirectoryDownloader(
- nickname, ip, dirPort);
- this.directoryMirrors.put(nickname, directoryMirror);
- /* TODO Implement prioritizing mirrors for non-vote downloads. */
- throw new UnsupportedOperationException("Prioritizing directory "
- + "mirrors over directory authorities is not implemented yet. "
- + "Until it is, configuring directory mirrors is misleading and "
- + "therefore not supported.");
- }
-
- private void checkDirectoryParameters(String nickname, String ip,
- int dirPort) {
- if (nickname == null || nickname.length() < 1) {
- throw new IllegalArgumentException("'" + nickname + "' is not a "
- + "valid nickname.");
- }
- if (ip == null || ip.length() < 7 || ip.split("\\.").length != 4) {
- throw new IllegalArgumentException("'" + ip + "' is not a valid IP "
- + "address.");
- }
- if (dirPort < 1 || dirPort > 65535) {
- throw new IllegalArgumentException(String.valueOf(dirPort) + " is "
- + "not a valid DirPort.");
- }
- /* TODO Relax the requirement for directory nicknames to be unique.
- * In theory, we can identify them by ip+port. */
- if (this.directoryAuthorities.containsKey(nickname) ||
- this.directoryMirrors.containsKey(nickname)) {
- throw new IllegalArgumentException("Directory nicknames must be "
- + "unique.");
- }
- }
-
- private boolean downloadConsensus = false;
- public void setIncludeCurrentConsensus() {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- this.downloadConsensus = true;
- }
-
- private boolean downloadConsensusFromAllAuthorities = false;
- public void setIncludeCurrentConsensusFromAllDirectoryAuthorities() {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- this.downloadConsensusFromAllAuthorities = true;
- }
-
- private boolean includeCurrentReferencedVotes = false;
- public void setIncludeCurrentReferencedVotes() {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- this.includeCurrentReferencedVotes = true;
- }
-
- private Set<String> downloadVotes = new HashSet<String>();
- public void setIncludeCurrentVote(String fingerprint) {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- this.checkVoteFingerprint(fingerprint);
- this.downloadVotes.add(fingerprint);
- }
-
- public void setIncludeCurrentVotes(Set<String> fingerprints) {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- if (fingerprints == null) {
- throw new IllegalArgumentException("Set of fingerprints must not "
- + "be null.");
- }
- for (String fingerprint : fingerprints) {
- this.checkVoteFingerprint(fingerprint);
- }
- for (String fingerprint : fingerprints) {
- this.setIncludeCurrentVote(fingerprint);
- }
- }
-
- private void checkVoteFingerprint(String fingerprint) {
- if (fingerprint == null || fingerprint.length() != 40) {
- throw new IllegalArgumentException("'" + fingerprint + "' is not a "
- + "valid fingerprint.");
- }
- }
-
- public void setIncludeReferencedServerDescriptors() {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- /* TODO Implement me. */
- throw new UnsupportedOperationException("Downloading server "
- + "descriptors is not implemented yet.");
- }
-
- public void setExcludeServerDescriptor(String identifier) {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- /* TODO Implement me. */
- throw new UnsupportedOperationException("Downloading server "
- + "descriptors is not implemented yet.");
- }
-
- public void setExcludeServerDescriptors(Set<String> identifier) {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- /* TODO Implement me. */
- throw new UnsupportedOperationException("Downloading server "
- + "descriptors is not implemented yet.");
- }
-
- public void setIncludeReferencedExtraInfoDescriptors() {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- /* TODO Implement me. */
- throw new UnsupportedOperationException("Downloading extra-info "
- + "descriptors is not implemented yet.");
- }
-
- public void setExcludeExtraInfoDescriptor(String identifier) {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- /* TODO Implement me. */
- throw new UnsupportedOperationException("Downloading extra-info "
- + "descriptors is not implemented yet.");
- }
-
- public void setExcludeExtraInfoDescriptors(Set<String> identifiers) {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- /* TODO Implement me. */
- throw new UnsupportedOperationException("Downloading extra-info "
- + "descriptors is not implemented yet.");
- }
-
- private long readTimeoutMillis = 60L * 1000L;
- public void setReadTimeout(long readTimeoutMillis) {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- if (readTimeoutMillis < 0L) {
- throw new IllegalArgumentException("Read timeout value "
- + String.valueOf(readTimeoutMillis) + " may not be "
- + "negative.");
- }
- this.readTimeoutMillis = readTimeoutMillis;
- }
-
- private long connectTimeoutMillis = 60L * 1000L;
- public void setConnectTimeout(long connectTimeoutMillis) {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- if (connectTimeoutMillis < 0L) {
- throw new IllegalArgumentException("Connect timeout value "
- + String.valueOf(connectTimeoutMillis) + " may not be "
- + "negative.");
- }
- this.connectTimeoutMillis = connectTimeoutMillis;
- }
-
- private long globalTimeoutMillis = 60L * 60L * 1000L;
- public void setGlobalTimeout(long globalTimeoutMillis) {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- if (globalTimeoutMillis < 0L) {
- throw new IllegalArgumentException("Global timeout value "
- + String.valueOf(globalTimeoutMillis) + " may not be "
- + "negative.");
- }
- this.globalTimeoutMillis = globalTimeoutMillis;
- }
-
- private boolean failUnrecognizedDescriptorLines = false;
- public void setFailUnrecognizedDescriptorLines() {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to download.");
- }
- this.failUnrecognizedDescriptorLines = true;
- }
-
- public Iterator<DescriptorRequest> downloadDescriptors() {
- if (this.hasStartedDownloading) {
- throw new IllegalStateException("Initiating downloads is only "
- + "permitted once.");
- }
- this.hasStartedDownloading = true;
- DownloadCoordinatorImpl downloadCoordinator =
- new DownloadCoordinatorImpl(this.directoryAuthorities,
- this.directoryMirrors, this.downloadConsensus,
- this.downloadConsensusFromAllAuthorities, this.downloadVotes,
- this.includeCurrentReferencedVotes, this.connectTimeoutMillis,
- this.readTimeoutMillis, this.globalTimeoutMillis,
- this.failUnrecognizedDescriptorLines);
- Iterator<DescriptorRequest> descriptorQueue = downloadCoordinator.
- getDescriptorQueue();
- return descriptorQueue;
- }
-}
-
diff --git a/src/org/torproject/descriptor/impl/RelayOrBridgeDescriptorReaderImpl.java b/src/org/torproject/descriptor/impl/RelayOrBridgeDescriptorReaderImpl.java
deleted file mode 100644
index 60c1e36..0000000
--- a/src/org/torproject/descriptor/impl/RelayOrBridgeDescriptorReaderImpl.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/* Copyright 2011, 2012 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.descriptor.impl;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.Stack;
-import java.util.TreeMap;
-
-import org.torproject.descriptor.BridgeDescriptorReader;
-import org.torproject.descriptor.BridgePoolAssignmentReader;
-import org.torproject.descriptor.Descriptor;
-import org.torproject.descriptor.DescriptorFile;
-import org.torproject.descriptor.RelayDescriptorReader;
-
-public class RelayOrBridgeDescriptorReaderImpl
- implements RelayDescriptorReader, BridgeDescriptorReader,
- BridgePoolAssignmentReader {
-
- private boolean hasStartedReading = false;
-
- private List<File> directories = new ArrayList<File>();
- public void addDirectory(File directory) {
- if (this.hasStartedReading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to read.");
- }
- this.directories.add(directory);
- }
-
- private File historyFile;
- public void setExcludeFiles(File historyFile) {
- if (this.hasStartedReading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to read.");
- }
- this.historyFile = historyFile;
- }
-
- private boolean failUnrecognizedDescriptorLines = false;
- public void setFailUnrecognizedDescriptorLines() {
- if (this.hasStartedReading) {
- throw new IllegalStateException("Reconfiguration is not permitted "
- + "after starting to read.");
- }
- this.failUnrecognizedDescriptorLines = true;
- }
-
- public Iterator<DescriptorFile> readDescriptors() {
- if (this.hasStartedReading) {
- throw new IllegalStateException("Initiating reading is only "
- + "permitted once.");
- }
- this.hasStartedReading = true;
- BlockingIteratorImpl<DescriptorFile> descriptorQueue =
- new BlockingIteratorImpl<DescriptorFile>();
- DescriptorReader reader = new DescriptorReader(this.directories,
- descriptorQueue, this.historyFile,
- this.failUnrecognizedDescriptorLines);
- new Thread(reader).start();
- return descriptorQueue;
- }
-
- private static class DescriptorReader implements Runnable {
- private List<File> directories;
- private BlockingIteratorImpl<DescriptorFile> descriptorQueue;
- private File historyFile;
- private boolean failUnrecognizedDescriptorLines;
- private DescriptorReader(List<File> directories,
- BlockingIteratorImpl<DescriptorFile> descriptorQueue,
- File historyFile, boolean failUnrecognizedDescriptorLines) {
- this.directories = directories;
- this.descriptorQueue = descriptorQueue;
- this.historyFile = historyFile;
- this.failUnrecognizedDescriptorLines =
- failUnrecognizedDescriptorLines;
- }
- public void run() {
- this.readOldHistory();
- this.readDescriptors();
- this.writeNewHistory();
- }
- private SortedMap<String, Long>
- oldHistory = new TreeMap<String, Long>(),
- newHistory = new TreeMap<String, Long>();
- private void readOldHistory() {
- if (this.historyFile == null) {
- return;
- }
- try {
- BufferedReader br = new BufferedReader(new FileReader(
- this.historyFile));
- String line;
- while ((line = br.readLine()) != null) {
- if (!line.contains(" ")) {
- /* TODO Handle this problem? */
- continue;
- }
- long lastModifiedMillis = Long.parseLong(line.substring(0,
- line.indexOf(" ")));
- String absolutePath = line.substring(line.indexOf(" ") + 1);
- this.oldHistory.put(absolutePath, lastModifiedMillis);
- }
- br.close();
- } catch (IOException e) {
- /* TODO Handle this exception. */
- } catch (NumberFormatException e) {
- /* TODO Handle this exception. */
- }
- }
- private void writeNewHistory() {
- if (this.historyFile == null) {
- return;
- }
- try {
- if (this.historyFile.getParentFile() != null) {
- this.historyFile.getParentFile().mkdirs();
- }
- BufferedWriter bw = new BufferedWriter(new FileWriter(
- this.historyFile));
- for (Map.Entry<String, Long> e : this.newHistory.entrySet()) {
- String absolutePath = e.getKey();
- long lastModifiedMillis = e.getValue();
- bw.write(String.valueOf(lastModifiedMillis) + " " + absolutePath
- + "\n");
- }
- bw.close();
- } catch (IOException e) {
- /* TODO Handle this exception. */
- }
- }
- private void readDescriptors() {
- for (File directory : this.directories) {
- Stack<File> files = new Stack<File>();
- files.add(directory);
- boolean abortReading = false;
- while (!abortReading && !files.isEmpty()) {
- File file = files.pop();
- if (file.isDirectory()) {
- files.addAll(Arrays.asList(file.listFiles()));
- } else {
- String absolutePath = file.getAbsolutePath();
- long lastModifiedMillis = file.lastModified();
- this.newHistory.put(absolutePath, lastModifiedMillis);
- if (this.oldHistory.containsKey(absolutePath) &&
- this.oldHistory.get(absolutePath) == lastModifiedMillis) {
- continue;
- }
- DescriptorFileImpl descriptorFile = new DescriptorFileImpl();
- try {
- descriptorFile.setDirectory(directory);
- descriptorFile.setFile(file);
- descriptorFile.setLastModified(lastModifiedMillis);
- descriptorFile.setDescriptors(this.readFile(file));
- } catch (DescriptorParseException e) {
- descriptorFile.setException(e);
- } catch (IOException e) {
- descriptorFile.setException(e);
- abortReading = true;
- }
- this.descriptorQueue.add(descriptorFile);
- }
- }
- }
- this.descriptorQueue.setOutOfDescriptors();
- }
- private List<Descriptor> readFile(File file) throws IOException,
- DescriptorParseException {
- FileInputStream fis = new FileInputStream(file);
- BufferedInputStream bis = new BufferedInputStream(fis);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int len;
- byte[] data = new byte[1024];
- while ((len = bis.read(data, 0, 1024)) >= 0) {
- baos.write(data, 0, len);
- }
- bis.close();
- byte[] rawDescriptorBytes = baos.toByteArray();
- return DescriptorImpl.parseRelayOrBridgeDescriptors(
- rawDescriptorBytes, file.getName(),
- this.failUnrecognizedDescriptorLines);
- }
- }
-}
-