/**
* 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.api.impl;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import org.openmrs.Cohort;
import org.openmrs.Concept;
import org.openmrs.ConceptName;
import org.openmrs.Encounter;
import org.openmrs.Location;
import org.openmrs.MimeType;
import org.openmrs.Obs;
import org.openmrs.Patient;
import org.openmrs.Person;
import org.openmrs.aop.RequiredDataAdvice;
import org.openmrs.api.APIException;
import org.openmrs.api.EncounterService;
import org.openmrs.api.ObsService;
import org.openmrs.api.PatientService;
import org.openmrs.api.context.Context;
import org.openmrs.api.db.ObsDAO;
import org.openmrs.api.handler.SaveHandler;
import org.openmrs.obs.ComplexObsHandler;
import org.openmrs.util.OpenmrsClassLoader;
import org.openmrs.util.OpenmrsConstants;
import org.openmrs.util.OpenmrsConstants.PERSON_TYPE;
import org.openmrs.util.PrivilegeConstants;
/**
* Default implementation of the Observation Service
*
* @see org.openmrs.api.ObsService
*/
public class ObsServiceImpl extends BaseOpenmrsService implements ObsService {
/**
* The data access object for the obs service
*/
protected ObsDAO dao;
/**
* Report handlers that have been registered. This is filled via {@link #setHandlers(Map)} and
* spring's applicationContext-service.xml object
*/
private static Map<String, ComplexObsHandler> handlers = null;
/**
* Default empty constructor for this obs service
*/
public ObsServiceImpl() {
}
/**
* @see org.openmrs.api.ObsService#setObsDAO(org.openmrs.api.db.ObsDAO)
*/
public void setObsDAO(ObsDAO dao) {
this.dao = dao;
}
/**
* Clean up after this class. Set the static var to null so that the classloader can reclaim the
* space.
*
* @see org.openmrs.api.impl.BaseOpenmrsService#onShutdown()
*/
@Override
public void onShutdown() {
handlers = null;
}
/**
* @see org.openmrs.api.ObsService#saveObs(org.openmrs.Obs, String)
*/
public Obs saveObs(Obs obs, String changeMessage) throws APIException {
if (null != obs && null != obs.getConcept() && obs.getConcept().isComplex()
&& null != obs.getComplexData().getData()) {
// save or update complexData object on this obs
// this is done before the database save so that the obs.valueComplex
// can be filled in by the handler.
ComplexObsHandler handler = getHandler(obs);
if (null != handler) {
handler.saveObs(obs);
} else {
throw new APIException("Unknown handler for " + obs.getConcept());
}
}
if (obs.getObsId() == null) {
Context.requirePrivilege(PrivilegeConstants.ADD_OBS);
return dao.saveObs(obs);
} else {
Context.requirePrivilege(PrivilegeConstants.EDIT_OBS);
if (changeMessage == null)
throw new APIException("ChangeMessage is required when updating an obs in the database");
// get a copy of the passed in obs and save it to the
// database. This allows us to create a new row and new obs_id
// this method doesn't copy the obs_id
Obs newObs = Obs.newInstance(obs);
// unset any voided properties on the new obs
newObs.setVoided(false);
newObs.setVoidReason(null);
newObs.setDateVoided(null);
newObs.setVoidedBy(null);
// unset the creation stats
newObs.setCreator(null);
newObs.setDateCreated(null);
RequiredDataAdvice.recursivelyHandle(SaveHandler.class, newObs, changeMessage);
// save the new row to the database with the changes that
// have been made to it
dao.saveObs(newObs);
// void out the original observation to keep it around for
// historical purposes
try {
Context.addProxyPrivilege(PrivilegeConstants.DELETE_OBS);
String reason = changeMessage + " (new obsId: " + newObs.getObsId() + ")";
// fetch a clean copy of this obs from the database so that
// we don't write the changes to the database when we save
// the fact that the obs is now voided
Context.evictFromSession(obs);
obs = getObs(obs.getObsId());
// calling this via the service so that AOP hooks are called
Context.getObsService().voidObs(obs, reason);
}
finally {
Context.removeProxyPrivilege(PrivilegeConstants.DELETE_OBS);
}
return newObs;
}
}
/**
* @see org.openmrs.api.ObsService#getObs(java.lang.Integer)
*/
public Obs getObs(Integer obsId) throws APIException {
return dao.getObs(obsId);
}
/**
* @see org.openmrs.api.ObsService#updateObs(org.openmrs.Obs)
* @deprecated
*/
@Deprecated
public void updateObs(Obs obs) throws APIException {
Context.getObsService().saveObs(obs, obs.getVoidReason());
}
/**
* Voids an Obs If the Obs argument is an obsGroup, all group members will be voided.
*
* @see org.openmrs.api.ObsService#voidObs(org.openmrs.Obs, java.lang.String)
* @param obs the Obs to void
* @param reason the void reason
* @throws APIException
*/
public Obs voidObs(Obs obs, String reason) throws APIException {
return dao.saveObs(obs);
}
/**
* Unvoids an Obs
* <p>
* If the Obs argument is an obsGroup, all group members with the same dateVoided will also be
* unvoided.
*
* @see org.openmrs.api.ObsService#unvoidObs(org.openmrs.Obs)
* @param obs the Obs to unvoid
* @return the unvoided Obs
* @throws APIException
*/
public Obs unvoidObs(Obs obs) throws APIException {
return dao.saveObs(obs);
}
/**
* @see org.openmrs.api.ObsService#purgeObs(org.openmrs.Obs, boolean)
*/
public void purgeObs(Obs obs, boolean cascade) throws APIException {
if (purgeComplexData(obs) == false) {
throw new APIException("Unable to purge complex data for obs: " + obs);
}
if (cascade) {
throw new APIException("Cascading purge of obs not yet implemented");
// TODO delete any related objects here before deleting the obs
// obsGroups objects?
// orders?
}
dao.deleteObs(obs);
}
/**
* @see org.openmrs.api.ObsService#purgeObs(org.openmrs.Obs)
*/
public void purgeObs(Obs obs) throws APIException {
purgeObs(obs, false);
}
/**
* @see org.openmrs.api.ObsService#getMimeTypes()
* @deprecated use {@link #getAllMimeTypes()}
*/
@Deprecated
public List<MimeType> getMimeTypes() throws APIException {
return getAllMimeTypes();
}
/**
* @see org.openmrs.api.ObsService#getAllMimeTypes()
* @deprecated
*/
@Deprecated
public List<MimeType> getAllMimeTypes() throws APIException {
return dao.getAllMimeTypes(true);
}
/**
* @see org.openmrs.api.ObsService#getAllMimeTypes(boolean)
* @deprecated
*/
@Deprecated
public List<MimeType> getAllMimeTypes(boolean includeRetired) {
return dao.getAllMimeTypes(includeRetired);
}
/**
* @see org.openmrs.api.ObsService#saveMimeType(org.openmrs.MimeType)
* @deprecated
*/
@Deprecated
public MimeType saveMimeType(MimeType mimeType) throws APIException {
return dao.saveMimeType(mimeType);
}
/**
* @see org.openmrs.api.ObsService#voidMimeType(org.openmrs.MimeType, java.lang.String)
* @deprecated
*/
@Deprecated
public MimeType voidMimeType(MimeType mimeType, String reason) throws APIException {
// TODO implement voidMimeType
throw new APIException("Not yet implemented");
}
/**
* @see org.openmrs.api.ObsService#getMimeType(java.lang.Integer)
* @deprecated
*/
@Deprecated
public MimeType getMimeType(Integer mimeTypeId) throws APIException {
return dao.getMimeType(mimeTypeId);
}
/**
* @see org.openmrs.api.ObsService#purgeMimeType(org.openmrs.MimeType)
* @deprecated
*/
@Deprecated
public void purgeMimeType(MimeType mimeType) {
dao.deleteMimeType(mimeType);
}
/**
* @see org.openmrs.api.ObsService#getObservations(java.util.List, java.util.List,
* java.util.List, java.util.List, List, List, java.util.List, java.lang.Integer,
* java.lang.Integer, java.util.Date, java.util.Date, boolean)
*/
public List<Obs> getObservations(List<Person> whom, List<Encounter> encounters, List<Concept> questions,
List<Concept> answers, List<PERSON_TYPE> personTypes, List<Location> locations, List<String> sort,
Integer mostRecentN, Integer obsGroupId, Date fromDate, Date toDate, boolean includeVoidedObs)
throws APIException {
if (sort == null)
sort = new Vector<String>();
if (sort.isEmpty())
sort.add("obsDatetime");
return dao.getObservations(whom, encounters, questions, answers, personTypes, locations, sort, mostRecentN,
obsGroupId, fromDate, toDate, includeVoidedObs);
}
/**
* @see org.openmrs.api.ObsService#getObservationCount(java.util.List, java.util.List,
* java.util.List, java.util.List, java.util.List, java.util.List, java.lang.Integer,
* java.util.Date, java.util.Date, boolean)
*/
public Integer getObservationCount(List<Person> whom, List<Encounter> encounters, List<Concept> questions,
List<Concept> answers, List<PERSON_TYPE> personTypes, List<Location> locations, Integer obsGroupId,
Date fromDate, Date toDate, boolean includeVoidedObs) throws APIException {
return dao.getObservationCount(whom, encounters, questions, answers, personTypes, locations, obsGroupId, fromDate,
toDate, null, includeVoidedObs);
}
/**
* This implementation queries the obs table comparing the given <code>searchString</code> with
* the patient's identifier, encounterId, and obsId
*
* @see org.openmrs.api.ObsService#getObservations(java.lang.String)
*/
public List<Obs> getObservations(String searchString) {
// search on patient identifier
PatientService ps = Context.getPatientService();
List<Patient> patients = ps.getPatients(null, searchString, null, false);
List<Person> persons = new Vector<Person>();
persons.addAll(patients);
// try to search on encounterId
EncounterService es = Context.getEncounterService();
List<Encounter> encounters = new Vector<Encounter>();
try {
Encounter e = es.getEncounter(Integer.valueOf(searchString));
if (e != null)
encounters.add(e);
}
catch (NumberFormatException e) {
// pass
}
List<Obs> returnList = new Vector<Obs>();
if (encounters.size() > 0 || persons.size() > 0)
returnList = getObservations(persons, encounters, null, null, null, null, null, null, null, null, null, false);
// try to search on obsId
try {
Obs o = getObs(Integer.valueOf(searchString));
if (o != null)
returnList.add(o);
}
catch (NumberFormatException e) {
// pass
}
return returnList;
}
/**
* @see org.openmrs.api.ObsService#createObs(org.openmrs.Obs)
* @deprecated
*/
@Deprecated
public void createObs(Obs obs) throws APIException {
Context.getObsService().saveObs(obs, null);
}
/**
* Correct use case:
*
* <pre>
* Obs parent = new Obs();
* Obs child1 = new Obs();
* Obs child2 = new Obs();
*
* parent.addGroupMember(child1);
* parent.addGroupMember(child2);
* </pre>
*
* @deprecated This method should no longer need to be called on the api. This was meant as
* temporary until we created a true ObsGroup pojo.
* @see org.openmrs.api.ObsService#createObsGroup(org.openmrs.Obs[])
*/
@Deprecated
public void createObsGroup(Obs[] obs) throws APIException {
if (obs == null || obs.length < 1)
return; // silently tolerate calls with missing/empty parameter
String conceptIdStr = Context.getAdministrationService().getGlobalProperty(
OpenmrsConstants.GLOBAL_PROPERTY_MEDICAL_RECORD_OBSERVATIONS, "1238");
// fail silently if a default obs group is not defined
if (conceptIdStr == null || conceptIdStr.length() == 0)
return;
Integer conceptId = Integer.valueOf(conceptIdStr);
Concept defaultObsGroupConcept = Context.getConceptService().getConcept(conceptId);
// if they defined a bad concept, bail
if (defaultObsGroupConcept == null)
throw new APIException("There is no concept defined with concept id: " + conceptIdStr
+ "You should correctly define the default obs group concept id with the global propery"
+ OpenmrsConstants.GLOBAL_PROPERTY_MEDICAL_RECORD_OBSERVATIONS);
Obs obsGroup = new Obs();
obsGroup.setConcept(defaultObsGroupConcept);
for (Obs member : obs) {
obsGroup.addGroupMember(member);
}
updateObs(obsGroup);
}
/**
* @see org.openmrs.api.ObsService#deleteObs(org.openmrs.Obs)
* @deprecated use #purgeObs(Obs)
*/
@Deprecated
public void deleteObs(Obs obs) throws APIException {
Context.getObsService().purgeObs(obs);
}
/**
* @see org.openmrs.api.ObsService#getObservationsByPerson(org.openmrs.Person)
*/
public List<Obs> getObservationsByPerson(Person who) {
List<Person> whom = new Vector<Person>();
whom.add(who);
return getObservations(whom, null, null, null, null, null, null, null, null, null, null, false);
}
/**
* @see org.openmrs.api.ObsService#getObservations(org.openmrs.Person, boolean includeVoided)
* @deprecated use {@link #getObservationsByPerson(Person)}
*/
@Deprecated
public Set<Obs> getObservations(Person who, boolean includeVoided) {
if (includeVoided == true)
throw new APIException("Voided observations are no longer allowed to be queried");
Set<Obs> obsSet = new HashSet<Obs>();
obsSet.addAll(getObservationsByPerson(who));
return obsSet;
}
/**
* @see org.openmrs.api.ObsService#getObservations(org.openmrs.Concept, org.openmrs.Location,
* java.lang.String, java.lang.Integer, boolean includeVoided)
* @deprecated
*/
@Deprecated
public List<Obs> getObservations(Concept c, Location loc, String sort, Integer personType, boolean includeVoided) {
List<Concept> questions = new Vector<Concept>();
questions.add(c);
List<Location> locations = new Vector<Location>();
locations.add(loc);
// make the sort list from the given sort string
List<String> sortList = makeSortList(sort);
return getObservations(null, null, questions, null, getPersonTypeEnumerations(personType), locations, sortList,
null, null, null, null, includeVoided);
}
/**
* Convenience method for turning a string like "location.locationId asc, obs.valueDatetime
* desc" into a list of strings to sort on
*
* @param sort string
* @return simple list of strings to sort on without asc/desc
*/
private List<String> makeSortList(String sort) {
List<String> sortList = new Vector<String>();
if (sort != null && !"".equals(sort)) {
for (String sortPart : sort.split(",")) {
sortPart = sortPart.trim();
// split out the asc/desc part if applicable
if (sortPart.contains(" "))
sortPart = sortPart.substring(0, sortPart.indexOf(" "));
// add the current sort to the list of things to sort on
if (!"".equals(sort))
sortList.add(sortPart);
}
}
return sortList;
}
/**
* This method should be removed when all methods using an Integer personType are removed. This
* method does a bitwise compare on <code>personType</code> and returns a list of PERSON_TYPEs
* that are comparable
*
* @param personType Integer corresponding to {@link ObsService#PERSON}, {@link ObsService#USER}
* , or {@link ObsService#PATIENT},
* @return the enumeration that corresponds to the given integer (old way of doing it)
*/
@SuppressWarnings("deprecation")
private List<PERSON_TYPE> getPersonTypeEnumerations(Integer personType) {
List<PERSON_TYPE> personTypes = new Vector<PERSON_TYPE>();
if (personType == null) {
personTypes.add(PERSON_TYPE.PERSON);
return personTypes;
} else if ((personType & ObsService.PATIENT) == ObsService.PATIENT) {
personTypes.add(PERSON_TYPE.PATIENT);
return personTypes;
} else if ((personType & ObsService.USER) == ObsService.USER) {
personTypes.add(PERSON_TYPE.USER);
return personTypes;
} else {
// default to an all-encompassing search
return personTypes;
}
}
/**
* @see org.openmrs.api.ObsService#getObservations(org.openmrs.Person, org.openmrs.Concept,
* boolean)
* @deprecated
*/
@Deprecated
public Set<Obs> getObservations(Person who, Concept question, boolean includeVoided) {
List<Obs> obs = getObservationsByPersonAndConcept(who, question);
Set<Obs> obsSet = new HashSet<Obs>();
obsSet.addAll(obs);
return obsSet;
}
/**
* @see org.openmrs.api.ObsService#getObservationsByPersonAndConcept(org.openmrs.Person,
* org.openmrs.Concept)
*/
public List<Obs> getObservationsByPersonAndConcept(Person who, Concept question) throws APIException {
List<Person> whom = new Vector<Person>();
if (who != null && who.getPersonId() != null)
whom.add(who);
List<Concept> questions = new Vector<Concept>();
questions.add(question);
return getObservations(whom, null, questions, null, null, null, null, null, null, null, null, false);
}
/**
* @see org.openmrs.api.ObsService#getLastNObservations(java.lang.Integer, org.openmrs.Person,
* org.openmrs.Concept, boolean includeVoided)
* @deprecated
*/
@Deprecated
public List<Obs> getLastNObservations(Integer n, Person who, Concept question, boolean includeVoided) {
List<Person> whom = new Vector<Person>();
whom.add(who);
List<Concept> questions = new Vector<Concept>();
questions.add(question);
return getObservations(whom, null, questions, null, null, null, null, n, null, null, null, includeVoided);
}
/**
* @see org.openmrs.api.ObsService#getObservations(org.openmrs.Concept, java.lang.String,
* java.lang.Integer, boolean includeVoided)
* @deprecated
*/
@Deprecated
public List<Obs> getObservations(Concept question, String sort, Integer personType, boolean includeVoided) {
List<Concept> questions = new Vector<Concept>();
questions.add(question);
// make the sort list from the given sort string
List<String> sortList = makeSortList(sort);
return getObservations(null, null, questions, null, getPersonTypeEnumerations(personType), null, sortList, null,
null, null, null, includeVoided);
}
/**
* @see org.openmrs.api.ObsService#getObservationsAnsweredByConcept(org.openmrs.Concept,
* java.lang.Integer, boolean includeVoided)
* @deprecated
*/
@Deprecated
public List<Obs> getObservationsAnsweredByConcept(Concept answer, Integer personType, boolean includeVoided) {
List<Concept> answers = new Vector<Concept>();
answers.add(answer);
return getObservations(null, null, null, answers, getPersonTypeEnumerations(personType), null, null, null, null,
null, null, includeVoided);
}
/**
* @see org.openmrs.api.ObsService#getNumericAnswersForConcept(org.openmrs.Concept,
* java.lang.Boolean, java.lang.Integer, boolean includeVoided)
* @deprecated
*/
@Deprecated
public List<Object[]> getNumericAnswersForConcept(Concept question, Boolean sortByValue, Integer personType,
boolean includeVoided) {
List<String> sortList = new Vector<String>();
if (sortByValue) {
sortList.add("valueNumeric");
}
List<Concept> questions = new Vector<Concept>();
questions.add(question);
List<Obs> obs = getObservations(null, null, questions, null, getPersonTypeEnumerations(personType), null, sortList,
null, null, null, null, includeVoided);
List<Object[]> returnList = new Vector<Object[]>();
for (Obs o : obs) {
returnList.add(new Object[] { o.getObsId(), o.getObsDatetime(), o.getValueNumeric() });
}
return returnList;
}
/**
* @see org.openmrs.api.ObsService#getObservations(org.openmrs.Encounter)
* @deprecated use org.openmrs.Encounter#getObs()
*/
@Deprecated
public Set<Obs> getObservations(Encounter whichEncounter) {
return whichEncounter.getObs();
}
/**
* @see org.openmrs.api.ObsService#getVoidedObservations()
* @deprecated
*/
@Deprecated
public List<Obs> getVoidedObservations() {
return getObservations(null, null, null, null, null, null, null, null, null, null, null, true);
}
/**
* @see org.openmrs.api.ObsService#findObservations(java.lang.String, boolean,
* java.lang.Integer)
* @deprecated
*/
@Deprecated
public List<Obs> findObservations(String search, boolean includeVoided, Integer personType) {
// ignoring voided and personTypes now
return getObservations(search);
}
/**
* @see org.openmrs.api.ObsService#findObsByGroupId(java.lang.Integer)
* @deprecated -- should use obs.getGroupMembers
*/
@Deprecated
public List<Obs> findObsByGroupId(Integer obsGroupId) {
return getObservations(null, null, null, null, null, null, null, null, obsGroupId, null, null, false);
}
/**
* @see org.openmrs.api.ObsService#getObsByUuid(java.lang.String)
*/
public Obs getObsByUuid(String uuid) throws APIException {
return dao.getObsByUuid(uuid);
}
/**
* @see org.openmrs.api.ObsService#getObservations(List, Date, Date, boolean)
* @deprecated
*/
@Deprecated
public List<Obs> getObservations(List<Concept> concepts, Date fromDate, Date toDate, boolean includeVoided) {
return getObservations(null, null, concepts, null, null, null, null, null, null, fromDate, toDate, includeVoided);
}
/**
* @see org.openmrs.api.ObsService#getObservations(List, Date, Date)
* @deprecated
*/
@Deprecated
public List<Obs> getObservations(List<Concept> concepts, Date fromDate, Date toDate) {
return getObservations(null, null, concepts, null, null, null, null, null, null, fromDate, toDate, false);
}
/**
* @see org.openmrs.api.ObsService#getObservations(Cohort, List, Date, Date)
* @deprecated
*/
@Deprecated
public List<Obs> getObservations(Cohort patients, List<Concept> concepts, Date fromDate, Date toDate) {
List<Person> persons = new Vector<Person>();
if (patients != null)
for (Integer memberId : patients.getMemberIds())
persons.add(new Person(memberId));
return getObservations(persons, null, concepts, null, null, null, null, null, null, fromDate, toDate, false);
}
/**
* @see org.openmrs.api.ObsService#getComplexObs(Integer, String)
*/
public Obs getComplexObs(Integer obsId, String view) throws APIException {
Obs obs = dao.getObs(obsId);
if (obs != null && obs.isComplex()) {
return getHandler(obs).getObs(obs, view);
}
return obs;
}
/**
* Internal method to remove ComplexData when an Obs is purged.
*/
protected boolean purgeComplexData(Obs obs) throws APIException {
if (obs.isComplex()) {
ComplexObsHandler handler = getHandler(obs);
if (null != handler) {
return handler.purgeComplexData(obs);
}
}
return true;
}
/**
* Convenience method to get the ComplexObsHandler associated with a complex Obs. Returns the
* ComplexObsHandler. Returns null if the Obs.isComplexObs() is false or there is an error
* instantiating the handler class.
*
* @param obs A complex Obs.
* @return ComplexObsHandler for the complex Obs. or null on error.
*/
public ComplexObsHandler getHandler(Obs obs) throws APIException {
if (obs.getConcept().isComplex()) {
// Get the ConceptComplex from the ConceptService then return its
// handler.
if (obs.getConcept() == null)
throw new APIException("Unable to get the handler for obs: " + obs + " because the concept is null");
String handlerString = Context.getConceptService().getConceptComplex(obs.getConcept().getConceptId())
.getHandler();
if (handlerString == null)
throw new APIException("Unable to get the handler for obs: " + obs + " and concept: " + obs.getConcept()
+ " because the handler is null");
return this.getHandler(handlerString);
}
return null;
}
/**
* @see org.openmrs.api.ObsService#getHandler(java.lang.String)
*/
public ComplexObsHandler getHandler(String key) {
return handlers.get(key);
}
/**
* @see org.openmrs.api.ObsService#setHandlers(Map)
* @see #registerHandler(String, ComplexObsHandler)
*/
public void setHandlers(Map<String, ComplexObsHandler> newHandlers) throws APIException {
for (Map.Entry<String, ComplexObsHandler> entry : newHandlers.entrySet()) {
registerHandler(entry.getKey(), entry.getValue());
}
}
/**
* @see org.openmrs.api.ObsService#getHandlers()
*/
public Map<String, ComplexObsHandler> getHandlers() throws APIException {
if (handlers == null)
handlers = new LinkedHashMap<String, ComplexObsHandler>();
return handlers;
}
/**
* @see org.openmrs.api.ObsService#registerHandler(String, ComplexObsHandler)
*/
public void registerHandler(String key, ComplexObsHandler handler) throws APIException {
getHandlers().put(key, handler);
}
/**
* @see org.openmrs.api.ObsService#registerHandler(String, String)
*/
@SuppressWarnings("unchecked")
public void registerHandler(String key, String handlerClass) throws APIException {
try {
Class loadedClass = OpenmrsClassLoader.getInstance().loadClass(handlerClass);
registerHandler(key, (ComplexObsHandler) loadedClass.newInstance());
}
catch (Exception e) {
throw new APIException("Unable to load and instantiate handler", e);
}
}
/**
* @see org.openmrs.api.ObsService#getObservationCount(java.util.List, boolean)
*/
@Override
public Integer getObservationCount(List<ConceptName> conceptNames, boolean includeVoided) {
return dao.getObservationCount(null, null, null, null, null, null, null, null, null, conceptNames, true);
}
/**
* @see org.openmrs.api.ObsService#removeHandler(java.lang.String)
*/
public void removeHandler(String key) {
handlers.remove(key);
}
}