Implemented first working version

This commit is contained in:
Robert Vokac 2023-07-30 18:48:14 +02:00
parent c6c996339c
commit edba08f896
No known key found for this signature in database
GPG Key ID: 693D30BEE3329055
34 changed files with 2376 additions and 1 deletions

View File

@ -14,11 +14,14 @@ You run the command bir:
* All files in this directory are inspected, new files are added to the database, deleted files are removed from the database.
* If the file last modification date in database and on the disk is the same, but the content checksum is different, then a bit rot is detected.
This program cannot restore files with bitrot.
* You have to backup up your files (do snapshots).
## How to setup your environment on Linux
Example:
alias bir='java -jar /rv/data/desktop/code/code.nanoboot.org/nanoboot/bit-inspector/target/bir-inspector-0.0.0-SNAPSHOT-jar-with-dependencies.jar'
alias bir='java -jar /rv/data/desktop/code/code.nanoboot.org/nanoboot/bit-inspector/target/bit-inspector-0.0.0-SNAPSHOT-jar-with-dependencies.jar'
## Usage

1
build.sh Executable file
View File

@ -0,0 +1 @@
mvn clean install

234
pom.xml Normal file
View File

@ -0,0 +1,234 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
bit-inspector: Tool detecting bit rots in files.
Copyright (C) 2016-2022 the original author or authors.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.nanoboot.essential</groupId>
<artifactId>nanoboot-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
</parent>
<groupId>org.nanoboot.tools</groupId>
<artifactId>bit-inspector</artifactId>
<version>0.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Bit Inspector</name>
<description>Tool detecting bit rots in files.</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<checkstyle.skip>true</checkstyle.skip><!-- TODO: make false-->
<power.version>2.0.1-SNAPSHOT</power.version>
<maven.compiler.source>19</maven.compiler.source>
<maven.compiler.target>19</maven.compiler.target>
<db-migration-core.version>0.1.0</db-migration-core.version>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<!--<compilerArgs>
-|-enable-preview
</compilerArgs>-->
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
<source>${javase.version}</source>
<target>${javase.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>${maven-assembly-plugin.version}</version>
<configuration>
<archive>
<manifest>
<mainClass>org.nanoboot.bitinspector.core.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<configuration>
<skip>${checkstyle.skip}</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>add-resource</id>
<phase>generate-resources</phase>
<goals>
<goal>add-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>src/main/resources/db_migrations/sqlite/bitinspector</directory>
<targetPath>db_migrations/sqlite/bitinspector</targetPath>
<includes>
<include>*.sql</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Power dependencies -->
<dependency>
<groupId>org.nanoboot.powerframework</groupId>
<artifactId>power-time</artifactId>
<version>${power.version}</version>
</dependency>
<dependency>
<groupId>org.nanoboot.powerframework</groupId>
<artifactId>power-random</artifactId>
<version>${power.version}</version>
</dependency>
<dependency>
<groupId>org.nanoboot.powerframework</groupId>
<artifactId>power-collections</artifactId>
<version>${power.version}</version>
</dependency>
<!-- Other dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit4.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.nanoboot.tools.dbmigration</groupId>
<artifactId>db-migration-core</artifactId>
<version>${db-migration-core.version}</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>${sqlite-jdbc.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!-- Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>releases</id>
<name>nanoboot-releases-repository</name>
<url>https://maven.nanoboot.org/releases</url>
</repository>
<repository>
<id>snapshots</id>
<name>nanoboot-snapshots-repository</name>
<url>https://maven.nanoboot.org/snapshots</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>releases</id>
<name>nanoboot-releases-repository</name>
<url>https://maven.nanoboot.org/releases</url>
</pluginRepository>
<pluginRepository>
<id>snapshots</id>
<name>nanoboot-snapshots-repository</name>
<url>https://maven.nanoboot.org/snapshots</url>
</pluginRepository>
</pluginRepositories>
</project>

3
setmodtime.sh Executable file
View File

@ -0,0 +1,3 @@
set_last_mod_time_the_same_as_this_file="$1"
set_last_mod_time_for_this_file="$2"
touch -r "$set_last_mod_time_the_same_as_this_file" "$set_last_mod_time_for_this_file"

28
src/main/java/module-info.java Executable file
View File

@ -0,0 +1,28 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2016-2022 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
module bitinspector {
requires org.apache.commons.io;
requires lombok;
requires org.apache.logging.log4j;
requires dbmigration.core;
requires java.sql;
requires powerframework.time;
requires powerframework.collections;
}

View File

@ -0,0 +1,113 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.commands;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import org.nanoboot.bitinspector.core.Utils;
/**
*
* @author robertvokac
*/
public class BirIgnoreRegex implements Predicate<String> {
private final List<String> patterns = new ArrayList<>();
public BirIgnoreRegex(File birIgnoreFile) {
String[] lines = birIgnoreFile.exists() ? Utils.readTextFromFile(birIgnoreFile).split("\\R") : new String[]{};
if (lines.length == 0) {
//nothing to do
return;
}
for (String l : lines) {
if (l.isBlank() || l.trim().startsWith("#")) {
//nothing to do
continue;
}
patterns.add(convertUnixRegexToJavaRegex(l));
}
patterns.add(convertUnixRegexToJavaRegex("*.birreport.csv"));
}
@Override
public boolean test(String text) {
if (patterns.isEmpty()) {
//nothing to do
return false;
}
boolean ignore = false;
for (String p : patterns) {
boolean b = Pattern.matches(p, text);
if (b) {
ignore = true;
} else {
}
}
// if (ignore) {
// System.out.println("ignoring file: " + text);
// } else {
// System.out.println("accepting file: " + text);
// }
return ignore;
}
public static String convertUnixRegexToJavaRegex(String wildcard) {
StringBuffer s = new StringBuffer(wildcard.length());
s.append('^');
for (int i = 0, is = wildcard.length(); i < is; i++) {
char c = wildcard.charAt(i);
switch (c) {
case '*':
s.append(".*");
break;
case '?':
s.append(".");
break;
// escape special regexp-characters
case '(':
case ')':
case '[':
case ']':
case '$':
case '^':
case '.':
case '{':
case '}':
case '|':
case '\\':
s.append("\\");
s.append(c);
break;
default:
s.append(c);
break;
}
}
s.append('$');
return (s.toString());
}
}

View File

@ -0,0 +1,280 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.commands;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import org.nanoboot.bitinspector.core.Command;
import org.nanoboot.bitinspector.core.BitInspectorArgs;
import org.nanoboot.bitinspector.core.BitInspectorException;
import org.nanoboot.bitinspector.core.Utils;
import org.nanoboot.bitinspector.entity.FsFile;
import org.nanoboot.bitinspector.entity.SystemItem;
import org.nanoboot.bitinspector.persistence.api.FileRepository;
import org.nanoboot.bitinspector.persistence.api.SystemItemRepository;
import org.nanoboot.bitinspector.persistence.impl.sqlite.FileRepositoryImplSqlite;
import org.nanoboot.bitinspector.persistence.impl.sqlite.SqliteDatabaseMigration;
import org.nanoboot.bitinspector.persistence.impl.sqlite.SystemItemRepositoryImplSqlite;
/**
*
* @author pc00289
*/
public class CheckCommand implements Command {
private final File currentDirRoot = new File(".");
private final File birSQLite3File = new File("./.bir.sqlite3");
private final File birSQLite3FileSha512 = new File("./.bir.sqlite3.sha512");
private final File birIgnore = new File("./.birignore");
BirIgnoreRegex birIgnoreRegex = new BirIgnoreRegex(birIgnore);
public CheckCommand() {
}
@Override
public String getName() {
return "check";
}
static int i = 0;
@Override
public void run(BitInspectorArgs bitInspectorArgs) {
SqliteDatabaseMigration sqliteDatabaseMigration = new SqliteDatabaseMigration();
sqliteDatabaseMigration.migrate();
SystemItemRepository systemItemRepository = new SystemItemRepositoryImplSqlite();
FileRepository fileRepository = new FileRepositoryImplSqlite();
////
String version = systemItemRepository.read("bir.version").getValue();
System.out.println("bir.version=" + version);
if (version == null) {
systemItemRepository.create(new SystemItem("bir.version", "0.0.0-SNAPSHOT"));
}
System.out.println("Updating version in DB.");
version = systemItemRepository.read("bir.version").getValue();
System.out.println("bir.version=" + version);
////
//// Check ,SQLite DB file has the expected SHA-512 hash sum
if (birSQLite3File.exists() && birSQLite3FileSha512.exists()) {
String expectedHash = Utils.readTextFromFile(birSQLite3FileSha512);
String returnedHash = Utils.calculateSHA512Hash(birSQLite3File);
if (!returnedHash.equals(expectedHash)) {
throw new BitInspectorException("Unexpected hash " + returnedHash + ". Expected SHA-512 hash sum was: " + expectedHash + " for file " + birSQLite3File.getAbsolutePath());
}
}
//// Found files in directory
List<File> filesInDir = foundFilesInCurrentDir(currentDirRoot, new ArrayList<>());
Set<String> filesInDirSet = filesInDir.stream().map(f -> loadPathButOnlyTheNeededPart(currentDirRoot, f)).collect(Collectors.toSet());
System.out.println("Found files:");
filesInDir.stream().forEach((f -> System.out.println("#" + (++i) + " " + f.getAbsolutePath().substring(currentDirRoot.getAbsolutePath().length() + 1))));
//// Found files in DB
List<FsFile> filesInDb = fileRepository.list();
Set<String> filesInDbSet = filesInDb.stream().map(f -> f.getAbsolutePath()).collect(Collectors.toSet());
System.out.println("Files in DB:");
i = 0;
filesInDb.stream().forEach((f -> System.out.println("#" + (++i) + " " + f.toString())));
//// Add new files
Date lastChecked = new Date();
org.nanoboot.powerframework.time.moment.LocalDateTime now = org.nanoboot.powerframework.time.moment.LocalDateTime.convertJavaUtilDateToPowerLocalDateTime(lastChecked);
int processedCount0 = 0;
List<FsFile> filesMissingInDb = new ArrayList<>();
for (File fileInDir : filesInDir) {
processedCount0 = processedCount0 + 1;
if (processedCount0 % 100 == 0) {
double progress = ((double) processedCount0) / filesInDir.size() * 100;
System.out.println("Add - Progress: " + processedCount0 + "/" + filesInDir.size() + " " + String.format("%,.2f", progress) + "%");
}
String absolutePathOfFileInDir = loadPathButOnlyTheNeededPart(currentDirRoot, fileInDir);
if (!filesInDbSet.contains(absolutePathOfFileInDir)) {
Date lastModified = new Date(fileInDir.lastModified());
org.nanoboot.powerframework.time.moment.LocalDateTime ldt = org.nanoboot.powerframework.time.moment.LocalDateTime.convertJavaUtilDateToPowerLocalDateTime(lastModified);
FsFile fsFile = new FsFile(
UUID.randomUUID().toString(),
fileInDir.getName(),
absolutePathOfFileInDir,
ldt.toString(),
now.toString(),
Utils.calculateSHA512Hash(fileInDir),
"SHA-512"
);
filesMissingInDb.add(fsFile);
}
}
fileRepository.create(filesMissingInDb);
//// Remove deleted files
List<FsFile> filesToBeRemovedFromDb = new ArrayList<>();
int processedCount1 = 0;
for (FsFile fileInDb : filesInDb) {
processedCount1 = processedCount1 + 1;
if (processedCount1 % 100 == 0) {
double progress = ((double) processedCount1) / filesInDb.size() * 100;
System.out.println("Remove - Progress: " + processedCount1 + "/" + filesInDb.size() + " " + String.format("%,.2f", progress) + "%");
}
String absolutePathOfFileInDb = fileInDb.getAbsolutePath();
if (!filesInDirSet.contains(absolutePathOfFileInDb)) {
filesToBeRemovedFromDb.add(fileInDb);
}
}
for (FsFile f : filesToBeRemovedFromDb) {
fileRepository.remove(f);
}
double countOfFilesToCalculateHashSum = filesInDb.size() - filesToBeRemovedFromDb.size();
int processedCount = 0;
//// Update modified files with same last modification date
List<FsFile> filesWithBitRot = new ArrayList<>();
List<FsFile> filesToUpdateLastCheckDate = new ArrayList<>();
for (FsFile fileInDb : filesInDb) {
String absolutePathOfFileInDb = fileInDb.getAbsolutePath();
if (filesToBeRemovedFromDb.contains(fileInDb)) {
//nothing to do
continue;
}
processedCount = processedCount + 1;
if (processedCount % 100 == 0) {
double progress = ((double) processedCount) / countOfFilesToCalculateHashSum * 100;
System.out.println("Update - Progress: " + processedCount + "/" + countOfFilesToCalculateHashSum + " " + String.format("%,.2f", progress) + "%");
}
File file = new File("./" + absolutePathOfFileInDb);
Date lastModified = new Date(file.lastModified());
org.nanoboot.powerframework.time.moment.LocalDateTime ldt = org.nanoboot.powerframework.time.moment.LocalDateTime.convertJavaUtilDateToPowerLocalDateTime(lastModified);
String calculatedHash = Utils.calculateSHA512Hash(file);
if (ldt.toString().equals(fileInDb.getLastModificationDate()) && !calculatedHash.equals(fileInDb.getHashSumValue())) {
filesWithBitRot.add(fileInDb);
fileInDb.setLastCheckDate(now.toString());
fileRepository.updateFile(fileInDb);
continue;
}
if (!ldt.toString().equals(fileInDb.getLastModificationDate())) {
fileInDb.setLastCheckDate(now.toString());
fileInDb.setLastModificationDate(ldt.toString());
fileInDb.setHashSumValue(calculatedHash);
fileInDb.setHashSumAlgorithm("SHA-512");
fileRepository.updateFile(fileInDb);
continue;
}
if (ldt.toString().equals(fileInDb.getLastModificationDate())) {
filesToUpdateLastCheckDate.add(fileInDb);
continue;
}
}
fileRepository.updateLastCheckDate(now.toString(), filesToUpdateLastCheckDate);
//// Report files, which may have a bitrot and will have to be restored from a backup
System.out.println("\n\n");
if (filesWithBitRot.isEmpty()) {
System.out.println("No files with bit rot were found.");
}
filesWithBitRot.stream().forEach(f
-> System.out.println("Bit rot detected: \"" + f.getAbsolutePath() + "\"" + " expected_sha512=" + f.getHashSumValue() + " returned_sha512=" + Utils.calculateSHA512Hash(new File("./" + f.getAbsolutePath())))
);
if (bitInspectorArgs.hasArgument("reportid")) {
String reportId = bitInspectorArgs.getArgument("reportid");
File reportIdFile = new File("./" + reportId + ".birreport.csv");
if (reportIdFile.exists()) {
Long nowLong = org.nanoboot.powerframework.time.moment.UniversalDateTime.now().toLong();
File backup = new File(reportIdFile.getParentFile().getAbsolutePath() + "/" + nowLong + "." + reportIdFile.getName());
System.out.println("backup=" + backup);
reportIdFile.renameTo(backup);
}
StringBuilder sb = new StringBuilder();
if (!filesWithBitRot.isEmpty()) {
sb.append("file;expected;calculated\n");
}
filesWithBitRot.stream().forEach(f
-> sb.append(f.getAbsolutePath())
.append(";")
.append(f.getHashSumValue())
.append(";")
.append(Utils.calculateSHA512Hash(new File("./" + f.getAbsolutePath())))
.append("\n")
);
Utils.writeTextToFile(sb.toString(), reportIdFile);
}
//// Calculate current checksum of DB file.
Utils.writeTextToFile(Utils.calculateSHA512Hash(birSQLite3File), birSQLite3FileSha512);
System.out.println("foundFiles=" + foundFiles);
System.out.println("foundDirs=" + foundDirs);
}
private String loadPathButOnlyTheNeededPart(File currentDir, File file) {
return file.getAbsolutePath().substring(currentDir.getAbsolutePath().length() + 1);
}
static int iii = 0;
private int foundFiles;
private int foundDirs;
private List<File> foundFilesInCurrentDir(File currentDir, List<File> files) {
for (File f : currentDir.listFiles()) {
if (f.isDirectory()) {
++foundDirs;
foundFilesInCurrentDir(f, files);
} else {
++foundFiles;
if (f.getAbsolutePath().equals(birSQLite3File.getAbsolutePath())) {
continue;
}
if (f.getAbsolutePath().equals(birSQLite3FileSha512.getAbsolutePath())) {
continue;
}
if (f.getAbsolutePath().equals(birIgnore.getAbsolutePath())) {
continue;
}
++iii;
//System.out.println("Testing file: " + iii + "#" + " " + loadPathButOnlyTheNeededPart(currentDirRoot, f));
if (birIgnoreRegex.test(loadPathButOnlyTheNeededPart(currentDirRoot, f))) {
continue;
}
files.add(f);
}
}
return files;
}
}

View File

@ -0,0 +1,304 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// dog: Tool generating documentation.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.dog.commands;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import org.nanoboot.dog.Command;
import org.nanoboot.dog.DogArgs;
import org.nanoboot.dog.Menu;
import org.nanoboot.dog.Utils;
import org.asciidoctor.Asciidoctor;
import static org.asciidoctor.Asciidoctor.Factory.create;
import org.nanoboot.dog.DogException;
import org.apache.commons.io.FileUtils;
/**
*
* @author pc00289
*/
public class GenCommand implements Command {
private static final String ADOC_EXTENSION = ".adoc";
public GenCommand() {
}
@Override
public String getName() {
return "gen";
}
@Override
public void run(DogArgs dogArgs) {
if (!dogArgs.hasArgument("in")) {
dogArgs.addArgument("in", new File(".").getAbsolutePath());
}
if (dogArgs.getArgument("in") == null) {
throw new DogException("Argument in must have a value (must not be empty).");
}
if (dogArgs.hasArgument("out") && !(new File(dogArgs.getArgument("out")).exists())) {
throw new DogException("Argument out must be an existing directory.");
}
File inDir = new File(dogArgs.getArgument("in"));
if (!inDir.exists()) {
throw new DogException("Argument in must be an existing directory, but that directory does not exist.");
}
File dogConfFile = new File(inDir, "dog.conf");
if (!dogConfFile.exists()) {
throw new DogException("File dog.conf was not found.");
}
File generatedDir = new File((dogArgs.hasArgument("out") ? new File(dogArgs.getArgument("out")) : inDir), "generated");
if (generatedDir.exists()) {
try {
FileUtils.deleteDirectory(generatedDir);
} catch (IOException ex) {
ex.printStackTrace();
throw new DogException("Deleting generated directory failed.", ex);
}
}
generatedDir.mkdir();
if (!generatedDir.exists()) {
throw new DogException("Argument out must be an existing directory, but that directory does not exist.");
}
//
Properties dogConfProperties = null;
try (InputStream input = new FileInputStream(dogConfFile.getAbsolutePath())) {
dogConfProperties = new Properties();
dogConfProperties.load(input);
} catch (IOException ex) {
ex.printStackTrace();
throw new DogException("Loading file dog.conf failed.", ex);
}
Utils.writeTextToFile(Utils.readTextFromResourceFile("/dog.css"), new File(generatedDir, "dog.css"));
File contentDir = new File(inDir, "content");
Menu menuInstance = new Menu(contentDir);
File templateDir = new File(contentDir.getParentFile().getAbsolutePath() + "/templates");
String headerTemplate = Utils.readTextFromFile(new File(templateDir, "header.html"));
String footerTemplate = Utils.readTextFromFile(new File(templateDir, "footer.html"));
processContentDir(contentDir, generatedDir, contentDir, dogConfProperties, menuInstance, headerTemplate, footerTemplate);
}
private static void processContentDir(File dir, File generatedDir, File contentDir, Properties dogConfProperties, Menu menuInstance, String headerTemplate, String footerTemplate) {
for (File inFile : dir.listFiles()) {
if (inFile.isFile()) {
processFileInContentDir(inFile, dir, contentDir, dogConfProperties, headerTemplate, menuInstance, footerTemplate, generatedDir);
}
if (inFile.isDirectory()) {
processDirInContentDir(generatedDir, inFile, contentDir, dogConfProperties, menuInstance, headerTemplate, footerTemplate);
}
}
}
public static void processDirInContentDir(File generatedDir, File inFile, File contentDir, Properties dogConfProperties, Menu menuInstance, String headerTemplate, String footerTemplate) {
File generatedDir2 = new File(generatedDir, inFile.getName());
generatedDir2.mkdir();
processContentDir(inFile, generatedDir2, contentDir, dogConfProperties, menuInstance, headerTemplate, footerTemplate);
}
public static void processFileInContentDir(File inFile, File dir, File contentDir, Properties dogConfProperties, String headerTemplate, Menu menuInstance, String footerTemplate, File generatedDir) {
if (inFile.getName().endsWith(ADOC_EXTENSION)) {
Asciidoctor asciidoctor = create();
String asciidocText = Utils.readTextFromFile(inFile);
String asciidocCompiled = asciidoctor
.convert(asciidocText, new HashMap<String, Object>());
String pathToRoot = dir.getAbsolutePath().replace(contentDir.getAbsolutePath(), "");
if (!pathToRoot.trim().isEmpty()) {
int count = 0;
for (char ch : pathToRoot.toCharArray()) {
if (ch == '/') {
count++;
}
}
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= count; i++) {
sb.append("../");
}
pathToRoot = sb.toString();
}
String titleSeparator = dogConfProperties.containsKey("titleSeparator") ? dogConfProperties.getProperty("titleSeparator") : "::";
final String humanName = createHumanName(inFile, dogConfProperties);
String start
= """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.16">
<title>
"""
+ humanName
+ (dogConfProperties.containsKey("title")
? (" " + titleSeparator + " " + dogConfProperties.getProperty("title")) : "")
+ """
</title>
<link rel="stylesheet" href="
"""
+ pathToRoot
+ """
dog.css">
</head>
<body class="article">
"""
+ headerTemplate
+ """
<div id="header">
"""
+ createNavigation(inFile, contentDir, dogConfProperties)
+ "<h1>"
+ humanName
+ """
</h1>
</div>"""
+ createMenu(menuInstance, inFile)
+ """
<div id="content">
""";
String end
= """
</div>
<div id="footer">
<div id="footer-text">
Last updated """
+ " "
+ (org.nanoboot.dog.Constants.YYYYMMDDHHMMSSZ_DATE_FORMAT.format(new Date()))
+ "<br>" + footerTemplate
+ """
</div>
</div>
</body>
</html>
""";
List<String> dirs = new ArrayList<>();
File currentFile = inFile;
String rootContentDirPath = contentDir.getAbsolutePath();
while (!currentFile.getAbsolutePath().equals(rootContentDirPath)) {
dirs.add(currentFile.getName());
currentFile = currentFile.getParentFile();
}
StringBuilder sb = new StringBuilder();
for (int i = dirs.size() - 1; i >= 0; i--) {
String d = dirs.get(i);
sb.append(d);
if (i > 0) {
sb.append("/");
}
}
String editThisPage = "<hr><a href=\"" + dogConfProperties.getProperty("editURL") + sb.toString() + "\">Edit this page</a>";
String htmlOutput = start + asciidocCompiled + editThisPage + end;
File htmlFile = new File(generatedDir, inFile.getName().replace(ADOC_EXTENSION, ".html"));
Utils.writeTextToFile(htmlOutput, htmlFile);
} else {
Utils.copyFile(inFile, generatedDir);
}
}
private static String createMenu(Menu menu, File currentFile) {
return //"<pre>" + menu.toAsciidoc(currentFile.getAbsolutePath().split("content")[1]) + "</pre>" +
menu.toHtml(currentFile.getAbsolutePath().split("content")[1]);
}
private static String createNavigation(File adocFile, File rootContentDir, Properties dogConfProperties) {
List<File> files = new ArrayList<>();
File currentFile = adocFile;
while (!currentFile.getAbsolutePath().equals(rootContentDir.getAbsolutePath())) {
if (currentFile.getName().equals("content")) {
continue;
}
files.add(currentFile);
currentFile = currentFile.getParentFile();
}
StringBuilder sb = new StringBuilder("<div class=\"navigation\" style=\"margin-top:20px;\"><a href=\"" + /*path +*/ Utils.createDoubleDotSlash(files.size() - 1) + "index.html\">Home</a>");
if (files.size() > 1 || !currentFile.getName().equals("index.adoc")) {
sb.append(" > ");
}
for (int i = (files.size() - 1); i >= 0; i--) {
File file = files.get(i);
if (file.getName().equals("index.adoc")) {
continue;
}
sb
.append("<a href=\"")
.append(Utils.createDoubleDotSlash(i - 1))
.append(i == 0 ? (file.getName().replace(ADOC_EXTENSION, "")) : "index")
.append(".html\">")
.append(createHumanName(file, dogConfProperties))
.append("</a>\n");
sb.append(" > ");
}
sb.append("</div>");
String result = sb.toString();
if (result.endsWith(" > </div>")) {
result = result.substring(0, result.length() - 9);
result = result + "</div>";
}
return result + "<hr>";
}
private static String createHumanName(File inFile, Properties dogConfProperties) {
String result = inFile.getName();
if (result.endsWith(ADOC_EXTENSION)) {
result = result.substring(0, inFile.getName().length() - ADOC_EXTENSION.length());
}
result = result.replace("_", " ");
if (Character.isLetter(result.charAt(0))) {
result = Character.toUpperCase(result.charAt(0)) + result.substring(1);
}
if (result.equals("Index")) {
File parentFile = inFile.getParentFile();
if (parentFile.getName().equals("content")) {
String frontPageName = dogConfProperties.getProperty("frontPageName", "");
return frontPageName.isBlank() ? "Home" : frontPageName;
}
return createHumanName(parentFile, dogConfProperties);
}
return result;
}
}

View File

@ -0,0 +1,63 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.commands;
import org.nanoboot.bitinspector.core.Command;
import org.nanoboot.bitinspector.core.BitInspectorArgs;
/**
*
* @author pc00289
*/
public class HelpCommand implements Command {
public HelpCommand() {
}
@Override
public String getName() {
return "help";
}
@Override
public void run(BitInspectorArgs bitInspectorArgs) {
String str = """
NAME
bir - " Bit Inspector"
SYNOPSIS
bir [command] [options]
If no command is provided, then the default command check is used. This means, if you run "bit-inspector", it is the same, as to run "bir check".
DESCRIPTION
Detects bit rotten files in the given directory to keep your files forever.
COMMAND
check Generates the static website
OPTIONS
reportid={unique name for this report, usually `date +'%Y%m%d_%H%M%S'`}
Optional. Default= (nothing will be reported to file report.{reportid}.bitreport.txt).
help Display help information
version Display version information
""";
System.out.println(str);
}
}

View File

@ -0,0 +1,38 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// dog: Tool generating documentation.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.dog.commands;
import org.nanoboot.dog.Command;
/**
*
* @author pc00289
*/
public class HelpCommand implements Command {
public HelpCommand() {
}
@Override
public String getName() {
return "help";
}
}

View File

@ -0,0 +1,44 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.commands;
import org.nanoboot.bitinspector.core.Command;
import org.nanoboot.bitinspector.core.BitInspectorArgs;
/**
*
* @author pc00289
*/
public class VersionCommand implements Command {
public VersionCommand() {
}
@Override
public String getName() {
return "version";
}
@Override
public void run(BitInspectorArgs bitInspectorArgs) {
System.out.println("Bit Inspector 0.0.0-SNAPSHOT");
}
}

View File

@ -0,0 +1,68 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
/**
*
* @author pc00289
*/
public class BitInspectorArgs {
@Getter
private final String command;
private final Map<String, String> internalMap = new HashMap<>();
public BitInspectorArgs(String[] args) {
command = args.length == 0 ? "check" : args[0];
if (args.length > 1) {
for (String arg : args) {
if (arg == null) {
continue;
}
if (args[0].equals(arg)) {
continue;
}
String[] keyValue = arg.split("=", 2);
internalMap.put(keyValue[0], keyValue.length > 1 ? keyValue[1] : null);
}
for (String key : internalMap.keySet()) {
System.out.println("Found argument: " + key + "(=)" + internalMap.get(key));
}
}
}
public boolean hasArgument(String arg) {
return internalMap.containsKey(arg);
}
public void addArgument(String arg, String value) {
this.internalMap.put(arg,value);
}
public String getArgument(String arg) {
return internalMap.get(arg);
}
}

View File

@ -0,0 +1,40 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
/**
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
* @since 0.0.0
*/
public class BitInspectorException extends RuntimeException {
public BitInspectorException(String msg) {
super(msg);
}
public BitInspectorException(String msg, Exception e) {
super(msg, e);
}
public BitInspectorException(Exception e) {
super(e);
}
}

View File

@ -0,0 +1,32 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
/**
*
* @author pc00289
*/
public interface Command {
public String getName();
default void run(BitInspectorArgs bitInspectorArgs) {
throw new BitInspectorException("Not yet implemented.");
}
}

View File

@ -0,0 +1,32 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
import java.text.SimpleDateFormat;
/**
*
* @author pc00289
*/
public class Constants {
public static final SimpleDateFormat YYYYMMDDHHMMSSZ_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
}

View File

@ -0,0 +1,60 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
import org.nanoboot.bitinspector.commands.HelpCommand;
import org.nanoboot.bitinspector.commands.CheckCommand;
import org.nanoboot.bitinspector.commands.VersionCommand;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
* @since 0.0.0
*/
public class Main {
public static void main(String[] args) {
System.out.println("Bir - Detects bit rotten files in the given directory to keep your files forever.\n");
BitInspectorArgs BitInspectorArgs = new BitInspectorArgs(args);
String command = BitInspectorArgs.getCommand();
Set<Command> commandImplementations = new HashSet<>();
commandImplementations.add(new CheckCommand());
commandImplementations.add(new HelpCommand());
commandImplementations.add(new VersionCommand());
Command foundCommand = null;
for(Command e:commandImplementations) {
if(e.getName().equals(command)) {
foundCommand = e;
break;
}
}
if(foundCommand == null) {
System.err.println("Error: Command \"" + command + "\" is not supported.\n");
new HelpCommand().run(BitInspectorArgs);
System.exit(1);
}
foundCommand.run(BitInspectorArgs);
}
}

View File

@ -0,0 +1,199 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author pc00289
*/
public class Utils {
private static final String UNDERSCORE = "_";
private Utils() {
//Not meant to be instantiated.
}
public static String replaceUnderscoresBySpaces(String s) {
if (!s.contains(UNDERSCORE)) {
//nothing to do
return s;
}
return s.replace(UNDERSCORE, " ");
}
public static String makeFirstLetterUppercase(String s) {
if (Character.isLetter(s.charAt(0)) && Character.isLowerCase(s.charAt(0))) {
return Character.toUpperCase(s.charAt(0))
+ (s.length() == 1 ? "" : s.substring(1));
} else {
return s;
}
}
public static int getCountOfSlashOccurences(String string) {
int i = 0;
for (char ch : string.toCharArray()) {
if (ch == '/') {
i++;
}
}
return i++;
}
public static List<File> listAdocFilesInDir(File dir) {
return listAdocFilesInDir(dir, new ArrayList<>());
}
private static List<File> listAdocFilesInDir(File dir, List<File> files) {
List<File> allFiles = listAllFilesInDir(dir, files);
List<File> adocFiles = new ArrayList<>();
for (File f : allFiles) {
if (f.getName().endsWith(".adoc") && !f.isDirectory()) {
adocFiles.add(f);
}
}
return adocFiles;
}
public static List<File> listAllFilesInDir(File dir) {
return listAllFilesInDir(dir, new ArrayList<>());
}
private static List<File> listAllFilesInDir(File dir, List<File> files) {
files.add(dir);
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
listAllFilesInDir(f, files);
} else {
files.add(f);
}
}
return files;
}
public static String createDoubleDotSlash(int times) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= times; i++) {
sb.append("../");
}
String result = sb.toString();
return result;//.substring(0, result.length() - 1);
}
public static void copyFile(File originalFile, File copiedFile) throws BitInspectorException {
Path originalPath = originalFile.toPath();
Path copied = new File(copiedFile, originalFile.getName()).toPath();
try {
Files.copy(originalPath, copied, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
ex.printStackTrace();
throw new BitInspectorException("Copying file failed: " + originalFile.getAbsolutePath());
}
}
public static void writeTextToFile(String text, File file) {
FileWriter fileWriter;
try {
fileWriter = new FileWriter(file);
} catch (IOException ex) {
ex.printStackTrace();
throw new BitInspectorException("Writing to file failed: " + file.getName(), ex);
}
PrintWriter printWriter = new PrintWriter(fileWriter);
printWriter.print(text);
printWriter.close();
}
public static String readTextFromFile(File file) {
if (!file.exists()) {
return "";
}
try {
return new String(Files.readAllBytes(Paths.get(file.getAbsolutePath())));
} catch (IOException ex) {
throw new BitInspectorException("Reading file failed: " + file.getName(), ex);
}
}
public static String readTextFromResourceFile(String fileName) {
try {
Class clazz = Main.class;
InputStream inputStream = clazz.getResourceAsStream(fileName);
return readFromInputStream(inputStream);
} catch (IOException ex) {
throw new BitInspectorException("Reading file failed: " + fileName, ex);
}
}
public static String readFromInputStream(InputStream inputStream)
throws IOException {
StringBuilder resultStringBuilder = new StringBuilder();
try (BufferedReader br
= new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = br.readLine()) != null) {
resultStringBuilder.append(line).append("\n");
}
}
return resultStringBuilder.toString();
}
public static String calculateSHA512Hash(File file) {
final Path path = Paths.get(file.getAbsolutePath());
byte[] bytes;
try {
bytes = Files.readAllBytes(path);
} catch (IOException ex) {
throw new BitInspectorException(ex);
}
byte[] sha512sumByteArray;
try {
sha512sumByteArray = MessageDigest.getInstance("SHA-512").digest(bytes);
} catch (NoSuchAlgorithmException ex) {
throw new BitInspectorException(ex);
}
StringBuilder sb = new StringBuilder(sha512sumByteArray.length * 2);
for (byte b : sha512sumByteArray) {
sb.append(String.format("%02x", b));
}
String hexString = sb.toString();
return hexString;
}
}

