1 package org
.argeo
.support
.odk
.servlet
;
3 import java
.io
.IOException
;
4 import java
.time
.Instant
;
5 import java
.time
.ZoneId
;
6 import java
.time
.ZoneOffset
;
7 import java
.time
.format
.DateTimeFormatter
;
8 import java
.util
.HashSet
;
11 import javax
.jcr
.ImportUUIDBehavior
;
12 import javax
.jcr
.Node
;
13 import javax
.jcr
.Property
;
14 import javax
.jcr
.Repository
;
15 import javax
.jcr
.RepositoryException
;
16 import javax
.jcr
.Session
;
17 import javax
.jcr
.nodetype
.NodeType
;
18 import javax
.servlet
.ServletException
;
19 import javax
.servlet
.http
.HttpServlet
;
20 import javax
.servlet
.http
.HttpServletRequest
;
21 import javax
.servlet
.http
.HttpServletResponse
;
22 import javax
.servlet
.http
.Part
;
24 import org
.apache
.commons
.logging
.Log
;
25 import org
.apache
.commons
.logging
.LogFactory
;
26 import org
.argeo
.api
.cms
.CmsSession
;
27 import org
.argeo
.cms
.auth
.HttpRequest
;
28 import org
.argeo
.cms
.jcr
.CmsJcrUtils
;
29 import org
.argeo
.cms
.servlet
.ServletAuthUtils
;
30 import org
.argeo
.cms
.servlet
.ServletHttpRequest
;
31 import org
.argeo
.jcr
.Jcr
;
32 import org
.argeo
.jcr
.JcrUtils
;
33 import org
.argeo
.suite
.SuiteUtils
;
34 import org
.argeo
.support
.odk
.OrxType
;
35 import org
.argeo
.support
.xforms
.FormSubmissionListener
;
37 /** Receives a form submission. */
38 public class OdkSubmissionServlet
extends HttpServlet
{
39 private static final long serialVersionUID
= 7834401404691302385L;
40 private final static Log log
= LogFactory
.getLog(OdkSubmissionServlet
.class);
42 private final static String XML_SUBMISSION_FILE
= "xml_submission_file";
44 private DateTimeFormatter submissionNameFormatter
= DateTimeFormatter
.ofPattern("YYYY-MM-dd-HHmmssSSS")
45 .withZone(ZoneId
.from(ZoneOffset
.UTC
));
47 private Repository repository
;
49 private Set
<FormSubmissionListener
> submissionListeners
= new HashSet
<>();
52 protected void doPost(HttpServletRequest req
, HttpServletResponse resp
) throws ServletException
, IOException
{
53 resp
.setContentType("text/xml; charset=utf-8");
54 resp
.setHeader("X-OpenRosa-Version", "1.0");
55 resp
.setDateHeader("Date", System
.currentTimeMillis());
56 resp
.setIntHeader("X-OpenRosa-Accept-Content-Length", 1024 * 1024);
58 HttpRequest request
= new ServletHttpRequest(req
);
59 Session session
= ServletAuthUtils
.doAs(() -> Jcr
.login(repository
, null), request
);
62 // Node submissions = JcrUtils.mkdirs(session,
63 // "/" + EntityType.form.get() + "/" + EntityNames.SUBMISSIONS_BASE);
64 CmsSession cmsSession
= ServletAuthUtils
.getCmsSession(request
);
66 ClassLoader currentContextCl
= Thread
.currentThread().getContextClassLoader();
67 Thread
.currentThread().setContextClassLoader(ServletAuthUtils
.class.getClassLoader());
68 Session adminSession
= null;
70 // TODO centralise at a deeper level
71 adminSession
= CmsJcrUtils
.openDataAdminSession(repository
, null);
72 SuiteUtils
.getOrCreateCmsSessionNode(adminSession
, cmsSession
);
74 Jcr
.logout(adminSession
);
75 Thread
.currentThread().setContextClassLoader(currentContextCl
);
78 Node cmsSessionNode
= SuiteUtils
.getCmsSessionNode(session
, cmsSession
);
79 Node submission
= cmsSessionNode
.addNode(submissionNameFormatter
.format(Instant
.now()),
80 OrxType
.submission
.get());
81 for (Part part
: req
.getParts()) {
82 if (log
.isDebugEnabled())
83 log
.debug("Part: " + part
.getName() + ", " + part
.getContentType());
85 if (part
.getName().equals(XML_SUBMISSION_FILE
)) {
86 Node xml
= submission
.addNode(XML_SUBMISSION_FILE
, NodeType
.NT_UNSTRUCTURED
);
87 session
.importXML(xml
.getPath(), part
.getInputStream(),
88 ImportUUIDBehavior
.IMPORT_UUID_COLLISION_REPLACE_EXISTING
);
91 Node fileNode
= JcrUtils
.copyStreamAsFile(submission
, part
.getName(), part
.getInputStream());
92 String contentType
= part
.getContentType();
93 if (contentType
!= null) {
94 fileNode
.addMixin(NodeType
.MIX_MIMETYPE
);
95 fileNode
.setProperty(Property
.JCR_MIMETYPE
, contentType
);
98 if (part
.getName().endsWith(".jpg") || part
.getName().endsWith(".png")) {
99 // TODO meta data and thumbnails
104 for (FormSubmissionListener submissionListener
: submissionListeners
) {
105 submissionListener
.formSubmissionReceived(submission
);
107 } catch (RepositoryException e
) {
116 resp
.getWriter().write("<OpenRosaResponse xmlns=\"http://openrosa.org/http/response\">"
117 + "<message>Form Received!</message>" + "</OpenRosaResponse>");
121 public void setRepository(Repository repository
) {
122 this.repository
= repository
;
125 public synchronized void addSubmissionListener(FormSubmissionListener listener
) {
126 submissionListeners
.add(listener
);
129 public synchronized void removeSubmissionListener(FormSubmissionListener listener
) {
130 submissionListeners
.remove(listener
);