/** * 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.web.dwr; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openmrs.Patient; import org.openmrs.Person; import org.openmrs.PersonName; import org.openmrs.Role; import org.openmrs.User; import org.openmrs.api.APIException; import org.openmrs.api.PatientService; import org.openmrs.api.PersonService; import org.openmrs.api.UserService; import org.openmrs.api.context.Context; /** * DWR methods for ajaxy effects on {@link Person} objects. */ public class DWRPersonService { protected final Log log = LogFactory.getLog(getClass()); /** * Searches for Person records that have a name similar to the given name, a birthdate that is * null or within a few years of the given birthdate, and a gender that matches. Note: this * method contains a non-backwards-compatible change between 1.5 and 1.6, since DWR has trouble * with method overloading. The String personType parameter was removed, since User no longer * extends Person * * @param name * @param birthyear * @param age * @param gender * @return */ public List<?> getSimilarPeople(String name, String birthdate, String age, String gender) { Vector<Object> personList = new Vector<Object>(); Integer userId = Context.getAuthenticatedUser().getUserId(); log.info(userId + "|" + name + "|" + birthdate + "|" + age + "|" + gender); PersonService ps = Context.getPersonService(); Integer d = null; birthdate = birthdate.trim(); age = age.trim(); if (birthdate.length() > 0) { // extract the year from the given birthdate string DateFormat format = Context.getDateFormat(); Date dateObject = null; try { dateObject = format.parse(birthdate); } catch (Exception e) {} if (dateObject != null) { Calendar c = Calendar.getInstance(); c.setTime(dateObject); d = c.get(Calendar.YEAR); } } else if (age.length() > 0) { // calculate their birth year from the given age string Calendar c = Calendar.getInstance(); c.setTime(new Date()); d = c.get(Calendar.YEAR); d = d - Integer.parseInt(age); } if (gender.length() < 1) gender = null; Set<Person> persons = ps.getSimilarPeople(name, d, gender); personList = new Vector<Object>(persons.size()); for (Person p : persons) { personList.add(PersonListItem.createBestMatch(p)); } return personList; } /** * @param searchPhrase * @param includeVoided * @return */ public List<?> findPeople(String searchPhrase, boolean includeVoided) { return findPeopleByRoles(searchPhrase, includeVoided, null); } /** * Find Person objects based on the given searchPhrase * * @param searchPhrase partial name or partial identifier * @param includeVoided true/false whether to include the voided objects * @param roles if not null, restricts search to only users and only users with these roles * @return list of PersonListItem s that match the given searchPhrase. The PersonListItems * contain as much information as possible about the matching persons, e.g. considering * whether they are patients or users, which for example is useful for displaying * patient identifiers in PersonSearch-widgets. * @should match on patient identifiers * @should allow null roles parameter */ public List<Object> findPeopleByRoles(String searchPhrase, boolean includeVoided, String roles) { return findBatchOfPeopleByRoles(searchPhrase, includeVoided, roles, null, null); } /** * Creates a new person stub. * * @param given * @param middle * @param family * @param birthdate * @param dateformat * @param age * @param gender * @return PersonListItem person stub created */ public Object createPerson(String given, String middle, String family, String birthdate, String dateformat, String age, String gender) { log.error(given + " " + middle + " " + family + " " + birthdate + " " + dateformat + " " + age + " " + gender); User user = Context.getAuthenticatedUser(); Person p = new Person(); p.setPersonCreator(user); p.setPersonDateCreated(new Date()); p.setPersonChangedBy(user); p.setPersonDateChanged(new Date()); if ("".equals(gender)) { log.error("Gender cannot be null."); return new String("Gender cannot be null."); } else if (gender.toUpperCase().contains("M")) p.setGender("M"); else if (gender.toUpperCase().contains("F")) p.setGender("F"); else { log.error("Gender must be 'M' or 'F'."); return new String("Gender must be 'M' or 'F'."); } if ("".equals(given) || "".equals(family)) { log.error("Given name and family name cannot be null."); return new String("Given name and family name cannot be null."); } PersonName name = new PersonName(given, middle, family); name.setCreator(user); name.setDateCreated(new Date()); name.setChangedBy(user); name.setDateChanged(new Date()); p.addName(name); try { Date d = updateAge(birthdate, dateformat, age); p.setBirthdate(d); } catch (java.text.ParseException pe) { log.error(pe); return new String("Birthdate cannot be parsed."); } p.setGender(gender); Person person = Context.getPersonService().savePerson(p); return PersonListItem.createBestMatch(person); } /** * @param patientId * @return */ public PersonListItem getPerson(Integer personId) { Person p = Context.getPersonService().getPerson(personId); return PersonListItem.createBestMatch(p); } /** * Private method to handle birth date and age input. * * @param birthdate * @param dateformat * @param age * @return * @throws java.text.ParseException */ private Date updateAge(String birthdate, String dateformat, String age) throws java.text.ParseException { SimpleDateFormat df = new SimpleDateFormat(); if (!"".equals(dateformat)) { dateformat = dateformat.toLowerCase().replaceAll("m", "M"); } else dateformat = new String("MM/dd/yyyy"); df.applyPattern(dateformat); Calendar cal = Calendar.getInstance(); cal.clear(Calendar.HOUR); cal.clear(Calendar.MINUTE); cal.clear(Calendar.SECOND); cal.clear(Calendar.MILLISECOND); if ("".equals(birthdate)) { if ("".equals(age)) return cal.getTime(); try { cal.add(Calendar.YEAR, -(Integer.parseInt(age))); } catch (NumberFormatException nfe) {} return cal.getTime(); } else cal.setTime(df.parse(birthdate)); return cal.getTime(); } /** * Find Person objects based on the given searchPhrase * * @param searchPhrase partial name or partial identifier * @param includeRetired true/false whether to include the voided objects * @param roles if not null, restricts search to only users and only users with these roles * @param start the beginning index (this is only used for user search i.e of roles are * specified) * @param length the number of matching people to return (this is only used for user search i.e * of roles are specified) * @return list of persons that match the given searchPhrase. The PersonListItems * @since 1.8 */ public Vector<Object> findBatchOfPeopleByRoles(String searchPhrase, boolean includeRetired, String roles, Integer start, Integer length) { Vector<Object> personList = new Vector<Object>(); try { // if roles were given, search for users with those roles if (StringUtils.isNotBlank(roles)) { UserService us = Context.getUserService(); List<Role> roleList = new Vector<Role>(); roles = roles.trim(); String[] splitRoles = roles.split(","); for (String role : splitRoles) { roleList.add(new Role(role)); } for (User u : us.getUsers(searchPhrase, roleList, includeRetired, start, length)) { personList.add(new UserListItem(u)); } } else { //TODO add batch person look up to the API and use it here and FIX the javadocs // if no roles were given, search for normal people PersonService ps = Context.getPersonService(); for (Person p : ps.getPeople(searchPhrase, null)) { personList.add(PersonListItem.createBestMatch(p)); } // also search on patient identifier if the query contains a number if (searchPhrase.matches(".*\\d+.*")) { PatientService patientService = Context.getPatientService(); for (Patient p : patientService.getPatients(null, searchPhrase, null, false)) { personList.add(PersonListItem.createBestMatch(p)); } } } } catch (Exception e) { log.error("Error while searching for persons", e); personList.clear(); personList.add(Context.getMessageSourceService().getMessage("Person.search.error") + " - " + e.getMessage()); } return personList; } /** * Returns a map of results with the values as count of matches and a partial list of the * matching people (depending on values of start and length parameters) while the keys are are * 'count' and 'objectList' respectively, if the length parameter is not specified, then all * matches will be returned from the start index if specified. * * @param phrase is the string used to search for people * @param includeRetired Specifies if retired people should be included or not * @param roles If not null, restricts search to only users and only users with these roles * @param start the beginning index * @param length the number of matching encounters to return * @param getMatchCount Specifies if the count of matches should be included in the returned map * @return a map of results * @throws APIException * @since 1.8 */ public Map<String, Object> findCountAndPeople(String phrase, boolean includeRetired, String roles, Integer start, Integer length, boolean getMatchCount) throws APIException { //Map to return Map<String, Object> resultsMap = new HashMap<String, Object>(); Vector<Object> objectList = new Vector<Object>(); try { UserService us = Context.getUserService(); int personCount = 0; if (getMatchCount) { if (StringUtils.isNotBlank(roles)) { roles = roles.trim(); List<Role> roleList = new Vector<Role>(); String[] splitRoles = roles.split(","); for (String role : splitRoles) { roleList.add(new Role(role)); } personCount = us.getCountOfUsers(phrase, roleList, includeRetired); } else { //TODO get the person count after adding the get count method for persons to the API } } //if we have any matches or this isn't the first ajax call when the caller //requests for the count if (personCount > 0 || !getMatchCount) objectList = findBatchOfPeopleByRoles(phrase, includeRetired, roles, start, length); resultsMap.put("count", personCount); resultsMap.put("objectList", objectList); } catch (Exception e) { log.error("Error while searching for persons", e); objectList.clear(); objectList.add(Context.getMessageSourceService().getMessage("Person.search.error") + " - " + e.getMessage()); resultsMap.put("count", 0); resultsMap.put("objectList", objectList); } return resultsMap; } }