View File

@ -0,0 +1,44 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
*
* @author robertvokac
*/
@Getter
@Setter
@AllArgsConstructor
@ToString
public class FsFile {
private final String id;
private String name;
private String absolutePath;
private String lastModificationDate;
private String lastCheckDate;
private String hashSumValue;
private String hashSumAlgorithm;
}

View File

@ -0,0 +1,38 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
/**
*
* @author robertvokac
*/
@Getter
@Setter
@AllArgsConstructor
public class SystemItem {
private String key;
private String value;
}

View File

@ -0,0 +1 @@
lombok.log.fieldName=LOG

View File

@ -0,0 +1,36 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.persistence.api;
import java.util.List;
import org.nanoboot.bitinspector.entity.FsFile;
/**
*
* @author robertvokac
*/
public interface FileRepository {
void create(List<FsFile> files);
List<FsFile> list();
void remove(FsFile file);
void updateFile(FsFile file);
void updateLastCheckDate(String lastCheckDate, List<FsFile> files);
}

View File

@ -0,0 +1,36 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.persistence.api;
import java.util.List;
import org.nanoboot.bitinspector.entity.SystemItem;
/**
*
* @author robertvokac
*/
public interface SystemItemRepository {
String create(SystemItem systemItem);
List<SystemItem> list();
SystemItem read(String key);
void remove(String key);
void update(SystemItem systemItem);
}

