/**
* The contents of this file are subject to the OpenMRS Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC. All Rights Reserved.
*/
package org.openmrs;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.api.APIException;
import org.openmrs.util.LocaleUtility;
import org.openmrs.util.OpenmrsConstants;
import org.openmrs.util.OpenmrsUtil;
import org.openmrs.util.RoleConstants;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.load.Replace;
import org.simpleframework.xml.load.Validate;
/**
* Defines a User Account in the system. This account belongs to a {@link Person} in the system,
* although that person may have other user accounts. Users have login credentials
* (username/password) and can have special user properties. User properties are just simple
* key-value pairs for either quick info or display specific info that needs to be persisted (like
* locale preferences, search options, etc)
*/
public class User extends BaseOpenmrsMetadata implements java.io.Serializable {
public static final long serialVersionUID = 2L;
private static final Log log = LogFactory.getLog(User.class);
// Fields
private Integer userId;
private Person person;
private String systemId;
private String username;
private String secretQuestion;
private Set<Role> roles;
private Map<String, String> userProperties;
private List<Locale> proficientLocales = null;
private String parsedProficientLocalesProperty = "";
// Constructors
/** default constructor */
public User() {
}
/** constructor with id */
public User(Integer userId) {
this.userId = userId;
}
/** constructor with person object */
public User(Person person) {
this.person = person;
}
/**
* Return true if this user has all privileges
*
* @return true/false if this user is defined as a super user
*/
public boolean isSuperUser() {
Set<Role> tmproles = getAllRoles();
Role role = new Role(RoleConstants.SUPERUSER); // default administrator with
// complete control
if (tmproles.contains(role))
return true;
return false;
}
/**
* This method shouldn't be used directly. Use org.openmrs.api.context.Context#hasPrivilege so
* that anonymous/authenticated/proxy privileges are all included Return true if this user has
* the specified privilege
*
* @param privilege
* @return true/false depending on whether user has specified privilege
*/
public boolean hasPrivilege(String privilege) {
// All authenticated users have the "" (empty) privilege
if (privilege == null || privilege.equals(""))
return true;
if (isSuperUser())
return true;
Set<Role> tmproles = getAllRoles();
// loop over the roles and check each for the privilege
for (Iterator<Role> i = tmproles.iterator(); i.hasNext();) {
if (i.next().hasPrivilege(privilege))
return true;
}
return false;
}
/**
* Check if this user has the given String role
*
* @param r String name of a role to check
* @return Returns true if this user has the specified role, false otherwise
*/
public boolean hasRole(String r) {
return hasRole(r, false);
}
/**
* Checks if this user has the given String role
*
* @param r String name of a role to check
* @param ignoreSuperUser If this is false, then this method will always return true for a
* superuser.
* @return Returns true if the user has the given role, or if ignoreSuperUser is false and the
* user is a superUser
*/
public boolean hasRole(String r, boolean ignoreSuperUser) {
if (ignoreSuperUser == false) {
if (isSuperUser())
return true;
}
if (roles == null)
return false;
Set<Role> tmproles = getAllRoles();
if (log.isDebugEnabled())
log.debug("User #" + userId + " has roles: " + tmproles);
Role role = new Role(r);
if (tmproles.contains(role))
return true;
return false;
}
/**
* Get <i>all</i> privileges this user has. This delves into all of the roles that a person has,
* appending unique privileges
*
* @return Collection of complete Privileges this user has
*/
public Collection<Privilege> getPrivileges() {
Set<Privilege> privileges = new HashSet<Privilege>();
Set<Role> tmproles = getAllRoles();
Role role;
for (Iterator<Role> i = tmproles.iterator(); i.hasNext();) {
role = i.next();
Collection<Privilege> privs = role.getPrivileges();
if (privs != null)
privileges.addAll(privs);
}
return privileges;
}
/**
* Compares two objects for similarity
*
* @param obj
* @return boolean true/false whether or not they are the same objects
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof User) {
User user = (User) obj;
if (getUserId() != null && user.getUserId() != null)
return userId.equals(user.getUserId());
}
// if userId is null for either object, for equality the
// two objects must be the same
return this == obj;
}
/**
* The hashcode for a user is used to index the objects in a tree
*
* @see org.openmrs.Person#hashCode()
*/
@Override
public int hashCode() {
if (getUserId() == null)
return super.hashCode();
return getUserId().hashCode();
}
// Property accessors
/**
* Returns all roles attributed to this user by expanding the role list to include the parents
* of the assigned roles
*
* @return all roles (inherited from parents and given) for this user
*/
public Set<Role> getAllRoles() {
// the user's immediate roles
Set<Role> baseRoles = new HashSet<Role>();
// the user's complete list of roles including
// the parent roles of their immediate roles
Set<Role> totalRoles = new HashSet<Role>();
if (getRoles() != null) {
baseRoles.addAll(getRoles());
totalRoles.addAll(getRoles());
}
if (log.isDebugEnabled())
log.debug("User's base roles: " + baseRoles);
try {
for (Role r : baseRoles) {
totalRoles.addAll(r.getAllParentRoles());
}
}
catch (ClassCastException e) {
log.error("Error converting roles for user: " + this);
log.error("baseRoles.class: " + baseRoles.getClass().getName());
log.error("baseRoles: " + baseRoles.toString());
Iterator<Role> iter = baseRoles.iterator();
while (iter.hasNext()) {
log.error("baseRole: '" + iter.next() + "'");
}
}
return totalRoles;
}
/**
* @return Returns the roles.
*/
public Set<Role> getRoles() {
return roles;
}
/**
* @param roles The roles to set.
*/
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
/**
* Add the given Role to the list of roles for this User
*
* @param role
* @return Returns this user with the given role attached
*/
public User addRole(Role role) {
if (roles == null)
roles = new HashSet<Role>();
if (!roles.contains(role) && role != null)
roles.add(role);
return this;
}
/**
* Remove the given Role from the list of roles for this User
*
* @param role
* @return this user with the given role removed
*/
public User removeRole(Role role) {
if (roles != null)
roles.remove(role);
return this;
}
/**
* @return Returns the systemId.
*/
@Attribute(required = false)
public String getSystemId() {
return systemId;
}
/**
* @param systemId The systemId to set.
*/
@Attribute(required = false)
public void setSystemId(String systemId) {
this.systemId = systemId;
}
/**
* @return Returns the userId.
*/
@Attribute(required = true)
public Integer getUserId() {
return userId;
}
/**
* @param userId The userId to set.
*/
@Attribute(required = true)
public void setUserId(Integer userId) {
this.userId = userId;
}
/**
* @deprecated see {@link #setPerson(Person)}
*/
@Deprecated
public void setPersonId(Integer personId) {
throw new APIException("You need to call setPerson(Person)");
}
/**
* @return the person
* @since 1.6
*/
public Person getPerson() {
return person;
}
/**
* @return the person, creating a new object if person is null
*/
private Person getPersonMaybeCreate() {
if (person == null)
person = new Person();
return person;
}
/**
* @param person the person to set
* @since 1.6
*/
public void setPerson(Person person) {
this.person = person;
}
/**
* @return Returns the username.
*/
@Attribute(required = false)
public String getUsername() {
return username;
}
/**
* @param username The username to set.
*/
@Attribute(required = false)
public void setUsername(String username) {
this.username = username;
}
/**
* @return Returns the secretQuestion.
*/
public String getSecretQuestion() {
return secretQuestion;
}
/**
* @param secretQuestion The secretQuestion to set.
*/
public void setSecretQuestion(String secretQuestion) {
this.secretQuestion = secretQuestion;
}
@Override
public String toString() {
return username;
}
/**
* @return Returns the userProperties.
*/
public Map<String, String> getUserProperties() {
if (userProperties == null)
userProperties = new HashMap<String, String>();
return userProperties;
}
/**
* @param userProperties A Map<String,String> of the properties to set.
*/
public void setUserProperties(Map<String, String> userProperties) {
this.userProperties = userProperties;
}
/**
* Convenience method. Adds the given property to the user's properties
*/
public void setUserProperty(String prop, String value) {
getUserProperties().put(prop, value);
}
/**
* Convenience method. Removes the given property from the user's properties
*/
public void removeUserProperty(String prop) {
if (getUserProperties() != null && userProperties.containsKey(prop))
userProperties.remove(prop);
}
/**
* Get prop property from this user's properties. If prop is not found in properties, return
* empty string
*
* @param prop
* @return property value
*/
public String getUserProperty(String prop) {
if (getUserProperties() != null && userProperties.containsKey(prop))
return userProperties.get(prop);
return "";
}
/**
* Get prop property from this user's properties. If prop is not found in properties, return
* <code>defaultValue</code>
*
* @param prop
* @param defaultValue
* @return property value
* @see #getUserProperty(java.lang.String)
*/
public String getUserProperty(String prop, String defaultValue) {
if (getUserProperties() != null && userProperties.containsKey(prop))
return userProperties.get(prop);
return defaultValue;
}
/**
* @see Person#addName(PersonName)
*/
public void addName(PersonName name) {
getPersonMaybeCreate().addName(name);
}
/**
* @see Person#getPersonName()
*/
public PersonName getPersonName() {
return getPerson() == null ? null : getPerson().getPersonName();
}
/**
* Get givenName on the Person this user account belongs to
*
* @see Person#getGivenName()
*/
public String getGivenName() {
return getPerson() == null ? null : getPerson().getGivenName();
}
/**
* Get familyName on the Person this user account belongs to
*
* @see Person#getFamilyName()
*/
public String getFamilyName() {
return getPerson() == null ? null : getPerson().getFamilyName();
}
/**
* @see org.openmrs.Person#getNames()
*/
public Set<PersonName> getNames() {
return person.getNames();
}
/**
* @deprecated use <tt>getGivenName</tt> on <tt>Person</tt>
* @return String user's first name
*/
@Deprecated
public String getFirstName() {
return getGivenName();
}
/**
* @deprecated use <tt>getFamilyName</tt> on <tt>Person</tt>
* @return String user's last name
*/
@Deprecated
public String getLastName() {
return getFamilyName();
}
/**
* If the serializer wishes, don't serialize this entire object, just the important parts
*
* @param sessionMap serialization session information
* @return User object to serialize
* @see OpenmrsUtil#isShortSerialization(Map)
*/
@Replace
public User replaceSerialization(Map<?, ?> sessionMap) {
if (OpenmrsUtil.isShortSerialization(sessionMap)) {
// only serialize the user id
return new User(getUserId());
}
// don't do short serialization
return this;
}
@Validate
public void validateSerialization(Map<?, ?> sessionMap) {
if (OpenmrsUtil.isShortSerialization(sessionMap)) {
// only serialize the user id
}
return;
}
/**
* Returns a list of Locales for which the User is considered proficient.
*
* @return List of the User's proficient locales
*/
public List<Locale> getProficientLocales() {
String proficientLocalesProperty = getUserProperty(OpenmrsConstants.USER_PROPERTY_PROFICIENT_LOCALES);
if ((proficientLocales == null) || (!parsedProficientLocalesProperty.equals(proficientLocalesProperty))) {
parsedProficientLocalesProperty = proficientLocalesProperty;
proficientLocales = new ArrayList<Locale>();
String[] proficientLocalesArray = proficientLocalesProperty.split(",");
for (String proficientLocaleSpec : proficientLocalesArray) {
if (proficientLocaleSpec.length() > 0) {
Locale proficientLocale = LocaleUtility.fromSpecification(proficientLocaleSpec);
if (!proficientLocales.contains(proficientLocale)) {
proficientLocales.add(proficientLocale);
if (!"".equals(proficientLocale.getCountry())) {
// add the language also
Locale languageOnlyLocale = LocaleUtility.fromSpecification(proficientLocale.getLanguage());
if (!proficientLocales.contains(languageOnlyLocale)) {
proficientLocales.add(LocaleUtility.fromSpecification(proficientLocale.getLanguage()));
}
}
}
}
}
}
// return a copy so that the list isn't changed by other processes
return new ArrayList<Locale>(proficientLocales);
}
/**
* @since 1.5
* @see org.openmrs.OpenmrsObject#getId()
*/
public Integer getId() {
return getUserId();
}
/**
* @since 1.5
* @see org.openmrs.OpenmrsObject#setId(java.lang.Integer)
*/
public void setId(Integer id) {
setUserId(id);
}
}