/*
* Copyright (C) 2011 Red Hat, Inc. and/or its affiliates.
*
* 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.jboss.errai.bus.client.api.base;
import org.jboss.errai.bus.client.api.BusErrorCallback;
import org.jboss.errai.bus.client.api.HasEncoded;
import org.jboss.errai.bus.client.api.RoutingFlag;
import org.jboss.errai.bus.client.api.builder.DefaultRemoteCallBuilder;
import org.jboss.errai.bus.client.api.builder.MessageBuildCommand;
import org.jboss.errai.bus.client.api.builder.MessageBuildSendableWithReply;
import org.jboss.errai.bus.client.api.builder.MessageBuildSubject;
import org.jboss.errai.bus.client.api.builder.MessageReplySendable;
import org.jboss.errai.bus.client.api.messaging.Message;
import org.jboss.errai.bus.client.api.messaging.MessageProvider;
import org.jboss.errai.common.client.api.RemoteCallback;
/**
* The MessageBuilder API provides a fluent method of building Messages.
*
* <h3>Example Message:</h3>
*
* <pre>
* Message m = MessageBuilder
* .createMessage()
* .toSubject("TheMessageSubject")
* .withValue("Hello everyone").done();
* </pre>
* <p>
* You can transmit a message using the the <tt>sendNowWith(RequestDispatcher)</tt> method by providing an instance of
* {@link org.jboss.errai.bus.client.api.messaging.MessageBus}.
* <p>
* Messages can be constructed using user-defined standard protocols through the use of enumerations. Both
* <tt>commandType</tt> and message parts can be defined through the use of enumerations. This helps create
* strongly-defined protocols for communicating with services. For instance:
*
* <pre>
* public enum LoginParts {
* Username, Password
* }
* </pre>
*
* .. and ..
*
* <pre>
* public enum LoginCommands {
* Login, Logout
* }
* </pre>
*
* A service can then use these enumerations to build and decode messages. For example:
*
* <pre>
* MessageBuilder
* .createMessage()
* .toSubject("LoginService")
* .command(LoginCommands.Login)
* .set(LoginParts.Username, "foo")
* .set(LoginParts.Password, "bar")
* .sendNowWith(busInstance);
* </pre>
*
* Messages may contain serialized objects that are annotated with
* {@link org.jboss.errai.common.client.api.annotations.Portable} and can be marshalled by the built-in Errai
* marshallers or by user-provided marshallers that have been registered with the system.
*
* @author Mike Brock
*/
public class MessageBuilder {
private static MessageProvider provider = new MessageProvider() {
@Override
public Message get() {
return CommandMessage.create();
}
};
/**
* Creates a new message.
*
* @return a <tt>MessageBuildSubject</tt> which essentially is a <tt>Message</tt>, but ensures that the user
* constructs messages properly
*/
@SuppressWarnings({ "unchecked" })
public static MessageBuildSubject<MessageBuildSendableWithReply> createMessage() {
return new DefaultMessageBuilder(provider.get()).start();
}
/**
* Creates a new message for the provided subject.
*
* @param subject
* the subject the message should be sent to
* @return a <tt>MessageBuildSubject</tt> which essentially is a <tt>Message</tt>, but ensures that the user
* constructs messages properly
*/
@SuppressWarnings({ "unchecked" })
public static MessageBuildCommand<MessageBuildSendableWithReply> createMessage(final String subject) {
return new DefaultMessageBuilder(provider.get()).start().toSubject(subject);
}
/**
* Creates a conversational message.
*
* @param message
* reference message to create conversation from
* @return a <tt>MessageBuildSubject</tt> which essentially is a <tt>Message</tt>, but ensures that the user
* constructs messages properly
*/
public static MessageBuildSubject<MessageReplySendable> createConversation(final Message message) {
final Message newMessage = provider.get();
newMessage.setFlag(RoutingFlag.NonGlobalRouting);
if (newMessage instanceof HasEncoded) {
return new DefaultMessageBuilder<MessageReplySendable>(new HasEncodedConvMessageWrapper(message, newMessage))
.start();
}
else {
return new DefaultMessageBuilder<MessageReplySendable>(new ConversationMessageWrapper(message, newMessage))
.start();
}
}
/**
* Creates a conversational message for the provided subject.
*
* @param message
* reference message to create conversation from
* @param subject
* the subject the message should be sent to
* @return a <tt>MessageBuildSubject</tt> which essentially is a <tt>Message</tt>, but ensures that the user
* constructs messages properly
*/
public static MessageBuildCommand<MessageReplySendable> createConversation(final Message message, final String subject) {
final Message newMessage = provider.get();
if (newMessage instanceof HasEncoded) {
return new DefaultMessageBuilder<MessageReplySendable>(new HasEncodedConvMessageWrapper(message, newMessage))
.start()
.toSubject(subject);
}
else {
return new DefaultMessageBuilder<MessageReplySendable>(new ConversationMessageWrapper(message, newMessage))
.start()
.toSubject(subject);
}
}
/**
* Creates an <tt>AbstractRemoteCallBuilder</tt> to construct a call.
*
* @return an instance of <tt>AbstractRemoteCallBuilder</tt>
*/
public static DefaultRemoteCallBuilder createCall() {
return new DefaultRemoteCallBuilder(CommandMessage.create());
}
/**
* Creates an RPC call, with no error handling.
*
* @param callback
* The remote callback that receives the return value from the call. Cannot not be null.
* @param service
* The remote interface.
* @param <T>
* The type of the remote service.
* @param <R>
* The return type of the invoked method.
* @return A proxy for the remote service. Methods invoked on this object will communicate with the remote service
* over the message bus.
*/
public static <R, T> T createCall(final RemoteCallback<R> callback, final Class<T> service) {
return new DefaultRemoteCallBuilder(CommandMessage.create()).call(callback, service);
}
/**
* Creates an RPC call with error handling.
*
* @param callback
* The remote callback that receives the return value from the call. Cannot not be null.
* @param errorCallback
* The error callback that receives transmission errors and exceptions thrown by the remote service. Cannot not be null.
* @param service
* The remote interface.
* @param <T>
* The type of the remote service.
* @param <R>
* The return type of the invoked method.
* @return A proxy for the remote service. Methods invoked on this object will communicate with the remote service
* over the message bus.
*/
public static <R, T> T createCall(final RemoteCallback<R> callback, final BusErrorCallback errorCallback, final Class<T> service) {
return new DefaultRemoteCallBuilder(CommandMessage.create()).call(callback, errorCallback, service);
}
/**
* Sets the message provider for this instance of <tt>MessageBuilder</tt>.
*
* @param provider to set this' provider to
*/
public static void setMessageProvider(final MessageProvider provider) {
MessageBuilder.provider = provider;
}
/**
* Returns the message provider.
*
* @return the message provider used by this instance of <tt>MessageBuilder</tt>.
*/
public static MessageProvider getMessageProvider() {
return provider;
}
}