View File

@ -0,0 +1,31 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.persistence.impl.sqlite;
/**
*
* @author robertvokac
*/
public class Constants {
static final String JDBC_URL = "jdbc:sqlite:" + "." + "/" + ".bir.sqlite3?foreign_keys=on;";
private Constants() {
//Not meant to be instantiated.
}
}

View File

@ -0,0 +1,301 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.persistence.impl.sqlite;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.nanoboot.bitinspector.entity.FsFile;
import org.nanoboot.bitinspector.persistence.api.FileRepository;
/**
*
* @author robertvokac
*/
public class FileRepositoryImplSqlite implements FileRepository {
@Override
public void create(List<FsFile> files) {
if (files.isEmpty()) {
return;
}
if (files.size() > 100) {
List<FsFile> tmpList = new ArrayList<>();
for (int i = 0; i < files.size(); i++) {
FsFile e = files.get(i);
tmpList.add(e);
if (tmpList.size() >= 100) {
create(tmpList);
tmpList.clear();
}
}
if (!tmpList.isEmpty()) {
create(tmpList);
tmpList.clear();
}
return;
}
StringBuilder sb = new StringBuilder();
sb
.append("INSERT INTO ")
.append(FileTable.TABLE_NAME)
.append("(")
.append(FileTable.ID).append(",")
.append(FileTable.NAME).append(",")
.append(FileTable.ABSOLUTE_PATH).append(",")
.append(FileTable.LAST_MODIFICATION_DATE).append(",")
.append(FileTable.LAST_CHECK_DATE).append(",")
//
.append(FileTable.HASH_SUM_VALUE).append(",")
.append(FileTable.HASH_SUM_ALGORITHM);
sb.append(") VALUES ");
int index = 0;
for (FsFile f : files) {
sb.append(" (?,?,?,?,?, ?,?)");
boolean lastFile = index == (files.size() - 1);
if (!lastFile) {
sb.append(",");
}
index = index + 1;
}
String sql = sb.toString();
System.err.println(sql);
try (
Connection connection = createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int i = 0;
for (FsFile f : files) {
stmt.setString(++i, f.getId());
stmt.setString(++i, f.getName());
stmt.setString(++i, f.getAbsolutePath());
stmt.setString(++i, f.getLastModificationDate());
//
stmt.setString(++i, f.getLastCheckDate());
//
stmt.setString(++i, f.getHashSumValue());
stmt.setString(++i, f.getHashSumAlgorithm());
}
//
stmt.execute();
System.out.println(stmt.toString());
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
Logger.getLogger(FileRepositoryImplSqlite.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public List<FsFile> list() {
List<FsFile> result = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb
.append("SELECT * FROM ")
.append(FileTable.TABLE_NAME);
String sql = sb.toString();
System.err.println(sql);
int i = 0;
ResultSet rs = null;
try (
Connection connection = createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
System.err.println(stmt.toString());
rs = stmt.executeQuery();
while (rs.next()) {
result.add(extractFileFromResultSet(rs));
}
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
Logger.getLogger(FileRepositoryImplSqlite.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
Logger.getLogger(FileRepositoryImplSqlite.class.getName()).log(Level.SEVERE, null, ex);
}
}
return result;
}
@Override
public void remove(FsFile file) {
StringBuilder sb = new StringBuilder();
sb
.append("DELETE FROM ")
.append(FileTable.TABLE_NAME);
sb.append(" WHERE ");
sb.append(FileTable.ID);
sb.append("=?");
String sql = sb.toString();
System.err.println("SQL::" + sql);
int i = 0;
try (
Connection connection = createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
stmt.setString(++i, file.getId());
System.err.println(stmt.toString());
stmt.execute();
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
Logger.getLogger(FileRepositoryImplSqlite.class.getName()).log(Level.SEVERE, null, ex);
}
}
private Connection createConnection() throws ClassNotFoundException {
return new SqliteConnectionFactory().createConnection();
}
@Override
public void updateFile(FsFile file) {
StringBuilder sb = new StringBuilder();
sb
.append("UPDATE ")
.append(FileTable.TABLE_NAME)
.append(" SET ")
.append(FileTable.LAST_MODIFICATION_DATE).append("=?, ")
.append(FileTable.LAST_CHECK_DATE).append("=?, ")
.append(FileTable.HASH_SUM_VALUE).append("=?, ")
.append(FileTable.HASH_SUM_ALGORITHM).append("=? ")
.append(" WHERE ").append(FileTable.ID).append("=?");
String sql = sb.toString();
//System.err.println(sql);
try (
Connection connection = createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int i = 0;
stmt.setString(++i, file.getLastModificationDate());
stmt.setString(++i, file.getLastCheckDate());
stmt.setString(++i, file.getHashSumValue());
stmt.setString(++i, file.getHashSumAlgorithm());
stmt.setString(++i, file.getId());
int numberOfUpdatedRows = stmt.executeUpdate();
//System.out.println("numberOfUpdatedRows=" + numberOfUpdatedRows);
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
Logger.getLogger(FileRepositoryImplSqlite.class.getName()).log(Level.SEVERE, null, ex);
}
}
private FsFile extractFileFromResultSet(final ResultSet rs) throws SQLException {
return new FsFile(
rs.getString(FileTable.ID),
rs.getString(FileTable.NAME),
rs.getString(FileTable.ABSOLUTE_PATH),
rs.getString(FileTable.LAST_MODIFICATION_DATE),
rs.getString(FileTable.LAST_CHECK_DATE),
rs.getString(FileTable.HASH_SUM_VALUE),
rs.getString(FileTable.HASH_SUM_ALGORITHM)
);
}
@Override
public void updateLastCheckDate(String lastCheckDate, List<FsFile> files) {
if (files.isEmpty()) {
return;
}
if (files.size() > 100) {
List<FsFile> tmpList = new ArrayList<>();
for (int i = 0; i < files.size(); i++) {
FsFile e = files.get(i);
tmpList.add(e);
if (tmpList.size() >= 100) {
updateLastCheckDate(lastCheckDate, tmpList);
tmpList.clear();
}
}
if (!tmpList.isEmpty()) {
updateLastCheckDate(lastCheckDate, tmpList);
tmpList.clear();
}
return;
}
StringBuilder sb = new StringBuilder();
sb
.append("UPDATE ")
.append(FileTable.TABLE_NAME)
.append(" SET ")
.append(FileTable.LAST_CHECK_DATE).append("=? ")
.append(" WHERE ").append(FileTable.ID).append(" IN (");
int index = 0;
for (FsFile f : files) {
index = index + 1;
sb.append("?");
if (index < files.size()) {
sb.append(",");
}
}
sb.append(")");
String sql = sb.toString();
//System.err.println(sql);
try (
Connection connection = createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int i = 0;
stmt.setString(++i, lastCheckDate);
for (FsFile f : files) {
stmt.setString(++i, f.getId());
}
int numberOfUpdatedRows = stmt.executeUpdate();
//System.out.println("numberOfUpdatedRows=" + numberOfUpdatedRows);
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
Logger.getLogger(FileRepositoryImplSqlite.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

View File

@ -0,0 +1,44 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.persistence.impl.sqlite;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
/**
*
* @author robertvokac
*/
@Getter
@Setter
@AllArgsConstructor
class FileTable {
public static final String TABLE_NAME = "FILE";
public static final String ID = "ID";
public static final String NAME = "NAME";
public static final String ABSOLUTE_PATH = "ABSOLUTE_PATH";
public static final String LAST_MODIFICATION_DATE = "LAST_MODIFICATION_DATE";
public static final String LAST_CHECK_DATE = "LAST_CHECK_DATE";
//
public static final String HASH_SUM_VALUE = "HASH_SUM_VALUE";
public static final String HASH_SUM_ALGORITHM = "HASH_SUM_ALGORITHM";
}

View File

@ -0,0 +1,48 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.persistence.impl.sqlite;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
*
* @author robertvokac
*/
public class SqliteConnectionFactory {
public Connection createConnection() throws ClassNotFoundException {
try {
Class.forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection(Constants.JDBC_URL);
return conn;
} catch (SQLException ex) {
if (true) {
throw new RuntimeException(ex);
}
System.err.println(ex.getMessage());
return null;
}
}
}

View File

@ -0,0 +1,50 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.persistence.impl.sqlite;
import org.nanoboot.dbmigration.core.main.DBMigration;
/**
*
* @author robertvokac
*/
public class SqliteDatabaseMigration {
public void migrate() {
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException ex) {
System.err.println(ex.getMessage());
throw new RuntimeException(ex);
}
System.err.println("jdbcUrl=" + Constants.JDBC_URL);
String clazz = this.getClass().getName();
DBMigration dbMigration = DBMigration
.configure()
.dataSource(Constants.JDBC_URL)
.installedBy("bitinspector-persistence-impl-sqlite")
.name("bitinspector")
.sqlDialect("sqlite", "org.nanoboot.dbmigration.core.persistence.impl.sqlite.DBMigrationPersistenceSqliteImpl")
.sqlMigrationsClass(clazz)
.load();
dbMigration.migrate();
}
}

View File

@ -0,0 +1,141 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.persistence.impl.sqlite;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.nanoboot.bitinspector.entity.SystemItem;
import org.nanoboot.bitinspector.persistence.api.SystemItemRepository;
/**
*
* @author robertvokac
*/
public class SystemItemRepositoryImplSqlite implements SystemItemRepository {
@Override
public String create(SystemItem systemItem) {
StringBuilder sb = new StringBuilder();
sb
.append("INSERT INTO ")
.append(SystemItemTable.TABLE_NAME)
.append("(")
.append(SystemItemTable.KEY).append(",")
//
.append(SystemItemTable.VALUE);
sb.append(")")
.append(" VALUES (?,?)");
String sql = sb.toString();
System.err.println(sql);
try (
Connection connection = new SqliteConnectionFactory().createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int i = 0;
stmt.setString(++i, systemItem.getKey());
stmt.setString(++i, systemItem.getValue());
//
stmt.execute();
System.out.println(stmt.toString());
return systemItem.getKey();
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
Logger.getLogger(SystemItemRepositoryImplSqlite.class.getName()).log(Level.SEVERE, null, ex);
}
System.err.println("Error.");
return "";
}
@Override
public List<SystemItem> list() {
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
}
@Override
public SystemItem read(String key) {
if (key == null) {
throw new RuntimeException("key is null");
}
StringBuilder sb = new StringBuilder();
sb
.append("SELECT * FROM ")
.append(SystemItemTable.TABLE_NAME)
.append(" WHERE ")
.append(SystemItemTable.KEY)
.append("=?");
String sql = sb.toString();
int i = 0;
ResultSet rs = null;
try (
Connection connection = new SqliteConnectionFactory().createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
stmt.setString(++i, key);
rs = stmt.executeQuery();
while (rs.next()) {
return extractSystemItemFromResultSet(rs);
}
return new SystemItem(key, null);
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
Logger.getLogger(SystemItemRepositoryImplSqlite.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
Logger.getLogger(SystemItemRepositoryImplSqlite.class.getName()).log(Level.SEVERE, null, ex);
}
}
return null;
}
@Override
public void remove(String key) {
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
}
@Override
public void update(SystemItem systemItem) {
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
}
private SystemItem extractSystemItemFromResultSet(final ResultSet rs) throws SQLException {
return new SystemItem(
rs.getString(SystemItemTable.KEY),
rs.getString(SystemItemTable.VALUE)
);
}
}

View File

@ -0,0 +1,38 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.persistence.impl.sqlite;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
/**
*
* @author robertvokac
*/
@Getter
@Setter
@AllArgsConstructor
class SystemItemTable {
public static final String TABLE_NAME = "SYSTEM_ITEM";
public static final String KEY = "KEY";
public static final String VALUE = "VALUE";
}

View File

View File

@ -0,0 +1,14 @@
CREATE TABLE "FILE" (
"ID" TEXT,
"NAME" TEXT NOT NULL,
"ABSOLUTE_PATH" TEXT NOT NULL,
"LAST_MODIFICATION_DATE" TEXT NOT NULL,
"LAST_CHECK_DATE" TEXT NOT NULL,
"HASH_SUM_VALUE" TEXT NOT NULL,
"HASH_SUM_ALGORITHM" TEXT NOT NULL,
UNIQUE(ABSOLUTE_PATH),
PRIMARY KEY("ID")
);
CREATE UNIQUE INDEX IDX_FILE_ABSOLUTE_PATH
ON FILE (ABSOLUTE_PATH);

View File

@ -0,0 +1,6 @@
CREATE TABLE "SYSTEM_ITEM" (
"KEY" TEXT,
"VALUE" TEXT NOT NULL,
PRIMARY KEY("KEY")
)

View File

@ -0,0 +1,5 @@
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
rootLogger=info, STDOUT