/** * 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.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.search.annotations.ContainedIn; import org.hibernate.search.annotations.Index; import org.hibernate.search.annotations.Field; import org.hibernate.search.annotations.IndexedEmbedded; import org.openmrs.util.OpenmrsConstants; import org.openmrs.util.OpenmrsUtil; import org.simpleframework.xml.Attribute; import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; import org.springframework.util.StringUtils; /** * A Person can have zero to n PersonName(s). */ @Root(strict = false) public class PersonName extends BaseOpenmrsData implements java.io.Serializable, Cloneable, Comparable<PersonName> { public static final long serialVersionUID = 4353L; private static final Log log = LogFactory.getLog(PersonName.class); // Fields @Field @ContainedIn private Integer personNameId; // @IndexedEmbedded private Person person; @Field private Boolean preferred = false; @Field(index = Index.TOKENIZED) private String prefix; @Field(index = Index.TOKENIZED) private String givenName; @Field(index = Index.TOKENIZED) private String middleName; @Field(index = Index.TOKENIZED) private String familyNamePrefix; @Field(index = Index.TOKENIZED) private String familyName; @Field(index = Index.TOKENIZED) private String familyName2; @Field(index = Index.TOKENIZED) private String familyNameSuffix; @Field(index = Index.TOKENIZED) private String degree; // 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 two objects for similarity * * @param obj PersonName to compare to * @return boolean true/false whether or not they are the same objects * @see java.lang.Object#equals(java.lang.Object) * @should not fail if either has a null person property * @should return false if this has a missing person property * @should return false if obj has a missing person property * @should return true if properties are equal and have null person */ public boolean equals(Object obj) { if (obj instanceof PersonName) { PersonName pname = (PersonName) obj; if (this.personNameId != null && pname.getPersonNameId() != null) return (this.personNameId.equals(pname.getPersonNameId())); else { return (OpenmrsUtil.nullSafeEquals(getPerson(), pname.getPerson()) && OpenmrsUtil.nullSafeEqualsIgnoreCase(getGivenName(), pname.getGivenName()) && OpenmrsUtil.nullSafeEqualsIgnoreCase(getMiddleName(), pname.getMiddleName()) && OpenmrsUtil .nullSafeEqualsIgnoreCase(getFamilyName(), pname.getFamilyName())); } } return false; } /** * @see java.lang.Object#hashCode() */ public int hashCode() { if (this.getPersonNameId() == null) return super.hashCode(); return this.getPersonNameId().hashCode(); } /** * 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 */ @SuppressWarnings("unchecked") public boolean equalsContent(PersonName otherName) { boolean returnValue = true; // these are the methods to compare. All are expected to be Strings String[] methods = { "getGivenName", "getMiddleName", "getFamilyName" }; Class nameClass = this.getClass(); // loop over all of the selected methods and compare this and other for (String methodName : methods) { try { Method method = nameClass.getMethod(methodName, new Class[] {}); String thisValue = (String) method.invoke(this); String otherValue = (String) method.invoke(otherName); if (otherValue != null && otherValue.length() > 0) returnValue &= otherValue.equals(thisValue); } catch (NoSuchMethodException e) { log.warn("No such method for comparison " + methodName, e); } catch (IllegalAccessException e) { log.error("Error while comparing names", e); } catch (InvocationTargetException e) { log.error("Error while comparing names", e); } } return returnValue; } /** * 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) { PersonName newName = new PersonName(new Integer(pn.getPersonNameId())); if (pn.getGivenName() != null) newName.setGivenName(new String(pn.getGivenName())); if (pn.getMiddleName() != null) newName.setMiddleName(new String(pn.getMiddleName())); if (pn.getFamilyName() != null) newName.setFamilyName(new String(pn.getFamilyName())); if (pn.getFamilyName2() != null) newName.setFamilyName2(new String(pn.getFamilyName2())); if (pn.getFamilyNamePrefix() != null) newName.setFamilyNamePrefix(new String(pn.getFamilyNamePrefix())); if (pn.getFamilyNameSuffix() != null) newName.setFamilyNameSuffix(new String(pn.getFamilyNameSuffix())); if (pn.getPrefix() != null) newName.setPrefix(new String(pn.getPrefix())); if (pn.getDegree() != null) newName.setDegree(new String(pn.getDegree())); if (pn.getVoidReason() != null) newName.setVoidReason(new String(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; } // Property accessors /** * This still exists on PersonName for the SimpleFramework annotation * * @return Returns the dateVoided. */ @Element(required = false) public Date getDateVoided() { return super.getDateVoided(); } /** * @param dateVoided The dateVoided to set. */ @Element(required = false) public void setDateVoided(Date dateVoided) { super.setDateVoided(dateVoided); } /** * @return Returns the degree. */ @Element(data = true, required = false) public String getDegree() { return degree; } /** * @param degree The degree to set. */ @Element(data = true, required = false) public void setDegree(String degree) { this.degree = degree; } /** * @return Returns the familyName. * @should return obscured name if obscure_patients is set to true */ @Element(data = true, required = false) public String getFamilyName() { if (OpenmrsConstants.OBSCURE_PATIENTS) return OpenmrsConstants.OBSCURE_PATIENTS_FAMILY_NAME; return familyName; } /** * @param familyName The familyName to set. */ @Element(data = true, required = false) public void setFamilyName(String familyName) { this.familyName = familyName; } /** * @return Returns the familyName2. * @should return null if obscure_patients is set to true */ @Element(data = true, required = false) public String getFamilyName2() { if (OpenmrsConstants.OBSCURE_PATIENTS) return null; return familyName2; } /** * @param familyName2 The familyName2 to set. */ @Element(data = true, required = false) public void setFamilyName2(String familyName2) { this.familyName2 = familyName2; } /** * @return Returns the familyNamePrefix. * @should return null if obscure_patients is set to true */ @Element(data = true, required = false) public String getFamilyNamePrefix() { if (OpenmrsConstants.OBSCURE_PATIENTS) return null; return familyNamePrefix; } /** * @param familyNamePrefix The familyNamePrefix to set. */ @Element(data = true, required = false) public void setFamilyNamePrefix(String familyNamePrefix) { this.familyNamePrefix = familyNamePrefix; } /** * @return Returns the familyNameSuffix. * @should return null if obscure_patients is set to true */ @Element(data = true, required = false) public String getFamilyNameSuffix() { if (OpenmrsConstants.OBSCURE_PATIENTS) return null; return familyNameSuffix; } /** * @param familyNameSuffix The familyNameSuffix to set. */ @Element(data = true, required = false) public void setFamilyNameSuffix(String familyNameSuffix) { this.familyNameSuffix = familyNameSuffix; } /** * @return Returns the givenName. * @should return obscured name if obscure_patients is set to true */ @Element(data = true, required = false) public String getGivenName() { if (OpenmrsConstants.OBSCURE_PATIENTS) return OpenmrsConstants.OBSCURE_PATIENTS_GIVEN_NAME; return givenName; } /** * @param givenName The givenName to set. */ @Element(data = true, required = false) public void setGivenName(String givenName) { this.givenName = givenName; } /** * @return Returns the middleName. * @should return obscured name if obscure_patients is set to true */ @Element(data = true, required = false) public String getMiddleName() { if (OpenmrsConstants.OBSCURE_PATIENTS) return OpenmrsConstants.OBSCURE_PATIENTS_MIDDLE_NAME; return middleName; } /** * @param middleName The middleName to set. */ @Element(data = true, required = false) public void setMiddleName(String middleName) { this.middleName = middleName; } /** * @return Returns the person. */ @Element(required = true) public Person getPerson() { return person; } /** * @param person The person to set. */ @Element(required = true) public void setPerson(Person person) { this.person = person; } /** * @return Returns the personNameId. */ @Attribute(required = true) public Integer getPersonNameId() { return personNameId; } /** * @param personNameId The personNameId to set. */ @Attribute(required = true) public void setPersonNameId(Integer personNameId) { this.personNameId = personNameId; } /** * @return Returns the preferred. */ public Boolean isPreferred() { if (preferred == null) return Boolean.FALSE; return preferred; } @Attribute(required = true) public Boolean getPreferred() { return isPreferred(); } /** * @param preferred The preferred to set. */ @Attribute(required = true) public void setPreferred(Boolean preferred) { this.preferred = preferred; } /** * @return Returns the prefix. * @should return null if obscure_patients is set to true */ @Element(data = true, required = false) public String getPrefix() { if (OpenmrsConstants.OBSCURE_PATIENTS) return null; return prefix; } /** * @param prefix The prefix to set. */ @Element(data = true, required = false) public void setPrefix(String prefix) { this.prefix = prefix; } /** * @see #isVoided() */ @Attribute(required = true) public Boolean getVoided() { return isVoided(); } /** * This still exists on PersonName for the SimpleFramework annotation * * @param voided The voided to set. */ @Attribute(required = true) public void setVoided(Boolean voided) { super.setVoided(voided); } /** * This still exists on PersonName for the SimpleFramework annotation * * @return Returns the voidedBy. */ @Element(required = false) public User getVoidedBy() { return super.getVoidedBy(); } /** * This still exists on PersonName for the SimpleFramework annotation * * @param voidedBy The voidedBy to set. */ @Element(required = false) public void setVoidedBy(User voidedBy) { super.setVoidedBy(voidedBy); } /** * This still exists on PersonName for the SimpleFramework annotation * * @return Returns the voidReason. */ @Element(data = true, required = false) public String getVoidReason() { return super.getVoidReason(); } /** * This still exists on PersonName for the SimpleFramework annotation * * @param voidReason The voidReason to set. */ @Element(data = true, required = false) public void setVoidReason(String voidReason) { super.setVoidReason(voidReason); } /** * Convenience method to get all the names of this PersonName and concatonating 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 (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()); String nameString = StringUtils.collectionToDelimitedString(temp, " "); return nameString.trim(); } /** * @see java.lang.Object#toString() */ @Override public String toString() { // TODO find all uses of this toString() method and // change them to use the getFullName() method. This // to string should print out the #getPersonNameId() and // all of the values for each part return getFullName(); } /** * TODO: the behavior 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 */ public int compareTo(PersonName other) { int ret = isVoided().compareTo(other.isVoided()); if (ret == 0) ret = other.isPreferred().compareTo(isPreferred()); if (ret == 0) ret = OpenmrsUtil.compareWithNullAsGreatest(getFamilyName(), other.getFamilyName()); if (ret == 0) ret = OpenmrsUtil.compareWithNullAsGreatest(getFamilyName2(), other.getFamilyName2()); if (ret == 0) ret = OpenmrsUtil.compareWithNullAsGreatest(getGivenName(), other.getGivenName()); if (ret == 0) ret = OpenmrsUtil.compareWithNullAsGreatest(getMiddleName(), other.getMiddleName()); if (ret == 0) ret = OpenmrsUtil.compareWithNullAsGreatest(getFamilyNamePrefix(), other.getFamilyNamePrefix()); if (ret == 0) ret = OpenmrsUtil.compareWithNullAsGreatest(getFamilyNameSuffix(), other.getFamilyNameSuffix()); if (ret == 0 && getDateCreated() != null) ret = OpenmrsUtil.compareWithNullAsLatest(getDateCreated(), other.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 && !equalsContent(other)) ret = 1; return ret; } /** * @since 1.5 * @see org.openmrs.OpenmrsObject#getId() */ public Integer getId() { return getPersonNameId(); } /** * @since 1.5 * @see org.openmrs.OpenmrsObject#setId(java.lang.Integer) */ public void setId(Integer id) { setPersonNameId(id); } }