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*/
020package org.olap4j.type;
021
022import org.olap4j.OlapException;
023import 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 */
034public 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