001/*
002 * Copyright 2002-2018 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.core;
018
019import org.springframework.lang.Nullable;
020import org.springframework.messaging.Message;
021import org.springframework.messaging.converter.MessageConversionException;
022import org.springframework.messaging.converter.MessageConverter;
023
024/**
025 * An extension of {@link AbstractMessageSendingTemplate} that adds support for
026 * receive style operations as defined by {@link MessageReceivingOperations}.
027 *
028 * @author Mark Fisher
029 * @author Rossen Stoyanchev
030 * @author Stephane Nicoll
031 * @since 4.1
032 * @param <D> the destination type
033 */
034public abstract class AbstractMessageReceivingTemplate<D> extends AbstractMessageSendingTemplate<D>
035                implements MessageReceivingOperations<D> {
036
037        @Override
038        @Nullable
039        public Message<?> receive() {
040                return doReceive(getRequiredDefaultDestination());
041        }
042
043        @Override
044        @Nullable
045        public Message<?> receive(D destination) {
046                return doReceive(destination);
047        }
048
049        /**
050         * Actually receive a message from the given destination.
051         * @param destination the target destination
052         * @return the received message, possibly {@code null} if the message could not
053         * be received, for example due to a timeout
054         */
055        @Nullable
056        protected abstract Message<?> doReceive(D destination);
057
058
059        @Override
060        @Nullable
061        public <T> T receiveAndConvert(Class<T> targetClass) {
062                return receiveAndConvert(getRequiredDefaultDestination(), targetClass);
063        }
064
065        @Override
066        @Nullable
067        public <T> T receiveAndConvert(D destination, Class<T> targetClass) {
068                Message<?> message = doReceive(destination);
069                if (message != null) {
070                        return doConvert(message, targetClass);
071                }
072                else {
073                        return null;
074                }
075        }
076
077        /**
078         * Convert from the given message to the given target class.
079         * @param message the message to convert
080         * @param targetClass the target class to convert the payload to
081         * @return the converted payload of the reply message (never {@code null})
082         */
083        @SuppressWarnings("unchecked")
084        @Nullable
085        protected <T> T doConvert(Message<?> message, Class<T> targetClass) {
086                MessageConverter messageConverter = getMessageConverter();
087                T value = (T) messageConverter.fromMessage(message, targetClass);
088                if (value == null) {
089                        throw new MessageConversionException(message, "Unable to convert payload [" + message.getPayload() +
090                                        "] to type [" + targetClass + "] using converter [" + messageConverter + "]");
091                }
092                return value;
093        }
094
095}