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) 2002-2005 Julian Hyde 008// Copyright (C) 2005-2011 Pentaho and others 009// All Rights Reserved. 010// 011// jhyde, 3 March, 2002 012*/ 013package mondrian.util; 014 015import mondrian.calc.TupleList; 016import mondrian.calc.impl.ArrayTupleList; 017import mondrian.olap.*; 018import mondrian.olap.fun.FunUtil; 019import mondrian.resource.MondrianResource; 020import mondrian.rolap.RolapCube; 021 022import java.util.*; 023 024/** 025 * Utilities for parsing fully-qualified member names, tuples, member lists, 026 * and tuple lists. 027 * 028 * @author jhyde 029 */ 030public class IdentifierParser extends org.olap4j.impl.IdentifierParser { 031 032 /** 033 * Implementation of Builder that resolves segment lists to members. 034 */ 035 public static class BuilderImpl extends MemberBuilder { 036 private final SchemaReader schemaReader; 037 private final Cube cube; 038 protected final List<Hierarchy> hierarchyList; 039 private final boolean ignoreInvalid; 040 041 BuilderImpl( 042 SchemaReader schemaReader, 043 Cube cube, 044 List<Hierarchy> hierarchyList) 045 { 046 this.schemaReader = schemaReader; 047 this.cube = cube; 048 this.hierarchyList = hierarchyList; 049 final MondrianProperties props = MondrianProperties.instance(); 050 final boolean load = ((RolapCube) cube).isLoadInProgress(); 051 this.ignoreInvalid = 052 (load 053 ? props.IgnoreInvalidMembers.get() 054 : props.IgnoreInvalidMembersDuringQuery.get()); 055 } 056 057 protected Member resolveMember(Hierarchy expectedHierarchy) { 058 final List<Id.Segment> mondrianSegmentList = 059 Util.convert(this.segmentList); 060 Member member = 061 (Member) Util.lookupCompound( 062 schemaReader, cube, mondrianSegmentList, !ignoreInvalid, 063 Category.Member); 064 if (member == null) { 065 assert ignoreInvalid; 066 if (expectedHierarchy != null) { 067 return expectedHierarchy.getNullMember(); 068 } else { 069 // Guess the intended hierarchy from the largest valid 070 // prefix. 071 for (int i = mondrianSegmentList.size() - 1; i > 0; --i) { 072 List<Id.Segment> partialName = 073 mondrianSegmentList.subList(0, i); 074 OlapElement olapElement = 075 schemaReader.lookupCompound( 076 cube, partialName, false, Category.Unknown); 077 if (olapElement != null) { 078 return olapElement.getHierarchy().getNullMember(); 079 } 080 } 081 throw MondrianResource.instance().MdxChildObjectNotFound.ex( 082 Util.implode(mondrianSegmentList), 083 cube.getQualifiedName()); 084 } 085 } 086 if (expectedHierarchy != null 087 && member.getHierarchy() != expectedHierarchy) 088 { 089 // TODO: better error 090 throw Util.newInternal("member is of wrong hierarchy"); 091 } 092 return member; 093 } 094 } 095 096 /** 097 * Implementation of Builder that builds a tuple. 098 */ 099 public static class TupleBuilder extends BuilderImpl { 100 protected final List<Member> memberList = new ArrayList<Member>(); 101 102 public TupleBuilder( 103 SchemaReader schemaReader, 104 Cube cube, 105 List<Hierarchy> hierarchyList) 106 { 107 super(schemaReader, cube, hierarchyList); 108 } 109 110 public void memberComplete() { 111 super.memberComplete(); 112 if (memberList.size() >= hierarchyList.size()) { 113 throw Util.newInternal("expected ')"); 114 } 115 final Hierarchy hierarchy = hierarchyList.get(memberList.size()); 116 final Member member = resolveMember(hierarchy); 117 memberList.add(member); 118 segmentList.clear(); 119 } 120 121 public void tupleComplete() { 122 if (memberList.size() < hierarchyList.size()) { 123 throw Util.newInternal("too few members"); 124 } 125 } 126 } 127 128 /** 129 * Implementation of Builder that builds a tuple list. 130 */ 131 public static class TupleListBuilder extends TupleBuilder { 132 public final TupleList tupleList; 133 134 public TupleListBuilder( 135 SchemaReader schemaReader, Cube cube, List<Hierarchy> hierarchyList) 136 { 137 super(schemaReader, cube, hierarchyList); 138 tupleList = new ArrayTupleList(hierarchyList.size()); 139 } 140 141 public void tupleComplete() { 142 super.tupleComplete(); 143 if (!FunUtil.tupleContainsNullMember(memberList)) { 144 tupleList.add(memberList); 145 } 146 this.memberList.clear(); 147 } 148 } 149 150 /** 151 * Implementation of Builder that builds a member list. 152 */ 153 public static class MemberListBuilder extends BuilderImpl { 154 public final List<Member> memberList = new ArrayList<Member>(); 155 156 public MemberListBuilder( 157 SchemaReader schemaReader, Cube cube, Hierarchy hierarchy) 158 { 159 super(schemaReader, cube, Collections.singletonList(hierarchy)); 160 } 161 162 public void memberComplete() { 163 final Member member = resolveMember(hierarchyList.get(0)); 164 if (!member.isNull()) { 165 memberList.add(member); 166 } 167 segmentList.clear(); 168 } 169 170 @Override 171 public void tupleComplete() { 172 // nothing to do 173 } 174 } 175} 176 177// End IdentifierParser.java