Search in sources :

Example 1 with PubSubMessageSerDes

use of io.micronaut.gcp.pubsub.serdes.PubSubMessageSerDes 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)

Example 2 with PubSubMessageSerDes

use of io.micronaut.gcp.pubsub.serdes.PubSubMessageSerDes in project micronaut-gcp by micronaut-projects.

the class PubSubBodyBinder method bind.

@Override
public BindingResult<Object> bind(ArgumentConversionContext<Object> context, PubSubConsumerState state) {
    Argument<Object> bodyType = context.getArgument();
    Object result = null;
    if (bodyType.getType().equals(byte[].class)) {
        result = state.getPubsubMessage().getData().toByteArray();
    } else if (bodyType.getType().equals(PubsubMessage.class)) {
        result = state.getPubsubMessage();
    } else {
        if (StringUtils.isEmpty(state.getContentType()) && !state.getPubsubMessage().containsAttributes("Content-Type")) {
            throw new PubSubListenerException("Could not detect Content-Type header at message and no Content-Type specified on method.");
        }
        PubSubMessageSerDes serDes = serDesRegistry.find(state.getContentType()).orElseThrow(() -> new PubSubListenerException("Could not locate a valid SerDes implementation for type: " + state.getContentType()));
        result = serDes.deserialize(state.getPubsubMessage().getData().toByteArray(), bodyType);
    }
    Object finalResult = result;
    return () -> Optional.ofNullable(finalResult);
}
Also used : PubSubMessageSerDes(io.micronaut.gcp.pubsub.serdes.PubSubMessageSerDes) PubSubListenerException(io.micronaut.gcp.pubsub.exception.PubSubListenerException) PubsubMessage(com.google.pubsub.v1.PubsubMessage)

Aggregations

PubsubMessage (com.google.pubsub.v1.PubsubMessage)2 PubSubMessageSerDes (io.micronaut.gcp.pubsub.serdes.PubSubMessageSerDes)2 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 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