Search in sources :

Example 1 with EncryptionKeys

use of org.apache.pulsar.common.api.proto.EncryptionKeys in project pulsar by apache.

the class TopicsImpl method getMessagesFromHttpResponse.

private List<Message<byte[]>> getMessagesFromHttpResponse(String topic, Response response) throws Exception {
    if (response.getStatus() != Status.OK.getStatusCode()) {
        throw getApiException(response);
    }
    String msgId = response.getHeaderString(MESSAGE_ID);
    // build broker entry metadata if exist
    String brokerEntryTimestamp = response.getHeaderString(BROKER_ENTRY_TIMESTAMP);
    String brokerEntryIndex = response.getHeaderString(BROKER_ENTRY_INDEX);
    BrokerEntryMetadata brokerEntryMetadata;
    if (brokerEntryTimestamp == null && brokerEntryIndex == null) {
        brokerEntryMetadata = null;
    } else {
        brokerEntryMetadata = new BrokerEntryMetadata();
        if (brokerEntryTimestamp != null) {
            brokerEntryMetadata.setBrokerTimestamp(DateFormatter.parse(brokerEntryTimestamp));
        }
        if (brokerEntryIndex != null) {
            brokerEntryMetadata.setIndex(Long.parseLong(brokerEntryIndex));
        }
    }
    MessageMetadata messageMetadata = new MessageMetadata();
    try (InputStream stream = (InputStream) response.getEntity()) {
        byte[] data = new byte[stream.available()];
        stream.read(data);
        Map<String, String> properties = new TreeMap<>();
        MultivaluedMap<String, Object> headers = response.getHeaders();
        Object tmp = headers.getFirst(PUBLISH_TIME);
        if (tmp != null) {
            messageMetadata.setPublishTime(DateFormatter.parse(tmp.toString()));
        }
        tmp = headers.getFirst(EVENT_TIME);
        if (tmp != null) {
            messageMetadata.setEventTime(DateFormatter.parse(tmp.toString()));
        }
        tmp = headers.getFirst(DELIVER_AT_TIME);
        if (tmp != null) {
            messageMetadata.setDeliverAtTime(DateFormatter.parse(tmp.toString()));
        }
        tmp = headers.getFirst("X-Pulsar-null-value");
        if (tmp != null) {
            messageMetadata.setNullValue(Boolean.parseBoolean(tmp.toString()));
        }
        tmp = headers.getFirst(PRODUCER_NAME);
        if (tmp != null) {
            messageMetadata.setProducerName(tmp.toString());
        }
        tmp = headers.getFirst(SEQUENCE_ID);
        if (tmp != null) {
            messageMetadata.setSequenceId(Long.parseLong(tmp.toString()));
        }
        tmp = headers.getFirst(REPLICATED_FROM);
        if (tmp != null) {
            messageMetadata.setReplicatedFrom(tmp.toString());
        }
        tmp = headers.getFirst(PARTITION_KEY);
        if (tmp != null) {
            messageMetadata.setPartitionKey(tmp.toString());
        }
        tmp = headers.getFirst(COMPRESSION);
        if (tmp != null) {
            messageMetadata.setCompression(CompressionType.valueOf(tmp.toString()));
        }
        tmp = headers.getFirst(UNCOMPRESSED_SIZE);
        if (tmp != null) {
            messageMetadata.setUncompressedSize(Integer.parseInt(tmp.toString()));
        }
        tmp = headers.getFirst(ENCRYPTION_ALGO);
        if (tmp != null) {
            messageMetadata.setEncryptionAlgo(tmp.toString());
        }
        tmp = headers.getFirst(PARTITION_KEY_B64_ENCODED);
        if (tmp != null) {
            messageMetadata.setPartitionKeyB64Encoded(Boolean.parseBoolean(tmp.toString()));
        }
        tmp = headers.getFirst(MARKER_TYPE);
        if (tmp != null) {
            messageMetadata.setMarkerType(Integer.parseInt(tmp.toString()));
        }
        tmp = headers.getFirst(TXNID_LEAST_BITS);
        if (tmp != null) {
            messageMetadata.setTxnidLeastBits(Long.parseLong(tmp.toString()));
        }
        tmp = headers.getFirst(TXNID_MOST_BITS);
        if (tmp != null) {
            messageMetadata.setTxnidMostBits(Long.parseLong(tmp.toString()));
        }
        tmp = headers.getFirst(HIGHEST_SEQUENCE_ID);
        if (tmp != null) {
            messageMetadata.setHighestSequenceId(Long.parseLong(tmp.toString()));
        }
        tmp = headers.getFirst(UUID);
        if (tmp != null) {
            messageMetadata.setUuid(tmp.toString());
        }
        tmp = headers.getFirst(NUM_CHUNKS_FROM_MSG);
        if (tmp != null) {
            messageMetadata.setNumChunksFromMsg(Integer.parseInt(tmp.toString()));
        }
        tmp = headers.getFirst(TOTAL_CHUNK_MSG_SIZE);
        if (tmp != null) {
            messageMetadata.setTotalChunkMsgSize(Integer.parseInt(tmp.toString()));
        }
        tmp = headers.getFirst(CHUNK_ID);
        if (tmp != null) {
            messageMetadata.setChunkId(Integer.parseInt(tmp.toString()));
        }
        tmp = headers.getFirst(NULL_PARTITION_KEY);
        if (tmp != null) {
            messageMetadata.setNullPartitionKey(Boolean.parseBoolean(tmp.toString()));
        }
        tmp = headers.getFirst(ENCRYPTION_PARAM);
        if (tmp != null) {
            messageMetadata.setEncryptionParam(Base64.getDecoder().decode(tmp.toString()));
        }
        tmp = headers.getFirst(ORDERING_KEY);
        if (tmp != null) {
            messageMetadata.setOrderingKey(Base64.getDecoder().decode(tmp.toString()));
        }
        tmp = headers.getFirst(SCHEMA_VERSION);
        if (tmp != null) {
            messageMetadata.setSchemaVersion(Base64.getDecoder().decode(tmp.toString()));
        }
        tmp = headers.getFirst(ENCRYPTION_PARAM);
        if (tmp != null) {
            messageMetadata.setEncryptionParam(Base64.getDecoder().decode(tmp.toString()));
        }
        List<Object> tmpList = headers.get(REPLICATED_TO);
        if (tmpList != null) {
            for (Object o : tmpList) {
                messageMetadata.addReplicateTo(o.toString());
            }
        }
        tmpList = headers.get(ENCRYPTION_KEYS);
        if (tmpList != null) {
            for (Object o : tmpList) {
                EncryptionKeys encryptionKey = messageMetadata.addEncryptionKey();
                encryptionKey.parseFrom(Base64.getDecoder().decode(o.toString()));
            }
        }
        tmp = headers.getFirst(BATCH_SIZE_HEADER);
        if (tmp != null) {
            properties.put(BATCH_SIZE_HEADER, (String) tmp);
        }
        for (Entry<String, List<Object>> entry : headers.entrySet()) {
            String header = entry.getKey();
            if (header.contains("X-Pulsar-PROPERTY-")) {
                String keyName = header.substring("X-Pulsar-PROPERTY-".length());
                properties.put(keyName, (String) entry.getValue().get(0));
            }
        }
        tmp = headers.getFirst(BATCH_HEADER);
        if (tmp != null) {
            properties.put(BATCH_HEADER, (String) tmp);
        }
        boolean isEncrypted = false;
        tmp = headers.getFirst("X-Pulsar-Is-Encrypted");
        if (tmp != null) {
            isEncrypted = Boolean.parseBoolean(tmp.toString());
        }
        if (!isEncrypted && response.getHeaderString(BATCH_HEADER) != null) {
            return getIndividualMsgsFromBatch(topic, msgId, data, properties, messageMetadata, brokerEntryMetadata);
        }
        MessageImpl message = new MessageImpl(topic, msgId, properties, Unpooled.wrappedBuffer(data), Schema.BYTES, messageMetadata);
        if (brokerEntryMetadata != null) {
            message.setBrokerEntryMetadata(brokerEntryMetadata);
        }
        return Collections.singletonList(message);
    }
}
Also used : InputStream(java.io.InputStream) TreeMap(java.util.TreeMap) EncryptionKeys(org.apache.pulsar.common.api.proto.EncryptionKeys) MessageMetadata(org.apache.pulsar.common.api.proto.MessageMetadata) SingleMessageMetadata(org.apache.pulsar.common.api.proto.SingleMessageMetadata) List(java.util.List) ArrayList(java.util.ArrayList) BrokerEntryMetadata(org.apache.pulsar.common.api.proto.BrokerEntryMetadata) MessageImpl(org.apache.pulsar.client.impl.MessageImpl)

