Emmanuel Bernard commented on Bug OGM-208

Internal model

The internal model can be type-safe or not.
We need a way to identify an option from another.

Each option needs a uniquely identifying key object.
This will tell if an option is overridden by another context
or merely duplicated by other values.

For example a named query using different names are not overlapping
but a named query with the same name is replaced by a more specific context.

/**
     * Interface required to be returned by the generator classes
     * It represents a tuple of the option and the value associated
     *
     * Option can be of any type, in particular it could be represented as
     * 
     * - an enum value
     * - a Class object in particular an annotation class object
     * - a String
     *
     * What is important is that the Option is unique according to
     * the `equals()` operation amongst the realm of possible options.
     * 
     * Likewise, Value can be of any type.
     */
    public interface OptionValueTuple<Option,Value> {
        Option getOption();
        Value getValue();
    }

    // most likely an anonymous class in a generator implementation
    public class QuorumOptionValueTuple implements OptionValueTuple<OptionEnum,Quorum> {
        private final int read;
        private final int write;

        public QuorumOptionValueTuple(int read, int write) { this.read = read; this.write = write; }

        public OptionEnum getOption() { return OptionEnum.QUORUM; }
        public Quorum getValue() { return new Quorum(read, write); }
    }
    
    //an example of possible Option identifier
    public enum OptionEnum {
        QUORUM;
    }
    
    // the object model representing the QUORUM value
    public class Quorum {
        private final int read;
        private final int write;
        public Quorum(int read, int write) { this.read = read; this.write = write }
    }

`OptionValueTuple` will be used by Hibernate OGM to collect a map of option / option value and expose that to
the `GridDialect`.

Problem, there is a notion of Option Type and a unique identifier made of option type and some other unique
identifier like in a named query. We uniquely define a named query by it's NamedQuery type and its actual name.

The Option object could be a subtype of `MultiOption`

/**
     * Common interface for options that can receive multiple values
     * like named queries.
     * TODO: are generics useful?
     */
    public class MultiOption<Type,Id> {
        /**
         * Class of option, this type can be any type but typically is an
         * enum, a Class instance or a String.
         */
        abstract Type getType();
        /**
         * Uniquely identify an option for a given type
         */ 
        abstract Id getUniqueIdentifier();

        public boolean equals(Object that) {
            //TODO implementation using getType and getUniqueIdentifier
        }

        public int hashCode() {
            //TODO implementation using getType and getUniqueIdentifier
        }
    }

    /**
     * Example of implementation
     */
    public NamedQueryOption extends MultiOption<Class<?>,String> {
        private final String queryName;
        public NamedQueryOption(String queryName) { this.queryName = queryName; }
        Class<?> getType() { return NamedQuery.class; }
        String getUniqueIdentifier() { return queryName; }
    }

    public class NamedQuery {
        private String name;
        private String hql;
        ...
    }

    // most likely an anonymous class in a generator implementation
    public class NamedQueryOptionValueTuple implements OptionValueTuple<NamedQueryOption, NamedQuery> {
        public NamedQueryOptionValueTuple(String name, String hsql) { ... }
        public NamedQueryOption getOption() { return new NamedQueryOption(name); }
        public NamedQuery getValue() { return new NamedQuery(name, hql);
    }

We could offer the ability to filter options by option or option type to help navigate them.
Wrt overriding, an option is overridden by a closer scope. Same for an option type with the same
unique identifier.

Usage from a GridDialect

We could imagine the following usage

Quorum quorum = (Quorum) context.inGlobalContext().getOption( QUORUM );
    List<NamedQuery> queries = (List<NamedQuery>) context.inEntityContext().getOptionByType(NamedQuery.class);

Observations

It seems the model is fairly verbose and I am willing to simplify it if we can. I am especially concerned
about the amount of concepts and classes the designer of an option needs to provide.

Paradoxically, there is not type-safe link between an option and its value besides the `OptionValueTuple`
which is not meant to be used by consumers of options. The `GridDialect` is force to downcast the data
which is not ideal.

I am also concerned about the fact that the set of options is quite dispersed due:

  • the ability to define the option (or option type) type freely
  • the fact that some options are specific to a given datastore provider

The design seems to need refinement but I have been working on it for some time now and need a fresh look at it.

This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators.
For more information on JIRA, see: http://www.atlassian.com/software/jira