@ConditionalOnBean(QueryInvocationErrorHandler.class) @ConditionalOnMissingBean(QueryBus.class) @Qualifier("localSegment") @Bean public SimpleQueryBus queryBus(AxonConfiguration axonConfiguration, TransactionManager transactionManager, QueryInvocationErrorHandler eh) { return SimpleQueryBus.builder() .messageMonitor(axonConfiguration.messageMonitor(QueryBus.class, "queryBus")) .transactionManager(transactionManager) .errorHandler(eh) .queryUpdateEmitter(axonConfiguration.getComponent(QueryUpdateEmitter.class)) .build(); }
@Bean( destroyMethod = "disconnect") @ConditionalOnMissingBean(QueryBus.class) public AxonServerQueryBus queryBus(AxonServerConnectionManager axonServerConnectionManager, AxonServerConfiguration axonServerConfiguration, AxonConfiguration axonConfiguration, TransactionManager txManager, @Qualifier("messageSerializer") Serializer messageSerializer, Serializer genericSerializer, QueryPriorityCalculator priorityCalculator, QueryInvocationErrorHandler queryInvocationErrorHandler) { SimpleQueryBus simpleQueryBus = SimpleQueryBus.builder() .messageMonitor(axonConfiguration.messageMonitor(QueryBus.class, "queryBus")) .transactionManager(txManager) .queryUpdateEmitter(axonConfiguration.getComponent(QueryUpdateEmitter.class)) .errorHandler(queryInvocationErrorHandler) .build(); simpleQueryBus.registerHandlerInterceptor(new CorrelationDataInterceptor<>(axonConfiguration .correlationDataProviders())); return new AxonServerQueryBus(axonServerConnectionManager, axonServerConfiguration, simpleQueryBus.queryUpdateEmitter(), simpleQueryBus, messageSerializer, genericSerializer, priorityCalculator); }
/** * Initializes a {@link SimpleQueryBus} as specified through this Builder. * * @return a {@link SimpleQueryBus} as specified through this Builder */ public SimpleQueryBus build() { return new SimpleQueryBus(this); }
@Override public <Q, R> Stream<QueryResponseMessage<R>> scatterGather(QueryMessage<Q, R> query, long timeout, TimeUnit unit) { MessageMonitor.MonitorCallback monitorCallback = messageMonitor.onMessageIngested(query); QueryMessage<Q, R> interceptedQuery = intercept(query); List<MessageHandler<? super QueryMessage<?, ?>>> handlers = getHandlersForMessage(interceptedQuery); if (handlers.isEmpty()) { monitorCallback.reportIgnored(); long leftTimeout = getRemainingOfDeadline(deadline); ResultMessage<CompletableFuture<QueryResponseMessage<R>>> resultMessage = interceptAndInvoke(DefaultUnitOfWork.startAndGet(interceptedQuery), handler); QueryResponseMessage<R> response = null;
/** * Instantiate a {@link SimpleQueryBus} based on the fields contained in the {@link Builder}. * * @param builder the {@link Builder} used to instantiate a {@link SimpleQueryBus} instance */ protected SimpleQueryBus(Builder builder) { builder.validate(); this.messageMonitor = builder.messageMonitor; this.errorHandler = builder.errorHandler; if (builder.transactionManager != NoTransactionManager.INSTANCE) { registerHandlerInterceptor(new TransactionManagingInterceptor<>(builder.transactionManager)); } this.queryUpdateEmitter = builder.queryUpdateEmitter; }
@Override public <R> Registration subscribe(String queryName, Type responseType, MessageHandler<? super QueryMessage<?, R>> handler) { CopyOnWriteArrayList<QuerySubscription> handlers = subscriptions.computeIfAbsent(queryName, k -> new CopyOnWriteArrayList<>()); QuerySubscription<R> querySubscription = new QuerySubscription<>(responseType, handler); handlers.addIfAbsent(querySubscription); return () -> unsubscribe(queryName, querySubscription); }
@SuppressWarnings("unchecked") private <Q, R> ResultMessage<CompletableFuture<QueryResponseMessage<R>>> interceptAndInvoke( UnitOfWork<QueryMessage<Q, R>> uow, MessageHandler<? super QueryMessage<?, R>> handler) { return uow.executeWithResult(() -> { ResponseType<R> responseType = uow.getMessage().getResponseType(); Object queryResponse = new DefaultInterceptorChain<>(uow, handlerInterceptors, handler).proceed(); if (queryResponse instanceof CompletableFuture) { return ((CompletableFuture) queryResponse).thenCompose( result -> buildCompletableFuture(responseType, result)); } else if (queryResponse instanceof Future) { return CompletableFuture.supplyAsync(() -> { try { return ((Future<QueryResponseMessage<R>>) queryResponse).get(); } catch (InterruptedException | ExecutionException e) { throw new QueryExecutionException("Error happened while trying to execute query handler", e); } }); } return buildCompletableFuture(responseType, queryResponse); }); }
@SuppressWarnings("unchecked") @Override public <Q, I, U> SubscriptionQueryResult<QueryResponseMessage<I>, SubscriptionQueryUpdateMessage<U>> subscriptionQuery( SubscriptionQueryMessage<Q, I, U> query, SubscriptionQueryBackpressure backpressure, int updateBufferSize) { if (queryUpdateEmitter.queryUpdateHandlerRegistered(query)) { throw new IllegalArgumentException("There is already a subscription with the given message identifier"); } MonoWrapper<QueryResponseMessage<I>> initialResult = MonoWrapper.create(monoSink -> query(query) .thenAccept(monoSink::success) .exceptionally(t -> { logger.error(format("An error happened while trying to report an initial result. Query: %s", query), t); monoSink.error(t.getCause()); return null; })); UpdateHandlerRegistration<U> updateHandlerRegistration = queryUpdateEmitter .registerUpdateHandler(query, backpressure, updateBufferSize); return new DefaultSubscriptionQueryResult<>(initialResult.getMono(), updateHandlerRegistration.getUpdates(), updateHandlerRegistration.getRegistration()); }
@Override public <Q, R> CompletableFuture<QueryResponseMessage<R>> query(QueryMessage<Q, R> query) { MessageMonitor.MonitorCallback monitorCallback = messageMonitor.onMessageIngested(query); QueryMessage<Q, R> interceptedQuery = intercept(query); List<MessageHandler<? super QueryMessage<?, ?>>> handlers = getHandlersForMessage(interceptedQuery); CompletableFuture<QueryResponseMessage<R>> result = new CompletableFuture<>(); try { DefaultUnitOfWork<QueryMessage<Q, R>> uow = DefaultUnitOfWork.startAndGet(interceptedQuery); ResultMessage<CompletableFuture<QueryResponseMessage<R>>> resultMessage = interceptAndInvoke(uow, handlerIterator.next()); if (resultMessage.isExceptional()) { if (!(resultMessage.exceptionResult() instanceof NoHandlerForQueryException)) {
/** * Instantiate a {@link SimpleQueryBus} based on the fields contained in the {@link Builder}. * * @param builder the {@link Builder} used to instantiate a {@link SimpleQueryBus} instance */ protected SimpleQueryBus(Builder builder) { builder.validate(); this.messageMonitor = builder.messageMonitor; this.errorHandler = builder.errorHandler; if (builder.transactionManager != NoTransactionManager.INSTANCE) { registerHandlerInterceptor(new TransactionManagingInterceptor<>(builder.transactionManager)); } this.queryUpdateEmitter = builder.queryUpdateEmitter; }
@Override public <R> Registration subscribe(String queryName, Type responseType, MessageHandler<? super QueryMessage<?, R>> handler) { CopyOnWriteArrayList<QuerySubscription> handlers = subscriptions.computeIfAbsent(queryName, k -> new CopyOnWriteArrayList<>()); QuerySubscription<R> querySubscription = new QuerySubscription<>(responseType, handler); handlers.addIfAbsent(querySubscription); return () -> unsubscribe(queryName, querySubscription); }
@SuppressWarnings("unchecked") private <Q, R> ResultMessage<CompletableFuture<QueryResponseMessage<R>>> interceptAndInvoke( UnitOfWork<QueryMessage<Q, R>> uow, MessageHandler<? super QueryMessage<?, R>> handler) { return uow.executeWithResult(() -> { ResponseType<R> responseType = uow.getMessage().getResponseType(); Object queryResponse = new DefaultInterceptorChain<>(uow, handlerInterceptors, handler).proceed(); if (queryResponse instanceof CompletableFuture) { return ((CompletableFuture) queryResponse).thenCompose( result -> buildCompletableFuture(responseType, result)); } else if (queryResponse instanceof Future) { return CompletableFuture.supplyAsync(() -> { try { return ((Future<QueryResponseMessage<R>>) queryResponse).get(); } catch (InterruptedException | ExecutionException e) { throw new QueryExecutionException("Error happened while trying to execute query handler", e); } }); } return buildCompletableFuture(responseType, queryResponse); }); }
@SuppressWarnings("unchecked") @Override public <Q, I, U> SubscriptionQueryResult<QueryResponseMessage<I>, SubscriptionQueryUpdateMessage<U>> subscriptionQuery( SubscriptionQueryMessage<Q, I, U> query, SubscriptionQueryBackpressure backpressure, int updateBufferSize) { if (queryUpdateEmitter.queryUpdateHandlerRegistered(query)) { throw new IllegalArgumentException("There is already a subscription with the given message identifier"); } MonoWrapper<QueryResponseMessage<I>> initialResult = MonoWrapper.create(monoSink -> query(query) .thenAccept(monoSink::success) .exceptionally(t -> { logger.error(format("An error happened while trying to report an initial result. Query: %s", query), t); monoSink.error(t.getCause()); return null; })); UpdateHandlerRegistration<U> updateHandlerRegistration = queryUpdateEmitter .registerUpdateHandler(query, backpressure, updateBufferSize); return new DefaultSubscriptionQueryResult<>(initialResult.getMono(), updateHandlerRegistration.getUpdates(), updateHandlerRegistration.getRegistration()); }
@Override public <Q, R> Stream<QueryResponseMessage<R>> scatterGather(QueryMessage<Q, R> query, long timeout, TimeUnit unit) { MessageMonitor.MonitorCallback monitorCallback = messageMonitor.onMessageIngested(query); QueryMessage<Q, R> interceptedQuery = intercept(query); List<MessageHandler<? super QueryMessage<?, ?>>> handlers = getHandlersForMessage(interceptedQuery); if (handlers.isEmpty()) { monitorCallback.reportIgnored(); return Stream.empty(); } long deadline = System.currentTimeMillis() + unit.toMillis(timeout); return handlers.stream() .map(handler -> { try { long leftTimeout = getRemainingOfDeadline(deadline); QueryResponseMessage<R> response = interceptAndInvoke(DefaultUnitOfWork.startAndGet(interceptedQuery), handler) .get(leftTimeout, TimeUnit.MILLISECONDS); monitorCallback.reportSuccess(); return response; } catch (Exception e) { monitorCallback.reportFailure(e); errorHandler.onError(e, interceptedQuery, handler); return null; } }).filter(Objects::nonNull); }
@ConditionalOnMissingBean(value = {QueryBus.class, QueryInvocationErrorHandler.class}) @Qualifier("localSegment") @Bean public SimpleQueryBus queryBus(AxonConfiguration axonConfiguration, TransactionManager transactionManager) { return SimpleQueryBus.builder() .messageMonitor(axonConfiguration.messageMonitor(QueryBus.class, "queryBus")) .transactionManager(transactionManager) .errorHandler(axonConfiguration.getComponent( QueryInvocationErrorHandler.class, () -> LoggingQueryInvocationErrorHandler.builder().build() )) .queryUpdateEmitter(axonConfiguration.getComponent(QueryUpdateEmitter.class)) .build(); }
@Bean( destroyMethod = "disconnect") @ConditionalOnMissingBean(QueryBus.class) public AxonServerQueryBus queryBus(AxonServerConnectionManager axonServerConnectionManager, AxonServerConfiguration axonServerConfiguration, AxonConfiguration axonConfiguration, TransactionManager txManager, @Qualifier("messageSerializer") Serializer messageSerializer, Serializer genericSerializer, QueryPriorityCalculator priorityCalculator, QueryInvocationErrorHandler queryInvocationErrorHandler) { SimpleQueryBus simpleQueryBus = SimpleQueryBus.builder() .messageMonitor(axonConfiguration.messageMonitor(QueryBus.class, "queryBus")) .transactionManager(txManager) .queryUpdateEmitter(axonConfiguration.getComponent(QueryUpdateEmitter.class)) .errorHandler(queryInvocationErrorHandler) .build(); simpleQueryBus.registerHandlerInterceptor(new CorrelationDataInterceptor<>(axonConfiguration .correlationDataProviders())); return new AxonServerQueryBus(axonServerConnectionManager, axonServerConfiguration, simpleQueryBus.queryUpdateEmitter(), simpleQueryBus, messageSerializer, genericSerializer, priorityCalculator); }
/** * Initialize the query bus with the given {@code messageMonitor}, {@code updateMessageMonitor}, {@code * transactionManager} and given {@code errorHandler}. * * @param messageMonitor The message monitor notified for incoming messages and their result * @param updateMessageMonitor The message monitor notified for incoming update message in regard to subscription * queries * @param transactionManager The transaction manager to manage transactions around query execution with * @param errorHandler The error handler to invoke when query handler report an error */ public SimpleQueryBus(MessageMonitor<? super QueryMessage<?, ?>> messageMonitor, MessageMonitor<? super SubscriptionQueryUpdateMessage<?>> updateMessageMonitor, TransactionManager transactionManager, QueryInvocationErrorHandler errorHandler) { this.messageMonitor = messageMonitor != null ? messageMonitor : NoOpMessageMonitor.instance(); this.updateMessageMonitor = updateMessageMonitor != null ? updateMessageMonitor : NoOpMessageMonitor.instance(); this.errorHandler = getOrDefault(errorHandler, () -> new LoggingQueryInvocationErrorHandler(logger)); if (transactionManager != null) { registerHandlerInterceptor(new TransactionManagingInterceptor<>(transactionManager)); } }
/** * Initializes a {@link SimpleQueryBus} as specified through this Builder. * * @return a {@link SimpleQueryBus} as specified through this Builder */ public SimpleQueryBus build() { return new SimpleQueryBus(this); }
@Override public <R> Registration subscribe(String queryName, Type responseType, MessageHandler<? super QueryMessage<?, R>> handler) { CopyOnWriteArrayList<QuerySubscription> handlers = subscriptions.computeIfAbsent(queryName, k -> new CopyOnWriteArrayList<>()); QuerySubscription<R> querySubscription = new QuerySubscription<>(responseType, handler); handlers.addIfAbsent(querySubscription); return () -> unsubscribe(queryName, querySubscription); }
@SuppressWarnings("unchecked") private <Q, R> CompletableFuture<QueryResponseMessage<R>> interceptAndInvoke(UnitOfWork<QueryMessage<Q, R>> uow, MessageHandler<? super QueryMessage<?, R>> handler) throws Exception { return uow.executeWithResult(() -> { ResponseType<R> responseType = uow.getMessage().getResponseType(); Object queryResponse = new DefaultInterceptorChain<>(uow, handlerInterceptors, handler).proceed(); if (queryResponse instanceof CompletableFuture) { return ((CompletableFuture) queryResponse).thenCompose( result -> buildCompletableFuture(responseType, result)); } else if (queryResponse instanceof Future) { return CompletableFuture.supplyAsync(() -> { try { return ((Future) queryResponse).get(); } catch (InterruptedException | ExecutionException e) { throw new QueryExecutionException("Error happened while trying to execute query handler", e); } }); } return buildCompletableFuture(responseType, queryResponse); }); }