/**
* 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.controller.migration;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.Drug;
import org.openmrs.DrugOrder;
import org.openmrs.Location;
import org.openmrs.Order;
import org.openmrs.OrderType;
import org.openmrs.Patient;
import org.openmrs.PatientIdentifier;
import org.openmrs.PatientIdentifierType;
import org.openmrs.User;
import org.openmrs.api.LocationService;
import org.openmrs.api.UserService;
import org.openmrs.api.context.Context;
import org.openmrs.hl7.HL7InQueue;
import org.openmrs.hl7.HL7Service;
import org.openmrs.hl7.HL7Source;
import org.openmrs.migration.MigrationHelper;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.view.RedirectView;
public class MigrationController implements Controller {
protected final Log log = LogFactory.getLog(getClass());
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
Map<String, Object> myModel = new HashMap<String, Object>();
if (Context.isAuthenticated()) {
String message = request.getParameter("message");
if (message == null || message.length() == 0) {
message = "Paste some xml";
}
LocationService ls = Context.getLocationService();
List<Location> locations = ls.getAllLocations();
UserService us = Context.getUserService();
List<User> users = us.getAllUsers();
myModel.put("message", message);
myModel.put("locations", locations);
myModel.put("users", users);
}
return new ModelAndView("/migration/migration", "model", myModel);
}
public ModelAndView uploadUsers(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException, ParserConfigurationException, ParseException {
String xml = request.getParameter("user_xml");
log.debug("xml to upload = " + xml);
int numAdded = MigrationHelper.importUsers(MigrationHelper.parseXml(xml));
return new ModelAndView(new RedirectView("migration.form?message="
+ URLEncoder.encode("Added " + numAdded + " users", "UTF-8")));
}
public ModelAndView uploadLocations(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException, ParserConfigurationException {
String xml = request.getParameter("location_xml");
log.debug("xml to upload = " + xml);
int numAdded = MigrationHelper.importLocations(MigrationHelper.parseXml(xml));
return new ModelAndView(new RedirectView("migration.form?message="
+ URLEncoder.encode("Uploaded " + numAdded + " locations", "UTF-8")));
}
public ModelAndView runHl7(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
List<String> messages = new ArrayList<String>();
String filename = request.getParameter("filename");
if (filename != null && filename.length() > 0) {
try {
BufferedReader r = new BufferedReader(new FileReader(filename));
StringBuilder thisMessage = new StringBuilder();
while (true) {
String line = r.readLine();
if (line == null || line.startsWith("MSH")) {
if (thisMessage.length() != 0) {
messages.add(thisMessage.toString());
log.debug("read message : " + thisMessage);
if (messages.size() % 100 == 0) {
log.debug("read " + messages.size() + " messages so far");
}
thisMessage = new StringBuilder();
}
}
if (line == null) {
break;
}
thisMessage.append(line).append('\r');
}
}
catch (Exception ex) {
log.error("Failed to read hl7 input file " + filename, ex);
throw new RuntimeException(ex);
}
} else {
String hl7 = request.getParameter("hl7");
hl7 = hl7.replaceAll("\\n", "");
for (int index = hl7.indexOf("MSH"); index >= 0; index = hl7.indexOf("MSH", index + 1)) {
int endIndex = hl7.indexOf("MSH", index + 1);
String oneMessage = endIndex <= 0 ? hl7.substring(index) : hl7.substring(index, endIndex);
messages.add(oneMessage);
// log.debug("has slashR: " + (oneMessage.indexOf("\r") > 0) + " , has slashN: " + (oneMessage.indexOf("\n") > 0));
}
}
// log.debug("About to handle " + messages.size() + " messages");
// split into messages
for (String oneMessage : messages) {
log.debug("oneMessage: " + oneMessage);
// Confusing terminology: an HL7InQueue is just one entry in the queue
HL7InQueue hl7InQueue = new HL7InQueue();
hl7InQueue.setHL7Data(oneMessage);
HL7Service hs = Context.getHL7Service();
if (hs.getAllHL7Sources().isEmpty()) {
HL7Source hl7Source = new HL7Source();
hl7Source.setName("MigrationTestTool");
hl7Source.setDescription("Testing migrating data, from MigrationController.");
hs.saveHL7Source(hl7Source);
}
hl7InQueue.setHL7Source(Context.getHL7Service().getHL7Source(1));
log.debug("hl7InQueue.hl7Data: " + hl7InQueue.getHL7Data());
Context.getHL7Service().saveHL7InQueue(hl7InQueue);
}
return new ModelAndView(new RedirectView("migration.form"));
}
// Hardcoded for PIH v1-v2 migration. Sorry about that.
public ModelAndView uploadRegimens(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException, ParseException {
String csv = request.getParameter("regimen_csv");
int numAdded = importRegimens(csv);
return new ModelAndView(new RedirectView("migration.form?message="
+ URLEncoder.encode("Uploaded " + numAdded + " regimens", "UTF-8")));
}
/**
* TODO: DOCUMENT THIS
*/
public ModelAndView uploadMigrationFile(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException, ParseException {
String filename = request.getParameter("filename");
if (filename == null || filename.length() == 0)
throw new IllegalArgumentException("Must specify a 'filename' parameter");
boolean autoCreateUsers = false;
boolean autoAddRole = false;
try {
autoCreateUsers = request.getParameter("auto_create_users").toLowerCase().startsWith("t");
}
catch (Exception ex) {}
try {
autoAddRole = request.getParameter("add_role_when_creating_users").toLowerCase().startsWith("t");
}
catch (Exception ex) {}
List<String> relationships = new ArrayList<String>();
List<String> programWorkflow = new ArrayList<String>();
BufferedReader r = new BufferedReader(new FileReader(filename));
while (true) {
String s = r.readLine();
if (s == null)
break;
s = s.trim();
if (s.length() == 0)
continue;
if (s.startsWith("RELATIONSHIP:")) {
relationships.add(s);
} else if (s.startsWith("ENROLLMENT:") || s.startsWith("STATUS:")) {
programWorkflow.add(s);
} else {
throw new IllegalArgumentException("Don't know how to handle '" + s + "'");
}
}
int numRels = MigrationHelper.importRelationships(relationships, autoCreateUsers, autoAddRole);
String message = "";
message += "Uploaded " + numRels + " relationships<br/>";
int numProgram = MigrationHelper.importProgramsAndStatuses(programWorkflow);
message += "Uploaded " + numProgram + " programs and statuses<br/>";
return new ModelAndView(new RedirectView("migration.form?message=" + URLEncoder.encode(message, "UTF-8")));
}
// takes something like "^glokawera@pih.org" and returns a user with that username (after the ^)
private User userHelper(String username) {
if (username == null)
return null;
int ind = username.indexOf('^');
if (ind >= 0)
username = username.substring(ind + 1);
return Context.getUserService().getUserByUsername(username);
}
/**
* Takes CSV like: patientId,drugName,formulationName,startDate,autoExpireDate,discontinuedDate,
* discontinuedReason,doseStrength,doseUnit,dosesPerDay,daysPerWeek,prn
*
* @return The number of regimens added
*/
public int importRegimens(String csv) throws IOException, ParseException {
PatientIdentifierType pihIdentifierType = Context.getPatientService().getPatientIdentifierTypeByName("HIVEMR-V1");
OrderType orderType = Context.getOrderService().getOrderType(1);
if (!orderType.getName().equals("Drug Order")) {
throw new RuntimeException("ERROR! ASSUMED THAT ORDER TYPE 1 IS DRUG ORDER, BUT IT'S NOT");
}
Map<Integer, List<Order>> patientRegimens = new HashMap<Integer, List<Order>>();
int numAdded = 0;
BufferedReader r = new BufferedReader(new StringReader(csv));
for (String s = r.readLine(); s != null; s = r.readLine()) {
String[] st = s.split(",");
Integer patientId = Integer.valueOf(st[0]);
//String drugName = st[1]; // ignored for now
String formulationName = st[2];
Date startDate = parseDate(st[3]);
Date autoExpireDate = parseDate(st[4]);
Date discontinuedDate = parseDate(st[5]);
String discontinuedReason = st[6];
if (discontinuedReason.trim().length() == 0)
discontinuedReason = null;
Double doseStrength = Double.parseDouble(st[7]);
String doseUnit = st[8];
if (doseUnit.trim().length() == 0)
doseUnit = null;
Integer dosesPerDay = Integer.valueOf(st[9]);
Integer daysPerWeek = Integer.valueOf(st[10]);
Boolean prn = Boolean.valueOf(st[11]);
String creator = st[12];
Date dateCreated = parseDate(st[13]);
String discontinuedBy = st.length > 14 ? st[14] : null;
if (dosesPerDay == null || dosesPerDay == 0) {
throw new IllegalArgumentException("Doses per day must be a positive integer");
}
Drug drug = Context.getConceptService().getDrug(formulationName);
if (drug == null)
throw new IllegalArgumentException("Can't find drug '" + formulationName + "'");
DrugOrder reg = new DrugOrder();
reg.setDrug(drug);
reg.setConcept(drug.getConcept());
reg.setStartDate(startDate);
reg.setAutoExpireDate(autoExpireDate);
reg.setDiscontinued(discontinuedDate != null);
reg.setDiscontinuedDate(discontinuedDate);
//reg.setDiscontinuedReason(discontinuedReason);
reg.setDose(doseStrength);
reg.setEquivalentDailyDose(doseStrength);
reg.setUnits(doseUnit);
reg.setFrequency(dosesPerDay + "/day x " + daysPerWeek + " days/week");
reg.setPrn(prn);
reg.setComplex(false);
reg.setOrderType(orderType);
reg.setCreator(userHelper(creator));
reg.setDateCreated(dateCreated);
reg.setDiscontinuedBy(userHelper(discontinuedBy));
List<Order> pat = patientRegimens.get(patientId);
if (pat == null) {
pat = new ArrayList<Order>();
patientRegimens.put(patientId, pat);
}
pat.add(reg);
}
for (Map.Entry<Integer, List<Order>> e : patientRegimens.entrySet()) {
List<PatientIdentifier> pil = Context.getPatientService().getPatientIdentifiers(e.getKey().toString(),
Collections.singletonList(pihIdentifierType), null, null, null);
if (pil.size() != 1) {
throw new RuntimeException("Found " + pil.size() + " PatientIdentifiers for " + pihIdentifierType + " of "
+ e.getKey());
}
Patient p = pil.get(0).getPatient();
List<Order> list = e.getValue();
Context.getOrderService().createOrdersAndEncounter(p, list);
numAdded += list.size();
}
return numAdded;
}
static DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static Date parseDate(String s) throws ParseException {
if (s == null || s.length() == 0) {
return null;
} else {
if (s.length() == 10) {
s += " 00:00:00";
}
return df.parse(s);
}
}
}