/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kuali.rice.kim.impl.jaxb;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.kuali.rice.core.api.membership.MemberType;
import org.kuali.rice.core.api.util.jaxb.DateTimeAdapter;
import org.kuali.rice.core.util.jaxb.NameAndNamespacePair;
import org.kuali.rice.core.util.jaxb.NameAndNamespacePairValidatingAdapter;
import org.kuali.rice.kim.api.group.GroupContract;
import org.kuali.rice.kim.api.identity.principal.PrincipalContract;
import org.kuali.rice.kim.api.jaxb.QualificationListAdapter;
import org.kuali.rice.kim.api.role.RoleContract;
import org.kuali.rice.kim.api.role.RoleMember;
import org.kuali.rice.kim.api.services.KimApiServiceLocator;
/**
* Base class representing an unmarshalled <roleMember> element.
* Refer to the static inner classes for more information about the specific contexts.
*
* @author Kuali Rice Team (rice.collab@kuali.org)
*/
@XmlTransient
public abstract class RoleMemberXmlDTO implements Serializable {
private static final long serialVersionUID = 1L;
@XmlElement(name="principalId")
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
private String principalId;
@XmlElement(name="principalName")
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
private String principalName;
@XmlElement(name="groupId")
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
private String groupId;
@XmlElement(name="groupName")
@XmlJavaTypeAdapter(NameAndNamespacePairValidatingAdapter.class)
private NameAndNamespacePair groupName;
@XmlElement(name="roleIdAsMember")
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
private String roleIdAsMember;
@XmlElement(name="roleNameAsMember")
@XmlJavaTypeAdapter(NameAndNamespacePairValidatingAdapter.class)
private NameAndNamespacePair roleNameAsMember;
@XmlElement(name="activeFromDate")
@XmlJavaTypeAdapter(DateTimeAdapter.class)
private DateTime activeFromDate;
@XmlElement(name="activeToDate")
@XmlJavaTypeAdapter(DateTimeAdapter.class)
private DateTime activeToDate;
@XmlElement(name="qualifications")
@XmlJavaTypeAdapter(QualificationListAdapter.class)
private Map<String, String> qualifications;
@XmlTransient
private MemberType memberType;
/**
* Constructs an empty RoleMemberXmlDTO instance.
*/
public RoleMemberXmlDTO() {}
/**
* Constructs a RoleMemberXmlDTO instance that is populated with the info from the given role member.
*
* @param roleMember The role member that this DTO should populate its data from.
* @param populateMemberId If true, the member principal/group/role ID will get populated; otherwise, only
* the member principal/group/role name and (if applicable) namespace will get populated.
* @throws IllegalArgumentException if roleMember is null, has an invalid member type, or refers to a nonexistent principal/group/role.
*/
public RoleMemberXmlDTO(RoleMember roleMember, boolean populateMemberId) {
if (roleMember == null) {
throw new IllegalArgumentException("roleMember cannot be null");
}
this.memberType = roleMember.getType();
this.activeFromDate = roleMember.getActiveFromDate();
this.activeToDate = roleMember.getActiveToDate();
this.qualifications = (roleMember.getAttributes() != null) ? roleMember.getAttributes() : new HashMap<String, String>();
if (MemberType.PRINCIPAL.equals(memberType)) {
if (populateMemberId) {
this.principalId = roleMember.getMemberId();
}
PrincipalContract principal = KimApiServiceLocator.getIdentityService().getPrincipal(
roleMember.getMemberId());
if (principal == null) {
throw new IllegalArgumentException("Cannot find principal with ID \"" + roleMember.getMemberId() + "\"");
}
this.principalName = principal.getPrincipalName();
} else if (MemberType.GROUP.equals(memberType)) {
if (populateMemberId) {
this.groupId = roleMember.getMemberId();
}
GroupContract group = KimApiServiceLocator.getGroupService().getGroup(roleMember.getMemberId());
if (group == null) {
throw new IllegalArgumentException("Cannot find group with ID \"" + roleMember.getMemberId() + "\"");
}
this.groupName = new NameAndNamespacePair(group.getNamespaceCode(), group.getName());
} else if (MemberType.ROLE.equals(memberType)) {
if (populateMemberId) {
this.roleIdAsMember = roleMember.getMemberId();
}
RoleContract role = KimApiServiceLocator.getRoleService().getRole(roleMember.getMemberId());
if (role == null) {
throw new IllegalArgumentException("Cannot find role with ID \"" + roleMember.getMemberId() + "\"");
}
this.roleNameAsMember = new NameAndNamespacePair(role.getNamespaceCode(), role.getName());
} else {
throw new IllegalArgumentException("Cannot construct a RoleMemberXmlDTO from a role member with an unrecognized member type code of \"" +
memberType + "\"");
}
}
/**
* @return the principalId
*/
public String getPrincipalId() {
return this.principalId;
}
/**
* @param principalId the principalId to set
*/
public void setPrincipalId(String principalId) {
this.principalId = principalId;
}
/**
* @return the principalName
*/
public String getPrincipalName() {
return this.principalName;
}
/**
* @param principalName the principalName to set
*/
public void setPrincipalName(String principalName) {
this.principalName = principalName;
}
/**
* @return the groupId
*/
public String getGroupId() {
return this.groupId;
}
/**
* @param groupId the groupId to set
*/
public void setGroupId(String groupId) {
this.groupId = groupId;
}
/**
* @return the groupName
*/
public NameAndNamespacePair getGroupName() {
return this.groupName;
}
/**
* @param groupName the groupName to set
*/
public void setGroupName(NameAndNamespacePair groupName) {
this.groupName = groupName;
}
/**
* @return the roleIdAsMember
*/
public String getRoleIdAsMember() {
return this.roleIdAsMember;
}
/**
* @param roleIdAsMember the roleIdAsMember to set
*/
public void setRoleIdAsMember(String roleIdAsMember) {
this.roleIdAsMember = roleIdAsMember;
}
/**
* @return the roleNameAsMember
*/
public NameAndNamespacePair getRoleNameAsMember() {
return this.roleNameAsMember;
}
/**
* @param roleNameAsMember the roleNameAsMember to set
*/
public void setRoleNameAsMember(NameAndNamespacePair roleNameAsMember) {
this.roleNameAsMember = roleNameAsMember;
}
/**
* @return the activeFromDate
*/
public DateTime getActiveFromDate() {
return this.activeFromDate;
}
/**
* @param activeFromDate the activeFromDate to set
*/
public void setActiveFromDate(DateTime activeFromDate) {
this.activeFromDate = activeFromDate;
}
/**
* @return the activeToDate
*/
public DateTime getActiveToDate() {
return this.activeToDate;
}
/**
* @param activeToDate the activeToDate to set
*/
public void setActiveToDate(DateTime activeToDate) {
this.activeToDate = activeToDate;
}
/**
* @return the qualifications
*/
public Map<String, String> getQualifications() {
return this.qualifications;
}
/**
* @param qualifications the qualifications to set
*/
public void setQualifications(Map<String, String> qualifications) {
this.qualifications = qualifications;
}
/**
* Retrieves the member type.
*
* <p>If the member type is null at the time that this method is invoked, an attempt will be made to set its
* value based on any populated member principal/group/role ID/name information.
*
* @return the member type, or null if no membership identification information has been set on this member.
* @throws IllegalStateException if the role member is populated simultaneously with multiple member ID/name information
*/
public MemberType getMemberType() {
if (memberType == null) {
boolean foundMemberInfo = false;
if (StringUtils.isNotBlank(principalId) || StringUtils.isNotBlank(principalName)) {
memberType = MemberType.PRINCIPAL;
foundMemberInfo = true;
}
if (StringUtils.isNotBlank(groupId) || groupName != null) {
if (foundMemberInfo) {
memberType = null;
throw new IllegalStateException("Cannot have a role member that is simultaneously populated with member principal, member group, and/or member role information");
}
memberType = MemberType.GROUP;
foundMemberInfo = true;
}
if (StringUtils.isNotBlank(roleIdAsMember) || roleNameAsMember != null) {
if (foundMemberInfo) {
memberType = null;
throw new IllegalStateException("Cannot have a role member that is simultaneously populated with member principal, member group, and/or member role information");
}
memberType = MemberType.ROLE;
foundMemberInfo = true;
}
}
return this.memberType;
}
/**
* Retrieves the role member's ID, based on the member type and any populated member principal/group/role IDs.
*
* <p>If the member type is null at the time that this method is invoked, an attempt will be made to set its
* value based on any populated member principal/group/role ID/name information.
*
* @return The member's ID, or null if the member type is null or the associated member ID information is null.
*/
public String getMemberId() {
if (MemberType.PRINCIPAL.equals(getMemberType())) {
return principalId;
} else if (MemberType.GROUP.equals(getMemberType())) {
return groupId;
} else if (MemberType.ROLE.equals(getMemberType())) {
return roleIdAsMember;
}
return null;
}
/**
* Retrieves the role member's name, based on the member type and any populated member principal/group/role names.
*
* <p>If the member type is null at the time that this method is invoked, an attempt will be made to set its
* value based on any populated member principal/group/role ID/name information.
*
* @return The member's name, or null if the member type is null or the associated member name information is null.
*/
public String getMemberName() {
if (MemberType.PRINCIPAL.equals(getMemberType())) {
return principalName;
} else if (MemberType.GROUP.equals(getMemberType())) {
return (groupName != null) ? groupName.getName() : null;
} else if (MemberType.ROLE.equals(getMemberType())) {
return (roleNameAsMember != null) ? roleNameAsMember.getName() : null;
}
return null;
}
/**
* Retrieves the role member's namespace code, based on the member type and any populated member principal/group/role names.
*
* <p>If the member type is null at the time that this method is invoked, an attempt will be made to set its
* value based on any populated member principal/group/role ID/name information.
*
* @return The member's namespace code, or null if the member type is null, the associated member name information is null,
* or the role member is a principal.
*/
public String getMemberNamespaceCode() {
if (MemberType.PRINCIPAL.equals(getMemberType())) {
return null;
} else if (MemberType.GROUP.equals(getMemberType())) {
return (groupName != null) ? groupName.getName() : null;
} else if (MemberType.ROLE.equals(getMemberType())) {
return (roleNameAsMember != null) ? roleNameAsMember.getName() : null;
}
return null;
}
/**
* Retrieves the ID of the role that this member belongs to.
* Subclasses are responsible for implementing this method so that it does so.
*
* @return The role ID of the role that this member belongs to.
*/
public abstract String getRoleId();
// =======================================================================================================
/**
* This class represents a <roleMember> element that is not a descendant of a <role> element.
*
* @author Kuali Rice Team (rice.collab@kuali.org)
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name="StandaloneRoleMemberType", propOrder={
"roleId", "roleNameAndNamespace", "principalId", "principalName", "groupId", "groupName", "roleIdAsMember",
"roleNameAsMember", "activeFromDate", "activeToDate", "qualifications"
})
public static class OutsideOfRole extends RoleMemberXmlDTO {
private static final long serialVersionUID = 1L;
@XmlElement(name="roleId")
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
private String roleId;
@XmlElement(name="roleName")
@XmlJavaTypeAdapter(NameAndNamespacePairValidatingAdapter.class)
private NameAndNamespacePair roleNameAndNamespace;
public OutsideOfRole() {
super();
}
public OutsideOfRole(RoleMember roleMember, boolean populateMemberId) {
super(roleMember, populateMemberId);
this.roleId = roleMember.getRoleId();
RoleContract tempRole = KimApiServiceLocator.getRoleService().getRole(roleId);
if (tempRole == null) {
throw new IllegalArgumentException("Cannot find role with ID \"" + roleId + "\"");
}
this.roleNameAndNamespace = new NameAndNamespacePair(tempRole.getNamespaceCode(), tempRole.getName());
}
/**
* @see org.kuali.rice.kim.impl.jaxb.RoleMemberXmlDTO#getRoleId()
*/
@Override
public String getRoleId() {
return roleId;
}
/**
* @param roleId the roleId to set
*/
public void setRoleId(String roleId) {
this.roleId = roleId;
}
/**
* @return the roleNameAndNamespace
*/
public NameAndNamespacePair getRoleNameAndNamespace() {
return this.roleNameAndNamespace;
}
/**
* @param roleNameAndNamespace the roleNameAndNamespace to set
*/
public void setRoleNameAndNamespace(NameAndNamespacePair roleNameAndNamespace) {
this.roleNameAndNamespace = roleNameAndNamespace;
}
/**
* Retrieves the role name from the role-name-and-namespace combo.
*
* @return The name of the role that this member belongs to, or null if the role-name-and-namespace combo is null.
*/
public String getRoleName() {
return (roleNameAndNamespace != null) ? roleNameAndNamespace.getName() : null;
}
/**
* Retrieves the role namespace code from the role-name-and-namespace combo.
*
* @return The namespace code of the role that this member belongs to, or null if the role-name-and-namespace combo is null.
*/
public String getRoleNamespaceCode() {
return (roleNameAndNamespace != null) ? roleNameAndNamespace.getNamespaceCode() : null;
}
}
// =======================================================================================================
/**
* This class represents a <roleMember> element that is a descendant of a <role> element.
*
* @author Kuali Rice Team (rice.collab@kuali.org)
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name="RoleMemberType", propOrder={
"principalId", "principalName", "groupId", "groupName", "roleIdAsMember",
"roleNameAsMember", "activeFromDate", "activeToDate", "qualifications"
})
public static class WithinRole extends RoleMemberXmlDTO {
private static final long serialVersionUID = 1L;
@XmlTransient
private String roleId;
public WithinRole() {
super();
}
public WithinRole(RoleMember roleMember, boolean populateMemberId) {
super(roleMember, populateMemberId);
this.roleId = roleMember.getRoleId();
}
void beforeUnmarshal(Unmarshaller unmarshaller, Object parent) {
if (parent instanceof RoleMembersXmlDTO.WithinRole) {
this.roleId = ((RoleMembersXmlDTO.WithinRole)parent).getRoleId();
}
}
/**
* @see org.kuali.rice.kim.impl.jaxb.RoleMemberXmlDTO#getRoleId()
*/
@Override
public String getRoleId() {
return roleId;
}
}
}