/* * Copyright 2002-2011 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.flex.messaging; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.flex.config.BeanIds; import org.springframework.util.Assert; import flex.messaging.FlexContext; import flex.messaging.MessageBroker; import flex.messaging.MessageDestination; import flex.messaging.messages.AsyncMessage; import flex.messaging.services.messaging.adapters.ActionScriptAdapter; import flex.messaging.services.messaging.adapters.MessagingAdapter; import flex.messaging.util.UUIDUtils; /** * Simple helper for sending Flex {@link AsyncMessage}s from a Java client. The message will be routed through the * {@link MessageBroker} to the specified {@link MessageDestination}. This allows for flexible routing of the message * using whatever {@link MessagingAdapter} is configured for the target destination, be it the basic BlazeDS * {@link ActionScriptAdapter}, one of the provided Spring adapters such as {@link org.springframework.flex.messaging.jms.JmsAdapter} * or {@link org.springframework.flex.messaging.integration.IntegrationAdapter}, or some other custom adapter implementation. * * <p>This class should typically be configured as a Spring bean in the same ApplicationContext as the <flex:message-broker> tag * to allow injection of a Spring-managed {@link MessageBroker} instance. When a single <code>MessageBroker</code> is detected in the * ApplicationContext, it will be automatically injected into the MessageTemplate bean. If more than one <code>MessageBroker</code> is * present (not typical), a reference to the correct <code>MessageBroker</code> must be explicitly set for the {@link MessageTemplate#setMessageBroker(MessageBroker)} * property. * * <p>The <code>MessageTemplate</code> may also be instantiated directly, in which case it will try to look up the ThreadLocal * <code>MessageBroker</code> instance for the current request, but configuration as a Spring bean is strongly preferred. * * @author Jeremy Grelle */ public class MessageTemplate implements InitializingBean, BeanFactoryAware { private static final Log log = LogFactory.getLog(MessageTemplate.class); private String defaultDestination; private MessageBroker messageBroker; private BeanFactory beanFactory; private final String clientId = UUIDUtils.createUUID(); private final AsyncMessageCreator defaultMessageCreator = new DefaultAsyncMessageCreator(); /** * * {@inheritDoc} */ public void afterPropertiesSet() throws Exception { if (this.messageBroker == null) { // first try the default id if (this.beanFactory.containsBean(BeanIds.MESSAGE_BROKER)) { this.messageBroker = (MessageBroker) this.beanFactory.getBean(BeanIds.MESSAGE_BROKER, MessageBroker.class); } else if (this.beanFactory instanceof ListableBeanFactory) { ListableBeanFactory lbf = (ListableBeanFactory) this.beanFactory; String[] brokerNames = lbf.getBeanNamesForType(MessageBroker.class); if (brokerNames.length == 1) { this.messageBroker = (MessageBroker) lbf.getBean(brokerNames[0]); } else if (brokerNames.length > 1) { log.warn("A MessageBroker was not explicitly set and one could not be auto-detected in the MessageTemplate's bean factory as " + "multiple MessageBrokers were found. Will fall back to attempting to obtain the MessageBroker from the FlexContext for " + "each operation."); } else { log.warn("A MessageBroker was not explicitly set and one could not be found in the MessageTemplate's bean factory. Will " + "will fall back to attempting to obtain the MessageBroker from the FlexContext for each operation."); } } } } /** * Creates a default {@link AsyncMessage} * * @return the created message */ public AsyncMessage createMessage() { return this.defaultMessageCreator.createMessage(); } /** * Creates a default {@link AsyncMessage} for a specified destination * * @param destination the target destination for the message * @return the created message */ public AsyncMessage createMessageForDestination(String destination) { AsyncMessage message = this.defaultMessageCreator.createMessage(); message.setDestination(destination); return message; } /** * Returns the id of the default message destination for this template * * @return the default destination id */ public String getDefaultDestination() { return this.defaultDestination; } /** * Returns the {@link MessageBroker} for routing messages * * @return the message broker */ public MessageBroker getMessageBroker() { if (this.messageBroker != null) { return this.messageBroker; } Assert.notNull(FlexContext.getMessageBroker(), "A MessageBroker was not set on the MessageTemplate " + "and no thread-local MessageBroker could be found in the FlexContext."); return FlexContext.getMessageBroker(); } /** * Sends a message created by the specified {@link AsyncMessageCreator} * * @param creator the message creator */ public void send(AsyncMessageCreator creator) { getMessageBroker().routeMessageToService(creator.createMessage(), null); } /** * Sends a message with the specified body to the default destination. * * @param body the body of the message */ public void send(Object body) { Assert.hasText(this.defaultDestination, "Cannot send message - no default destination has been set for this MessageTemplate."); send(this.defaultDestination, body); } /** * Sends a message with the specified body to the specified destination * * @param destination the target destination id * @param body the body of the message */ public void send(String destination, Object body) { AsyncMessage message = this.defaultMessageCreator.createMessage(); message.setDestination(destination); message.setBody(body); getMessageBroker().routeMessageToService(message, null); } /** * * {@inheritDoc} */ public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } /** * Sets the id of the default message destination for this template * * @param defaultDestination the default destination id */ public void setDefaultDestination(String defaultDestination) { this.defaultDestination = defaultDestination; } /** * Sets the {@link MessageBroker} for routing messages * * @param messageBroker the message broker */ public void setMessageBroker(MessageBroker messageBroker) { this.messageBroker = messageBroker; } private final class DefaultAsyncMessageCreator implements AsyncMessageCreator { public AsyncMessage createMessage() { AsyncMessage message = new AsyncMessage(); message.setClientId(MessageTemplate.this.clientId); message.setMessageId(UUIDUtils.createUUID()); message.setTimestamp(System.currentTimeMillis()); return message; } } }