001    // Copyright 2008 Thiago H. de Paula Figueiredo
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package br.com.arsmachina.authentication.entity;
016    
017    import java.io.Serializable;
018    import java.util.ArrayList;
019    import java.util.Collections;
020    import java.util.HashSet;
021    import java.util.Iterator;
022    import java.util.List;
023    import java.util.Set;
024    
025    import javax.persistence.CascadeType;
026    import javax.persistence.Column;
027    import javax.persistence.Entity;
028    import javax.persistence.GeneratedValue;
029    import javax.persistence.Id;
030    import javax.persistence.JoinColumn;
031    import javax.persistence.JoinTable;
032    import javax.persistence.ManyToMany;
033    import javax.persistence.OneToMany;
034    import javax.persistence.OrderBy;
035    import javax.persistence.Table;
036    import javax.persistence.Transient;
037    
038    import org.hibernate.validator.Email;
039    import org.hibernate.validator.Length;
040    import org.hibernate.validator.NotNull;
041    
042    /**
043     * Class that represents an application user. Each user can belong to any number of
044     * {@link Permission}s. When a given user belongs to a {@link Permission}, but cannot be granted
045     * some {@link Permission} in that group, this permission must be added to the list of removed
046     * permissions (<code>removedPermissions</code> property).
047     * 
048     * @author Thiago H. de Paula Figueiredo
049     */
050    @Entity
051    @Table(name = "`user`")
052    final public class User implements Comparable<User>, Serializable {
053    
054            private static final long serialVersionUID = 1L;
055    
056            /**
057             * Minimum e-mail length.
058             */
059            public static final int MINIMUM_EMAIL_LENGTH = 3;
060    
061            /**
062             * Minimum e-mail length.
063             */
064            public static final int MAXIMUM_EMAIL_LENGTH = 50;
065    
066            /**
067             * Minimum login length.
068             */
069            public static final int MINIMUM_LOGIN_LENGTH = 2;
070    
071            /**
072             * Maximum e-mail length.
073             */
074            public static final int MAXIMUM_LOGIN_LENGTH = 50;
075    
076            /**
077             * Minimum name length.
078             */
079            public static final int MINIMUM_NAME_LENGTH = 2;
080    
081            /**
082             * Maximum name length.
083             */
084            public static final int MAXIMUM_NAME_LENGTH = 50;
085    
086            /**
087             * Minimum name length.
088             */
089            public static final int MINIMUM_PASSWORD_LENGTH = 6;
090    
091            /**
092             * Maximum name length.
093             */
094            public static final int MAXIMUM_PASSWORD_LENGTH = 40;
095    
096            private Integer id;
097    
098            private String login;
099    
100            private String name;
101    
102            private String email;
103    
104            private boolean credentialsExpired = false;
105    
106            private boolean enabled = true;
107    
108            private boolean expired = false;
109    
110            private boolean locked = false;
111    
112            private boolean loggedIn = false;
113    
114            private String password;
115    
116            private List<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>();
117    
118            private List<Permission> removedPermissions = new ArrayList<Permission>();
119    
120            private List<Role> roles = new ArrayList<Role>();
121    
122            /**
123             * Adds a permission group to this user.
124             * 
125             * @param permissionGroup a {@link PermissionGroup}.
126             */
127            public void add(PermissionGroup permissionGroup) {
128    
129                    if (permissionGroups.contains(permissionGroup) == false) {
130                            permissionGroups.add(permissionGroup);
131                    }
132    
133            }
134    
135            /**
136             * Adds a role to this user.
137             * 
138             * @param role a {@link Role}.
139             */
140            public void add(Role role) {
141    
142                    if (roles.contains(role) == false) {
143                            role.setUser(this);
144                            roles.add(role);
145                    }
146    
147            }
148    
149            /**
150             * Tells if this user has some a given role type.
151             * 
152             * @param <R> a {@link Role} subclass.
153             * @param roleClass a {@link Class}.
154             * @return a <code>boolean</code>.
155             */
156            public <R extends Role> boolean hasRole(Class<R> roleClass) {
157                    return getRole(roleClass) != null;
158            }
159    
160            /**
161             * Adds a removed permission to this user.
162             * 
163             * @param permission a {@link PermissionGroup}.
164             */
165            public void addRemovedPermission(Permission permission) {
166    
167                    if (removedPermissions.contains(permission) == false) {
168                            removedPermissions.add(permission);
169                    }
170    
171            }
172    
173            /**
174             * @see java.lang.Comparable#compareTo(java.lang.Object)
175             */
176            public int compareTo(User o) {
177                    return getName().compareToIgnoreCase(o.getName());
178            }
179    
180            /**
181             * @see java.lang.Object#equals(java.lang.Object)
182             */
183            @Override
184            public boolean equals(Object obj) {
185                    if (this == obj) {
186                            return true;
187                    }
188                    if (obj == null) {
189                            return false;
190                    }
191                    if (getClass() != obj.getClass()) {
192                            return false;
193                    }
194                    User other = (User) obj;
195                    if (login == null) {
196                            if (other.login != null) {
197                                    return false;
198                            }
199                    }
200                    else if (!login.equals(other.login)) {
201                            return false;
202                    }
203                    return true;
204            }
205    
206            /**
207             * Returns the value of the <code>email</code> property.
208             * 
209             * @return a {@link String}.
210             */
211            @Email
212            @Length(min = User.MINIMUM_EMAIL_LENGTH, max = User.MAXIMUM_EMAIL_LENGTH)
213            public String getEmail() {
214                    return email;
215            }
216    
217            /**
218             * Returns the value of the <code>id</code> property.
219             * 
220             * @return a {@link Integer}.
221             */
222            @Id
223            @GeneratedValue
224            public Integer getId() {
225                    return id;
226            }
227    
228            /**
229             * Returns the value of the <code>login</code> property.
230             * 
231             * @return a {@link String}.
232             */
233            @Column(nullable = false, unique = true)
234            @NotNull
235            @Length(min = User.MINIMUM_LOGIN_LENGTH, max = User.MAXIMUM_LOGIN_LENGTH)
236            public String getLogin() {
237                    return login;
238            }
239    
240            /**
241             * Returns the value of the <code>name</code> property.
242             * 
243             * @return a {@link String}.
244             */
245            @Column(nullable = false)
246            @NotNull
247            @Length(min = User.MINIMUM_NAME_LENGTH, max = User.MAXIMUM_NAME_LENGTH)
248            public String getName() {
249                    return name;
250            }
251    
252            /**
253             * Returns the value of the <code>password</code> property.
254             * 
255             * @return a {@link String}.
256             */
257            @Column(nullable = false, length = MAXIMUM_PASSWORD_LENGTH)
258            @NotNull
259            @Length(min = User.MINIMUM_PASSWORD_LENGTH, max = User.MAXIMUM_PASSWORD_LENGTH)
260            public String getPassword() {
261                    return password;
262            }
263    
264            /**
265             * Returns the value of the <code>permissionGroups</code> property.
266             * 
267             * @return a {@link List<PermissionGroup>}.
268             */
269            @ManyToMany
270            @OrderBy("name asc")
271            @JoinTable(name = "user_permissiongroup", joinColumns = @JoinColumn(name = "user_id", nullable = false), inverseJoinColumns = @JoinColumn(name = "permissiongroup_id", nullable = false))
272            public List<PermissionGroup> getPermissionGroups() {
273                    return permissionGroups;
274            }
275    
276            /**
277             * Returns an unmodifiable list containing all the permissions granted to this user. It is
278             * comprised by the sum of all permissions in its permission groups, except the ones in its
279             * removed permissions list.
280             * 
281             * @return a {@link List} of {@link Permission}s.
282             */
283            @Transient
284            final public List<Permission> getPermissions() {
285    
286                    Set<Permission> permissions = new HashSet<Permission>();
287    
288                    for (PermissionGroup group : getPermissionGroups()) {
289    
290                            for (Permission permission : group.getPermissions()) {
291                                    permissions.add(permission);
292                            }
293    
294                    }
295    
296                    for (Permission permission : getRemovedPermissions()) {
297                            permissions.remove(permission);
298                    }
299    
300                    ArrayList<Permission> list = new ArrayList<Permission>(permissions);
301    
302                    Collections.sort(list);
303    
304                    return Collections.unmodifiableList(list);
305    
306            }
307    
308            /**
309             * Returns the value of the <code>removedPermissions</code> property.
310             * 
311             * @return a {@link List<Permission>}.
312             */
313            @ManyToMany
314            @OrderBy("name asc")
315            @JoinTable(name = "user_removedpermission", joinColumns = @JoinColumn(name = "user_id", nullable = false), inverseJoinColumns = @JoinColumn(name = "permission_id", nullable = false))
316            public List<Permission> getRemovedPermissions() {
317                    return removedPermissions;
318            }
319    
320            /**
321             * Given a {@link Class} object, returns the corresponding {@link Role} instance or null if this
322             * user has no such role.
323             * 
324             * @param <T> a {@link Role} subclass.
325             * @param clasz a {@link Class<T>}.
326             * @return a {@link #T}.
327             */
328            @SuppressWarnings("unchecked")
329            public final <T extends Role> T getRole(Class<T> clasz) {
330    
331                    T role = null;
332    
333                    for (Role r : getRoles()) {
334                            if (r.getClass().equals(clasz)) {
335                                    role = (T) r;
336                                    break;
337                            }
338                    }
339    
340                    return role;
341    
342            }
343    
344            /**
345             * Returns the value of the <code>roles</code> property.
346             * 
347             * @return a {@link List<Role>}.
348             */
349            @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
350            public List<Role> getRoles() {
351                    return roles;
352            }
353    
354            /**
355             * @see java.lang.Object#hashCode()
356             */
357            @Override
358            public int hashCode() {
359                    return login != null ? login.hashCode() : super.hashCode();
360            }
361    
362            /**
363             * Is this user's credentials expired?
364             * 
365             * @return a {@link boolean}.
366             */
367            public boolean isCredentialsExpired() {
368                    return credentialsExpired;
369            }
370    
371            /**
372             * Is this user's account enabled?.
373             * 
374             * @return a {@link boolean}.
375             */
376            public boolean isEnabled() {
377                    return enabled;
378            }
379    
380            /**
381             * Is this user's account expired?
382             * 
383             * @return a {@link boolean}.
384             */
385            public boolean isExpired() {
386                    return expired;
387            }
388    
389            /**
390             * Is this user's account locked?
391             * 
392             * @return a {@link boolean}.
393             */
394            public boolean isLocked() {
395                    return locked;
396            }
397    
398            /**
399             * Is this user's logged in now?
400             * 
401             * @return a {@link boolean}.
402             */
403            public boolean isLoggedIn() {
404                    return loggedIn;
405            }
406    
407            /**
408             * Removes a role from this user.
409             * 
410             * @param role a {@link Role}.
411             */
412            public void remove(Role role) {
413                    permissionGroups.remove(role);
414            }
415    
416            /**
417             * Removes all roles from a given type from this user.
418             * 
419             * @param roleClass a {@link Class}.
420             */
421            public <T extends Role> void removeRole(Class<T> roleClass) {
422    
423                    for (Iterator<Role> i = roles.iterator(); i.hasNext();) {
424    
425                            Role role = i.next();
426    
427                            if (role.getClass().equals(roleClass)) {
428                                    i.remove();
429                            }
430    
431                    }
432    
433            }
434    
435            /**
436             * Removes a permission group from this user.
437             * 
438             * @param permissionGroup a {@link PermissionGroup}.
439             */
440            public void remove(PermissionGroup permissionGroup) {
441                    permissionGroups.remove(permissionGroup);
442            }
443    
444            /**
445             * Removes a removed permission from this user.
446             * 
447             * @param permission a {@link Permission}.
448             */
449            public void removeRemovedPermission(Permission permission) {
450                    removedPermissions.remove(permission);
451            }
452    
453            /**
454             * Changes the value of the <code>credentialsExpired</code> property.
455             * 
456             * @param credentialsExpired a {@link boolean}.
457             */
458            public void setCredentialsExpired(boolean credentialsExpired) {
459                    this.credentialsExpired = credentialsExpired;
460            }
461    
462            /**
463             * Changes the value of the <code>email</code> property.
464             * 
465             * @param email a {@link String}.
466             */
467            public void setEmail(String email) {
468                    this.email = email;
469            }
470    
471            /**
472             * Changes the value of the <code>enabled</code> property.
473             * 
474             * @param enabled a {@link boolean}.
475             */
476            public void setEnabled(boolean enabled) {
477                    this.enabled = enabled;
478            }
479    
480            /**
481             * Changes the value of the <code>expired</code> property.
482             * 
483             * @param expired a {@link boolean}.
484             */
485            public void setExpired(boolean accountExpired) {
486                    this.expired = accountExpired;
487            }
488    
489            /**
490             * Changes the value of the <code>id</code> property.
491             * 
492             * @param id a {@link Integer}.
493             */
494            public void setId(Integer id) {
495                    this.id = id;
496            }
497    
498            /**
499             * Changes the value of the <code>locked</code> property.
500             * 
501             * @param locked a {@link boolean}.
502             */
503            public void setLocked(boolean accountLocked) {
504                    this.locked = accountLocked;
505            }
506    
507            /**
508             * Changes the value of the <code>loggedIn</code> property.
509             * 
510             * @param loggedIn a {@link boolean}.
511             */
512            public void setLoggedIn(boolean loggedIn) {
513                    this.loggedIn = loggedIn;
514            }
515    
516            /**
517             * Changes the value of the <code>login</code> property.
518             * 
519             * @param login a {@link String}.
520             */
521            public void setLogin(String login) {
522                    this.login = login;
523            }
524    
525            /**
526             * Changes the value of the <code>name</code> property.
527             * 
528             * @param name a {@link String}.
529             */
530            public void setName(String name) {
531                    this.name = name;
532            }
533    
534            /**
535             * Changes the value of the <code>password</code> property.
536             * 
537             * @param password a {@link String}.
538             */
539            public void setPassword(String password) {
540                    this.password = password;
541            }
542    
543            /**
544             * Changes the value of the <code>permissionGroups</code> property.
545             * 
546             * @param permissionGroups a {@link List<PermissionGroup>}.
547             * @deprecated Use {@link #add(PermissionGroup)} and {@link #remove(PermissionGroup)} instead.
548             */
549            @Deprecated
550            public void setPermissionGroups(List<PermissionGroup> permissionGroups) {
551                    this.permissionGroups = permissionGroups;
552            }
553    
554            /**
555             * Changes the value of the <code>removedPermissions</code> property.
556             * 
557             * @param removedPermissions a {@link List<Permission>}.
558             * @deprecated Use {@link #addRemovedPermission(Permission)} and
559             * {@link #removeRemovedPermisson(Permission)} instead.
560             */
561            @Deprecated
562            public void setRemovedPermissions(List<Permission> removedRoles) {
563                    this.removedPermissions = removedRoles;
564            }
565    
566            /**
567             * Changes the value of the <code>roles</code> property.
568             * 
569             * @param roles a {@link List<Role>}.
570             * @deprecated Use {@link #add(Role)} and {@link #remove(Role)} instead.
571             */
572            @Deprecated
573            public void setRoles(List<Role> roles) {
574                    this.roles = roles;
575            }
576    
577            /**
578             * Returns the <code>name</code> property.
579             * 
580             * @return a {@link String}.
581             */
582            @Override
583            public String toString() {
584                    return getName();
585            }
586    
587    }