001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.messaging.handler.invocation; 018 019import java.util.ArrayList; 020import java.util.Collections; 021import java.util.List; 022 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025 026import org.springframework.core.MethodParameter; 027import org.springframework.lang.Nullable; 028import org.springframework.messaging.Message; 029import org.springframework.util.concurrent.ListenableFuture; 030 031/** 032 * A HandlerMethodReturnValueHandler that wraps and delegates to others. 033 * 034 * @author Rossen Stoyanchev 035 * @since 4.0 036 */ 037public class HandlerMethodReturnValueHandlerComposite implements AsyncHandlerMethodReturnValueHandler { 038 039 /** Public for wrapping with fallback logger. */ 040 public static final Log defaultLogger = LogFactory.getLog(HandlerMethodReturnValueHandlerComposite.class); 041 042 043 private Log logger = defaultLogger; 044 045 private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>(); 046 047 048 /** 049 * Set an alternative logger to use than the one based on the class name. 050 * @param logger the logger to use 051 * @since 5.1 052 */ 053 public void setLogger(Log logger) { 054 this.logger = logger; 055 } 056 057 /** 058 * Return the currently configured Logger. 059 * @since 5.1 060 */ 061 public Log getLogger() { 062 return logger; 063 } 064 065 /** 066 * Return a read-only list with the configured handlers. 067 */ 068 public List<HandlerMethodReturnValueHandler> getReturnValueHandlers() { 069 return Collections.unmodifiableList(this.returnValueHandlers); 070 } 071 072 /** 073 * Clear the list of configured handlers. 074 */ 075 public void clear() { 076 this.returnValueHandlers.clear(); 077 } 078 079 /** 080 * Add the given {@link HandlerMethodReturnValueHandler}. 081 */ 082 public HandlerMethodReturnValueHandlerComposite addHandler(HandlerMethodReturnValueHandler returnValueHandler) { 083 this.returnValueHandlers.add(returnValueHandler); 084 return this; 085 } 086 087 /** 088 * Add the given {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers}. 089 */ 090 public HandlerMethodReturnValueHandlerComposite addHandlers( 091 @Nullable List<? extends HandlerMethodReturnValueHandler> handlers) { 092 093 if (handlers != null) { 094 this.returnValueHandlers.addAll(handlers); 095 } 096 return this; 097 } 098 099 @Override 100 public boolean supportsReturnType(MethodParameter returnType) { 101 return getReturnValueHandler(returnType) != null; 102 } 103 104 @SuppressWarnings("ForLoopReplaceableByForEach") 105 @Nullable 106 private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) { 107 for (int i = 0; i < this.returnValueHandlers.size(); i++) { 108 HandlerMethodReturnValueHandler handler = this.returnValueHandlers.get(i); 109 if (handler.supportsReturnType(returnType)) { 110 return handler; 111 } 112 } 113 return null; 114 } 115 116 @Override 117 public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, Message<?> message) 118 throws Exception { 119 120 HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType); 121 if (handler == null) { 122 throw new IllegalStateException("No handler for return value type: " + returnType.getParameterType()); 123 } 124 if (logger.isTraceEnabled()) { 125 logger.trace("Processing return value with " + handler); 126 } 127 handler.handleReturnValue(returnValue, returnType, message); 128 } 129 130 @Override 131 public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) { 132 HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType); 133 return (handler instanceof AsyncHandlerMethodReturnValueHandler && 134 ((AsyncHandlerMethodReturnValueHandler) handler).isAsyncReturnValue(returnValue, returnType)); 135 } 136 137 @Override 138 @Nullable 139 public ListenableFuture<?> toListenableFuture(Object returnValue, MethodParameter returnType) { 140 HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType); 141 if (handler instanceof AsyncHandlerMethodReturnValueHandler) { 142 return ((AsyncHandlerMethodReturnValueHandler) handler).toListenableFuture(returnValue, returnType); 143 } 144 return null; 145 } 146 147}