001    /*
002    // $Id: TypeUtil.java 482 2012-01-05 23:27:27Z jhyde $
003    //
004    // Licensed to Julian Hyde under one or more contributor license
005    // agreements. See the NOTICE file distributed with this work for
006    // additional information regarding copyright ownership.
007    //
008    // Julian Hyde licenses this file to you under the Apache License,
009    // Version 2.0 (the "License"); you may not use this file except in
010    // compliance with the License. You may obtain a copy of the License at:
011    //
012    // http://www.apache.org/licenses/LICENSE-2.0
013    //
014    // Unless required by applicable law or agreed to in writing, software
015    // distributed under the License is distributed on an "AS IS" BASIS,
016    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017    // See the License for the specific language governing permissions and
018    // limitations under the License.
019    */
020    package org.olap4j.type;
021    
022    import org.olap4j.OlapException;
023    import org.olap4j.metadata.Hierarchy;
024    
025    /**
026     * Utility methods relating to types.
027     *
028     * <p>NOTE: This class is experimental. Not part of the public olap4j API.
029     *
030     * @author jhyde
031     * @since Feb 17, 2005
032     * @version $Id: TypeUtil.java 482 2012-01-05 23:27:27Z jhyde $
033     */
034    public class TypeUtil {
035    
036        /**
037         * Given a set type, returns the element type. Or its element type, if it
038         * is a set type. And so on.
039         */
040        private static Type stripSetType(Type type) {
041            while (type instanceof SetType) {
042                type = ((SetType) type).getElementType();
043            }
044            return type;
045        }
046    
047        /**
048         * Converts a type to a member or tuple type.
049         * If it cannot, returns null.
050         */
051        private static Type toMemberOrTupleType(Type type) throws OlapException {
052            type = stripSetType(type);
053            if (type instanceof TupleType) {
054                return (TupleType) type;
055            } else {
056                return toMemberType(type);
057            }
058        }
059    
060        /**
061         * Converts a type to a member type.
062         * If it is a set, strips the set.
063         * If it is a member type, returns the type unchanged.
064         * If it is a dimension, hierarchy or level type, converts it to
065         * a member type.
066         * If it is a tuple, number, string, or boolean, returns null.
067         */
068        static MemberType toMemberType(Type type) throws OlapException {
069            type = stripSetType(type);
070            if (type instanceof MemberType) {
071                return (MemberType) type;
072            } else if (type instanceof DimensionType
073                || type instanceof HierarchyType
074                || type instanceof LevelType)
075            {
076                return MemberType.forType(type);
077            } else {
078                return null;
079            }
080        }
081    
082        /**
083         * Returns whether this type is union-compatible with another.
084         * In general, to be union-compatible, types must have the same
085         * dimensionality.
086         *
087         * @param type1 First type
088         * @param type2 Second type
089         * @return Whether types are union-compatible
090         * @throws OlapException on error
091         */
092        static boolean isUnionCompatible(
093            Type type1,
094            Type type2)
095            throws OlapException
096        {
097            if (type1 instanceof TupleType) {
098                return type2 instanceof TupleType
099                    && ((TupleType) type1).isUnionCompatibleWith(
100                        (TupleType) type2);
101            } else {
102                final MemberType memberType1 = toMemberType(type1);
103                if (memberType1 == null) {
104                    return false;
105                }
106                final MemberType memberType2 = toMemberType(type2);
107                if (memberType2 == null) {
108                    return false;
109                }
110                final Hierarchy hierarchy1 = memberType1.getHierarchy();
111                final Hierarchy hierarchy2 = memberType2.getHierarchy();
112                return equal(hierarchy1, hierarchy2);
113            }
114        }
115    
116        private static boolean equal(
117            final Hierarchy hierarchy1, final Hierarchy hierarchy2)
118        {
119            if (hierarchy1 == null
120                || hierarchy2 == null
121                || hierarchy2.getUniqueName().equals(
122                    hierarchy1.getUniqueName()))
123            {
124                // They are compatible.
125                return true;
126            } else {
127                return false;
128            }
129        }
130    
131        /**
132         * Returns whether a value of a given type can be evaluated to a scalar
133         * value.
134         *
135         * <p>The rules are as follows:<ul>
136         * <li>Clearly boolean, numeric and string expressions can be evaluated.
137         * <li>Member and tuple expressions can be interpreted as a scalar value.
138         *     The expression is evaluated to establish the context where a measure
139         *     can be evaluated.
140         * <li>Hierarchy and dimension expressions are implicitly
141         *     converted into the current member, and evaluated as above.
142         * <li>Level expressions cannot be evaluated
143         * <li>Cube and Set (even sets with a single member) cannot be evaluated.
144         * </ul>
145         *
146         * @param type Type
147         * @return Whether an expression of this type can be evaluated to yield a
148         *   scalar value.
149         */
150        public static boolean canEvaluate(Type type) {
151            return ! (type instanceof SetType
152                      || type instanceof CubeType
153                      || type instanceof LevelType);
154        }
155    
156        /**
157         * Returns whether a type is a set type.
158         *
159         * @param type Type
160         * @return Whether a value of this type can be evaluated to yield a set.
161         */
162        public static boolean isSet(Type type) {
163            return type instanceof SetType;
164        }
165    
166        private static boolean couldBeMember(Type type) {
167            return type instanceof MemberType
168                || type instanceof HierarchyType
169                || type instanceof DimensionType;
170        }
171    
172        static boolean equal(Object o, Object p) {
173            return o == null ? p == null : p != null && o.equals(p);
174        }
175    }
176    
177    // End TypeUtil.java
178