/** * 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 java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Comparator; 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.OpenmrsUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A <code>Patient</code> can have zero to n identifying PatientIdentifier(s). PatientIdentifiers * are anything from medical record numbers, to social security numbers, to driver's licenses. The * type of identifier is defined by the PatientIdentifierType. A PatientIdentifier also contains a * Location. * * @see org.openmrs.PatientIdentifierType */ @Indexed public class PatientIdentifier extends BaseOpenmrsData implements java.io.Serializable, Comparable<PatientIdentifier> { public static final long serialVersionUID = 1123121L; private static final Logger log = LoggerFactory.getLogger(PatientIdentifier.class); // Fields /** * @since 1.5 */ @DocumentId private Integer patientIdentifierId; @IndexedEmbedded(includeEmbeddedObjectId = true) private Patient patient; @Fields({ @Field(name = "identifierPhrase", analyzer = @Analyzer(definition = LuceneAnalyzers.PHRASE_ANALYZER), boost = @Boost(8f)), @Field(name = "identifierExact", analyzer = @Analyzer(definition = LuceneAnalyzers.EXACT_ANALYZER), boost = @Boost(4f)), @Field(name = "identifierStart", analyzer = @Analyzer(definition = LuceneAnalyzers.START_ANALYZER), boost = @Boost(2f)), @Field(name = "identifierAnywhere", analyzer = @Analyzer(definition = LuceneAnalyzers.ANYWHERE_ANALYZER)) }) private String identifier; @IndexedEmbedded(includeEmbeddedObjectId = true) private PatientIdentifierType identifierType; private Location location; @Field private Boolean preferred = false; /** default constructor */ public PatientIdentifier() { } /** * Convenience constructor for creating a basic identifier * * @param identifier String identifier * @param type PatientIdentifierType * @param location Location of the identifier */ public PatientIdentifier(String identifier, PatientIdentifierType type, Location location) { this.identifier = identifier; this.identifierType = type; this.location = location; } /** * Compares this PatientIdentifier object to the given otherIdentifier. This method differs from * {@link #equals(Object)} in that this method compares the inner fields of each identifier for * equality. Note: Null/empty fields on <code>otherIdentifier</code> /will not/ cause a false * value to be returned * * @param otherIdentifier PatientiIdentifier with which to compare * @return boolean true/false whether or not they are the same names */ public boolean equalsContent(PatientIdentifier otherIdentifier) { boolean returnValue = true; // these are the methods to compare. String[] methods = { "getIdentifier", "getIdentifierType", "getLocation" }; Class<? extends PatientIdentifier> identifierClass = this.getClass(); // loop over all of the selected methods and compare this and other for (String methodName : methods) { try { Method method = identifierClass.getMethod(methodName, new Class[] {}); Object thisValue = method.invoke(this); Object otherValue = method.invoke(otherIdentifier); if (otherValue != null) { returnValue &= otherValue.equals(thisValue); } } catch (NoSuchMethodException e) { log.warn("No such method for comparison " + methodName, e); } catch (IllegalAccessException e) { log.error("Error while comparing identifiers", e); } catch (InvocationTargetException e) { log.error("Error while comparing identifiers", e); } } return returnValue; } //property accessors /** * @return Returns the identifier. */ public String getIdentifier() { return identifier; } /** * @param identifier The identifier to set. */ public void setIdentifier(String identifier) { this.identifier = identifier; } /** * @return Returns the identifierType. */ public PatientIdentifierType getIdentifierType() { return identifierType; } /** * @param identifierType The identifierType to set. */ public void setIdentifierType(PatientIdentifierType identifierType) { this.identifierType = identifierType; } /** * @return Returns the location. */ public Location getLocation() { return location; } /** * @param location The location to set. */ public void setLocation(Location location) { this.location = location; } /** * @return Returns the patient. */ public Patient getPatient() { return patient; } /** * @param patient The patient to set. */ public void setPatient(Patient patient) { this.patient = patient; } @Override public String toString() { return this.identifier; } /** * @return Returns the preferred. */ public Boolean getPreferred() { return preferred; } /** * @param preferred The preferred to set. */ public void setPreferred(Boolean preferred) { this.preferred = preferred; } /** * @return the preferred status * * @deprecated as of 2.0, use {@link #getPreferred()} */ @Deprecated @JsonIgnore public Boolean isPreferred() { return getPreferred(); } /** * @see java.lang.Comparable#compareTo(java.lang.Object) * @deprecated since 1.12. Use DefaultComparator instead. * Note: this comparator imposes orderings that are inconsistent with equals. */ @Deprecated @Override @SuppressWarnings("squid:S1210") public int compareTo(PatientIdentifier other) { DefaultComparator piDefaultComparator = new DefaultComparator(); return piDefaultComparator.compare(this, other); } /** * @since 1.5 * @see org.openmrs.OpenmrsObject#getId() */ @Override public Integer getId() { return getPatientIdentifierId(); } /** * @since 1.5 * @see org.openmrs.OpenmrsObject#setId(java.lang.Integer) */ @Override public void setId(Integer id) { setPatientIdentifierId(id); } /** * @since 1.5 * @return the patientIdentifierId */ public Integer getPatientIdentifierId() { return patientIdentifierId; } /** * @since 1.5 * @param patientIdentifierId the patientIdentifierId to set */ public void setPatientIdentifierId(Integer patientIdentifierId) { this.patientIdentifierId = patientIdentifierId; } /** Provides a default comparator. @since 1.12 **/ public static class DefaultComparator implements Comparator<PatientIdentifier> { @Override public int compare(PatientIdentifier pi1, PatientIdentifier pi2) { int retValue = 0; if (pi2 != null) { retValue = pi1.getVoided().compareTo(pi2.getVoided()); if (retValue == 0) { retValue = pi1.isPreferred().compareTo(pi2.isPreferred()); } if (retValue == 0) { retValue = OpenmrsUtil.compareWithNullAsLatest(pi1.getDateCreated(), pi2.getDateCreated()); } if (pi1.getIdentifierType() == null && pi2.getIdentifierType() == null) { return 0; } if (pi1.getIdentifierType() == null && pi2.getIdentifierType() != null) { retValue = 1; } if (pi1.getIdentifierType() == null && pi2.getIdentifierType() != null) { retValue = -1; } if (retValue == 0) { retValue = OpenmrsUtil.compareWithNullAsGreatest(pi1.getIdentifierType().getPatientIdentifierTypeId(), pi2.getIdentifierType().getPatientIdentifierTypeId()); } if (retValue == 0) { retValue = OpenmrsUtil.compareWithNullAsGreatest(pi1.getIdentifier(), pi2.getIdentifier()); } // if we've gotten this far, just check all identifier values. If they are // equal, leave the objects at 0. If not, arbitrarily pick retValue=1 // and return that (they are not equal). if (retValue == 0 && !pi1.equalsContent(pi2)) { retValue = 1; } } return retValue; } } }