package org.akaza.openclinica.web.pform; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.net.FileNameMap; import java.net.URLConnection; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.TimeZone; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource; import javax.ws.rs.GET; import javax.ws.rs.HEAD; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.StreamingOutput; 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 javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathFactory; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.core.util.StatusPrinter; import org.akaza.openclinica.bean.admin.CRFBean; import org.akaza.openclinica.bean.core.Status; import org.akaza.openclinica.bean.managestudy.StudyBean; import org.akaza.openclinica.bean.managestudy.StudyEventBean; import org.akaza.openclinica.bean.managestudy.StudySubjectBean; import org.akaza.openclinica.bean.service.StudyParameterValueBean; import org.akaza.openclinica.bean.submit.CRFVersionBean; import org.akaza.openclinica.control.SpringServletAccess; import org.akaza.openclinica.controller.openrosa.OpenRosaSubmissionController; import org.akaza.openclinica.dao.admin.CRFDAO; import org.akaza.openclinica.dao.core.CoreResources; import org.akaza.openclinica.dao.hibernate.CrfVersionMediaDao; import org.akaza.openclinica.dao.hibernate.RuleActionPropertyDao; import org.akaza.openclinica.dao.hibernate.SCDItemMetadataDao; import org.akaza.openclinica.dao.hibernate.StudyDao; import org.akaza.openclinica.dao.hibernate.UserAccountDao; import org.akaza.openclinica.dao.managestudy.StudyDAO; import org.akaza.openclinica.dao.managestudy.StudyEventDAO; import org.akaza.openclinica.dao.managestudy.StudySubjectDAO; import org.akaza.openclinica.dao.service.StudyParameterValueDAO; import org.akaza.openclinica.dao.submit.CRFVersionDAO; import org.akaza.openclinica.domain.datamap.CrfVersionMedia; import org.akaza.openclinica.domain.datamap.Study; import org.akaza.openclinica.domain.user.UserAccount; import org.akaza.openclinica.service.pmanage.ParticipantPortalRegistrar; import org.akaza.openclinica.web.pform.formlist.XForm; import org.akaza.openclinica.web.pform.formlist.XFormList; import org.akaza.openclinica.web.pform.manifest.Manifest; import org.akaza.openclinica.web.pform.manifest.MediaFile; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.exception.ExceptionUtils; import org.exolab.castor.mapping.Mapping; import org.exolab.castor.xml.Marshaller; import org.exolab.castor.xml.XMLContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestHeader; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NodeList; @Path("/openrosa") @Component public class OpenRosaServices { @Autowired UserAccountDao userAccountDao; @Autowired StudyDao studyDao; public static final String INPUT_USER_SOURCE = "userSource"; public static final String INPUT_FIRST_NAME = "Participant"; public static final String INPUT_LAST_NAME = "User"; public static final String INPUT_EMAIL = "email"; public static final String INPUT_INSTITUTION = "PFORM"; public static final String INPUT_STUDY = "activeStudy"; public static final String INPUT_ROLE = "role"; public static final String INPUT_TYPE = "type"; public static final String INPUT_DISPLAY_PWD = "displayPwd"; public static final String INPUT_RUN_WEBSERVICES = "runWebServices"; public static final String USER_ACCOUNT_NOTIFICATION = "notifyPassword"; public static final String FORM_CONTEXT = "ecid"; private static final Logger LOGGER = LoggerFactory.getLogger(OpenRosaServices.class); private DataSource dataSource; private CoreResources coreResources; private OpenRosaSubmissionController openRosaSubmissionController; private RuleActionPropertyDao ruleActionPropertyDao; private SCDItemMetadataDao scdItemMetadataDao; ParticipantPortalRegistrar participantPortalRegistrar; protected final Logger logger = LoggerFactory.getLogger(getClass().getName()); StudyDAO sdao; StudySubjectDAO studySubjectDao; /** * @api {get} /rest2/openrosa/:studyOID/formList Get Form List * @apiName getFormList * @apiPermission admin * @apiVersion 3.8.0 * @apiParam {String} studyOID Study Oid. * @apiGroup Form * @apiDescription Retrieves a listing of the available OpenClinica forms. * @apiParamExample {json} Request-Example: * { * "studyOid": "S_SAMPLTE", * } * @apiSuccessExample {xml} Success-Response: * HTTP/1.1 200 OK * { * <xforms xmlns="http://openrosa.org/xforms/xformsList"> * <xform> * <formID>F_FIRSTFORM_1</formID> * <name>First Form</name> * <majorMinorVersion>1</majorMinorVersion> * <version>1</version> * <hash>8678370cd92814d4e3216d58d821403f</hash> * <downloadUrl>http://oc1.openclinica.com/OpenClinica-web/rest2/openrosa/S_SAMPLTE/formXml? * formId=F_FIRSTFORM_1</downloadUrl> * </xform> * <xform> * <formID>F_SECONDFORM_1</formID> * <name>Second Form</name> * <majorMinorVersion>1</majorMinorVersion> * <version>1</version> * <hash>7ee60d1c6516b730bbe9bdbd7cad942f</hash> * <downloadUrl>http://oc1.openclinica.com/OpenClinica-web/rest2/openrosa/S_SAMPLTE/formXml? * formId=F_SECONDFORM_1</downloadUrl> * </xform> * </xforms> */ @GET @Path("/{studyOID}/formList") @Produces(MediaType.TEXT_XML) public String getFormList(@Context HttpServletRequest request, @Context HttpServletResponse response, @PathParam("studyOID") String studyOID, @QueryParam("formID") String crfOID, @RequestHeader("Authorization") String authorization, @Context ServletContext context) throws Exception { LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); // print logback's internal status StatusPrinter.print(lc); logger.error("*********************************Test log"); if (!mayProceedPreview(studyOID)) return null; StudyDAO sdao = new StudyDAO(getDataSource()); StudyBean study = sdao.findByOid(studyOID); CRFDAO cdao = new CRFDAO(getDataSource()); Collection<CRFBean> crfs = cdao.findAll(); CRFVersionDAO cVersionDao = new CRFVersionDAO(getDataSource()); Collection<CRFVersionBean> crfVersions = cVersionDao.findAll(); CrfVersionMediaDao mediaDao = (CrfVersionMediaDao) SpringServletAccess.getApplicationContext(context).getBean("crfVersionMediaDao"); try { XFormList formList = new XFormList(); for (CRFBean crf : crfs) { for (CRFVersionBean version : crfVersions) { if (version.getCrfId() == crf.getId()) { XForm form = new XForm(crf, version); // TODO: Need to generate hash based on contents of // XForm. Will be done in a later story. // TODO: For now all XForms get a date based hash to // trick Enketo into always downloading // TODO: them. if (version.getXformName() != null){ form.setHash(DigestUtils.md5Hex(version.getXform())); }else { Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); form.setHash(DigestUtils.md5Hex(String.valueOf(cal.getTimeInMillis()))); } String urlBase = getCoreResources().getDataInfo().getProperty("sysURL").split("/MainMenu")[0]; form.setDownloadURL(urlBase + "/rest2/openrosa/" + studyOID + "/formXml?formId=" + version.getOid()); //TODO: Change test here to see if user list should be appended. Hardcode to always add for now. List<CrfVersionMedia> mediaList = mediaDao.findByCrfVersionId(version.getId()); //if (mediaList != null && mediaList.size() > 0) { if (true) { form.setManifestURL(urlBase + "/rest2/openrosa/" + studyOID + "/manifest?formId=" + version.getOid()); } formList.add(form); } } } // Create the XML formList using a Castor mapping file. XMLContext xmlContext = new XMLContext(); Mapping mapping = xmlContext.createMapping(); mapping.loadMapping(getCoreResources().getURL("openRosaFormListMapping.xml")); xmlContext.addMapping(mapping); Marshaller marshaller = xmlContext.createMarshaller(); StringWriter writer = new StringWriter(); marshaller.setWriter(writer); marshaller.marshal(formList); // Set response headers Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); Date currentDate = new Date(); cal.setTime(currentDate); SimpleDateFormat format = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss zz"); format.setCalendar(cal); response.setHeader("Content-Type", "text/xml; charset=UTF-8"); response.setHeader("Date", format.format(currentDate)); response.setHeader("X-OpenRosa-Version", "1.0"); return writer.toString(); } catch (Exception e) { LOGGER.error(e.getMessage()); LOGGER.error(ExceptionUtils.getStackTrace(e)); return "<Error>" + e.getMessage() + "</Error>"; } } /** * @api {get} /rest2/openrosa/:studyOID/manifest Get Form Manifest * @apiName getManifest * @apiPermission admin * @apiVersion 3.8.0 * @apiParam {String} studyOID Study Oid. * @apiGroup Form * @apiDescription Gets additional information on a particular Form, including links to associated media. */ @GET @Path("/{studyOID}/manifest") @Produces(MediaType.TEXT_XML) public String getManifest(@Context HttpServletRequest request, @Context HttpServletResponse response, @PathParam("studyOID") String studyOID, @QueryParam("formId") String crfOID, @RequestHeader("Authorization") String authorization, @Context ServletContext context) throws Exception { if (!mayProceedPreview(studyOID)) return null; CRFVersionDAO cVersionDao = new CRFVersionDAO(getDataSource()); CrfVersionMediaDao mediaDao = (CrfVersionMediaDao) SpringServletAccess.getApplicationContext(context).getBean("crfVersionMediaDao"); CRFVersionBean crfVersion = cVersionDao.findByOid(crfOID); List<MediaFile> mediaFiles = new ArrayList<MediaFile>(); Manifest manifest = new Manifest(); List<CrfVersionMedia> mediaList = mediaDao.findByCrfVersionId(crfVersion.getId()); String urlBase = getCoreResources().getDataInfo().getProperty("sysURL").split("/MainMenu")[0]; if (mediaList != null && mediaList.size() > 0) { for (CrfVersionMedia media : mediaList) { MediaFile mediaFile = new MediaFile(); mediaFile.setFilename(media.getName()); File image = new File(media.getPath() + media.getName()); mediaFile.setHash(DigestUtils.md5Hex(media.getName()) + Double.toString(image.length())); mediaFile.setDownloadUrl(urlBase + "/rest2/openrosa/" + studyOID + "/downloadMedia?crfVersionMediaId=" + media.getCrfVersionMediaId()); manifest.add(mediaFile); } } //Add user list MediaFile userList = new MediaFile(); Study study = studyDao.findByOcOID(studyOID); String userXml = getUserXml(study.getStudyId()); userList.setFilename("users.xml"); userList.setHash((DigestUtils.md5Hex(userXml))); userList.setDownloadUrl(urlBase + "/rest2/openrosa/" + studyOID + "/downloadUsers"); manifest.add(userList); try { // Create the XML manifest using a Castor mapping file. XMLContext xmlContext = new XMLContext(); Mapping mapping = xmlContext.createMapping(); mapping.loadMapping(getCoreResources().getURL("openRosaManifestMapping.xml")); xmlContext.addMapping(mapping); Marshaller marshaller = xmlContext.createMarshaller(); StringWriter writer = new StringWriter(); marshaller.setWriter(writer); marshaller.marshal(manifest); // Set response headers Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); Date currentDate = new Date(); cal.setTime(currentDate); SimpleDateFormat format = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss zz"); format.setCalendar(cal); response.setHeader("Content-Type", "text/xml; charset=UTF-8"); response.setHeader("Date", format.format(currentDate)); response.setHeader("X-OpenRosa-Version", "1.0"); return writer.toString(); } catch (Exception e) { LOGGER.error(e.getMessage()); LOGGER.error(ExceptionUtils.getStackTrace(e)); return "<Error>" + e.getMessage() + "</Error>"; } } /** * @api {get} /rest2/openrosa/:studyOID/formXml Get Form XML * @apiName getFormXml * @apiPermission admin * @apiVersion 3.8.0 * @apiParam {String} studyOID Study Oid. * @apiGroup Form * @apiDescription Downloads the contents of a form */ @GET @Path("/{studyOID}/formXml") @Produces(MediaType.APPLICATION_XML) public String getFormXml(@Context HttpServletRequest request, @Context HttpServletResponse response, @PathParam("studyOID") String studyOID, @QueryParam("formID") String crfOID, @RequestHeader("Authorization") String authorization) throws Exception { if (!mayProceedPreview(studyOID)) return null; String xform = null; // get parameters String formId = request.getParameter("formId"); if (formId == null) { return "<error>formID is null :(</error>"; } try { CRFVersionDAO versionDAO = new CRFVersionDAO(dataSource); CRFVersionBean crfVersion = versionDAO.findByOid(formId); if (crfVersion.getXform() != null && !crfVersion.getXform().equals("")){ xform = updateRepeatGroupsWithOrdinal(crfVersion.getXform()); } else { OpenRosaXmlGenerator generator = new OpenRosaXmlGenerator(coreResources, dataSource, ruleActionPropertyDao); xform = generator.buildForm(formId); } } catch (Exception e) { System.out.println(e.getMessage()); System.out.println(ExceptionUtils.getStackTrace(e)); LOGGER.error(e.getMessage()); LOGGER.error(ExceptionUtils.getStackTrace(e)); return "<error>" + e.getMessage() + "</error>"; } response.setHeader("Content-Type", "text/xml; charset=UTF-8"); response.setHeader("Content-Disposition", "attachment; filename=\"" + crfOID + ".xml" + "\";"); response.setContentType("text/xml; charset=utf-8"); return xform; } /** * @api {get} /rest2/openrosa/:studyOID/downloadMedia Download media * @apiName getMediaFile * @apiPermission admin * @apiVersion 3.8.0 * @apiParam {String} studyOID Study Oid. * @apiGroup Form * @apiDescription Downloads media associated with a form, including images and video. */ @GET @Path("/{studyOID}/downloadMedia") public Response getMediaFile(@Context HttpServletRequest request, @Context HttpServletResponse response, @PathParam("studyOID") String studyOID, @QueryParam("crfVersionMediaId") String crfVersionMediaId, @RequestHeader("Authorization") String authorization, @Context ServletContext context) throws Exception { if (!mayProceedPreview(studyOID)) return null; CrfVersionMediaDao mediaDao = (CrfVersionMediaDao) SpringServletAccess.getApplicationContext(context).getBean("crfVersionMediaDao"); CrfVersionMedia media = mediaDao.findById(Integer.valueOf(crfVersionMediaId)); File image = new File(media.getPath() + media.getName()); FileInputStream fis = new FileInputStream(image); StreamingOutput stream = new MediaStreamingOutput(fis); ResponseBuilder builder = Response.ok(stream); // Set content type, if known FileNameMap fileNameMap = URLConnection.getFileNameMap(); String type = fileNameMap.getContentTypeFor(media.getPath() + media.getName()); if (type != null && !type.isEmpty()) builder = builder.header("Content-Type", type); return builder.build(); } /** * @api {get} /rest2/openrosa/:studyOID/downloadUsers Download users * @apiName getUserList * @apiPermission admin * @apiVersion 3.12.0 * @apiParam {String} studyOID Study Oid. * @apiGroup Form * @apiDescription Downloads list of users for use with queries. */ @GET @Path("/{studyOID}/downloadUsers") public Response getUserList(@Context HttpServletRequest request, @Context HttpServletResponse response, @PathParam("studyOID") String studyOID, @RequestHeader("Authorization") String authorization, @Context ServletContext context) throws Exception { if (!mayProceedPreview(studyOID)) return null; Study study = studyDao.findByOcOID(studyOID); String userXml = getUserXml(study.getStudyId()); ResponseBuilder builder = Response.ok(userXml); builder = builder.header("Content-Type", "text/xml"); return builder.build(); } /** * @api {post} /rest2/openrosa/:studyOid/submission Submit form data * @apiName doSubmission * @apiPermission admin * @apiVersion 3.8.0 * @apiParam {String} studyOid Study Oid. * @apiParam {String} ecid Key that will be used to look up subject context information while processing submission. * @apiGroup Form * @apiDescription Submits the data from a completed form. */ @POST @Path("/{studyOID}/submission") @Produces(MediaType.APPLICATION_XML) public Response doSubmission(@Context HttpServletRequest request, @Context HttpServletResponse response, @Context ServletContext servletContext, @PathParam("studyOID") String studyOID, @QueryParam(FORM_CONTEXT) String context) { Response.ResponseBuilder builder = Response.noContent(); ResponseEntity<String> responseEntity = openRosaSubmissionController.doSubmission(request, response, studyOID, context); if (responseEntity == null) { LOGGER.debug("Null response from OpenRosaSubmissionController."); return builder.status(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR).build(); } else if (responseEntity.getStatusCode().equals(org.springframework.http.HttpStatus.CREATED)) { LOGGER.debug("Successful OpenRosa submission"); builder.entity("<OpenRosaResponse xmlns=\"http://openrosa.org/http/response\">" + "<message>success</message>" + "</OpenRosaResponse>"); return builder.status(javax.ws.rs.core.Response.Status.CREATED).build(); } else if (responseEntity.getStatusCode().equals(org.springframework.http.HttpStatus.NOT_ACCEPTABLE)) { LOGGER.debug("Failed OpenRosa submission"); return builder.status(javax.ws.rs.core.Response.Status.NOT_ACCEPTABLE).build(); } else { LOGGER.debug("Failed OpenRosa submission with unhandled error"); return builder.status(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR).build(); } } @POST @Path("/{studyOID}/fieldsubmission") @Produces(MediaType.APPLICATION_XML) public Response doFieldSubmission(@Context HttpServletRequest request, @Context HttpServletResponse response, @Context ServletContext servletContext, @PathParam("studyOID") String studyOID, @QueryParam(FORM_CONTEXT) String context) { Response.ResponseBuilder builder = Response.noContent(); ResponseEntity<String> responseEntity = openRosaSubmissionController.doFieldSubmission(request, response, studyOID, context); if (responseEntity == null) { LOGGER.debug("Null response from OpenRosaSubmissionController."); return builder.status(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR).build(); } else if (responseEntity.getStatusCode().equals(org.springframework.http.HttpStatus.CREATED)) { LOGGER.debug("Successful OpenRosa submission"); builder.entity("<OpenRosaResponse xmlns=\"http://openrosa.org/http/response\">" + "<message>success</message>" + "</OpenRosaResponse>"); return builder.status(javax.ws.rs.core.Response.Status.CREATED).build(); } else if (responseEntity.getStatusCode().equals(org.springframework.http.HttpStatus.NOT_ACCEPTABLE)) { LOGGER.debug("Failed OpenRosa submission"); return builder.status(javax.ws.rs.core.Response.Status.NOT_ACCEPTABLE).build(); } else { LOGGER.debug("Failed OpenRosa submission with unhandled error"); return builder.status(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR).build(); } } /** * @api {head} /rest2/openrosa/:studyOid/submission Submit form data * @apiName doSubmissionHead * @apiPermission admin * @apiVersion 3.11.0 * @apiParam {String} studyOid Study Oid. * @apiGroup Form * @apiDescription Returns the HTTP headers for a form submission request. */ @HEAD @Path("/{studyOID}/submission") @Produces(MediaType.APPLICATION_XML) public Response doSubmissionHead(@PathParam("studyOID") String studyOID) { Response.ResponseBuilder builder = Response.noContent(); String maxSubmissionSize = CoreResources.getField("pformMaxSubmissionSize"); int maxSubmissionSizeInt = -1; try { maxSubmissionSizeInt = Integer.valueOf(maxSubmissionSize); } catch (Exception e) { logger.error("Unable to parse pformMaxSubmissionSize as an integer."); } // Build response headers Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); Date currentDate = new Date(); cal.setTime(currentDate); SimpleDateFormat format = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss zz"); format.setCalendar(cal); builder = builder.header("Date", format.format(currentDate)); builder = builder.header("X-OpenRosa-Version", "1.0"); if (maxSubmissionSizeInt < 1) { logger.error("pformMaxSubmissionSize does not contain an integer value greater than 0."); return builder.status(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR).build(); } else { builder = builder.header("X-OpenRosa-Accept-Content-Length", maxSubmissionSizeInt); return builder.status(javax.ws.rs.core.Response.Status.ACCEPTED).build(); } } @GET @Path("/{studyOID}/getSchedule") @Produces(MediaType.APPLICATION_XML) public String getSchedule(@Context HttpServletRequest request, @Context HttpServletResponse response, @Context ServletContext context, @PathParam("studyOID") String studyOID, @RequestHeader("Authorization") String authorization) throws Exception { String ssoid = request.getParameter("studySubjectOID"); StudySubjectDAO ssdao = new StudySubjectDAO<String, ArrayList>(dataSource); StudySubjectBean ssBean = ssdao.findByOid(ssoid); if (!mayProceedSubmission(studyOID, ssBean)) return null; HashMap<String, String> urlCache = (HashMap<String, String>) context.getAttribute("pformURLCache"); context.getAttribute("subjectContextCache"); if (ssoid == null) { return "<error>studySubjectOID is null :(</error>"; } try { // Need to retrieve crf's for next event StudyEventDAO eventDAO = new StudyEventDAO(getDataSource()); StudyEventBean nextEvent = (StudyEventBean) eventDAO.getNextScheduledEvent(ssoid); CRFVersionDAO versionDAO = new CRFVersionDAO(getDataSource()); ArrayList<CRFVersionBean> crfs = versionDAO.findDefCRFVersionsByStudyEvent(nextEvent.getStudyEventDefinitionId()); PFormCache cache = PFormCache.getInstance(context); for (CRFVersionBean crfVersion : crfs) { String enketoURL = cache.getPFormURL(studyOID, crfVersion.getOid()); String contextHash = cache.putSubjectContext(ssoid, String.valueOf(nextEvent.getStudyEventDefinitionId()), String.valueOf(nextEvent.getSampleOrdinal()), crfVersion.getOid()); } } catch (Exception e) { LOGGER.debug(e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); return "<error>" + e.getMessage() + "</error>"; } response.setHeader("Content-Type", "text/xml; charset=UTF-8"); response.setHeader("Content-Disposition", "attachment; filename=\"schedule.xml\";"); response.setContentType("text/xml; charset=utf-8"); return "<result>success</result>"; } public DataSource getDataSource() { return dataSource; } public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public CoreResources getCoreResources() { return coreResources; } public void setCoreResources(CoreResources coreResources) { this.coreResources = coreResources; } public OpenRosaSubmissionController getOpenRosaSubmissionController() { return openRosaSubmissionController; } public void setOpenRosaSubmissionController(OpenRosaSubmissionController openRosaSubmissionController) { this.openRosaSubmissionController = openRosaSubmissionController; } public RuleActionPropertyDao getRuleActionPropertyDao() { return ruleActionPropertyDao; } public void setRuleActionPropertyDao(RuleActionPropertyDao ruleActionPropertyDao) { this.ruleActionPropertyDao = ruleActionPropertyDao; } public SCDItemMetadataDao getScdItemMetadataDao() { return scdItemMetadataDao; } public void setScdItemMetadataDao(SCDItemMetadataDao scdItemMetadataDao) { this.scdItemMetadataDao = scdItemMetadataDao; } private StudyBean getStudy(String oid) { sdao = new StudyDAO(dataSource); StudyBean studyBean = (StudyBean) sdao.findByOid(oid); return studyBean; } private StudyBean getParentStudy(String studyOid) { StudyBean study = getStudy(studyOid); if (study.getParentStudyId() == 0) { return study; } else { StudyBean parentStudy = (StudyBean) sdao.findByPK(study.getParentStudyId()); return parentStudy; } } private String updateRepeatGroupsWithOrdinal(String xform) throws Exception { NamedNodeMap attribs = fetchXformAttributes(xform); InputStream is = new ByteArrayInputStream(xform.getBytes()); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(false); Document doc = factory.newDocumentBuilder().parse(is); XPathFactory xPathfactory = XPathFactory.newInstance(); XPath xpath = xPathfactory.newXPath(); XPathExpression expr = null; expr = xpath.compile("/html/body/group/repeat"); NodeList repeatNodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET); for (int k = 0; k < repeatNodes.getLength(); k++) { Element groupElement = ((Element) repeatNodes.item(k).getParentNode()); String groupRef = groupElement.getAttribute("ref"); expr = xpath.compile("/html/head/model/instance[1]" + groupRef); Element group = (Element) expr.evaluate(doc, XPathConstants.NODE); Element ordinal = doc.createElement("OC.REPEAT_ORDINAL"); group.appendChild(ordinal); } TransformerFactory transformFactory = TransformerFactory.newInstance(); Transformer transformer = transformFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); transformer.setOutputProperty(OutputKeys.INDENT, "no"); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); StringWriter writer = new StringWriter(); StreamResult result = new StreamResult(writer); DOMSource source = new DOMSource(doc); transformer.transform(source, result); String modifiedXform = writer.toString(); modifiedXform = applyXformAttributes(modifiedXform, attribs); System.out.println("Finalized xform source: " + modifiedXform); return modifiedXform; } private String applyXformAttributes(String xform, NamedNodeMap attribs) throws Exception { String defaultNamespace = null; for (int i=0;i<attribs.getLength();i++) { Attr attrib = (Attr) attribs.item(i); if (attrib.getName().equals("xmlns")) defaultNamespace = attrib.getValue(); } String xformArray[] = xform.split("html",2); String modifiedXform = xformArray[0] + "html xmlns=\"" + defaultNamespace + "\" " + xformArray[1]; return modifiedXform; } private NamedNodeMap fetchXformAttributes(String xform) throws Exception { InputStream is = new ByteArrayInputStream(xform.getBytes()); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); Document doc = factory.newDocumentBuilder().parse(is); Element html = doc.getDocumentElement(); NamedNodeMap attribs = html.getAttributes(); return attribs; } private String getUserXml(Integer studyId) throws Exception { DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); Document doc = docBuilder.newDocument(); Element root = doc.createElement("root"); doc.appendChild(root); List<UserAccount> users = userAccountDao.findNonRootNonParticipateUsersByStudyId(studyId); for ( UserAccount userAccount:users) { Element item = doc.createElement("item"); Element userName = doc.createElement("user_name"); userName.appendChild(doc.createTextNode(userAccount.getUserName())); Element firstName = doc.createElement("first_name"); firstName.appendChild(doc.createTextNode(userAccount.getFirstName())); Element lastName = doc.createElement("last_name"); lastName.appendChild(doc.createTextNode(userAccount.getLastName())); item.appendChild(userName); item.appendChild(firstName); item.appendChild(lastName); root.appendChild(item); } DOMSource dom = new DOMSource(doc); StringWriter writer = new StringWriter(); StreamResult result = new StreamResult(writer); TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); transformer.transform(dom, result); String userXml = writer.toString(); return userXml; } private boolean mayProceedSubmission(String studyOid, StudySubjectBean ssBean) throws Exception { boolean accessPermission = false; StudyBean study = getParentStudy(studyOid); StudyParameterValueDAO spvdao = new StudyParameterValueDAO(dataSource); StudyParameterValueBean pStatus = spvdao.findByHandleAndStudy(study.getId(), "participantPortal"); participantPortalRegistrar = new ParticipantPortalRegistrar(); String pManageStatus = participantPortalRegistrar.getRegistrationStatus(studyOid).toString(); // ACTIVE , // PENDING , // INACTIVE String participateStatus = pStatus.getValue().toString(); // enabled , disabled String studyStatus = study.getStatus().getName().toString(); // available , pending , frozen , locked logger.info("pManageStatus: " + pManageStatus + " participantStatus: " + participateStatus + " studyStatus: " + studyStatus + " studySubjectStatus: " + ssBean.getStatus().getName()); if (participateStatus.equalsIgnoreCase("enabled") && studyStatus.equalsIgnoreCase("available") && pManageStatus.equalsIgnoreCase("ACTIVE") && ssBean.getStatus() == Status.AVAILABLE) { accessPermission = true; } return accessPermission; } private boolean mayProceedPreview(String studyOid) throws Exception { boolean accessPermission = false; StudyBean study = getParentStudy(studyOid); StudyParameterValueDAO spvdao = new StudyParameterValueDAO(dataSource); StudyParameterValueBean pStatus = spvdao.findByHandleAndStudy(study.getId(), "participantPortal"); participantPortalRegistrar = new ParticipantPortalRegistrar(); String pManageStatus = participantPortalRegistrar.getRegistrationStatus(study.getOid()).toString(); // ACTIVE , // PENDING , // INACTIVE String participateStatus = pStatus.getValue().toString(); // enabled , disabled String studyStatus = study.getStatus().getName().toString(); // available , pending , frozen , locked logger.info("pManageStatus: " + pManageStatus + " participantStatus: " + participateStatus + " studyStatus: " + studyStatus); if (participateStatus.equalsIgnoreCase("enabled") && (studyStatus.equalsIgnoreCase("available") || studyStatus.equalsIgnoreCase("pending") || studyStatus.equalsIgnoreCase("frozen") || studyStatus .equalsIgnoreCase("locked")) && (pManageStatus.equalsIgnoreCase("ACTIVE") || pManageStatus.equalsIgnoreCase("PENDING") || pManageStatus.equalsIgnoreCase("INACTIVE"))) { accessPermission = true; } return accessPermission; } private class MediaStreamingOutput implements StreamingOutput { private InputStream in = null; public MediaStreamingOutput(InputStream in) { this.in = in; } @Override public void write(OutputStream out) throws IOException, WebApplicationException { // TODO Auto-generated method stub IOUtils.copy(in, out); in.close(); out.close(); } } }