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

net.sf.eBus.client.sysmessages.AbstractKeyMessage Maven / Gradle / Ivy

The newest version!
//
// Copyright 2015, 2016, 2019, 2020 Charles W. Rapp
//
// 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 net.sf.eBus.client.sysmessages;

import com.google.common.base.Strings;
import java.io.Serializable;
import net.sf.eBus.messages.EMessage;
import net.sf.eBus.messages.EMessageKey;
import net.sf.eBus.messages.EMessageObject;
import net.sf.eBus.messages.ESystemMessage;
import net.sf.eBus.messages.UnknownMessageException;
import net.sf.eBus.util.Validator;

/**
 * Base class for all system messages which contain a message
 * class name and message subject. The reason for sending a
 * message key as a separate message class name and subject is
 * due to the receiving eBus application failing to de-serialize
 * the message key because {@code Class.forName} throwing
 * {@code ClassNotFoundException}. It is entirely reasonable for
 * connected eBus applications not to use exactly the same
 * message set. Therefore, if an eBus application receives a
 * message class name for a class it doesn't know about, that
 * inbound message will successfully deserialize but is ignored.
 *
 * @author Charles W. Rapp
 */

public abstract class AbstractKeyMessage
    extends ESystemMessage
    implements Serializable
{
//---------------------------------------------------------------
// Member data.
//

    //-----------------------------------------------------------
    // Constants.
    //

    /**
     * Serialization version identifier.
     */
    private static final long serialVersionUID = 0x050200L;

    //-----------------------------------------------------------
    // Locals.
    //

    /**
     * The message key class name. The class name is transmitted
     * rather than the {@code Class} instance because the far-end
     * deserialization will fail if the {@code Class} is
     * unknown.
     */
    public final String messageClass;

    /**
     * The message key subject.
     */
    public final String messageSubject;

//---------------------------------------------------------------
// Member methods.
//

    //-----------------------------------------------------------
    // Constructors.
    //

    /**
     * Creates a new abstract key message from the configured
     * message builder.
     * @param builder message builder.
     */
    protected AbstractKeyMessage(final Builder builder)
    {
        super (builder);

        this.messageClass = builder.mMessageClass;
        this.messageSubject = builder.mMessageSubject;
    } // end of AbstractKeyMessage(Builder)

    //
    // end of Constructors.
    //-----------------------------------------------------------

    //-----------------------------------------------------------
    // Object Method Overrides.
    //

    /**
     * Returns {@code true} if {@code o} is a
     * non-{@code null AdMessage} instance with ad status,
     * message class, and message type equal to
     * {@code this AdMessage} instance and {@code false}
     * otherwise.
     * @param o comparison object.
     * @return {@code true} if the message fields are equal
     * and {@code false} otherwise.
     */
    // Calling super.equals is *never* silly.
    @SuppressWarnings({"java:S2159"})
    @Override
    public boolean equals(final Object o)
    {
        boolean retcode = super.equals(o);

        if (!retcode && o instanceof AbstractKeyMessage)
        {
            final AbstractKeyMessage keyMsg =
                (AbstractKeyMessage) o;

            retcode =
                (messageClass.equals(keyMsg.messageClass) &&
                 messageSubject.equals(keyMsg.messageSubject));
        }

        return (retcode);
    } // end of equals(Object)

    /**
     * Returns the advertisement message hash code.
     * @return the advertisement message hash code.
     */
    @Override
    public int hashCode()
    {
        return (
            (((super.hashCode() * 37) +
              messageClass.hashCode()) * 37) +
            messageSubject.hashCode());
    } // end of hashCode()

    /**
     * Returns a human-readable text version of this message.
     * @return text version of this message.
     */
    @Override
    public String toString()
    {
        return (
            String.format(
                "%s%n            message key: %s/%s",
                super.toString(),
                messageClass,
                messageSubject));
    } // end of toString()

    //
    // end of Object Method Overrides.
    //-----------------------------------------------------------

    //-----------------------------------------------------------
    // Get Methods.
    //

    /**
     * Returns the message key based on the message class name
     * and subject.
     * @return the message key.
     * @throws UnknownMessageException
     * if {@link #messageClass} is an unknown class name.
     */
    @SuppressWarnings ("unchecked")
    public final EMessageKey messageKey()
        throws UnknownMessageException
    {
        final Class mc;

        try
        {
            mc =
                (Class)
                    Class.forName(messageClass);
        }
        catch (ClassNotFoundException classex)
        {
            throw (new UnknownMessageException(messageClass));
        }

        return (new EMessageKey(mc, messageSubject));
    } // end of messageKey()

    //
    // end of Get Methods.
    //-----------------------------------------------------------

//---------------------------------------------------------------
// Member methods.
//

    /**
     * Base class for all {@link AbstractKeyMessage} builders.
     * Provides message class and subject validation.
     *
     * @param  builds this target message class.
     * @param  message builder subclass. Needed to return the
     * correct builder type when setting fields. If this were not
     * the case, field chaining would not work.
     */
    public abstract static class Builder>
        extends ESystemMessage.Builder
    {
    //-----------------------------------------------------------
    // Member data.
    //

        //-------------------------------------------------------
        // Locals.
        //

        /**
         * Configured message class.
         */
        private String mMessageClass;

        /**
         * Configured message subject.
         */
        private String mMessageSubject;

    //-----------------------------------------------------------
    // Member methods.
    //

        //-------------------------------------------------------
        // Constructors.
        //

        protected Builder(final Class targetClass)
        {
            super (targetClass);
        } // end of Builder(Class)

        //
        // end of Constructors.
        //-------------------------------------------------------

        //-------------------------------------------------------
        // Builder Method Overrides.
        //

        /**
         * Checks if the message class and subject are
         * configured. If not, then appends those problems to the
         * list.
         * @param problems used to check field validity and
         * collect discovered invalid fields.
         * @return {@code problems} to allow for method chaining.
         */
        @Override
        protected Validator validate(final Validator problems)
        {
            // Note: only check for null since message class
            // and subject cannot be set to an empty string.
            return (super.validate(problems)
                         .requireNotNull(mMessageClass,
                                         "message class")
                         .requireNotNull(mMessageSubject,
                                         "message subject"));
        } // end of validate(Validator)

        //
        // end of Builder Method Overrides.
        //-------------------------------------------------------

        //-------------------------------------------------------
        // Set Methods.
        //

        /**
         * Sets the message class name to the given value.
         * @param mc message class name.
         * @return {@code this} message builder.
         * @throws IllegalArgumentException
         * if {@code mc} is {@code null} or empty.
         */
        @SuppressWarnings ("unchecked")
        public final B messageClass(final String mc)
        {
            if (Strings.isNullOrEmpty(mc))
            {
                throw (
                    new IllegalArgumentException(
                        "mc is null or empty"));
            }

            mMessageClass = mc;

            return ((B) this);
        } // end of messageClass(String)

        /**
         * Sets the message subject to the given value.
         * @param subject message subject.
         * @return {@code this} message builder.
         * @throws IllegalArgumentException
         * if {@code subject} is {@code null} or empty.
         */
        @SuppressWarnings ("unchecked")
        public final B messageSubject(final String subject)
        {
            if (Strings.isNullOrEmpty(subject))
            {
                throw (
                    new IllegalArgumentException(
                        "subject is null or empty"));
            }

            mMessageSubject = subject;

            return ((B) this);
        } // end of messageSubject(final String subject)

        /**
         * Sets both the message class name and subject based on
         * the given message key.
         * @param key message key containing message class and
         * subject.
         * @return {@code this} message builder.
         * @throws NullPointerException
         * if {@code key} is {@code null}.
         */
        @SuppressWarnings ("unchecked")
        public final B messageKey(final EMessageKey key)
        {
            if (key == null)
            {
                throw (new NullPointerException("key is null"));
            }

            mMessageClass = key.className();
            mMessageSubject = key.subject();

            return ((B) this);
        } // end of messageKey(final EMessageKey key)

        //
        // end of Set Methods.
        //-------------------------------------------------------
    } // end of class Builder
} // end of class AbstractKeyMessage




© 2015 - 2024 Weber Informatics LLC | Privacy Policy