/** * 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.module.xforms; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.lang.reflect.Method; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Locale; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.kxml2.kdom.Document; import org.kxml2.kdom.Element; import org.openmrs.Concept; import org.openmrs.ConceptDatatype; import org.openmrs.ConceptName; import org.openmrs.Encounter; import org.openmrs.Location; import org.openmrs.Obs; import org.openmrs.Person; import org.openmrs.User; import org.openmrs.api.context.Context; import org.openmrs.module.xforms.util.DOMUtil; import org.openmrs.module.xforms.util.XformsUtil; import org.openmrs.propertyeditor.ConceptEditor; import org.openmrs.propertyeditor.LocationEditor; import org.openmrs.propertyeditor.UserEditor; import org.openmrs.util.FormConstants; import org.openmrs.util.FormUtil; import org.openmrs.util.OpenmrsUtil; import org.springframework.util.FileCopyUtils; import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; /** * Utility functions and variables for editing for obs using xforms. * * @author daniel * */ public class XformObsEdit { private static final Log log = LogFactory.getLog(XformObsEdit.class); /** A mapping of xpath expressions to their complex data. */ private static HashMap<String,byte[]> complexData; /** A mapping of xpath expressions and their corresponding node names. */ private static HashMap<String,String> complexDataNodeNames; /** A list of xpath expressions for complex data which has beed edited. */ private static List<String> dirtyComplexData; public static String getMultSelObsNodeName(Element parent, Obs obs, List<String> nonCopyAttributes){ return XformBuilder.getElementByAttributePrefix(parent, "openmrs_concept",obs.getValueCoded().getConceptId()+"^", false, "obsId", true, nonCopyAttributes).getName(); } public static void fillObs(HttpServletRequest request,Document doc, Integer encounterId, String xml)throws Exception{ Element formNode = XformBuilder.getElement(doc.getRootElement(),"form"); if(formNode == null) return; Encounter encounter = Context.getEncounterService().getEncounter(encounterId); if(encounter == null) return; retrieveSessionValues(request); clearSessionData(request,encounter.getForm().getFormId()); formNode.setAttribute(null, "encounterId", encounter.getEncounterId().toString()); if (encounter.getLocation() != null) { XformBuilder.setNodeValue(doc, XformBuilder.NODE_ENCOUNTER_LOCATION_ID, encounter.getLocation().getLocationId().toString()); XformBuilder.setNodeAttributeValue(doc, XformBuilder.NODE_ENCOUNTER_LOCATION_ID, "displayValue", encounter.getLocation().getName()); } XformBuilder.setNodeValue(doc, XformBuilder.NODE_ENCOUNTER_ENCOUNTER_DATETIME, XformsUtil.encounterDateIncludesTime() ? XformsUtil.fromDateTime2SubmitString(encounter.getEncounterDatetime()) : XformsUtil.fromDate2SubmitString(encounter.getEncounterDatetime())); Integer providerId = XformsUtil.getProviderId(encounter); if (providerId != null) { XformBuilder.setNodeValue(doc, XformBuilder.NODE_ENCOUNTER_PROVIDER_ID, providerId.toString()); String name = XformsUtil.getProviderName(encounter); if (name != null) { XformBuilder.setNodeAttributeValue(doc, XformBuilder.NODE_ENCOUNTER_PROVIDER_ID, "displayValue", name); } } List<String> complexObs = DOMUtil.getXformComplexObsNodeNames(xml); HashMap<String,Element> obsGroupNodes = new HashMap<String,Element>(); List<String> nonCopyAttributes = new ArrayList<String>(); nonCopyAttributes.add("obsId"); nonCopyAttributes.add("obsGroupId"); DecimalFormat decimalFormat = new DecimalFormat("#"); Set<Obs> observations = encounter.getObs(); for(Obs obs : observations){ Concept concept = obs.getConcept(); //Obs obsGroup = obs.getObsGroup(); String obsGroupId = obs.getObsGroup() == null ? null : obs.getObsGroup().getObsId().toString(); //TODO This needs to do a better job by searching for an attribute that starts with //a concept id of the concept and hence remove the name dependency as the concept name //could change or may be different in a different locale. Element node = XformBuilder.getElementByAttributePrefix(formNode,"openmrs_concept", (obsGroupId == null ? concept.getConceptId() : obs.getObsGroup().getConcept()) +"^", (obsGroupId == null ? false : true), (obsGroupId == null ? "obsId" : "obsGroupId"), true, nonCopyAttributes); if(node == null) continue; //check if this is a repeating obs. if(obsGroupId != null){ String nodeGroupId = node.getAttributeValue(null, "obsGroupId"); //if this is first time to get a node of this parent. if(nodeGroupId == null || nodeGroupId.trim().length() == 0){ node.setAttribute(null, "obsGroupId", obsGroupId); //new group processing obsGroupNodes.put(obsGroupId, node); } else{ if(!nodeGroupId.equals(obsGroupId)){ Element groupNode = obsGroupNodes.get(obsGroupId); if(groupNode == null){//new group node = XformBuilder.createCopy(node, nonCopyAttributes); node.setAttribute(null, "obsGroupId", obsGroupId); obsGroupNodes.put(obsGroupId, node); }//else a kid of some other group which we processed but not necessarily being the first one. else node = groupNode; }//else another kid of an already processed group. } node = XformBuilder.getElementByAttributePrefix(node,"openmrs_concept",concept.getConceptId()+"^", false, "obsId", false, nonCopyAttributes); if(node == null) continue; } String value = obs.getValueAsString(Context.getLocale()); if(concept.getDatatype().isCoded() && obs.getValueCoded() != null) value = FormUtil.conceptToString(obs.getValueCoded(), Context.getLocale()); else if(concept.getDatatype().getHl7Abbreviation().equals(ConceptDatatype.DATE) && obs.getValueDatetime() != null) value = XformsUtil.fromDate2SubmitString(obs.getValueDatetime()); else if(concept.getDatatype().getHl7Abbreviation().equals(ConceptDatatype.DATETIME) && obs.getValueDatetime() != null) value = XformsUtil.fromDateTime2SubmitString(obs.getValueDatetime()); else if(concept.getDatatype().getHl7Abbreviation().equals(ConceptDatatype.TIME) && obs.getValueDatetime() != null) value = XformsUtil.fromTime2SubmitString(obs.getValueDatetime()); else if(concept.getDatatype().getHl7Abbreviation().equals(ConceptDatatype.NUMERIC) && obs.getValueNumeric() != null){ if(value != null && value.contains("E")) //check if number is in scientific format. value = decimalFormat.format(obs.getValueNumeric()); } if("1".equals(node.getAttributeValue(null,"multiple"))){ Element multNode = XformBuilder.getElement(node, "xforms_value"); if(multNode != null){ value = XformBuilder.getTextValue(multNode); if(value != null && value.trim().length() > 0) value += " "; else value = ""; //TODO This may fail when locale changes from the one in which the form was designed. //String xmlToken = FormUtil.getXmlToken(obs.getValueAsString(Context.getLocale())); try{ String xmlToken = getMultSelObsNodeName((Element)multNode.getParent(), obs, nonCopyAttributes); XformBuilder.setNodeValue(node, "xforms_value", value + xmlToken); //TODO May need to use getElementWithAttributePrefix() Element valueNode = XformBuilder.getElement(node, xmlToken); if(valueNode != null){ XformBuilder.setNodeValue(valueNode,"true"); valueNode.setAttribute(null, "obsId", obs.getObsId().toString()); } }catch(Exception ex){ ex.printStackTrace(); } } } else{ Element valueNode = XformBuilder.getElement(node, "value"); if(valueNode != null){ String nodeName = node.getName(); if(complexObs.contains(nodeName)){ String key = getComplexDataKey(formNode.getAttributeValue(null, "id"),"/form/obs/" + node.getName() + "/value"); value = getComplexObsValue(node.getName(),valueNode,value,key); } XformBuilder.setNodeValue(valueNode,value); valueNode.setAttribute(null, "obsId", obs.getObsId().toString()); if(concept.getDatatype().isCoded() && obs.getValueCoded() != null) valueNode.setAttribute(null, "displayValue", obs.getValueCoded().getName().getName()); if(obsGroupId != null || (nodeName.equals("problem_added") || nodeName.equals("problem_resolved"))) valueNode.setAttribute(null, "default", "false()"); } node.setAttribute(null, "obsId", obs.getObsId().toString()); //XformBuilder.setNodeValue(node, "value", value); } //If obs date is not the same as for that of the encounter, it means the user explicitly entered it. if (obs.getObsDatetime() != null && !encounter.getEncounterDatetime().equals(obs.getObsDatetime())) { Element dateNode = XformBuilder.getElement(node, "date"); if (dateNode != null) { value = XformsUtil.fromDate2SubmitString(obs.getObsDatetime()); XformBuilder.setNodeValue(dateNode, value); } } } //System.out.println(XformBuilder.fromDoc2String(doc)); } private static String getComplexObsValue(String nodeName, Element valueNode, String value, String key){ complexDataNodeNames.put(key, nodeName); if(value == null || value.trim().length() == 0) return value; try{ byte[] bytes = FileCopyUtils.copyToByteArray(new FileInputStream(value)); complexData.put(key, bytes); return Base64.encode(bytes); } catch(Exception ex){ log.error(ex); //File may be deleted, but that should not prevent loading of the form. } return value; } public static Encounter getEditedEncounter(HttpServletRequest request,Document doc,Set<Obs> obs2Void, String xml) throws Exception{ return getEditedEncounter(request,XformBuilder.getElement(doc.getRootElement(),"form"),obs2Void); } public static Encounter getEditedEncounter(HttpServletRequest request,Element formNode,Set<Obs> obs2Void) throws Exception{ if(formNode == null || !"form".equals(formNode.getName())) return null; String formId = formNode.getAttributeValue(null, "id"); retrieveSessionValues(request); clearSessionData(request,Integer.parseInt(formId)); List<String> complexObs = DOMUtil.getModelComplexObsNodeNames(formId); List<String> dirtyComplexObs = getEditedComplexObsNames(); Date datetime = new Date(); Integer encounterId = Integer.parseInt(formNode.getAttributeValue(null, "encounterId")); Encounter encounter = Context.getEncounterService().getEncounter(encounterId); setEncounterHeader(encounter,formNode); Hashtable<String,String[]> multipleSelValues = new Hashtable<String,String[]>(); Set<Obs> observations = encounter.getObs(); for(Obs obs : observations){ Concept concept = obs.getConcept(); String nodeName = FormUtil.getXmlToken(concept.getDisplayString()); Element node = XformBuilder.getElementByAttributeValue(formNode,"obsId",obs.getObsId().toString()); if(node == null){ if(obs.getObsGroup() != null) voidObs(obs.getObsGroup(),datetime,obs2Void); voidObs(obs,datetime,obs2Void); continue; } if(isMultipleSelNode((Element)node.getParent())) node = (Element)node.getParent(); if(isMultipleSelNode(node)){ String xmlToken = FormUtil.getXmlToken(obs.getValueAsString(Context.getLocale())); if(multipleSelValueContains(nodeName,xmlToken,node,multipleSelValues)) continue; voidObs(obs,datetime,obs2Void); } else{ Element valueNode = XformBuilder.getElement(node, "value"); if(valueNode != null){ String newValue = XformBuilder.getTextValue(valueNode); String oldValue = obs.getValueAsString(Context.getLocale()); if(concept.getDatatype().getHl7Abbreviation().equals(ConceptDatatype.DATETIME) && obs.getValueDatetime() != null) oldValue = XformsUtil.fromDateTime2SubmitString(obs.getValueDatetime()); else if(concept.getDatatype().getHl7Abbreviation().equals(ConceptDatatype.TIME) && obs.getValueDatetime() != null) oldValue = XformsUtil.fromTime2SubmitString(obs.getValueDatetime()); //Deal with complex obs first if(complexObs.contains(nodeName)){ //Continue if complex obs has neither been replaced //with a another one nor cleared. if(!dirtyComplexObs.contains(nodeName) && !( (newValue == null || newValue.trim().length() == 0) && (oldValue != null && oldValue.trim().length() > 0 ) )) continue; //complex obs not modified. voidObs(obs,datetime,obs2Void); if(newValue == null || newValue.trim().length() == 0) continue; //complex obs just cleared without a replacement. newValue = saveComplexObs(nodeName,newValue,formNode); } else{ if(concept.getDatatype().isCoded() && obs.getValueCoded() != null) oldValue = conceptToString(obs.getValueCoded(), Context.getLocale()); if(oldValue.equals(newValue)) continue; //obs has not changed voidObs(obs,datetime,obs2Void); if(newValue == null || newValue.trim().length() == 0) continue; } //setObsValue(obs,newValue); //obs.setDateChanged(datetime); //obs.setChangedBy(Context.getAuthenticatedUser()); encounter.addObs(createObs(concept,obs.getObsGroup(),newValue,datetime)); } else throw new IllegalArgumentException("cannot locate node for concept: " + concept.getDisplayString()); } } //addNewObs(formNode,complexObs,encounter,XformBuilder.getElement(formNode,"obs"),datetime,null); //addNewObs(formNode,complexObs,encounter,XformBuilder.getElement(formNode,"problem_list"),datetime,null); //Add new obs for all form sections for(int i=0; i<formNode.getChildCount(); i++){ if(formNode.getType(i) != Element.ELEMENT) continue; Element child = (Element)formNode.getChild(i); String conceptStr = child.getAttributeValue(null, "openmrs_concept"); if(conceptStr == null || conceptStr.trim().length() == 0) ;//continue; //TODO Can't we have sections which are not concepts? addNewObs(formNode, complexObs, encounter, child, datetime, null); } XformObsPatientEdit.updatePatientDemographics(encounter.getPatient(), formNode); return encounter; } private static void voidObs(Obs obs, Date datetime, Set<Obs> obs2Void){ obs.setVoided(true); obs.setVoidedBy(Context.getAuthenticatedUser()); obs.setDateVoided(datetime); obs.setVoidReason("xformsmodule"); //TODO Need to set this from user. obs2Void.add(obs); } private static void setEncounterHeader(Encounter encounter, Element formNode) throws Exception{ encounter.setLocation(Context.getLocationService().getLocation(Integer.valueOf(XformBuilder.getNodeValue(formNode, XformBuilder.NODE_ENCOUNTER_LOCATION_ID)))); Integer id = Integer.valueOf(XformBuilder.getNodeValue(formNode, XformBuilder.NODE_ENCOUNTER_PROVIDER_ID)); if (XformsUtil.isOnePointNineAndAbove()) { XformsUtil.setProvider(encounter, id); } else { Person person = Context.getPersonService().getPerson(id); try{ Method method = encounter.getClass().getMethod("setProvider", new Class[]{Person.class}); method.invoke(encounter, new Object[]{person}); } catch(NoSuchMethodError ex){ encounter.setProvider(Context.getUserService().getUser(id)); } } String submitString = XformBuilder.getNodeValue(formNode, XformBuilder.NODE_ENCOUNTER_ENCOUNTER_DATETIME); Date date = null; if(XformsUtil.encounterDateIncludesTime()) date = XformsUtil.fromSubmitString2DateTime(submitString); else date = XformsUtil.fromSubmitString2Date(submitString); encounter.setEncounterDatetime(date); } private static void addNewObs(Element formNode, List<String> complexObs,Encounter encounter, Element obsNode, Date datetime, Obs obsGroup) throws Exception{ if(obsNode == null) return; for(int i=0; i<obsNode.getChildCount(); i++){ if(obsNode.getType(i) != Element.ELEMENT) continue; Element node = (Element)obsNode.getChild(i); String conceptStr = node.getAttributeValue(null, "openmrs_concept"); if(conceptStr == null || conceptStr.trim().length() == 0) continue; Concept concept = Context.getConceptService().getConcept(Integer.parseInt(getConceptId(conceptStr))); if(isMultipleSelNode(node)) addMultipleSelObs(encounter,concept,node,datetime); else{ Element valueNode = XformBuilder.getElement(node, "value"); String value = XformBuilder.getTextValue(valueNode); String obsId = node.getAttributeValue(null, "obsId"); String obsGroupId = node.getAttributeValue(null, "obsGroupId"); if((obsId != null && obsId.trim().length() > 0) || obsGroupId != null && obsGroupId.trim().length() > 0){ if(!"true()".equals(valueNode.getAttributeValue(null, "new"))) continue; //new obs cant have an obs id } if(obsGroupId != null && obsGroupId.trim().length() > 0){ Obs group = createObs(concept,obsGroup,value,datetime); encounter.addObs(group); addNewObs(formNode,complexObs,encounter,node,datetime,group); continue; //new obs cant have an obsGroupId } if(valueNode == null) continue; if(value == null || value.trim().length() == 0) continue; String nodeName = node.getName(); if(complexObs.contains(nodeName)) value = saveComplexObs(nodeName,value,formNode); Obs obs = createObs(concept,obsGroup,value,datetime); encounter.addObs(obs); if(concept.isSet()) addNewObs(node,complexObs,encounter,node,datetime,obs); } } } private static void addMultipleSelObs(Encounter encounter, Concept concept,Element node, Date datetime) throws Exception{ Element multValueNode = XformBuilder.getElement(node, "xforms_value"); if(multValueNode == null) return; String value = XformBuilder.getTextValue(multValueNode); if(value == null || value.trim().length() == 0) return; String[] valueArray = value.split(XformBuilder.MULTIPLE_SELECT_VALUE_SEPARATOR); for(int i=0; i<node.getChildCount(); i++){ if(node.getType(i) != Element.ELEMENT) continue; Element valueNode = (Element)node.getChild(i); String obsId = valueNode.getAttributeValue(null, "obsId"); if(obsId != null && obsId.trim().length() > 0){ if(!"true()".equals(valueNode.getAttributeValue(null, "new"))) continue; //new obs cant have an obs id } String obsGroupId = valueNode.getAttributeValue(null, "obsGroupId"); if(obsGroupId != null && obsGroupId.trim().length() > 0) continue; //new obs cant have an obsGroupId String conceptStr = valueNode.getAttributeValue(null, "openmrs_concept"); if(conceptStr == null || conceptStr.trim().length() == 0) continue; //must have an openmrs_concept attribute hence nothing like date or value nodes if(!contains(valueNode.getName(),valueArray)) continue; //name must be in the xforms_value Obs obs = createObs(concept,null,conceptStr,datetime); encounter.addObs(obs); } } private static boolean multipleSelValueContains(String nodeName, String valueName,Element node,Hashtable<String,String[]> multipleSelValues){ String[] values = multipleSelValues.get(nodeName); if(values == null){ Element multNode = XformBuilder.getElement(node, "xforms_value"); if(multNode != null){ String value = XformBuilder.getTextValue(multNode); if(value == null) value = ""; values = value.split(XformBuilder.MULTIPLE_SELECT_VALUE_SEPARATOR); multipleSelValues.put(nodeName, values); } } return contains(valueName,values); } /*private static void setObsValue(Obs obs,Element valueNode, boolean isNew) throws Exception{ setObsValue(obs,XformBuilder.getTextValue(valueNode),isNew); }*/ private static boolean setObsValue(Obs obs,String value) throws Exception{ ConceptDatatype dt = obs.getConcept().getDatatype(); if (dt.isNumeric()) obs.setValueNumeric(Double.parseDouble(value.toString())); else if (dt.isText()) obs.setValueText(value); else if (dt.isCoded()) obs.setValueCoded((Concept) convertToType(getConceptId(value), Concept.class)); else if (dt.isBoolean()){ boolean booleanValue = value != null && !Boolean.FALSE.equals(value) && !"false".equals(value); obs.setValueNumeric(booleanValue ? 1.0 : 0.0); } else if(dt.TIME.equals(dt.getHl7Abbreviation())) obs.setValueDatetime(XformsUtil.fromSubmitString2Time(value)); else if(dt.DATETIME.equals(dt.getHl7Abbreviation())) obs.setValueDatetime(XformsUtil.fromSubmitString2DateTime(value)); else if (dt.isDate()) obs.setValueDatetime(XformsUtil.fromSubmitString2Date(value)); else if ("ZZ".equals(dt.getHl7Abbreviation())) { // don't set a value. eg could be a set }else throw new IllegalArgumentException("concept datatype not yet implemented: " + dt.getName() + " with Hl7 Abbreviation: " + dt.getHl7Abbreviation()); return false; } private static String getConceptId(String conceptStr){ int pos = conceptStr.indexOf('^'); if(pos < 1) return conceptStr; //must be a number already. return conceptStr.substring(0, pos); } private static Object convertToType(String val, Class<?> clazz) { if (val == null) return null; if ("".equals(val) && !String.class.equals(clazz)) return null; if (Location.class.isAssignableFrom(clazz)) { LocationEditor ed = new LocationEditor(); ed.setAsText(val); return ed.getValue(); } else if (User.class.isAssignableFrom(clazz)) { UserEditor ed = new UserEditor(); ed.setAsText(val); return ed.getValue(); } else if (Date.class.isAssignableFrom(clazz)) { try { DateFormat df = Context.getDateFormat(); df.setLenient(false); return df.parse(val); } catch (ParseException e) { throw new IllegalArgumentException(e); } } else if (Double.class.isAssignableFrom(clazz)) { return Double.valueOf(val); } else if (Concept.class.isAssignableFrom(clazz)) { ConceptEditor ed = new ConceptEditor(); ed.setAsText(val); return ed.getValue(); } else { return val; } } private static Obs createObs(Concept concept,Obs obsGroup, String value, Date datetime) throws Exception{ Obs obs = new Obs(); obs.setConcept(concept); obs.setObsGroup(obsGroup); setObsValue(obs,value); if (datetime != null) obs.setObsDatetime(datetime); obs.setCreator(Context.getAuthenticatedUser()); return obs; } private static boolean isMultipleSelNode(Element node){ return "1".equals(node.getAttributeValue(null,"multiple")); } private static boolean contains(String name,String[] valueArray){ for(String value : valueArray){ if(!value.equalsIgnoreCase(name)) continue; return true; } return false; } public static String conceptToString(Concept concept, Locale locale) { ConceptName localizedName = concept.getName(locale); return conceptToString(concept, localizedName); } /** * Turn the given concept/concept-name pair into a string acceptable for hl7 and forms * * @param concept Concept to convert to a string * @param localizedName specific localized concept-name * @return String representation of the given concept */ public static String conceptToString(Concept concept, ConceptName localizedName) { return concept.getConceptId() + "^" + localizedName.getName() + "^" + FormConstants.HL7_LOCAL_CONCEPT; // + "^" // + localizedName.getConceptNameId() + "^" + localizedName.getName() + "^" + FormConstants.HL7_LOCAL_CONCEPT_NAME; } public static String getComplexDataKey(String formid, String xpath){ return formid + xpath; } public static List<String> getEditedComplexObsNames(){ List<String> names = new ArrayList<String>(); for(String xpath : dirtyComplexData){ String name = complexDataNodeNames.get(xpath); if(name != null) names.add(name); } return names; } public static String saveComplexObs(String nodeName, String value, Element formNode) throws Exception { byte[] bytes = Base64.decode(value); String path = formNode.getAttributeValue(null,"name"); path += File.separatorChar + nodeName; File file = OpenmrsUtil.getOutFile(XformsUtil.getXformsComplexObsDir(path), new Date(), Context.getAuthenticatedUser()); FileOutputStream writter = new FileOutputStream(file); writter.write(bytes); writter.close(); return file.getAbsolutePath(); } public static void retrieveSessionValues(HttpServletRequest request){ HttpSession session = request.getSession(); complexData = (HashMap<String,byte[]>)session.getAttribute("XformObsEdit.complexData"); complexDataNodeNames = (HashMap<String,String>)session.getAttribute("XformObsEdit.complexDataNodeNames"); dirtyComplexData = (List<String>)session.getAttribute("XformObsEdit.dirtyComplexData"); if(complexData == null){ complexData = new HashMap<String,byte[]>(); session.setAttribute("XformObsEdit.complexData", complexData); } if(complexDataNodeNames == null){ complexDataNodeNames = new HashMap<String,String>(); session.setAttribute("XformObsEdit.complexDataNodeNames", complexDataNodeNames); } if(dirtyComplexData == null){ dirtyComplexData = new ArrayList<String>(); session.setAttribute("XformObsEdit.dirtyComplexData", dirtyComplexData); } } public static void clearSessionData(HttpServletRequest request,Integer formId){ complexData.clear(); complexDataNodeNames.clear(); dirtyComplexData.clear(); clearFormSessionData(request, formId.toString()); } public static byte[] getComplexData(HttpServletRequest request,String formId, String xpath){ retrieveSessionValues(request); return complexData.get(getComplexDataKey(formId, xpath)); } public static void setComplexDataDirty(HttpServletRequest request,String formId, String xpath){ retrieveSessionValues(request); String key = getComplexDataKey(formId, xpath); if(!dirtyComplexData.contains(key)) dirtyComplexData.add(key); } public static void loadAndClearSessionData(HttpServletRequest request,Integer formId){ HttpSession session = request.getSession(); complexData = (HashMap<String,byte[]>)session.getAttribute("XformObsEdit.complexData"); complexDataNodeNames = (HashMap<String,String>)session.getAttribute("XformObsEdit.complexDataNodeNames"); dirtyComplexData = (List<String>)session.getAttribute("XformObsEdit.dirtyComplexData"); if(complexData != null) complexData.clear(); if(complexDataNodeNames != null) complexDataNodeNames.clear(); if(dirtyComplexData != null) dirtyComplexData.clear(); clearFormSessionData(request, formId.toString()); } public static void clearFormSessionData(HttpServletRequest request,String formId){ HttpSession session = request.getSession(); session.setAttribute(getFormKey(formId), null); } public static String getFormKey(String formId){ return "MultidemiaData"+formId; } public static void fillPatientComplexObs(HttpServletRequest request,Document doc, String xml) throws Exception{ retrieveSessionValues(request); clearSessionData(request, XformConstants.PATIENT_XFORM_FORM_ID); Element patientNode = XformBuilder.getElement(doc.getRootElement(), "patient"); if(patientNode== null) return; List<String> complexObs = DOMUtil.getXformComplexObsNodeNames(xml); for(int index = 0; index < patientNode.getChildCount(); index++){ if(patientNode.getType(index) != Element.ELEMENT) continue; //Syste Element node = (Element)patientNode.getChild(index); if(complexObs.contains(node.getName())){ String value = XformBuilder.getTextValue(node); if(value != null && value.trim().length() > 0){ String key = getComplexDataKey(patientNode.getAttributeValue(null, "id"),"/patient/" + node.getName()); value = getComplexObsValue(node.getName(),node,value,key); XformBuilder.setNodeValue(node,value); } } } } }