001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2005-2005 Julian Hyde 008// Copyright (C) 2005-2011 Pentaho 009// All Rights Reserved. 010*/ 011package mondrian.olap.type; 012 013import mondrian.olap.*; 014import mondrian.resource.MondrianResource; 015 016import java.util.*; 017 018/** 019 * Tuple type. 020 * 021 * @author jhyde 022 * @since Feb 17, 2005 023 */ 024public class TupleType implements Type { 025 public final Type[] elementTypes; 026 private final String digest; 027 028 /** 029 * Creates a type representing a tuple whose fields are the given types. 030 * 031 * @param elementTypes Array of types of the members in this tuple 032 */ 033 public TupleType(Type[] elementTypes) { 034 assert elementTypes != null; 035 this.elementTypes = elementTypes.clone(); 036 037 final StringBuilder buf = new StringBuilder(); 038 buf.append("TupleType<"); 039 int k = 0; 040 for (Type elementType : elementTypes) { 041 if (k++ > 0) { 042 buf.append(", "); 043 } 044 buf.append(elementType); 045 } 046 buf.append(">"); 047 digest = buf.toString(); 048 } 049 050 public String toString() { 051 return digest; 052 } 053 054 public boolean equals(Object obj) { 055 if (obj instanceof TupleType) { 056 TupleType that = (TupleType) obj; 057 return Arrays.equals(this.elementTypes, that.elementTypes); 058 } else { 059 return false; 060 } 061 } 062 063 public int hashCode() { 064 return digest.hashCode(); 065 } 066 067 public boolean usesDimension(Dimension dimension, boolean definitely) { 068 for (Type elementType : elementTypes) { 069 if (elementType.usesDimension(dimension, definitely)) { 070 return true; 071 } 072 } 073 return false; 074 } 075 076 public boolean usesHierarchy(Hierarchy hierarchy, boolean definitely) { 077 for (Type elementType : elementTypes) { 078 if (elementType.usesHierarchy(hierarchy, definitely)) { 079 return true; 080 } 081 } 082 return false; 083 } 084 085 public List<Hierarchy> getHierarchies() { 086 final List<Hierarchy> hierarchies = 087 new ArrayList<Hierarchy>(elementTypes.length); 088 for (Type elementType : elementTypes) { 089 hierarchies.add(elementType.getHierarchy()); 090 } 091 return hierarchies; 092 } 093 094 public int getArity() { 095 return elementTypes.length; 096 } 097 098 public Dimension getDimension() { 099 throw new UnsupportedOperationException(); 100 } 101 102 public Hierarchy getHierarchy() { 103 throw new UnsupportedOperationException(); 104 } 105 106 public Level getLevel() { 107 throw new UnsupportedOperationException(); 108 } 109 110 public Type getValueType() { 111 for (Type elementType : elementTypes) { 112 if (elementType instanceof MemberType) { 113 MemberType memberType = (MemberType) elementType; 114 Dimension dimension = memberType.getDimension(); 115 if (dimension != null && dimension.isMeasures()) { 116 return memberType.getValueType(); 117 } 118 } 119 } 120 return new ScalarType(); 121 } 122 123 public Type computeCommonType(Type type, int[] conversionCount) { 124 if (type instanceof ScalarType) { 125 return getValueType().computeCommonType(type, conversionCount); 126 } 127 if (type instanceof MemberType) { 128 return commonTupleType( 129 new TupleType(new Type[]{type}), 130 conversionCount); 131 } 132 if (!(type instanceof TupleType)) { 133 return null; 134 } 135 return commonTupleType(type, conversionCount); 136 } 137 138 public boolean isInstance(Object value) { 139 if (!(value instanceof Object[])) { 140 return false; 141 } 142 Object[] objects = (Object[]) value; 143 if (objects.length != elementTypes.length) { 144 return false; 145 } 146 for (int i = 0; i < objects.length; i++) { 147 if (!elementTypes[i].isInstance(objects[i])) { 148 return false; 149 } 150 } 151 return true; 152 } 153 154 private Type commonTupleType(Type type, int[] conversionCount) { 155 TupleType that = (TupleType) type; 156 157 if (this.elementTypes.length < that.elementTypes.length) { 158 return createCommonTupleType(that, conversionCount); 159 } 160 return that.createCommonTupleType(this, conversionCount); 161 } 162 163 private Type createCommonTupleType(TupleType that, int[] conversionCount) { 164 final List<Type> elementTypes = new ArrayList<Type>(); 165 for (int i = 0; i < this.elementTypes.length; i++) { 166 Type commonType = this.elementTypes[i].computeCommonType( 167 that.elementTypes[i], conversionCount); 168 elementTypes.add(commonType); 169 if (commonType == null) { 170 return null; 171 } 172 } 173 if (elementTypes.size() < that.elementTypes.length) { 174 for (int i = elementTypes.size(); 175 i < that.elementTypes.length; i++) 176 { 177 elementTypes.add(new ScalarType()); 178 } 179 } 180 return new TupleType( 181 elementTypes.toArray(new Type[elementTypes.size()])); 182 } 183 184 /** 185 * Checks that there are no duplicate dimensions in a list of member types. 186 * If so, the member types will form a valid tuple type. 187 * If not, throws {@link mondrian.olap.MondrianException}. 188 * 189 * @param memberTypes Array of member types 190 */ 191 public static void checkHierarchies(MemberType[] memberTypes) { 192 for (int i = 0; i < memberTypes.length; i++) { 193 MemberType memberType = memberTypes[i]; 194 for (int j = 0; j < i; j++) { 195 MemberType member1 = memberTypes[j]; 196 final Hierarchy hierarchy = memberType.getHierarchy(); 197 final Hierarchy hierarchy1 = member1.getHierarchy(); 198 if (hierarchy != null && hierarchy == hierarchy1) { 199 throw MondrianResource.instance().DupHierarchiesInTuple.ex( 200 hierarchy.getUniqueName()); 201 } 202 } 203 } 204 } 205} 206 207// End TupleType.java