/* * 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.common.client.api.ErrorCallback; import org.jboss.errai.bus.client.api.messaging.Message; import org.jboss.errai.bus.client.api.messaging.MessageBus; import org.jboss.errai.bus.client.api.messaging.RequestDispatcher; import org.jboss.errai.bus.client.api.RoutingFlag; import org.jboss.errai.common.client.api.Assert; import org.jboss.errai.common.client.api.ResourceProvider; import org.jboss.errai.common.client.protocols.MessageParts; import org.jboss.errai.common.client.types.TypeHandlerFactory; import java.util.HashMap; import java.util.Map; /** * The default implementation of the Message interface. The usual way to create a CommandMessage is through the * {@link MessageBuilder} API. * * @see ConversationMessage * @see MessageBuilder * @author Mike Brock * @author Max Barkley <mbarkley@redhat.com> */ @SuppressWarnings({"UnusedDeclarations"}) public class CommandMessage implements Message { transient final Map<String, ResourceProvider<?>> providedParts; final Map<String, Object> parts; transient Map<String, Object> resources; ErrorCallback errorsCall; int routingFlags; /** * Creates a new CommandMessage with no parts and no provided parts. * * @return a new instance of CommandMessage. */ public static CommandMessage create() { return new CommandMessage(); } /** * Creates a new CommandMessage with the given parts and no provided parts. * <p> * Note that {@link MessageBuilder} is the preferred API for creating Message * instances. * * @param parts * The parts that this message should have initially. This map is * taken as-is. No copy is made. Changes to the provided map will be * reflected in this message, and additional parts given to this * message will appear in the provided map. */ public static CommandMessage createWithParts(final Map<String, Object> parts) { return new CommandMessage(Assert.notNull(parts)); } @SuppressWarnings("unchecked") public static CommandMessage createWithPartsFromRawMap(final Map parts) { return new CommandMessage(parts); } public static CommandMessage createWithParts(final Map<String, Object> parts, final int flags) { return new CommandMessage(Assert.notNull(parts), flags); } /** * Creates a new CommandMessage with the given parts and provided parts. * <p> * Note that {@link MessageBuilder} is the preferred API for creating Message * instances. * * @param parts * The parts that this message should have initially. This map is * taken as-is. No copy is made. Changes to the provided map will be * reflected in this message, and additional parts given to this * message will appear in the provided map. * @param provided * The provided parts that this message should have initially. This * map is taken as-is. No copy is made. Changes to the provided map * will be reflected in this message, and additional parts given to * this message will appear in the provided map. */ public static CommandMessage createWithParts(final Map<String, Object> parts, final Map<String, ResourceProvider<?>> provided) { return new CommandMessage(parts, provided); } CommandMessage() { this.parts = new HashMap<String, Object>(); this.providedParts = new HashMap<String, ResourceProvider<?>>(5); } private CommandMessage(final Map<String, Object> parts) { this.parts = parts; this.providedParts = new HashMap<String, ResourceProvider<?>>(0); } public CommandMessage(final Map<String, Object> parts, final int routingFlags) { this.parts = parts; this.routingFlags = routingFlags; this.providedParts = new HashMap<String, ResourceProvider<?>>(5); } private CommandMessage(final Map<String, Object> parts, final Map<String, ResourceProvider<?>> providers) { this.parts = parts; this.providedParts = providers; } @Override public String getCommandType() { return (String) parts.get(MessageParts.CommandType.name()); } @Override public String getSubject() { return String.valueOf(parts.get(MessageParts.ToSubject.name())); } @Override public Message toSubject(final String subject) { parts.put(MessageParts.ToSubject.name(), subject); return this; } @Override public Message command(final Enum<?> type) { parts.put(MessageParts.CommandType.name(), type.name()); return this; } @Override public Message command(final String type) { parts.put(MessageParts.CommandType.name(), type); return this; } @Override public Message set(final Enum<?> part, final Object value) { return set(part.name(), value); } @Override public Message set(final String part, final Object value) { parts.put(part, value); return this; } @Override public Message setProvidedPart(final String part, final ResourceProvider<?> provider) { providedParts.put(part, provider); return this; } @Override public Message setProvidedPart(final Enum<?> part, final ResourceProvider<?> provider) { return setProvidedPart(part.name(), provider); } @Override public void remove(final String part) { parts.remove(part); } @Override public void remove(final Enum<?> part) { parts.remove(part.name()); } @Override public Message copy(final Enum<?> part, final Message message) { set(part, message.get(Object.class, part)); return this; } @Override public Message copy(final String part, final Message message) { set(part, message.get(Object.class, part)); return this; } @Override public Message setFlag(final RoutingFlag flag) { routingFlags |= flag.flag(); return this; } @Override public void unsetFlag(final RoutingFlag flag) { if ((routingFlags & flag.flag()) != 0) { routingFlags ^= flag.flag(); } } @Override public boolean isFlagSet(final RoutingFlag flag) { return (routingFlags & flag.flag()) != 0; } @Override public <T> T getValue(Class<T> type) { return get(type, MessageParts.Value); } @Override @SuppressWarnings({ "UnusedDeclaration" }) public <T> T get(final Class<T> type, final Enum<?> part) { return get(type, part.toString()); } @Override @SuppressWarnings({ "UnusedDeclaration" }) public <T> T get(final Class<T> type, final String part) { final Object value = parts.get(part); return value == null ? null : TypeHandlerFactory.convert(value.getClass(), type, value); } @Override public boolean hasPart(final Enum<?> part) { return hasPart(part.name()); } @Override public boolean hasPart(final String part) { return parts.containsKey(part); } @Override public Map<String, Object> getParts() { return parts; } @Override public Map<String, ResourceProvider<?>> getProvidedParts() { return providedParts; } @Override public Message setParts(final Map<String, Object> parts) { parts.clear(); parts.putAll(parts); return this; } @Override public Message addAllParts(final Map<String, Object> parts) { this.parts.putAll(parts); return this; } @Override public Message addAllProvidedParts(final Map<String, ResourceProvider<?>> parts) { this.providedParts.putAll(parts); return this; } @Override public Message setResource(final String key, final Object res) { if (this.resources == null) this.resources = new HashMap<String, Object>(); this.resources.put(key, res); return this; } @Override @SuppressWarnings("unchecked") public <T> T getResource(final Class<T> type, final String key) { return (T) (this.resources == null ? null : this.resources.get(key)); } @Override public Message copyResource(final String key, final Message copyFrom) { if (!copyFrom.hasResource(key)) { throw new RuntimeException("Cannot copy resource '" + key + "': no such resource."); } setResource(key, copyFrom.getResource(Object.class, key)); return this; } @Override public Message errorsCall(final ErrorCallback callback) { if (this.errorsCall != null) { throw new RuntimeException("An ErrorCallback is already registered"); } this.errorsCall = callback; return this; } @Override public ErrorCallback getErrorCallback() { return errorsCall; } @Override public boolean hasResource(final String key) { return this.resources != null && this.resources.containsKey(key); } @Override public void addResources(final Map<String, ?> resources) { if (this.resources == null) { this.resources = new HashMap<String, Object>(resources); } else { this.resources.putAll(resources); } } @Override public void commit() { if (!providedParts.isEmpty()) { for (final Map.Entry<String, ResourceProvider<?>> entry : providedParts.entrySet()) set(entry.getKey(), entry.getValue().get()); } } @Override public boolean isCommited() { return isFlagSet(RoutingFlag.Committed); } @Override public void sendNowWith(final MessageBus viaThis) { if (ConversationHelper.hasConversationCallback(this)) { ConversationHelper.createConversationService(viaThis, this); } viaThis.send(this); } @Override public void sendNowWith(final RequestDispatcher viaThis) { try { viaThis.dispatch(this); } catch (Exception e) { throw new MessageDeliveryFailure("could not deliver message: " + e.getMessage(), e); } } @Override public String toString() { return buildDescription(); } private String buildDescription() { final StringBuilder append = new StringBuilder(); boolean f = false; for (final Map.Entry<String, Object> entry : parts.entrySet()) { if (f) append.append(", "); append.append(entry.getKey()).append("=").append(String.valueOf(entry.getValue())); f = true; } return append.toString(); } }