/**
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
*
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
* graphic logo is a trademark of OpenMRS Inc.
*/
package org.openmrs;
import static org.apache.commons.lang.StringUtils.defaultString;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.hibernate.search.annotations.Analyzer;
import org.hibernate.search.annotations.Boost;
import org.hibernate.search.annotations.DocumentId;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Fields;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.openmrs.api.db.hibernate.search.LuceneAnalyzers;
import org.openmrs.util.OpenmrsConstants;
import org.openmrs.util.OpenmrsUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
/**
* A Person can have zero to n PersonName(s).
*/
@Indexed
public class PersonName extends BaseOpenmrsData implements java.io.Serializable, Cloneable, Comparable<PersonName> {
public static final long serialVersionUID = 4353L;
private static final Logger log = LoggerFactory.getLogger(PersonName.class);
// Fields
@DocumentId
private Integer personNameId;
@IndexedEmbedded(includeEmbeddedObjectId = true)
private Person person;
private Boolean preferred = false;
@Fields({
@Field(name = "givenNameExact", analyzer = @Analyzer(definition = LuceneAnalyzers.EXACT_ANALYZER), boost = @Boost(8f)),
@Field(name = "givenNameStart", analyzer = @Analyzer(definition = LuceneAnalyzers.START_ANALYZER), boost = @Boost(4f)),
@Field(name = "givenNameAnywhere", analyzer = @Analyzer(definition = LuceneAnalyzers.ANYWHERE_ANALYZER), boost = @Boost(2f))
})
private String givenName;
private String prefix;
@Fields({
@Field(name = "middleNameExact", analyzer = @Analyzer(definition = LuceneAnalyzers.EXACT_ANALYZER), boost = @Boost(4f)),
@Field(name = "middleNameStart", analyzer = @Analyzer(definition = LuceneAnalyzers.START_ANALYZER), boost = @Boost(2f)),
@Field(name = "middleNameAnywhere", analyzer = @Analyzer(definition = LuceneAnalyzers.ANYWHERE_ANALYZER))
})
private String middleName;
private String familyNamePrefix;
@Fields({
@Field(name = "familyNameExact", analyzer = @Analyzer(definition = LuceneAnalyzers.EXACT_ANALYZER), boost = @Boost(8f)),
@Field(name = "familyNameStart", analyzer = @Analyzer(definition = LuceneAnalyzers.START_ANALYZER), boost = @Boost(4f)),
@Field(name = "familyNameAnywhere", analyzer = @Analyzer(definition = LuceneAnalyzers.ANYWHERE_ANALYZER), boost = @Boost(2f)),
})
private String familyName;
@Fields({
@Field(name = "familyName2Exact", analyzer = @Analyzer(definition = LuceneAnalyzers.EXACT_ANALYZER), boost = @Boost(4f)),
@Field(name = "familyName2Start", analyzer = @Analyzer(definition = LuceneAnalyzers.START_ANALYZER), boost = @Boost(2f)),
@Field(name = "familyName2Anywhere", analyzer = @Analyzer(definition = LuceneAnalyzers.ANYWHERE_ANALYZER)),
})
private String familyName2;
private String familyNameSuffix;
private String degree;
private static String format = OpenmrsConstants.PERSON_NAME_FORMAT_SHORT;
// Constructors
/** default constructor */
public PersonName() {
}
/** constructor with id */
public PersonName(Integer personNameId) {
this.personNameId = personNameId;
}
/**
* Convenience constructor with the basic requirements
*
* @param givenName String this person's first name
* @param middleName String this person's middle name
* @param familyName String this person's last name
*/
public PersonName(String givenName, String middleName, String familyName) {
this.givenName = givenName;
this.middleName = middleName;
this.familyName = familyName;
}
/**
* Compares this PersonName object to the given otherName. This method differs from
* {@link #equals(Object)} in that this method compares the inner fields of each name for
* equality. Note: Null/empty fields on <code>otherName</code> /will not/ cause a false value to
* be returned
*
* @param otherName PersonName with which to compare
* @return boolean true/false whether or not they are the same names
* @should return true if given middle and family name are equal
*/
public boolean equalsContent(PersonName otherName) {
return new EqualsBuilder().append(defaultString(otherName.getPrefix()), defaultString(prefix)).append(
defaultString(otherName.getGivenName()), defaultString(givenName)).append(
defaultString(otherName.getMiddleName()), defaultString(middleName)).append(
defaultString(otherName.getFamilyNamePrefix()), defaultString(familyNamePrefix)).append(
defaultString(otherName.getDegree()), defaultString(degree)).append(defaultString(otherName.getFamilyName()),
defaultString(familyName)).append(defaultString(otherName.getFamilyName2()), defaultString(familyName2)).append(
defaultString(otherName.getFamilyNameSuffix()), defaultString(familyNameSuffix)).isEquals();
}
/**
* Bitwise copy of the personName object. NOTICE: THIS WILL NOT COPY THE PATIENT OBJECT. The
* PersonName.person object in this object AND the cloned object will point at the same person
*
* @return New PersonName object
* @should copy every property of given personName
*/
public static PersonName newInstance(PersonName pn) {
if (pn == null) {
throw new IllegalArgumentException();
}
PersonName newName = new PersonName(Integer.valueOf(pn.getPersonNameId()));
if (pn.getGivenName() != null) {
newName.setGivenName(String.valueOf(pn.getGivenName()));
}
if (pn.getMiddleName() != null) {
newName.setMiddleName(String.valueOf(pn.getMiddleName()));
}
if (pn.getFamilyName() != null) {
newName.setFamilyName(String.valueOf(pn.getFamilyName()));
}
if (pn.getFamilyName2() != null) {
newName.setFamilyName2(String.valueOf(pn.getFamilyName2()));
}
if (pn.getFamilyNamePrefix() != null) {
newName.setFamilyNamePrefix(String.valueOf(pn.getFamilyNamePrefix()));
}
if (pn.getFamilyNameSuffix() != null) {
newName.setFamilyNameSuffix(String.valueOf(pn.getFamilyNameSuffix()));
}
if (pn.getPrefix() != null) {
newName.setPrefix(String.valueOf(pn.getPrefix()));
}
if (pn.getDegree() != null) {
newName.setDegree(String.valueOf(pn.getDegree()));
}
if (pn.getVoidReason() != null) {
newName.setVoidReason(String.valueOf(pn.getVoidReason()));
}
if (pn.getDateChanged() != null) {
newName.setDateChanged((Date) pn.getDateChanged().clone());
}
if (pn.getDateCreated() != null) {
newName.setDateCreated((Date) pn.getDateCreated().clone());
}
if (pn.getDateVoided() != null) {
newName.setDateVoided((Date) pn.getDateVoided().clone());
}
if (pn.getPreferred() != null) {
newName.setPreferred(pn.getPreferred().booleanValue());
}
if (pn.getVoided() != null) {
newName.setVoided(pn.getVoided().booleanValue());
}
newName.setPerson(pn.getPerson());
newName.setVoidedBy(pn.getVoidedBy());
newName.setChangedBy(pn.getChangedBy());
newName.setCreator(pn.getCreator());
return newName;
}
/**
* @return Returns the degree.
*/
public String getDegree() {
return degree;
}
/**
* @param degree The degree to set.
*/
public void setDegree(String degree) {
this.degree = degree;
}
/**
* @return Returns the familyName.
* @should return obscured name if obscure_patients is set to true
*/
public String getFamilyName() {
if (OpenmrsConstants.OBSCURE_PATIENTS) {
return OpenmrsConstants.OBSCURE_PATIENTS_FAMILY_NAME;
}
return familyName;
}
/**
* @param familyName The familyName to set.
*/
public void setFamilyName(String familyName) {
this.familyName = familyName;
}
/**
* @return Returns the familyName2.
* @should return null if obscure_patients is set to true
*/
public String getFamilyName2() {
if (OpenmrsConstants.OBSCURE_PATIENTS) {
return null;
}
return familyName2;
}
/**
* @param familyName2 The familyName2 to set.
*/
public void setFamilyName2(String familyName2) {
this.familyName2 = familyName2;
}
/**
* @return Returns the familyNamePrefix.
* @should return null if obscure_patients is set to true
*/
public String getFamilyNamePrefix() {
if (OpenmrsConstants.OBSCURE_PATIENTS) {
return null;
}
return familyNamePrefix;
}
/**
* @param familyNamePrefix The familyNamePrefix to set.
*/
public void setFamilyNamePrefix(String familyNamePrefix) {
this.familyNamePrefix = familyNamePrefix;
}
/**
* @return Returns the familyNameSuffix.
* @should return null if obscure_patients is set to true
*/
public String getFamilyNameSuffix() {
if (OpenmrsConstants.OBSCURE_PATIENTS) {
return null;
}
return familyNameSuffix;
}
/**
* @param familyNameSuffix The familyNameSuffix to set.
*/
public void setFamilyNameSuffix(String familyNameSuffix) {
this.familyNameSuffix = familyNameSuffix;
}
/**
* @return Returns the givenName.
* @should return obscured name if obscure_patients is set to true
*/
public String getGivenName() {
if (OpenmrsConstants.OBSCURE_PATIENTS) {
return OpenmrsConstants.OBSCURE_PATIENTS_GIVEN_NAME;
}
return givenName;
}
/**
* @param givenName The givenName to set.
*/
public void setGivenName(String givenName) {
this.givenName = givenName;
}
/**
* @return Returns the middleName.
* @should return obscured name if obscure_patients is set to true
*/
public String getMiddleName() {
if (OpenmrsConstants.OBSCURE_PATIENTS) {
return OpenmrsConstants.OBSCURE_PATIENTS_MIDDLE_NAME;
}
return middleName;
}
/**
* @param middleName The middleName to set.
*/
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
/**
* @return Returns the person.
*/
public Person getPerson() {
return person;
}
/**
* @param person The person to set.
*/
public void setPerson(Person person) {
this.person = person;
}
/**
* @return Returns the personNameId.
*/
public Integer getPersonNameId() {
return personNameId;
}
/**
* @param personNameId The personNameId to set.
*/
public void setPersonNameId(Integer personNameId) {
this.personNameId = personNameId;
}
/**
* @return Returns the preferred.
*
* @deprecated as of 2.0, use {@link #getPreferred()}
*/
@Deprecated
@JsonIgnore
public Boolean isPreferred() {
return getPreferred();
}
public Boolean getPreferred() {
if (preferred == null) {
return Boolean.FALSE;
}
return preferred;
}
/**
* @param preferred The preferred to set.
*/
public void setPreferred(Boolean preferred) {
this.preferred = preferred;
}
/**
* @return Returns the prefix.
* @should return null if obscure_patients is set to true
*/
public String getPrefix() {
if (OpenmrsConstants.OBSCURE_PATIENTS) {
return null;
}
return prefix;
}
/**
* @param prefix The prefix to set.
*/
public void setPrefix(String prefix) {
this.prefix = prefix;
}
/**
* Convenience method to get all the names of this PersonName and concatenating them together
* with spaces in between. If any part of {@link #getPrefix()}, {@link #getGivenName()},
* {@link #getMiddleName()}, etc are null, they are not included in the returned name
*
* @return all of the parts of this {@link PersonName} joined with spaces
* @should not put spaces around an empty middle name
*/
public String getFullName() {
List<String> temp = new ArrayList<String>();
if (StringUtils.hasText(getPrefix())) {
temp.add(getPrefix());
}
if (StringUtils.hasText(getGivenName())) {
temp.add(getGivenName());
}
if (StringUtils.hasText(getMiddleName())) {
temp.add(getMiddleName());
}
if (OpenmrsConstants.PERSON_NAME_FORMAT_LONG.equals(PersonName.getFormat())) {
if (StringUtils.hasText(getFamilyNamePrefix())) {
temp.add(getFamilyNamePrefix());
}
if (StringUtils.hasText(getFamilyName())) {
temp.add(getFamilyName());
}
if (StringUtils.hasText(getFamilyName2())) {
temp.add(getFamilyName2());
}
if (StringUtils.hasText(getFamilyNameSuffix())) {
temp.add(getFamilyNameSuffix());
}
if (StringUtils.hasText(getDegree())) {
temp.add(getDegree());
}
} else {
if (StringUtils.hasText(getFamilyName())) {
temp.add(getFamilyName());
}
}
String nameString = StringUtils.collectionToDelimitedString(temp, " ");
return nameString.trim();
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
//This should not be changed due to extensive usage in UI.
return getFullName();
}
/**
* @since 1.5
* @see org.openmrs.OpenmrsObject#getId()
*/
@Override
public Integer getId() {
return getPersonNameId();
}
/**
* TODO: the behaviour of this method needs to be controlled by some sort of global property
* because an implementation can define how they want their names to look (which fields to
* show/hide)
*
* @see java.lang.Comparable#compareTo(java.lang.Object)
* @should return negative if other name is voided
* @should return negative if this name is preferred
* @should return negative if other familyName is greater
* @should return negative if other familyName2 is greater
* @should return negative if other givenName is greater
* @should return negative if other middleName is greater
* @should return negative if other familynamePrefix is greater
* @should return negative if other familyNameSuffix is greater
* @should return negative if other dateCreated is greater
* Note: this comparator imposes orderings that are inconsistent with equals.
*/
@Override
public int compareTo(PersonName other) {
DefaultComparator pnDefaultComparator = new DefaultComparator();
return pnDefaultComparator.compare(this, other);
}
/**
* @since 1.5
* @see org.openmrs.OpenmrsObject#setId(java.lang.Integer)
*/
@Override
public void setId(Integer id) {
setPersonNameId(id);
}
public static void setFormat(String format) {
if (StringUtils.isEmpty(format)) {
PersonName.format = OpenmrsConstants.PERSON_NAME_FORMAT_SHORT;
} else {
PersonName.format = format;
}
}
public static String getFormat() {
return PersonName.format;
}
/**
Provides a default comparator.
@since 1.12
**/
public static class DefaultComparator implements Comparator<PersonName> {
@Override
public int compare(PersonName pn1, PersonName pn2) {
int ret = pn1.getVoided().compareTo(pn2.getVoided());
if (ret == 0) {
ret = pn2.isPreferred().compareTo(pn1.isPreferred());
}
if (ret == 0) {
ret = OpenmrsUtil.compareWithNullAsGreatest(pn1.getFamilyName(), pn2.getFamilyName());
}
if (ret == 0) {
ret = OpenmrsUtil.compareWithNullAsGreatest(pn1.getFamilyName2(), pn2.getFamilyName2());
}
if (ret == 0) {
ret = OpenmrsUtil.compareWithNullAsGreatest(pn1.getGivenName(), pn2.getGivenName());
}
if (ret == 0) {
ret = OpenmrsUtil.compareWithNullAsGreatest(pn1.getMiddleName(), pn2.getMiddleName());
}
if (ret == 0) {
ret = OpenmrsUtil.compareWithNullAsGreatest(pn1.getFamilyNamePrefix(), pn2.getFamilyNamePrefix());
}
if (ret == 0) {
ret = OpenmrsUtil.compareWithNullAsGreatest(pn1.getFamilyNameSuffix(), pn2.getFamilyNameSuffix());
}
if (ret == 0 && pn1.getDateCreated() != null) {
ret = OpenmrsUtil.compareWithNullAsLatest(pn1.getDateCreated(), pn2.getDateCreated());
}
// if we've gotten this far, just check all name values. If they are
// equal, leave the objects at 0. If not, arbitrarily pick retValue=1
// and return that (they are not equal).
if (ret == 0 && !pn1.equalsContent(pn2)) {
ret = 1;
}
return ret;
}
}
}