Example 2 with EncryptionKeys

use of org.apache.pulsar.common.api.proto.EncryptionKeys in project pulsar by apache.

the class MessageCryptoBc method decrypt.

/*
     * Decrypt the payload using the data key. Keys used to encrypt data key can be retrieved from msgMetadata
     *
     * @param msgMetadata Message Metadata
     *
     * @param payload Message which needs to be decrypted
     *
     * @param keyReader KeyReader implementation to retrieve key value
     *
     * @return true if success, false otherwise
     */
@Override
public boolean decrypt(Supplier<MessageMetadata> messageMetadataSupplier, ByteBuffer payload, ByteBuffer outBuffer, CryptoKeyReader keyReader) {
    MessageMetadata msgMetadata = messageMetadataSupplier.get();
    // If dataKey is present, attempt to decrypt using the existing key
    if (dataKey != null) {
        if (getKeyAndDecryptData(msgMetadata, payload, outBuffer)) {
            return true;
        }
    }
    // dataKey is null or decryption failed. Attempt to regenerate data key
    List<EncryptionKeys> encKeys = msgMetadata.getEncryptionKeysList();
    EncryptionKeys encKeyInfo = encKeys.stream().filter(kbv -> {
        byte[] encDataKey = kbv.getValue();
        List<KeyValue> encKeyMeta = kbv.getMetadatasList();
        return decryptDataKey(kbv.getKey(), encDataKey, encKeyMeta, keyReader);
    }).findFirst().orElse(null);
    if (encKeyInfo == null || dataKey == null) {
        // Unable to decrypt data key
        return false;
    }
    return getKeyAndDecryptData(msgMetadata, payload, outBuffer);
}
Also used : MessageMetadata(org.apache.pulsar.common.api.proto.MessageMetadata) KeyValue(org.apache.pulsar.common.api.proto.KeyValue) EncryptionKeys(org.apache.pulsar.common.api.proto.EncryptionKeys)

