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