forked from Qortal/qortal
Replaced all IllegalStateException with DataException in arbitrary code
This was necessary to ensure that all exceptions are caught intentionally, as otherwise it creates endless amounts of edge cases.
This commit is contained in:
parent
8cb06bf451
commit
73e609fa29
@ -36,7 +36,7 @@ public class ArbitraryDataBuildQueueItem {
|
||||
public void build() throws IOException, DataException, MissingDataException {
|
||||
Long now = NTP.getTime();
|
||||
if (now == null) {
|
||||
throw new IllegalStateException("NTP time hasn't synced yet");
|
||||
throw new DataException("NTP time hasn't synced yet");
|
||||
}
|
||||
|
||||
this.buildStartTimestamp = now;
|
||||
|
@ -88,7 +88,7 @@ public class ArbitraryDataBuilder {
|
||||
if (latestPut == null) {
|
||||
String message = String.format("Couldn't find PUT transaction for name %s, service %s and identifier %s",
|
||||
this.name, this.service, this.identifierString());
|
||||
throw new IllegalStateException(message);
|
||||
throw new DataException(message);
|
||||
}
|
||||
this.latestPutTransaction = latestPut;
|
||||
|
||||
@ -101,25 +101,25 @@ public class ArbitraryDataBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void validateTransactions() {
|
||||
private void validateTransactions() throws DataException {
|
||||
List<ArbitraryTransactionData> transactionDataList = new ArrayList<>(this.transactions);
|
||||
ArbitraryTransactionData latestPut = this.latestPutTransaction;
|
||||
|
||||
if (latestPut == null) {
|
||||
throw new IllegalStateException("Cannot PATCH without existing PUT. Deploy using PUT first.");
|
||||
throw new DataException("Cannot PATCH without existing PUT. Deploy using PUT first.");
|
||||
}
|
||||
if (latestPut.getMethod() != Method.PUT) {
|
||||
throw new IllegalStateException("Expected PUT but received PATCH");
|
||||
throw new DataException("Expected PUT but received PATCH");
|
||||
}
|
||||
if (transactionDataList.size() == 0) {
|
||||
throw new IllegalStateException(String.format("No transactions found for name %s, service %s, " +
|
||||
throw new DataException(String.format("No transactions found for name %s, service %s, " +
|
||||
"identifier: %s, since %d", name, service, this.identifierString(), latestPut.getTimestamp()));
|
||||
}
|
||||
|
||||
// Verify that the signature of the first transaction matches the latest PUT
|
||||
ArbitraryTransactionData firstTransaction = transactionDataList.get(0);
|
||||
if (!Arrays.equals(firstTransaction.getSignature(), latestPut.getSignature())) {
|
||||
throw new IllegalStateException("First transaction did not match latest PUT transaction");
|
||||
throw new DataException("First transaction did not match latest PUT transaction");
|
||||
}
|
||||
|
||||
// Remove the first transaction, as it should be the only PUT
|
||||
@ -127,10 +127,10 @@ public class ArbitraryDataBuilder {
|
||||
|
||||
for (ArbitraryTransactionData transactionData : transactionDataList) {
|
||||
if (transactionData == null) {
|
||||
throw new IllegalStateException("Transaction not found");
|
||||
throw new DataException("Transaction not found");
|
||||
}
|
||||
if (transactionData.getMethod() != Method.PATCH) {
|
||||
throw new IllegalStateException("Expected PATCH but received PUT");
|
||||
throw new DataException("Expected PATCH but received PUT");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -173,32 +173,32 @@ public class ArbitraryDataBuilder {
|
||||
// By this point we should have all data needed to build the layers
|
||||
Path path = arbitraryDataReader.getFilePath();
|
||||
if (path == null) {
|
||||
throw new IllegalStateException(String.format("Null path when building data from transaction %s", sig58));
|
||||
throw new DataException(String.format("Null path when building data from transaction %s", sig58));
|
||||
}
|
||||
if (!Files.exists(path)) {
|
||||
throw new IllegalStateException(String.format("Path doesn't exist when building data from transaction %s", sig58));
|
||||
throw new DataException(String.format("Path doesn't exist when building data from transaction %s", sig58));
|
||||
}
|
||||
paths.add(path);
|
||||
}
|
||||
}
|
||||
|
||||
private void findLatestSignature() {
|
||||
private void findLatestSignature() throws DataException {
|
||||
if (this.transactions.size() == 0) {
|
||||
throw new IllegalStateException("Unable to find latest signature from empty transaction list");
|
||||
throw new DataException("Unable to find latest signature from empty transaction list");
|
||||
}
|
||||
|
||||
// Find the latest signature
|
||||
ArbitraryTransactionData latestTransaction = this.transactions.get(this.transactions.size() - 1);
|
||||
if (latestTransaction == null) {
|
||||
throw new IllegalStateException("Unable to find latest signature from null transaction");
|
||||
throw new DataException("Unable to find latest signature from null transaction");
|
||||
}
|
||||
|
||||
this.latestSignature = latestTransaction.getSignature();
|
||||
}
|
||||
|
||||
private void validatePaths() {
|
||||
private void validatePaths() throws DataException {
|
||||
if (this.paths.isEmpty()) {
|
||||
throw new IllegalStateException("No paths available from which to build latest state");
|
||||
throw new DataException("No paths available from which to build latest state");
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,7 +238,7 @@ public class ArbitraryDataBuilder {
|
||||
private void cacheLatestSignature() throws IOException, DataException {
|
||||
byte[] latestTransactionSignature = this.transactions.get(this.transactions.size()-1).getSignature();
|
||||
if (latestTransactionSignature == null) {
|
||||
throw new IllegalStateException("Missing latest transaction signature");
|
||||
throw new DataException("Missing latest transaction signature");
|
||||
}
|
||||
Long now = NTP.getTime();
|
||||
if (now == null) {
|
||||
|
@ -153,7 +153,7 @@ public class ArbitraryDataCache {
|
||||
cache.read();
|
||||
return cache.getSignature();
|
||||
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | DataException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -79,12 +79,12 @@ public class ArbitraryDataCombiner {
|
||||
}
|
||||
}
|
||||
|
||||
private void preExecute() {
|
||||
private void preExecute() throws DataException {
|
||||
if (this.pathBefore == null || this.pathAfter == null) {
|
||||
throw new IllegalStateException("No paths available to build patch");
|
||||
throw new DataException("No paths available to build patch");
|
||||
}
|
||||
if (!Files.exists(this.pathBefore) || !Files.exists(this.pathAfter)) {
|
||||
throw new IllegalStateException("Unable to create patch because at least one path doesn't exist");
|
||||
throw new DataException("Unable to create patch because at least one path doesn't exist");
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,35 +92,35 @@ public class ArbitraryDataCombiner {
|
||||
|
||||
}
|
||||
|
||||
private void readMetadata() throws IOException {
|
||||
private void readMetadata() throws IOException, DataException {
|
||||
this.metadata = new ArbitraryDataMetadataPatch(this.pathAfter);
|
||||
this.metadata.read();
|
||||
}
|
||||
|
||||
private void validatePreviousSignature() {
|
||||
private void validatePreviousSignature() throws DataException {
|
||||
if (this.signatureBefore == null) {
|
||||
throw new IllegalStateException("No previous signature passed to the combiner");
|
||||
throw new DataException("No previous signature passed to the combiner");
|
||||
}
|
||||
|
||||
byte[] previousSignature = this.metadata.getPreviousSignature();
|
||||
if (previousSignature == null) {
|
||||
throw new IllegalStateException("Unable to extract previous signature from patch metadata");
|
||||
throw new DataException("Unable to extract previous signature from patch metadata");
|
||||
}
|
||||
|
||||
// Compare the signatures
|
||||
if (!Arrays.equals(previousSignature, this.signatureBefore)) {
|
||||
throw new IllegalStateException("Previous signatures do not match - transactions out of order?");
|
||||
throw new DataException("Previous signatures do not match - transactions out of order?");
|
||||
}
|
||||
}
|
||||
|
||||
private void validatePreviousHash() throws IOException {
|
||||
private void validatePreviousHash() throws IOException, DataException {
|
||||
if (!Settings.getInstance().shouldValidateAllDataLayers()) {
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] previousHash = this.metadata.getPreviousHash();
|
||||
if (previousHash == null) {
|
||||
throw new IllegalStateException("Unable to extract previous hash from patch metadata");
|
||||
throw new DataException("Unable to extract previous hash from patch metadata");
|
||||
}
|
||||
|
||||
ArbitraryDataDigest digest = new ArbitraryDataDigest(this.pathBefore);
|
||||
@ -139,14 +139,14 @@ public class ArbitraryDataCombiner {
|
||||
this.finalPath = merge.getMergePath();
|
||||
}
|
||||
|
||||
private void validateCurrentHash() throws IOException {
|
||||
private void validateCurrentHash() throws IOException, DataException {
|
||||
if (!this.shouldValidateHashes) {
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] currentHash = this.metadata.getCurrentHash();
|
||||
if (currentHash == null) {
|
||||
throw new IllegalStateException("Unable to extract current hash from patch metadata");
|
||||
throw new DataException("Unable to extract current hash from patch metadata");
|
||||
}
|
||||
|
||||
ArbitraryDataDigest digest = new ArbitraryDataDigest(this.finalPath);
|
||||
|
@ -48,12 +48,12 @@ public class ArbitraryDataCreatePatch {
|
||||
}
|
||||
}
|
||||
|
||||
private void preExecute() {
|
||||
private void preExecute() throws DataException {
|
||||
if (this.pathBefore == null || this.pathAfter == null) {
|
||||
throw new IllegalStateException("No paths available to build patch");
|
||||
throw new DataException("No paths available to build patch");
|
||||
}
|
||||
if (!Files.exists(this.pathBefore) || !Files.exists(this.pathAfter)) {
|
||||
throw new IllegalStateException("Unable to create patch because at least one path doesn't exist");
|
||||
throw new DataException("Unable to create patch because at least one path doesn't exist");
|
||||
}
|
||||
|
||||
this.createRandomIdentifier();
|
||||
@ -84,14 +84,14 @@ public class ArbitraryDataCreatePatch {
|
||||
this.identifier = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
private void createWorkingDirectory() {
|
||||
private void createWorkingDirectory() throws DataException {
|
||||
// Use the user-specified temp dir, as it is deterministic, and is more likely to be located on reusable storage hardware
|
||||
String baseDir = Settings.getInstance().getTempDataPath();
|
||||
Path tempDir = Paths.get(baseDir, "patch", this.identifier);
|
||||
try {
|
||||
Files.createDirectories(tempDir);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to create temp directory");
|
||||
throw new DataException("Unable to create temp directory");
|
||||
}
|
||||
this.workingPath = tempDir;
|
||||
}
|
||||
@ -114,7 +114,7 @@ public class ArbitraryDataCreatePatch {
|
||||
}
|
||||
}
|
||||
|
||||
private void process() throws IOException {
|
||||
private void process() throws IOException, DataException {
|
||||
|
||||
ArbitraryDataDiff diff = new ArbitraryDataDiff(this.pathBefore, this.pathAfter, this.previousSignature);
|
||||
this.finalPath = diff.getDiffPath();
|
||||
|
@ -6,6 +6,7 @@ import org.json.JSONObject;
|
||||
import org.qortal.arbitrary.metadata.ArbitraryDataMetadataPatch;
|
||||
import org.qortal.arbitrary.patch.UnifiedDiffPatch;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.settings.Settings;
|
||||
|
||||
import java.io.*;
|
||||
@ -75,7 +76,7 @@ public class ArbitraryDataDiff {
|
||||
|
||||
private int totalFileCount;
|
||||
|
||||
public ArbitraryDataDiff(Path pathBefore, Path pathAfter, byte[] previousSignature) {
|
||||
public ArbitraryDataDiff(Path pathBefore, Path pathAfter, byte[] previousSignature) throws DataException {
|
||||
this.pathBefore = pathBefore;
|
||||
this.pathAfter = pathAfter;
|
||||
this.previousSignature = previousSignature;
|
||||
@ -88,7 +89,7 @@ public class ArbitraryDataDiff {
|
||||
this.createOutputDirectory();
|
||||
}
|
||||
|
||||
public void compute() throws IOException {
|
||||
public void compute() throws IOException, DataException {
|
||||
try {
|
||||
this.preExecute();
|
||||
this.hashPreviousState();
|
||||
@ -115,19 +116,19 @@ public class ArbitraryDataDiff {
|
||||
this.identifier = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
private void createOutputDirectory() {
|
||||
private void createOutputDirectory() throws DataException {
|
||||
// Use the user-specified temp dir, as it is deterministic, and is more likely to be located on reusable storage hardware
|
||||
String baseDir = Settings.getInstance().getTempDataPath();
|
||||
Path tempDir = Paths.get(baseDir, "diff", this.identifier);
|
||||
try {
|
||||
Files.createDirectories(tempDir);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to create temp directory");
|
||||
throw new DataException("Unable to create temp directory");
|
||||
}
|
||||
this.diffPath = tempDir;
|
||||
}
|
||||
|
||||
private void hashPreviousState() throws IOException {
|
||||
private void hashPreviousState() throws IOException, DataException {
|
||||
ArbitraryDataDigest digest = new ArbitraryDataDigest(this.pathBefore);
|
||||
digest.compute();
|
||||
this.previousHash = digest.getHash();
|
||||
@ -181,7 +182,12 @@ public class ArbitraryDataDiff {
|
||||
diff.copyFilePathToBaseDir(afterPathAbsolute, diffPathAbsolute, afterPathRelative);
|
||||
}
|
||||
if (wasModified) {
|
||||
try {
|
||||
diff.pathModified(beforePathAbsolute, afterPathAbsolute, afterPathRelative, diffPathAbsolute);
|
||||
} catch (DataException e) {
|
||||
// We can only throw IOExceptions because we are overriding FileVisitor.visitFile()
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep a tally of the total number of files to help with decision making
|
||||
@ -273,19 +279,19 @@ public class ArbitraryDataDiff {
|
||||
}
|
||||
}
|
||||
|
||||
private void validate() {
|
||||
private void validate() throws DataException {
|
||||
if (this.addedPaths.isEmpty() && this.modifiedPaths.isEmpty() && this.removedPaths.isEmpty()) {
|
||||
throw new IllegalStateException("Current state matches previous state. Nothing to do.");
|
||||
throw new DataException("Current state matches previous state. Nothing to do.");
|
||||
}
|
||||
}
|
||||
|
||||
private void hashCurrentState() throws IOException {
|
||||
private void hashCurrentState() throws IOException, DataException {
|
||||
ArbitraryDataDigest digest = new ArbitraryDataDigest(this.pathAfter);
|
||||
digest.compute();
|
||||
this.currentHash = digest.getHash();
|
||||
}
|
||||
|
||||
private void writeMetadata() throws IOException {
|
||||
private void writeMetadata() throws IOException, DataException {
|
||||
ArbitraryDataMetadataPatch metadata = new ArbitraryDataMetadataPatch(this.diffPath);
|
||||
metadata.setAddedPaths(this.addedPaths);
|
||||
metadata.setModifiedPaths(this.modifiedPaths);
|
||||
@ -298,7 +304,7 @@ public class ArbitraryDataDiff {
|
||||
|
||||
|
||||
private void pathModified(Path beforePathAbsolute, Path afterPathAbsolute, Path afterPathRelative,
|
||||
Path destinationBasePathAbsolute) throws IOException {
|
||||
Path destinationBasePathAbsolute) throws IOException, DataException {
|
||||
|
||||
Path destination = Paths.get(destinationBasePathAbsolute.toString(), afterPathRelative.toString());
|
||||
long beforeSize = Files.size(beforePathAbsolute);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.qortal.arbitrary;
|
||||
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.utils.Base58;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -21,7 +22,7 @@ public class ArbitraryDataDigest {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public void compute() throws IOException {
|
||||
public void compute() throws IOException, DataException {
|
||||
List<Path> allPaths = Files.walk(path).filter(Files::isRegularFile).sorted().collect(Collectors.toList());
|
||||
Path basePathAbsolute = this.path.toAbsolutePath();
|
||||
|
||||
@ -29,7 +30,7 @@ public class ArbitraryDataDigest {
|
||||
try {
|
||||
sha256 = MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("SHA-256 hashing algorithm unavailable");
|
||||
throw new DataException("SHA-256 hashing algorithm unavailable");
|
||||
}
|
||||
|
||||
for (Path path : allPaths) {
|
||||
|
@ -3,6 +3,7 @@ package org.qortal.arbitrary;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.settings.Settings;
|
||||
import org.qortal.transform.transaction.TransactionTransformer;
|
||||
import org.qortal.utils.Base58;
|
||||
@ -64,14 +65,14 @@ public class ArbitraryDataFile {
|
||||
public ArbitraryDataFile() {
|
||||
}
|
||||
|
||||
public ArbitraryDataFile(String hash58) {
|
||||
public ArbitraryDataFile(String hash58) throws DataException {
|
||||
this.createDataDirectory();
|
||||
this.filePath = ArbitraryDataFile.getOutputFilePath(hash58, false);
|
||||
this.chunks = new ArrayList<>();
|
||||
this.hash58 = hash58;
|
||||
}
|
||||
|
||||
public ArbitraryDataFile(byte[] fileContent) {
|
||||
public ArbitraryDataFile(byte[] fileContent) throws DataException {
|
||||
if (fileContent == null) {
|
||||
LOGGER.error("fileContent is null");
|
||||
return;
|
||||
@ -89,18 +90,18 @@ public class ArbitraryDataFile {
|
||||
if (!this.hash58.equals(this.digest58())) {
|
||||
LOGGER.error("Hash {} does not match file digest {}", this.hash58, this.digest58());
|
||||
this.delete();
|
||||
throw new IllegalStateException("Data file digest validation failed");
|
||||
throw new DataException("Data file digest validation failed");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to write data to file");
|
||||
throw new DataException("Unable to write data to file");
|
||||
}
|
||||
}
|
||||
|
||||
public static ArbitraryDataFile fromHash58(String hash58) {
|
||||
public static ArbitraryDataFile fromHash58(String hash58) throws DataException {
|
||||
return new ArbitraryDataFile(hash58);
|
||||
}
|
||||
|
||||
public static ArbitraryDataFile fromHash(byte[] hash) {
|
||||
public static ArbitraryDataFile fromHash(byte[] hash) throws DataException {
|
||||
return ArbitraryDataFile.fromHash58(Base58.encode(hash));
|
||||
}
|
||||
|
||||
@ -126,7 +127,7 @@ public class ArbitraryDataFile {
|
||||
}
|
||||
return arbitraryDataFile;
|
||||
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | DataException e) {
|
||||
LOGGER.error("Couldn't compute digest for ArbitraryDataFile");
|
||||
}
|
||||
}
|
||||
@ -150,7 +151,7 @@ public class ArbitraryDataFile {
|
||||
return true;
|
||||
}
|
||||
|
||||
private Path copyToDataDirectory(Path sourcePath) {
|
||||
private Path copyToDataDirectory(Path sourcePath) throws DataException {
|
||||
if (this.hash58 == null || this.filePath == null) {
|
||||
return null;
|
||||
}
|
||||
@ -160,11 +161,11 @@ public class ArbitraryDataFile {
|
||||
try {
|
||||
return Files.copy(sourcePath, destPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(String.format("Unable to copy file %s to data directory %s", sourcePath, destPath));
|
||||
throw new DataException(String.format("Unable to copy file %s to data directory %s", sourcePath, destPath));
|
||||
}
|
||||
}
|
||||
|
||||
public static Path getOutputFilePath(String hash58, boolean createDirectories) {
|
||||
public static Path getOutputFilePath(String hash58, boolean createDirectories) throws DataException {
|
||||
if (hash58 == null) {
|
||||
return null;
|
||||
}
|
||||
@ -176,7 +177,7 @@ public class ArbitraryDataFile {
|
||||
try {
|
||||
Files.createDirectories(directory);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to create data subdirectory");
|
||||
throw new DataException("Unable to create data subdirectory");
|
||||
}
|
||||
}
|
||||
return Paths.get(directory.toString(), hash58);
|
||||
@ -208,7 +209,7 @@ public class ArbitraryDataFile {
|
||||
this.chunks.add(chunk);
|
||||
}
|
||||
|
||||
public void addChunkHashes(byte[] chunks) {
|
||||
public void addChunkHashes(byte[] chunks) throws DataException {
|
||||
if (chunks == null || chunks.length == 0) {
|
||||
return;
|
||||
}
|
||||
@ -234,7 +235,7 @@ public class ArbitraryDataFile {
|
||||
return hashes;
|
||||
}
|
||||
|
||||
public int split(int chunkSize) {
|
||||
public int split(int chunkSize) throws DataException {
|
||||
try {
|
||||
|
||||
File file = this.getFile();
|
||||
@ -256,14 +257,14 @@ public class ArbitraryDataFile {
|
||||
if (validationResult == ValidationResult.OK) {
|
||||
this.chunks.add(chunk);
|
||||
} else {
|
||||
throw new IllegalStateException(String.format("Chunk %s is invalid", chunk));
|
||||
throw new DataException(String.format("Chunk %s is invalid", chunk));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Unable to split file into chunks");
|
||||
throw new DataException("Unable to split file into chunks");
|
||||
}
|
||||
|
||||
return this.chunks.size();
|
||||
@ -308,7 +309,7 @@ public class ArbitraryDataFile {
|
||||
return true;
|
||||
} catch (FileNotFoundException e) {
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | DataException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -416,7 +417,7 @@ public class ArbitraryDataFile {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean allChunksExist(byte[] chunks) {
|
||||
public boolean allChunksExist(byte[] chunks) throws DataException {
|
||||
if (chunks == null) {
|
||||
return true;
|
||||
}
|
||||
@ -432,7 +433,7 @@ public class ArbitraryDataFile {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean anyChunksExist(byte[] chunks) {
|
||||
public boolean anyChunksExist(byte[] chunks) throws DataException {
|
||||
if (chunks == null) {
|
||||
return false;
|
||||
}
|
||||
@ -473,7 +474,7 @@ public class ArbitraryDataFile {
|
||||
return this.chunks;
|
||||
}
|
||||
|
||||
public byte[] chunkHashes() {
|
||||
public byte[] chunkHashes() throws DataException {
|
||||
if (this.chunks != null && this.chunks.size() > 0) {
|
||||
// Return null if we only have one chunk, with the same hash as the parent
|
||||
if (Arrays.equals(this.digest(), this.chunks.get(0).digest())) {
|
||||
@ -486,7 +487,7 @@ public class ArbitraryDataFile {
|
||||
byte[] chunkHash = chunk.digest();
|
||||
if (chunkHash.length != 32) {
|
||||
LOGGER.info("Invalid chunk hash length: {}", chunkHash.length);
|
||||
throw new IllegalStateException("Invalid chunk hash length");
|
||||
throw new DataException("Invalid chunk hash length");
|
||||
}
|
||||
outputStream.write(chunk.digest());
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package org.qortal.arbitrary;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.utils.Base58;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -12,19 +13,19 @@ public class ArbitraryDataFileChunk extends ArbitraryDataFile {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(ArbitraryDataFileChunk.class);
|
||||
|
||||
public ArbitraryDataFileChunk(String hash58) {
|
||||
public ArbitraryDataFileChunk(String hash58) throws DataException {
|
||||
super(hash58);
|
||||
}
|
||||
|
||||
public ArbitraryDataFileChunk(byte[] fileContent) {
|
||||
public ArbitraryDataFileChunk(byte[] fileContent) throws DataException {
|
||||
super(fileContent);
|
||||
}
|
||||
|
||||
public static ArbitraryDataFileChunk fromHash58(String hash58) {
|
||||
public static ArbitraryDataFileChunk fromHash58(String hash58) throws DataException {
|
||||
return new ArbitraryDataFileChunk(hash58);
|
||||
}
|
||||
|
||||
public static ArbitraryDataFileChunk fromHash(byte[] hash) {
|
||||
public static ArbitraryDataFileChunk fromHash(byte[] hash) throws DataException {
|
||||
return ArbitraryDataFileChunk.fromHash58(Base58.encode(hash));
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ public class ArbitraryDataMerge {
|
||||
}
|
||||
}
|
||||
|
||||
private void preExecute() {
|
||||
private void preExecute() throws DataException {
|
||||
this.createRandomIdentifier();
|
||||
this.createOutputDirectory();
|
||||
}
|
||||
@ -57,14 +57,14 @@ public class ArbitraryDataMerge {
|
||||
this.identifier = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
private void createOutputDirectory() {
|
||||
private void createOutputDirectory() throws DataException {
|
||||
// Use the user-specified temp dir, as it is deterministic, and is more likely to be located on reusable storage hardware
|
||||
String baseDir = Settings.getInstance().getTempDataPath();
|
||||
Path tempDir = Paths.get(baseDir, "merge", this.identifier);
|
||||
try {
|
||||
Files.createDirectories(tempDir);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to create temp directory");
|
||||
throw new DataException("Unable to create temp directory");
|
||||
}
|
||||
this.mergePath = tempDir;
|
||||
}
|
||||
@ -73,7 +73,7 @@ public class ArbitraryDataMerge {
|
||||
ArbitraryDataMerge.copyDirPathToBaseDir(this.pathBefore, this.mergePath, Paths.get(""));
|
||||
}
|
||||
|
||||
private void loadMetadata() throws IOException {
|
||||
private void loadMetadata() throws IOException, DataException {
|
||||
this.metadata = new ArbitraryDataMetadataPatch(this.pathAfter);
|
||||
this.metadata.read();
|
||||
}
|
||||
|
@ -131,12 +131,11 @@ public class ArbitraryDataReader {
|
||||
* If no exception is thrown, you can then use getFilePath() to access the data immediately after returning
|
||||
*
|
||||
* @param overwrite - set to true to force rebuild an existing cache
|
||||
* @throws IllegalStateException
|
||||
* @throws IOException
|
||||
* @throws DataException
|
||||
* @throws MissingDataException
|
||||
*/
|
||||
public void loadSynchronously(boolean overwrite) throws IllegalStateException, IOException, DataException, MissingDataException {
|
||||
public void loadSynchronously(boolean overwrite) throws DataException, IOException, MissingDataException {
|
||||
try {
|
||||
ArbitraryDataCache cache = new ArbitraryDataCache(this.uncompressedPath, overwrite,
|
||||
this.resourceId, this.resourceIdType, this.service, this.identifier);
|
||||
@ -158,7 +157,7 @@ public class ArbitraryDataReader {
|
||||
}
|
||||
}
|
||||
|
||||
private void preExecute() {
|
||||
private void preExecute() throws DataException {
|
||||
ArbitraryDataBuildManager.getInstance().setBuildInProgress(true);
|
||||
this.createWorkingDirectory();
|
||||
this.createUncompressedDirectory();
|
||||
@ -168,15 +167,15 @@ public class ArbitraryDataReader {
|
||||
ArbitraryDataBuildManager.getInstance().setBuildInProgress(false);
|
||||
}
|
||||
|
||||
private void createWorkingDirectory() {
|
||||
private void createWorkingDirectory() throws DataException {
|
||||
try {
|
||||
Files.createDirectories(this.workingPath);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to create temp directory");
|
||||
throw new DataException("Unable to create temp directory");
|
||||
}
|
||||
}
|
||||
|
||||
private void createUncompressedDirectory() {
|
||||
private void createUncompressedDirectory() throws DataException {
|
||||
try {
|
||||
// Create parent directory
|
||||
Files.createDirectories(this.uncompressedPath.getParent());
|
||||
@ -184,7 +183,7 @@ public class ArbitraryDataReader {
|
||||
FileUtils.deleteDirectory(this.uncompressedPath.toFile());
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to create uncompressed directory");
|
||||
throw new DataException("Unable to create uncompressed directory");
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,7 +224,7 @@ public class ArbitraryDataReader {
|
||||
}
|
||||
}
|
||||
|
||||
private void fetch() throws IllegalStateException, IOException, DataException, MissingDataException {
|
||||
private void fetch() throws DataException, IOException, MissingDataException {
|
||||
switch (resourceIdType) {
|
||||
|
||||
case FILE_HASH:
|
||||
@ -245,18 +244,18 @@ public class ArbitraryDataReader {
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException(String.format("Unknown resource ID type specified: %s", resourceIdType.toString()));
|
||||
throw new DataException(String.format("Unknown resource ID type specified: %s", resourceIdType.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchFromFileHash() {
|
||||
private void fetchFromFileHash() throws DataException {
|
||||
// Load data file directly from the hash
|
||||
ArbitraryDataFile arbitraryDataFile = ArbitraryDataFile.fromHash58(resourceId);
|
||||
// Set filePath to the location of the ArbitraryDataFile
|
||||
this.filePath = arbitraryDataFile.getFilePath();
|
||||
}
|
||||
|
||||
private void fetchFromName() throws IllegalStateException, IOException, DataException, MissingDataException {
|
||||
private void fetchFromName() throws DataException, IOException, MissingDataException {
|
||||
try {
|
||||
|
||||
// Build the existing state using past transactions
|
||||
@ -264,7 +263,7 @@ public class ArbitraryDataReader {
|
||||
builder.build();
|
||||
Path builtPath = builder.getFinalPath();
|
||||
if (builtPath == null) {
|
||||
throw new IllegalStateException("Unable to build path");
|
||||
throw new DataException("Unable to build path");
|
||||
}
|
||||
|
||||
// Update stats
|
||||
@ -282,7 +281,7 @@ public class ArbitraryDataReader {
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchFromSignature() throws IllegalStateException, IOException, DataException, MissingDataException {
|
||||
private void fetchFromSignature() throws DataException, IOException, MissingDataException {
|
||||
|
||||
// Load the full transaction data from the database so we can access the file hashes
|
||||
ArbitraryTransactionData transactionData;
|
||||
@ -290,15 +289,15 @@ public class ArbitraryDataReader {
|
||||
transactionData = (ArbitraryTransactionData) repository.getTransactionRepository().fromSignature(Base58.decode(resourceId));
|
||||
}
|
||||
if (transactionData == null) {
|
||||
throw new IllegalStateException(String.format("Transaction data not found for signature %s", this.resourceId));
|
||||
throw new DataException(String.format("Transaction data not found for signature %s", this.resourceId));
|
||||
}
|
||||
|
||||
this.fetchFromTransactionData(transactionData);
|
||||
}
|
||||
|
||||
private void fetchFromTransactionData(ArbitraryTransactionData transactionData) throws IllegalStateException, IOException, MissingDataException {
|
||||
private void fetchFromTransactionData(ArbitraryTransactionData transactionData) throws DataException, IOException, MissingDataException {
|
||||
if (transactionData == null) {
|
||||
throw new IllegalStateException(String.format("Transaction data not found for signature %s", this.resourceId));
|
||||
throw new DataException(String.format("Transaction data not found for signature %s", this.resourceId));
|
||||
}
|
||||
|
||||
// Load hashes
|
||||
@ -316,7 +315,7 @@ public class ArbitraryDataReader {
|
||||
if (!arbitraryDataFile.exists()) {
|
||||
if (!arbitraryDataFile.allChunksExist(chunkHashes) || chunkHashes == null) {
|
||||
if (ArbitraryDataStorageManager.getInstance().isNameInBlacklist(transactionData.getName())) {
|
||||
throw new IllegalStateException(
|
||||
throw new DataException(
|
||||
String.format("Unable to request missing data for file %s due to blacklist", arbitraryDataFile));
|
||||
}
|
||||
else {
|
||||
@ -352,13 +351,13 @@ public class ArbitraryDataReader {
|
||||
}
|
||||
// Ensure the complete hash matches the joined chunks
|
||||
if (!Arrays.equals(arbitraryDataFile.digest(), digest)) {
|
||||
throw new IllegalStateException("Unable to validate complete file hash");
|
||||
throw new DataException("Unable to validate complete file hash");
|
||||
}
|
||||
// Set filePath to the location of the ArbitraryDataFile
|
||||
this.filePath = arbitraryDataFile.getFilePath();
|
||||
}
|
||||
|
||||
private void decrypt() {
|
||||
private void decrypt() throws DataException {
|
||||
// Decrypt if we have the secret key.
|
||||
byte[] secret = this.secret58 != null ? Base58.decode(this.secret58) : null;
|
||||
if (secret != null && secret.length == Transformer.AES256_LENGTH) {
|
||||
@ -373,7 +372,7 @@ public class ArbitraryDataReader {
|
||||
|
||||
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | NoSuchPaddingException
|
||||
| BadPaddingException | IllegalBlockSizeException | IOException | InvalidKeyException e) {
|
||||
throw new IllegalStateException(String.format("Unable to decrypt file at path %s: %s", this.filePath, e.getMessage()));
|
||||
throw new DataException(String.format("Unable to decrypt file at path %s: %s", this.filePath, e.getMessage()));
|
||||
}
|
||||
} else {
|
||||
// Assume it is unencrypted. This will be the case when we have built a custom path by combining
|
||||
@ -381,9 +380,9 @@ public class ArbitraryDataReader {
|
||||
}
|
||||
}
|
||||
|
||||
private void uncompress() throws IOException {
|
||||
private void uncompress() throws IOException, DataException {
|
||||
if (this.filePath == null || !Files.exists(this.filePath)) {
|
||||
throw new IllegalStateException("Can't uncompress non-existent file path");
|
||||
throw new DataException("Can't uncompress non-existent file path");
|
||||
}
|
||||
File file = new File(this.filePath.toString());
|
||||
if (file.isDirectory()) {
|
||||
@ -407,10 +406,10 @@ public class ArbitraryDataReader {
|
||||
this.filePath.toFile().renameTo(finalPath.toFile());
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(String.format("Unrecognized compression type: %s", transactionData.getCompression()));
|
||||
throw new DataException(String.format("Unrecognized compression type: %s", transactionData.getCompression()));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(String.format("Unable to unzip file: %s", e.getMessage()));
|
||||
throw new DataException(String.format("Unable to unzip file: %s", e.getMessage()));
|
||||
}
|
||||
|
||||
// If unzipped data was a file not a directory, move it into a data/ directory so that the .qortal
|
||||
@ -449,12 +448,12 @@ public class ArbitraryDataReader {
|
||||
}
|
||||
|
||||
|
||||
private void moveFilePathToFinalDestination() throws IOException {
|
||||
private void moveFilePathToFinalDestination() throws IOException, DataException {
|
||||
if (this.filePath.compareTo(this.uncompressedPath) != 0) {
|
||||
File source = new File(this.filePath.toString());
|
||||
File dest = new File(this.uncompressedPath.toString());
|
||||
if (!source.exists()) {
|
||||
throw new IllegalStateException("Source directory doesn't exist");
|
||||
throw new DataException("Source directory doesn't exist");
|
||||
}
|
||||
// Ensure destination directory doesn't exist
|
||||
FileUtils.deleteDirectory(dest);
|
||||
|
@ -65,7 +65,7 @@ public class ArbitraryDataResource {
|
||||
} catch (MissingDataException e) {
|
||||
return new ArbitraryResourceSummary(ArbitraryResourceStatus.DOWNLOADING);
|
||||
|
||||
} catch (IOException | DataException | IllegalStateException e) {
|
||||
} catch (IOException | DataException e) {
|
||||
// Ignore for now
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ public class ArbitraryDataTransactionBuilder {
|
||||
// State is appropriate for a PATCH transaction
|
||||
return Method.PATCH;
|
||||
}
|
||||
catch (IOException | DataException | MissingDataException | IllegalStateException e) {
|
||||
catch (IOException | DataException | MissingDataException e) {
|
||||
// Handle matching states separately, as it's best to block transactions with duplicate states
|
||||
if (e.getMessage().equals("Current state matches previous state. Nothing to do.")) {
|
||||
throw new DataException(e.getMessage());
|
||||
|
@ -56,7 +56,7 @@ public class ArbitraryDataWriter {
|
||||
this.compression = compression;
|
||||
}
|
||||
|
||||
public void save() throws IllegalStateException, IOException, DataException, InterruptedException, MissingDataException {
|
||||
public void save() throws DataException, IOException, DataException, InterruptedException, MissingDataException {
|
||||
try {
|
||||
this.preExecute();
|
||||
this.validateService();
|
||||
@ -71,11 +71,11 @@ public class ArbitraryDataWriter {
|
||||
}
|
||||
}
|
||||
|
||||
private void preExecute() {
|
||||
private void preExecute() throws DataException {
|
||||
// Enforce compression when uploading a directory
|
||||
File file = new File(this.filePath.toString());
|
||||
if (file.isDirectory() && compression == Compression.NONE) {
|
||||
throw new IllegalStateException("Unable to upload a directory without compression");
|
||||
throw new DataException("Unable to upload a directory without compression");
|
||||
}
|
||||
|
||||
// Create temporary working directory
|
||||
@ -86,7 +86,7 @@ public class ArbitraryDataWriter {
|
||||
this.cleanupFilesystem();
|
||||
}
|
||||
|
||||
private void createWorkingDirectory() {
|
||||
private void createWorkingDirectory() throws DataException {
|
||||
// Use the user-specified temp dir, as it is deterministic, and is more likely to be located on reusable storage hardware
|
||||
String baseDir = Settings.getInstance().getTempDataPath();
|
||||
String identifier = Base58.encode(Crypto.digest(this.filePath.toString().getBytes()));
|
||||
@ -94,7 +94,7 @@ public class ArbitraryDataWriter {
|
||||
try {
|
||||
Files.createDirectories(tempDir);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to create temp directory");
|
||||
throw new DataException("Unable to create temp directory");
|
||||
}
|
||||
this.workingPath = tempDir;
|
||||
}
|
||||
@ -124,7 +124,7 @@ public class ArbitraryDataWriter {
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException(String.format("Unknown method specified: %s", method.toString()));
|
||||
throw new DataException(String.format("Unknown method specified: %s", method.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,29 +154,29 @@ public class ArbitraryDataWriter {
|
||||
this.validatePatch();
|
||||
}
|
||||
|
||||
private void validatePatch() {
|
||||
private void validatePatch() throws DataException {
|
||||
if (this.filePath == null) {
|
||||
throw new IllegalStateException("Null path after creating patch");
|
||||
throw new DataException("Null path after creating patch");
|
||||
}
|
||||
|
||||
File qortalMetadataDirectoryFile = Paths.get(this.filePath.toString(), ".qortal").toFile();
|
||||
if (!qortalMetadataDirectoryFile.exists()) {
|
||||
throw new IllegalStateException("Qortal metadata folder doesn't exist in patch");
|
||||
throw new DataException("Qortal metadata folder doesn't exist in patch");
|
||||
}
|
||||
if (!qortalMetadataDirectoryFile.isDirectory()) {
|
||||
throw new IllegalStateException("Qortal metadata folder isn't a directory");
|
||||
throw new DataException("Qortal metadata folder isn't a directory");
|
||||
}
|
||||
|
||||
File qortalPatchMetadataFile = Paths.get(this.filePath.toString(), ".qortal", "patch").toFile();
|
||||
if (!qortalPatchMetadataFile.exists()) {
|
||||
throw new IllegalStateException("Qortal patch metadata file doesn't exist in patch");
|
||||
throw new DataException("Qortal patch metadata file doesn't exist in patch");
|
||||
}
|
||||
if (!qortalPatchMetadataFile.isFile()) {
|
||||
throw new IllegalStateException("Qortal patch metadata file isn't a file");
|
||||
throw new DataException("Qortal patch metadata file isn't a file");
|
||||
}
|
||||
}
|
||||
|
||||
private void compress() throws InterruptedException {
|
||||
private void compress() throws InterruptedException, DataException {
|
||||
// Compress the data if requested
|
||||
if (this.compression != Compression.NONE) {
|
||||
this.compressedPath = Paths.get(this.workingPath.toString() + File.separator + "data.zip");
|
||||
@ -187,7 +187,7 @@ public class ArbitraryDataWriter {
|
||||
ZipUtils.zip(this.filePath.toString(), this.compressedPath.toString(), "data");
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(String.format("Unknown compression type specified: %s", compression.toString()));
|
||||
throw new DataException(String.format("Unknown compression type specified: %s", compression.toString()));
|
||||
}
|
||||
// FUTURE: other compression types
|
||||
|
||||
@ -199,13 +199,13 @@ public class ArbitraryDataWriter {
|
||||
// Replace filePath pointer with the zipped file path
|
||||
this.filePath = this.compressedPath;
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to zip directory", e);
|
||||
} catch (IOException | DataException e) {
|
||||
throw new DataException("Unable to zip directory", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void encrypt() {
|
||||
private void encrypt() throws DataException {
|
||||
this.encryptedPath = Paths.get(this.workingPath.toString() + File.separator + "data.zip.encrypted");
|
||||
try {
|
||||
// Encrypt the file with AES
|
||||
@ -222,11 +222,11 @@ public class ArbitraryDataWriter {
|
||||
|
||||
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | NoSuchPaddingException
|
||||
| BadPaddingException | IllegalBlockSizeException | IOException | InvalidKeyException e) {
|
||||
throw new IllegalStateException(String.format("Unable to encrypt file %s: %s", this.filePath, e.getMessage()));
|
||||
throw new DataException(String.format("Unable to encrypt file %s: %s", this.filePath, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void validate() throws IOException {
|
||||
private void validate() throws IOException, DataException {
|
||||
if (this.arbitraryDataFile == null) {
|
||||
throw new IOException("No file available when validating");
|
||||
}
|
||||
@ -235,7 +235,7 @@ public class ArbitraryDataWriter {
|
||||
// Validate the file
|
||||
ValidationResult validationResult = this.arbitraryDataFile.isValid();
|
||||
if (validationResult != ValidationResult.OK) {
|
||||
throw new IllegalStateException(String.format("File %s failed validation: %s", this.arbitraryDataFile, validationResult));
|
||||
throw new DataException(String.format("File %s failed validation: %s", this.arbitraryDataFile, validationResult));
|
||||
}
|
||||
LOGGER.info("Whole file hash is valid: {}", this.arbitraryDataFile.digest58());
|
||||
|
||||
@ -243,14 +243,14 @@ public class ArbitraryDataWriter {
|
||||
for (ArbitraryDataFileChunk chunk : this.arbitraryDataFile.getChunks()) {
|
||||
validationResult = chunk.isValid();
|
||||
if (validationResult != ValidationResult.OK) {
|
||||
throw new IllegalStateException(String.format("Chunk %s failed validation: %s", chunk, validationResult));
|
||||
throw new DataException(String.format("Chunk %s failed validation: %s", chunk, validationResult));
|
||||
}
|
||||
}
|
||||
LOGGER.info("Chunk hashes are valid");
|
||||
|
||||
}
|
||||
|
||||
private void split() throws IOException {
|
||||
private void split() throws IOException, DataException {
|
||||
this.arbitraryDataFile = ArbitraryDataFile.fromPath(this.filePath);
|
||||
if (this.arbitraryDataFile == null) {
|
||||
throw new IOException("No file available when trying to split");
|
||||
@ -261,7 +261,7 @@ public class ArbitraryDataWriter {
|
||||
LOGGER.info(String.format("Successfully split into %d chunk%s", chunkCount, (chunkCount == 1 ? "" : "s")));
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Unable to split file into chunks");
|
||||
throw new DataException("Unable to split file into chunks");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package org.qortal.arbitrary.metadata;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.repository.DataException;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
@ -30,7 +31,7 @@ public class ArbitraryDataMetadata {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void readJson() {
|
||||
protected void readJson() throws DataException {
|
||||
// To be overridden
|
||||
}
|
||||
|
||||
@ -39,12 +40,12 @@ public class ArbitraryDataMetadata {
|
||||
}
|
||||
|
||||
|
||||
public void read() throws IOException {
|
||||
public void read() throws IOException, DataException {
|
||||
this.loadJson();
|
||||
this.readJson();
|
||||
}
|
||||
|
||||
public void write() throws IOException {
|
||||
public void write() throws IOException, DataException {
|
||||
this.buildJson();
|
||||
this.createQortalDirectory();
|
||||
this.writeToQortalPath();
|
||||
@ -61,11 +62,11 @@ public class ArbitraryDataMetadata {
|
||||
this.jsonString = new String(Files.readAllBytes(path));
|
||||
}
|
||||
|
||||
protected void createQortalDirectory() {
|
||||
protected void createQortalDirectory() throws DataException {
|
||||
try {
|
||||
Files.createDirectories(this.qortalDirectoryPath);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to create .qortal directory");
|
||||
throw new DataException("Unable to create .qortal directory");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.qortal.arbitrary.metadata;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.utils.Base58;
|
||||
|
||||
import java.nio.file.Path;
|
||||
@ -21,9 +22,9 @@ public class ArbitraryDataMetadataCache extends ArbitraryDataMetadata {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readJson() {
|
||||
protected void readJson() throws DataException {
|
||||
if (this.jsonString == null) {
|
||||
throw new IllegalStateException("Patch JSON string is null");
|
||||
throw new DataException("Patch JSON string is null");
|
||||
}
|
||||
|
||||
JSONObject cache = new JSONObject(this.jsonString);
|
||||
|
@ -5,6 +5,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.qortal.arbitrary.ArbitraryDataDiff.*;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.utils.Base58;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@ -39,9 +40,9 @@ public class ArbitraryDataMetadataPatch extends ArbitraryDataMetadata {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readJson() {
|
||||
protected void readJson() throws DataException {
|
||||
if (this.jsonString == null) {
|
||||
throw new IllegalStateException("Patch JSON string is null");
|
||||
throw new DataException("Patch JSON string is null");
|
||||
}
|
||||
|
||||
JSONObject patch = new JSONObject(this.jsonString);
|
||||
|
@ -8,6 +8,7 @@ import org.apache.commons.io.FileUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.settings.Settings;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
@ -96,7 +97,7 @@ public class UnifiedDiffPatch {
|
||||
*
|
||||
* @return true if valid, false if invalid
|
||||
*/
|
||||
public boolean isValid() {
|
||||
public boolean isValid() throws DataException {
|
||||
this.createRandomIdentifier();
|
||||
this.createTempValidationDirectory();
|
||||
|
||||
@ -147,7 +148,7 @@ public class UnifiedDiffPatch {
|
||||
* @param pathSuffix - a file path to append to the base paths, or null if the base paths are already files
|
||||
* @throws IOException
|
||||
*/
|
||||
public void apply(Path pathSuffix) throws IOException {
|
||||
public void apply(Path pathSuffix) throws IOException, DataException {
|
||||
Path originalPath = this.before;
|
||||
Path patchPath = this.after;
|
||||
Path mergePath = this.destination;
|
||||
@ -160,7 +161,7 @@ public class UnifiedDiffPatch {
|
||||
}
|
||||
|
||||
if (!patchPath.toFile().exists()) {
|
||||
throw new IllegalStateException("Patch file doesn't exist, but its path was included in modifiedPaths");
|
||||
throw new DataException("Patch file doesn't exist, but its path was included in modifiedPaths");
|
||||
}
|
||||
|
||||
// Delete an existing file, as we are starting from a duplicate of pathBefore
|
||||
@ -190,7 +191,7 @@ public class UnifiedDiffPatch {
|
||||
writer.close();
|
||||
|
||||
} catch (PatchFailedException e) {
|
||||
throw new IllegalStateException(String.format("Failed to apply patch for path %s: %s", pathSuffix, e.getMessage()));
|
||||
throw new DataException(String.format("Failed to apply patch for path %s: %s", pathSuffix, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,14 +199,14 @@ public class UnifiedDiffPatch {
|
||||
this.identifier = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
private void createTempValidationDirectory() {
|
||||
private void createTempValidationDirectory() throws DataException {
|
||||
// Use the user-specified temp dir, as it is deterministic, and is more likely to be located on reusable storage hardware
|
||||
String baseDir = Settings.getInstance().getTempDataPath();
|
||||
Path tempDir = Paths.get(baseDir, "diff", "validate");
|
||||
try {
|
||||
Files.createDirectories(tempDir);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to create temp directory");
|
||||
throw new DataException("Unable to create temp directory");
|
||||
}
|
||||
this.validationPath = tempDir;
|
||||
}
|
||||
|
@ -779,7 +779,9 @@ public class ArbitraryDataManager extends Thread {
|
||||
byte[] hash = getArbitraryDataFileMessage.getHash();
|
||||
Controller.getInstance().stats.getArbitraryDataFileMessageStats.requests.incrementAndGet();
|
||||
|
||||
try {
|
||||
ArbitraryDataFile arbitraryDataFile = ArbitraryDataFile.fromHash(hash);
|
||||
|
||||
if (arbitraryDataFile.exists()) {
|
||||
ArbitraryDataFileMessage arbitraryDataFileMessage = new ArbitraryDataFileMessage(arbitraryDataFile);
|
||||
arbitraryDataFileMessage.setId(message.getId());
|
||||
@ -808,6 +810,10 @@ public class ArbitraryDataManager extends Thread {
|
||||
LOGGER.info("Sent file-unknown response for file {}", arbitraryDataFile);
|
||||
}
|
||||
}
|
||||
catch (DataException e) {
|
||||
LOGGER.info("Unable to handle request for arbitrary data file: {}", Base58.encode(hash));
|
||||
}
|
||||
}
|
||||
|
||||
public void onNetworkGetArbitraryDataFileListMessage(Peer peer, Message message) {
|
||||
GetArbitraryDataFileListMessage getArbitraryDataFileListMessage = (GetArbitraryDataFileListMessage) message;
|
||||
|
@ -2,6 +2,7 @@ package org.qortal.network.message;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
import org.qortal.arbitrary.ArbitraryDataFile;
|
||||
import org.qortal.repository.DataException;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -36,10 +37,15 @@ public class ArbitraryDataFileMessage extends Message {
|
||||
|
||||
byte[] data = new byte[dataLength];
|
||||
byteBuffer.get(data);
|
||||
ArbitraryDataFile arbitraryDataFile = new ArbitraryDataFile(data);
|
||||
|
||||
try {
|
||||
ArbitraryDataFile arbitraryDataFile = new ArbitraryDataFile(data);
|
||||
return new ArbitraryDataFileMessage(id, arbitraryDataFile);
|
||||
}
|
||||
catch (DataException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] toData() {
|
||||
|
@ -77,7 +77,7 @@ public class ArbitraryTransactionUtils {
|
||||
return hasNewerPut;
|
||||
}
|
||||
|
||||
public static boolean completeFileExists(ArbitraryTransactionData transactionData) {
|
||||
public static boolean completeFileExists(ArbitraryTransactionData transactionData) throws DataException {
|
||||
if (transactionData == null) {
|
||||
return false;
|
||||
}
|
||||
@ -90,7 +90,7 @@ public class ArbitraryTransactionUtils {
|
||||
|
||||
}
|
||||
|
||||
public static boolean allChunksExist(ArbitraryTransactionData transactionData) {
|
||||
public static boolean allChunksExist(ArbitraryTransactionData transactionData) throws DataException {
|
||||
if (transactionData == null) {
|
||||
return false;
|
||||
}
|
||||
@ -111,7 +111,7 @@ public class ArbitraryTransactionUtils {
|
||||
return arbitraryDataFile.allChunksExist(chunkHashes);
|
||||
}
|
||||
|
||||
public static boolean anyChunksExist(ArbitraryTransactionData transactionData) {
|
||||
public static boolean anyChunksExist(ArbitraryTransactionData transactionData) throws DataException {
|
||||
if (transactionData == null) {
|
||||
return false;
|
||||
}
|
||||
@ -132,7 +132,7 @@ public class ArbitraryTransactionUtils {
|
||||
return arbitraryDataFile.anyChunksExist(chunkHashes);
|
||||
}
|
||||
|
||||
public static int ourChunkCount(ArbitraryTransactionData transactionData) {
|
||||
public static int ourChunkCount(ArbitraryTransactionData transactionData) throws DataException {
|
||||
if (transactionData == null) {
|
||||
return 0;
|
||||
}
|
||||
@ -174,7 +174,7 @@ public class ArbitraryTransactionUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isFileHashRecent(byte[] hash, long now, long cleanupAfter) {
|
||||
public static boolean isFileHashRecent(byte[] hash, long now, long cleanupAfter) throws DataException {
|
||||
ArbitraryDataFile arbitraryDataFile = ArbitraryDataFile.fromHash(hash);
|
||||
if (arbitraryDataFile == null || !arbitraryDataFile.exists()) {
|
||||
// No hash, or file doesn't exist, so it's not recent
|
||||
@ -185,7 +185,7 @@ public class ArbitraryTransactionUtils {
|
||||
return ArbitraryTransactionUtils.isFileRecent(filePath, now, cleanupAfter);
|
||||
}
|
||||
|
||||
public static void deleteCompleteFile(ArbitraryTransactionData arbitraryTransactionData, long now, long cleanupAfter) {
|
||||
public static void deleteCompleteFile(ArbitraryTransactionData arbitraryTransactionData, long now, long cleanupAfter) throws DataException {
|
||||
byte[] completeHash = arbitraryTransactionData.getData();
|
||||
byte[] chunkHashes = arbitraryTransactionData.getChunkHashes();
|
||||
|
||||
@ -200,7 +200,7 @@ public class ArbitraryTransactionUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteCompleteFileAndChunks(ArbitraryTransactionData arbitraryTransactionData) {
|
||||
public static void deleteCompleteFileAndChunks(ArbitraryTransactionData arbitraryTransactionData) throws DataException {
|
||||
byte[] completeHash = arbitraryTransactionData.getData();
|
||||
byte[] chunkHashes = arbitraryTransactionData.getChunkHashes();
|
||||
|
||||
@ -209,7 +209,7 @@ public class ArbitraryTransactionUtils {
|
||||
arbitraryDataFile.deleteAll();
|
||||
}
|
||||
|
||||
public static void convertFileToChunks(ArbitraryTransactionData arbitraryTransactionData, long now, long cleanupAfter) {
|
||||
public static void convertFileToChunks(ArbitraryTransactionData arbitraryTransactionData, long now, long cleanupAfter) throws DataException {
|
||||
byte[] completeHash = arbitraryTransactionData.getData();
|
||||
byte[] chunkHashes = arbitraryTransactionData.getChunkHashes();
|
||||
|
||||
|
@ -22,7 +22,7 @@ public class ArbitraryDataDigestTests extends Common {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectoryDigest() throws IOException {
|
||||
public void testDirectoryDigest() throws IOException, DataException {
|
||||
Path dataPath = Paths.get("src/test/resources/arbitrary/demo1");
|
||||
String expectedHash58 = "DKyMuonWKoneJqiVHgw26Vk1ytrZG9PGsE9xfBg3GKDp";
|
||||
|
||||
|
@ -18,7 +18,7 @@ public class ArbitraryDataFileTests extends Common {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitAndJoin() {
|
||||
public void testSplitAndJoin() throws DataException {
|
||||
String dummyDataString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
ArbitraryDataFile arbitraryDataFile = new ArbitraryDataFile(dummyDataString.getBytes());
|
||||
assertTrue(arbitraryDataFile.exists());
|
||||
@ -45,7 +45,7 @@ public class ArbitraryDataFileTests extends Common {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitAndJoinWithLargeFiles() {
|
||||
public void testSplitAndJoinWithLargeFiles() throws DataException {
|
||||
int fileSize = (int) (5.5f * 1024 * 1024); // 5.5MiB
|
||||
byte[] randomData = new byte[fileSize];
|
||||
new Random().nextBytes(randomData); // No need for SecureRandom here
|
||||
|
@ -148,7 +148,7 @@ public class ArbitraryDataMergeTests extends Common {
|
||||
patch.create();
|
||||
fail("Creating patch should fail due to matching states");
|
||||
|
||||
} catch (IllegalStateException expectedException) {
|
||||
} catch (DataException expectedException) {
|
||||
assertEquals("Current state matches previous state. Nothing to do.", expectedException.getMessage());
|
||||
}
|
||||
|
||||
|
@ -234,7 +234,7 @@ public class ArbitraryDataTests extends Common {
|
||||
arbitraryDataReader1a.loadSynchronously(true);
|
||||
fail("Loading data with null identifier should fail due to nonexistent PUT transaction");
|
||||
|
||||
} catch (IllegalStateException expectedException) {
|
||||
} catch (DataException expectedException) {
|
||||
assertEquals(String.format("Couldn't find PUT transaction for name %s, service %s "
|
||||
+ "and identifier ", name.toLowerCase(), service), expectedException.getMessage());
|
||||
}
|
||||
@ -246,7 +246,7 @@ public class ArbitraryDataTests extends Common {
|
||||
arbitraryDataReader1b.loadSynchronously(true);
|
||||
fail("Loading data with incorrect identifier should fail due to nonexistent PUT transaction");
|
||||
|
||||
} catch (IllegalStateException expectedException) {
|
||||
} catch (DataException expectedException) {
|
||||
assertEquals(String.format("Couldn't find PUT transaction for name %s, service %s "
|
||||
+ "and identifier %s", name.toLowerCase(), service, differentIdentifier), expectedException.getMessage());
|
||||
}
|
||||
@ -321,7 +321,7 @@ public class ArbitraryDataTests extends Common {
|
||||
arbitraryDataReader1c.loadSynchronously(true);
|
||||
fail("Loading data with incorrect identifier should fail due to nonexistent PUT transaction");
|
||||
|
||||
} catch (IllegalStateException expectedException) {
|
||||
} catch (DataException expectedException) {
|
||||
assertEquals(String.format("Couldn't find PUT transaction for name %s, service %s "
|
||||
+ "and identifier %s", name.toLowerCase(), service, differentIdentifier), expectedException.getMessage());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user