Monday, April 26, 2010

Well, nothing

We've got no reply yet. Should have marked it as needs review, however we didn't have that ability, like permissions or some fun stuff like that. Anyway, it's submitted for review now. Fun.

Friday, April 23, 2010

Done... or are we

We submitted our patch. We'll see if it gets accepted.
Goooooooooooooo openMRS!
Ticket 1150

Irrelevant Post 2


This bears absolutely no relevance to OpenMRS but watch it anyway.

Win.

Monday, April 19, 2010

Completely Phased Out

Soooooooo... we got an email from Darius. He was actually quite helpful, however the first part of the email was troubling. Apparently CohortReportsFromControler has been completely phased out due to a better reporting module. Well... woulda been nice to know. Anyway,
The helpful part was that if we still should complete this task, we found out some good stuff about the refactroing that we're doing. It seems that the onSubmit method we pulled out needs to be pulled out, however they just want the meat of the method pulled out. They would like it if the method onSubmit stayed in place even though it isn't called by anything outside cohortReportsFormController. That's obviously doable, so I'm not really all that worried if Darius says he wants it done that way for 100% real. Also, they want the method itself broken down more... or refacored. Bad a. I can finally do what I've been trying to do all semester.
Freakin WOOT.
The End.
For Now.
Or IS ITTTTTTTTT????!!!?!?!???!?!?!!!!!
Ya, it is.
Bye.

Monday, April 12, 2010

Success

So we got CohortReportFormController refactored successfully. See code below:

CohortReportFormController:




