org.apache.camel.component.aws2.s3.AWS2S3Consumer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of camel-aws2-s3 Show documentation
Show all versions of camel-aws2-s3 Show documentation
A Camel Amazon S3 Web Service Component Version 2
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.aws2.s3;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Queue;
import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.ExchangePropertyKey;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.spi.Synchronization;
import org.apache.camel.support.ScheduledBatchPollingConsumer;
import org.apache.camel.support.SynchronizationAdapter;
import org.apache.camel.util.CastUtils;
import org.apache.camel.util.IOHelper;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.URISupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.awscore.exception.AwsServiceException;
import software.amazon.awssdk.core.ResponseInputStream;
import software.amazon.awssdk.core.sync.ResponseTransformer;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.CopyObjectRequest;
import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.GetObjectRequest.Builder;
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
import software.amazon.awssdk.services.s3.model.HeadObjectRequest;
import software.amazon.awssdk.services.s3.model.ListObjectsRequest;
import software.amazon.awssdk.services.s3.model.ListObjectsResponse;
import software.amazon.awssdk.services.s3.model.NoSuchKeyException;
import software.amazon.awssdk.services.s3.model.S3Object;
import software.amazon.awssdk.utils.IoUtils;
/**
* A Consumer of messages from the Amazon Web Service Simple Storage Service AWS
* S3
*/
public class AWS2S3Consumer extends ScheduledBatchPollingConsumer {
private static final Logger LOG = LoggerFactory.getLogger(AWS2S3Consumer.class);
private String marker;
private transient String s3ConsumerToString;
public AWS2S3Consumer(AWS2S3Endpoint endpoint, Processor processor) {
super(endpoint, processor);
}
@Override
protected void doStart() throws Exception {
super.doStart();
if (getConfiguration().isMoveAfterRead()) {
try {
getAmazonS3Client()
.headBucket(HeadBucketRequest.builder().bucket(getConfiguration().getDestinationBucket()).build());
LOG.trace("Bucket [{}] already exists", getConfiguration().getDestinationBucket());
return;
} catch (AwsServiceException ase) {
/* 404 means the bucket doesn't exist */
if (ase.awsErrorDetails().sdkHttpResponse().statusCode() != 404) {
throw ase;
}
}
LOG.trace("Destination Bucket [{}] doesn't exist yet", getConfiguration().getDestinationBucket());
if (getConfiguration().isAutoCreateBucket()) {
// creates the new bucket because it doesn't exist yet
CreateBucketRequest createBucketRequest
= CreateBucketRequest.builder().bucket(getConfiguration().getDestinationBucket()).build();
LOG.trace("Creating Destination bucket [{}] in region [{}] with request [{}]...",
getConfiguration().getDestinationBucket(), getConfiguration().getRegion(),
createBucketRequest);
getAmazonS3Client().createBucket(createBucketRequest);
LOG.trace("Destination Bucket created");
}
}
}
@Override
protected int poll() throws Exception {
// must reset for each poll
shutdownRunningTask = null;
pendingExchanges = 0;
String fileName = getConfiguration().getFileName();
String bucketName = getConfiguration().getBucketName();
String doneFileName = getConfiguration().getDoneFileName();
Queue exchanges;
if (!doneFileCheckPasses(bucketName, doneFileName)) {
exchanges = new LinkedList<>();
} else if (fileName != null) {
LOG.trace("Getting object in bucket [{}] with file name [{}]...", bucketName, fileName);
ResponseInputStream s3Object
= getAmazonS3Client().getObject(GetObjectRequest.builder().bucket(bucketName).key(fileName).build());
exchanges = createExchanges(s3Object, fileName);
} else {
LOG.trace("Queueing objects in bucket [{}]...", bucketName);
ListObjectsRequest.Builder listObjectsRequest = ListObjectsRequest.builder();
listObjectsRequest.bucket(bucketName);
listObjectsRequest.prefix(getConfiguration().getPrefix());
listObjectsRequest.delimiter(getConfiguration().getDelimiter());
if (maxMessagesPerPoll > 0) {
listObjectsRequest.maxKeys(maxMessagesPerPoll);
}
// if there was a marker from previous poll then use that to
// continue from where we left last time
if (marker != null) {
LOG.trace("Resuming from marker: {}", marker);
listObjectsRequest.marker(marker);
}
ListObjectsResponse listObjects = getAmazonS3Client().listObjects(listObjectsRequest.build());
if (Boolean.TRUE.equals(listObjects.isTruncated())) {
marker = listObjects.nextMarker();
LOG.trace("Returned list is truncated, so setting next marker: {}", marker);
} else {
// no more data so clear marker
marker = null;
}
if (LOG.isTraceEnabled()) {
LOG.trace("Found {} objects in bucket [{}]...", listObjects.contents().size(), bucketName);
}
exchanges = createExchanges(listObjects.contents());
}
// okay we have some response from azure so lets mark the consumer as ready
forceConsumerAsReady();
return processBatch(CastUtils.cast(exchanges));
}
private boolean doneFileCheckPasses(String bucketName, String doneFileName) {
if (doneFileName == null) {
return true;
} else {
return checkFileExists(bucketName, doneFileName);
}
}
private boolean checkFileExists(String bucketName, String doneFileName) {
HeadObjectRequest.Builder headObjectsRequest = HeadObjectRequest.builder();
headObjectsRequest.bucket(bucketName);
headObjectsRequest.key(doneFileName);
try {
getAmazonS3Client().headObject(headObjectsRequest.build());
return true;
} catch (NoSuchKeyException e) {
return false;
}
}
protected Queue createExchanges(ResponseInputStream s3Object, String key) {
Queue answer = new LinkedList<>();
Exchange exchange = createExchange(s3Object, key);
answer.add(exchange);
return answer;
}
protected Queue createExchanges(List s3ObjectSummaries) {
if (LOG.isTraceEnabled()) {
LOG.trace("Received {} messages in this poll", s3ObjectSummaries.size());
}
Collection> s3Objects = new ArrayList<>();
Queue answer = new LinkedList<>();
try {
for (S3Object s3ObjectSummary : s3ObjectSummaries) {
String key = s3ObjectSummary.key();
// check if file is already in progress (add false = duplicate file)
if (!getEndpoint().getInProgressRepository().add(key)) {
if (LOG.isTraceEnabled()) {
LOG.trace("Skipping as s3 object is already in progress: {}", key);
}
continue;
}
LOG.debug("S3Object to be consumed: {}", key);
Builder getRequest
= GetObjectRequest.builder().bucket(getConfiguration().getBucketName()).key(key);
if (getConfiguration().isUseCustomerKey()) {
if (ObjectHelper.isNotEmpty(getConfiguration().getCustomerKeyId())) {
getRequest.sseCustomerKey(getConfiguration().getCustomerKeyId());
}
if (ObjectHelper.isNotEmpty(getConfiguration().getCustomerKeyMD5())) {
getRequest.sseCustomerKeyMD5(getConfiguration().getCustomerKeyMD5());
}
if (ObjectHelper.isNotEmpty(getConfiguration().getCustomerAlgorithm())) {
getRequest.sseCustomerAlgorithm(getConfiguration().getCustomerAlgorithm());
}
}
ResponseInputStream s3Object
= getAmazonS3Client().getObject(getRequest.build(), ResponseTransformer.toInputStream());
if (includeS3Object(s3Object)) {
s3Objects.add(s3Object);
Exchange exchange = createExchange(s3Object, key);
answer.add(exchange);
} else {
// If includeFolders != true and the object is not included, it is safe to close the object here.
// If includeFolders == true, the exchange will close the object.
IOHelper.close(s3Object);
// remove in progress
getEndpoint().getInProgressRepository().remove(key);
}
}
} catch (Exception e) {
LOG.warn("Error getting S3Object due: {}. This exception is ignored.", e.getMessage(), e);
// ensure all previous gathered s3 objects are closed
// if there was an exception creating the exchanges in this batch
s3Objects.forEach(IOHelper::close);
// remove all in-progress as we failed
for (Exchange exchange : answer) {
String key = exchange.getProperty(AWS2S3Constants.KEY, String.class);
if (key != null) {
getEndpoint().getInProgressRepository().remove(key);
}
}
throw e;
}
return answer;
}
/**
* Decide whether to include the S3Objects in the results
*
* @return true to include, false to exclude
*/
protected boolean includeS3Object(ResponseInputStream s3Object) {
if (getConfiguration().isIncludeFolders()) {
return true;
} else {
// Config says to ignore folders/directories
return !Optional.of(s3Object.response().contentType()).orElse("")
.toLowerCase().startsWith("application/x-directory");
}
}
@Override
public int processBatch(Queue
© 2015 - 2025 Weber Informatics LLC | Privacy Policy