Example 3 with EncryptionKeys

use of org.apache.pulsar.common.api.proto.EncryptionKeys in project pulsar by apache.

the class MessageCryptoBc method encrypt.

/*
     * Encrypt the payload using the data key and update message metadata with the keyname & encrypted data key
     *
     * @param encKeys One or more public keys to encrypt data key
     *
     * @param msgMetadata Message Metadata
     *
     * @param payload Message which needs to be encrypted
     *
     * @return encryptedData if success
     */
@Override
public synchronized void encrypt(Set<String> encKeys, CryptoKeyReader keyReader, Supplier<MessageMetadata> messageMetadataBuilderSupplier, ByteBuffer payload, ByteBuffer outBuffer) throws PulsarClientException {
    MessageMetadata msgMetadata = messageMetadataBuilderSupplier.get();
    if (encKeys.isEmpty()) {
        outBuffer.put(payload);
        outBuffer.flip();
        return;
    }
    msgMetadata.clearEncryptionKeys();
    // Update message metadata with encrypted data key
    for (String keyName : encKeys) {
        if (encryptedDataKeyMap.get(keyName) == null) {
            // Attempt to load the key. This will allow us to load keys as soon as
            // a new key is added to producer config
            addPublicKeyCipher(keyName, keyReader);
        }
        EncryptionKeyInfo keyInfo = encryptedDataKeyMap.get(keyName);
        if (keyInfo != null) {
            if (keyInfo.getMetadata() != null && !keyInfo.getMetadata().isEmpty()) {
                EncryptionKeys encKey = msgMetadata.addEncryptionKey().setKey(keyName).setValue(keyInfo.getKey());
                keyInfo.getMetadata().forEach((key, value) -> {
                    encKey.addMetadata().setKey(key).setValue(value);
                });
            } else {
                msgMetadata.addEncryptionKey().setKey(keyName).setValue(keyInfo.getKey());
            }
        } else {
            // We should never reach here.
            log.error("{} Failed to find encrypted Data key for key {}.", logCtx, keyName);
        }
    }
    // Create gcm param
    // TODO: Replace random with counter and periodic refreshing based on timer/counter value
    secureRandom.nextBytes(iv);
    GCMParameterSpec gcmParam = new GCMParameterSpec(tagLen, iv);
    // Update message metadata with encryption param
    msgMetadata.setEncryptionParam(iv);
    try {
        // Encrypt the data
        cipher.init(Cipher.ENCRYPT_MODE, dataKey, gcmParam);
        int maxLength = cipher.getOutputSize(payload.remaining());
        if (outBuffer.remaining() < maxLength) {
            throw new IllegalArgumentException("Outbuffer has not enough space available");
        }
        int bytesStored = cipher.doFinal(payload, outBuffer);
        outBuffer.flip();
        outBuffer.limit(bytesStored);
    } catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | ShortBufferException e) {
        log.error("{} Failed to encrypt message. {}", logCtx, e);
        throw new PulsarClientException.CryptoException(e.getMessage());
    }
}
Also used : InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) IllegalBlockSizeException(javax.crypto.IllegalBlockSizeException) EncryptionKeyInfo(org.apache.pulsar.client.api.EncryptionKeyInfo) GCMParameterSpec(javax.crypto.spec.GCMParameterSpec) BadPaddingException(javax.crypto.BadPaddingException) InvalidKeyException(java.security.InvalidKeyException) EncryptionKeys(org.apache.pulsar.common.api.proto.EncryptionKeys) MessageMetadata(org.apache.pulsar.common.api.proto.MessageMetadata) CryptoException(org.apache.pulsar.client.api.PulsarClientException.CryptoException) PulsarClientException(org.apache.pulsar.client.api.PulsarClientException) ShortBufferException(javax.crypto.ShortBufferException)

