Skip to content

Commit

Permalink
added support for azure blob store as file storage
Browse files Browse the repository at this point in the history
  • Loading branch information
mswiderski committed Jan 2, 2024
1 parent 0ef0294 commit 2efbf02
Show file tree
Hide file tree
Showing 17 changed files with 642 additions and 3 deletions.
65 changes: 65 additions & 0 deletions addons/files/automatiko-files-azure-blob-addon/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.automatiko</groupId>
<artifactId>files</artifactId>
<version>0.0.0-SNAPSHOT</version>
</parent>

<groupId>io.automatiko.addons</groupId>
<artifactId>automatiko-files-azure-blob-addon</artifactId>
<name>Automatiko Engine :: Add-Ons :: Files :: Azure BlobStore</name>
<description>Files based on Azure BlobStore AddOn for Automatiko Engine</description>

<properties>
<java.module.name>io.automatiko.addons.files.azureblob</java.module.name>
</properties>

<dependencies>
<dependency>
<groupId>io.automatiko.engine</groupId>
<artifactId>automatiko-engine-api</artifactId>
</dependency>
<dependency>
<groupId>io.automatiko.workflow</groupId>
<artifactId>automatiko-workflow-core</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile.openapi</groupId>
<artifactId>microprofile-openapi-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>

<dependency>
<groupId>io.quarkiverse.azureservices</groupId>
<artifactId>quarkus-azure-storage-blob</artifactId>
<version>1.0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package io.automatiko.addon.files.s3;

import java.util.Map;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;

import io.automatiko.engine.workflow.file.ByteArrayFile;
import io.quarkus.arc.Arc;