/**
* 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.report;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.Location;
import org.openmrs.api.ReportService;
import org.openmrs.api.context.Context;
import org.openmrs.cohort.CohortDefinition;
import org.openmrs.cohort.CohortUtil;
import org.openmrs.module.reportingcompatibility.ReportingCompatibilityConstants;
import org.openmrs.report.CohortDataSetDefinition;
import org.openmrs.report.DataSetDefinition;
import org.openmrs.report.Parameter;
import org.openmrs.report.ReportSchema;
import org.openmrs.report.ReportSchemaXml;
import org.openmrs.reporting.AbstractReportObject;
import org.openmrs.reporting.PatientSearchReportObject;
import org.openmrs.reporting.ReportObjectService;
import org.openmrs.util.OpenmrsConstants;
import org.openmrs.util.OpenmrsUtil;
import org.simpleframework.xml.Serializer;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.view.RedirectView;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;

/**
* This form lets you create or edit a report with a single CohortDataSetDefinition. You should
* not use this form to edit other types of reports.
*/
public class CohortReportFormController extends SimpleFormController implements Validator {

Log log = LogFactory.getLog(getClass());

/**
* Creates a command object and tries to fill it with data from the saved report schema with the
* id given by the 'reportId' parameter.
*
* @see org.springframework.web.servlet.mvc.AbstractFormController#formBackingObject(javax.servlet.http.HttpServletRequest)
*/
protected Object formBackingObject(HttpServletRequest request) throws Exception {
CommandObject command = new CommandObject();

if (Context.isAuthenticated() && !isFormSubmission(request)) {
// if this is an existing report, get its data
String idString = request.getParameter("reportId");
if (idString != null) {
Integer id = Integer.valueOf(idString);
ReportService rs = (ReportService) Context.getService(ReportService.class);
ReportSchemaXml schemaXml = rs.getReportSchemaXml(id);
ReportSchema schema = rs.getReportSchema(schemaXml);
CohortDataSetDefinition cohorts = null;
if (schema.getDataSetDefinitions() == null)
schema.setDataSetDefinitions(new ArrayList());
if (schema.getDataSetDefinitions().size() == 0)
schema.getDataSetDefinitions().add(new CohortDataSetDefinition());
for (DataSetDefinition d : schema.getDataSetDefinitions()) {
if (d instanceof CohortDataSetDefinition) {
if (cohorts != null)
throw new Exception(
"You may not edit a report that contains more than one Cohort Dataset Definition");
cohorts = (CohortDataSetDefinition) d;
} else {
throw new Exception(
"You may not edit a report that contains datasets besides Cohort Dataset Definition");
}
}
if (cohorts == null)
throw new Exception("You may only edit a report that has exactly one Cohort Dataset Definition");

command.setReportId(id);
command.setName(schema.getName());
command.setDescription(schema.getDescription());
command.getParameters().addAll(schema.getReportParameters());

CohortReportXMLBuilder crxml = new CohortReportXMLBuilder(); //Make new instance of CohortReportXMLBuilder called crxml
// populate command.rows, directly from XML
Document xml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
new InputSource(new StringReader(schemaXml.getXml())));
// xml looks like ......
// TODO: do this with xpath
Node temp = crxml.findChild(xml, "reportSchema"); //calls findChild method in CohortReportXMLBuilder
temp = crxml.findChild(temp, "dataSets"); //calls findChild method in CohortReportXMLBuilder
temp = crxml.findChildWithAttribute(temp, "dataSetDefinition", "class",
"org.openmrs.report.CohortDataSetDefinition"); //calls findChildWithAttribute method in CohortReportXMLBuilder

Map nameToStrategy = new LinkedHashMap();
Node strategies = crxml.findChild(temp, "strategies"); //calls findChild method in CohortReportXMLBuilder
if (strategies != null) {
NodeList nl = strategies.getChildNodes();
// each is a namestrategy
for (int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if ("entry".equals(node.getNodeName())) {
String name = crxml.findChild(node, "string").getFirstChild().getNodeValue(); //calls findChild method in CohortReportXMLBuilder
String strategy = crxml.findChild(crxml.findChild(node, "cohort"), "specification").getFirstChild() //calls findChild method in CohortReportXMLBuilder
.getNodeValue();
nameToStrategy.put(name, strategy);
}
}
}

Map nameToDescription = new LinkedHashMap();
Node descriptions = crxml.findChild(temp, "descriptions"); //calls findChild method in CohortReportXMLBuilder
if (descriptions != null) {
NodeList nl = descriptions.getChildNodes();
// each is a namedescr
for (int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if ("entry".equals(node.getNodeName())) {
String name = crxml.findChild(node, "string").getFirstChild().getNodeValue(); //calls findChild method in CohortReportXMLBuilder
String descr = crxml.findChild(node, "string", 2).getFirstChild().getNodeValue(); //calls findChild method in CohortReportXMLBuilder
nameToDescription.put(name, descr);
}
}
}

LinkedHashSet names = new LinkedHashSet();
names.addAll(nameToStrategy.keySet());
names.addAll(nameToDescription.keySet());

List rows = new ArrayList();
for (String name : names) {
String descr = nameToDescription.get(name);
String strat = nameToStrategy.get(name);
CohortReportRow row = new CohortReportRow();
row.setName(name);
row.setDescription(descr);
row.setQuery(strat);
rows.add(row);
}
command.setRows(rows);
}
}
return command;
}

/**
* @see org.springframework.web.servlet.mvc.SimpleFormController#referenceData(javax.servlet.http.HttpServletRequest)
*/
@Override
protected Map referenceData(HttpServletRequest request) throws Exception {
Map ret = new HashMap();

List> classes = new ArrayList>();
classes.add(Date.class);
classes.add(Integer.class);
classes.add(Double.class);
classes.add(Location.class);
ret.put("parameterClasses", classes);

ReportObjectService rs = (ReportObjectService) Context.getService(ReportObjectService.class);
List searches = rs.getReportObjectsByType(
OpenmrsConstants.REPORT_OBJECT_TYPE_PATIENTSEARCH);
Map map = new LinkedHashMap();
for (AbstractReportObject o : searches) {
if (o instanceof PatientSearchReportObject) {
StringBuilder searchName = new StringBuilder(o.getName());
List parameters = ((PatientSearchReportObject) o).getPatientSearch().getParameters();
if (parameters != null && !parameters.isEmpty()) {
searchName.append("|");
for (Iterator i = parameters.iterator(); i.hasNext();) {
Parameter p = i.next();
searchName.append(p.getName()).append("=${?}");
if (i.hasNext()) {
searchName.append(",");
}
}
}
map.put(searchName.toString(), o.getDescription());
} else {
map.put(o.getName(), o.getDescription());
}
}
ret.put("patientSearches", map);

ReportService rptSvc = (ReportService) Context.getService(ReportService.class);
Properties macros = rptSvc.getReportXmlMacros();
map = new LinkedHashMap();
for (Map.Entry e : macros.entrySet()) {
if (!e.getKey().toString().equals("macroPrefix") && !e.getKey().toString().equals("macroSuffix"))
map.put(e.getKey().toString(), e.getValue().toString());
}
ret.put("macros", map);
ret.put("macroPrefix", macros.get("macroPrefix"));
ret.put("macroSuffix", macros.get("macroSuffix"));

return ret;
}

