Using the AmazonS3InputDataHandler with Groupdocs.Annotation v1.9.0 I’ve run into issues. After making a request and viewing 4 or 5 documents, I will eventually get the following exception.
[error] c.g.a.h.AnnotationHandler - Annotation throws exception: Unable to execute HTTP request: Timeout waiting for connection from pool
com.groupdocs.annotation.exception.AnnotationException: Unable to execute HTTP request: Timeout waiting for connection from pool
at com.groupdocs.annotation.api.shared.CommonApi.viewDocument(CommonApi.java:368)
at com.groupdocs.annotation.api.shared.WebApi.viewDocumentHandler(WebApi.java:307)
at com.groupdocs.annotation.handler.AnnotationHandler.viewDocumentHandler(AnnotationHandler.java:128)
at groupdocs.ClientViewer$.viewDocument(ClientViewer.scala:20)
I ran across this post in the AWS forums along with others that have similar issues.
It looks as though the S3Object may not be getting closed properly.
I know from another project of ours in which we use the Amazon S3 client in Scala, we create a new AmazonS3Client for each method call we make. I noticed in the AmazonS3InputDataHandler that the S3Client is a private final class variable.
public class AmazonS3InputDataHandler extends InputDataHandler {
private final AmazonS3 s3;
private final String bucketName;
private final String uploadPath;
public AmazonS3InputDataHandler(String accessKey, String secretKey, String bucketName) {
this(accessKey, secretKey, bucketName, (String)null);
}
public AmazonS3InputDataHandler(String accessKey, String secretKey, String bucketName, String uploadPath) {
BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
this.s3 = new AmazonS3Client(credentials);
this.bucketName = bucketName;
if(uploadPath == null) {
this.uploadPath = “”;
} else {
if(!uploadPath.endsWith(“/”)) {
uploadPath = uploadPath + “/”;
}
this.uploadPath = uploadPath;
}
}
As a work around I created a new class, AwsS3InputDataHandler, in which I moved the S3Client from a class level variable into a local method variable. This seems to resolve the issue. See the code example below.
public class AwsS3InputDataHandler extends InputDataHandler {
private final BasicAWSCredentials credentials;
private final String bucketName;
private final String uploadPath;
public AwsS3InputDataHandler(String accessKey, String secretKey, String bucketName) {
this(accessKey, secretKey, bucketName, (String)null);
}
public AwsS3InputDataHandler(String accessKey, String secretKey, String bucketName, String uploadPath) {
credentials = new BasicAWSCredentials(accessKey, secretKey);
this.bucketName = bucketName;
if(uploadPath == null) {
this.uploadPath = “”;
} else {
if(!uploadPath.endsWith(“/”)) {
uploadPath = uploadPath + “/”;
}
this.uploadPath = uploadPath;
}
}…
public InputStream getFile(String guid) {
AmazonS3 s3 = new AmazonS3Client(credentials);
String decodedGuid = d.a(guid);
S3Object object = s3.getObject(new GetObjectRequest(this.bucketName, decodedGuid));
S3ObjectInputStream content = object.getObjectContent();
return content;
}…
In order to resolve this issue I think it would require tracking down where the S3Object is being referenced and then not being closed, but for the time being moving the S3Client to a method level variable seems to be a reasonable work around.