001    /*
002    // $Id: TypeUtil.java 247 2009-06-20 05:52:40Z jhyde $
003    // This software is subject to the terms of the Eclipse Public License v1.0
004    // Agreement, available at the following URL:
005    // http://www.eclipse.org/legal/epl-v10.html.
006    // Copyright (C) 2005-2009 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package org.olap4j.type;
011    
012    import org.olap4j.metadata.Hierarchy;
013    import org.olap4j.OlapException;
014    
015    /**
016     * Utility methods relating to types.
017     *
018     * <p>NOTE: This class is experimental. Not part of the public olap4j API.
019     *
020     * @author jhyde
021     * @since Feb 17, 2005
022     * @version $Id: TypeUtil.java 247 2009-06-20 05:52:40Z jhyde $
023     */
024    public class TypeUtil {
025    
026        /**
027         * Given a set type, returns the element type. Or its element type, if it
028         * is a set type. And so on.
029         */
030        private static Type stripSetType(Type type) {
031            while (type instanceof SetType) {
032                type = ((SetType) type).getElementType();
033            }
034            return type;
035        }
036    
037        /**
038         * Converts a type to a member or tuple type.
039         * If it cannot, returns null.
040         */
041        private static Type toMemberOrTupleType(Type type) throws OlapException {
042            type = stripSetType(type);
043            if (type instanceof TupleType) {
044                return (TupleType) type;
045            } else {
046                return toMemberType(type);
047            }
048        }
049    
050        /**
051         * Converts a type to a member type.
052         * If it is a set, strips the set.
053         * If it is a member type, returns the type unchanged.
054         * If it is a dimension, hierarchy or level type, converts it to
055         * a member type.
056         * If it is a tuple, number, string, or boolean, returns null.
057         */
058        static MemberType toMemberType(Type type) throws OlapException {
059            type = stripSetType(type);
060            if (type instanceof MemberType) {
061                return (MemberType) type;
062            } else if (type instanceof DimensionType
063                || type instanceof HierarchyType
064                || type instanceof LevelType)
065            {
066                return MemberType.forType(type);
067            } else {
068                return null;
069            }
070        }
071    
072        /**
073         * Returns whether this type is union-compatible with another.
074         * In general, to be union-compatible, types must have the same
075         * dimensionality.
076         *
077         * @param type1 First type
078         * @param type2 Second type
079         * @return Whether types are union-compatible
080         * @throws OlapException on error
081         */
082        static boolean isUnionCompatible(
083            Type type1,
084            Type type2)
085            throws OlapException
086        {
087            if (type1 instanceof TupleType) {
088                return type2 instanceof TupleType
089                    && ((TupleType) type1).isUnionCompatibleWith(
090                    (TupleType) type2);
091            } else {
092                final MemberType memberType1 = toMemberType(type1);
093                if (memberType1 == null) {
094                    return false;
095                }
096                final MemberType memberType2 = toMemberType(type2);
097                if (memberType2 == null) {
098                    return false;
099                }
100                final Hierarchy hierarchy1 = memberType1.getHierarchy();
101                final Hierarchy hierarchy2 = memberType2.getHierarchy();
102                return equal(hierarchy1, hierarchy2);
103            }
104        }
105    
106        private static boolean equal(
107            final Hierarchy hierarchy1, final Hierarchy hierarchy2)
108        {
109            if (hierarchy1 == null
110                || hierarchy2 == null
111                || hierarchy2.getUniqueName().equals(
112                    hierarchy1.getUniqueName()))
113            {
114                // They are compatible.
115                return true;
116            } else {
117                return false;
118            }
119        }
120    
121        /**
122         * Returns whether a value of a given type can be evaluated to a scalar
123         * value.
124         *
125         * <p>The rules are as follows:<ul>
126         * <li>Clearly boolean, numeric and string expressions can be evaluated.
127         * <li>Member and tuple expressions can be interpreted as a scalar value.
128         *     The expression is evaluated to establish the context where a measure
129         *     can be evaluated.
130         * <li>Hierarchy and dimension expressions are implicitly
131         *     converted into the current member, and evaluated as above.
132         * <li>Level expressions cannot be evaluated
133         * <li>Cube and Set (even sets with a single member) cannot be evaluated.
134         * </ul>
135         *
136         * @param type Type
137         * @return Whether an expression of this type can be evaluated to yield a
138         *   scalar value.
139         */
140        public static boolean canEvaluate(Type type) {
141            return ! (type instanceof SetType
142                      || type instanceof CubeType
143                      || type instanceof LevelType);
144        }
145    
146        /**
147         * Returns whether a type is a set type.
148         *
149         * @param type Type
150         * @return Whether a value of this type can be evaluated to yield a set.
151         */
152        public static boolean isSet(Type type) {
153            return type instanceof SetType;
154        }
155    
156        private static boolean couldBeMember(Type type) {
157            return type instanceof MemberType
158                || type instanceof HierarchyType
159                || type instanceof DimensionType;
160        }
161    
162        static boolean equal(Object o, Object p) {
163            return o == null ? p == null : p != null && o.equals(p);
164        }
165    }
166    
167    // End TypeUtil.java