package fr.openwide.core.jpa.security.business.person.model; import java.util.Collections; import java.util.Date; import java.util.LinkedHashSet; import java.util.Locale; import java.util.Set; import javax.persistence.Column; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.MappedSuperclass; import javax.persistence.UniqueConstraint; import org.bindgen.Bindable; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.NaturalId; import org.hibernate.annotations.NaturalIdCache; import org.hibernate.annotations.SortComparator; import org.hibernate.search.annotations.Analyzer; import org.hibernate.search.annotations.DocumentId; import org.hibernate.search.annotations.Field; import org.hibernate.search.annotations.FieldBridge; import org.hibernate.search.annotations.Fields; import org.hibernate.search.annotations.Indexed; import org.hibernate.search.annotations.SortableField; import org.springframework.security.acls.model.Permission; import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.common.collect.Sets; import com.querydsl.core.annotations.PropertyType; import com.querydsl.core.annotations.QueryType; import fr.openwide.core.commons.util.CloneUtils; import fr.openwide.core.commons.util.collections.CollectionUtils; import fr.openwide.core.jpa.business.generic.model.GenericEntity; import fr.openwide.core.jpa.search.bridge.GenericEntityCollectionIdFieldBridge; import fr.openwide.core.jpa.search.util.HibernateSearchAnalyzer; import fr.openwide.core.jpa.security.business.authority.model.Authority; import fr.openwide.core.jpa.security.business.person.util.AbstractPersonGroupComparator; @Indexed @MappedSuperclass @Bindable @NaturalIdCache public abstract class GenericUser<U extends GenericUser<U, G>, G extends GenericUserGroup<G, U>> extends GenericEntity<Long, U> implements IGroupedUser<G> { private static final long serialVersionUID = 1803671157183603979L; public static final String USER_NAME_SORT_FIELD_NAME = "userNameSort"; @Id @GeneratedValue @DocumentId private Long id; @Column(nullable = false) @NaturalId(mutable = true) @Fields({ @Field(analyzer = @Analyzer(definition = HibernateSearchAnalyzer.TEXT)), @Field(name = USER_NAME_SORT_FIELD_NAME, analyzer = @Analyzer(definition = HibernateSearchAnalyzer.TEXT_SORT)) }) @SortableField(forField = USER_NAME_SORT_FIELD_NAME) private String userName; @JsonIgnore private String passwordHash = "*NO PASSWORD*"; @Field private boolean active = true; @JsonIgnore @Column(nullable = false) private Date creationDate = new Date(); @JsonIgnore @Column(nullable = false) private Date lastUpdateDate = new Date(); @JsonIgnore private Date lastLoginDate; /** * preferred locale for user, can be null */ @JsonIgnore private Locale locale; @JsonIgnore @ManyToMany @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE}) private Set<Authority> authorities = new LinkedHashSet<Authority>(); @ManyToMany @JoinTable(uniqueConstraints = { @UniqueConstraint(columnNames = { "persons_id", "groups_id" }) }) @SortComparator(AbstractPersonGroupComparator.class) @Field(bridge = @FieldBridge(impl = GenericEntityCollectionIdFieldBridge.class), analyzer = @Analyzer(definition = HibernateSearchAnalyzer.KEYWORD)) private Set<G> groups = Sets.newTreeSet(AbstractPersonGroupComparator.get()); public GenericUser() { } public GenericUser(String userName, String passwordHash) { this.userName = userName; this.passwordHash = passwordHash; } @Override public Long getId() { return id; } @Override public void setId(Long id) { this.id = id; } @Override public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public abstract String getFullName(); @Override public Set<Authority> getAuthorities() { return Collections.unmodifiableSet(authorities); } public void setAuthorities(Set<Authority> authorities) { CollectionUtils.replaceAll(this.authorities, authorities); } public void addAuthority(Authority authority) { this.authorities.add(authority); } public void removeAuthority(Authority authority) { this.authorities.remove(authority); } @Override public Set<G> getGroups() { return Collections.unmodifiableSet(groups); } public void setGroups(Set<G> groups) { CollectionUtils.replaceAll(this.groups, groups); } @Override public void addGroup(G group) { this.groups.add(group); } @Override public void removeGroup(G personGroup) { this.groups.remove(personGroup); } @Override public String getPasswordHash() { return passwordHash; } public void setPasswordHash(String passwordHash) { this.passwordHash = passwordHash; } public void setActive(boolean active) { this.active = active; } @Override public boolean isActive() { return active; } public void setLastLoginDate(Date lastLoginDate) { this.lastLoginDate = CloneUtils.clone(lastLoginDate); } public Date getLastLoginDate() { return CloneUtils.clone(lastLoginDate); } public void setCreationDate(Date creationDate) { this.creationDate = CloneUtils.clone(creationDate); } public Date getCreationDate() { return CloneUtils.clone(creationDate); } public Date getLastUpdateDate() { return CloneUtils.clone(lastUpdateDate); } public void setLastUpdateDate(Date lastUpdateDate) { this.lastUpdateDate = CloneUtils.clone(lastUpdateDate); } /** * Fournit la locale préférée de l'utilisateur. Il faut utiliser * {@link CoreConfigurer##toAvailableLocale(Locale)} si la locale * préférée de l'utilisateur doit être exploitée pour choisir des traductions. * Cette méthode permet de mapper une locale quelconque (incluant null) sur * une locale qui sera obligatoirement reconnue pas le système (de manière à * avoir un fonctionnement prédictible). * @return une locale, possiblement null */ public Locale getLocale() { return locale; } public void setLocale(Locale locale) { this.locale = locale; } @Override @QueryType(PropertyType.NONE) public Set<? extends Permission> getPermissions() { return Sets.newHashSetWithExpectedSize(0); } @Override public int compareTo(U user) { if(this.equals(user)) { return 0; } return DEFAULT_STRING_COLLATOR.compare(this.getUserName(), user.getUserName()); } @Override public String getNameForToString() { return getUserName(); } @Override public String getDisplayName() { return getUserName(); } }