org.openmrs.module.personalhr.web.controller.NewPatientFormController.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.module.personalhr.web.controller.NewPatientFormController.java

Source

/**
 * 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.module.personalhr.web.controller;

import java.text.NumberFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.Attributable;
import org.openmrs.Concept;
import org.openmrs.Location;
import org.openmrs.Obs;
import org.openmrs.Patient;
import org.openmrs.PatientIdentifier;
import org.openmrs.PatientIdentifierType;
import org.openmrs.Person;
import org.openmrs.PersonAddress;
import org.openmrs.PersonAttribute;
import org.openmrs.PersonAttributeType;
import org.openmrs.PersonName;
import org.openmrs.Relationship;
import org.openmrs.RelationshipType;
import org.openmrs.api.APIException;
import org.openmrs.api.DuplicateIdentifierException;
import org.openmrs.api.IdentifierNotUniqueException;
import org.openmrs.api.InsufficientIdentifiersException;
import org.openmrs.api.InvalidCheckDigitException;
import org.openmrs.api.InvalidIdentifierFormatException;
import org.openmrs.api.PatientIdentifierException;
import org.openmrs.api.PatientService;
import org.openmrs.api.PersonService;
import org.openmrs.api.PersonService.ATTR_VIEW_TYPE;
import org.openmrs.api.context.Context;
import org.openmrs.module.messaging.MessagingAddressService;
import org.openmrs.module.messaging.domain.MessagingAddress;
import org.openmrs.module.personalhr.PersonalhrUtil;
import org.openmrs.propertyeditor.ConceptEditor;
import org.openmrs.propertyeditor.LocationEditor;
import org.openmrs.util.OpenmrsConstants;
import org.openmrs.util.OpenmrsConstants.PERSON_TYPE;
import org.openmrs.util.OpenmrsUtil;
import org.openmrs.web.WebConstants;
import org.openmrs.web.controller.person.PersonFormController;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.view.RedirectView;

/**
 * This controller is used for the "mini"/"new"/"short" patient form. Only key/important attributes
 * for the patient are displayed and allowed to be edited
 * 
 * @see org.openmrs.web.controller.patient.PatientFormController
 */
public class NewPatientFormController extends SimpleFormController {

    /** Logger for this class and subclasses */
    protected final Log log = LogFactory.getLog(getClass());

    public void setShortPatientValidator(final ShortPatientValidator shortPatientValidator) {
        super.setValidator(shortPatientValidator);
    }

    // identifiers submitted with the form.  Stored here so that they can
    // be redisplayed for the user after an error
    Set<PatientIdentifier> newIdentifiers = new HashSet<PatientIdentifier>();

    String pref = "";

