All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.eBus.messages.EMessage Maven / Gradle / Ivy

//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this library; if not, write to the
//
// Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330,
// Boston, MA
// 02111-1307 USA
//
// The Initial Developer of the Original Code is Charles W. Rapp.
// Portions created by Charles W. Rapp are
// Copyright (C) 2001 - 2011, 2013, 2016. Charles W. Rapp.
// All Rights Reserved.
//

package net.sf.eBus.messages;

import java.io.Serializable;

/**
 * {@code EMessage} is the base class for all eBus messages and
 * contains the message subject and timestamp.
 * Application messages do not extend this class
 * directly but one of the subclasses:
 * {@link ENotificationMessage}, {@link ERequestMessage}, or
 * {@link EReplyMessage}.
 * 

* Note: messages are limited to 31 fields. This * is due to eBus binary serialization format. This number is * decreased to 29 fields for sub-classes because * {@code EMessage} used two fields: {@link #subject} and * {@link #timestamp}. The work-around to this limitation is to * group fields into an {@link EField} subclass, which is allowed * to have 31 fields of its own. So if a message class uses two * {@code EField} subclasses, it may contain up to 62 fields with * 31 in each field subclass. *

*

* Note: a {@code EMessage} subclass may * not be used as a message field itself. That means * that a message may not contain another message as a field. * Again, the work-around is to group fields which are common to * multiple {@code EMessage} subclasses in an {@code EField} and * use that field subclass in the message subclasses. *

*

* This class is immutable. *

*

De-serialization Constructor

* All {@code EMessage} and {@code EField} subclasses are * required to provide a {@code public} * constructor used to instantiate a de-serialized message. An * example is provided as way of explanation. Consider a * user-defined message class {@code OrderReply} which extends * {@link EReplyMessage} and with the following fields: *

 * public final OrderPart[] parts;
 * public final BigDecimal shippingCost;
 * public final BigDecimal totalPrice;
 * 
* {@code EFieldInfo} defines the field order as * {@code &at;fields={parts, shippingCost, totalPrice}}. Given this * information, {@code OrderReply} must define the following * constructor: *

 * public OrderReply(final String subject,
 *                   final long timestamp,
 *                   final EReplyMessage.ReplyStatus status,
 *                   final String reason,
 *                   OrderPart[] parts,
 *                   BigDecimal shipping,
 *                   BigDecimal totalPx)
 * {
 *     super (subject, timestamp, status, reason);
 *
 *     this.parts = parts;
 *     this.shippingCost = shipping;
 *     this.totalPrice = totalPx;
 *
 *     // Other user code goes here if needed.
 * }
 * 
* Because {@code OrderReply} is a reply message, {@code subject} * and {@code timestamp} are inherited from {@code EMessage} and * {@code status} and {@code reason} are inherited from * {@code EReplyMessage}. Therefore, these fields must also be * included in the constructor. *

Message Compilation

* Note: as of eBus 4.4.0, messages are * automatically compiled when first used for serialization * or de-serialization. This increases the time it takes to * send or receive a message the first time. When a message * is frequently transmitted, it is recommended that the * message class is "compiled" by calling * {@link net.sf.eBus.messages.type.DataType#findType(java.lang.Class)} * for that message class. So when a message is sent or received * the first time, the message compilation is already done. *

* Message compilation also compiles all {@code EField} classes * contained in the message class. Compilation cascades down to * leaf fields which are pre-defined eBus field types. *

* * @see EMessageHeader * @see EMessageObject * @see ENotificationMessage * @see ERequestMessage * @see EReplyMessage * @see EField * * @author Charles Rapp */ @EFieldInfo (fields = {"subject", "timestamp"}) public abstract class EMessage extends EMessageObject implements Serializable { //--------------------------------------------------------------- // Enums. // /** * Messages are divided into four types: notification, * request, reply and system. System messages are reserved * for use by the eBus system itself and may not be used * by applications. */ public enum MessageType { /** * A notification is an event with an associated * subject. Notifications are routed by subject. */ NOTIFICATION (ENotificationMessage.class), /** * A request contains a subject and request identifier * and is routed by subject. */ REQUEST (ERequestMessage.class), /** * A reply contains a subject, request identifier, * reply status and optional reason. Replies are routed * by their destination address. The destination is * the corresponding request source address. */ REPLY (EReplyMessage.class), /** * eBus system message. Reserved for use by the eBus * system and may not be used by applications. */ SYSTEM (ESystemMessage.class); //----------------------------------------------------------- // Member methods. // //------------------------------------------------------- // Constructors. // private MessageType(final Class mc) { mMsgClass = mc; } // end of MessageType(Class) // // end of Constructors. //------------------------------------------------------- //------------------------------------------------------- // Get Methods. // /** * Returns the associated message class. * @return message class. */ public Class messageClass() { return (mMsgClass); } // end of messageClass() /** * Returns {@code true} if {@code mc} is not {@code null} * and is assignable from this message type. * @param mc check if this message class matches this * type. * @return {@code true} if {@code mc} matches this * message type. */ public boolean isMatching(final Class mc) { return (mc != null && mMsgClass.isAssignableFrom(mc)); } // end of isMatching(Class) // // end of Get Methods. //------------------------------------------------------- //----------------------------------------------------------- // Member data. // /** * Message class associated with this message type. */ private final Class mMsgClass; } // end of enum MessageType //--------------------------------------------------------------- // Member data. // //----------------------------------------------------------- // Constants. // /** * Serialization version identifier. */ private static final long serialVersionUID = 0x040400L; //----------------------------------------------------------- // Locals. // /** * The required message subject. The subject and the message * class are used to route this message to the intended * eBus clients. */ public final String subject; /** * The message timestamp in Java millisecond epoch time. */ public final long timestamp; /** * The message type. Either notification, request, reply, or * system. */ private final MessageType mMessageType; /** * The message key combining the message class and subject. */ private final EMessageKey mKey; //--------------------------------------------------------------- // Member methods. // //----------------------------------------------------------- // Constructors. // /** * Creates a new eBus message for the given subject and * timestamp. The message type defaults to * {@link MessageType#SYSTEM}. *

* This constructor is required to be {@code public} by * {@link net.sf.eBus.messages.type.MessageType#load}. * @param subject the message timestamp. * @param timestamp the message timestamp in Java, * millisecond epoch time. * @throws IllegalArgumentException * if {@code subject} is either {@code null} or empty. * @throws InvalidMessageException * if this message violates the eBus correct message rules. */ public EMessage(final String subject, final long timestamp) throws IllegalArgumentException, InvalidMessageException { this (subject, timestamp, MessageType.SYSTEM); } // end of EMessage(String, long) /** * Creates a new eBus message based on the given subject, * timestamp, and message type. * @param subject the message subject. * @param timestamp the message timestamp in Java, * millisecond epoch time. * @param msgType the message type. * @throws IllegalArgumentException * if: *

    *
  • * {@code subject} is either of {@code null} or empty; *
  • *
  • * {@code msgType} is {@code null}. *
  • *
* @throws InvalidMessageException * if this message violates the eBus correct message rules. */ /* package */ EMessage(final String subject, final long timestamp, final MessageType msgType) throws IllegalArgumentException, InvalidMessageException { if (subject == null || subject.isEmpty() == true) { throw ( new IllegalArgumentException( "null or empty subject")); } else if (msgType == null) { throw (new IllegalArgumentException("null msgType")); } this.subject = subject; this.timestamp = timestamp; this.mMessageType = msgType; this.mKey = new EMessageKey(this.getClass(), subject); } // end of EMessage(String, long, MessageType) // // end of Constructors. //----------------------------------------------------------- //----------------------------------------------------------- // Object Method Overrides. // /** * Returns {@code true} if {@code o} is a * non-{@code null EMessage} instance with a subject and * timestamp equal to {@code this EMessage} instance and * {@code false} otherwise. * @param o comparison object. * @return {@code true} if the message fields are equal * and {@code false} otherwise. */ @Override public boolean equals(final Object o) { boolean retcode = (this == o); if (retcode == false && o instanceof EMessage) { final EMessage msg = (EMessage) o; retcode = (subject.equals(msg.subject) == true && timestamp == msg.timestamp); } return (retcode); } // end of equals(Object) /** * Returns the message header hash code. * @return the message header hash code. */ @Override public int hashCode() { return ((subject.hashCode() * 37) + (Long.valueOf(timestamp)).hashCode()); } // end of hashCode() /** * Returns the message subject and timestamp as a string. * @return the message as text. */ @Override public String toString() { return ( String.format( "%1$s:%2$s%n timestamp: %3$tY/%3$tm/%3$td %3$tH:%3$tM:%3$tS.%3$tL", this.getClass(), subject, new java.util.Date(timestamp))); } // end of toString() // // end of Object Method Overrides. //----------------------------------------------------------- //----------------------------------------------------------- // Get methods. // /** * Returns the unique message key based on the message class * and subject. * @return the unique message key based on the message class * and subject. */ public EMessageKey key() { return (mKey); } // end of key() /** * Returns the * {@link net.sf.eBus.messages.EMessage.MessageType message type}. * @return the message type. */ public MessageType messageType() { return (mMessageType); } // end of messageType() /** * Returns {@code true} if this is a system message and * {@code false} otherwise. Only eBus is allowed to transmit * a system message. * @return {@code true} if this is a system message and * {@code false} otherwise. */ public boolean isSystemMessage() { return (mMessageType == MessageType.SYSTEM); } // end of isSystemMessage() /** * Returns {@code true} if this is an application * message and {@code false} otherwise. * @return {@code true} if this is an application * message and {@code false} otherwise. */ public boolean isApplicationMessage() { return (mMessageType != MessageType.SYSTEM); } // end of isApplicationMessage() // // end of Get methods. //----------------------------------------------------------- } // end of class EMessage




© 2015 - 2025 Weber Informatics LLC | Privacy Policy