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