Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add prefix harvesting CLI #127

Merged
merged 27 commits into from
May 3, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3ee311b
Add resolveAllPids to PID systems.
Pfeil Apr 6, 2023
48a1b7a
Add comments to handle protocol credential values.
Pfeil Apr 6, 2023
19a2b6f
Fix most Sonarlint hints of PR and local.
Pfeil Apr 6, 2023
9792507
Implement write-file cli commands.
Pfeil Apr 6, 2023
5adc1ae
Simplify resolveAll for handle protocol.
Pfeil Apr 6, 2023
674f8e5
Handle theoretical NPE (sonarlift).
Pfeil Apr 11, 2023
dc4245c
gitignore: ignore csv files
Pfeil Apr 11, 2023
5338929
Avoid 2nd instance of ApplicationProperties class.
Pfeil Apr 11, 2023
61abcb1
Implement CLI task "bootstrap".
Pfeil Apr 11, 2023
a3ebf03
Logging: show CLI info logging by default.
Pfeil Apr 11, 2023
952e5a5
Make all source work with all tasks.
Pfeil Apr 11, 2023
db44b04
Add query and delete tests for sandboxes pid systems.
Pfeil Apr 12, 2023
9855826
Fix possible line breaks in logging.
Pfeil Apr 21, 2023
aefd643
Add cli documentation to readme.
Pfeil Apr 21, 2023
5ed8dae
Fix missing cli option on usage prompt.
Pfeil Apr 21, 2023
edb8c30
Cli parser code: make constant static members.
Pfeil Apr 21, 2023
d30ca16
Add tests for CliTaskBootstrap
Pfeil Apr 21, 2023
15bde35
Add tests for CliTaskWriteFile
Pfeil Apr 24, 2023
0245a43
Remove unnecessary spring test annotations.
Pfeil Apr 24, 2023
2a5b041
Use file names which should be windows compatible.
Pfeil Apr 25, 2023
3e6a881
Cleanup unused imports.
Pfeil Apr 25, 2023
856a88a
Fix bootstrap storing PIDs known in beforehand.
Pfeil Apr 25, 2023
b6f7c87
Add test: Bootstrap shall not change existing entries.
Pfeil Apr 25, 2023
c1ac07e
Reduce temporal precision for test.
Pfeil Apr 25, 2023
5af2864
Merge branch 'master' into add-prefix-harvesting-cli
Pfeil May 3, 2023
c09fde9
fix: queryByType must return null if PID does not exist.
Pfeil May 3, 2023
2b8f649
feat(bootstrap): fill elasticsearch index
Pfeil May 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# !/setup/build/env.sh
##############

# csv files may be generated using the Typed PID Maker CLI (write-file)
*.csv

### SPRING BOOT ###
# Ignore local settings for spring boot
# If you want to provide default settings use 'application.properties.default' and rename it while building service.
Expand Down
3 changes: 2 additions & 1 deletion config/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ logging.level.edu.kit: WARN
#logging.level.org.springframework.transaction: TRACE
logging.level.org.springframework: WARN
logging.level.org.springframework.amqp: WARN
logging.level.com.zaxxer.hikari: DEBUG
#logging.level.com.zaxxer.hikari: ERROR
logging.level.edu.kit.datamanager.pit.cli: INFO

######################
### Authentication ###
Expand Down
91 changes: 89 additions & 2 deletions src/main/java/edu/kit/datamanager/pit/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
import com.google.common.cache.LoadingCache;
import com.google.common.cache.RemovalNotification;

import edu.kit.datamanager.pit.cli.CliTaskBootstrap;
import edu.kit.datamanager.pit.cli.CliTaskWriteFile;
import edu.kit.datamanager.pit.cli.ICliTask;
import edu.kit.datamanager.pit.cli.PidSource;
import edu.kit.datamanager.pit.common.InvalidConfigException;
import edu.kit.datamanager.pit.configuration.ApplicationProperties;
import edu.kit.datamanager.pit.domain.PIDRecord;
import edu.kit.datamanager.pit.domain.TypeDefinition;
Expand All @@ -37,7 +42,10 @@

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.cache.CacheConfig;
Expand All @@ -50,6 +58,7 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Scope;
Expand Down Expand Up @@ -155,7 +164,6 @@ public TypeDefinition load(String typeIdentifier) throws IOException, URISyntaxE
});
}

