001 /* 002 // $Id: //open/mondrian/src/main/mondrian/rolap/RestrictedMemberReader.java#16 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2003-2007 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 // 010 // jhyde, Feb 26, 2003 011 */ 012 package mondrian.rolap; 013 014 import java.util.ArrayList; 015 import java.util.Collections; 016 import java.util.List; 017 018 import mondrian.olap.*; 019 import mondrian.rolap.sql.TupleConstraint; 020 import mondrian.rolap.sql.MemberChildrenConstraint; 021 022 /** 023 * A <code>RestrictedMemberReader</code> reads only the members of a hierarchy 024 * allowed by a role's access profile. 025 * 026 * @author jhyde 027 * @since Feb 26, 2003 028 * @version $Id: //open/mondrian/src/main/mondrian/rolap/RestrictedMemberReader.java#16 $ 029 */ 030 class RestrictedMemberReader extends DelegatingMemberReader { 031 032 private final Role.HierarchyAccess hierarchyAccess; 033 private final boolean ragged; 034 private final SqlConstraintFactory sqlConstraintFactory = 035 SqlConstraintFactory.instance(); 036 037 /** 038 * Creates a <code>RestrictedMemberReader</code>. 039 * 040 * <p>There's no filtering to be done unless 041 * either the role has restrictions on this hierarchy, 042 * or the hierarchy is ragged; there's a pre-condition to this effect.</p> 043 * 044 * @param memberReader Underlying (presumably unrestricted) member reader 045 * @param role Role whose access profile to obey. The role must have 046 * restrictions on this hierarchy 047 * @pre role.getAccessDetails(memberReader.getHierarchy()) != null || 048 * memberReader.getHierarchy().isRagged() 049 */ 050 RestrictedMemberReader(MemberReader memberReader, Role role) { 051 super(memberReader); 052 RolapHierarchy hierarchy = memberReader.getHierarchy(); 053 ragged = hierarchy.isRagged(); 054 if (role.getAccessDetails(hierarchy) == null) { 055 assert ragged; 056 hierarchyAccess = RoleImpl.createAllAccess(hierarchy); 057 } else { 058 hierarchyAccess = role.getAccessDetails(hierarchy); 059 } 060 } 061 062 public boolean setCache(MemberCache cache) { 063 // Don't support cache-writeback. It would confuse the cache! 064 return false; 065 } 066 067 public RolapMember getLeadMember(RolapMember member, int n) { 068 int i = 0; 069 int increment = 1; 070 if (n < 0) { 071 increment = -1; 072 n = -n; 073 } 074 while (i < n) { 075 member = memberReader.getLeadMember(member, increment); 076 if (member.isNull()) { 077 return member; 078 } 079 if (canSee(member)) { 080 ++i; 081 } 082 } 083 return member; 084 } 085 086 public void getMemberChildren( 087 RolapMember parentMember, 088 List<RolapMember> children) 089 { 090 MemberChildrenConstraint constraint = 091 sqlConstraintFactory.getMemberChildrenConstraint(null); 092 getMemberChildren(parentMember, children, constraint); 093 } 094 095 public void getMemberChildren( 096 RolapMember parentMember, 097 List<RolapMember> children, 098 MemberChildrenConstraint constraint) 099 { 100 List<RolapMember> fullChildren = new ArrayList<RolapMember>(); 101 memberReader.getMemberChildren(parentMember, fullChildren, constraint); 102 processMemberChildren(fullChildren, children, constraint); 103 } 104 105 private void processMemberChildren( 106 List<RolapMember> fullChildren, 107 List<RolapMember> children, 108 MemberChildrenConstraint constraint) 109 { 110 // todo: optimize if parentMember is beyond last level 111 List<RolapMember> grandChildren = null; 112 for (int i = 0; i < fullChildren.size(); i++) { 113 RolapMember member = fullChildren.get(i); 114 // If a child is hidden (due to raggedness) include its children. 115 // This must be done before applying access-control. 116 if (ragged) { 117 if (member.isHidden()) { 118 // Replace this member with all of its children. 119 // They might be hidden too, but we'll get to them in due 120 // course. They also might be access-controlled; that's why 121 // we deal with raggedness before we apply access-control. 122 fullChildren.remove(i); 123 if (grandChildren == null) { 124 grandChildren = new ArrayList<RolapMember>(); 125 } else { 126 grandChildren.clear(); 127 } 128 memberReader.getMemberChildren(member, grandChildren, constraint); 129 fullChildren.addAll(i, grandChildren); 130 // Step back to before the first child we just inserted, 131 // and go through the loop again. 132 --i; 133 continue; 134 } 135 } 136 // Filter out children which are invisible because of 137 // access-control. 138 final Access access; 139 if (hierarchyAccess != null) { 140 access = hierarchyAccess.getAccess(member); 141 } else { 142 access = Access.ALL; 143 } 144 switch (access) { 145 case NONE: 146 break; 147 default: 148 children.add(member); 149 break; 150 } 151 } 152 } 153 154 /** 155 * Writes to members which we can see. 156 * @param members Input list 157 * @param filteredMembers Output list 158 */ 159 private void filterMembers( 160 List<RolapMember> members, 161 List<RolapMember> filteredMembers) 162 { 163 for (RolapMember member : members) { 164 if (canSee(member)) { 165 filteredMembers.add(member); 166 } 167 } 168 } 169 170 private boolean canSee(final RolapMember member) { 171 if (ragged && member.isHidden()) { 172 return false; 173 } 174 if (hierarchyAccess != null) { 175 final Access access = hierarchyAccess.getAccess(member); 176 return access != Access.NONE; 177 } 178 return true; 179 } 180 181 public void getMemberChildren( 182 List<RolapMember> parentMembers, 183 List<RolapMember> children) 184 { 185 MemberChildrenConstraint constraint = 186 sqlConstraintFactory.getMemberChildrenConstraint(null); 187 getMemberChildren(parentMembers, children, constraint); 188 } 189 190 public synchronized void getMemberChildren( 191 List<RolapMember> parentMembers, 192 List<RolapMember> children, 193 MemberChildrenConstraint constraint) 194 { 195 // for (Iterator i = parentMembers.iterator(); i.hasNext();) { 196 // RolapMember parentMember = (RolapMember) i.next(); 197 // getMemberChildren(parentMember, children, constraint); 198 // } 199 List<RolapMember> fullChildren = new ArrayList<RolapMember>(); 200 super.getMemberChildren(parentMembers, fullChildren, constraint); 201 processMemberChildren(fullChildren, children, constraint); 202 } 203 204 public List<RolapMember> getRootMembers() { 205 int topLevelDepth = hierarchyAccess.getTopLevelDepth(); 206 if (topLevelDepth > 0) { 207 RolapLevel topLevel = 208 (RolapLevel) getHierarchy().getLevels()[topLevelDepth]; 209 return getMembersInLevel(topLevel, 0, Integer.MAX_VALUE); 210 } 211 return super.getRootMembers(); 212 } 213 214 public List<RolapMember> getMembersInLevel( 215 RolapLevel level, 216 int startOrdinal, 217 int endOrdinal) 218 { 219 TupleConstraint constraint = 220 sqlConstraintFactory.getLevelMembersConstraint(null); 221 return getMembersInLevel(level, startOrdinal, endOrdinal, constraint); 222 } 223 224 public List<RolapMember> getMembersInLevel( 225 RolapLevel level, 226 int startOrdinal, 227 int endOrdinal, 228 TupleConstraint constraint) 229 { 230 if (hierarchyAccess != null) { 231 final int depth = level.getDepth(); 232 if (depth < hierarchyAccess.getTopLevelDepth()) { 233 return Collections.emptyList(); 234 } 235 if (depth > hierarchyAccess.getBottomLevelDepth()) { 236 return Collections.emptyList(); 237 } 238 } 239 final List<RolapMember> membersInLevel = 240 memberReader.getMembersInLevel( 241 level, startOrdinal, endOrdinal, constraint); 242 List<RolapMember> filteredMembers = new ArrayList<RolapMember>(); 243 filterMembers(membersInLevel, filteredMembers); 244 return filteredMembers; 245 } 246 247 public RolapMember getDefaultMember() { 248 RolapMember defaultMember = 249 (RolapMember) getHierarchy().getDefaultMember(); 250 if (defaultMember != null) { 251 Access i = hierarchyAccess.getAccess(defaultMember); 252 if (i != Access.NONE) { 253 return defaultMember; 254 } 255 } 256 return getRootMembers().get(0); 257 } 258 259 public RolapMember getMemberParent(RolapMember member) { 260 RolapMember parentMember = member.getParentMember(); 261 // Skip over hidden parents. 262 while (parentMember != null && parentMember.isHidden()) { 263 parentMember = parentMember.getParentMember(); 264 } 265 // Skip over non-accessible parents. 266 if (parentMember != null) { 267 if (hierarchyAccess.getAccess(parentMember) == Access.NONE) { 268 return null; 269 } 270 } 271 return parentMember; 272 } 273 } 274 275 // End RestrictedMemberReader.java