]> git.argeo.org Git - gpl/argeo-suite.git/blob - org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java
Introduce open user menu icon
[gpl/argeo-suite.git] / org.argeo.app.servlet.odk / src / org / argeo / app / servlet / odk / OdkSubmissionServlet.java
1 package org.argeo.app.servlet.odk;
2
3 import java.io.IOException;
4 import java.nio.file.Files;
5 import java.nio.file.Path;
6 import java.time.Instant;
7 import java.time.ZoneId;
8 import java.time.ZoneOffset;
9 import java.time.format.DateTimeFormatter;
10 import java.util.HashSet;
11 import java.util.Set;
12
13 import javax.jcr.ImportUUIDBehavior;
14 import javax.jcr.Node;
15 import javax.jcr.Property;
16 import javax.jcr.Repository;
17 import javax.jcr.RepositoryException;
18 import javax.jcr.Session;
19 import javax.jcr.nodetype.NodeType;
20 import javax.servlet.ServletException;
21 import javax.servlet.http.HttpServlet;
22 import javax.servlet.http.HttpServletRequest;
23 import javax.servlet.http.HttpServletResponse;
24 import javax.servlet.http.Part;
25
26 import org.argeo.api.cms.CmsLog;
27 import org.argeo.api.cms.CmsSession;
28 import org.argeo.app.core.SuiteUtils;
29 import org.argeo.app.image.ImageProcessor;
30 import org.argeo.app.odk.OrxType;
31 import org.argeo.app.xforms.FormSubmissionListener;
32 import org.argeo.cms.auth.RemoteAuthRequest;
33 import org.argeo.cms.auth.RemoteAuthUtils;
34 import org.argeo.cms.jcr.CmsJcrUtils;
35 import org.argeo.cms.servlet.ServletHttpRequest;
36 import org.argeo.jcr.Jcr;
37 import org.argeo.jcr.JcrUtils;
38
39 /** Receives a form submission. */
40 public class OdkSubmissionServlet extends HttpServlet {
41 private static final long serialVersionUID = 7834401404691302385L;
42 private final static CmsLog log = CmsLog.getLog(OdkSubmissionServlet.class);
43
44 private final static String XML_SUBMISSION_FILE = "xml_submission_file";
45
46 private DateTimeFormatter submissionNameFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd-HHmmssSSS")
47 .withZone(ZoneId.from(ZoneOffset.UTC));
48
49 private Repository repository;
50
51 private Set<FormSubmissionListener> submissionListeners = new HashSet<>();
52
53 @Override
54 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
55 resp.setContentType("text/xml; charset=utf-8");
56 resp.setHeader("X-OpenRosa-Version", "1.0");
57 resp.setDateHeader("Date", System.currentTimeMillis());
58 resp.setIntHeader("X-OpenRosa-Accept-Content-Length", 1024 * 1024);
59
60 RemoteAuthRequest request = new ServletHttpRequest(req);
61 Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), request);
62
63 try {
64 CmsSession cmsSession = RemoteAuthUtils.getCmsSession(request);
65
66 Session adminSession = null;
67 try {
68 // TODO centralise at a deeper level
69 adminSession = CmsJcrUtils.openDataAdminSession(repository, null);
70 SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
71 } finally {
72 Jcr.logout(adminSession);
73 }
74
75 Node cmsSessionNode = SuiteUtils.getCmsSessionNode(session, cmsSession);
76 Node submission = cmsSessionNode.addNode(submissionNameFormatter.format(Instant.now()),
77 OrxType.submission.get());
78 for (Part part : req.getParts()) {
79 if (log.isDebugEnabled())
80 log.debug("Part: " + part.getName() + ", " + part.getContentType());
81
82 if (part.getName().equals(XML_SUBMISSION_FILE)) {
83 Node xml = submission.addNode(XML_SUBMISSION_FILE, NodeType.NT_UNSTRUCTURED);
84 session.importXML(xml.getPath(), part.getInputStream(),
85 ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
86
87 } else {
88 Node fileNode;
89 if (part.getName().endsWith(".jpg")) {
90 // Fix metadata
91 Path temp = Files.createTempFile("image", ".jpg");
92 try {
93 ImageProcessor imageProcessor = new ImageProcessor(() -> part.getInputStream(),
94 () -> Files.newOutputStream(temp));
95 imageProcessor.process();
96 fileNode = JcrUtils.copyStreamAsFile(submission, part.getName(),
97 Files.newInputStream(temp));
98 } finally {
99 Files.deleteIfExists(temp);
100 }
101 } else {
102 fileNode = JcrUtils.copyStreamAsFile(submission, part.getName(), part.getInputStream());
103 }
104 String contentType = part.getContentType();
105 if (contentType != null) {
106 fileNode.addMixin(NodeType.MIX_MIMETYPE);
107 fileNode.setProperty(Property.JCR_MIMETYPE, contentType);
108
109 }
110 if (part.getName().endsWith(".jpg") || part.getName().endsWith(".png")) {
111 // TODO meta data and thumbnails
112 }
113 }
114 }
115 session.save();
116 for (FormSubmissionListener submissionListener : submissionListeners) {
117 submissionListener.formSubmissionReceived(submission);
118 }
119 } catch (RepositoryException e) {
120 e.printStackTrace();
121 resp.setStatus(503);
122 return;
123 } finally {
124 Jcr.logout(session);
125 }
126
127 resp.setStatus(201);
128 resp.getWriter().write("<OpenRosaResponse xmlns=\"http://openrosa.org/http/response\">"
129 + "<message>Form Received!</message>" + "</OpenRosaResponse>");
130
131 }
132
133 public void setRepository(Repository repository) {
134 this.repository = repository;
135 }
136
137 public synchronized void addSubmissionListener(FormSubmissionListener listener) {
138 submissionListeners.add(listener);
139 }
140
141 public synchronized void removeSubmissionListener(FormSubmissionListener listener) {
142 submissionListeners.remove(listener);
143 }
144 }