From b6145512385234bb27025e3d9254447c9a417ec9 Mon Sep 17 00:00:00 2001
From: Will Lehman
Date: Thu, 25 Jul 2024 15:28:18 -0400
Subject: [PATCH 1/6] all kc changes except centralized output store
implemented
---
src/main/java/usace/cc/plugin/Action.java | 29 ++--
src/main/java/usace/cc/plugin/CcStoreS3.java | 7 +-
.../usace/cc/plugin/ConnectionDataStore.java | 6 +
src/main/java/usace/cc/plugin/DataSource.java | 2 +-
.../usace/cc/plugin/DataSourceIOType.java | 7 +
src/main/java/usace/cc/plugin/DataStore.java | 6 +-
.../cc/plugin/DataStoreTypeRegistry.java | 27 ++++
.../java/usace/cc/plugin/FileDataStoreS3.java | 19 ++-
.../usace/cc/plugin/GetDataSourceInput.java | 16 ++
src/main/java/usace/cc/plugin/IOManager.java | 137 ++++++++++++++++++
src/main/java/usace/cc/plugin/Payload.java | 28 +---
.../usace/cc/plugin/PayloadAttributes.java | 104 +++++++++++++
.../java/usace/cc/plugin/PluginManager.java | 109 ++------------
13 files changed, 350 insertions(+), 147 deletions(-)
create mode 100644 src/main/java/usace/cc/plugin/ConnectionDataStore.java
create mode 100644 src/main/java/usace/cc/plugin/DataSourceIOType.java
create mode 100644 src/main/java/usace/cc/plugin/DataStoreTypeRegistry.java
create mode 100644 src/main/java/usace/cc/plugin/GetDataSourceInput.java
create mode 100644 src/main/java/usace/cc/plugin/IOManager.java
create mode 100644 src/main/java/usace/cc/plugin/PayloadAttributes.java
diff --git a/src/main/java/usace/cc/plugin/Action.java b/src/main/java/usace/cc/plugin/Action.java
index a5754fe..e46805a 100644
--- a/src/main/java/usace/cc/plugin/Action.java
+++ b/src/main/java/usace/cc/plugin/Action.java
@@ -1,36 +1,27 @@
package usace.cc.plugin;
-import java.util.Map;
-
import com.fasterxml.jackson.annotation.JsonProperty;
public class Action {
@JsonProperty
- private String name;
+ private String type;
@JsonProperty
private String desc;
@JsonProperty
- private Map params;
- public String getName(){
- return name;
+ private IOManager ioManager;
+ public String getType(){
+ return type;
+ }
+ public IOManager getIOManager(){
+ return ioManager;
}
-
public String getDescription(){
return desc;
}
-
- public Map getParameters(){
- return params;
- }
- public void UpdateActionPaths(){
+ public void UpdateActionPaths()throws Exception{
PluginManager pm = PluginManager.getInstance();
- this.name = pm.SubstitutePath(this.name);
+ this.type = pm.SubstitutePath(this.type);
this.desc = pm.SubstitutePath(this.desc);
- if(params!=null){
- for(Map.Entry apb : params.entrySet()){
- params.replace(apb.getKey(),apb.getValue().UpdatePaths());
- }
- }
-
+ this.ioManager = ioManager.UpdateIOManagerPaths();
}
}
diff --git a/src/main/java/usace/cc/plugin/CcStoreS3.java b/src/main/java/usace/cc/plugin/CcStoreS3.java
index 54087f7..4f124f6 100644
--- a/src/main/java/usace/cc/plugin/CcStoreS3.java
+++ b/src/main/java/usace/cc/plugin/CcStoreS3.java
@@ -156,8 +156,11 @@ private void writeInputStreamToDisk(InputStream input, String outputDestination)
f.mkdirs();
}
byte[] bytes = input.readAllBytes();
- OutputStream os = new FileOutputStream(new File(outputDestination));
- os.write(bytes);
+ try (OutputStream os = new FileOutputStream(new File(outputDestination))) {
+ os.write(bytes);
+ } catch (Exception e) {
+ e.printStackTrace();
+ };
}
@Override
public byte[] GetObject(GetObjectInput input) throws AmazonS3Exception {
diff --git a/src/main/java/usace/cc/plugin/ConnectionDataStore.java b/src/main/java/usace/cc/plugin/ConnectionDataStore.java
new file mode 100644
index 0000000..6237d03
--- /dev/null
+++ b/src/main/java/usace/cc/plugin/ConnectionDataStore.java
@@ -0,0 +1,6 @@
+package usace.cc.plugin;
+
+public interface ConnectionDataStore {
+ public ConnectionDataStore Connect(DataStore ds);
+ public Object RawSession();
+}
diff --git a/src/main/java/usace/cc/plugin/DataSource.java b/src/main/java/usace/cc/plugin/DataSource.java
index 99359a4..97c4f0e 100644
--- a/src/main/java/usace/cc/plugin/DataSource.java
+++ b/src/main/java/usace/cc/plugin/DataSource.java
@@ -26,7 +26,7 @@ public String[] getDataPaths(){
public String getStoreName(){
return StoreName;
}
- public DataSource UpdatePaths(){
+ public DataSource UpdatePaths()throws Exception{
DataSource dest = this;
PluginManager pm = PluginManager.getInstance();
dest.Name = pm.SubstitutePath(this.getName());
diff --git a/src/main/java/usace/cc/plugin/DataSourceIOType.java b/src/main/java/usace/cc/plugin/DataSourceIOType.java
new file mode 100644
index 0000000..faab2b0
--- /dev/null
+++ b/src/main/java/usace/cc/plugin/DataSourceIOType.java
@@ -0,0 +1,7 @@
+package usace.cc.plugin;
+
+public enum DataSourceIOType {
+ INPUT,
+ OUTPUT,
+ ANY,
+}
diff --git a/src/main/java/usace/cc/plugin/DataStore.java b/src/main/java/usace/cc/plugin/DataStore.java
index 2c482e7..b1c9852 100644
--- a/src/main/java/usace/cc/plugin/DataStore.java
+++ b/src/main/java/usace/cc/plugin/DataStore.java
@@ -1,5 +1,4 @@
package usace.cc.plugin;
-import java.util.Map;
import com.fasterxml.jackson.annotation.JsonProperty;
public class DataStore {
@@ -8,12 +7,11 @@ public class DataStore {
@JsonProperty
private String ID;
@JsonProperty
- private Map Parameters;
+ private PayloadAttributes Parameters;
@JsonProperty
private StoreType StoreType;
@JsonProperty
private String DsProfile;
- @JsonProperty
private Object Session;
public String getName(){
@@ -25,7 +23,7 @@ public String getId(){
public StoreType getStoreType(){
return StoreType;
}
- public Map getParameters(){
+ public PayloadAttributes getParameters(){
return Parameters;
}
public String getDsProfile(){
diff --git a/src/main/java/usace/cc/plugin/DataStoreTypeRegistry.java b/src/main/java/usace/cc/plugin/DataStoreTypeRegistry.java
new file mode 100644
index 0000000..9c91abb
--- /dev/null
+++ b/src/main/java/usace/cc/plugin/DataStoreTypeRegistry.java
@@ -0,0 +1,27 @@
+package usace.cc.plugin;
+
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+
+public final class DataStoreTypeRegistry {
+ private Map registry;
+ private static DataStoreTypeRegistry _instance = null;
+ public static DataStoreTypeRegistry getInstance(){
+ if (_instance==null){
+ _instance = new DataStoreTypeRegistry();
+ }
+ return _instance;
+ }
+ private DataStoreTypeRegistry(){
+ registry = new HashMap();
+ registry.put(StoreType.S3, FileDataStoreS3.class);
+ }
+ public static void Register(StoreType storeType, Object storeInstance){
+ DataStoreTypeRegistry.getInstance().registry.put(storeType, storeInstance.getClass());
+ }
+ public Object New(StoreType s)throws Exception{
+ Type type = DataStoreTypeRegistry.getInstance().registry.get(s);
+ return type.getClass().getDeclaredConstructor().newInstance();
+ }
+}
diff --git a/src/main/java/usace/cc/plugin/FileDataStoreS3.java b/src/main/java/usace/cc/plugin/FileDataStoreS3.java
index b9d0bf4..20826f4 100644
--- a/src/main/java/usace/cc/plugin/FileDataStoreS3.java
+++ b/src/main/java/usace/cc/plugin/FileDataStoreS3.java
@@ -26,7 +26,7 @@
import com.amazonaws.services.s3.model.S3Object;
-public class FileDataStoreS3 implements FileDataStore {
+public class FileDataStoreS3 implements FileDataStore, ConnectionDataStore {
String bucket;
String postFix;
StoreType storeType;
@@ -89,8 +89,15 @@ public Boolean Delete(String path) {
return false;
}
}
+ public FileDataStoreS3(){
- public FileDataStoreS3(DataStore ds){
+ }
+ @Override
+ public Object RawSession(){
+ return awsS3;
+ }
+ @Override
+ public ConnectionDataStore Connect(DataStore ds) {
AWSConfig acfg = new AWSConfig();
acfg.aws_access_key_id = System.getenv(ds.getDsProfile() + "_" + EnvironmentVariables.AWS_ACCESS_KEY_ID);
acfg.aws_secret_access_key_id = System.getenv(ds.getDsProfile() + "_" + EnvironmentVariables.AWS_SECRET_ACCESS_KEY);
@@ -141,7 +148,12 @@ public FileDataStoreS3(DataStore ds){
e.printStackTrace();
}
storeType = StoreType.S3;
- String tmpRoot = ds.getParameters().get(FileDataStoreS3.S3ROOT);
+ String tmpRoot="";
+ try {
+ tmpRoot = ds.getParameters().getString(FileDataStoreS3.S3ROOT);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
if (tmpRoot == ""){
//error out?
System.out.print("Missing S3 Root Paramter. Cannot create the store.");
@@ -149,6 +161,7 @@ public FileDataStoreS3(DataStore ds){
this.bucket = config.aws_bucket;
tmpRoot = tmpRoot.replaceFirst("^/+", "");
this.postFix = tmpRoot;
+ return this;
}
private byte[] GetObject(String path) throws RemoteException {
byte[] data;
diff --git a/src/main/java/usace/cc/plugin/GetDataSourceInput.java b/src/main/java/usace/cc/plugin/GetDataSourceInput.java
new file mode 100644
index 0000000..cbb78af
--- /dev/null
+++ b/src/main/java/usace/cc/plugin/GetDataSourceInput.java
@@ -0,0 +1,16 @@
+package usace.cc.plugin;
+
+public class GetDataSourceInput {
+ private DataSourceIOType dataSourceType;
+ private String dataSourceName;
+ public DataSourceIOType getDataSourceIOType(){
+ return dataSourceType;
+ }
+ public String getDataSourceName(){
+ return dataSourceName;
+ }
+ public GetDataSourceInput(String name, DataSourceIOType type){
+ dataSourceType = type;
+ dataSourceName = name;
+ }
+}
diff --git a/src/main/java/usace/cc/plugin/IOManager.java b/src/main/java/usace/cc/plugin/IOManager.java
new file mode 100644
index 0000000..c201d72
--- /dev/null
+++ b/src/main/java/usace/cc/plugin/IOManager.java
@@ -0,0 +1,137 @@
+package usace.cc.plugin;
+
+import java.util.Arrays;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class IOManager {
+ @JsonProperty
+ private PayloadAttributes attributes;
+ @JsonProperty
+ private DataStore[] stores;
+ @JsonProperty
+ private DataSource[] inputs;
+ @JsonProperty
+ private DataSource[] outputs;
+ public PayloadAttributes getAttributes(){
+ return attributes;
+ }
+ public DataStore[] getStores(){
+ return stores;
+ }
+ public DataSource getDataSource(GetDataSourceInput gdsi)throws Exception{
+ DataSource[] sources;
+ switch (gdsi.getDataSourceIOType()) {
+ case INPUT:
+ sources = inputs;
+ break;
+ case OUTPUT:
+ sources = outputs;
+ break;
+ case ANY:
+ sources = Arrays.copyOf(inputs,inputs.length+ outputs.length);
+ System.arraycopy(outputs, 0, sources, inputs.length, outputs.length);
+ break;
+ default:
+ throw new Exception("input type not recognized");
+ }
+ for(DataSource ds : sources){
+ if(ds.getName() == gdsi.getDataSourceName()){
+ return ds;
+ }
+ }
+ throw new Exception("input type not recognized");
+ }
+ public IOManager UpdateIOManagerPaths()throws Exception{
+ DataSource[] updatedInputs = new DataSource[inputs.length];
+ for(int i=0;iT GetStoreSession(String name) throws Exception {
+ for(DataStore ds : stores){
+ if (ds.getName()==name){
+ T session = (T)ds.getSession();
+ if (session==null){
+ throw new Exception("unable to cast to type t");
+ }else{
+ return session;
+ }
+ }
+ }
+ throw new Exception("unable to find session by name of " + name);
+ }
+}
diff --git a/src/main/java/usace/cc/plugin/Payload.java b/src/main/java/usace/cc/plugin/Payload.java
index 3febdb9..b3e7c64 100644
--- a/src/main/java/usace/cc/plugin/Payload.java
+++ b/src/main/java/usace/cc/plugin/Payload.java
@@ -1,35 +1,19 @@
package usace.cc.plugin;
import com.fasterxml.jackson.annotation.JsonProperty;
-import java.util.Map;
public class Payload {
@JsonProperty
- private Map attributes;
- @JsonProperty
- private DataStore[] stores;
- @JsonProperty
- private DataSource[] inputs;
- @JsonProperty
- private DataSource[] outputs;
+ private IOManager ioManager;
@JsonProperty
private Action[] actions;
- public Map getAttributes(){
- return attributes;
- }
- public DataStore[] getStores(){
- return stores;
- }
- public void setStore(int index, DataStore store){
- stores[index] = store;
- }
- public DataSource[] getInputs(){
- return inputs;
- }
- public DataSource[] getOutputs(){
- return outputs;
+ public IOManager getIOManager(){
+ return ioManager;
}
public Action[] getActions(){
return actions;
}
+ public void setIOManager(IOManager inIOManager){
+ ioManager = inIOManager;
+ }
}
diff --git a/src/main/java/usace/cc/plugin/PayloadAttributes.java b/src/main/java/usace/cc/plugin/PayloadAttributes.java
new file mode 100644
index 0000000..da4a9d6
--- /dev/null
+++ b/src/main/java/usace/cc/plugin/PayloadAttributes.java
@@ -0,0 +1,104 @@
+package usace.cc.plugin;
+
+import java.util.Map;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class PayloadAttributes {
+ @JsonProperty
+ private Map attributes;
+
+ public Map getParameters(){
+ return attributes;
+ }
+ public int getInt(String name) throws Exception{
+ Object val = attributes.get(name);
+ if (val==null){
+ throw new Exception(name + " not found");
+ }else{
+ if(val instanceof Number){
+ return ((Number)val).intValue();
+ }else{
+ return Integer.parseInt(val.toString());
+ }
+ }
+ }
+ public int getIntOrDefault(String name, int defaultValue){
+ try{
+ int value = getInt(name);
+ return value;
+ }catch(Exception ex){
+ System.out.println(ex.getMessage());
+ return defaultValue;
+ }
+ }
+ public long getInt64(String name) throws Exception{
+ Object val = attributes.get(name);
+ if (val==null){
+ throw new Exception(name + " not found");
+ }else{
+ if(val instanceof Number){
+ return ((Number)val).longValue();
+ }else{
+ return Long.parseLong(val.toString());
+ }
+ }
+ }
+ public long getInt64OrDefault(String name, long defaultValue){
+ try{
+ long value = getInt64(name);
+ return value;
+ }catch(Exception ex){
+ System.out.println(ex.getMessage());
+ return defaultValue;
+ }
+ }
+ public double getDouble(String name) throws Exception{
+ Object val = attributes.get(name);
+ if (val==null){
+ throw new Exception(name + " not found");
+ }else{
+ if(val instanceof Number){
+ return ((Number)val).doubleValue();
+ }else{
+ return Double.parseDouble(val.toString());
+ }
+ }
+ }
+ public double getDoubleOrDefault(String name, double defaultValue){
+ try{
+ double value = getDouble(name);
+ return value;
+ }catch(Exception ex){
+ System.out.println(ex.getMessage());
+ return defaultValue;
+ }
+ }
+ public String getString(String name) throws Exception{
+ Object val = attributes.get(name);
+ if (val==null){
+ throw new Exception(name + " not found");
+ }else{
+ return String.valueOf(val);
+ }
+ }
+ public String getStringOrDefault(String name, String defaultValue){
+ try{
+ String value = getString(name);
+ return value;
+ }catch(Exception ex){
+ System.out.println(ex.getMessage());
+ return defaultValue;
+ }
+ }
+ public void UpdatePayloadAttributes()throws Exception{
+ PluginManager pm = PluginManager.getInstance();
+ for(Map.Entry me : attributes.entrySet()){
+ Object val = me.getValue();
+ if(val instanceof String){
+ String strval = String.valueOf(val);
+ strval = pm.SubstitutePath(strval);
+ attributes.replace(me.getKey(),strval);
+ }//TODO: what if it is an array of string?
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/usace/cc/plugin/PluginManager.java b/src/main/java/usace/cc/plugin/PluginManager.java
index 3a5a95a..31c757e 100644
--- a/src/main/java/usace/cc/plugin/PluginManager.java
+++ b/src/main/java/usace/cc/plugin/PluginManager.java
@@ -3,7 +3,6 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -29,22 +28,9 @@ private PluginManager(){
cs = new CcStoreS3();
try {
_payload = cs.GetPayload();
- int i = 0;
- for (DataStore store : _payload.getStores()) {
- switch (store.getStoreType()){
- case S3:
- store.setSession(new FileDataStoreS3(store));
- _payload.setStore(i, store);
- break;
- case WS://does java work with fallthrough?
- case RDBMS:
- System.out.println("WS and RDBMS session instantiation is the responsibility of the plugin.");
- break;
- default:
- System.out.println("Invalid Store type");//what type was provided?
- break;
- }
- i ++;
+ _payload.getIOManager().ConnectStores();
+ for (Action action : _payload.getActions()) {
+ action.getIOManager().ConnectStores();
}
//substitutePathVariables();
} catch (Exception e) {
@@ -52,25 +38,15 @@ private PluginManager(){
}
}
- private void substitutePathVariables() {
- if (_payload.getInputs()!=null){
- for (int i= 0; i<_payload.getInputs().length; i++){
- _payload.getInputs()[i] = _payload.getInputs()[i].UpdatePaths();
- }
- }
- if (_payload.getOutputs()!=null){
- for (int i= 0; i<_payload.getOutputs().length; i++){
- _payload.getOutputs()[i] = _payload.getOutputs()[i].UpdatePaths();
- }
- }
+ private void substitutePathVariables() throws Exception{
+ _payload.setIOManager(_payload.getIOManager().UpdateIOManagerPaths());
if(_payload.getActions()!=null){
for (int i= 0; i<_payload.getActions().length; i++){
_payload.getActions()[i].UpdateActionPaths();
}
}
-
}
- public String SubstitutePath(String path) {
+ public String SubstitutePath(String path) throws Exception {
Matcher m = p.matcher(path);
while(m.find()){
String result = m.group();
@@ -83,7 +59,7 @@ public String SubstitutePath(String path) {
m = p.matcher(path);
break;
case "ATTR":
- String valattr = _payload.getAttributes().get(parts[1]).toString();
+ String valattr = _payload.getIOManager().getAttributes().getString(parts[1]);
path = path.replaceFirst("\\{"+result+"\\}", valattr);//?
m = p.matcher(path);
break;
@@ -95,57 +71,16 @@ public String SubstitutePath(String path) {
}
public Payload getPayload(){
if (!_hasUpdatedPaths){
- substitutePathVariables();
+ try{
+ substitutePathVariables();
+ }catch(Exception e){
+ e.printStackTrace();
+ System.exit(1);
+ }
_hasUpdatedPaths = true;
}
return _payload;
}
- public FileDataStore getFileStore(String storeName){
- return (FileDataStore) findDataStore(storeName).getSession();//check for nil?
- }
- public DataStore getStore(String storeName){
- return findDataStore(storeName);
- }
- public DataSource getInputDataSource(String name){
- return findDataSource(name, getInputDataSources());
- }
- public DataSource getOutputDataSource(String name){
- return findDataSource(name, getOutputDataSources());
- }
- public DataSource[] getInputDataSources(){
- return _payload.getInputs();
- }
- public DataSource[] getOutputDataSources(){
- return _payload.getOutputs();
- }
- public byte[] getFile(DataSource ds, int path){
- FileDataStore store = getFileStore(ds.getStoreName());
- InputStream reader = store.Get(ds.getPaths()[path]);
- byte[] data;
- try {
- data = reader.readAllBytes();
- return data;
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- }
- public boolean putFile(byte[] data, DataSource ds, int path){
- FileDataStore store = getFileStore(ds.getStoreName());
- return store.Put(new ByteArrayInputStream(data), ds.getPaths()[path]);
- }
- public boolean fileWriter(InputStream inputstream, DataSource destDs, int destPath){
- FileDataStore store = getFileStore(destDs.getStoreName());
- return store.Put(inputstream, destDs.getPaths()[destPath]);
- }
- public InputStream fileReader(DataSource ds, int path){
- FileDataStore store = getFileStore(ds.getStoreName());
- return store.Get(ds.getPaths()[path]);
- }
- public InputStream fileReaderByName(String dataSourceName, int path){
- DataSource ds = findDataSource(dataSourceName, getInputDataSources());
- return fileReader(ds, path);
- }
public void setLogLevel(ErrorLevel level){
_logger.setErrorLevel(level);
}
@@ -159,26 +94,8 @@ public void ReportProgress(Status report){
_logger.ReportStatus(report);
}
public int EventNumber(){
- //Object result = _payload.getAttributes().get(EnvironmentVariables.CC_EVENT_NUMBER);
String val = System.getenv(EnvironmentVariables.CC_EVENT_NUMBER);
int eventNumber = Integer.parseInt(val);
return eventNumber;
}
- private DataSource findDataSource(String name, DataSource[] dataSources){
- for (DataSource dataSource : dataSources) {
- if (dataSource.getName().equalsIgnoreCase(name)){
- return dataSource;
- }
- }
- return null;
- }
- private DataStore findDataStore(String name){
- for (DataStore dataStore : _payload.getStores()) {
- if (dataStore.getName().equalsIgnoreCase(name)){
- return dataStore;
- }
- }
- System.out.println(name + " store not found.");
- return null;
- }
}
\ No newline at end of file
From 47261d3f12dc55fd2b9a05424197d25215832005 Mon Sep 17 00:00:00 2001
From: Randal
Date: Tue, 15 Apr 2025 16:17:52 -0400
Subject: [PATCH 2/6] begin sync of API with golang API
---
Dockerfile | 19 +++--
build.gradle | 4 +-
src/main/java/usace/cc/plugin/Action.java | 4 +-
src/main/java/usace/cc/plugin/DataSource.java | 10 +--
.../usace/cc/plugin/EnvironmentVariables.java | 6 +-
.../java/usace/cc/plugin/FileDataStoreS3.java | 73 +++++++---------
.../usace/cc/plugin/PayloadAttributes.java | 2 +-
.../java/usace/cc/plugin/PluginManager.java | 85 +++++++++++--------
8 files changed, 109 insertions(+), 94 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index b85590b..cc0814d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,13 @@
-FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu as dev
-ENV TZ=America/New_York
-RUN apt update
-RUN apt -y install wget
-RUN apt -y install git
-#FROM ubuntu:20.04 as prod
+FROM --platform=linux/amd64 ubuntu:24.04
+
+ENV TZ=America/New_York
+
+RUN echo 'Acquire::http::Pipeline-Depth 0;\nAcquire::http::No-Cache true; \nAcquire::BrokenProxy true;\n' > /etc/apt/apt.conf.d/99fixbadproxy
+
+RUN apt update &&\
+ apt -y install wget &&\
+ apt -y install git &&\
+ apt -y install curl &&\
+ apt -y install vim &&\
+ apt -y install unzip &&\
+ apt -y install openjdk-17-jdk
diff --git a/build.gradle b/build.gradle
index 1a91eab..b9c404d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -18,8 +18,8 @@ dependencies {
implementation 'com.amazonaws:aws-java-sdk-s3'
}
jar {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
publishing {
repositories {
diff --git a/src/main/java/usace/cc/plugin/Action.java b/src/main/java/usace/cc/plugin/Action.java
index e46805a..356add9 100644
--- a/src/main/java/usace/cc/plugin/Action.java
+++ b/src/main/java/usace/cc/plugin/Action.java
@@ -20,8 +20,8 @@ public String getDescription(){
}
public void UpdateActionPaths()throws Exception{
PluginManager pm = PluginManager.getInstance();
- this.type = pm.SubstitutePath(this.type);
- this.desc = pm.SubstitutePath(this.desc);
+ this.type = pm.substitutePath(this.type);
+ this.desc = pm.substitutePath(this.desc);
this.ioManager = ioManager.UpdateIOManagerPaths();
}
}
diff --git a/src/main/java/usace/cc/plugin/DataSource.java b/src/main/java/usace/cc/plugin/DataSource.java
index 97c4f0e..443904c 100644
--- a/src/main/java/usace/cc/plugin/DataSource.java
+++ b/src/main/java/usace/cc/plugin/DataSource.java
@@ -29,18 +29,18 @@ public String getStoreName(){
public DataSource UpdatePaths()throws Exception{
DataSource dest = this;
PluginManager pm = PluginManager.getInstance();
- dest.Name = pm.SubstitutePath(this.getName());
+ dest.Name = pm.substitutePath(this.getName());
if(this.getPaths()!=null){
for(int j=0; j
Date: Mon, 28 Apr 2025 15:18:42 -0400
Subject: [PATCH 3/6] IOManager and Payload updates
---
.../compileJava/previous-compilation-data.bin | Bin 45716 -> 0 bytes
build/tmp/jar/MANIFEST.MF | 2 -
src/main/java/usace/cc/plugin/AWSConfig.java | 11 +
src/main/java/usace/cc/plugin/Action.java | 25 +-
src/main/java/usace/cc/plugin/Config.java | 4 +
src/main/java/usace/cc/plugin/DataSource.java | 82 ++--
.../java/usace/cc/plugin/FileDataStore.java | 2 +-
.../java/usace/cc/plugin/FileDataStoreS3.java | 11 +-
.../usace/cc/plugin/GetDataSourceInput.java | 4 +
src/main/java/usace/cc/plugin/IOManager.java | 389 ++++++++++++++----
src/main/java/usace/cc/plugin/Message.java | 4 +
src/main/java/usace/cc/plugin/Payload.java | 23 ++
.../usace/cc/plugin/PayloadAttributes.java | 40 +-
.../java/usace/cc/plugin/PluginManager.java | 213 ++++++++--
14 files changed, 650 insertions(+), 160 deletions(-)
delete mode 100644 build/tmp/compileJava/previous-compilation-data.bin
delete mode 100644 build/tmp/jar/MANIFEST.MF
diff --git a/build/tmp/compileJava/previous-compilation-data.bin b/build/tmp/compileJava/previous-compilation-data.bin
deleted file mode 100644
index 568a1501ae2eda5e0d59fee5cc263ec81d5dcfea..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 45716
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
V^*0t}VoClnBh`1+<2d2)??1ADU1b0O
diff --git a/build/tmp/jar/MANIFEST.MF b/build/tmp/jar/MANIFEST.MF
deleted file mode 100644
index 58630c0..0000000
--- a/build/tmp/jar/MANIFEST.MF
+++ /dev/null
@@ -1,2 +0,0 @@
-Manifest-Version: 1.0
-
diff --git a/src/main/java/usace/cc/plugin/AWSConfig.java b/src/main/java/usace/cc/plugin/AWSConfig.java
index f2ecd48..df6726d 100644
--- a/src/main/java/usace/cc/plugin/AWSConfig.java
+++ b/src/main/java/usace/cc/plugin/AWSConfig.java
@@ -1,22 +1,33 @@
package usace.cc.plugin;
+
import com.fasterxml.jackson.annotation.JsonProperty;
+
public class AWSConfig {
@JsonProperty
public String aws_config_name;
+
@JsonProperty
public String aws_access_key_id;
+
@JsonProperty
public String aws_secret_access_key_id;
+
@JsonProperty
public String aws_region;
+
@JsonProperty
public String aws_bucket;
+
@JsonProperty
public Boolean aws_mock;
+
@JsonProperty
public String aws_endpoint;
+
@JsonProperty
public Boolean aws_disable_ssl;
+
@JsonProperty
public Boolean aws_force_path_style;
+
}
diff --git a/src/main/java/usace/cc/plugin/Action.java b/src/main/java/usace/cc/plugin/Action.java
index 356add9..567fc5e 100644
--- a/src/main/java/usace/cc/plugin/Action.java
+++ b/src/main/java/usace/cc/plugin/Action.java
@@ -3,12 +3,16 @@
import com.fasterxml.jackson.annotation.JsonProperty;
public class Action {
+
@JsonProperty
private String type;
+
@JsonProperty
private String desc;
+
@JsonProperty
private IOManager ioManager;
+
public String getType(){
return type;
}
@@ -18,10 +22,21 @@ public IOManager getIOManager(){
public String getDescription(){
return desc;
}
- public void UpdateActionPaths()throws Exception{
- PluginManager pm = PluginManager.getInstance();
- this.type = pm.substitutePath(this.type);
- this.desc = pm.substitutePath(this.desc);
- this.ioManager = ioManager.UpdateIOManagerPaths();
+
+ public DataStore[] getStores(){
+ return this.ioManager.getStores();
}
+
+ public DataSource[] getInputs() {
+ return this.ioManager.getInputs();
+ }
+
+ public DataSource[] getOutputs(){
+ return this.ioManager.getOutputs();
+ }
+
+ public PayloadAttributes getAttributes(){
+ return this.ioManager.getAttributes();
+ }
+
}
diff --git a/src/main/java/usace/cc/plugin/Config.java b/src/main/java/usace/cc/plugin/Config.java
index 892d996..749ac27 100644
--- a/src/main/java/usace/cc/plugin/Config.java
+++ b/src/main/java/usace/cc/plugin/Config.java
@@ -1,6 +1,10 @@
package usace.cc.plugin;
+
import com.fasterxml.jackson.annotation.JsonProperty;
+
public class Config {
+
@JsonProperty
public AWSConfig[] aws_configs;
+
}
\ No newline at end of file
diff --git a/src/main/java/usace/cc/plugin/DataSource.java b/src/main/java/usace/cc/plugin/DataSource.java
index 443904c..57b3fd1 100644
--- a/src/main/java/usace/cc/plugin/DataSource.java
+++ b/src/main/java/usace/cc/plugin/DataSource.java
@@ -1,49 +1,73 @@
package usace.cc.plugin;
import com.fasterxml.jackson.annotation.JsonProperty;
public class DataSource {
+
@JsonProperty
- private String Name;
+ private String name;
+
@JsonProperty
- private String ID;
+ private String id;
+
@JsonProperty
- private String StoreName;
+ private String storeName;
+
@JsonProperty
- private String[] Paths;
+ private String[] paths;
+
@JsonProperty
- private String[] DataPaths;
+ private String[] dataPaths;
+
public String getId(){
- return ID;
+ return id;
}
+
public String getName(){
- return Name;
+ return name;
+ }
+
+ public void setName(String name){
+ this.name=name;
}
+
public String[] getPaths(){
- return Paths;
+ return this.paths;
+ }
+
+ public void setPaths(String[] paths){
+ this.paths=paths;
}
+
public String[] getDataPaths(){
- return DataPaths;
+ return dataPaths;
}
- public String getStoreName(){
- return StoreName;
- }
- public DataSource UpdatePaths()throws Exception{
- DataSource dest = this;
- PluginManager pm = PluginManager.getInstance();
- dest.Name = pm.substitutePath(this.getName());
- if(this.getPaths()!=null){
- for(int j=0; j optParam = ds.getParameters().get(FileDataStoreS3.S3ROOT);
+ if (optParam.isPresent()){
+ tmpRoot = optParam.get();
+ }
} catch (Exception e) {
e.printStackTrace();
+ //@TODO UGH....NOT HANDLING THE ERRORS!!!!!!!!!!!!!!!!
}
if (tmpRoot == ""){
//error out?
@@ -202,4 +208,5 @@ private boolean UploadToS3(String bucketName, String objectKey, byte[] fileBytes
return false;
}
}
+
}
diff --git a/src/main/java/usace/cc/plugin/GetDataSourceInput.java b/src/main/java/usace/cc/plugin/GetDataSourceInput.java
index cbb78af..39c18a9 100644
--- a/src/main/java/usace/cc/plugin/GetDataSourceInput.java
+++ b/src/main/java/usace/cc/plugin/GetDataSourceInput.java
@@ -1,14 +1,18 @@
package usace.cc.plugin;
public class GetDataSourceInput {
+
private DataSourceIOType dataSourceType;
private String dataSourceName;
+
public DataSourceIOType getDataSourceIOType(){
return dataSourceType;
}
+
public String getDataSourceName(){
return dataSourceName;
}
+
public GetDataSourceInput(String name, DataSourceIOType type){
dataSourceType = type;
dataSourceName = name;
diff --git a/src/main/java/usace/cc/plugin/IOManager.java b/src/main/java/usace/cc/plugin/IOManager.java
index c201d72..9e18a62 100644
--- a/src/main/java/usace/cc/plugin/IOManager.java
+++ b/src/main/java/usace/cc/plugin/IOManager.java
@@ -1,137 +1,362 @@
package usace.cc.plugin;
import java.util.Arrays;
+import java.util.Optional;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.fasterxml.jackson.annotation.JsonProperty;
public class IOManager {
+
+ //IO Manager Error Types
+ static class InvalidDataSourceException extends Exception {
+ public InvalidDataSourceException(String message) {
+ super(message);
+ }
+
+ public InvalidDataSourceException(Exception ex){
+ super(ex);
+ }
+ }
+
+ static class InvalidDataStoreException extends Exception {
+ public InvalidDataStoreException(String message) {
+ super(message);
+ }
+
+ public InvalidDataStoreException(Exception ex){
+ super(ex);
+ }
+ }
+
@JsonProperty
private PayloadAttributes attributes;
+
@JsonProperty
private DataStore[] stores;
+
@JsonProperty
private DataSource[] inputs;
+
@JsonProperty
private DataSource[] outputs;
+
+ private IOManager parent;
+
public PayloadAttributes getAttributes(){
return attributes;
}
+
public DataStore[] getStores(){
- return stores;
+ return this.stores;
}
- public DataSource getDataSource(GetDataSourceInput gdsi)throws Exception{
+
+ public DataSource[] getInputs(){
+ return this.inputs;
+ }
+
+ public DataSource[] getOutputs(){
+ return this.outputs;
+ }
+
+ public void setParent(IOManager parent){
+ this.parent=parent;
+ }
+
+
+ /**
+ * Retrieves a {@link DataStore} by its name.
+ *
+ * This method searches the current list of data stores for one with a matching name.
+ * If not found and a parent is defined, it will recursively search the parent.
+ *
+ *
+ * @param name the name of the data store to retrieve
+ * @return an {@code Optional} containing the matching {@code DataStore}, or
+ * {@code Optional.empty()} if no matching store is found in this instance
+ * or its parent chain
+ */
+ public Optional getStore(String name){
+ for (DataStore store:this.stores){
+ if (name.equals(store.getName())){
+ return Optional.of(store);
+ }
+ }
+ if (this.parent!=null){
+ return parent.getStore(name);
+ }
+ return Optional.empty();
+ }
+
+
+ /**
+ * Retrieves a {@link DataSource} based on the provided input criteria.
+ *
+ * This method selects from input sources, output sources, or both depending on the
+ * {@link GetDataSourceInput#getDataSourceIOType()} value. It then searches for a
+ * {@code DataSource} with a matching name. If no match is found locally and a parent
+ * exists, the search will continue recursively in the parent.
+ *
+ *
+ * @param gdsi an object encapsulating the data source name and the I/O type to search
+ * @return an {@code Optional} containing the matching {@code DataSource}, or {@code Optional.empty()}
+ * if no such data source exists in this instance or its parent chain
+ * @throws InvalidDataSourceException if the {@code DataSourceIOType} in the input is not recognized
+ */
+ public Optional getDataSource(GetDataSourceInput gdsi) throws InvalidDataSourceException{
DataSource[] sources;
switch (gdsi.getDataSourceIOType()) {
case INPUT:
- sources = inputs;
+ sources = this.inputs;
break;
- case OUTPUT:
- sources = outputs;
+ case OUTPUT:
+ sources = this.outputs;
break;
- case ANY:
- sources = Arrays.copyOf(inputs,inputs.length+ outputs.length);
- System.arraycopy(outputs, 0, sources, inputs.length, outputs.length);
+ case ANY:
+ sources = Arrays.copyOf(this.inputs,this.inputs.length + this.outputs.length);
+ System.arraycopy(this.outputs, 0, sources, this.inputs.length, this.outputs.length);
break;
default:
- throw new Exception("input type not recognized");
+ throw new InvalidDataSourceException("datan source input type not recognized");
}
+
for(DataSource ds : sources){
if(ds.getName() == gdsi.getDataSourceName()){
- return ds;
+ return Optional.of(ds);
}
}
- throw new Exception("input type not recognized");
- }
- public IOManager UpdateIOManagerPaths()throws Exception{
- DataSource[] updatedInputs = new DataSource[inputs.length];
- for(int i=0;i
+ * This is a convenience method that constructs a {@link GetDataSourceInput} with the specified
+ * name and an I/O type of {@code INPUT}, then delegates to {@link #getDataSource(GetDataSourceInput)}.
+ *
+ *
+ * @param name the name of the input data source to retrieve
+ * @return an {@code Optional} containing the matching input {@code DataSource}, or
+ * {@code Optional.empty()} if no matching source is found locally or in a parent
+ * @throws InvalidDataSourceException if the underlying data source lookup encounters an error
+ */
+ public Optional getInputDataSource(String name) throws InvalidDataSourceException {
+ var gdsi = new GetDataSourceInput(name, DataSourceIOType.INPUT);
+ return getDataSource(gdsi);
+ }
+
+ /**
+ * Retrieves an output {@link DataSource} by name.
+ *
+ * This is a convenience method that constructs a {@link GetDataSourceInput} with the specified
+ * name and an I/O type of {@code OUTPUT}, then delegates to {@link #getDataSource(GetDataSourceInput)}.
+ *
+ *
+ * @param name the name of the output data source to retrieve
+ * @return an {@code Optional} containing the matching output {@code DataSource}, or
+ * {@code Optional.empty()} if no matching source is found locally or in a parent
+ * @throws InvalidDataSourceException if the underlying data source lookup encounters an error
+ */
+ public Optional getOutputDataSource(String name) throws InvalidDataSourceException {
+ var gdsi = new GetDataSourceInput(name, DataSourceIOType.OUTPUT);
+ return getDataSource(gdsi);
+ }
+
+ //@TODO....I include a data path here
+ /**
+ * Copies a file from an input {@link DataSource} to a local file path.
+ *
+ * This method locates the input data source by name, retrieves the input stream
+ * for the specified path key, reads the file's contents, and writes them to the
+ * specified local file path.
+ *
+ *
+ * @param dataSourceName the name of the input data source
+ * @param pathkey the key or path identifying the file within the data source
+ * @param localPath the path on the local filesystem where the file will be written
+ * @throws InvalidDataSourceException if the data source is not found or if an error occurs while accessing it
+ * @throws IOException if an I/O error occurs during reading from the source or writing to the local file
+ */
+ public void copyFileToLocal(String dataSourceName, String pathkey, String localPath) throws IOException, InvalidDataSourceException{
+ Optional indsOpt = getDataSource(new GetDataSourceInput(dataSourceName, DataSourceIOType.INPUT));
+ if (!indsOpt.isPresent()){
+ throw new InvalidDataSourceException("Data source not found");
}
- IOManager updatedIOManager = new IOManager();
- updatedIOManager.inputs = updatedInputs;
- updatedIOManager.outputs = updatedOutputs;
- this.attributes.UpdatePayloadAttributes();
- updatedIOManager.attributes = this.attributes;
- updatedIOManager.stores = this.stores;
- return updatedIOManager;
- }
- public void CopyFileToLocal(String dataSourceName, String pathkey, String localPath) throws Exception{
- DataSource inds = getDataSource(new GetDataSourceInput(dataSourceName, DataSourceIOType.INPUT));
- InputStream is = GetReader(inds, pathkey);
- try (is) {
+
+ DataSource inds = indsOpt.get();
+
+ try (InputStream is = getInputStream(inds, pathkey)) {
byte[] bytes = is.readAllBytes();
File outfile = new File(localPath);
- OutputStream writer = new FileOutputStream(outfile);
- try(writer){
+ try(OutputStream writer = new FileOutputStream(outfile)){
writer.write(bytes);
- }catch (Exception e){
- e.printStackTrace();
- }
- } catch (Exception e) {
- // TODO: handle exception
- e.printStackTrace();
+ }
}
}
- public void Write(InputStream writer, String datasourcename, String pathName, String datapathName) throws Exception{
- DataSource ds = this.getDataSource(new GetDataSourceInput(datasourcename, DataSourceIOType.OUTPUT));
- FileDataStore fds = GetStoreSession(ds.getStoreName());
- fds.Put(writer, pathName);
- }
- public byte[] Get(String dataSourceName, String pathName, String DataPathName)throws Exception{
- DataSource ds = this.getDataSource(new GetDataSourceInput(dataSourceName, DataSourceIOType.INPUT));
- return GetReader(ds, pathName).readAllBytes();
- }
- public void Put(byte[] data, String dataSourceName, String pathName, String DataPathName) throws Exception{
- DataSource ds = this.getDataSource(new GetDataSourceInput(dataSourceName, DataSourceIOType.OUTPUT));
- FileDataStore fds = GetStoreSession(ds.getStoreName());
- ByteArrayInputStream bais = new ByteArrayInputStream(data);
- fds.Put(bais, pathName);
- }
- public InputStream GetReader(DataSource dataSource, String pathKey) throws Exception{
- FileDataStore fds = GetStoreSession(dataSource.getStoreName());
- InputStream s = fds.Get(pathKey);
- return s;
- }
- public void CopyFileToRemote(String destinationName, String pathKey, String localPath) throws Exception{
- DataSource ds = this.getDataSource(new GetDataSourceInput(destinationName, DataSourceIOType.OUTPUT));
- FileDataStore fdstore = GetStoreSession(ds.getStoreName());
- File localFile = new File(localPath);
-
- InputStream reader = new FileInputStream(localFile);
- fdstore.Put(reader, pathKey);
- }
- public void ConnectStores() throws Exception{
- DataStoreTypeRegistry registry = DataStoreTypeRegistry.getInstance();
- //int i = 0;
- for (int i = 0; i
+ * This method locates the data source by name and attempts to read the contents of the file
+ * identified by the given {@code pathName}. If the data source is not found, or an error occurs
+ * while accessing it, an exception is thrown. The {@code dataPathName} is included for error
+ * context but not used directly in the lookup.
+ *
+ *
+ * @param dataSourceName the name of the input data source
+ * @param pathName the key or identifier of the file within the data source
+ * @param dataPathName an additional path descriptor for context in error reporting
+ * @return a byte array containing the contents of the specified file
+ * @throws InvalidDataSourceException if the data source is not found or cannot be accessed
+ * @throws IOException if an I/O error occurs while reading from the data source
+ */
+ public byte[] get(String dataSourceName, String pathName, String dataPathName) throws IOException, InvalidDataSourceException{
+ Optional dsOpt = this.getDataSource(new GetDataSourceInput(dataSourceName, DataSourceIOType.INPUT));
+ if (dsOpt.isPresent()){
+ var ds = dsOpt.get();
+ return getInputStream(ds, pathName).readAllBytes();
+ }
+ throw new InvalidDataSourceException(String.format("invalid data source. Name: %s, Path: %s, DataPath: %s",dataSourceName,pathName,dataPathName));
+ }
+
+ /**
+ * Writes the provided byte array to a specified path in a named output data source.
+ *
+ * This method looks up the data source by name and attempts to retrieve a corresponding
+ * {@code FileDataStore} session. If both are found, it writes the data to the given path
+ * within that data store. If either the data source or the data store is not found,
+ * an appropriate checked exception is thrown.
+ *
+ * @param data the data to write
+ * @param dataSourceName the name of the output data source to target
+ * @param pathName the path within the data store to write the data to
+ * @param dataPathName currently unused, reserved for future expansion or routing
+ *
+ * @throws IOException if an I/O error occurs during the write
+ * @throws InvalidDataSourceException if the specified data source cannot be found
+ * @throws InvalidDataStoreException if the data store session for the data source cannot be obtained
+ */
+ public void put(byte[] data, String dataSourceName, String pathName, String dataPathName) throws IOException, InvalidDataSourceException, InvalidDataStoreException{
+ Optional dsOpt = this.getDataSource(new GetDataSourceInput(dataSourceName, DataSourceIOType.OUTPUT));
+ if (dsOpt.isPresent()){
+ var ds = dsOpt.get();
+ Optional fdsOpt = getStoreSession(ds.getStoreName());
+ if (fdsOpt.isPresent()){
+ var fds = fdsOpt.get();
+ ByteArrayInputStream bais = new ByteArrayInputStream(data);
+ fds.Put(bais, pathName);
+ } else {
+ throw new InvalidDataStoreException("Datastore not found");
}
+ } else {
+ throw new InvalidDataSourceException("Datasource not found");
}
}
- public T GetStoreSession(String name) throws Exception {
+
+ /**
+ * Retrieves an {@link InputStream} from the given {@link DataSource} using the specified path key.
+ *
+ * This method attempts to obtain a {@code FileDataStore} session from the data source's store name,
+ * and then retrieves the corresponding input stream using the provided {@code pathKey}.
+ *
+ *
+ * @param dataSource the data source from which to retrieve the input stream
+ * @param pathKey the key or identifier used to locate the desired file within the store
+ * @return an {@code InputStream} for reading the data associated with the given key
+ * @throws InvalidDataSourceException if the store session cannot be obtained, if the store is not
+ * present, or if an underlying {@code InvalidDataStoreException} occurs
+ */
+ public InputStream getInputStream(DataSource dataSource, String pathKey) throws InvalidDataSourceException{
+ try{
+ Optional fdsOpt = getStoreSession(dataSource.getStoreName());
+ if(fdsOpt.isPresent()){
+ var fds = fdsOpt.get();
+ return fds.get(pathKey);
+ }
+ throw new InvalidDataSourceException("Unable to get input stream from the data source");
+ } catch(InvalidDataStoreException ex) {
+ throw new InvalidDataSourceException(ex);
+ }
+ }
+
+ /**
+ * Copies a local file to a remote data store.
+ *
+ * This method retrieves a {@link DataSource} configured for output using the given
+ * destination name, then locates the associated {@link FileDataStore} session.
+ * It reads the local file from the specified {@code localPath} and uploads its contents
+ * to the remote store under the provided {@code pathKey}.
+ *
+ * @param destinationName the name of the remote destination to which the file will be copied
+ * @param pathKey the key (path) under which the file will be stored remotely
+ * @param localPath the file system path to the local file that needs to be copied
+ * @throws InvalidDataSourceException if the specified data source is invalid or cannot be retrieved
+ * @throws InvalidDataStoreException if the data store session cannot be established or is invalid
+ * @throws IOException if an I/O error occurs while reading the local file or writing to the remote store
+ */
+ public void copyFileToRemote(String destinationName, String pathKey, String localPath) throws InvalidDataSourceException, InvalidDataStoreException, IOException{
+ Optional dsOpt = this.getDataSource(new GetDataSourceInput(destinationName, DataSourceIOType.OUTPUT));
+ if(dsOpt.isPresent()){
+ var ds = dsOpt.get();
+ Optional fdsOpt = getStoreSession(ds.getStoreName());
+ if(fdsOpt.isPresent()){
+ var fdstore = fdsOpt.get();
+ File localFile = new File(localPath);
+ InputStream reader = new FileInputStream(localFile);
+ fdstore.Put(reader, pathKey);
+ }
+ }
+ }
+
+
+ /**
+ * Retrieves a session object of type {@code T} from a data store with the specified name.
+ *
+ * This method searches through the available {@code DataStore} instances to find one
+ * matching the given {@code name}. If found, it attempts to retrieve and cast the session
+ * object to the desired type {@code T}.
+ *
+ *
+ * @param The expected type of the session object.
+ * @param name The name of the data store to retrieve the session from.
+ * @return An {@code Optional} containing the session object if present and of the correct type,
+ * or {@code Optional.empty()} if no matching store is found or the session is {@code null}.
+ * @throws InvalidDataStoreException if the session cannot be cast to the specified type {@code T}.
+ */
+ public Optional getStoreSession(String name) throws InvalidDataStoreException{
for(DataStore ds : stores){
if (ds.getName()==name){
- T session = (T)ds.getSession();
- if (session==null){
- throw new Exception("unable to cast to type t");
- }else{
- return session;
+ try{
+ T session = (T)ds.getSession();
+ if (session==null){
+ return Optional.empty();
+ }
+ return Optional.of(session);
+ } catch(ClassCastException ex){
+ throw new InvalidDataStoreException(ex);
}
}
}
- throw new Exception("unable to find session by name of " + name);
+ return Optional.empty();
}
}
diff --git a/src/main/java/usace/cc/plugin/Message.java b/src/main/java/usace/cc/plugin/Message.java
index 57f0837..3d5996d 100644
--- a/src/main/java/usace/cc/plugin/Message.java
+++ b/src/main/java/usace/cc/plugin/Message.java
@@ -1,12 +1,16 @@
package usace.cc.plugin;
import com.fasterxml.jackson.annotation.JsonProperty;
+
public class Message {
+
@JsonProperty
private String message;
+
public String getMessage(){
return message;
}
+
public Message(String message){
this.message = message;
}
diff --git a/src/main/java/usace/cc/plugin/Payload.java b/src/main/java/usace/cc/plugin/Payload.java
index b3e7c64..4ce7e11 100644
--- a/src/main/java/usace/cc/plugin/Payload.java
+++ b/src/main/java/usace/cc/plugin/Payload.java
@@ -2,18 +2,41 @@
import com.fasterxml.jackson.annotation.JsonProperty;
public class Payload {
+
@JsonProperty
private IOManager ioManager;
+
@JsonProperty
private Action[] actions;
+
public IOManager getIOManager(){
return ioManager;
}
+
public Action[] getActions(){
return actions;
}
+
public void setIOManager(IOManager inIOManager){
ioManager = inIOManager;
}
+
+ public DataStore[] getStores(){
+ return this.ioManager.getStores();
+ }
+
+ public PayloadAttributes getAttributes(){
+ return this.ioManager.getAttributes();
+ }
+
+ public DataSource[] getInputs(){
+ return this.ioManager.getInputs();
+ }
+
+ public DataSource[] getOutputs(){
+ return this.ioManager.getOutputs();
+ }
+
+
}
diff --git a/src/main/java/usace/cc/plugin/PayloadAttributes.java b/src/main/java/usace/cc/plugin/PayloadAttributes.java
index 8bdd074..8d91fa3 100644
--- a/src/main/java/usace/cc/plugin/PayloadAttributes.java
+++ b/src/main/java/usace/cc/plugin/PayloadAttributes.java
@@ -1,15 +1,48 @@
package usace.cc.plugin;
import java.util.Map;
+import java.util.Optional;
+
import com.fasterxml.jackson.annotation.JsonProperty;
public class PayloadAttributes {
+
@JsonProperty
private Map attributes;
- public Map getParameters(){
+ public Map getAttributes(){
return attributes;
}
+
+ public Optional get(String name) throws IllegalArgumentException{
+ Object val = attributes.get(name);
+ if (val==null){
+ return Optional.empty();
+ }else{
+ try {
+ @SuppressWarnings("unchecked")
+ T tval = (T) val;
+ return Optional.of(tval);
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("Invalid type cast.", e);
+ }
+ }
+ }
+
+ //@TODO delete if uneccesary
+ public Optional getAlt1(String name, Class clazz) throws IllegalArgumentException{
+ Object val = attributes.get(name);
+ if (val==null){
+ return Optional.empty();
+ }else{
+ if (clazz.isInstance(val)){
+ return Optional.of((T)val);
+ }
+ throw new IllegalArgumentException("Incorrect type");
+ }
+ }
+
+ /*
public int getInt(String name) throws Exception{
Object val = attributes.get(name);
if (val==null){
@@ -22,6 +55,7 @@ public int getInt(String name) throws Exception{
}
}
}
+
public int getIntOrDefault(String name, int defaultValue){
try{
int value = getInt(name);
@@ -31,6 +65,7 @@ public int getIntOrDefault(String name, int defaultValue){
return defaultValue;
}
}
+
public long getInt64(String name) throws Exception{
Object val = attributes.get(name);
if (val==null){
@@ -43,6 +78,7 @@ public long getInt64(String name) throws Exception{
}
}
}
+
public long getInt64OrDefault(String name, long defaultValue){
try{
long value = getInt64(name);
@@ -52,6 +88,7 @@ public long getInt64OrDefault(String name, long defaultValue){
return defaultValue;
}
}
+
public double getDouble(String name) throws Exception{
Object val = attributes.get(name);
if (val==null){
@@ -101,4 +138,5 @@ public void UpdatePayloadAttributes()throws Exception{
}//TODO: what if it is an array of string?
}
}
+ */
}
\ No newline at end of file
diff --git a/src/main/java/usace/cc/plugin/PluginManager.java b/src/main/java/usace/cc/plugin/PluginManager.java
index 411f25f..8ec5c71 100644
--- a/src/main/java/usace/cc/plugin/PluginManager.java
+++ b/src/main/java/usace/cc/plugin/PluginManager.java
@@ -1,5 +1,8 @@
package usace.cc.plugin;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -32,51 +35,19 @@ private PluginManager(){
logger = new Logger(sender, ErrorLevel.WARN);
cs = new CcStoreS3();
try {
- payload = cs.GetPayload();
- payload.getIOManager().ConnectStores();
+ this.payload = cs.GetPayload();
+ this.connectStores(payload.getStores());
for (Action action : payload.getActions()) {
- action.getIOManager().ConnectStores();
+ this.connectStores(action.getStores());
}
- //substitutePathVariables();
+ substitutePathVariables();
} catch (Exception e) {
e.printStackTrace();
}
}
- private void substitutePathVariables() throws Exception{
- payload.setIOManager(payload.getIOManager().UpdateIOManagerPaths());
- if(payload.getActions()!=null){
- for (int i= 0; i entry : attrs.entrySet()) {
+ var key = entry.getKey();
+ var val = entry.getValue();
+ if (val instanceof String){
+ parameterSubstitute((String)val, pattrs);
+ }
+ }
+ }
+
+ //a.k.a. pathssubstitute
+ private void substitutePaths(DataSource ds, PayloadAttributes attrs){
+ var param = parameterSubstitute(ds.getName(),attrs);
+ ds.setName(param);
+
+ var paths = ds.getPaths();
+ for (int i=0;i valattr = attrs.get(subname);
+ //Optional valattr = (Optional)attrs.get(subname);
+ //Optional valattr = attrs.getAlt1(subname, String.class);
+ Optional optVal = attrs.get(subname);
+ if (optVal.isPresent()){
+ param = param.replaceFirst("\\{"+result+"\\}", optVal.get());//?
+ m = p.matcher(param);
+ } else{
+ //@TODO logging is kind of annoying
+ logger.LogMessage(new Message(String.format("Attribute %s not found", subname)));
+ }
+ break;
+ }
+ }
+ return param;
+ }
+
+
+ // private void substitutePathVariables() throws Exception{
+ // payload.setIOManager(payload.getIOManager().UpdateIOManagerPaths());
+ // if(payload.getActions()!=null){
+ // for (int i= 0; i
Date: Tue, 29 Apr 2025 15:47:44 -0400
Subject: [PATCH 4/6] get payloads working. finish up editing styles
---
build.gradle | 2 +-
src/main/java/usace/cc/plugin/AWSConfig.java | 3 -
src/main/java/usace/cc/plugin/Action.java | 27 +----
src/main/java/usace/cc/plugin/CcStore.java | 12 +-
src/main/java/usace/cc/plugin/CcStoreS3.java | 79 ++++++------
.../usace/cc/plugin/ConnectionDataStore.java | 4 +-
src/main/java/usace/cc/plugin/Constants.java | 4 +-
src/main/java/usace/cc/plugin/DataSource.java | 40 ++-----
src/main/java/usace/cc/plugin/DataStore.java | 46 ++++---
.../cc/plugin/DataStoreTypeRegistry.java | 22 ++--
.../usace/cc/plugin/EnvironmentVariables.java | 1 +
src/main/java/usace/cc/plugin/Error.java | 4 +
.../java/usace/cc/plugin/FileDataStore.java | 7 +-
.../java/usace/cc/plugin/FileDataStoreS3.java | 32 ++---
.../java/usace/cc/plugin/GetObjectInput.java | 21 ++--
src/main/java/usace/cc/plugin/IOManager.java | 16 ++-
src/main/java/usace/cc/plugin/Logger.java | 16 +--
.../java/usace/cc/plugin/ObjectState.java | 4 +-
src/main/java/usace/cc/plugin/Payload.java | 31 +----
.../usace/cc/plugin/PayloadAttributes.java | 102 +---------------
.../java/usace/cc/plugin/PluginManager.java | 113 ++++--------------
.../java/usace/cc/plugin/PullObjectInput.java | 24 ++--
.../java/usace/cc/plugin/PutObjectInput.java | 30 +++--
src/main/java/usace/cc/plugin/SeedSet.java | 5 +
src/main/java/usace/cc/plugin/Status.java | 4 +
src/main/java/usace/cc/plugin/StoreType.java | 3 +-
26 files changed, 243 insertions(+), 409 deletions(-)
diff --git a/build.gradle b/build.gradle
index b9c404d..4d8e03f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -51,5 +51,5 @@ publishing {
}
group 'mil.army.usace.hec'
- version '0.0.56'
+ version '0.0.50'
}
diff --git a/src/main/java/usace/cc/plugin/AWSConfig.java b/src/main/java/usace/cc/plugin/AWSConfig.java
index df6726d..cde21de 100644
--- a/src/main/java/usace/cc/plugin/AWSConfig.java
+++ b/src/main/java/usace/cc/plugin/AWSConfig.java
@@ -18,9 +18,6 @@ public class AWSConfig {
@JsonProperty
public String aws_bucket;
- @JsonProperty
- public Boolean aws_mock;
-
@JsonProperty
public String aws_endpoint;
diff --git a/src/main/java/usace/cc/plugin/Action.java b/src/main/java/usace/cc/plugin/Action.java
index 567fc5e..6d425be 100644
--- a/src/main/java/usace/cc/plugin/Action.java
+++ b/src/main/java/usace/cc/plugin/Action.java
@@ -2,41 +2,20 @@
import com.fasterxml.jackson.annotation.JsonProperty;
-public class Action {
+public class Action extends IOManager{
@JsonProperty
private String type;
- @JsonProperty
+ @JsonProperty("description")
private String desc;
- @JsonProperty
- private IOManager ioManager;
-
public String getType(){
return type;
}
- public IOManager getIOManager(){
- return ioManager;
- }
+
public String getDescription(){
return desc;
}
- public DataStore[] getStores(){
- return this.ioManager.getStores();
- }
-
- public DataSource[] getInputs() {
- return this.ioManager.getInputs();
- }
-
- public DataSource[] getOutputs(){
- return this.ioManager.getOutputs();
- }
-
- public PayloadAttributes getAttributes(){
- return this.ioManager.getAttributes();
- }
-
}
diff --git a/src/main/java/usace/cc/plugin/CcStore.java b/src/main/java/usace/cc/plugin/CcStore.java
index 0d76bd7..9ef1b25 100644
--- a/src/main/java/usace/cc/plugin/CcStore.java
+++ b/src/main/java/usace/cc/plugin/CcStore.java
@@ -1,11 +1,11 @@
package usace.cc.plugin;
public interface CcStore {
- public boolean PutObject(PutObjectInput input);
- public boolean PullObject(PullObjectInput input);
- public byte[] GetObject(GetObjectInput input) throws Exception;
- public Payload GetPayload() throws Exception;
+ public boolean putObject(PutObjectInput input);
+ public boolean pullObject(PullObjectInput input);
+ public byte[] getObject(GetObjectInput input) throws Exception;
+ public Payload getPayload() throws Exception;
//public void SetPayload(Payload payload); only used in the go sdk to support cloudcompute which is written in go.
- public String RootPath();
- public boolean HandlesDataStoreType(StoreType datastoretype);
+ public String rootPath();
+ public boolean handlesDataStoreType(StoreType datastoretype);
}
diff --git a/src/main/java/usace/cc/plugin/CcStoreS3.java b/src/main/java/usace/cc/plugin/CcStoreS3.java
index 4f124f6..9c42f56 100644
--- a/src/main/java/usace/cc/plugin/CcStoreS3.java
+++ b/src/main/java/usace/cc/plugin/CcStoreS3.java
@@ -34,37 +34,27 @@ public class CcStoreS3 implements CcStore {
String bucket;
String root;
String manifestId;
+ String payloadId;
StoreType storeType;
AmazonS3 awsS3;
AWSConfig config;
- @Override
- public String RootPath() {
- return bucket;
- }
+
public CcStoreS3(){
AWSConfig acfg = new AWSConfig();
acfg.aws_access_key_id = System.getenv(EnvironmentVariables.CC_PROFILE + "_" + EnvironmentVariables.AWS_ACCESS_KEY_ID);
acfg.aws_secret_access_key_id = System.getenv(EnvironmentVariables.CC_PROFILE + "_" + EnvironmentVariables.AWS_SECRET_ACCESS_KEY);
acfg.aws_region = System.getenv(EnvironmentVariables.CC_PROFILE + "_" + EnvironmentVariables.AWS_DEFAULT_REGION);
acfg.aws_bucket = System.getenv(EnvironmentVariables.CC_PROFILE + "_" + EnvironmentVariables.AWS_S3_BUCKET);
- acfg.aws_mock = Boolean.parseBoolean(System.getenv(EnvironmentVariables.CC_PROFILE + "_" +"S3_MOCK"));//convert to boolean;//stringformat
- acfg.aws_endpoint = System.getenv(EnvironmentVariables.CC_PROFILE + "_" +"S3_ENDPOINT");
- acfg.aws_disable_ssl = Boolean.parseBoolean(System.getenv(EnvironmentVariables.CC_PROFILE + "_" +"S3_DISABLE_SSL"));//convert to bool?
- acfg.aws_force_path_style = Boolean.parseBoolean(System.getenv(EnvironmentVariables.CC_PROFILE + "_" +"S3_FORCE_PATH_STYLE"));//convert to bool
+ acfg.aws_endpoint = System.getenv(EnvironmentVariables.CC_PROFILE + "_" +"AWS_ENDPOINT");
config = acfg;
- //System.out.println(EnvironmentVariables.CC_PROFILE + "_" + EnvironmentVariables.AWS_DEFAULT_REGION+"::"+config.aws_region);
- //System.out.println(EnvironmentVariables.CC_PROFILE + "_" + EnvironmentVariables.AWS_ACCESS_KEY_ID+"::"+config.aws_access_key_id);
- //System.out.println(EnvironmentVariables.CC_PROFILE + "_" + EnvironmentVariables.AWS_SECRET_ACCESS_KEY+"::"+config.aws_secret_access_key_id);
- //System.out.println(EnvironmentVariables.CC_PROFILE + "_" + EnvironmentVariables.AWS_S3_BUCKET+"::"+config.aws_bucket);
+
Region clientRegion = RegionUtils.getRegion(config.aws_region);//.toUpperCase().replace("-", "_"));//Regions.valueOf(config.aws_region.toUpperCase().replace("-", "_"));
try {
AmazonS3 s3Client = null;
- if(config.aws_mock){
- System.out.println("mocking s3 with minio");
- //System.out.println(EnvironmentVariables.CC_PROFILE + "_S3_MOCK::"+config.aws_mock);
- //System.out.println(EnvironmentVariables.CC_PROFILE + "_S3_ENDPOINT::"+config.aws_endpoint);
- //System.out.println(EnvironmentVariables.CC_PROFILE + "_S3_DISABLE_SSL::"+config.aws_disable_ssl);
- //System.out.println(EnvironmentVariables.CC_PROFILE + "_S3_FORCE_PATH_STYLE::"+config.aws_force_path_style);
+ if(!config.aws_endpoint.equals("")){
+ System.out.println(String.format("Using alt endpoint: %s",config.aws_endpoint));
+ config.aws_force_path_style=true;
+ config.aws_disable_ssl=true;
AWSCredentials credentials = new BasicAWSCredentials(config.aws_access_key_id, config.aws_secret_access_key_id);
ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setSignerOverride("AWSS3V4SignerType");
@@ -97,20 +87,28 @@ public CcStoreS3(){
}
storeType = StoreType.S3;
manifestId = System.getenv(EnvironmentVariables.CC_MANIFEST_ID);
- localRootPath = Constants.LocalRootPath;
+ payloadId = System.getenv(EnvironmentVariables.CC_PAYLOAD_ID);
+ localRootPath = Constants.LOCAL_ROOT_PATH;
bucket = config.aws_bucket;// + Constants.RemoteRootPath;
root = System.getenv(EnvironmentVariables.CC_ROOT);
}
+
+ @Override
+ public String rootPath() {
+ return bucket;
+ }
+
@Override
- public boolean HandlesDataStoreType(StoreType storeType){
+ public boolean handlesDataStoreType(StoreType storeType){
return this.storeType == storeType;
}
+
@Override
- public boolean PutObject(PutObjectInput input) {
+ public boolean putObject(PutObjectInput input) {
String path = root + "/" + manifestId + "/" + input.getFileName() + "." + input.getFileExtension();
byte[] data;
switch(input.getObjectState()){
- case LocalDisk:
+ case LOCAL_DISK:
//read from local
File file = new File(path);
data = new byte[(int) file.length()];
@@ -120,11 +118,11 @@ public boolean PutObject(PutObjectInput input) {
catch(Exception e){
//@TODOprint?
}
- UploadToS3(config.aws_bucket, path, data);
+ uploadToS3(config.aws_bucket, path, data);
break;
- case Memory:
+ case MEMORY:
data = input.getData();
- UploadToS3(config.aws_bucket, path, data);
+ uploadToS3(config.aws_bucket, path, data);
break;
default:
return false;
@@ -132,14 +130,15 @@ public boolean PutObject(PutObjectInput input) {
return true;
}
+
@Override
- public boolean PullObject(PullObjectInput input) {
+ public boolean pullObject(PullObjectInput input) {
String path = root + "/" + manifestId + "/" + input.getFileName() + "." + input.getFileExtension();
byte[] data;
String localPath = input.getDestRootPath() + "/" + input.getFileName() + "." + input.getFileExtension();
try {
//get the object from s3
- data = DownloadBytesFromS3(path);
+ data = downloadBytesFromS3(path);
//create localpath writer
InputStream stream = new ByteArrayInputStream(data);
//write it.
@@ -149,6 +148,7 @@ public boolean PullObject(PullObjectInput input) {
}
return false;
}
+
private void writeInputStreamToDisk(InputStream input, String outputDestination) throws IOException {
String directory = new File(outputDestination).getParent();
File f = new File(directory);
@@ -162,28 +162,31 @@ private void writeInputStreamToDisk(InputStream input, String outputDestination)
e.printStackTrace();
};
}
+
@Override
- public byte[] GetObject(GetObjectInput input) throws AmazonS3Exception {
- String path = root + "/" + manifestId + "/" + input.getFileName() + "." + input.getFileExtension();
+ public byte[] getObject(GetObjectInput input) throws AmazonS3Exception {
+ String path = root + "/" + payloadId + "/" + input.getFileName() + "." + input.getFileExtension();
byte[] data;
try {
- data = DownloadBytesFromS3(path);
+ data = downloadBytesFromS3(path);
} catch (Exception e) {
throw new AmazonS3Exception(e.toString());
}
return data;
}
+
@Override
- public Payload GetPayload() throws AmazonS3Exception {
- String filepath = root + "/" + manifestId + "/" + Constants.PayloadFileName;
+ public Payload getPayload() throws AmazonS3Exception {
+ String filepath = root + "/" + payloadId + "/" + Constants.PAYLOAD_FILE_NAME;
try{
- byte[] body = DownloadBytesFromS3(filepath);
- return ReadJsonModelPayloadFromBytes(body);
+ byte[] body = downloadBytesFromS3(filepath);
+ return readJsonModelPayloadFromBytes(body);
} catch (Exception e){
throw new AmazonS3Exception(e.toString());
}
}
- private byte[] DownloadBytesFromS3(String key) throws Exception{
+
+ private byte[] downloadBytesFromS3(String key) throws Exception{
S3Object fullObject = null;
boolean spaces = key.contains(" ");
if(spaces){
@@ -208,7 +211,8 @@ private byte[] DownloadBytesFromS3(String key) throws Exception{
}
}
}
- private Payload ReadJsonModelPayloadFromBytes(byte[] bytes) throws Exception {
+
+ private Payload readJsonModelPayloadFromBytes(byte[] bytes) throws Exception {
final ObjectMapper mapper = new ObjectMapper(); // jackson databind
try {
return mapper.readValue(bytes, Payload.class);
@@ -216,7 +220,8 @@ private Payload ReadJsonModelPayloadFromBytes(byte[] bytes) throws Exception {
throw e;
}
}
- private void UploadToS3(String bucketName, String objectKey, byte[] fileBytes) {
+
+ private void uploadToS3(String bucketName, String objectKey, byte[] fileBytes) {
try {
//File file = new File(objectPath);
InputStream stream = new ByteArrayInputStream(fileBytes);
diff --git a/src/main/java/usace/cc/plugin/ConnectionDataStore.java b/src/main/java/usace/cc/plugin/ConnectionDataStore.java
index 6237d03..c6de7b2 100644
--- a/src/main/java/usace/cc/plugin/ConnectionDataStore.java
+++ b/src/main/java/usace/cc/plugin/ConnectionDataStore.java
@@ -1,6 +1,6 @@
package usace.cc.plugin;
public interface ConnectionDataStore {
- public ConnectionDataStore Connect(DataStore ds);
- public Object RawSession();
+ public ConnectionDataStore connect(DataStore ds);
+ public Object rawSession();
}
diff --git a/src/main/java/usace/cc/plugin/Constants.java b/src/main/java/usace/cc/plugin/Constants.java
index 825f3db..3c9610f 100644
--- a/src/main/java/usace/cc/plugin/Constants.java
+++ b/src/main/java/usace/cc/plugin/Constants.java
@@ -1,6 +1,6 @@
package usace.cc.plugin;
public final class Constants {
- public static String PayloadFileName = "payload";
- public static String LocalRootPath = "/data";
+ public static String PAYLOAD_FILE_NAME = "payload";
+ public static String LOCAL_ROOT_PATH = "/data";
}
diff --git a/src/main/java/usace/cc/plugin/DataSource.java b/src/main/java/usace/cc/plugin/DataSource.java
index 57b3fd1..c3afb5e 100644
--- a/src/main/java/usace/cc/plugin/DataSource.java
+++ b/src/main/java/usace/cc/plugin/DataSource.java
@@ -1,5 +1,8 @@
package usace.cc.plugin;
+
+import java.util.Map;
import com.fasterxml.jackson.annotation.JsonProperty;
+
public class DataSource {
@JsonProperty
@@ -8,14 +11,14 @@ public class DataSource {
@JsonProperty
private String id;
- @JsonProperty
+ @JsonProperty("store_name")
private String storeName;
@JsonProperty
- private String[] paths;
+ private Map paths;
- @JsonProperty
- private String[] dataPaths;
+ @JsonProperty("data_paths")
+ private Map dataPaths;
public String getId(){
return id;
@@ -29,45 +32,24 @@ public void setName(String name){
this.name=name;
}
- public String[] getPaths(){
+ public Map getPaths(){
return this.paths;
}
- public void setPaths(String[] paths){
+ public void setPaths(Map paths){
this.paths=paths;
}
- public String[] getDataPaths(){
+ public Map getDataPaths(){
return dataPaths;
}
- public void setDataPaths(String[] datapaths){
+ public void setDataPaths(Map datapaths){
this.dataPaths=datapaths;
}
-
public String getStoreName(){
return storeName;
}
- // public DataSource UpdatePaths()throws Exception{
- // DataSource dest = this;
- // PluginManager pm = PluginManager.getInstance();
- // dest.Name = pm.substitutePath(this.getName());
- // if(this.getPaths()!=null){
- // for(int j=0; j parameters;
+ //private PayloadAttributes parameters;
+
+ @JsonProperty("store_type")
+ private StoreType storeType;
+
+ @JsonProperty("profile")
+ private String dsProfile;
+
+ //@TODO can session be a narrower type or a generic?
+ private Object session;
public String getName(){
- return Name;
+ return name;
}
public String getId(){
- return ID;
+ return id;
}
public StoreType getStoreType(){
- return StoreType;
+ return storeType;
}
public PayloadAttributes getParameters(){
- return Parameters;
+ return new PayloadAttributes(parameters);
}
public String getDsProfile(){
- return DsProfile;
+ return dsProfile;
}
public Object getSession(){
- return Session;
+ return session;
}
public void setSession(Object session){
- this.Session = session;
+ this.session = session;
}
}
\ No newline at end of file
diff --git a/src/main/java/usace/cc/plugin/DataStoreTypeRegistry.java b/src/main/java/usace/cc/plugin/DataStoreTypeRegistry.java
index 9c91abb..19f975c 100644
--- a/src/main/java/usace/cc/plugin/DataStoreTypeRegistry.java
+++ b/src/main/java/usace/cc/plugin/DataStoreTypeRegistry.java
@@ -6,21 +6,25 @@
public final class DataStoreTypeRegistry {
private Map registry;
- private static DataStoreTypeRegistry _instance = null;
- public static DataStoreTypeRegistry getInstance(){
- if (_instance==null){
- _instance = new DataStoreTypeRegistry();
- }
- return _instance;
- }
+ private static DataStoreTypeRegistry instance = null;
+
private DataStoreTypeRegistry(){
registry = new HashMap();
registry.put(StoreType.S3, FileDataStoreS3.class);
}
- public static void Register(StoreType storeType, Object storeInstance){
+
+ public static DataStoreTypeRegistry getInstance(){
+ if (instance==null){
+ instance = new DataStoreTypeRegistry();
+ }
+ return instance;
+ }
+
+ public static void register(StoreType storeType, Object storeInstance){
DataStoreTypeRegistry.getInstance().registry.put(storeType, storeInstance.getClass());
}
- public Object New(StoreType s)throws Exception{
+
+ public Object newStore(StoreType s)throws Exception{
Type type = DataStoreTypeRegistry.getInstance().registry.get(s);
return type.getClass().getDeclaredConstructor().newInstance();
}
diff --git a/src/main/java/usace/cc/plugin/EnvironmentVariables.java b/src/main/java/usace/cc/plugin/EnvironmentVariables.java
index 22e30fa..00d1822 100644
--- a/src/main/java/usace/cc/plugin/EnvironmentVariables.java
+++ b/src/main/java/usace/cc/plugin/EnvironmentVariables.java
@@ -2,6 +2,7 @@
public final class EnvironmentVariables {
public static String CC_MANIFEST_ID = "CC_MANIFEST_ID";
+ public static String CC_PAYLOAD_ID = "CC_PAYLOAD_ID";
//public static String CC_EVENT_NUMBER = "CC_EVENT_NUMBER";
public static String CC_EVENT_IDENTIFIER = "CC_EVENT_IDENTIFIER";
public static String CC_EVENT_ID = "CC_EVENT_ID";
diff --git a/src/main/java/usace/cc/plugin/Error.java b/src/main/java/usace/cc/plugin/Error.java
index 20e0134..d0a2a6c 100644
--- a/src/main/java/usace/cc/plugin/Error.java
+++ b/src/main/java/usace/cc/plugin/Error.java
@@ -15,13 +15,17 @@ enum ErrorLevel {
DISABLED;
public static final EnumSet All_Opts = EnumSet.allOf(ErrorLevel.class);
}
+
@JsonProperty
private String error;
+
@JsonProperty
private ErrorLevel errorlevel;
+
public String getError(){
return error;
}
+
public ErrorLevel getErrorLevel(){
return errorlevel;
}
diff --git a/src/main/java/usace/cc/plugin/FileDataStore.java b/src/main/java/usace/cc/plugin/FileDataStore.java
index 1c66a53..6dc6310 100644
--- a/src/main/java/usace/cc/plugin/FileDataStore.java
+++ b/src/main/java/usace/cc/plugin/FileDataStore.java
@@ -1,9 +1,10 @@
package usace.cc.plugin;
+
import java.io.InputStream;
public interface FileDataStore {
- public Boolean Copy(FileDataStore destStore, String srcPath, String destPath);
+ public Boolean copy(FileDataStore destStore, String srcPath, String destPath);
public InputStream get(String path);
- public Boolean Put(InputStream data, String path);
- public Boolean Delete(String path);
+ public Boolean put(InputStream data, String path);
+ public Boolean delete(String path);
}
\ No newline at end of file
diff --git a/src/main/java/usace/cc/plugin/FileDataStoreS3.java b/src/main/java/usace/cc/plugin/FileDataStoreS3.java
index a8e5a20..a62ff5d 100644
--- a/src/main/java/usace/cc/plugin/FileDataStoreS3.java
+++ b/src/main/java/usace/cc/plugin/FileDataStoreS3.java
@@ -26,7 +26,7 @@
import com.amazonaws.services.s3.model.PutObjectResult;
import com.amazonaws.services.s3.model.S3Object;
-
+//@TODO move all package private vars to class private vars
public class FileDataStoreS3 implements FileDataStore, ConnectionDataStore {
String bucket;
String postFix;
@@ -35,13 +35,15 @@ public class FileDataStoreS3 implements FileDataStore, ConnectionDataStore {
AWSConfig config;
private static String S3ROOT = "root";
+ public FileDataStoreS3(){}
+
@Override
- public Boolean Copy(FileDataStore destStore, String srcPath, String destPath) {
+ public Boolean copy(FileDataStore destStore, String srcPath, String destPath) {
byte[] data;
try {
- data = GetObject(srcPath);
+ data = getObject(srcPath);
ByteArrayInputStream bias = new ByteArrayInputStream(data);
- return destStore.Put(bias, destPath);
+ return destStore.put(bias, destPath);
} catch (RemoteException e) {
e.printStackTrace();
return false;
@@ -65,11 +67,11 @@ public InputStream get(String path) {
}
@Override
- public Boolean Put(InputStream data, String path) {
+ public Boolean put(InputStream data, String path) {
byte[] bytes;
try {
bytes = data.readAllBytes();
- return UploadToS3(config.aws_bucket, postFix + "/" + path, bytes);
+ return uploadToS3(config.aws_bucket, postFix + "/" + path, bytes);
} catch (IOException e) {
e.printStackTrace();
return false;
@@ -78,7 +80,7 @@ public Boolean Put(InputStream data, String path) {
}
@Override
- public Boolean Delete(String path) {
+ public Boolean delete(String path) {
DeleteObjectRequest dor = new DeleteObjectRequest(config.aws_bucket,postFix + "/" + path);
try{
awsS3.deleteObject(dor);
@@ -93,15 +95,13 @@ public Boolean Delete(String path) {
}
}
- public FileDataStoreS3(){}
-
@Override
- public Object RawSession(){
+ public Object rawSession(){
return awsS3;
}
@Override
- public ConnectionDataStore Connect(DataStore ds) {
+ public ConnectionDataStore connect(DataStore ds) {
config = new AWSConfig();
config.aws_access_key_id = System.getenv(ds.getDsProfile() + "_" + EnvironmentVariables.AWS_ACCESS_KEY_ID);
config.aws_secret_access_key_id = System.getenv(ds.getDsProfile() + "_" + EnvironmentVariables.AWS_SECRET_ACCESS_KEY);
@@ -139,9 +139,11 @@ public ConnectionDataStore Connect(DataStore ds) {
e.printStackTrace();
throw new RuntimeException(e);
}
+
storeType = StoreType.S3;
String tmpRoot="";
+
try {
Optional optParam = ds.getParameters().get(FileDataStoreS3.S3ROOT);
if (optParam.isPresent()){
@@ -161,17 +163,17 @@ public ConnectionDataStore Connect(DataStore ds) {
return this;
}
- private byte[] GetObject(String path) throws RemoteException {
+ private byte[] getObject(String path) throws RemoteException {
byte[] data;
try {
- data = DownloadBytesFromS3(path);
+ data = downloadBytesFromS3(path);
} catch (Exception e) {
throw new RemoteException(e.toString());
}
return data;
}
- private byte[] DownloadBytesFromS3(String key) throws Exception{
+ private byte[] downloadBytesFromS3(String key) throws Exception{
S3Object fullObject = null;
key = postFix + "/" + key;
System.out.println(key);
@@ -194,7 +196,7 @@ private byte[] DownloadBytesFromS3(String key) throws Exception{
}
}
- private boolean UploadToS3(String bucketName, String objectKey, byte[] fileBytes) {
+ private boolean uploadToS3(String bucketName, String objectKey, byte[] fileBytes) {
try {
InputStream stream = new ByteArrayInputStream(fileBytes);
ObjectMetadata meta = new ObjectMetadata();
diff --git a/src/main/java/usace/cc/plugin/GetObjectInput.java b/src/main/java/usace/cc/plugin/GetObjectInput.java
index fb6c513..95ef467 100644
--- a/src/main/java/usace/cc/plugin/GetObjectInput.java
+++ b/src/main/java/usace/cc/plugin/GetObjectInput.java
@@ -5,25 +5,28 @@ public class GetObjectInput {
private String fileExtension;
private StoreType sourceStoreType;
private String sourceRootPath;
+
+ public GetObjectInput(String fileName, StoreType sourceStoreType, String sourceRootPath, String fileExtension){
+ this.fileName = fileName;
+ this.sourceStoreType = sourceStoreType;
+ this.sourceRootPath = sourceRootPath;
+ this.fileExtension = fileExtension;
+ }
+
public String getFileName(){
return fileName;
}
+
public String getFileExtension(){
return fileExtension;
}
+
public StoreType getSourceStoreType(){
return sourceStoreType;
}
+
public String getSourceRootPath(){
return sourceRootPath;
}
- /**
- *
- */
- public GetObjectInput(String fileName, StoreType sourceStoreType, String sourceRootPath, String fileExtension){
- this.fileName = fileName;
- this.sourceStoreType = sourceStoreType;
- this.sourceRootPath = sourceRootPath;
- this.fileExtension = fileExtension;
- }
+
}
\ No newline at end of file
diff --git a/src/main/java/usace/cc/plugin/IOManager.java b/src/main/java/usace/cc/plugin/IOManager.java
index 9e18a62..258854c 100644
--- a/src/main/java/usace/cc/plugin/IOManager.java
+++ b/src/main/java/usace/cc/plugin/IOManager.java
@@ -1,6 +1,7 @@
package usace.cc.plugin;
import java.util.Arrays;
+import java.util.Map;
import java.util.Optional;
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -10,6 +11,8 @@
import java.io.InputStream;
import java.io.OutputStream;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
public class IOManager {
@@ -36,21 +39,26 @@ public InvalidDataStoreException(Exception ex){
}
@JsonProperty
- private PayloadAttributes attributes;
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ private Map attributes;
+ //private PayloadAttributes attributes;
@JsonProperty
+ @JsonIgnoreProperties(ignoreUnknown = true)
private DataStore[] stores;
@JsonProperty
+ @JsonIgnoreProperties(ignoreUnknown = true)
private DataSource[] inputs;
@JsonProperty
+ @JsonIgnoreProperties(ignoreUnknown = true)
private DataSource[] outputs;
private IOManager parent;
public PayloadAttributes getAttributes(){
- return attributes;
+ return new PayloadAttributes(attributes);
}
public DataStore[] getStores(){
@@ -264,7 +272,7 @@ public void put(byte[] data, String dataSourceName, String pathName, String data
if (fdsOpt.isPresent()){
var fds = fdsOpt.get();
ByteArrayInputStream bais = new ByteArrayInputStream(data);
- fds.Put(bais, pathName);
+ fds.put(bais, pathName);
} else {
throw new InvalidDataStoreException("Datastore not found");
}
@@ -323,7 +331,7 @@ public void copyFileToRemote(String destinationName, String pathKey, String loca
var fdstore = fdsOpt.get();
File localFile = new File(localPath);
InputStream reader = new FileInputStream(localFile);
- fdstore.Put(reader, pathKey);
+ fdstore.put(reader, pathKey);
}
}
}
diff --git a/src/main/java/usace/cc/plugin/Logger.java b/src/main/java/usace/cc/plugin/Logger.java
index a8a13c6..6dc6e14 100644
--- a/src/main/java/usace/cc/plugin/Logger.java
+++ b/src/main/java/usace/cc/plugin/Logger.java
@@ -1,33 +1,35 @@
package usace.cc.plugin;
import java.time.LocalDate;
-
import usace.cc.plugin.Error.ErrorLevel;
public class Logger {
//this is an aggregator, it is anticipated that this will get replaced but the api will remain.
private ErrorLevel errorLevel;
private String sender;
+
public Logger(String sender, ErrorLevel level){
this.sender = sender;
this.errorLevel = level;
}
+
public void setErrorLevel(ErrorLevel level){
this.errorLevel = level;
}
- public void LogMessage(Message message){
+
+ public void logMessage(Message message){
String line = this.sender + ":" + LocalDate.now() + "\n\t" + message.getMessage() + "\n";
System.out.println(line);
}
- public void LogError(Error error){
+
+ public void logError(Error error){
if (error.getErrorLevel().compareTo(this.errorLevel)>=0){
String line = sender + "issues a " + error.getErrorLevel().toString() + " error:" + LocalDate.now() + "\n\t" + error.getError() + "\n";
System.out.println(line);
- }
-
-
+ }
}
- public void ReportStatus(Status report){
+
+ public void reportStatus(Status report){
String line = this.sender + ":" + report.getStatus().toString() + ":" + LocalDate.now() + "\n\t" + report.getProgress() + " percent complete." + "\n";
System.out.println(line);
}
diff --git a/src/main/java/usace/cc/plugin/ObjectState.java b/src/main/java/usace/cc/plugin/ObjectState.java
index 89a170b..041ea69 100644
--- a/src/main/java/usace/cc/plugin/ObjectState.java
+++ b/src/main/java/usace/cc/plugin/ObjectState.java
@@ -1,7 +1,7 @@
package usace.cc.plugin;
public enum ObjectState {
- Memory,
- LocalDisk,
+ MEMORY,
+ LOCAL_DISK,
//RemoteDisk //ToDo
}
diff --git a/src/main/java/usace/cc/plugin/Payload.java b/src/main/java/usace/cc/plugin/Payload.java
index 4ce7e11..83c5049 100644
--- a/src/main/java/usace/cc/plugin/Payload.java
+++ b/src/main/java/usace/cc/plugin/Payload.java
@@ -1,42 +1,15 @@
package usace.cc.plugin;
import com.fasterxml.jackson.annotation.JsonProperty;
-public class Payload {
-
- @JsonProperty
- private IOManager ioManager;
+public class Payload extends IOManager{
+
@JsonProperty
private Action[] actions;
- public IOManager getIOManager(){
- return ioManager;
- }
-
public Action[] getActions(){
return actions;
}
- public void setIOManager(IOManager inIOManager){
- ioManager = inIOManager;
- }
-
- public DataStore[] getStores(){
- return this.ioManager.getStores();
- }
-
- public PayloadAttributes getAttributes(){
- return this.ioManager.getAttributes();
- }
-
- public DataSource[] getInputs(){
- return this.ioManager.getInputs();
- }
-
- public DataSource[] getOutputs(){
- return this.ioManager.getOutputs();
- }
-
-
}
diff --git a/src/main/java/usace/cc/plugin/PayloadAttributes.java b/src/main/java/usace/cc/plugin/PayloadAttributes.java
index 8d91fa3..65c97ec 100644
--- a/src/main/java/usace/cc/plugin/PayloadAttributes.java
+++ b/src/main/java/usace/cc/plugin/PayloadAttributes.java
@@ -7,6 +7,10 @@
public class PayloadAttributes {
+ public PayloadAttributes(Map attrs){
+ this.attributes=attrs;
+ }
+
@JsonProperty
private Map attributes;
@@ -41,102 +45,4 @@ public Optional getAlt1(String name, Class clazz) throws IllegalArgumentE
throw new IllegalArgumentException("Incorrect type");
}
}
-
- /*
- public int getInt(String name) throws Exception{
- Object val = attributes.get(name);
- if (val==null){
- throw new Exception(name + " not found");
- }else{
- if(val instanceof Number){
- return ((Number)val).intValue();
- }else{
- return Integer.parseInt(val.toString());
- }
- }
- }
-
- public int getIntOrDefault(String name, int defaultValue){
- try{
- int value = getInt(name);
- return value;
- }catch(Exception ex){
- System.out.println(ex.getMessage());
- return defaultValue;
- }
- }
-
- public long getInt64(String name) throws Exception{
- Object val = attributes.get(name);
- if (val==null){
- throw new Exception(name + " not found");
- }else{
- if(val instanceof Number){
- return ((Number)val).longValue();
- }else{
- return Long.parseLong(val.toString());
- }
- }
- }
-
- public long getInt64OrDefault(String name, long defaultValue){
- try{
- long value = getInt64(name);
- return value;
- }catch(Exception ex){
- System.out.println(ex.getMessage());
- return defaultValue;
- }
- }
-
- public double getDouble(String name) throws Exception{
- Object val = attributes.get(name);
- if (val==null){
- throw new Exception(name + " not found");
- }else{
- if(val instanceof Number){
- return ((Number)val).doubleValue();
- }else{
- return Double.parseDouble(val.toString());
- }
- }
- }
- public double getDoubleOrDefault(String name, double defaultValue){
- try{
- double value = getDouble(name);
- return value;
- }catch(Exception ex){
- System.out.println(ex.getMessage());
- return defaultValue;
- }
- }
- public String getString(String name) throws Exception{
- Object val = attributes.get(name);
- if (val==null){
- throw new Exception(name + " not found");
- }else{
- return String.valueOf(val);
- }
- }
- public String getStringOrDefault(String name, String defaultValue){
- try{
- String value = getString(name);
- return value;
- }catch(Exception ex){
- System.out.println(ex.getMessage());
- return defaultValue;
- }
- }
- public void UpdatePayloadAttributes()throws Exception{
- PluginManager pm = PluginManager.getInstance();
- for(Map.Entry me : attributes.entrySet()){
- Object val = me.getValue();
- if(val instanceof String){
- String strval = String.valueOf(val);
- strval = pm.substitutePath(strval);
- attributes.replace(me.getKey(),strval);
- }//TODO: what if it is an array of string?
- }
- }
- */
}
\ No newline at end of file
diff --git a/src/main/java/usace/cc/plugin/PluginManager.java b/src/main/java/usace/cc/plugin/PluginManager.java
index 8ec5c71..4f15db5 100644
--- a/src/main/java/usace/cc/plugin/PluginManager.java
+++ b/src/main/java/usace/cc/plugin/PluginManager.java
@@ -35,7 +35,7 @@ private PluginManager(){
logger = new Logger(sender, ErrorLevel.WARN);
cs = new CcStoreS3();
try {
- this.payload = cs.GetPayload();
+ this.payload = cs.getPayload();
this.connectStores(payload.getStores());
for (Action action : payload.getActions()) {
this.connectStores(action.getStores());
@@ -49,15 +49,16 @@ private PluginManager(){
public Payload getPayload(){
- if (!hasUpdatedPaths){
- try{
- substitutePathVariables();
- }catch(Exception e){
- e.printStackTrace();
- System.exit(1);
- }
- hasUpdatedPaths = true;
- }
+ //@TODO why substitute here?
+ // if (!hasUpdatedPaths){
+ // try{
+ // substitutePathVariables();
+ // }catch(Exception e){
+ // e.printStackTrace();
+ // System.exit(1);
+ // }
+ // hasUpdatedPaths = true;
+ // }
return payload;
}
@@ -70,25 +71,25 @@ public void setLogLevel(ErrorLevel level){
}
public void logMessage(Message message){
- logger.LogMessage(message);
+ logger.logMessage(message);
}
public void logError(Error error){
- logger.LogError(error);
+ logger.logError(error);
}
public void reportProgress(Status report){
- logger.ReportStatus(report);
+ logger.reportStatus(report);
}
private void connectStores(DataStore[] stores) throws Exception{
DataStoreTypeRegistry registry = DataStoreTypeRegistry.getInstance();
for (int i = 0; i entry : attrs.entrySet()) {
- var key = entry.getKey();
+ //var key = entry.getKey();
var val = entry.getValue();
if (val instanceof String){
parameterSubstitute((String)val, pattrs);
@@ -136,14 +137,14 @@ private void substitutePaths(DataSource ds, PayloadAttributes attrs){
ds.setName(param);
var paths = ds.getPaths();
- for (int i=0;i
Date: Wed, 30 Apr 2025 09:28:35 -0400
Subject: [PATCH 5/6] switched to unchecked exceptions in DataSource. Add
entryset to PayloadAttributes
---
build.gradle | 2 +-
src/main/java/usace/cc/plugin/IOManager.java | 6 +++---
src/main/java/usace/cc/plugin/PayloadAttributes.java | 10 ++++++++++
3 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/build.gradle b/build.gradle
index 4d8e03f..51a21e7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -51,5 +51,5 @@ publishing {
}
group 'mil.army.usace.hec'
- version '0.0.50'
+ version '0.0.59'
}
diff --git a/src/main/java/usace/cc/plugin/IOManager.java b/src/main/java/usace/cc/plugin/IOManager.java
index 258854c..889ec74 100644
--- a/src/main/java/usace/cc/plugin/IOManager.java
+++ b/src/main/java/usace/cc/plugin/IOManager.java
@@ -18,7 +18,7 @@
public class IOManager {
//IO Manager Error Types
- static class InvalidDataSourceException extends Exception {
+ static class InvalidDataSourceException extends RuntimeException {
public InvalidDataSourceException(String message) {
super(message);
}
@@ -115,7 +115,7 @@ public Optional getStore(String name){
* @param gdsi an object encapsulating the data source name and the I/O type to search
* @return an {@code Optional} containing the matching {@code DataSource}, or {@code Optional.empty()}
* if no such data source exists in this instance or its parent chain
- * @throws InvalidDataSourceException if the {@code DataSourceIOType} in the input is not recognized
+ * @throws InvalidDataSourceException runtime exception if the {@code DataSourceIOType} in the input is not recognized
*/
public Optional getDataSource(GetDataSourceInput gdsi) throws InvalidDataSourceException{
DataSource[] sources;
@@ -131,7 +131,7 @@ public Optional getDataSource(GetDataSourceInput gdsi) throws Invali
System.arraycopy(this.outputs, 0, sources, this.inputs.length, this.outputs.length);
break;
default:
- throw new InvalidDataSourceException("datan source input type not recognized");
+ throw new InvalidDataSourceException("data source input type not recognized");
}
for(DataSource ds : sources){
diff --git a/src/main/java/usace/cc/plugin/PayloadAttributes.java b/src/main/java/usace/cc/plugin/PayloadAttributes.java
index 65c97ec..d59df71 100644
--- a/src/main/java/usace/cc/plugin/PayloadAttributes.java
+++ b/src/main/java/usace/cc/plugin/PayloadAttributes.java
@@ -1,7 +1,9 @@
package usace.cc.plugin;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Optional;
+import java.util.Set;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -18,6 +20,14 @@ public Map getAttributes(){
return attributes;
}
+ public Set> entrySet(){
+ return attributes.entrySet();
+ }
+
+ public Set keySet(){
+ return attributes.keySet();
+ }
+
public Optional get(String name) throws IllegalArgumentException{
Object val = attributes.get(name);
if (val==null){
From f1783d6a8adf61437df59aa95c56e33e6d987897 Mon Sep 17 00:00:00 2001
From: Will Lehman
Date: Wed, 30 Apr 2025 09:13:50 -0500
Subject: [PATCH 6/6] Update CI.yml
upgrade to java 17
---
.github/workflows/CI.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index 40bd49b..ad0e2c8 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -23,10 +23,10 @@ jobs:
steps:
- uses: actions/checkout@v3
- - name: Set up JDK 11
+ - name: Set up JDK 17
uses: actions/setup-java@v3
with:
- java-version: '11'
+ java-version: '17'
distribution: 'temurin'
- name: Validate Gradle wrapper