Unique username and some first update routine (still needs testing) #4102
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / User.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.cdm.model.common;
11
12 import java.util.Collection;
13 import java.util.HashSet;
14 import java.util.Set;
15
16 import javax.persistence.Column;
17 import javax.persistence.Entity;
18 import javax.persistence.FetchType;
19 import javax.persistence.ManyToMany;
20 import javax.persistence.OneToOne;
21 import javax.persistence.Table;
22 import javax.persistence.Transient;
23 import javax.xml.bind.annotation.XmlAccessType;
24 import javax.xml.bind.annotation.XmlAccessorType;
25 import javax.xml.bind.annotation.XmlElement;
26 import javax.xml.bind.annotation.XmlElementWrapper;
27 import javax.xml.bind.annotation.XmlIDREF;
28 import javax.xml.bind.annotation.XmlRootElement;
29 import javax.xml.bind.annotation.XmlSchemaType;
30 import javax.xml.bind.annotation.XmlTransient;
31 import javax.xml.bind.annotation.XmlType;
32
33 import org.apache.log4j.Logger;
34 import org.hibernate.annotations.Cascade;
35 import org.hibernate.annotations.CascadeType;
36 import org.hibernate.envers.Audited;
37 import org.hibernate.envers.NotAudited;
38 import org.hibernate.search.annotations.Analyze;
39 import org.hibernate.search.annotations.Field;
40 import org.hibernate.search.annotations.Indexed;
41 import org.hibernate.search.annotations.IndexedEmbedded;
42 import org.springframework.security.core.GrantedAuthority;
43 import org.springframework.security.core.userdetails.UserDetails;
44
45 import eu.etaxonomy.cdm.model.agent.Person;
46
47 @XmlAccessorType(XmlAccessType.FIELD)
48 @XmlType(name = "User", propOrder = {
49 "username",
50 "password",
51 "emailAddress",
52 "grantedAuthorities",
53 "groups",
54 "enabled",
55 "accountNonExpired",
56 "credentialsNonExpired",
57 "accountNonLocked",
58 "person"
59 })
60 @XmlRootElement(name = "User")
61 @Entity
62 @Indexed(index = "eu.etaxonomy.cdm.model.common.User")
63 @Audited
64 @Table(name = "UserAccount")
65 public class User extends CdmBase implements UserDetails {
66 private static final long serialVersionUID = 6582191171369439163L;
67 private static final Logger logger = Logger.getLogger(User.class);
68
69 // **************************** FACTORY *****************************************/
70
71 public static User NewInstance(String username, String pwd){
72 User user = new User();
73 user.setUsername(username);
74 user.setPassword(pwd);
75
76 user.setAccountNonExpired(true);
77 user.setAccountNonLocked(true);
78 user.setCredentialsNonExpired(true);
79 user.setEnabled(true);
80
81 return user;
82 }
83
84 public static User NewInstance(String personTitle, String username, String pwd){
85 User user = new User();
86 user.setUsername(username);
87 user.setPassword(pwd);
88
89 user.setAccountNonExpired(true);
90 user.setAccountNonLocked(true);
91 user.setCredentialsNonExpired(true);
92 user.setEnabled(true);
93 Person userPerson = Person.NewTitledInstance(personTitle);
94 user.setPerson(userPerson);
95
96 return user;
97 }
98
99 //***************************** Fields *********************** /
100
101 @XmlElement(name = "Username")
102 @Column(unique = true)
103 @Field(analyze = Analyze.NO)
104 protected String username;
105
106 /**
107 * a salted, MD5 encoded hash of the plaintext password
108 */
109 @XmlElement(name = "Password")
110 @NotAudited
111 protected String password;
112
113 @XmlElement(name = "EmailAddress")
114 protected String emailAddress;
115
116 @XmlElementWrapper(name = "GrantedAuthorities")
117 @XmlElement(name = "GrantedAuthority", type = GrantedAuthorityImpl.class)
118 @XmlIDREF
119 @XmlSchemaType(name = "IDREF")
120 @ManyToMany(fetch = FetchType.LAZY, targetEntity = GrantedAuthorityImpl.class)
121 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.REFRESH}) // see #2414 (Group updating doesn't work)
122 @NotAudited
123 protected Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>(); //authorities of this user only
124
125 @XmlElementWrapper(name = "Groups")
126 @XmlElement(name = "Group")
127 @XmlIDREF
128 @XmlSchemaType(name = "IDREF")
129 @ManyToMany(fetch = FetchType.LAZY)
130 @Cascade(CascadeType.REFRESH) // see #2414 (Group updating doesn't work)
131 @IndexedEmbedded(depth = 1)
132 @NotAudited
133 protected Set<Group> groups = new HashSet<Group>();
134
135 @XmlElement(name = "Enabled")
136 protected boolean enabled;
137
138 @XmlElement(name = "AccountNonExpired")
139 protected boolean accountNonExpired;
140
141 @XmlElement(name = "CredentialsNonExpired")
142 protected boolean credentialsNonExpired;
143
144 @XmlElement(name = "AccountNonLocked")
145 protected boolean accountNonLocked;
146
147 @XmlElement(name = "Person")
148 @XmlIDREF
149 @XmlSchemaType(name = "IDREF")
150 @OneToOne(fetch = FetchType.LAZY)
151 @Cascade({CascadeType.SAVE_UPDATE})
152 @IndexedEmbedded(depth = 1)
153 protected Person person;
154
155 @XmlTransient
156 @Transient
157 private Set<GrantedAuthority> authorities; //authorities of this user and of all groups the user belongs to
158
159 //***************************** Constructor *********************** /
160
161 protected User(){
162 super();
163 }
164
165 // ***************************** METHODS ******************************/
166
167 /**
168 * Initializes or refreshes the collection of authorities, See
169 * {@link #getAuthorities()}
170 */
171 //FIXME made public as preliminary solution to #4053 (Transient field User.authorities not refreshed on reloading entity)
172 public void initAuthorities() {
173 authorities = new HashSet<GrantedAuthority>();
174 authorities.addAll(grantedAuthorities);
175 for(Group group : groups) {
176 authorities.addAll(group.getGrantedAuthorities());
177 }
178 }
179
180 /**
181 * Implementation of {@link UserDetails#getAuthorities()}
182 *
183 * {@inheritDoc}
184 *
185 * @return returns all {@code Set<GrantedAuthority>} instances contained in
186 * the sets {@link #getGrantedAuthorities()} and
187 * {@link #getGroups()}
188 */
189 @Override
190 @Transient
191 public Collection<GrantedAuthority> getAuthorities() {
192 if(authorities == null || authorities.size() == 0) {
193 initAuthorities();
194 }
195 return authorities;
196 }
197
198 @Override
199 public String getPassword() {
200 return password;
201 }
202
203 @Override
204 public String getUsername() {
205 return username;
206 }
207
208 @Override
209 public boolean isAccountNonExpired() {
210 return accountNonExpired;
211 }
212
213 @Override
214 public boolean isAccountNonLocked() {
215 return accountNonLocked;
216 }
217
218 @Override
219 public boolean isCredentialsNonExpired() {
220 return credentialsNonExpired;
221 }
222
223 @Override
224 public boolean isEnabled() {
225 return enabled;
226 }
227
228 public String getEmailAddress() {
229 return emailAddress;
230 }
231
232 public void setEmailAddress(String emailAddress) {
233 this.emailAddress = emailAddress;
234 }
235
236 public Set<GrantedAuthority> getGrantedAuthorities() {
237 return grantedAuthorities;
238 }
239
240 public void setGrantedAuthorities(Set<GrantedAuthority> grantedAuthorities) {
241 this.grantedAuthorities = grantedAuthorities;
242 initAuthorities();
243 }
244
245 public void setUsername(String username) {
246 this.username = username;
247 }
248
249 public void setPassword(String password) {
250 this.password = password;
251 }
252
253 public void setEnabled(boolean enabled) {
254 this.enabled = enabled;
255 }
256
257 public void setAccountNonExpired(boolean accountNonExpired) {
258 this.accountNonExpired = accountNonExpired;
259 }
260
261 public void setCredentialsNonExpired(boolean credentialsNonExpired) {
262 this.credentialsNonExpired = credentialsNonExpired;
263 }
264
265 public void setAccountNonLocked(boolean accountNonLocked) {
266 this.accountNonLocked = accountNonLocked;
267 }
268
269 protected void setGroups(Set<Group> groups) {
270 this.groups = groups;
271 initAuthorities();
272 }
273
274 public Set<Group> getGroups() {
275 return groups;
276 }
277
278
279 public Person getPerson() {
280 return person;
281 }
282
283 public void setPerson(Person person) {
284 this.person = person;
285 }
286
287 //*********************** CLONE ********************************************************/
288
289 /**
290 * Clones <i>this</i> User. This is a shortcut that enables to create
291 * a new instance that differs only slightly from <i>this</i> User.
292 * The corresponding person is cloned.
293 *
294 * @see eu.etaxonomy.cdm.model.common.CdmBase#clone()
295 * @see java.lang.Object#clone()
296 */
297 @Override
298 public Object clone() {
299 try{
300 User result = (User)super.clone();
301 result.setPerson((Person)this.person.clone());
302 return result;
303 } catch (CloneNotSupportedException e){
304 logger.warn("Object does not implement cloneable");
305 e.printStackTrace();
306 return null;
307 }
308
309
310 }
311 }