001/* 002 * The Kuali Financial System, a comprehensive financial management system for higher education. 003 * 004 * Copyright 2005-2014 The Kuali Foundation 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU Affero General Public License as 008 * published by the Free Software Foundation, either version 3 of the 009 * License, or (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU Affero General Public License for more details. 015 * 016 * You should have received a copy of the GNU Affero General Public License 017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package org.kuali.rice.kim.impl.jaxb; 020 021import java.io.Serializable; 022import java.util.HashMap; 023import java.util.Map; 024 025import javax.xml.bind.Unmarshaller; 026import javax.xml.bind.annotation.XmlAccessType; 027import javax.xml.bind.annotation.XmlAccessorType; 028import javax.xml.bind.annotation.XmlElement; 029import javax.xml.bind.annotation.XmlTransient; 030import javax.xml.bind.annotation.XmlType; 031import javax.xml.bind.annotation.adapters.NormalizedStringAdapter; 032import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 033 034import org.apache.commons.lang.StringUtils; 035import org.joda.time.DateTime; 036import org.kuali.rice.core.api.membership.MemberType; 037import org.kuali.rice.core.api.util.jaxb.DateTimeAdapter; 038import org.kuali.rice.core.util.jaxb.NameAndNamespacePair; 039import org.kuali.rice.core.util.jaxb.NameAndNamespacePairValidatingAdapter; 040import org.kuali.rice.kim.api.group.GroupContract; 041import org.kuali.rice.kim.api.identity.principal.PrincipalContract; 042import org.kuali.rice.kim.api.jaxb.QualificationListAdapter; 043import org.kuali.rice.kim.api.role.RoleContract; 044import org.kuali.rice.kim.api.role.RoleMember; 045import org.kuali.rice.kim.api.services.KimApiServiceLocator; 046 047/** 048 * Base class representing an unmarshalled <roleMember> element. 049 * Refer to the static inner classes for more information about the specific contexts. 050 * 051 * @author Kuali Rice Team (rice.collab@kuali.org) 052 */ 053@XmlTransient 054public abstract class RoleMemberXmlDTO implements Serializable { 055 056 private static final long serialVersionUID = 1L; 057 058 @XmlElement(name="principalId") 059 @XmlJavaTypeAdapter(NormalizedStringAdapter.class) 060 private String principalId; 061 062 @XmlElement(name="principalName") 063 @XmlJavaTypeAdapter(NormalizedStringAdapter.class) 064 private String principalName; 065 066 @XmlElement(name="groupId") 067 @XmlJavaTypeAdapter(NormalizedStringAdapter.class) 068 private String groupId; 069 070 @XmlElement(name="groupName") 071 @XmlJavaTypeAdapter(NameAndNamespacePairValidatingAdapter.class) 072 private NameAndNamespacePair groupName; 073 074 @XmlElement(name="roleIdAsMember") 075 @XmlJavaTypeAdapter(NormalizedStringAdapter.class) 076 private String roleIdAsMember; 077 078 @XmlElement(name="roleNameAsMember") 079 @XmlJavaTypeAdapter(NameAndNamespacePairValidatingAdapter.class) 080 private NameAndNamespacePair roleNameAsMember; 081 082 @XmlElement(name="activeFromDate") 083 @XmlJavaTypeAdapter(DateTimeAdapter.class) 084 private DateTime activeFromDate; 085 086 @XmlElement(name="activeToDate") 087 @XmlJavaTypeAdapter(DateTimeAdapter.class) 088 private DateTime activeToDate; 089 090 @XmlElement(name="qualifications") 091 @XmlJavaTypeAdapter(QualificationListAdapter.class) 092 private Map<String, String> qualifications; 093 094 @XmlTransient 095 private MemberType memberType; 096 097 /** 098 * Constructs an empty RoleMemberXmlDTO instance. 099 */ 100 public RoleMemberXmlDTO() {} 101 102 /** 103 * Constructs a RoleMemberXmlDTO instance that is populated with the info from the given role member. 104 * 105 * @param roleMember The role member that this DTO should populate its data from. 106 * @param populateMemberId If true, the member principal/group/role ID will get populated; otherwise, only 107 * the member principal/group/role name and (if applicable) namespace will get populated. 108 * @throws IllegalArgumentException if roleMember is null, has an invalid member type, or refers to a nonexistent principal/group/role. 109 */ 110 public RoleMemberXmlDTO(RoleMember roleMember, boolean populateMemberId) { 111 if (roleMember == null) { 112 throw new IllegalArgumentException("roleMember cannot be null"); 113 } 114 this.memberType = roleMember.getType(); 115 this.activeFromDate = roleMember.getActiveFromDate(); 116 this.activeToDate = roleMember.getActiveToDate(); 117 this.qualifications = (roleMember.getAttributes() != null) ? roleMember.getAttributes() : new HashMap<String, String>(); 118 119 if (MemberType.PRINCIPAL.equals(memberType)) { 120 if (populateMemberId) { 121 this.principalId = roleMember.getMemberId(); 122 } 123 PrincipalContract principal = KimApiServiceLocator.getIdentityService().getPrincipal( 124 roleMember.getMemberId()); 125 if (principal == null) { 126 throw new IllegalArgumentException("Cannot find principal with ID \"" + roleMember.getMemberId() + "\""); 127 } 128 this.principalName = principal.getPrincipalName(); 129 } else if (MemberType.GROUP.equals(memberType)) { 130 if (populateMemberId) { 131 this.groupId = roleMember.getMemberId(); 132 } 133 GroupContract group = KimApiServiceLocator.getGroupService().getGroup(roleMember.getMemberId()); 134 if (group == null) { 135 throw new IllegalArgumentException("Cannot find group with ID \"" + roleMember.getMemberId() + "\""); 136 } 137 this.groupName = new NameAndNamespacePair(group.getNamespaceCode(), group.getName()); 138 } else if (MemberType.ROLE.equals(memberType)) { 139 if (populateMemberId) { 140 this.roleIdAsMember = roleMember.getMemberId(); 141 } 142 RoleContract role = KimApiServiceLocator.getRoleService().getRole(roleMember.getMemberId()); 143 if (role == null) { 144 throw new IllegalArgumentException("Cannot find role with ID \"" + roleMember.getMemberId() + "\""); 145 } 146 this.roleNameAsMember = new NameAndNamespacePair(role.getNamespaceCode(), role.getName()); 147 } else { 148 throw new IllegalArgumentException("Cannot construct a RoleMemberXmlDTO from a role member with an unrecognized member type code of \"" + 149 memberType + "\""); 150 } 151 } 152 153 /** 154 * @return the principalId 155 */ 156 public String getPrincipalId() { 157 return this.principalId; 158 } 159 160 /** 161 * @param principalId the principalId to set 162 */ 163 public void setPrincipalId(String principalId) { 164 this.principalId = principalId; 165 } 166 167 /** 168 * @return the principalName 169 */ 170 public String getPrincipalName() { 171 return this.principalName; 172 } 173 174 /** 175 * @param principalName the principalName to set 176 */ 177 public void setPrincipalName(String principalName) { 178 this.principalName = principalName; 179 } 180 181 /** 182 * @return the groupId 183 */ 184 public String getGroupId() { 185 return this.groupId; 186 } 187 188 /** 189 * @param groupId the groupId to set 190 */ 191 public void setGroupId(String groupId) { 192 this.groupId = groupId; 193 } 194 195 /** 196 * @return the groupName 197 */ 198 public NameAndNamespacePair getGroupName() { 199 return this.groupName; 200 } 201 202 /** 203 * @param groupName the groupName to set 204 */ 205 public void setGroupName(NameAndNamespacePair groupName) { 206 this.groupName = groupName; 207 } 208 209 /** 210 * @return the roleIdAsMember 211 */ 212 public String getRoleIdAsMember() { 213 return this.roleIdAsMember; 214 } 215 216 /** 217 * @param roleIdAsMember the roleIdAsMember to set 218 */ 219 public void setRoleIdAsMember(String roleIdAsMember) { 220 this.roleIdAsMember = roleIdAsMember; 221 } 222 223 /** 224 * @return the roleNameAsMember 225 */ 226 public NameAndNamespacePair getRoleNameAsMember() { 227 return this.roleNameAsMember; 228 } 229 230 /** 231 * @param roleNameAsMember the roleNameAsMember to set 232 */ 233 public void setRoleNameAsMember(NameAndNamespacePair roleNameAsMember) { 234 this.roleNameAsMember = roleNameAsMember; 235 } 236 237 /** 238 * @return the activeFromDate 239 */ 240 public DateTime getActiveFromDate() { 241 return this.activeFromDate; 242 } 243 244 /** 245 * @param activeFromDate the activeFromDate to set 246 */ 247 public void setActiveFromDate(DateTime activeFromDate) { 248 this.activeFromDate = activeFromDate; 249 } 250 251 /** 252 * @return the activeToDate 253 */ 254 public DateTime getActiveToDate() { 255 return this.activeToDate; 256 } 257 258 /** 259 * @param activeToDate the activeToDate to set 260 */ 261 public void setActiveToDate(DateTime activeToDate) { 262 this.activeToDate = activeToDate; 263 } 264 265 /** 266 * @return the qualifications 267 */ 268 public Map<String, String> getQualifications() { 269 return this.qualifications; 270 } 271 272 /** 273 * @param qualifications the qualifications to set 274 */ 275 public void setQualifications(Map<String, String> qualifications) { 276 this.qualifications = qualifications; 277 } 278 279 /** 280 * Retrieves the member type. 281 * 282 * <p>If the member type is null at the time that this method is invoked, an attempt will be made to set its 283 * value based on any populated member principal/group/role ID/name information. 284 * 285 * @return the member type, or null if no membership identification information has been set on this member. 286 * @throws IllegalStateException if the role member is populated simultaneously with multiple member ID/name information 287 */ 288 public MemberType getMemberType() { 289 if (memberType == null) { 290 boolean foundMemberInfo = false; 291 292 if (StringUtils.isNotBlank(principalId) || StringUtils.isNotBlank(principalName)) { 293 memberType = MemberType.PRINCIPAL; 294 foundMemberInfo = true; 295 } 296 297 if (StringUtils.isNotBlank(groupId) || groupName != null) { 298 if (foundMemberInfo) { 299 memberType = null; 300 throw new IllegalStateException("Cannot have a role member that is simultaneously populated with member principal, member group, and/or member role information"); 301 } 302 memberType = MemberType.GROUP; 303 foundMemberInfo = true; 304 } 305 306 if (StringUtils.isNotBlank(roleIdAsMember) || roleNameAsMember != null) { 307 if (foundMemberInfo) { 308 memberType = null; 309 throw new IllegalStateException("Cannot have a role member that is simultaneously populated with member principal, member group, and/or member role information"); 310 } 311 memberType = MemberType.ROLE; 312 foundMemberInfo = true; 313 } 314 } 315 return this.memberType; 316 } 317 318 /** 319 * Retrieves the role member's ID, based on the member type and any populated member principal/group/role IDs. 320 * 321 * <p>If the member type is null at the time that this method is invoked, an attempt will be made to set its 322 * value based on any populated member principal/group/role ID/name information. 323 * 324 * @return The member's ID, or null if the member type is null or the associated member ID information is null. 325 */ 326 public String getMemberId() { 327 if (MemberType.PRINCIPAL.equals(getMemberType())) { 328 return principalId; 329 } else if (MemberType.GROUP.equals(getMemberType())) { 330 return groupId; 331 } else if (MemberType.ROLE.equals(getMemberType())) { 332 return roleIdAsMember; 333 } 334 return null; 335 } 336 337 /** 338 * Retrieves the role member's name, based on the member type and any populated member principal/group/role names. 339 * 340 * <p>If the member type is null at the time that this method is invoked, an attempt will be made to set its 341 * value based on any populated member principal/group/role ID/name information. 342 * 343 * @return The member's name, or null if the member type is null or the associated member name information is null. 344 */ 345 public String getMemberName() { 346 if (MemberType.PRINCIPAL.equals(getMemberType())) { 347 return principalName; 348 } else if (MemberType.GROUP.equals(getMemberType())) { 349 return (groupName != null) ? groupName.getName() : null; 350 } else if (MemberType.ROLE.equals(getMemberType())) { 351 return (roleNameAsMember != null) ? roleNameAsMember.getName() : null; 352 } 353 return null; 354 } 355 356 /** 357 * Retrieves the role member's namespace code, based on the member type and any populated member principal/group/role names. 358 * 359 * <p>If the member type is null at the time that this method is invoked, an attempt will be made to set its 360 * value based on any populated member principal/group/role ID/name information. 361 * 362 * @return The member's namespace code, or null if the member type is null, the associated member name information is null, 363 * or the role member is a principal. 364 */ 365 public String getMemberNamespaceCode() { 366 if (MemberType.PRINCIPAL.equals(getMemberType())) { 367 return null; 368 } else if (MemberType.GROUP.equals(getMemberType())) { 369 return (groupName != null) ? groupName.getName() : null; 370 } else if (MemberType.ROLE.equals(getMemberType())) { 371 return (roleNameAsMember != null) ? roleNameAsMember.getName() : null; 372 } 373 return null; 374 } 375 376 /** 377 * Retrieves the ID of the role that this member belongs to. 378 * Subclasses are responsible for implementing this method so that it does so. 379 * 380 * @return The role ID of the role that this member belongs to. 381 */ 382 public abstract String getRoleId(); 383 384 // ======================================================================================================= 385 386 /** 387 * This class represents a <roleMember> element that is not a descendant of a <role> element. 388 * 389 * @author Kuali Rice Team (rice.collab@kuali.org) 390 */ 391 @XmlAccessorType(XmlAccessType.FIELD) 392 @XmlType(name="StandaloneRoleMemberType", propOrder={ 393 "roleId", "roleNameAndNamespace", "principalId", "principalName", "groupId", "groupName", "roleIdAsMember", 394 "roleNameAsMember", "activeFromDate", "activeToDate", "qualifications" 395 }) 396 public static class OutsideOfRole extends RoleMemberXmlDTO { 397 398 private static final long serialVersionUID = 1L; 399 400 @XmlElement(name="roleId") 401 @XmlJavaTypeAdapter(NormalizedStringAdapter.class) 402 private String roleId; 403 404 @XmlElement(name="roleName") 405 @XmlJavaTypeAdapter(NameAndNamespacePairValidatingAdapter.class) 406 private NameAndNamespacePair roleNameAndNamespace; 407 408 public OutsideOfRole() { 409 super(); 410 } 411 412 public OutsideOfRole(RoleMember roleMember, boolean populateMemberId) { 413 super(roleMember, populateMemberId); 414 this.roleId = roleMember.getRoleId(); 415 RoleContract tempRole = KimApiServiceLocator.getRoleService().getRole(roleId); 416 if (tempRole == null) { 417 throw new IllegalArgumentException("Cannot find role with ID \"" + roleId + "\""); 418 } 419 this.roleNameAndNamespace = new NameAndNamespacePair(tempRole.getNamespaceCode(), tempRole.getName()); 420 } 421 422 /** 423 * @see org.kuali.rice.kim.impl.jaxb.RoleMemberXmlDTO#getRoleId() 424 */ 425 @Override 426 public String getRoleId() { 427 return roleId; 428 } 429 430 /** 431 * @param roleId the roleId to set 432 */ 433 public void setRoleId(String roleId) { 434 this.roleId = roleId; 435 } 436 437 /** 438 * @return the roleNameAndNamespace 439 */ 440 public NameAndNamespacePair getRoleNameAndNamespace() { 441 return this.roleNameAndNamespace; 442 } 443 444 /** 445 * @param roleNameAndNamespace the roleNameAndNamespace to set 446 */ 447 public void setRoleNameAndNamespace(NameAndNamespacePair roleNameAndNamespace) { 448 this.roleNameAndNamespace = roleNameAndNamespace; 449 } 450 451 /** 452 * Retrieves the role name from the role-name-and-namespace combo. 453 * 454 * @return The name of the role that this member belongs to, or null if the role-name-and-namespace combo is null. 455 */ 456 public String getRoleName() { 457 return (roleNameAndNamespace != null) ? roleNameAndNamespace.getName() : null; 458 } 459 460 /** 461 * Retrieves the role namespace code from the role-name-and-namespace combo. 462 * 463 * @return The namespace code of the role that this member belongs to, or null if the role-name-and-namespace combo is null. 464 */ 465 public String getRoleNamespaceCode() { 466 return (roleNameAndNamespace != null) ? roleNameAndNamespace.getNamespaceCode() : null; 467 } 468 } 469 470 // ======================================================================================================= 471 472 /** 473 * This class represents a <roleMember> element that is a descendant of a <role> element. 474 * 475 * @author Kuali Rice Team (rice.collab@kuali.org) 476 */ 477 @XmlAccessorType(XmlAccessType.FIELD) 478 @XmlType(name="RoleMemberType", propOrder={ 479 "principalId", "principalName", "groupId", "groupName", "roleIdAsMember", 480 "roleNameAsMember", "activeFromDate", "activeToDate", "qualifications" 481 }) 482 public static class WithinRole extends RoleMemberXmlDTO { 483 484 private static final long serialVersionUID = 1L; 485 486 @XmlTransient 487 private String roleId; 488 489 public WithinRole() { 490 super(); 491 } 492 493 public WithinRole(RoleMember roleMember, boolean populateMemberId) { 494 super(roleMember, populateMemberId); 495 this.roleId = roleMember.getRoleId(); 496 } 497 498 void beforeUnmarshal(Unmarshaller unmarshaller, Object parent) { 499 if (parent instanceof RoleMembersXmlDTO.WithinRole) { 500 this.roleId = ((RoleMembersXmlDTO.WithinRole)parent).getRoleId(); 501 } 502 } 503 504 /** 505 * @see org.kuali.rice.kim.impl.jaxb.RoleMemberXmlDTO#getRoleId() 506 */ 507 @Override 508 public String getRoleId() { 509 return roleId; 510 } 511 512 } 513}