Example 4 with EncryptionKeys

use of org.apache.pulsar.common.api.proto.EncryptionKeys in project pulsar by apache.

the class MessageCryptoBc method getKeyAndDecryptData.

private boolean getKeyAndDecryptData(MessageMetadata msgMetadata, ByteBuffer payload, ByteBuffer targetBuffer) {
    List<EncryptionKeys> encKeys = msgMetadata.getEncryptionKeysList();
    // Go through all keys to retrieve data key from cache
    for (int i = 0; i < encKeys.size(); i++) {
        byte[] msgDataKey = encKeys.get(i).getValue();
        byte[] keyDigest = digest.digest(msgDataKey);
        SecretKey storedSecretKey = dataKeyCache.getIfPresent(ByteBuffer.wrap(keyDigest));
        if (storedSecretKey != null) {
            // call decryptDataKey to refresh the cache and come here again to decrypt.
            if (decryptData(storedSecretKey, msgMetadata, payload, targetBuffer)) {
                // If decryption succeeded, we can already return
                return true;
            }
        } else {
            // First time, entry won't be present in cache
            log.debug("{} Failed to decrypt data or data key is not in cache. Will attempt to refresh", logCtx);
        }
    }
    return false;
}
Also used : SecretKey(javax.crypto.SecretKey) EncryptionKeys(org.apache.pulsar.common.api.proto.EncryptionKeys)

Example 5 with EncryptionKeys

use of org.apache.pulsar.common.api.proto.EncryptionKeys in project pulsar by apache.

the class ConsumerImpl method createEncryptionContext.

/**
 * Create EncryptionContext if message payload is encrypted.
 *
 * @param msgMetadata
 * @return {@link Optional}<{@link EncryptionContext}>
 */