@Bean
@ConfigurationProperties("pit")
public ApplicationProperties applicationProperties() {
return new ApplicationProperties();
Expand All @@ -173,8 +181,87 @@ public HttpMessageConverter<PIDRecord> simplePidRecordConverter() {
}

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
System.out.println("Spring is running!");

final boolean cliArgsGiven = args != null && args.length != 0;
final boolean cliArgsAmountValid = cliArgsGiven && args.length >= 2;

final String writeFileCmd = "write-file";
final String bootstrapCmd = "bootstrap";

final String sourceFromPrefix = "all-pids-from-prefix";
final String sourceKnownPids = "known-pids";

final String errorCommunication = "Communication error: {}";
final String errorConfiguration = "Configuration error: {}";

if (cliArgsAmountValid) {
ICliTask task = null;
Stream<String> pidSource = null;

if (Objects.equals(args[1], sourceFromPrefix)) {
try {
pidSource = PidSource.fromPrefix(context);
} catch (IOException e) {
e.printStackTrace();
LOG.error(errorCommunication, e.getMessage());
exitApp(context, 1);
}
} else if (Objects.equals(args[1], sourceKnownPids)) {
pidSource = PidSource.fromKnown(context);
}

if (Objects.equals(args[0], bootstrapCmd)) {
task = new CliTaskBootstrap(context, pidSource);
} else if (Objects.equals(args[0], writeFileCmd)) {
task = new CliTaskWriteFile(context, pidSource);
}

try {
if (task != null && pidSource != null) {
// ---process task---
if (task.process()) {
exitApp(context, 0);
}
} else {
printUsage(args);
exitApp(context, 1);
}
} catch (InvalidConfigException e) {
e.printStackTrace();
LOG.error(errorConfiguration, e.getMessage());
exitApp(context, 1);
} catch (IOException e) {
e.printStackTrace();
LOG.error(errorCommunication, e.getMessage());
exitApp(context, 1);
}
}
}

private static void printUsage(String[] args) {
LOG.error("Got commands: {} and {}", args[0], args[1]);
Pfeil marked this conversation as resolved.
Show resolved Hide resolved
LOG.error("CLI usage incorrect. Usage:");
LOG.error("java -jar TypedPIDMaker.jar [ACTION] [SOURCE]");
LOG.error("java -jar TypedPIDMaker.jar bootstrap all-pids-from-prefix");
LOG.error("java -jar TypedPIDMaker.jar write-file all-pids-from-prefix");
LOG.error("java -jar TypedPIDMaker.jar write-file known-pids");
}