@JsonAutoDetect(fieldVisibility = Visibility.PUBLIC_ONLY)
public class AzureBlobStoreFile extends ByteArrayFile {

private String url;

public AzureBlobStoreFile(String name, byte[] content) {
super(name, content);
}

@JsonCreator
public AzureBlobStoreFile(@JsonProperty("name") String name, @JsonProperty("content") byte[] content,
@JsonProperty("attributes") Map<String, String> attributes) {
super(name, content, attributes);
}

@JsonGetter
public String name() {
return name;
}

public byte[] content() {
if (content == null) {
AzureBlobStoreStore store = Arc.container().instance(AzureBlobStoreStore.class).orElse(null);
if (store != null) {
content = store.content(url());
}
}

return content;
}

@Override
@JsonGetter
public Map<String, String> attributes() {
return attributes;
}

@Override
@JsonGetter
public String url() {
return url;
}

@JsonSetter
public void url(String url) {
this.url = url;
}

@Override
public String toString() {
return "AzureBlob [name=" + name + ", content (url)=" + url + ", attributes=" + attributes + "]";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package io.automatiko.addon.files.s3;

import java.util.ArrayList;
import java.util.Collection;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import io.automatiko.engine.api.workflow.Variable;
import io.automatiko.engine.api.workflow.VariableAugmentor;
import io.automatiko.engine.api.workflow.files.HasFiles;
import io.automatiko.engine.workflow.file.ByteArrayFile;

@ApplicationScoped
public class AzureBlobStoreFileVariableAugmentor implements VariableAugmentor {

private String serviceUrl;

private AzureBlobStoreStore store;

@Inject
public AzureBlobStoreFileVariableAugmentor(AzureBlobStoreStore store) {
this.store = store;
this.serviceUrl = store.urlPrefix();
}

@Override
public boolean accept(Variable variable, Object value) {
if (value == null) {
// check variable definition
if (variable.getType().getClassType() != null) {
return ByteArrayFile.class.isAssignableFrom(variable.getType().getClassType());
}
return false;
}

if (value instanceof HasFiles) {
value = ((HasFiles<?>) value).files();
}

if (value instanceof ByteArrayFile) {
return true;
}

if (value instanceof Collection) {
return ((Collection<?>) value).stream().anyMatch(item -> item instanceof ByteArrayFile);
}
return false;
}

@Override
public Object augmentOnCreate(String processId, String processVersion, String processInstanceId, Variable variable,
Object value) {
Object originalValue = value;
value = retrieveValue(value);
if (value == null) {
return value;
}
StringBuilder url = new StringBuilder(serviceUrl);
url.append(processId).append("/");
if (processVersion != null && !processVersion.isEmpty()) {
url.append(processVersion).append("/");
}
url.append(processInstanceId).append("/").append(variable.getName());

if (value instanceof ByteArrayFile) {
ByteArrayFile file = (ByteArrayFile) value;
if (file.content() != null) {
AzureBlobStoreFile fsFile = new AzureBlobStoreFile(file.name(), null, file.attributes());
fsFile.url(url.toString() + "/" + file.name());

// store file on file system
store.save(file, processId, processVersion, processInstanceId, variable.getName(),
file.name());
value = updateValue(originalValue, fsFile);
}
} else if (value instanceof Collection) {
Collection<ByteArrayFile> fsFiles = new ArrayList<>();
for (Object potentialFile : (Collection<?>) value) {
if (potentialFile instanceof ByteArrayFile) {
ByteArrayFile file = (ByteArrayFile) potentialFile;
if (file.content() != null) {
AzureBlobStoreFile fsFile = new AzureBlobStoreFile(file.name(), null, file.attributes());
fsFile.url(url.toString() + "/" + file.name());

// store file on file system
store.save(file, processId, processVersion, processInstanceId, variable.getName(),
file.name());
fsFiles.add(fsFile);
} else {
fsFiles.add(file);
}
}
}
return updateValue(originalValue, fsFiles);
}

return value;
}

@Override
public Object augmentOnUpdate(String processId, String processVersion, String processInstanceId, Variable variable,
Object value) {
Object originalValue = value;
value = retrieveValue(value);
if (value == null) {
return value;
}
StringBuilder url = new StringBuilder(serviceUrl);
url.append(processId).append("/");
if (processVersion != null && !processVersion.isEmpty()) {
url.append(processVersion).append("/");
}
url.append(processInstanceId).append("/").append(variable.getName());

if (value instanceof ByteArrayFile) {
ByteArrayFile file = (ByteArrayFile) value;
if (file.content() != null) {
AzureBlobStoreFile fsFile = new AzureBlobStoreFile(file.name(), null, file.attributes());
fsFile.url(url.toString() + "/" + file.name());

// replace file on file system
store.replace(file, processId, processVersion, processInstanceId, variable.getName(),
file.name());
value = updateValue(originalValue, fsFile);
}
} else if (value instanceof Collection) {
Collection<ByteArrayFile> fsFiles = new ArrayList<>();
for (Object potentialFile : (Collection<?>) value) {
if (potentialFile instanceof ByteArrayFile) {
ByteArrayFile file = (ByteArrayFile) potentialFile;
if (file.content() != null) {
AzureBlobStoreFile fsFile = new AzureBlobStoreFile(file.name(), null, file.attributes());
fsFile.url(url.toString() + "/" + file.name());

// replace file on file system
store.replace(file, processId, processVersion, processInstanceId, variable.getName(),
file.name());
fsFiles.add(fsFile);
} else {
fsFiles.add(file);
}
}
}
return updateValue(originalValue, fsFiles);
}

return value;
}

@Override
public void augmentOnDelete(String processId, String processVersion, String processInstanceId, Variable variable,
Object value) {
value = retrieveValue(value);
if (value instanceof ByteArrayFile) {
ByteArrayFile file = (ByteArrayFile) value;
store.remove(processId, processVersion, processInstanceId, variable.getName(), file.name());
} else if (value instanceof Collection) {
for (Object potentialFile : (Collection<?>) value) {
if (potentialFile instanceof ByteArrayFile) {
ByteArrayFile file = (ByteArrayFile) potentialFile;
store.remove(processId, processVersion, processInstanceId, variable.getName(), file.name());
}
}

}

}

protected Object retrieveValue(Object value) {
if (value instanceof HasFiles) {
return ((HasFiles<?>) value).files();
}

return value;
}

@SuppressWarnings({ "unchecked", "rawtypes" })
protected Object updateValue(Object variable, Object value) {
if (variable instanceof HasFiles) {
((HasFiles) variable).augmentFiles(value);

return variable;
}

return value;
}

}
Loading

0 comments on commit 2efbf02

Please sign in to comment.