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

allows to list existing and upload new datasets #4

Merged
merged 5 commits into from
Jun 28, 2024
Merged
Changes from all commits
Commits
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
11 changes: 9 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -11,8 +11,7 @@
<description>A client software written in Java to query openBIS</description>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.3.31</spring.version>
</properties>
@@ -138,6 +137,14 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
56 changes: 37 additions & 19 deletions src/main/java/life/qbic/App.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package life.qbic;

import ch.ethz.sis.openbis.generic.OpenBIS;
import life.qbic.io.commandline.CommandLineOptions;
import life.qbic.model.Configuration;
import life.qbic.model.download.Authentication;
import life.qbic.model.download.AuthenticationException;
import life.qbic.model.download.ConnectionException;
import org.apache.logging.log4j.LogManager;
@@ -35,30 +35,36 @@ private static Boolean isNotNullOrEmpty(String envVariableCommandLineParameter)
}

/**
* Logs into OpenBIS asks for and verifies password.
* Logs into OpenBIS, asks for and verifies password.
*
* @return An instance of the Authentication class.
*/
public static Authentication loginToOpenBIS(
char[] password, String user, String as_url) {
public static OpenBIS loginToOpenBIS(
char[] password, String user, String url) {
setupLog();

// Ensure 'logs' folder is created
File logFolder = new File(Configuration.LOG_PATH.toAbsolutePath().toString());
if (!logFolder.exists()) {
boolean logFolderCreated = logFolder.mkdirs();
if (!logFolderCreated) {
LOG.error("Could not create log folder '" + logFolder.getAbsolutePath() + "'");
System.exit(1);
}
}
OpenBIS authentication = new OpenBIS(url);

return tryLogin(authentication, user, password);
}

/**
* Logs into OpenBIS, asks for and verifies password, includes Datastore Server connection.
*
* @return An instance of the Authentication class.
*/
public static OpenBIS loginToOpenBIS(
char[] password, String user, String url, String dssUrl) {
setupLog();

OpenBIS authentication = new OpenBIS(url, dssUrl);

return tryLogin(authentication, user, password);
}

Authentication authentication =
new Authentication(
user,
new String(password),
as_url);
private static OpenBIS tryLogin(OpenBIS authentication, String user, char[] password) {
try {
authentication.login();
authentication.login(user, new String(password));
} catch (ConnectionException e) {
LOG.error(e.getMessage(), e);
LOG.error("Could not connect to QBiC's data source. Have you requested access to the "
@@ -70,4 +76,16 @@ public static Authentication loginToOpenBIS(
}
return authentication;
}

private static void setupLog() {
// Ensure 'logs' folder is created
File logFolder = new File(Configuration.LOG_PATH.toAbsolutePath().toString());
if (!logFolder.exists()) {
boolean logFolderCreated = logFolder.mkdirs();
if (!logFolderCreated) {
LOG.error("Could not create log folder '" + logFolder.getAbsolutePath() + "'");
System.exit(1);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -3,7 +3,13 @@
import static java.util.Objects.nonNull;
import static picocli.CommandLine.ArgGroup;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.StringJoiner;
import java.util.TreeMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import picocli.CommandLine;
@@ -14,17 +20,49 @@ public class AuthenticationOptions {

@Option(
names = {"-u", "--user"},
required = true,
description = "openBIS user name")
public String user;
private String user;
@ArgGroup(multiplicity = "1") // ensures the password is provided once with at least one of the possible options.
PasswordOptions passwordOptions;

@Option(
names = {"-as", "-as_url"},
description = "ApplicationServer URL",
scope = CommandLine.ScopeType.INHERIT)
public String as_url;
private String as_url;

@Option(
names = {"-dss", "-dss_url"},
description = "DatastoreServer URL",
scope = CommandLine.ScopeType.INHERIT)
private String dss_url;

@Option(
names = {"-config", "-config_file"},
description = "Config file path to provide openbis server information.",
scope = CommandLine.ScopeType.INHERIT)
public String configPath;

public String getUser() {
if(user == null & configPath!=null && !configPath.isBlank()) {
user = ReadProperties.getProperties(configPath).get("user");
}
return user;
}

public String getDSS() {
if(dss_url == null & configPath!=null && !configPath.isBlank()) {
dss_url = ReadProperties.getProperties(configPath).get("dss");
}
return dss_url;
}

public String getAS() {
if(as_url == null & configPath!=null && !configPath.isBlank()) {
as_url = ReadProperties.getProperties(configPath).get("as");
}
return as_url;
}

public char[] getPassword() {
return passwordOptions.getPassword();
@@ -76,4 +114,40 @@ public String toString() {
.toString();
//ATTENTION: do not expose the password here!
}

public static class ReadProperties {

public static TreeMap<String, String> getProperties(String infile) {

TreeMap<String, String> properties = new TreeMap<>();
BufferedReader bfr = null;
try {
bfr = new BufferedReader(new FileReader(new File(infile)));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}

String line;
while (true) {
try {
if ((line = bfr.readLine()) == null)
break;
} catch (IOException e) {
throw new RuntimeException(e);
}
if (!line.startsWith("#") && !line.isEmpty()) {
String[] property = line.trim().split("=");
properties.put(property[0].trim(), property[1].trim());
}
}

try {
bfr.close();
} catch (IOException e) {
throw new RuntimeException(e);
}

return(properties);
}
}
}
Original file line number Diff line number Diff line change
@@ -8,17 +8,17 @@

// main command with format specifiers for the usage help message
@Command(name = "openbis-scripts",
subcommands = { SampleHierarchyCommand.class },
subcommands = { SampleHierarchyCommand.class, FindDatasetsCommand.class, UploadDatasetCommand.class },
description = "A client software for querying openBIS.",
mixinStandardHelpOptions = true)
mixinStandardHelpOptions = true, versionProvider = ManifestVersionProvider.class)
public class CommandLineOptions {
private static final Logger LOG = LogManager.getLogger(CommandLineOptions.class);

@Option(names = {"-V", "--version"},
versionHelp = true,
description = "print version information",
scope = CommandLine.ScopeType.INHERIT)
boolean versionRequested;
boolean versionRequested = false;

@Option(
names = {"-h", "--help"},
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package life.qbic.io.commandline;

import ch.ethz.sis.openbis.generic.OpenBIS;
import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet;
import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import life.qbic.App;
import life.qbic.model.download.OpenbisConnector;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;

@Command(name = "list-data",
description = "lists datasets and their details for a given experiment code")
public class DownloadDatasetCommand implements Runnable {

@Parameters(arity = "1", paramLabel = "experiment", description = "The code of the experiment data is attached to")
private String experimentCode;
@Option(arity = "1", paramLabel = "<space>", description = "Optional openBIS spaces to filter results", names = {"-s", "--space"})
private String space;
@Mixin
AuthenticationOptions auth = new AuthenticationOptions();

@Override
public void run() {
List<String> spaces = new ArrayList<>();
if (space != null) {
System.out.println("Querying experiment in space: " + space + "...");
spaces.add(space);
} else {
System.out.println("Querying experiment in all available spaces...");
}
Comment on lines +36 to +41

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Down the line the printing could be done in a seperate method to keep the logic seperated

OpenBIS authentication = App.loginToOpenBIS(auth.getPassword(), auth.getUser(), auth.getAS());
OpenbisConnector openbis = new OpenbisConnector(authentication);
List<DataSet> datasets = openbis.listDatasetsOfExperiment(spaces, experimentCode).stream()
.sorted(Comparator.comparing(
(DataSet d) -> d.getExperiment().getProject().getSpace().getCode())).collect(
Collectors.toList());
int datasetIndex = 0;
for (DataSet dataSet : datasets) {
datasetIndex++;
System.out.println("["+datasetIndex+"]");
System.out.println(dataSet.getExperiment().getIdentifier());
System.out.println(dataSet.getCode());
System.out.println(dataSet.getType().getCode());
System.out.println(dataSet.getRegistrationDate());
System.out.println(new SimpleDateFormat("MM-dd-yyyy").format(dataSet.getRegistrationDate()));
Person person = dataSet.getRegistrator();
System.out.println(person.getFirstName() + " " + person.getLastName());
System.out.println();
}
}

private String getTimeStamp() {
final String PATTERN_FORMAT = "YYYY-MM-dd_HHmmss";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_FORMAT);
return LocalDateTime.ofInstant(Instant.now(), ZoneOffset.UTC).format(formatter);
}
}
70 changes: 70 additions & 0 deletions src/main/java/life/qbic/io/commandline/FindDatasetsCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package life.qbic.io.commandline;

import ch.ethz.sis.openbis.generic.OpenBIS;
import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet;
import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import life.qbic.App;
import life.qbic.model.download.OpenbisConnector;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;

@Command(name = "list-data",
description = "lists datasets and their details for a given experiment code")
public class FindDatasetsCommand implements Runnable {

@Parameters(arity = "1", paramLabel = "experiment", description = "The code of the experiment data is attached to")
private String experimentCode;
@Option(arity = "1", paramLabel = "<space>", description = "Optional openBIS spaces to filter samples", names = {"-s", "--space"})
private String space;
@Mixin
AuthenticationOptions auth = new AuthenticationOptions();

@Override
public void run() {
List<String> spaces = new ArrayList<>();
if (space != null) {
System.out.println("Querying experiment in space: " + space + "...");
spaces.add(space);
} else {
System.out.println("Querying experiment in all available spaces...");
Comment on lines +37 to +40

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: As previously mentioned, maybe a print class with distinct methods makes sense to avoid cluttering the code?

}
OpenBIS authentication = App.loginToOpenBIS(auth.getPassword(), auth.getUser(), auth.getAS());
OpenbisConnector openbis = new OpenbisConnector(authentication);
List<DataSet> datasets = openbis.listDatasetsOfExperiment(spaces, experimentCode).stream()
.sorted(Comparator.comparing(
(DataSet d) -> d.getExperiment().getProject().getSpace().getCode())).collect(
Collectors.toList());
int datasetIndex = 0;
System.out.println();
System.out.printf("Found %s datasets for experiment %s:%n", datasets.size(), experimentCode);
for (DataSet dataSet : datasets) {
datasetIndex++;
System.out.println("["+datasetIndex+"]");
System.out.printf("ID: %s (%s)%n", dataSet.getCode(), dataSet.getExperiment().getIdentifier());
System.out.println("Type: "+dataSet.getType().getCode());
Person person = dataSet.getRegistrator();
String simpleTime = new SimpleDateFormat("MM-dd-yy HH:mm:ss").format(dataSet.getRegistrationDate());
String name = person.getFirstName() +" "+ person.getLastName();
String uploadedBy = "Uploaded by "+name+" ("+simpleTime+")";
System.out.println(uploadedBy);
System.out.println();
}
}

private String getTimeStamp() {
final String PATTERN_FORMAT = "YYYY-MM-dd_HHmmss";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_FORMAT);
return LocalDateTime.ofInstant(Instant.now(), ZoneOffset.UTC).format(formatter);
}
}
Loading