1 /* 2 * Copyright 2002-2018 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 module hunt.stomp.simp.annotation.AbstractMethodMessageHandler; 18 19 import hunt.stomp.simp.SimpMessageHeaderAccessor; 20 import hunt.stomp.simp.SimpMessageType; 21 22 // import hunt.framework.beans.factory.InitializingBean; 23 // import hunt.framework.context.ApplicationContext; 24 // import hunt.framework.websocket.WebSocketController; 25 // import hunt.framework.context.ApplicationContextAware; 26 // import hunt.framework.core.MethodIntrospector; 27 // import hunt.framework.core.MethodParameter; 28 29 import hunt.stomp.Message; 30 import hunt.stomp.MessagingException; 31 import hunt.stomp.handler.DestinationPatternsMessageCondition; 32 // import hunt.stomp.handler.HandlerMethod; 33 // import hunt.stomp.handler.MessagingAdviceBean; 34 import hunt.stomp.support.GenericMessage; 35 import hunt.stomp.support.MessageBuilder; 36 import hunt.stomp.support.MessageHeaderAccessor; 37 38 // import hunt.framework.util.ClassUtils; 39 // import hunt.framework.util.concurrent.ListenableFuture; 40 // import hunt.framework.util.concurrent.ListenableFutureCallback; 41 42 import hunt.collection; 43 import hunt.Exceptions; 44 import hunt.Nullable; 45 import hunt.logging; 46 import hunt.util.TypeUtils; 47 48 import std.array; 49 import std.conv; 50 import std.string; 51 52 /** 53 * Abstract base class for HandlerMethod-based message handling. Provides most of 54 * the logic required to discover handler methods at startup, find a matching handler 55 * method at runtime for a given message and invoke it. 56 * 57 * <p>Also supports discovering and invoking exception handling methods to process 58 * exceptions raised during message handling. 59 * 60 * @author Rossen Stoyanchev 61 * @author Juergen Hoeller 62 * @since 4.0 63 * @param (T) the type of the Object that contains information mapping a 64 * {@link hunt.stomp.handler.HandlerMethod} to incoming messages 65 */ 66 abstract class AbstractMethodMessageHandler(T) 67 : MessageHandler { // , ApplicationContextAware, InitializingBean 68 69 /** 70 * Bean name prefix for target beans behind scoped proxies. Used to exclude those 71 * targets from handler method detection, in favor of the corresponding proxies. 72 * <p>We're not checking the autowire-candidate status here, which is how the 73 * proxy target filtering problem is being handled at the autowiring level, 74 * since autowire-candidate may have been turned to {@code false} for other 75 * reasons, while still expecting the bean to be eligible for handler methods. 76 * <p>Originally defined in {@link hunt.framework.aop.scope.ScopedProxyUtils} 77 * but duplicated here to avoid a hard dependency on the spring-aop module. 78 */ 79 private enum string SCOPED_TARGET_NAME_PREFIX = "scopedTarget."; 80 81 private string[] destinationPrefixes; 82 83 // private List!(HandlerMethodArgumentResolver) customArgumentResolvers = new ArrayList<>(4); 84 85 // private List!(HandlerMethodReturnValueHandler) customReturnValueHandlers = new ArrayList<>(4); 86 87 // private HandlerMethodArgumentResolverComposite argumentResolvers = 88 // new HandlerMethodArgumentResolverComposite(); 89 90 // private HandlerMethodReturnValueHandlerComposite returnValueHandlers = 91 // new HandlerMethodReturnValueHandlerComposite(); 92 93 94 // private ApplicationContext applicationContext; 95 96 // private Map!(T, HandlerMethod) handlerMethods = new LinkedHashMap<>(64); 97 98 // private MultiValueMap!(string, T) destinationLookup = new LinkedMultiValueMap<>(64); 99 100 // private Map<Class<?>, AbstractExceptionHandlerMethodResolver> exceptionHandlerCache = 101 // new ConcurrentHashMap<>(64); 102 103 // private Map!(MessagingAdviceBean, AbstractExceptionHandlerMethodResolver) exceptionHandlerAdviceCache = 104 // new LinkedHashMap<>(64); 105 106 this() { 107 } 108 109 /** 110 * When this property is configured only messages to destinations matching 111 * one of the configured prefixes are eligible for handling. When there is a 112 * match the prefix is removed and only the remaining part of the destination 113 * is used for method-mapping purposes. 114 * <p>By default, no prefixes are configured in which case all messages are 115 * eligible for handling. 116 */ 117 void setDestinationPrefixes(string[] prefixes) { 118 this.destinationPrefixes = []; 119 foreach (string prefix ; prefixes) { 120 prefix = prefix.strip(); 121 this.destinationPrefixes ~= prefix; 122 } 123 } 124 125 /** 126 * Return the configured destination prefixes, if any. 127 */ 128 string[] getDestinationPrefixes() { 129 return this.destinationPrefixes; 130 } 131 132 /** 133 * Sets the list of custom {@code HandlerMethodArgumentResolver}s that will be used 134 * after resolvers for supported argument type. 135 */ 136 // void setCustomArgumentResolvers(List!(HandlerMethodArgumentResolver) customArgumentResolvers) { 137 // this.customArgumentResolvers.clear(); 138 // if (customArgumentResolvers !is null) { 139 // this.customArgumentResolvers.addAll(customArgumentResolvers); 140 // } 141 // } 142 143 /** 144 * Return the configured custom argument resolvers, if any. 145 */ 146 // List!(HandlerMethodArgumentResolver) getCustomArgumentResolvers() { 147 // return this.customArgumentResolvers; 148 // } 149 150 /** 151 * Set the list of custom {@code HandlerMethodReturnValueHandler}s that will be used 152 * after return value handlers for known types. 153 */ 154 // void setCustomReturnValueHandlers(List!(HandlerMethodReturnValueHandler) customReturnValueHandlers) { 155 // this.customReturnValueHandlers.clear(); 156 // if (customReturnValueHandlers !is null) { 157 // this.customReturnValueHandlers.addAll(customReturnValueHandlers); 158 // } 159 // } 160 161 /** 162 * Return the configured custom return value handlers, if any. 163 */ 164 // List!(HandlerMethodReturnValueHandler) getCustomReturnValueHandlers() { 165 // return this.customReturnValueHandlers; 166 // } 167 168 /** 169 * Configure the complete list of supported argument types, effectively overriding 170 * the ones configured by default. This is an advanced option; for most use cases 171 * it should be sufficient to use {@link #setCustomArgumentResolvers}. 172 */ 173 // void setArgumentResolvers(List!(HandlerMethodArgumentResolver) argumentResolvers) { 174 // if (argumentResolvers is null) { 175 // this.argumentResolvers.clear(); 176 // return; 177 // } 178 // this.argumentResolvers.addResolvers(argumentResolvers); 179 // } 180 181 /** 182 * Return the complete list of argument resolvers. 183 */ 184 // List!(HandlerMethodArgumentResolver) getArgumentResolvers() { 185 // return this.argumentResolvers.getResolvers(); 186 // } 187 188 /** 189 * Configure the complete list of supported return value types, effectively overriding 190 * the ones configured by default. This is an advanced option; for most use cases 191 * it should be sufficient to use {@link #setCustomReturnValueHandlers}. 192 */ 193 // void setReturnValueHandlers(List!(HandlerMethodReturnValueHandler) returnValueHandlers) { 194 // if (returnValueHandlers is null) { 195 // this.returnValueHandlers.clear(); 196 // return; 197 // } 198 // this.returnValueHandlers.addHandlers(returnValueHandlers); 199 // } 200 201 /** 202 * Return the complete list of return value handlers. 203 */ 204 // List!(HandlerMethodReturnValueHandler) getReturnValueHandlers() { 205 // return this.returnValueHandlers.getReturnValueHandlers(); 206 // } 207 208 // override 209 // void setApplicationContext(ApplicationContext applicationContext) { 210 // this.applicationContext = applicationContext; 211 // } 212 213 214 // ApplicationContext getApplicationContext() { 215 // return this.applicationContext; 216 // } 217 218 219 // override 220 void afterPropertiesSet() { 221 implementationMissing(false); 222 // if (this.argumentResolvers.getResolvers().isEmpty()) { 223 // this.argumentResolvers.addResolvers(initArgumentResolvers()); 224 // } 225 226 // if (this.returnValueHandlers.getReturnValueHandlers().isEmpty()) { 227 // this.returnValueHandlers.addHandlers(initReturnValueHandlers()); 228 // } 229 // Log returnValueLogger = getReturnValueHandlerLogger(); 230 // if (returnValueLogger !is null) { 231 // this.returnValueHandlers.setLogger(returnValueLogger); 232 // } 233 234 // this.handlerMethodLogger = getHandlerMethodLogger(); 235 236 // ApplicationContext context = getApplicationContext(); 237 // if (context is null) { 238 // return; 239 // } 240 // for (string beanName : context.getBeanNamesForType(Object.class)) { 241 // if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { 242 // Class<?> beanType = null; 243 // try { 244 // beanType = context.getType(beanName); 245 // } 246 // catch (Throwable ex) { 247 // // An unresolvable bean type, probably from a lazy bean - let's ignore it. 248 // version(HUNT_DEBUG) { 249 // trace("Could not resolve target class for bean with name '" ~ beanName ~ "'", ex); 250 // } 251 // } 252 // if (beanType !is null && isHandler(beanType)) { 253 // detectHandlerMethods(beanName); 254 // } 255 // } 256 // } 257 } 258 259 /** 260 * Return the list of argument resolvers to use. Invoked only if the resolvers 261 * have not already been set via {@link #setArgumentResolvers}. 262 * <p>Subclasses should also take into account custom argument types configured via 263 * {@link #setCustomArgumentResolvers}. 264 */ 265 // protected abstract List!(HandlerMethodArgumentResolver) initArgumentResolvers(); 266 267 /** 268 * Return the list of return value handlers to use. Invoked only if the return 269 * value handlers have not already been set via {@link #setReturnValueHandlers}. 270 * <p>Subclasses should also take into account custom return value types configured 271 * via {@link #setCustomReturnValueHandlers}. 272 */ 273 // protected abstract List!(HandlerMethodReturnValueHandler) initReturnValueHandlers(); 274 275 276 /** 277 * Whether the given bean type should be introspected for messaging handling methods. 278 */ 279 // protected abstract isHandler(Class<?> beanType); 280 281 /** 282 * Detect if the given handler has any methods that can handle messages and if 283 * so register it with the extracted mapping information. 284 * @param handler the handler to check, either an instance of a Spring bean name 285 */ 286 // protected final void detectHandlerMethods(Object handler) { 287 // Class<?> handlerType; 288 // if (handler instanceof string) { 289 // ApplicationContext context = getApplicationContext(); 290 // assert(context !is null, "ApplicationContext is required for resolving handler bean names"); 291 // handlerType = context.getType((string) handler); 292 // } 293 // else { 294 // handlerType = handler.getClass(); 295 // } 296 297 // if (handlerType !is null) { 298 // Class<?> userType = ClassUtils.getUserClass(handlerType); 299 // Map!(Method, T) methods = MethodIntrospector.selectMethods(userType, 300 // (MethodIntrospector.MetadataLookup!(T)) method -> getMappingForMethod(method, userType)); 301 // version(HUNT_DEBUG) { 302 // trace(methods.size() ~ " message handler methods found on " ~ userType ~ ": " ~ methods); 303 // } 304 // methods.forEach((key, value) -> registerHandlerMethod(handler, key, value)); 305 // } 306 // } 307 308 /** 309 * Provide the mapping for a handler method. 310 * @param method the method to provide a mapping for 311 * @param handlerType the handler type, possibly a sub-type of the method's declaring class 312 * @return the mapping, or {@code null} if the method is not mapped 313 */ 314 315 // protected abstract T getMappingForMethod(Method method, Class<?> handlerType); 316 317 /** 318 * Register a handler method and its unique mapping. 319 * @param handler the bean name of the handler or the handler instance 320 * @param method the method to register 321 * @param mapping the mapping conditions associated with the handler method 322 * @throws IllegalStateException if another method was already registered 323 * under the same mapping 324 */ 325 // protected void registerHandlerMethod(Object handler, Method method, T mapping) { 326 // assert(mapping, "Mapping must not be null"); 327 // HandlerMethod newHandlerMethod = createHandlerMethod(handler, method); 328 // HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping); 329 330 // if (oldHandlerMethod !is null && !oldHandlerMethod.equals(newHandlerMethod)) { 331 // throw new IllegalStateException("Ambiguous mapping found. Cannot map '" ~ newHandlerMethod.getBean() + 332 // "' bean method \n" ~ newHandlerMethod ~ "\nto " ~ mapping ~ ": There is already '" ~ 333 // oldHandlerMethod.getBean() ~ "' bean method\n" ~ oldHandlerMethod ~ " mapped."); 334 // } 335 336 // this.handlerMethods.put(mapping, newHandlerMethod); 337 // version(HUNT_DEBUG) { 338 // trace("Mapped \"" ~ mapping ~ "\" onto " ~ newHandlerMethod); 339 // } 340 341 // for (string pattern : getDirectLookupDestinations(mapping)) { 342 // this.destinationLookup.add(pattern, mapping); 343 // } 344 // } 345 346 /** 347 * Create a HandlerMethod instance from an Object handler that is either a handler 348 * instance or a string-based bean name. 349 */ 350 // protected HandlerMethod createHandlerMethod(Object handler, Method method) { 351 // HandlerMethod handlerMethod; 352 // if (handler instanceof string) { 353 // ApplicationContext context = getApplicationContext(); 354 // assert(context !is null, "ApplicationContext is required for resolving handler bean names"); 355 // string beanName = (string) handler; 356 // handlerMethod = new HandlerMethod(beanName, context.getAutowireCapableBeanFactory(), method); 357 // } 358 // else { 359 // handlerMethod = new HandlerMethod(handler, method); 360 // } 361 // return handlerMethod; 362 // } 363 364 /** 365 * Return destinations contained in the mapping that are not patterns and are 366 * therefore suitable for direct lookups. 367 */ 368 // protected abstract Set!(string) getDirectLookupDestinations(T mapping); 369 370 /** 371 * Return a logger to set on {@link HandlerMethodReturnValueHandlerComposite}. 372 * @since 5.1 373 */ 374 375 // protected Log getReturnValueHandlerLogger() { 376 // return null; 377 // } 378 379 /** 380 * Return a logger to set on {@link InvocableHandlerMethod}. 381 * @since 5.1 382 */ 383 384 // protected Log getHandlerMethodLogger() { 385 // return null; 386 // } 387 388 /** 389 * Subclasses can invoke this method to populate the MessagingAdviceBean cache 390 * (e.g. to support "global" {@code @MessageExceptionHandler}). 391 * @since 4.2 392 */ 393 // protected void registerExceptionHandlerAdvice( 394 // MessagingAdviceBean bean, AbstractExceptionHandlerMethodResolver resolver) { 395 396 // this.exceptionHandlerAdviceCache.put(bean, resolver); 397 // } 398 399 /** 400 * Return a map with all handler methods and their mappings. 401 */ 402 // Map!(T, HandlerMethod) getHandlerMethods() { 403 // return Collections.unmodifiableMap(this.handlerMethods); 404 // } 405 406 407 override 408 void handleMessage(MessageBase message) { 409 version(HUNT_DEBUG) { 410 trace("Processing " ~ typeid(cast(Object)message).name); 411 } 412 413 string destination = getDestination(message); 414 if (destination is null) { 415 return; 416 } 417 string lookupDestination = getLookupDestination(destination); 418 if (lookupDestination is null) { 419 return; 420 } 421 MessageHeaderAccessor headerAccessor = MessageHeaderAccessor.getMutableAccessor(message); 422 headerAccessor.setHeader(DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER, lookupDestination); 423 headerAccessor.setLeaveMutable(true); 424 425 if(message.payloadType == typeid(byte[])) { 426 GenericMessage!(byte[]) gm = cast(GenericMessage!(byte[]))message; 427 message = MessageHelper.createMessage(gm.getPayload(), headerAccessor.getMessageHeaders()); 428 429 version(HUNT_DEBUG) { 430 trace("Searching methods to handle " ~ 431 headerAccessor.getShortLogMessage(new Nullable!(byte[])(gm.getPayload())) ~ 432 ", lookupDestination='" ~ lookupDestination ~ "'"); 433 } 434 } else { 435 warning("Can't handle message: ", message.payloadType.toString()); 436 } 437 438 handleMessageInternal(message, lookupDestination); 439 headerAccessor.setImmutable(); 440 } 441 442 443 protected abstract string getDestination(MessageBase message); 444 445 /** 446 * Check whether the given destination (of an incoming message) matches to 447 * one of the configured destination prefixes and if so return the remaining 448 * portion of the destination after the matched prefix. 449 * <p>If there are no matching prefixes, return {@code null}. 450 * <p>If there are no destination prefixes, return the destination as is. 451 */ 452 protected string getLookupDestination(string destination) { 453 if (destination.empty()) { 454 return null; 455 } 456 if (this.destinationPrefixes.length >0) { 457 return destination; 458 } 459 460 foreach(string prefix; destinationPrefixes) { 461 if (destination.startsWith(prefix)) { 462 return destination[prefix.length .. $]; 463 } 464 } 465 return null; 466 } 467 468 protected void handleReturnValue(Object returnValue, TypeInfo returnType, 469 MessageBase message, string[] destinations) ; 470 471 protected void handleMessageInternal(MessageBase message, string lookupDestination) { 472 implementationMissing(false); 473 } 474 // protected void handleMessageInternal(MessageBase message, string lookupDestination) { 475 // // FIXME: Needing refactor or cleanup -@zxp at 11/13/2018, 3:07:59 PM 476 // // more tests 477 // try { 478 // WebSocketControllerHelper.invoke(lookupDestination, message, 479 // (Object returnValue, TypeInfo returnType, string[] destinations) { 480 // handleReturnValue(returnValue, returnType, message, destinations); 481 // }); 482 // } 483 // catch (Exception ex) { 484 // warning(ex.msg); 485 // // processHandlerMethodException(handlerMethod, ex, message); 486 // } 487 // catch (Throwable ex) { 488 // warning(ex.msg); 489 // Exception handlingException = new MessageHandlingException(message, 490 // "Unexpected handler method invocation error", ex); 491 // } 492 // } 493 494 // private void addMatchesToCollection(Collection!(T) mappingsToCheck, MessageBase message, List!(Match) matches) { 495 // foreach (T mapping ; mappingsToCheck) { 496 // T match = getMatchingMapping(mapping, message); 497 // if (match !is null) { 498 // matches.add(new Match(match, this.handlerMethods.get(mapping))); 499 // } 500 // } 501 // } 502 503 /** 504 * Check if a mapping matches the current message and return a possibly 505 * new mapping with conditions relevant to the current request. 506 * @param mapping the mapping to get a match for 507 * @param message the message being handled 508 * @return the match or {@code null} if there is no match 509 */ 510 511 // protected abstract T getMatchingMapping(T mapping, MessageBase message); 512 513 // protected void handleNoMatch(Set!(T) ts, string lookupDestination, MessageBase message) { 514 // trace("No matching message handler methods."); 515 // } 516 517 /** 518 * Return a comparator for sorting matching mappings. 519 * The returned comparator should sort 'better' matches higher. 520 * @param message the current Message 521 * @return the comparator, never {@code null} 522 */ 523 // protected abstract Comparator!(T) getMappingComparator(MessageBase message); 524 525 // protected void handleMatch(T mapping, HandlerMethod handlerMethod, string lookupDestination, MessageBase message) { 526 // version(HUNT_DEBUG) { 527 // trace("Invoking " ~ handlerMethod.getShortLogMessage()); 528 // } 529 // handlerMethod = handlerMethod.createWithResolvedBean(); 530 // InvocableHandlerMethod invocable = new InvocableHandlerMethod(handlerMethod); 531 // if (this.handlerMethodLogger !is null) { 532 // invocable.setLogger(this.handlerMethodLogger); 533 // } 534 // invocable.setMessageMethodArgumentResolvers(this.argumentResolvers); 535 // try { 536 // Object returnValue = invocable.invoke(message); 537 // MethodParameter returnType = handlerMethod.getReturnType(); 538 // if (void.class == returnType.getParameterType()) { 539 // return; 540 // } 541 // if (returnValue !is null && this.returnValueHandlers.isAsyncReturnValue(returnValue, returnType)) { 542 // ListenableFuture<?> future = this.returnValueHandlers.toListenableFuture(returnValue, returnType); 543 // if (future !is null) { 544 // future.addCallback(new ReturnValueListenableFutureCallback(invocable, message)); 545 // } 546 // } 547 // else { 548 // this.returnValueHandlers.handleReturnValue(returnValue, returnType, message); 549 // } 550 // } 551 // catch (Exception ex) { 552 // processHandlerMethodException(handlerMethod, ex, message); 553 // } 554 // catch (Throwable ex) { 555 // Exception handlingException = 556 // new MessageHandlingException(message, "Unexpected handler method invocation error", ex); 557 // processHandlerMethodException(handlerMethod, handlingException, message); 558 // } 559 // } 560 561 // protected void processHandlerMethodException(HandlerMethod handlerMethod, Exception exception, MessageBase message) { 562 // InvocableHandlerMethod invocable = getExceptionHandlerMethod(handlerMethod, exception); 563 // if (invocable is null) { 564 // error("Unhandled exception from message handler method", exception); 565 // return; 566 // } 567 // invocable.setMessageMethodArgumentResolvers(this.argumentResolvers); 568 // version(HUNT_DEBUG) { 569 // trace("Invoking " ~ invocable.getShortLogMessage()); 570 // } 571 // try { 572 // Throwable cause = exception.getCause(); 573 // Object returnValue = (cause !is null ? 574 // invocable.invoke(message, exception, cause, handlerMethod) : 575 // invocable.invoke(message, exception, handlerMethod)); 576 // MethodParameter returnType = invocable.getReturnType(); 577 // if (void.class == returnType.getParameterType()) { 578 // return; 579 // } 580 // this.returnValueHandlers.handleReturnValue(returnValue, returnType, message); 581 // } 582 // catch (Throwable ex2) { 583 // error("Error while processing handler method exception", ex2); 584 // } 585 // } 586 587 /** 588 * Find an {@code @MessageExceptionHandler} method for the given exception. 589 * The default implementation searches methods in the class hierarchy of the 590 * HandlerMethod first and if not found, it continues searching for additional 591 * {@code @MessageExceptionHandler} methods among the configured 592 * {@linkplain hunt.stomp.handler.MessagingAdviceBean 593 * MessagingAdviceBean}, if any. 594 * @param handlerMethod the method where the exception was raised 595 * @param exception the raised exception 596 * @return a method to handle the exception, or {@code null} 597 * @since 4.2 598 */ 599 600 // protected InvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) { 601 // version(HUNT_DEBUG) { 602 // trace("Searching methods to handle " ~ exception.TypeUtils.getSimpleName(typeid(this))); 603 // } 604 // Class<?> beanType = handlerMethod.getBeanType(); 605 // AbstractExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(beanType); 606 // if (resolver is null) { 607 // resolver = createExceptionHandlerMethodResolverFor(beanType); 608 // this.exceptionHandlerCache.put(beanType, resolver); 609 // } 610 // Method method = resolver.resolveMethod(exception); 611 // if (method !is null) { 612 // return new InvocableHandlerMethod(handlerMethod.getBean(), method); 613 // } 614 // for (MessagingAdviceBean advice : this.exceptionHandlerAdviceCache.keySet()) { 615 // if (advice.isApplicableToBeanType(beanType)) { 616 // resolver = this.exceptionHandlerAdviceCache.get(advice); 617 // method = resolver.resolveMethod(exception); 618 // if (method !is null) { 619 // return new InvocableHandlerMethod(advice.resolveBean(), method); 620 // } 621 // } 622 // } 623 // return null; 624 // } 625 626 // protected abstract AbstractExceptionHandlerMethodResolver createExceptionHandlerMethodResolverFor( 627 // Class<?> beanType); 628 629 override int opCmp(MessageHandler o) { 630 implementationMissing(false); 631 return 0; 632 } 633 634 override 635 string toString() { 636 return TypeUtils.getSimpleName(typeid(this)) ~ "[prefixes=" ~ getDestinationPrefixes().to!string() ~ "]"; 637 } 638 639 640 /** 641 * A thin wrapper around a matched HandlerMethod and its matched mapping for 642 * the purpose of comparing the best match with a comparator in the context 643 * of a message. 644 */ 645 // private class Match { 646 647 // private T mapping; 648 649 // private HandlerMethod handlerMethod; 650 651 // this(T mapping, HandlerMethod handlerMethod) { 652 // this.mapping = mapping; 653 // this.handlerMethod = handlerMethod; 654 // } 655 656 // override 657 // string toString() { 658 // return this.mapping.toString(); 659 // } 660 // } 661 662 663 // private class MatchComparator : Comparator!(Match) { 664 665 // private Comparator!(T) comparator; 666 667 // this(Comparator!(T) comparator) { 668 // this.comparator = comparator; 669 // } 670 671 // override 672 // int compare(Match match1, Match match2) { 673 // return this.comparator.compare(match1.mapping, match2.mapping); 674 // } 675 // } 676 677 678 // private class ReturnValueListenableFutureCallback : ListenableFutureCallback!(Object) { 679 680 // private InvocableHandlerMethod handlerMethod; 681 682 // private MessageBase message; 683 684 // this(InvocableHandlerMethod handlerMethod, MessageBase message) { 685 // this.handlerMethod = handlerMethod; 686 // this.message = message; 687 // } 688 689 // override 690 // void onSuccess(Object result) { 691 // try { 692 // MethodParameter returnType = this.handlerMethod.getAsyncReturnValueType(result); 693 // returnValueHandlers.handleReturnValue(result, returnType, this.message); 694 // } 695 // catch (Throwable ex) { 696 // handleFailure(ex); 697 // } 698 // } 699 700 // override 701 // void onFailure(Throwable ex) { 702 // handleFailure(ex); 703 // } 704 705 // private void handleFailure(Throwable ex) { 706 // Exception cause = (ex instanceof Exception ? (Exception) ex : new IllegalStateException(ex)); 707 // processHandlerMethodException(this.handlerMethod, cause, this.message); 708 // } 709 // } 710 711 }