/**
* Handles parameters and rows, since Spring isn't good with lists
*
* @see org.springframework.web.servlet.mvc.BaseCommandController#onBind(javax.servlet.http.HttpServletRequest,
* java.lang.Object, org.springframework.validation.BindException)
*/
@Override
protected void onBind(HttpServletRequest request, Object commandObj, BindException errors) throws Exception {
CommandObject command = (CommandObject) commandObj;

// parameters
String[] paramNames = request.getParameterValues("parameterName");
String[] paramLabels = request.getParameterValues("parameterLabel");
String[] paramClasses = request.getParameterValues("parameterClass");
List params = new ArrayList();
if (paramNames != null) {
for (int i = 0; i < paramNames.length; ++i) {
if (StringUtils.hasText(paramNames[i]) || StringUtils.hasText(paramLabels[i])
|| StringUtils.hasText(paramClasses[i])) {
try {
Class clz = null;
if (StringUtils.hasText(paramClasses[i]))
clz = Class.forName(paramClasses[i]);
Parameter p = new Parameter(paramNames[i], paramLabels[i], clz, null);
params.add(p);
}
catch (Exception ex) {
errors.rejectValue("parameters", null, "Parameter error: " + ex.toString());
}
}
}
}
command.setParameters(params);

// rows
String[] rowNames = request.getParameterValues("rowName");
String[] rowDescriptions = request.getParameterValues("rowDescription");
String[] rowQueries = request.getParameterValues("rowQuery");
List rows = new ArrayList();
if (rowNames != null) {
for (int i = 0; i < rowNames.length; ++i) {
try {
CohortReportRow row = new CohortReportRow();
row.setName(rowNames[i]);
row.setDescription(rowDescriptions[i]);
row.setQuery(rowQueries[i]);
rows.add(row);
}
catch (Exception ex) {
errors.rejectValue("rows", null, "Row error: " + ex.toString());
}
}
}
command.setRows(rows);
}

// ***** Validator methods *****

/**
* @see org.springframework.validation.Validator#supports(java.lang.Class)
*/
@SuppressWarnings("unchecked")
public boolean supports(Class clazz) {
return clazz.equals(CommandObject.class);
}

/**
* @see org.springframework.validation.Validator#validate(java.lang.Object,
* org.springframework.validation.Errors)
*/
public void validate(Object commandObj, Errors errors) {
CommandObject command = (CommandObject) commandObj;

ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "error.null");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "description", "error.null");

for (Parameter p : command.getParameters()) {
if (!StringUtils.hasText(p.getName()) || !StringUtils.hasText(p.getLabel()) || p.getClazz() == null)
errors.rejectValue("parameters", null, "All parameters must have a name, a label, and a datatype");
}

for (CohortReportRow row : command.getRows()) {
if (!StringUtils.hasText(row.getName()))
errors.rejectValue("rows", null, "Each row must have a name");

try {
String query = row.getQuery();
ReportService rptSvc = (ReportService) Context.getService(ReportService.class);
query = rptSvc.applyReportXmlMacros(query);
CohortDefinition def = CohortUtil.parse(query);
if (def == null)
throw new Exception();
}
catch (Exception ex) {
errors.rejectValue("rows", null, "Failed to parse: " + row.getQuery() + " (" + ex.getMessage() + ")");
}
}
}

