package net.lenards.kinesis.types; import java.io.Serializable; import java.net.InetAddress; import java.util.UUID; import net.lenards.kinesis.KinesisCheckpointState; import net.lenards.kinesis.SerializableClientConfiguration; import net.lenards.kinesis.SerializableDefaultAWSCredentialsProviderChain; import org.apache.spark.storage.StorageLevel; import org.apache.spark.streaming.Duration; import org.apache.spark.streaming.receiver.Receiver; import com.amazonaws.AmazonClientException; import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; import com.amazonaws.auth.profile.ProfileCredentialsProvider; import com.amazonaws.regions.Region; import com.amazonaws.regions.RegionUtils; import com.amazonaws.services.kinesis.clientlibrary.interfaces.IRecordProcessor; import com.amazonaws.services.kinesis.clientlibrary.interfaces.IRecordProcessorCheckpointer; import com.amazonaws.services.kinesis.clientlibrary.interfaces.IRecordProcessorFactory; import com.amazonaws.services.kinesis.clientlibrary.lib.worker.InitialPositionInStream; import com.amazonaws.services.kinesis.clientlibrary.lib.worker.KinesisClientLibConfiguration; import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker; public class JKinesisReceiver extends Receiver<String> implements Serializable { private static final String APP = "StockTradesProcessor"; private static final String VERSION = "0.0.1"; private static SerializableClientConfiguration CLIENT_CONF; private KinesisClientLibConfiguration kclConfig; private String workerId; private Duration checkpointInterval; private InitialPositionInStream initialPosition; private IRecordProcessorFactory recordProcessorFactory; private Worker worker; static { SerializableClientConfiguration config = new SerializableClientConfiguration(); config.setUserAgent(String.format("%s %s/%s", ClientConfiguration.DEFAULT_USER_AGENT, APP, VERSION)); CLIENT_CONF = config; } public JKinesisReceiver(String applicationName, String streamName, String endpointUrl, String regionName, Duration checkpoint, InitialPositionInStream position) { super(StorageLevel.MEMORY_ONLY_SER()); this.workerId = getHostname() + ":" + String.valueOf(UUID.randomUUID()); this.checkpointInterval = checkpoint; this.initialPosition = position; Region region = RegionUtils.getRegion(regionName); try { this.kclConfig = new KinesisClientLibConfiguration(applicationName, streamName, getCredsProvider(), workerId) .withCommonClientConfig(CLIENT_CONF) .withRegionName(region.getName()) .withKinesisEndpoint(endpointUrl) .withInitialPositionInStream(InitialPositionInStream.LATEST) .withTaskBackoffTimeMillis(500); } catch (Exception ex) { // do absolutely nothing - and feel good about it! // but ... // we'd do something meaningful in a PROD context } } private static String getHostname() { try { return InetAddress.getLocalHost().getHostAddress(); } catch (Exception ex) { return "localhost"; } } private static AWSCredentialsProvider getCredsProvider() throws Exception { String msg = "Cannot load AWS credentials, no 'default' profile available."; try { //AWSCredentialsProvider provider = // new ProfileCredentialsProvider("default"); //return provider; return new SerializableDefaultAWSCredentialsProviderChain(); } catch (Exception e) { throw new AmazonClientException(msg, e); //return null; } } @Override public void onStart() { this.recordProcessorFactory = new EventRecordProcessorFactory(this, workerId, checkpointInterval); this.worker = new Worker(this.recordProcessorFactory, this.kclConfig); int exitCode = 0; try { worker.run(); } catch (Throwable t) { exitCode = 1; } System.exit(exitCode); } @Override public void onStop() { this.worker.shutdown(); this.workerId = null; this.recordProcessorFactory = null; this.worker = null; } }