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) 2007-2013 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.olap; 011 012import org.apache.log4j.Logger; 013 014import java.util.ArrayList; 015import java.util.List; 016 017/** 018 * Implementation of {@link Role} which combines the privileges of several 019 * roles and has the superset of their privileges. 020 * 021 * @see mondrian.olap.RoleImpl#union(java.util.List) 022 * 023 * @author jhyde 024 * @since Nov 26, 2007 025 */ 026class UnionRoleImpl implements Role { 027 private static final Logger LOGGER = 028 Logger.getLogger(UnionRoleImpl.class); 029 private final List<Role> roleList; 030 031 /** 032 * Creates a UnionRoleImpl. 033 * 034 * @param roleList List of constituent roles 035 */ 036 UnionRoleImpl(List<Role> roleList) { 037 this.roleList = new ArrayList<Role>(roleList); 038 } 039 040 public Access getAccess(Schema schema) { 041 Access access = Access.NONE; 042 for (Role role : roleList) { 043 access = max(access, role.getAccess(schema)); 044 if (access == Access.ALL) { 045 break; 046 } 047 } 048 LOGGER.debug( 049 "Access level " + access 050 + " granted to schema " + schema.getName() 051 + " because of a union of roles."); 052 return access; 053 } 054 055 /** 056 * Returns the larger of two enum values. Useful if the enums are sorted 057 * so that more permissive values come after less permissive values. 058 * 059 * @param t1 First value 060 * @param t2 Second value 061 * @return larger of the two values 062 */ 063 private static <T extends Enum<T>> T max(T t1, T t2) { 064 if (t1.ordinal() > t2.ordinal()) { 065 return t1; 066 } else { 067 return t2; 068 } 069 } 070 071 public Access getAccess(Cube cube) { 072 Access access = Access.NONE; 073 for (Role role : roleList) { 074 access = max(access, role.getAccess(cube)); 075 if (access == Access.ALL) { 076 break; 077 } 078 } 079 LOGGER.debug( 080 "Access level " + access 081 + " granted to cube " + cube.getName() 082 + " because of a union of roles."); 083 return access; 084 } 085 086 public Access getAccess(Dimension dimension) { 087 Access access = Access.NONE; 088 for (Role role : roleList) { 089 access = max(access, role.getAccess(dimension)); 090 if (access == Access.ALL) { 091 break; 092 } 093 } 094 LOGGER.debug( 095 "Access level " + access 096 + " granted to dimension " + dimension.getUniqueName() 097 + " because of a union of roles."); 098 return access; 099 } 100 101 public Access getAccess(Hierarchy hierarchy) { 102 Access access = Access.NONE; 103 for (Role role : roleList) { 104 access = max(access, role.getAccess(hierarchy)); 105 if (access == Access.ALL) { 106 break; 107 } 108 } 109 LOGGER.debug( 110 "Access level " + access 111 + " granted to hierarchy " + hierarchy.getUniqueName() 112 + " because of a union of roles."); 113 return access; 114 } 115 116 public HierarchyAccess getAccessDetails(final Hierarchy hierarchy) { 117 List<HierarchyAccess> list = new ArrayList<HierarchyAccess>(); 118 for (Role role : roleList) { 119 final HierarchyAccess accessDetails = 120 role.getAccessDetails(hierarchy); 121 if (accessDetails != null) { 122 list.add(accessDetails); 123 } 124 } 125 // If none of the roles call out access details, we shouldn't either. 126 if (list.isEmpty()) { 127 return null; 128 } 129 HierarchyAccess hierarchyAccess = 130 new UnionHierarchyAccessImpl(hierarchy, list); 131 if (list.size() > 5) { 132 hierarchyAccess = 133 new RoleImpl.CachingHierarchyAccess(hierarchyAccess); 134 } 135 return hierarchyAccess; 136 } 137 138 public Access getAccess(Level level) { 139 Access access = Access.NONE; 140 for (Role role : roleList) { 141 access = max(access, role.getAccess(level)); 142 if (access == Access.ALL) { 143 break; 144 } 145 } 146 LOGGER.debug( 147 "Access level " + access 148 + " granted to level " + level.getUniqueName() 149 + " because of a union of roles."); 150 return access; 151 } 152 153 public Access getAccess(Member member) { 154 assert member != null; 155 HierarchyAccess hierarchyAccess = 156 getAccessDetails(member.getHierarchy()); 157 if (hierarchyAccess != null) { 158 return hierarchyAccess.getAccess(member); 159 } 160 final Access access = getAccess(member.getDimension()); 161 LOGGER.debug( 162 "Access level " + access 163 + " granted to member " + member.getUniqueName() 164 + " because of a union of roles."); 165 return access; 166 } 167 168 public Access getAccess(NamedSet set) { 169 Access access = Access.NONE; 170 for (Role role : roleList) { 171 access = max(access, role.getAccess(set)); 172 if (access == Access.ALL) { 173 break; 174 } 175 } 176 LOGGER.debug( 177 "Access level " + access 178 + " granted to set " + set.getUniqueName() 179 + " because of a union of roles."); 180 return access; 181 } 182 183 public boolean canAccess(OlapElement olapElement) { 184 for (Role role : roleList) { 185 if (role.canAccess(olapElement)) { 186 return true; 187 } 188 } 189 return false; 190 } 191 192 /** 193 * Implementation of {@link mondrian.olap.Role.HierarchyAccess} that 194 * gives access to an object if any one of the constituent hierarchy 195 * accesses has access to that object. 196 */ 197 private class UnionHierarchyAccessImpl implements HierarchyAccess { 198 private final List<HierarchyAccess> list; 199 private final Hierarchy hierarchy; 200 201 /** 202 * Creates a UnionHierarchyAccessImpl. 203 * 204 * @param hierarchy Hierarchy 205 * @param list List of underlying hierarchy accesses 206 */ 207 UnionHierarchyAccessImpl( 208 Hierarchy hierarchy, 209 List<HierarchyAccess> list) 210 { 211 this.hierarchy = hierarchy; 212 this.list = list; 213 } 214 215 public Access getAccess(Member member) { 216 Access access = Access.NONE; 217 final int roleCount = roleList.size(); 218 for (int i = 0; i < roleCount; i++) { 219 Role role = roleList.get(i); 220 access = max(access, role.getAccess(member)); 221 if (access == Access.ALL) { 222 break; 223 } 224 } 225 LOGGER.debug( 226 "Access level " + access 227 + " granted to member " + member.getUniqueName() 228 + " because of a union of roles."); 229 return access; 230 } 231 232 public int getTopLevelDepth() { 233 if (!isTopLeveRestricted()) { 234 // We don't restrict the top level. 235 // Return 0 for root. 236 return 0; 237 } 238 int access = Integer.MAX_VALUE; 239 for (HierarchyAccess hierarchyAccess : list) { 240 if (hierarchyAccess.getTopLevelDepth() == 0) { 241 // No restrictions. Skip. 242 continue; 243 } 244 access = 245 Math.min( 246 access, 247 hierarchyAccess.getTopLevelDepth()); 248 if (access == 0) { 249 break; 250 } 251 } 252 return access; 253 } 254 255 public int getBottomLevelDepth() { 256 if (!isBottomLeveRestricted()) { 257 // We don't restrict the bottom level. 258 return list.get(0).getBottomLevelDepth(); 259 } 260 int access = -1; 261 for (HierarchyAccess hierarchyAccess : list) { 262 if (hierarchyAccess.getBottomLevelDepth() 263 == hierarchy.getLevels().length) 264 { 265 // No restrictions. Skip. 266 continue; 267 } 268 access = 269 Math.max( 270 access, 271 hierarchyAccess.getBottomLevelDepth()); 272 } 273 return access; 274 } 275 276 public RollupPolicy getRollupPolicy() { 277 RollupPolicy rollupPolicy = RollupPolicy.HIDDEN; 278 for (HierarchyAccess hierarchyAccess : list) { 279 rollupPolicy = 280 max( 281 rollupPolicy, 282 hierarchyAccess.getRollupPolicy()); 283 if (rollupPolicy == RollupPolicy.FULL) { 284 break; 285 } 286 } 287 return rollupPolicy; 288 } 289 290 public boolean hasInaccessibleDescendants(Member member) { 291 // If any of the roles return all the members, 292 // we assume that all descendants are accessible when 293 // we create a union of these roles. 294 final Access unionAccess = getAccess(member); 295 if (unionAccess == Access.ALL) { 296 return false; 297 } 298 if (unionAccess == Access.NONE) { 299 return true; 300 } 301 for (HierarchyAccess hierarchyAccess : list) { 302 if (hierarchyAccess.getAccess(member) == Access.CUSTOM 303 && !hierarchyAccess.hasInaccessibleDescendants(member)) 304 { 305 return false; 306 } 307 } 308 // All of the roles have restricted the descendants in 309 // some way. 310 return true; 311 } 312 313 private boolean isTopLeveRestricted() { 314 for (HierarchyAccess hierarchyAccess : list) { 315 if (hierarchyAccess.getTopLevelDepth() > 0) { 316 return true; 317 } 318 } 319 return false; 320 } 321 322 private boolean isBottomLeveRestricted() { 323 for (HierarchyAccess hierarchyAccess : list) { 324 if (hierarchyAccess.getBottomLevelDepth() 325 == hierarchy.getLevels().length) 326 { 327 return true; 328 } 329 } 330 return false; 331 } 332 } 333} 334 335// End UnionRoleImpl.java