Search in sources :

Example 1 with OrderingKey

use of io.micronaut.gcp.pubsub.annotation.OrderingKey in project micronaut-gcp by micronaut-projects.

the class PubSubClientIntroductionAdvice method intercept.

@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
    if (context.hasAnnotation(Topic.class)) {
        PubSubPublisherState publisherState = publisherStateCache.computeIfAbsent(context.getExecutableMethod(), method -> {
            String projectId = method.stringValue(PubSubClient.class).orElse(googleCloudConfiguration.getProjectId());
            Optional<Argument> orderingArgument = Arrays.stream(method.getArguments()).filter(argument -> argument.getAnnotationMetadata().hasAnnotation(OrderingKey.class)).findFirst();
            String topic = method.stringValue(Topic.class).orElse(context.getName());
            String endpoint = method.stringValue(Topic.class, "endpoint").orElse("");
            String configurationName = method.stringValue(Topic.class, "configuration").orElse("");
            String contentType = method.stringValue(Topic.class, "contentType").orElse(MediaType.APPLICATION_JSON);
            ProjectTopicName projectTopicName = PubSubTopicUtils.toProjectTopicName(topic, projectId);
            Map<String, String> staticMessageAttributes = new HashMap<>();
            List<AnnotationValue<MessageHeader>> headerAnnotations = context.getAnnotationValuesByType(MessageHeader.class);
            headerAnnotations.forEach((header) -> {
                String name = header.stringValue("name").orElse(null);
                String value = header.stringValue().orElse(null);
                if (StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(value)) {
                    staticMessageAttributes.put(name, value);
                }
            });
            Argument<?> bodyArgument = findBodyArgument(method).orElseThrow(() -> new PubSubClientException("No valid message body argument found for method: " + context.getExecutableMethod()));
            PubSubPublisherState.TopicState topicState = new PubSubPublisherState.TopicState(contentType, projectTopicName, configurationName, endpoint, orderingArgument.isPresent());
            logger.debug("Created a new publisher[{}] for topic: {}", context.getExecutableMethod().getName(), topic);
            PublisherInterface publisher = publisherFactory.createPublisher(new PublisherFactoryConfig(topicState, pubSubConfigurationProperties.getPublishingExecutor()));
            return new PubSubPublisherState(topicState, staticMessageAttributes, bodyArgument, publisher, orderingArgument);
        });
        Map<String, String> messageAttributes = new HashMap<>(publisherState.getStaticMessageAttributes());
        String contentType = publisherState.getTopicState().getContentType();
        Argument<?> bodyArgument = publisherState.getBodyArgument();
        Map<String, Object> parameterValues = context.getParameterValueMap();
        final ReturnType<Object> returnTypeInfo = context.getReturnType();
        ReturnType<Object> returnType = returnTypeInfo;
        Class<?> javaReturnType = returnType.getType();
        Argument[] arguments = context.getArguments();
        for (Argument arg : arguments) {
            AnnotationValue<MessageHeader> headerAnn = arg.getAnnotation(MessageHeader.class);
            if (headerAnn != null) {
                Map.Entry<String, String> entry = getNameAndValue(arg, headerAnn, parameterValues);
                messageAttributes.put(entry.getKey(), entry.getValue());
            }
        }
        PublisherInterface publisher = publisherState.getPublisher();
        Object body = parameterValues.get(bodyArgument.getName());
        PubsubMessage pubsubMessage = null;
        if (body.getClass() == PubsubMessage.class) {
            pubsubMessage = (PubsubMessage) body;
        } else {
            // if target type is byte[] we bypass serdes completely
            byte[] serialized = null;
            if (body.getClass() == byte[].class) {
                serialized = (byte[]) body;
            } else {
                PubSubMessageSerDes serDes = serDesRegistry.find(contentType).orElseThrow(() -> new PubSubClientException("Could not locate a valid SerDes implementation for type: " + contentType));
                serialized = serDes.serialize(body);
            }
            messageAttributes.put("Content-Type", contentType);
            PubsubMessage.Builder messageBuilder = PubsubMessage.newBuilder();
            messageBuilder.setData(ByteString.copyFrom(serialized)).putAllAttributes(messageAttributes);
            if (publisherState.getOrderingArgument().isPresent()) {
                String orderingKey = conversionService.convert(parameterValues.get(publisherState.getOrderingArgument().get().getName()), String.class).orElseThrow(() -> new PubSubClientException("Could not convert argument annotated with @OrderingKey to String type"));
                messageBuilder.setOrderingKey(orderingKey);
            }
            pubsubMessage = messageBuilder.build();
        }
        PubsubMessage finalPubsubMessage = pubsubMessage;
        Mono<String> reactiveResult = Mono.create(sink -> {
            ApiFuture<String> future = publisher.publish(finalPubsubMessage);
            future.addListener(() -> {
                try {
                    final String result = future.get();
                    sink.success(result);
                } catch (Throwable e) {
                    sink.error(e);
                }
            }, executorService);
        });
        if (javaReturnType == void.class || javaReturnType == Void.class) {
            String result = reactiveResult.block();
            return null;
        } else {
            if (returnTypeInfo.isReactive()) {
                return Publishers.convertPublisher(reactiveResult, javaReturnType);
            } else if (returnTypeInfo.isAsync()) {
                return reactiveResult.toFuture();
            } else {
                String result = reactiveResult.block();
                return conversionService.convert(result, javaReturnType).orElseThrow(() -> new PubSubClientException("Could not convert publisher result to method return type: " + javaReturnType));
            }
        }
    } else {
        return context.proceed();
    }
}
Also used : PublisherFactory(io.micronaut.gcp.pubsub.support.PublisherFactory) Arrays(java.util.Arrays) Publishers(io.micronaut.core.async.publisher.Publishers) PubSubPublisherState(io.micronaut.gcp.pubsub.support.PubSubPublisherState) LoggerFactory(org.slf4j.LoggerFactory) MessageHeader(io.micronaut.messaging.annotation.MessageHeader) HashMap(java.util.HashMap) PublisherFactoryConfig(io.micronaut.gcp.pubsub.support.PublisherFactoryConfig) ExecutableMethod(io.micronaut.inject.ExecutableMethod) PubSubMessageSerDesRegistry(io.micronaut.gcp.pubsub.serdes.PubSubMessageSerDesRegistry) PubsubMessage(com.google.pubsub.v1.PubsubMessage) PreDestroy(javax.annotation.PreDestroy) TaskExecutors(io.micronaut.scheduling.TaskExecutors) PublisherInterface(com.google.cloud.pubsub.v1.PublisherInterface) PubSubClientException(io.micronaut.gcp.pubsub.exception.PubSubClientException) MethodInterceptor(io.micronaut.aop.MethodInterceptor) PubSubTopicUtils(io.micronaut.gcp.pubsub.support.PubSubTopicUtils) MediaType(io.micronaut.http.MediaType) Map(java.util.Map) ReturnType(io.micronaut.core.type.ReturnType) PubSubConfigurationProperties(io.micronaut.gcp.pubsub.configuration.PubSubConfigurationProperties) ProjectTopicName(com.google.pubsub.v1.ProjectTopicName) Argument(io.micronaut.core.type.Argument) PubSubClient(io.micronaut.gcp.pubsub.annotation.PubSubClient) ConversionService(io.micronaut.core.convert.ConversionService) PubSubMessageSerDes(io.micronaut.gcp.pubsub.serdes.PubSubMessageSerDes) ExecutorService(java.util.concurrent.ExecutorService) Logger(org.slf4j.Logger) GoogleCloudConfiguration(io.micronaut.gcp.GoogleCloudConfiguration) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Singleton(jakarta.inject.Singleton) Mono(reactor.core.publisher.Mono) ApiFuture(com.google.api.core.ApiFuture) ByteString(com.google.protobuf.ByteString) StringUtils(io.micronaut.core.util.StringUtils) AbstractMap(java.util.AbstractMap) List(java.util.List) MethodInvocationContext(io.micronaut.aop.MethodInvocationContext) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) OrderingKey(io.micronaut.gcp.pubsub.annotation.OrderingKey) Optional(java.util.Optional) Topic(io.micronaut.gcp.pubsub.annotation.Topic) MessageBody(io.micronaut.messaging.annotation.MessageBody) Named(jakarta.inject.Named) PubSubClientException(io.micronaut.gcp.pubsub.exception.PubSubClientException) Argument(io.micronaut.core.type.Argument) HashMap(java.util.HashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) PubSubPublisherState(io.micronaut.gcp.pubsub.support.PubSubPublisherState) ByteString(com.google.protobuf.ByteString) PublisherInterface(com.google.cloud.pubsub.v1.PublisherInterface) PubsubMessage(com.google.pubsub.v1.PubsubMessage) PubSubClient(io.micronaut.gcp.pubsub.annotation.PubSubClient) Topic(io.micronaut.gcp.pubsub.annotation.Topic) PubSubMessageSerDes(io.micronaut.gcp.pubsub.serdes.PubSubMessageSerDes) PublisherFactoryConfig(io.micronaut.gcp.pubsub.support.PublisherFactoryConfig) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) ProjectTopicName(com.google.pubsub.v1.ProjectTopicName) MessageHeader(io.micronaut.messaging.annotation.MessageHeader) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) AbstractMap(java.util.AbstractMap)