    /**
     * Allows for other Objects to be used as values in input tags. Normally, only strings and lists
     * are expected
     * 
     * @see org.springframework.web.servlet.mvc.BaseCommandController#initBinder(javax.servlet.http.HttpServletRequest,
     *      org.springframework.web.bind.ServletRequestDataBinder)
     */
    @Override
    protected void initBinder(final HttpServletRequest request, final ServletRequestDataBinder binder)
            throws Exception {
        super.initBinder(request, binder);

        final NumberFormat nf = NumberFormat.getInstance(Context.getLocale());
        binder.registerCustomEditor(java.lang.Integer.class,
                new CustomNumberEditor(java.lang.Integer.class, nf, true));
        binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(Context.getDateFormat(), true, 10));
        binder.registerCustomEditor(Location.class, new LocationEditor());
        binder.registerCustomEditor(Concept.class, "causeOfDeath", new ConceptEditor());
        request.getSession().setAttribute(WebConstants.OPENMRS_HEADER_USE_MINIMAL, "true");

    }

    @Override
    protected ModelAndView processFormSubmission(final HttpServletRequest request,
            final HttpServletResponse response, final Object obj, final BindException errors) throws Exception {

        this.newIdentifiers = new HashSet<PatientIdentifier>();

        final ShortPatientModel shortPatient = (ShortPatientModel) obj;

        this.log.debug(
                "\nNOW GOING THROUGH PROCESSFORMSUBMISSION METHOD.......................................\n\n");

        if (Context.isAuthenticated()) {
            final PatientService ps = Context.getPatientService();
            final MessageSourceAccessor msa = getMessageSourceAccessor();

            final String action = request.getParameter("action");
            if ((action == null) || action.equals(msa.getMessage("general.save"))) {

                final String[] identifiers = request.getParameterValues("identifier");
                final String[] types = request.getParameterValues("identifierType");
                final String[] locs = request.getParameterValues("location");
                this.pref = request.getParameter("preferred");
                if (this.pref == null) {
                    this.pref = "";
                }

                if (this.log.isDebugEnabled()) {
                    this.log.debug("identifiers: " + identifiers);
                    if (identifiers != null) {
                        for (final String s : identifiers) {
                            this.log.debug(s);
                        }
                    }

                    this.log.debug("types: " + types);
                    if (types != null) {
                        for (final String s : types) {
                            this.log.debug(s);
                        }
                    }

                    this.log.debug("locations: " + locs);
                    if (locs != null) {
                        for (final String s : locs) {
                            this.log.debug(s);
                        }
                    }

                    this.log.debug("preferred: " + this.pref);
                }

                // loop over the identifiers to create the patient.identifiers set
                if (identifiers != null) {
                    for (int i = 0; i < identifiers.length; i++) {
                        // arguments for the spring error messages
                        final String id = identifiers[i].trim();
                        final String[] args = { id };

                        // add the new identifier only if they put in some identifier string
                        if (id.length() > 0) {

                            // set up the actual identifier java object
                            PatientIdentifierType pit = null;
                            if ((types[i] == null) || types[i].equals("")) {
                                final String msg = getMessageSourceAccessor()
                                        .getMessage("PatientIdentifier.identifierType.null", args);
                                errors.reject(msg);
                            } else {
                                pit = ps.getPatientIdentifierType(Integer.valueOf(types[i]));
                            }

                            Location loc = null;
                            if ((locs[i] == null) || locs[i].equals("")) {
                                final String msg = getMessageSourceAccessor()
                                        .getMessage("PatientIdentifier.location.null", args);
                                errors.reject(msg);
                            } else {
                                loc = Context.getLocationService().getLocation(Integer.valueOf(locs[i]));
                            }

                            final PatientIdentifier pi = new PatientIdentifier(id, pit, loc);
                            pi.setPreferred(this.pref.equals(id + types[i]));
                            this.newIdentifiers.add(pi);

                            if (this.log.isDebugEnabled()) {
                                this.log.debug("Creating patient identifier with identifier: " + id);
                                this.log.debug("and type: " + types[i]);
                                this.log.debug("and location: " + locs[i]);
                            }

                        }
                    }
                }
            }

        }

        // skip calling super.processFormSubmission so that setting up the page is done
        // again in the onSubmit method

        return onSubmit(request, response, shortPatient, errors);
    }

    /**
     * The onSubmit function receives the form/command object that was modified by the input form
     * and saves it to the db
     * 
     * @see org.springframework.web.servlet.mvc.SimpleFormController#onSubmit(javax.servlet.http.HttpServletRequest,
     *      javax.servlet.http.HttpServletResponse, java.lang.Object,
     *      org.springframework.validation.BindException)
     */
    @Override
    @SuppressWarnings("unchecked")
    protected ModelAndView onSubmit(final HttpServletRequest request, final HttpServletResponse response,
            final Object obj, final BindException errors) throws Exception {

        final HttpSession httpSession = request.getSession();
        request.getSession().setAttribute(WebConstants.OPENMRS_HEADER_USE_MINIMAL, "true");

        this.log.debug("\nNOW GOING THROUGH ONSUBMIT METHOD.......................................\n\n");

        if (Context.isAuthenticated()) {
            final PatientService ps = Context.getPatientService();
            final PersonService personService = Context.getPersonService();

            final ShortPatientModel shortPatient = (ShortPatientModel) obj;
            final String view = getFormView();
            boolean isError = errors.hasErrors(); // account for possible errors in the processFormSubmission method

            if (isError) {
                httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, errors.getFieldError().getCode());
            }

            final String action = request.getParameter("action");
            final MessageSourceAccessor msa = getMessageSourceAccessor();
            if ((action != null) && action.equals(msa.getMessage("general.cancel"))) {
                httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "general.canceled");
                return new ModelAndView(new RedirectView("addPerson.htm?personType=patient"));
            }

            Patient patient = null;
            if (shortPatient.getPatientId() != null) {
                patient = ps.getPatient(shortPatient.getPatientId());
                if (patient == null) {
                    try {
                        final Person p = personService.getPerson(shortPatient.getPatientId());
                        Context.clearSession(); // so that this Person doesn't cause hibernate to think the new Patient is in the cache already (only needed until #725 is fixed)
                        patient = new Patient(p);
                    } catch (final ObjectRetrievalFailureException noUserEx) {
                        // continue;
                    }
                }
            }

            if (patient == null) {
                patient = new Patient();
            }

            boolean duplicate = false;
            final PersonName newName = shortPatient.getName();

            if (this.log.isDebugEnabled()) {
                this.log.debug("Checking new name: " + newName.toString());
            }

            for (final PersonName pn : patient.getNames()) {
                if ((((pn.getGivenName() == null) && (newName.getGivenName() == null))
                        || OpenmrsUtil.nullSafeEquals(pn.getGivenName(), newName.getGivenName()))
                        && (((pn.getMiddleName() == null) && (newName.getMiddleName() == null))
                                || OpenmrsUtil.nullSafeEquals(pn.getMiddleName(), newName.getMiddleName()))
                        && (((pn.getFamilyName() == null) && (newName.getFamilyName() == null))
                                || OpenmrsUtil.nullSafeEquals(pn.getFamilyName(), newName.getFamilyName()))) {
                    duplicate = true;
                }
            }

            // if this is a new name, add it to the patient
            if (!duplicate) {
                // set the current name to "non-preferred"
                if (patient.getPersonName() != null) {
                    patient.getPersonName().setPreferred(false);
                }

                // add the new name
                newName.setPersonNameId(null);
                newName.setPreferred(true);
                newName.setUuid(null);
                patient.addName(newName);
            }

            if (this.log.isDebugEnabled()) {
                this.log.debug("The address to add/check: " + shortPatient.getAddress());
            }

            if ((shortPatient.getAddress() != null) && !shortPatient.getAddress().isBlank()) {
                duplicate = false;
                for (final PersonAddress pa : patient.getAddresses()) {
                    if (pa.toString().equals(shortPatient.getAddress().toString())) {
                        duplicate = true;
                        pa.setPreferred(true);
                    } else {
                        pa.setPreferred(false);
                    }
                }

                if (this.log.isDebugEnabled()) {
                    this.log.debug("The duplicate address:  " + duplicate);
                }

                if (!duplicate) {
                    final PersonAddress newAddress = (PersonAddress) shortPatient.getAddress().clone();
                    newAddress.setPersonAddressId(null);
                    newAddress.setPreferred(true);
                    newAddress.setUuid(null);
                    patient.addAddress(newAddress);
                }
            }
            if (this.log.isDebugEnabled()) {
                this.log.debug("patient addresses: " + patient.getAddresses());
            }

            // set or unset the preferred bit for the old identifiers if needed
            if (patient.getIdentifiers() == null) {
                patient.setIdentifiers(new LinkedHashSet<PatientIdentifier>());
            }

            for (final PatientIdentifier pi : patient.getIdentifiers()) {
                pi.setPreferred(
                        this.pref.equals(pi.getIdentifier() + pi.getIdentifierType().getPatientIdentifierTypeId()));
            }

            String email = null;
            // look for person attributes in the request and save to patient
            for (final PersonAttributeType type : personService.getPersonAttributeTypes(PERSON_TYPE.PATIENT,
                    ATTR_VIEW_TYPE.VIEWING)) {
                final String paramName = type.getPersonAttributeTypeId().toString();
                final String value = request.getParameter(paramName);

                this.log.debug("paramName=" + paramName);
                if ("9".equalsIgnoreCase(paramName)) {
                    if (PersonalhrUtil.isNullOrEmpty(value)) {
                        //errors.reject("Email address cannot be empty!");
                        httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "Email address cannot be empty!");
                        isError = true;
                    } else if (!PersonalhrUtil.isValidEmail(value)) {
                        //errors.reject("Invalid email address: " + value);
                        httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR,
                                "Invalid email address: " + value);
                        isError = true;
                    } else {
                        //store email address to messaging_addresses table
                        email = value;
                    }
                }

                // if there is an error displaying the attribute, the value will be null
                if (!isError) {
                    final PersonAttribute attribute = new PersonAttribute(type, value);
                    try {
                        final Object hydratedObject = attribute.getHydratedObject();
                        if ((hydratedObject == null) || "".equals(hydratedObject.toString())) {
                            // if null is returned, the value should be blanked out
                            attribute.setValue("");
                        } else if (hydratedObject instanceof Attributable) {
                            attribute.setValue(((Attributable) hydratedObject).serialize());
                        } else if (!hydratedObject.getClass().getName().equals(type.getFormat())) {
                            // if the classes doesn't match the format, the hydration failed somehow
                            // TODO change the PersonAttribute.getHydratedObject() to not swallow all errors?
                            throw new APIException();
                        }
                    } catch (final APIException e) {
                        errors.rejectValue("attributeMap[" + type.getName() + "]",
                                "Invalid value for " + type.getName() + ": '" + value + "'");
                        this.log.warn("Got an invalid value: " + value + " while setting personAttributeType id #"
                                + paramName, e);

                        // setting the value to empty so that the user can reset the value to something else
                        attribute.setValue("");

                    }
                    patient.addAttribute(attribute);
                }
            }

            if (this.newIdentifiers.isEmpty()) {
                final PatientIdentifier ident = new PatientIdentifier();
                ident.setIdentifier(PersonalhrUtil.getRandomIdentifer());
                ident.setIdentifierType(new PatientIdentifierType(1));
                ident.setLocation(new Location(1));
                this.newIdentifiers.add(ident);
            }
            // add the new identifiers.  First remove them so that things like
            // changes to preferred status and location are persisted
            for (final PatientIdentifier identifier : this.newIdentifiers) {
                identifier.setPatient(patient);
                for (final PatientIdentifier currentIdentifier : patient.getActiveIdentifiers()) {
                    patient.removeIdentifier(currentIdentifier);
                }
            }

            patient.addIdentifiers(this.newIdentifiers);

            // find which identifiers they removed and void them
            // must create a new list so that the updated identifiers in
            // the newIdentifiers list are hashed correctly
            final List<PatientIdentifier> newIdentifiersList = new Vector<PatientIdentifier>();
            newIdentifiersList.addAll(this.newIdentifiers);
            for (final PatientIdentifier identifier : patient.getIdentifiers()) {
                if (!newIdentifiersList.contains(identifier)) {
                    // mark the "removed" identifiers as voided
                    identifier.setVoided(true);
                    identifier.setVoidReason("Removed from new patient screen");
                }
            }

            // set the other patient attributes
            patient.setBirthdate(shortPatient.getBirthdate());
            patient.setBirthdateEstimated(shortPatient.getBirthdateEstimated());
            patient.setGender(shortPatient.getGender());

            patient.setDead(shortPatient.getDead());
            if (patient.isDead()) {
                patient.setDeathDate(shortPatient.getDeathDate());
                patient.setCauseOfDeath(shortPatient.getCauseOfDeath());
            } else {
                patient.setDeathDate(null);
                patient.setCauseOfDeath(null);
            }

            Patient newPatient = null;

            if (!isError) {
                // save or add the patient
                try {
                    newPatient = ps.savePatient(patient);
                } catch (final InvalidIdentifierFormatException iife) {
                    this.log.error(iife);
                    patient.removeIdentifier(iife.getPatientIdentifier());
                    httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR,
                            "PatientIdentifier.error.formatInvalid");
                    //errors = new BindException(new InvalidIdentifierFormatException(msa.getMessage("PatientIdentifier.error.formatInvalid")), "givenName");
                    isError = true;
                } catch (final InvalidCheckDigitException icde) {
                    this.log.error(icde);
                    patient.removeIdentifier(icde.getPatientIdentifier());
                    httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "PatientIdentifier.error.checkDigit");
                    //errors = new BindException(new InvalidCheckDigitException(msa.getMessage("PatientIdentifier.error.checkDigit")), "givenName");
                    isError = true;
                } catch (final IdentifierNotUniqueException inue) {
                    this.log.error(inue);
                    patient.removeIdentifier(inue.getPatientIdentifier());
                    httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "PatientIdentifier.error.notUnique");
                    //errors = new BindException(new IdentifierNotUniqueException(msa.getMessage("PatientIdentifier.error.notUnique")), "givenName");
                    isError = true;
                } catch (final DuplicateIdentifierException die) {
                    this.log.error(die);
                    patient.removeIdentifier(die.getPatientIdentifier());
                    httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "PatientIdentifier.error.duplicate");
                    //errors = new BindException(new DuplicateIdentifierException(msa.getMessage("PatientIdentifier.error.duplicate")), "givenName");
                    isError = true;
                } catch (final InsufficientIdentifiersException iie) {
                    this.log.error(iie);
                    patient.removeIdentifier(iie.getPatientIdentifier());
                    httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR,
                            "PatientIdentifier.error.insufficientIdentifiers");
                    //errors = new BindException(new InsufficientIdentifiersException(msa.getMessage("PatientIdentifier.error.insufficientIdentifiers")), "givenName");
                    isError = true;
                } catch (final PatientIdentifierException pie) {
                    this.log.error(pie);
                    patient.removeIdentifier(pie.getPatientIdentifier());
                    httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, pie.getMessage());
                    //errors = new BindException(new PatientIdentifierException(msa.getMessage("PatientIdentifier.error.general")), "givenName");
                    isError = true;
                }

                // update the death reason
                if (patient.getDead()) {
                    this.log.debug("Patient is dead, so let's make sure there's an Obs for it");
                    // need to make sure there is an Obs that represents the patient's cause of death, if applicable

                    final String codProp = Context.getAdministrationService()
                            .getGlobalProperty("concept.causeOfDeath");
                    final Concept causeOfDeath = Context.getConceptService().getConcept(codProp);

                    if (causeOfDeath != null) {
                        final List<Obs> obssDeath = Context.getObsService()
                                .getObservationsByPersonAndConcept(patient, causeOfDeath);
                        if (obssDeath != null) {
                            if (obssDeath.size() > 1) {
                                this.log.error(
                                        "Multiple causes of death (" + obssDeath.size() + ")?  Shouldn't be...");
                            } else {
                                Obs obsDeath = null;
                                if (obssDeath.size() == 1) {
                                    // already has a cause of death - let's edit it.
                                    this.log.debug("Already has a cause of death, so changing it");

                                    obsDeath = obssDeath.iterator().next();

                                } else {
                                    // no cause of death obs yet, so let's make one
                                    this.log.debug("No cause of death yet, let's create one.");

                                    obsDeath = new Obs();
                                    obsDeath.setPerson(patient);
                                    obsDeath.setConcept(causeOfDeath);

                                    // Get default location
                                    final Location loc = Context.getLocationService().getDefaultLocation();

                                    // TODO person healthcenter if ( loc == null ) loc = patient.getHealthCenter();
                                    if (loc != null) {
                                        obsDeath.setLocation(loc);
                                    } else {
                                        this.log.error(
                                                "Could not find a suitable location for which to create this new Obs");
                                    }
                                }

                                // put the right concept and (maybe) text in this obs
                                Concept currCause = patient.getCauseOfDeath();
                                if (currCause == null) {
                                    // set to NONE
                                    this.log.debug("Current cause is null, attempting to set to NONE");
                                    final String noneConcept = Context.getAdministrationService()
                                            .getGlobalProperty("concept.none");
                                    currCause = Context.getConceptService().getConcept(noneConcept);
                                }

                                if (currCause != null) {
                                    this.log.debug("Current cause is not null, setting to value_coded");
                                    obsDeath.setValueCoded(currCause);
                                    obsDeath.setValueCodedName(currCause.getName()); // ABKTODO: presume current locale?

                                    Date dateDeath = patient.getDeathDate();
                                    if (dateDeath == null) {
                                        dateDeath = new Date();
                                    }
                                    obsDeath.setObsDatetime(dateDeath);

                                    // check if this is an "other" concept - if so, then we need to add value_text
                                    final String otherConcept = Context.getAdministrationService()
                                            .getGlobalProperty("concept.otherNonCoded");
                                    final Concept conceptOther = Context.getConceptService()
                                            .getConcept(otherConcept);
                                    if (conceptOther != null) {
                                        if (conceptOther.equals(currCause)) {
                                            // seems like this is an other concept - let's try to get the "other" field info
                                            final String otherInfo = ServletRequestUtils.getStringParameter(request,
                                                    "causeOfDeath_other", "");
                                            this.log.debug("Setting value_text as " + otherInfo);
                                            obsDeath.setValueText(otherInfo);
                                        } else {
                                            this.log.debug(
                                                    "New concept is NOT the OTHER concept, so setting to blank");
                                            obsDeath.setValueText("");
                                        }
                                    } else {
                                        this.log.debug(
                                                "Don't seem to know about an OTHER concept, so deleting value_text");
                                        obsDeath.setValueText("");
                                    }

                                    if (!StringUtils.hasText(obsDeath.getVoidReason())) {
                                        obsDeath.setVoidReason(Context.getMessageSourceService()
                                                .getMessage("general.default.changeReason"));
                                    }
                                    Context.getObsService().saveObs(obsDeath, obsDeath.getVoidReason());
                                } else {
                                    this.log.debug("Current cause is still null - aborting mission");
                                }
                            }
                        }
                    } else {
                        this.log.debug(
                                "Cause of death is null - should not have gotten here without throwing an error on the form.");
                    }

                }

            }

            // save the relationships to the database
            if (!isError && !errors.hasErrors()) {
                final Map<String, Relationship> relationships = getRelationshipsMap(patient, request);
                for (final Relationship relationship : relationships.values()) {
                    // if the user added a person to this relationship, save it
                    if ((relationship.getPersonA() != null) && (relationship.getPersonB() != null)) {
                        personService.saveRelationship(relationship);
                    }
                }

                //save email to messaging_addresses table
                Integer addressId = saveEmail(newPatient, email);
                //set default messaging alert address
                boolean shouldAlert = true;
                PersonalhrUtil.setMessagingAlertSettings(newPatient, shouldAlert, addressId);

            }

            // redirect if an error occurred
            if (isError || errors.hasErrors()) {
                this.log.error("Had an error during processing. Redirecting to " + this.getSuccessView());

                final Map<String, Object> model = new HashMap<String, Object>();
                model.put(getCommandName(), new ShortPatientModel(patient));

                // evict from session so that nothing temporarily added here is saved
                Context.evictFromSession(patient);

                httpSession.setAttribute(WebConstants.OPENMRS_HEADER_USE_MINIMAL, "false");

                return this.showForm(request, response, errors, model);
                //return new ModelAndView(new RedirectView("findPatient.htm"));
            } else {
                httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "Patient.saved");
                this.log.debug("Patient saved! Redirect to " + this.getSuccessView() + "?patientId="
                        + newPatient.getPatientId());
                request.getSession().setAttribute(WebConstants.OPENMRS_HEADER_USE_MINIMAL, "false");
                return new ModelAndView(
                        new RedirectView(this.getSuccessView() + "?patientId=" + newPatient.getPatientId()));
            }

        } else {
            return new ModelAndView(new RedirectView(getFormView()));
        }
    }

    /**
     * Auto generated method comment
     * 
     * @param newPatient
     * @param email
     */
    private Integer saveEmail(final Patient newPatient, final String email) {
        try {
            final MessagingAddressService mas = Context.getService(MessagingAddressService.class);
            MessagingAddress ma = new MessagingAddress(email, newPatient,
                    org.openmrs.module.messaging.email.EmailProtocol.class);
            ma.setPreferred(true);
            List<MessagingAddress> addresses = mas.findMessagingAddresses(null,
                    org.openmrs.module.messaging.email.EmailProtocol.class, newPatient, false);
            if (addresses != null && !addresses.isEmpty()) {
                for (MessagingAddress addr : addresses) {
                    if (addr.getPreferred()) {
                        addr.setAddress(email);
                        ma = addr;
                        break;
                    }
                }
            }
            mas.saveMessagingAddress(ma);

            List<MessagingAddress> addresses2 = mas.findMessagingAddresses(null,
                    org.openmrs.module.messaging.email.EmailProtocol.class, newPatient, false);
            if (addresses2 != null && !addresses2.isEmpty() && addresses2.get(0) != null) {
                return addresses2.get(0).getId();
            } else {
                return null;
            }
        } catch (final Exception e) {
            this.log.debug("Unable to save email address to messaging_addresses table " + email, e);
            return null;
        } catch (final NoClassDefFoundError e) {
            this.log.debug("Messaging module is not found, cannot save " + email, e);
            return null;
        }

    }

    /**
     * This is called prior to displaying a form for the first time. It tells Spring the
     * form/command object to load into the request
     * 
     * @see org.springframework.web.servlet.mvc.AbstractFormController#formBackingObject(javax.servlet.http.HttpServletRequest)
     */
    @Override
    protected Object formBackingObject(final HttpServletRequest request) throws ServletException {
        this.log.debug("Start NewPatientFormController:formBackingObject...");
        this.newIdentifiers = new HashSet<PatientIdentifier>();
        Patient p = null;
        Integer id = null;

        if (Context.isAuthenticated()) {
            final PatientService ps = Context.getPatientService();
            String patientId = request.getParameter("patientId");
            if (!StringUtils.hasText(patientId)
                    && (request.getAttribute("org.openmrs.portlet.patientId") != null)) {
                patientId = request.getAttribute("org.openmrs.portlet.patientId").toString();
            }

            if (StringUtils.hasText(patientId)) {
                try {
                    id = Integer.valueOf(patientId);
                    p = ps.getPatient(id);
                } catch (final NumberFormatException numberError) {
                    this.log.warn("Invalid patientId supplied: '" + patientId + "'", numberError);
                } catch (final ObjectRetrievalFailureException noUserEx) {
                    // continue
                }
            }

            if (p == null) {
                try {
                    final Person person = Context.getPersonService().getPerson(id);
                    if (person != null) {
                        p = new Patient(person);
                    }
                } catch (final ObjectRetrievalFailureException noPersonEx) {
                    this.log.warn("There is no patient or person with id: '" + id + "'", noPersonEx);
                    throw new ServletException("There is no patient or person with id: '" + id + "'");
                }
            }
        }

        this.log.debug("Patient=" + p + ", id: " + id);

        ShortPatientModel patient = new ShortPatientModel(p);

        final String name = request.getParameter("addName");
        if ((p == null) && (name != null)) {
            final String gender = request.getParameter("addGender");
            final String date = request.getParameter("addBirthdate");
            final String age = request.getParameter("addAge");

            p = new Patient();
            PersonFormController.getMiniPerson(p, name, gender, date, age);

            patient = new ShortPatientModel(p);
        }

        if (patient.getAddress() == null) {
            final PersonAddress pa = new PersonAddress();
            pa.setPreferred(true);
            patient.setAddress(pa);
        }

        return patient;
    }

    /**
     * Called prior to form display. Allows for data to be put in the request to be used in the view
     * 
     * @see org.springframework.web.servlet.mvc.SimpleFormController#referenceData(javax.servlet.http.HttpServletRequest)
     */
    @Override
    protected Map<String, Object> referenceData(final HttpServletRequest request) throws Exception {

        final Map<String, Object> map = new HashMap<String, Object>();

        // the list of identifiers to display
        // this is a hashset so that the comparison is one with .equals() instead of .compareTo
        final Set<PatientIdentifier> identifiers = new HashSet<PatientIdentifier>();

        Patient patient = null;
        String causeOfDeathOther = "";

        if (Context.isAuthenticated()) {
            final PatientService ps = Context.getPatientService();
            final String patientId = request.getParameter("patientId");
            if ((patientId != null) && !patientId.equals("")) {

                // our current patient
                patient = ps.getPatient(Integer.valueOf(patientId));

                if (patient != null) {

                    // only show non-voided identifiers
                    identifiers.addAll(patient.getActiveIdentifiers());
                    // get 'other' cause of death
                    final String propCause = Context.getAdministrationService()
                            .getGlobalProperty("concept.causeOfDeath");
                    final Concept conceptCause = Context.getConceptService().getConcept(propCause);
                    if ((conceptCause != null) && (patient.getPatientId() != null)) {
                        final List<Obs> obssDeath = Context.getObsService()
                                .getObservationsByPersonAndConcept(patient, conceptCause);

                        if (obssDeath.size() == 1) {
                            final Obs obsDeath = obssDeath.iterator().next();
                            causeOfDeathOther = obsDeath.getValueText();
                            if (causeOfDeathOther == null) {
                                this.log.debug("cod is null, so setting to empty string");
                                causeOfDeathOther = "";
                            } else {
                                this.log.debug("cod is valid: " + causeOfDeathOther);
                            }
                        } else {
                            this.log.debug("obssDeath is wrong size: " + obssDeath.size());
                        }
                    } else {
                        this.log.debug("No concept cause found");
                    }
                    // end get 'other' cause of death
                }
            }

            // set up the property for the relationships

            // {'3a':Relationship#234, '7b':Relationship#9488}
            final Map<String, Relationship> relationships = getRelationshipsMap(patient, request);
            map.put("relationships", relationships);
        }

        // give them both the just-entered identifiers and the patient's current identifiers
        for (final PatientIdentifier identifier : this.newIdentifiers) {
            // add the patient object to the new identifier list so
            // that the .equals method works correctly in the next loop
            identifier.setPatient(patient);
        }

        if (this.pref.length() > 0) {
            for (final PatientIdentifier pi : identifiers) {
                pi.setPreferred(
                        this.pref.equals(pi.getIdentifier() + pi.getIdentifierType().getPatientIdentifierTypeId()));
            }
        }

        if (Context.isAuthenticated()) {
            map.put("defaultLocation", Context.getAuthenticatedUser()
                    .getUserProperty(OpenmrsConstants.USER_PROPERTY_DEFAULT_LOCATION));
        }
        map.put("identifiers", identifiers);
        map.put("causeOfDeathOther", causeOfDeathOther);

        return map;
    }

    /**
     * Convenience method to fetch the relationships to display on the page. First the database is
     * queried for the user demanded relationships to show on the new patient form. @see
     * OpenmrsConstants#GLOBAL_PROPERTY_NEWPATIENTFORM_RELATIONSHIPS Each 3a, 6b relationship
     * defined there is pulled from the db and put into the map. If one doesn't exist in the db yet,
     * a relationship stub is created. If '3a' or '6b' exist as parameters in the given
     * <code>request</code>, that parameter value is put into the returned map
     * 
     * @param person The person to match against
     * @param request the current request with or without 3a-named parameters in it
     * @return Map from relation string to defined relationship object {'3a':obj, '7b':obj}
     */
    private Map<String, Relationship> getRelationshipsMap(final Person person, final HttpServletRequest request) {
        final Map<String, Relationship> relationshipMap = new LinkedHashMap<String, Relationship>();

        // gp is in the form "3a, 7b, 4a"
        String relationshipsString = Context.getAdministrationService()
                .getGlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_NEWPATIENTFORM_RELATIONSHIPS, "");
        relationshipsString = relationshipsString.trim();
        if (relationshipsString.length() > 0) {
            final String[] showRelations = relationshipsString.split(",");
            // iterate over strings like "3a"
            for (String showRelation : showRelations) {
                showRelation = showRelation.trim();

                boolean aIsToB = true;
                if (showRelation.endsWith("b")) {
                    aIsToB = false;
                }

                // trim out the trailing a or b char
                String showRelationId = showRelation.replace("a", "");
                showRelationId = showRelationId.replace("b", "");

                final RelationshipType relationshipType = Context.getPersonService()
                        .getRelationshipType(Integer.valueOf(showRelationId));

                // flag to know if we need to create a stub relationship
                boolean relationshipFound = false;

                if ((person != null) && (person.getPersonId() != null)) {
                    if (aIsToB) {
                        final List<Relationship> relationships = Context.getPersonService().getRelationships(null,
                                person, relationshipType);
                        if (relationships.size() > 0) {
                            relationshipMap.put(showRelation, relationships.get(0));
                            relationshipFound = true;
                        }
                    } else {
                        final List<Relationship> relationships = Context.getPersonService().getRelationships(person,
                                null, relationshipType);
                        if (relationships.size() > 0) {
                            relationshipMap.put(showRelation, relationships.get(0));
                            relationshipFound = true;
                        }
                    }
                }

                // if no relationship was found, create a stub one now
                if (relationshipFound == false) {
                    final Relationship relationshipStub = new Relationship();
                    relationshipStub.setRelationshipType(relationshipType);
                    if (aIsToB) {
                        relationshipStub.setPersonB(person);
                    } else {
                        relationshipStub.setPersonA(person);
                    }

                    relationshipMap.put(showRelation, relationshipStub);
                }

                // check the request to see if a parameter exists in there
                // that matches to the user desired relation.  Overwrite
                // any previous data if found
                final String submittedPersonId = request.getParameter(showRelation);
                if ((submittedPersonId != null) && (submittedPersonId.length() > 0)) {
                    final Person submittedPerson = Context.getPersonService()
                            .getPerson(Integer.valueOf(submittedPersonId));
                    if (aIsToB) {
                        relationshipMap.get(showRelation).setPersonA(submittedPerson);
                    } else {
                        relationshipMap.get(showRelation).setPersonB(submittedPerson);
                    }
                }

            }

        }

        return relationshipMap;
    }

}