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