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