Features to merge

original list: https://issues.apache.org/jira/browse/DELTASPIKE-119

Part 1

Feature

Comments

Objections

Discussion finished

Basic API

 

 

(plus)

Serializable messages

 

not compatible with type-safe messages

 

Transferable messages (resolve the final text for a different context (locale,…)) and context-config

 

 

(plus)

custom message types

 

 

 

creating messages via builder pattern

 

 

(plus)

numbered message arguments

 

 

(plus)

eval existing converter approach for numbered message arguments

 

 

 

message resolver to support different message-sources

 

 

(plus)

message interpolator

 

 

(plus)

locale resolver

 

 

(plus) due to type-safe messages it changed a bit - we have to re-visit it

type safe messages

 

 

(plus)

Part 2

This part depends on decissions of part 1.

Feature

Comments

Objections

Discussion finished

el support (= el interpolation)

 

 

 

named message arguments

 

 

 

message payload -> allows to control processing of the message (via custom impl. of different SPIs) – similar to payload in bean-validation

 

 

 

message context (config) is immutable to avoid side-effects

 

 

 

clone a message context to use the same config but it’s possible to change it before the new context gets created (and is immutable)

 

 

 

formatter to allow to format argument-values for the final message text (similar to a converter -> we can think about merging the concepts)

 

 

 

tooling for devs to generate their own type-safe messages

 

 

 

messages within a database, or any other possible back end

 

 

 

inline translated type safe messages

 

 

 

pluralizer system for message i18n

 

 

 

static helpers for simple messages

 

 

 

Part 3

This part depends on the planned integration with other technologies like JSF, BV,...

Feature

Comments

Objections

Discussion finished

add message to the "current" context

 

 

 

factories to customize the default behaviour

 

 

 

allows multi-tenant support

 

 

 

message targets (ie. a message for a specific component)

 

 

 

application and client locale

 

 

 

application and client timezone

 

 

 

support jsr310 dates

 

 

 

transaction phase for message, ie. only produce a message when a transaction is committed (usually used in conjunction with observers)

 

 

 

integrate type safe messages with bean validation

 

 

 

ability to hook Bean Validation messages into same infrastructure

needs clarification - reason: ConstraintViolation#getMessage returns a string

 

 

ability to hook JSF validation messages into same infrastructure

see "current" context

 

 

messages surviving multiple http redirects

 

 

 

Part 4

This part contains features for integrating 3rd party libraries.

Feature

Comments

Objections

Discussion finished

support joda-time dates

 

 

 

Agreed API

Basic API

/**
 * Basic interface for all message-types
 */
public interface Message extends Localizable, Serializable
{
    /**
     * @return the message key (or inline-text) of the current message
     */
    String getDescriptor();

    /**
     * @return all named and numbered arguments
     */
    Serializable[] getArguments();

    /**
     * @param arguments 1-n new arguments for the current message
     * @return the current instance
     */
    Message addArgument(Serializable... arguments);

    /*
     * TBD
     */
    String toText();
}
@MessageBundle
public interface CustomMessageBundle
{
    @Message("Hello %s")
    Message sayHello(String cause);
}

//...

@Inject
private CustomMessageBundle messages;

//...

String messageText;
messageText = messages.sayHello("DeltaSpike").toText();
//or
messageText = messages.sayHello("DeltaSpike").toString();
//or
Message message = messages.sayHello("DeltaSpike");

API under discussion - Part 1

Message Interface

/**
 * Basic interface for all message-types
 */
public interface Message extends Localizable, Serializable
{
    /**
     * @return the message key (or inline-text) of the current message
     */
    String getDescriptor();

    /**
     * @return all named and numbered arguments
     */
    Serializable[] getArguments();

    /**
     * @param arguments 1-n new arguments for the current message
     * @return the current instance
     */
    Message addArgument(Serializable... arguments);

    //TODO check compatibility with type-safe messages
    //payload postponed (addPayload, getPayload)
}

Localizable