private static void exitApp(ConfigurableApplicationContext context, int errCode) {
context.close();
try {
Thread.sleep(2 * 1000L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
if (errCode != 0) {
LOG.error("Exited with error.");
} else {
LOG.info("Success");
}
System.exit(errCode);
}

}
59 changes: 59 additions & 0 deletions src/main/java/edu/kit/datamanager/pit/cli/CliTaskBootstrap.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package edu.kit.datamanager.pit.cli;

import java.io.IOException;
import java.time.Instant;
import java.util.stream.Stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;

import edu.kit.datamanager.entities.messaging.PidRecordMessage;
import edu.kit.datamanager.pit.common.InvalidConfigException;
import edu.kit.datamanager.pit.configuration.ApplicationProperties;
import edu.kit.datamanager.pit.pidlog.KnownPid;
import edu.kit.datamanager.pit.pidlog.KnownPidsDao;
import edu.kit.datamanager.service.IMessagingService;
import edu.kit.datamanager.util.AuthenticationHelper;
import edu.kit.datamanager.util.ControllerUtils;

public class CliTaskBootstrap implements ICliTask {

private static final Logger LOG = LoggerFactory.getLogger(CliTaskBootstrap.class);

Stream<String> pids;
ApplicationProperties appProps;
KnownPidsDao knownPids;
IMessagingService messagingService;

public CliTaskBootstrap(ConfigurableApplicationContext context, Stream<String> pids) {
this.pids = pids;
this.appProps = context.getBean(ApplicationProperties.class);
this.knownPids = context.getBean(KnownPidsDao.class);
this.messagingService = context.getBean(IMessagingService.class);
}

@Override
public boolean process() throws IOException, InvalidConfigException {
Instant unknownTime = Instant.ofEpochMilli(0);
pids
.map(pid -> new KnownPid(pid, unknownTime, unknownTime))
.forEach(known -> {
// store PIDs in the local database of known PIDs
LOG.info("Store PID {} in the local database of known PIDs.", known.getPid());
knownPids.save(known);
// send to message broker
PidRecordMessage message = PidRecordMessage.creation(
known.getPid(),
"",
AuthenticationHelper.getPrincipal(),
ControllerUtils.getLocalHostname()
);
LOG.info("Send PID {} to message broker.", known.getPid());
messagingService.send(message);
});
knownPids.flush();
return false;
}

}
58 changes: 58 additions & 0 deletions src/main/java/edu/kit/datamanager/pit/cli/CliTaskWriteFile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package edu.kit.datamanager.pit.cli;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Iterator;
import java.util.stream.Stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;

import edu.kit.datamanager.pit.configuration.ApplicationProperties;

public class CliTaskWriteFile implements ICliTask {

private static final Logger LOG = LoggerFactory.getLogger(CliTaskWriteFile.class);

Stream<String> pids;
ConfigurableApplicationContext context;
ApplicationProperties appProps;

public CliTaskWriteFile(ConfigurableApplicationContext context, Stream<String> pids) {
this.pids = pids;
this.context = context;
this.appProps = context.getBean(ApplicationProperties.class);
}

@Override
public boolean process() throws IOException {
String date = ZonedDateTime
.now(ZoneId.systemDefault())
.toString()
//.replace(":", ".")
.replace("[", "(")
.replace("]", ")")
.replace("/", "-")
//.replace("+", "_")
;
String filename = String.format("%s.%s", date, "csv");
Path path = Paths.get(filename);
{
File f = path.toFile();
f.createNewFile();
}
for (Iterator<String> iter = pids.iterator(); iter.hasNext(); ) {
String pid = iter.next();
LOG.info("Storing into CSV: {}", pid);
Files.writeString(path, pid + "\n", StandardOpenOption.APPEND);
}
return true;
}
}
15 changes: 15 additions & 0 deletions src/main/java/edu/kit/datamanager/pit/cli/ICliTask.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package edu.kit.datamanager.pit.cli;

import java.io.IOException;
import edu.kit.datamanager.pit.common.InvalidConfigException;

public interface ICliTask {
/**
* Processes this CLI task.
*
* @return true, if application should shut down after this task.
* @throws IOException on IO issues
* @throws InvalidConfigException on configuration issues
*/
public boolean process() throws IOException, InvalidConfigException;
}
42 changes: 42 additions & 0 deletions src/main/java/edu/kit/datamanager/pit/cli/PidSource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package edu.kit.datamanager.pit.cli;

import java.io.IOException;
import java.util.Map.Entry;
import java.util.stream.Stream;

import org.springframework.context.ConfigurableApplicationContext;

import edu.kit.datamanager.pit.pidlog.KnownPidsDao;
import edu.kit.datamanager.pit.pidsystem.IIdentifierSystem;

/**
* All static methods are sources for PIDs. Used in Command Line Tasks.
*/
public class PidSource {

private PidSource() {
// This class contains only static methods and shall not be instanciated.
}

public static Stream<String> fromPrefix(ConfigurableApplicationContext context) throws IOException {
return context
.getBeansOfType(IIdentifierSystem.class)
.entrySet()
.stream()
.filter(e -> !e.getKey().contains("typing"))
.map(Entry<String, IIdentifierSystem>::getValue)
.findFirst()
.orElseThrow()
.resolveAllPidsOfPrefix()
.stream();
}

public static Stream<String> fromKnown(ConfigurableApplicationContext context) {
return context
.getBean(KnownPidsDao.class)
.findAll()
.stream()
.map(e -> e.getPid());
}

}
Loading