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