private Optional<EncryptionContext> createEncryptionContext(MessageMetadata msgMetadata) {
    EncryptionContext encryptionCtx = null;
    if (msgMetadata.getEncryptionKeysCount() > 0) {
        encryptionCtx = new EncryptionContext();
        Map<String, EncryptionKey> keys = msgMetadata.getEncryptionKeysList().stream().collect(Collectors.toMap(EncryptionKeys::getKey, e -> new EncryptionKey(e.getValue(), e.getMetadatasList().stream().collect(Collectors.toMap(KeyValue::getKey, KeyValue::getValue)))));
        byte[] encParam = msgMetadata.getEncryptionParam();
        Optional<Integer> batchSize = Optional.ofNullable(msgMetadata.hasNumMessagesInBatch() ? msgMetadata.getNumMessagesInBatch() : null);
        encryptionCtx.setKeys(keys);
        encryptionCtx.setParam(encParam);
        if (msgMetadata.hasEncryptionAlgo()) {
            encryptionCtx.setAlgorithm(msgMetadata.getEncryptionAlgo());
        }
        encryptionCtx.setCompressionType(CompressionCodecProvider.convertFromWireProtocol(msgMetadata.getCompression()));
        encryptionCtx.setUncompressedMessageSize(msgMetadata.getUncompressedSize());
        encryptionCtx.setBatchSize(batchSize);
    }
    return Optional.ofNullable(encryptionCtx);
}
Also used : EncryptionKey(org.apache.pulsar.common.api.EncryptionContext.EncryptionKey) SubscriptionMode(org.apache.pulsar.client.api.SubscriptionMode) MessageIdData(org.apache.pulsar.common.api.proto.MessageIdData) Producer(org.apache.pulsar.client.api.Producer) LoggerFactory(org.slf4j.LoggerFactory) MessageCryptoBc(org.apache.pulsar.client.impl.crypto.MessageCryptoBc) MessageCrypto(org.apache.pulsar.client.api.MessageCrypto) StringUtils(org.apache.commons.lang3.StringUtils) KeyValue(org.apache.pulsar.common.api.proto.KeyValue) ByteBuffer(java.nio.ByteBuffer) GrowableArrayBlockingQueue(org.apache.pulsar.common.util.collections.GrowableArrayBlockingQueue) ProtocolVersion(org.apache.pulsar.common.api.proto.ProtocolVersion) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) TxnID(org.apache.pulsar.client.api.transaction.TxnID) Handle(io.netty.util.Recycler.Handle) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ExecutorProvider(org.apache.pulsar.client.util.ExecutorProvider) Runnables.catchingAndLoggingThrowables(org.apache.pulsar.common.util.Runnables.catchingAndLoggingThrowables) Map(java.util.Map) Messages(org.apache.pulsar.client.api.Messages) RetryMessageUtil(org.apache.pulsar.client.util.RetryMessageUtil) CompletableFutureCancellationHandler(org.apache.pulsar.common.util.CompletableFutureCancellationHandler) PulsarClientException(org.apache.pulsar.client.api.PulsarClientException) ReadWriteLock(java.util.concurrent.locks.ReadWriteLock) BrokerEntryMetadata(org.apache.pulsar.common.api.proto.BrokerEntryMetadata) Crc32cIntChecksum(com.scurrilous.circe.checksum.Crc32cIntChecksum) ValidationError(org.apache.pulsar.common.api.proto.CommandAck.ValidationError) BitSetRecyclable(org.apache.pulsar.common.util.collections.BitSetRecyclable) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) BlockingQueue(java.util.concurrent.BlockingQueue) EncryptionContext(org.apache.pulsar.common.api.EncryptionContext) ComparisonChain(com.google.common.collect.ComparisonChain) Collectors(java.util.stream.Collectors) PulsarByteBufAllocator(org.apache.pulsar.common.allocator.PulsarByteBufAllocator) Recycler(io.netty.util.Recycler) Objects(java.util.Objects) Consumer(org.apache.pulsar.client.api.Consumer) List(java.util.List) FutureUtil(org.apache.pulsar.common.util.FutureUtil) MessageMetadata(org.apache.pulsar.common.api.proto.MessageMetadata) ConcurrentOpenHashMap(org.apache.pulsar.common.util.collections.ConcurrentOpenHashMap) EncryptionKeys(org.apache.pulsar.common.api.proto.EncryptionKeys) CommandMessage(org.apache.pulsar.common.api.proto.CommandMessage) ReferenceCountUtil(io.netty.util.ReferenceCountUtil) Optional(java.util.Optional) SchemaInfo(org.apache.pulsar.common.schema.SchemaInfo) SortedMap(java.util.SortedMap) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) CompressionCodec(org.apache.pulsar.common.compression.CompressionCodec) Iterables(com.google.common.collect.Iterables) AtomicIntegerFieldUpdater(java.util.concurrent.atomic.AtomicIntegerFieldUpdater) ConsumerCryptoFailureAction(org.apache.pulsar.client.api.ConsumerCryptoFailureAction) TopicName(org.apache.pulsar.common.naming.TopicName) ConsumerConfigurationData(org.apache.pulsar.client.impl.conf.ConsumerConfigurationData) AckType(org.apache.pulsar.common.api.proto.CommandAck.AckType) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) ReentrantReadWriteLock(java.util.concurrent.locks.ReentrantReadWriteLock) Message(org.apache.pulsar.client.api.Message) SubscriptionInitialPosition(org.apache.pulsar.client.api.SubscriptionInitialPosition) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) SchemaType(org.apache.pulsar.common.schema.SchemaType) ArrayList(java.util.ArrayList) Commands(org.apache.pulsar.common.protocol.Commands) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) ByteBuf(io.netty.buffer.ByteBuf) Commands.hasChecksum(org.apache.pulsar.common.protocol.Commands.hasChecksum) TopicDoesNotExistException(org.apache.pulsar.client.api.PulsarClientException.TopicDoesNotExistException) CompressionCodecProvider(org.apache.pulsar.common.compression.CompressionCodecProvider) CompressionType(org.apache.pulsar.common.api.proto.CompressionType) TypedMessageBuilder(org.apache.pulsar.client.api.TypedMessageBuilder) SafeCollectionUtils(org.apache.pulsar.common.util.SafeCollectionUtils) DEFAULT_CONSUMER_EPOCH(org.apache.pulsar.common.protocol.Commands.DEFAULT_CONSUMER_EPOCH) Timeout(io.netty.util.Timeout) Logger(org.slf4j.Logger) TransactionImpl(org.apache.pulsar.client.impl.transaction.TransactionImpl) InitialPosition(org.apache.pulsar.common.api.proto.CommandSubscribe.InitialPosition) DeadLetterPolicy(org.apache.pulsar.client.api.DeadLetterPolicy) IOException(java.io.IOException) AtomicLongFieldUpdater(java.util.concurrent.atomic.AtomicLongFieldUpdater) SubscriptionType(org.apache.pulsar.client.api.SubscriptionType) Schema(org.apache.pulsar.client.api.Schema) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) AtomicLong(java.util.concurrent.atomic.AtomicLong) MessageId(org.apache.pulsar.client.api.MessageId) TreeMap(java.util.TreeMap) SingleMessageMetadata(org.apache.pulsar.common.api.proto.SingleMessageMetadata) Collections(java.util.Collections) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) KeyValue(org.apache.pulsar.common.api.proto.KeyValue) EncryptionContext(org.apache.pulsar.common.api.EncryptionContext) EncryptionKey(org.apache.pulsar.common.api.EncryptionContext.EncryptionKey)

Aggregations

EncryptionKeys (org.apache.pulsar.common.api.proto.EncryptionKeys)6 MessageMetadata (org.apache.pulsar.common.api.proto.MessageMetadata)5 ArrayList (java.util.ArrayList)3 List (java.util.List)3 PulsarClientException (org.apache.pulsar.client.api.PulsarClientException)3 BrokerEntryMetadata (org.apache.pulsar.common.api.proto.BrokerEntryMetadata)3 KeyValue (org.apache.pulsar.common.api.proto.KeyValue)3 ByteBuf (io.netty.buffer.ByteBuf)2 IOException (java.io.IOException)2 Collections (java.util.Collections)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 Optional (java.util.Optional)2 Set (java.util.Set)2 CompletableFuture (java.util.concurrent.CompletableFuture)2 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)2 ExecutionException (java.util.concurrent.ExecutionException)2 TimeUnit (java.util.concurrent.TimeUnit)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 AtomicReference (java.util.concurrent.atomic.AtomicReference)2