001 /**
002 * Copyright 2005-2012 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 }