#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
index 7d763b53200317514133d131ce1fde3c3702be48..a8a139f027c3659bad34188089a6e485cb46a415 100644 (file)
-/**\r
-* Copyright (C) 2007 EDIT\r
-* European Distributed Institute of Taxonomy \r
-* http://www.e-taxonomy.eu\r
-* \r
-* The contents of this file are subject to the Mozilla Public License Version 1.1\r
-* See LICENSE.TXT at the top of this package for the full license terms.\r
-*/\r
-\r
-package eu.etaxonomy.cdm.model.common;\r
-\r
-import java.util.Collection;\r
-import java.util.HashSet;\r
-import java.util.Set;\r
-\r
-import javax.persistence.Entity;\r
-import javax.persistence.FetchType;\r
-import javax.persistence.ManyToMany;\r
-import javax.persistence.OneToOne;\r
-import javax.persistence.Table;\r
-import javax.persistence.Transient;\r
-import javax.xml.bind.annotation.XmlAccessType;\r
-import javax.xml.bind.annotation.XmlAccessorType;\r
-import javax.xml.bind.annotation.XmlElement;\r
-import javax.xml.bind.annotation.XmlElementWrapper;\r
-import javax.xml.bind.annotation.XmlIDREF;\r
-import javax.xml.bind.annotation.XmlRootElement;\r
-import javax.xml.bind.annotation.XmlSchemaType;\r
-import javax.xml.bind.annotation.XmlTransient;\r
-import javax.xml.bind.annotation.XmlType;\r
-\r
-import org.apache.log4j.Logger;\r
-import org.hibernate.annotations.Cascade;\r
-import org.hibernate.annotations.CascadeType;\r
-import org.hibernate.annotations.NaturalId;\r
-import org.hibernate.envers.Audited;\r
-import org.hibernate.envers.NotAudited;\r
-\r
-\r
-import org.hibernate.search.annotations.Field;\r
-import org.hibernate.search.annotations.Index;\r
-import org.hibernate.search.annotations.Indexed;\r
-import org.hibernate.search.annotations.IndexedEmbedded;\r
-import org.springframework.security.core.GrantedAuthority;\r
-import org.springframework.security.core.userdetails.UserDetails;\r
-\r
-import eu.etaxonomy.cdm.model.agent.Person;\r
-\r
-@XmlAccessorType(XmlAccessType.FIELD)\r
-@XmlType(name = "User", propOrder = {\r
-    "username",\r
-    "password",\r
-    "emailAddress",\r
-    "grantedAuthorities",\r
-    "groups",\r
-    "enabled",\r
-    "accountNonExpired",\r
-    "credentialsNonExpired",\r
-    "accountNonLocked",\r
-    "person"    \r
-})\r
-@XmlRootElement(name = "User")\r
-@Entity\r
-@Indexed(index = "eu.etaxonomy.cdm.model.common.User")\r
-@Audited\r
-@Table(name = "UserAccount")\r
-public class User extends CdmBase implements UserDetails {\r
-       private static final long serialVersionUID = 6582191171369439163L;\r
-       @SuppressWarnings(value="unused")\r
-       private static final Logger logger = Logger.getLogger(User.class);\r
-       \r
-       protected User(){\r
-               super();\r
-       }\r
-       \r
-       public static User NewInstance(String username, String pwd){\r
-               User user = new User();\r
-               user.setUsername(username);\r
-               user.setPassword(pwd);\r
-               \r
-               user.setAccountNonExpired(true);\r
-               user.setAccountNonLocked(true);\r
-               user.setCredentialsNonExpired(true);\r
-               user.setEnabled(true);\r
-               \r
-               return user;\r
-       }\r
-       \r
-       public static User NewInstance(String personTitle, String username, String pwd){\r
-               User user = new User();\r
-               user.setUsername(username);\r
-               user.setPassword(pwd);\r
-               \r
-               user.setAccountNonExpired(true);\r
-               user.setAccountNonLocked(true);\r
-               user.setCredentialsNonExpired(true);\r
-               user.setEnabled(true);\r
-               Person userPerson = Person.NewTitledInstance(personTitle);\r
-               user.setPerson(userPerson);\r
-               \r
-               return user;\r
-       }\r
-       \r
-       @XmlElement(name = "Username")\r
-       @NaturalId\r
-       @Field(index = Index.UN_TOKENIZED)\r
-       protected String username;\r
-       \r
-       /**\r
-        * a salted, MD5 encoded hash of the plaintext password\r
-        */\r
-       @XmlElement(name = "Password")\r
-       @NotAudited\r
-       protected String password;\r
-       \r
-       @XmlElement(name = "EmailAddress")\r
-       protected String emailAddress;\r
-       \r
-       @XmlElementWrapper(name = "GrantedAuthorities")\r
-       @XmlElement(name = "GrantedAuthority", type = GrantedAuthorityImpl.class)\r
-       @XmlIDREF\r
-       @XmlSchemaType(name = "IDREF")\r
-       @ManyToMany(fetch = FetchType.LAZY, targetEntity = GrantedAuthorityImpl.class)\r
-       @NotAudited\r
-       protected Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>();\r
-       \r
-       @XmlElementWrapper(name = "Groups")\r
-       @XmlElement(name = "Group")\r
-       @XmlIDREF\r
-       @XmlSchemaType(name = "IDREF")\r
-       @ManyToMany(fetch = FetchType.LAZY)\r
-       @IndexedEmbedded(depth = 1)\r
-       @NotAudited\r
-       protected Set<Group> groups = new HashSet<Group>();\r
-       \r
-       @XmlElement(name = "Enabled")\r
-       protected boolean enabled;\r
-       \r
-       @XmlElement(name = "AccountNonExpired")\r
-       protected boolean accountNonExpired;\r
-\r
-       @XmlElement(name = "CredentialsNonExpired")\r
-       protected boolean credentialsNonExpired;\r
-       \r
-       @XmlElement(name = "AccountNonLocked")\r
-       protected boolean accountNonLocked;     \r
-       \r
-       @XmlElement(name = "Person")\r
-       @XmlIDREF\r
-       @XmlSchemaType(name = "IDREF")\r
-       @OneToOne(fetch = FetchType.LAZY)\r
-       @Cascade({CascadeType.SAVE_UPDATE})\r
-       @IndexedEmbedded(depth = 1)\r
-       protected Person person;\r
-       \r
-       @XmlTransient\r
-       @Transient\r
-       private Set<GrantedAuthority> authorities;\r
-       \r
-       private void initAuthorities() {\r
-               authorities = new HashSet<GrantedAuthority>();\r
-               authorities.addAll(grantedAuthorities);\r
-               for(Group group : groups) {\r
-                       authorities.addAll(group.getGrantedAuthorities());\r
-               }\r
-       }\r
-       \r
-       @Transient\r
-       public Collection<GrantedAuthority> getAuthorities() {\r
-               if(authorities == null) {\r
-                       initAuthorities();\r
-               }\r
-               return authorities;\r
-       }\r
-\r
-       public String getPassword() {\r
-               return password;\r
-       }\r
-\r
-       public String getUsername() {\r
-               return username;\r
-       }\r
-\r
-       public boolean isAccountNonExpired() {\r
-               return accountNonExpired;\r
-       }\r
-\r
-       public boolean isAccountNonLocked() {\r
-               return accountNonLocked;\r
-       }\r
-\r
-       public boolean isCredentialsNonExpired() {\r
-               return credentialsNonExpired;\r
-       }\r
-\r
-       public boolean isEnabled() {\r
-               return enabled;\r
-       }\r
-\r
-       public String getEmailAddress() {\r
-               return emailAddress;\r
-       }\r
-\r
-       public void setEmailAddress(String emailAddress) {\r
-               this.emailAddress = emailAddress;\r
-       }\r
-\r
-       public Set<GrantedAuthority> getGrantedAuthorities() {\r
-               return grantedAuthorities;\r
-       }\r
-\r
-       public void setGrantedAuthorities(Set<GrantedAuthority> grantedAuthorities) {\r
-               this.grantedAuthorities = grantedAuthorities;\r
-               initAuthorities();\r
-       }\r
-\r
-       public void setUsername(String username) {\r
-               this.username = username;\r
-       }\r
-\r
-       public void setPassword(String password) {\r
-               this.password = password;\r
-       }\r
-\r
-       public void setEnabled(boolean enabled) {\r
-               this.enabled = enabled;\r
-       }\r
-\r
-       public void setAccountNonExpired(boolean accountNonExpired) {\r
-               this.accountNonExpired = accountNonExpired;\r
-       }\r
-\r
-       public void setCredentialsNonExpired(boolean credentialsNonExpired) {\r
-               this.credentialsNonExpired = credentialsNonExpired;\r
-       }\r
-\r
-       public void setAccountNonLocked(boolean accountNonLocked) {\r
-               this.accountNonLocked = accountNonLocked;\r
-       }\r
-       \r
-       protected void setGroups(Set<Group> groups) {\r
-               this.groups = groups;\r
-               initAuthorities();\r
-       }\r
-       \r
-       public Set<Group> getGroups() {\r
-               return groups;\r
-       }\r
-       \r
-       \r
-       public Person getPerson() {\r
-               return person;\r
-       }\r
-       \r
-       public void setPerson(Person person) {\r
-               this.person = person;\r
-       }\r
-}\r
+/**
+* Copyright (C) 2007 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+
+package eu.etaxonomy.cdm.model.common;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import javax.validation.constraints.NotNull;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlIDREF;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.log4j.Logger;
+import org.hibernate.annotations.Cascade;
+import org.hibernate.annotations.CascadeType;
+import org.hibernate.envers.Audited;
+import org.hibernate.envers.NotAudited;
+import org.hibernate.search.annotations.Analyze;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.IndexedEmbedded;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import eu.etaxonomy.cdm.model.agent.Person;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "User", propOrder = {
+    "username",
+    "password",
+    "emailAddress",
+    "grantedAuthorities",
+    "groups",
+    "enabled",
+    "accountNonExpired",
+    "credentialsNonExpired",
+    "accountNonLocked",
+    "person"
+})
+@XmlRootElement(name = "User")
+@Entity
+//@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
+//@Indexed(index = "eu.etaxonomy.cdm.model.common.User")
+@Audited
+@Table(name = "UserAccount")
+public class User extends CdmBase implements UserDetails {
+    private static final long serialVersionUID = 6582191171369439163L;
+    private static final Logger logger = Logger.getLogger(User.class);
+
+ // **************************** FACTORY *****************************************/
+
+    public static User NewInstance(String username, String pwd){
+        User user = new User();
+        user.setUsername(username);
+        user.setPassword(pwd);
+
+        user.setAccountNonExpired(true);
+        user.setAccountNonLocked(true);
+        user.setCredentialsNonExpired(true);
+        user.setEnabled(true);
+
+        return user;
+    }
+
+    public static User NewInstance(String personTitle, String username, String pwd){
+        User user = new User();
+        user.setUsername(username);
+        user.setPassword(pwd);
+
+        user.setAccountNonExpired(true);
+        user.setAccountNonLocked(true);
+        user.setCredentialsNonExpired(true);
+        user.setEnabled(true);
+        Person userPerson = Person.NewTitledInstance(personTitle);
+        user.setPerson(userPerson);
+
+        return user;
+    }
+
+//***************************** Fields *********************** /
+
+    @XmlElement(name = "Username")
+    @Column(unique = true)
+    @Field(analyze = Analyze.NO)
+    @NotNull
+    protected String username;
+
+    /**
+     * a salted, MD5 encoded hash of the plaintext password
+     */
+    @XmlElement(name = "Password")
+    @NotAudited
+    protected String password;
+
+    @XmlElement(name = "EmailAddress")
+    protected String emailAddress;
+
+    @XmlElementWrapper(name = "GrantedAuthorities")
+    @XmlElement(name = "GrantedAuthority", type = GrantedAuthorityImpl.class)
+    @XmlIDREF
+    @XmlSchemaType(name = "IDREF")
+    @ManyToMany(fetch = FetchType.LAZY, targetEntity = GrantedAuthorityImpl.class)
+    //preliminary  #5369
+    @JoinTable(joinColumns = @JoinColumn( name="UserAccount_id"))
+    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE, CascadeType.REFRESH}) // see #2414 (Group updating doesn't work)
+    @NotAudited
+    protected Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>();  //authorities of this user only
+
+    @XmlElementWrapper(name = "Groups")
+    @XmlElement(name = "Group")
+    @XmlIDREF
+    @XmlSchemaType(name = "IDREF")
+    @ManyToMany(fetch = FetchType.LAZY)
+        @Cascade({CascadeType.REFRESH, CascadeType.SAVE_UPDATE,CascadeType.MERGE}) // see #2414 (Group updating doesn't work)
+    @IndexedEmbedded(depth = 1)
+    @NotAudited
+    protected Set<Group> groups = new HashSet<Group>();
+
+    @XmlElement(name = "Enabled")
+    protected boolean enabled;
+
+    @XmlElement(name = "AccountNonExpired")
+    protected boolean accountNonExpired;
+
+    @XmlElement(name = "CredentialsNonExpired")
+    protected boolean credentialsNonExpired;
+
+    @XmlElement(name = "AccountNonLocked")
+    protected boolean accountNonLocked;
+
+    @XmlElement(name = "Person")
+    @XmlIDREF
+    @XmlSchemaType(name = "IDREF")
+    @OneToOne(fetch = FetchType.LAZY)
+    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
+    @IndexedEmbedded(depth = 1)
+    protected Person person;
+
+    @XmlTransient
+    @Transient
+    private Set<GrantedAuthority> authorities;  //authorities of this user and of all groups the user belongs to
+
+//***************************** Constructor *********************** /
+
+    protected User(){
+        super();
+    }
+
+// ***************************** METHODS ******************************/
+
+    /**
+     * Initializes or refreshes the collection of authorities, See
+     * {@link #getAuthorities()}
+     */
+    //FIXME made public as preliminary solution to #4053 (Transient field User.authorities not refreshed on reloading entity)
+    public void initAuthorities() {
+        authorities = new HashSet<GrantedAuthority>();
+        authorities.addAll(grantedAuthorities);
+        for(Group group : groups) {
+            authorities.addAll(group.getGrantedAuthorities());
+        }
+    }
+
+    /**
+     * Implementation of {@link UserDetails#getAuthorities()}
+     *
+     * {@inheritDoc}
+     *
+     * @return returns all {@code Set<GrantedAuthority>} instances contained in
+     *         the sets {@link #getGrantedAuthorities()} and
+     *         {@link #getGroups()}
+     */
+    @Override
+    @Transient
+    public Collection<GrantedAuthority> getAuthorities() {
+        if(authorities == null || authorities.size() == 0) {
+            initAuthorities();
+        }
+        return authorities;
+    }
+
+    @Override
+    public String getPassword() {
+        return password;
+    }
+
+    @Override
+    public String getUsername() {
+        return username;
+    }
+
+    @Override
+    public boolean isAccountNonExpired() {
+        return accountNonExpired;
+    }
+
+    @Override
+    public boolean isAccountNonLocked() {
+        return accountNonLocked;
+    }
+
+    @Override
+    public boolean isCredentialsNonExpired() {
+        return credentialsNonExpired;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public String getEmailAddress() {
+        return emailAddress;
+    }
+
+    public void setEmailAddress(String emailAddress) {
+        this.emailAddress = emailAddress;
+    }
+
+    public Set<GrantedAuthority> getGrantedAuthorities() {
+        return grantedAuthorities;
+    }
+
+    public void setGrantedAuthorities(Set<GrantedAuthority> grantedAuthorities) {
+        this.grantedAuthorities = grantedAuthorities;
+        initAuthorities();
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public void setAccountNonExpired(boolean accountNonExpired) {
+        this.accountNonExpired = accountNonExpired;
+    }
+
+    public void setCredentialsNonExpired(boolean credentialsNonExpired) {
+        this.credentialsNonExpired = credentialsNonExpired;
+    }
+
+    public void setAccountNonLocked(boolean accountNonLocked) {
+        this.accountNonLocked = accountNonLocked;
+    }
+
+    protected void setGroups(Set<Group> groups) {
+        this.groups = groups;
+        initAuthorities();
+    }
+
+    public Set<Group> getGroups() {
+        return groups;
+    }
+
+
+    public Person getPerson() {
+        return person;
+    }
+
+    public void setPerson(Person person) {
+        this.person = person;
+    }
+
+    public static User getCurrentAuthenticatedUser() {
+        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+        if(authentication != null && authentication.getPrincipal() != null && authentication.getPrincipal() instanceof User) {
+            return (User)authentication.getPrincipal();
+        }
+        return null;
+    }
+
+//*********************** CLONE ********************************************************/
+
+    /**
+     * Clones <i>this</i> User. This is a shortcut that enables to create
+     * a new instance that differs only slightly from <i>this</i> User.
+     * The corresponding person is cloned.
+     *
+     * @see eu.etaxonomy.cdm.model.common.CdmBase#clone()
+     * @see java.lang.Object#clone()
+     */
+    @Override
+    public Object clone() {
+        try{
+            User result = (User)super.clone();
+            result.setPerson((Person)this.person.clone());
+            return result;
+        } catch (CloneNotSupportedException e){
+            logger.warn("Object does not implement cloneable");
+            e.printStackTrace();
+            return null;
+        }
+
+
+    }
+}