// ***** Command object *****

public class CommandObject {

private Integer reportId;

private String name;

private String description;

private List parameters;

private List rows;

public CommandObject() {
parameters = new ArrayList();
rows = new ArrayList();
}

public Integer getReportId() {
return reportId;
}

public void setReportId(Integer reportId) {
this.reportId = reportId;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public List getParameters() {
return parameters;
}

public void setParameters(List parameters) {
this.parameters = parameters;
}

public List getRows() {
return rows;
}

public void setRows(List rows) {
this.rows = rows;
}
}

public class CohortReportRow {

private String name;

private String description;

private String query;

public CohortReportRow() {
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public String getQuery() {
return query;
}

public void setQuery(String query) {
this.query = query;
}
}

}


CohortReportXMLBuilder:




package org.openmrs.web.controller.report;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.openmrs.api.ReportService;
import org.openmrs.api.context.Context;
import org.openmrs.report.DataSetDefinition;
import org.openmrs.report.ReportSchema;
import org.openmrs.report.ReportSchemaXml;
import org.openmrs.util.OpenmrsUtil;
import org.openmrs.web.controller.report.CohortReportFormController.CohortReportRow;
import org.openmrs.web.controller.report.CohortReportFormController.CommandObject;
import org.simpleframework.xml.Serializer;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.view.RedirectView;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;

public class CohortReportXMLBuilder extends SimpleFormController {

@Override
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object commandObj,
BindException errors) throws Exception {
CommandObject command = (CommandObject) commandObj;

// do simpleframework serialization of everything but 'rows', and add those via handcoded xml, since
// serializing them is not reversible

ReportSchema rs = new ReportSchema();
rs.setReportSchemaId(command.getReportId());
rs.setName(command.getName());
rs.setDescription(command.getDescription());
rs.setReportParameters(command.getParameters());
rs.setDataSetDefinitions(new ArrayList());
Serializer serializer = OpenmrsUtil.getSerializer();
StringWriter sw = new StringWriter();
serializer.write(rs, sw);

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
DocumentBuilder db = dbf.newDocumentBuilder();


Document xml = db.parse(new InputSource(new StringReader(
"" + sw.toString())));
Node node = findChild(xml, "reportSchema");
node = findChild(node, "dataSets");
Element dsd = xml.createElement("dataSetDefinition");
dsd.setAttribute("name", "cohorts");
dsd.setAttribute("class", "org.openmrs.report.CohortDataSetDefinition");
node.appendChild(dsd);
Element strategies = xml.createElement("strategies");
strategies.setAttribute("class", "java.util.LinkedHashMap");
dsd.appendChild(strategies);
Element descriptions = xml.createElement("descriptions");
descriptions.setAttribute("class", "java.util.LinkedHashMap");
dsd.appendChild(descriptions);
for (CohortReportRow row : command.getRows()) {
if (StringUtils.hasText(row.getQuery())) {
Element entry = xml.createElement("entry");
strategies.appendChild(entry);
Element nameEl = xml.createElement("string");
Text val = xml.createTextNode(row.getName());
val.setNodeValue(row.getName());
nameEl.appendChild(val);
entry.appendChild(nameEl);
Element cohort = xml.createElement("cohort");
entry.appendChild(cohort);
cohort.setAttribute("class", "org.openmrs.reporting.PatientSearch");
Element strategyEl = xml.createElement("specification");
val = xml.createTextNode(row.getQuery());
val.setNodeValue(row.getQuery());
strategyEl.appendChild(val);
cohort.appendChild(strategyEl);
}
if (StringUtils.hasText(row.getDescription())) {
Element entry = xml.createElement("entry");
descriptions.appendChild(entry);
Element el = xml.createElement("string");
Text val = xml.createTextNode(row.getName());
val.setNodeValue(row.getName());
el.appendChild(val);
entry.appendChild(el);
el = xml.createElement("string");
val = xml.createTextNode(row.getDescription());
val.setNodeValue(row.getDescription());
el.appendChild(val);
entry.appendChild(el);
}
}

// now turn this into an xml string
System.setProperty("javax.xml.transform.TransformerFactory",
"com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
TransformerFactory transfac = TransformerFactory.newInstance();
Transformer trans = transfac.newTransformer();
trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.setOutputProperty(OutputKeys.METHOD, "xml");
StringWriter out = new StringWriter();
StreamResult result = new StreamResult(out);
DOMSource source = new DOMSource(xml);
trans.transform(source, result);
String schemaXml = out.toString();

ReportSchemaXml rsx = new ReportSchemaXml();
rsx.populateFromReportSchema(rs);
rsx.setXml(schemaXml);
rsx.updateXmlFromAttributes();

ReportService rptSvc = (ReportService) Context.getService(ReportService.class);
if (rsx.getReportSchemaId() != null) {
rptSvc.saveReportSchemaXml(rsx);
} else {
rptSvc.saveReportSchemaXml(rsx);
}

return new ModelAndView(new RedirectView(getSuccessView() + "?reportId=" + rsx.getReportSchemaId()));
}

Node findChild(Node parent, String name) {
NodeList list = parent.getChildNodes();
for (int i = 0; i < list.getLength(); ++i) {
Node node = list.item(i);
if (node.getNodeName().equals(name))
return node;
}
return null;
}

/**
* finds the ith occurrence of a child with the given name
*/
protected Node findChild(Node parent, String name, int index) {
int soFar = 0;
NodeList list = parent.getChildNodes();
for (int i = 0; i < list.getLength(); ++i) {
Node node = list.item(i);
if (node.getNodeName().equals(name)) {
++soFar;
if (soFar == index)
return node;
}
}
return null;
}

protected Node findChildWithAttribute(Node parent, String name, String attrName, String attrValue) {
NodeList list = parent.getChildNodes();
for (int i = 0; i < list.getLength(); ++i) {
Node node = list.item(i);
if (node.getNodeName().equals(name)) {
Node attr = node.getAttributes().getNamedItem(attrName);
if (attr != null && attr.getNodeValue().equals(attrValue))
return node;
}
}
return null;
}

}



Frustration

I'm getting more and more frustrated with this, but hopefully we're almost at an end with the problems. Today we'll be refactoring the code in yet another build. I'll post the results.

Monday, March 29, 2010

Debugging, working, having a blast

So while David looks at roller coaster rides, I'm working on getting debugging working. Wootzorz!

Refactor Success... I think.

So I refactored the code. But I'm not 100% sure if I refactored it flawlessly or not because there's an error when we compile reportingcompatibility that has nothing to do with the new code. It's a shame. This stuff is so much fun.

Friday, March 5, 2010

Progress is limited

Trying to get the cohort reports module to work is frustrating. We've got our ideas in order on how we're going to start refactoring, but we need to get OpenMRS 1.4 to work since Cohort Reports hasn't been updated to work on either 1.5 or 1.6. I've started getting really familiar with the code and as soon as we get the Cohort Reports module working on OpenMRS we'll start hard core refactoring. First we're going to pull out the builder utility, then go to town commenting some other person's code who wasn't terribly fond of commenting. Like as in there are like 2 comment lines for 606 lines of code. Fun stuff. Will update later.

Wednesday, February 17, 2010

Progress report for today...

So in over and hour I sat in the lab and had to reinstall my virtual machine and reimport openMRS into eclipse. It was fun. Then David and I managed to locate the module and the class to be worked on. I've got everything in place now to start working through the code and refactoring the heck out of it. That'll be started on Friday. Hopefully we can figure out what's going on in the code even though there are virtually NO comments, which incidentally is part of the refactoring we are to be doing. Adding loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooots and looooooooooooooooooooooooooooooooooooooooooooooooots of comments. Woo. Fun stuff. Now off we go to the first star to the right and straight on 'till morning.

The End.

Wednesday, February 3, 2010

This is random and bears no relevance...


Watch this crap.
The End.

OpenMRS

So I'm working with David on ticket 1150 on the OpenMRS project. I expect it will be more than a blast and we shall have the fun of many lifetimes as we make progress on it. Refactoring is so much fun.
The end
for now...