How to work with Amazon S3?

Hi Guys,

I am trying to store files to S3 by creating a module, by following SDK example ignition-sdk-examples/scripting-function at master · inductiveautomation/ignition-sdk-examples · GitHub I can use all scripts in designer.
It shows error below:
software.amazon.awssdk.core.exception.SdkClientException: Unable to load an HTTP implementation from any provider in the chain. You must declare a dependency on an appropriate HTTP implementation or pass in an SdkHttpClient explicitly to the client builder.

How can I work with S3 properly?
Java code in script common project

package com.inductiveautomation.ignition.examples.scripting;

import java.util.ArrayList;
import java.util.List;

import com.inductiveautomation.ignition.common.BundleUtil;
import com.inductiveautomation.ignition.common.script.hints.ScriptArg;
import com.inductiveautomation.ignition.common.script.hints.ScriptFunction;

import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.ListBucketsResponse;

import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;

public abstract class AbstractScriptModule implements MathBlackBox {

static {
    BundleUtil.get().addBundle(
        AbstractScriptModule.class.getSimpleName(),
        AbstractScriptModule.class.getClassLoader(),
        AbstractScriptModule.class.getName().replace('.', '/')
    );
}

@Override
@ScriptFunction(docBundlePrefix = "AbstractScriptModule")
public int multiply2(
    @ScriptArg("arg0") int arg0,
    @ScriptArg("arg1") int arg1) {

    return multiplyImpl(arg0, arg1);
}

protected abstract int multiplyImpl(int arg0, int arg1);


@ScriptFunction(docBundlePrefix = "AbstractScriptModule")
public String helloWorld(){
    return "Hi there!";
}

@ScriptFunction(docBundlePrefix = "AbstractScriptModule")

public List GetBuckets() {

String ACCESS_KEY = "AKIA6FIM....FPSN";
String SECRET_KEY = "QlliRmIATzF/ESX9.....bj9754ZbcL";
String BUCKET_NAME = "files";
S3Client s3Client = S3Client.builder().region(Region.CA_CENTRAL_1).credentialsProvider(StaticCredentialsProvider
.create(AwsSessionCredentials.create(ACCESS_KEY, SECRET_KEY, ""))).build();
ListBucketsResponse listBucketsResponse = s3Client.listBuckets();

List res = new ArrayList();
listBucketsResponse.buckets().stream().forEach(x -> res.add(x.name()));

return res;
}

}

Any ideas would be appreciated!

Hmm, it's issue of AWS.

S3Client s3Client = S3Client.builder().region(Region.CA_CENTRAL_1)
			.credentialsProvider(StaticCredentialsProvider.create(AwsSessionCredentials.create(ACCESS_KEY, SECRET_KEY, "")))
			.httpClient(UrlConnectionHttpClient.builder().build())
            .build();

Why following code is working on script console but not script panel when we bind to text?
import software.amazon.awssdk.regions.Region as Region;

What do you mean by this? Can we get an example?

Is there an exception message we can look at?

Error message is no module "software"

In the gateway, modules are installed into isolated classloaders--the contents are not exposed to the gateway as a whole. It works in the designer script console "by accident" because the designer (and vision clients) does not use more than one classloader.

To expose classes in the gateway, you must initialize script functions in script managers using the proper gateway hook.

1 Like

Got it! It made things more tougher. :joy:

1 Like

You can short-cut the process by exposing classes in fields instead of writing wrapper functions. In the class you register with the script manager, have lines like this:

public static final Class<?> AwsBasicCredentials = AwsBasicCredentials.class;
public static final Class<?> AwsCredentials = AwsCredentials.class;
public static final Class<?> S3Client = S3Client.class;
public static final Class<?> ListBucketsResponse = ListBucketsResponse.class;

If you register that as system.amazon, then your jython scripts can do this:

from system.amazon import AwsBasicCredentials, AwsCredentials, S3Client, ListBucketsResponse

:grin:

1 Like