use of io.micronaut.gcp.pubsub.exception.PubSubClientException 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();
}
}
use of io.micronaut.gcp.pubsub.exception.PubSubClientException in project micronaut-gcp by micronaut-projects.
the class DefaultPublisherFactory method createPublisher.
/**
* Creates a publisher for a given topic.
*
* @param config {@link PublisherFactoryConfig} object containing all required properties.
* @return An instance of {@link Publisher} configured using the config and environment properties from `gcp.pubsub.publisher.>config_name<`
*/
@Override
public Publisher createPublisher(@NonNull PublisherFactoryConfig config) {
try {
Publisher.Builder publisherBuilder = Publisher.newBuilder(config.getTopicState().getProjectTopicName());
Optional<PublisherConfigurationProperties> publisherConfiguration = beanContext.findBean(PublisherConfigurationProperties.class, Qualifiers.byName(config.getTopicState().getConfigurationName()));
String executor = publisherConfiguration.map(p -> p.getExecutor()).orElse(config.getDefaultExecutor());
ExecutorService executorService = beanContext.getBean(ExecutorService.class, Qualifiers.byName(executor));
publisherBuilder.setEnableMessageOrdering(config.getTopicState().getOrdered());
if (!StringUtils.isEmpty(config.getTopicState().getEndpoint())) {
publisherBuilder.setEndpoint(config.getTopicState().getEndpoint());
}
if (publisherConfiguration.isPresent()) {
publisherBuilder.setRetrySettings(publisherConfiguration.get().getRetrySettings().build());
// FlowControl had to be flatten in order to be parsed
BatchingSettings batchSettings = publisherConfiguration.get().getBatchingSettings().build();
publisherBuilder.setBatchingSettings(BatchingSettings.newBuilder().setDelayThreshold(batchSettings.getDelayThreshold()).setElementCountThreshold(batchSettings.getElementCountThreshold()).setIsEnabled(batchSettings.getIsEnabled()).setRequestByteThreshold(batchSettings.getRequestByteThreshold()).setFlowControlSettings(publisherConfiguration.get().getFlowControlSettings().build()).build());
}
if (!(executorService instanceof ScheduledExecutorService)) {
throw new IllegalStateException("Invalid Executor type provided, please make sure you have a ScheduledExecutorService configured for Publisher: " + config.getTopicState().getProjectTopicName().getTopic());
}
publisherBuilder.setExecutorProvider(FixedExecutorProvider.create((ScheduledExecutorService) executorService));
publisherBuilder.setChannelProvider(this.transportChannelProvider);
publisherBuilder.setCredentialsProvider(this.credentialsProvider);
return publisherBuilder.build();
} catch (Exception ex) {
throw new PubSubClientException("Failed to create subscriber", ex);
}
}
Aggregations