/**
 * Classes which implement it can provide the message-text based on the given {@link MessageContext}
 */
public interface Localizable
{
    /**
     * @param messageContext the current context
     * @return the text which represents the current instance for the given message context
     */
    String toString(MessageContext messageContext);
}

MessageInterpolator

/**
 * Implementations are responsible to replace placeholders in a message with the final value
 */
public interface MessageInterpolator extends Serializable
{
    /**
     * replaces the arguments of the given message with the given arguments
     *
     * @param messageContext the current {@link org.apache.myfaces.extensions.cdi.message.api.MessageContext}
     * instead of a MessageContextAware interface. we need it to avoid expensive operations like locking or deep cloning
     * @param messageText the message text which has to be interpolated
     * @param arguments a list of numbered and/or named arguments for the current message
     * @return the final (interpolated) message text
     *         if it was possible to replace the parameters with the given arguments
     *         the unmodified messageText otherwise
     */
    String interpolate(MessageContext messageContext, String messageText, Serializable... arguments);
}

MessageResolver

/**
 * Implementations have to resolve the text stored for a given key in the message-source they are aware of
 */
public interface MessageResolver extends Serializable
{
    String MISSING_RESOURCE_MARKER = "???";

    /**
     * @param messageContext the current {@link org.apache.myfaces.extensions.cdi.message.api.MessageContext}
     * @param messageDescriptor the message key (or in-lined text) of the current message
     * @param payload //TBD the payload of the message e.g. to use different message sources
     * @return the final but not interpolated message text
     */
    String getMessage(MessageContext messageContext,
                      String messageDescriptor,
                      /*TBD*/ Map<Class, MessagePayload> payload);
}

LocaleResolver

/**
 * Implementations have to provide the current locale
 */
public interface LocaleResolver extends Serializable
{
    /**
     * @return the current locale
     */
    Locale getLocale();
}

MessageContext

/**
 * Central context for handling messages
 */
public interface MessageContext extends LocaleResolver, MessageHandler, Serializable
{
    /**
     * @return message builder to add and/or create a new message based on the current context via a fluent api
     */
    MessageBuilder message();

    /**
     * @return the current config to change it or create a new one base on the current config
     */
    MessageContextConfig config();



    /*
     * TBD:
     */


    /**
     * @param contextType the type of the custom implementation
     * @return the instance of the current message context to use the api of the concrete implementation
     */
    <T extends MessageContext> T typed(Class<T> contextType);

    /*
     * convenient methods
     */

    /**
     * @return creates a new context based on the current one
     */
    MessageContext cloneContext();

    //the rest will be discussed later
}

MessageContextConfig

/**
 * Config for customizing a {@link MessageContext}
 */
public interface MessageContextConfig extends Serializable
{
    /**
     * create a new context based on the default context - the default context won't get modified
     *
     * @return a message context builder based on the current config
     */
    MessageContextBuilder use();

    /**
     * change the default context
     *
     * @return a message context builder to change the current config
     */
    MessageContextBuilder change();

    /**
     * @return the current message interpolator
     */
    MessageInterpolator getMessageInterpolator();

    /**
     * @return the current message resolver
     */
    MessageResolver getMessageResolver();

    /**
     * @return the current locale resolver
     */
    LocaleResolver getLocaleResolver();

    //the rest will be discussed later

    interface MessageContextBuilder
    {
        /**
         * @param messageInterpolator a new message interpolator
         * @return the instance of the current message context builder
         */
        MessageContextBuilder messageInterpolator(MessageInterpolator messageInterpolator);

        /**
         * @param messageResolver a new message resolver
         * @return the instance of the current message context builder
         */
        MessageContextBuilder messageResolver(MessageResolver messageResolver);

        /**
         * @param localeResolver a new locale resolver
         * @return the instance of the current message context builder
         */
        MessageContextBuilder localeResolver(LocaleResolver localeResolver);

        /**
         * @return a new message context based on the current config
         */
        MessageContext create();

        //the rest will be discussed later
    }
}
  • No labels