Aggregations

ApiFuture (com.google.api.core.ApiFuture)1 PublisherInterface (com.google.cloud.pubsub.v1.PublisherInterface)1 ByteString (com.google.protobuf.ByteString)1 ProjectTopicName (com.google.pubsub.v1.ProjectTopicName)1 PubsubMessage (com.google.pubsub.v1.PubsubMessage)1 MethodInterceptor (io.micronaut.aop.MethodInterceptor)1 MethodInvocationContext (io.micronaut.aop.MethodInvocationContext)1 AnnotationValue (io.micronaut.core.annotation.AnnotationValue)1 Publishers (io.micronaut.core.async.publisher.Publishers)1 ConversionService (io.micronaut.core.convert.ConversionService)1 Argument (io.micronaut.core.type.Argument)1 ReturnType (io.micronaut.core.type.ReturnType)1 StringUtils (io.micronaut.core.util.StringUtils)1 GoogleCloudConfiguration (io.micronaut.gcp.GoogleCloudConfiguration)1 OrderingKey (io.micronaut.gcp.pubsub.annotation.OrderingKey)1 PubSubClient (io.micronaut.gcp.pubsub.annotation.PubSubClient)1 Topic (io.micronaut.gcp.pubsub.annotation.Topic)1 PubSubConfigurationProperties (io.micronaut.gcp.pubsub.configuration.PubSubConfigurationProperties)1 PubSubClientException (io.micronaut.gcp.pubsub.exception.PubSubClientException)1 PubSubMessageSerDes (io.micronaut.gcp.pubsub.serdes.PubSubMessageSerDes)1