]> git.argeo.org Git - gpl/argeo-suite.git/blob - org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java
Disable development mode in FOP servlet
[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.nodetype.NodeType;
17 import javax.servlet.ServletException;
18 import javax.servlet.http.HttpServlet;
19 import javax.servlet.http.HttpServletRequest;
20 import javax.servlet.http.HttpServletResponse;
21 import javax.servlet.http.Part;
22
23 import org.argeo.api.acr.Content;
24 import org.argeo.api.cms.CmsLog;
25 import org.argeo.api.cms.CmsSession;
26 import org.argeo.app.api.AppUserState;
27 import org.argeo.app.image.ImageProcessor;
28 import org.argeo.app.odk.OrxType;
29 import org.argeo.app.xforms.FormSubmissionListener;
30 import org.argeo.cms.auth.RemoteAuthRequest;
31 import org.argeo.cms.auth.RemoteAuthUtils;
32 import org.argeo.cms.jcr.acr.JcrContent;
33 import org.argeo.cms.servlet.ServletHttpRequest;
34 import org.argeo.jcr.JcrUtils;
35
36 /** Receives a form submission. */
37 public class OdkSubmissionServlet extends HttpServlet {
38 private static final long serialVersionUID = 7834401404691302385L;
39 private final static CmsLog log = CmsLog.getLog(OdkSubmissionServlet.class);
40
41 private final static String XML_SUBMISSION_FILE = "xml_submission_file";
42
43 private DateTimeFormatter submissionNameFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd-HHmmssSSS")
44 .withZone(ZoneId.from(ZoneOffset.UTC));
45
46 // private Repository repository;
47 // private ContentRepository contentRepository;
48
49 private Set<FormSubmissionListener> submissionListeners = new HashSet<>();
50
51 private AppUserState appUserState;
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
59 // should be set in HEAD? Let's rather use defaults.
60 // resp.setIntHeader("X-OpenRosa-Accept-Content-Length", 1024 * 1024);
61
62 RemoteAuthRequest request = new ServletHttpRequest(req);
63 // Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), request);
64 //
65 CmsSession cmsSession = RemoteAuthUtils.getCmsSession(request);
66
67 // Session adminSession = null;
68 // try {
69 // // TODO centralise at a deeper level
70 // adminSession = CmsJcrUtils.openDataAdminSession(repository, null);
71 // SuiteJcrUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
72 // } finally {
73 // Jcr.logout(adminSession);
74 // }
75
76 try {
77 Content sessionDir = appUserState.getOrCreateSessionDir(cmsSession);
78 Node cmsSessionNode = sessionDir.adapt(Node.class);
79 // Node cmsSessionNode = SuiteJcrUtils.getCmsSessionNode(session, cmsSession);
80 Node submission = cmsSessionNode.addNode(submissionNameFormatter.format(Instant.now()),
81 OrxType.submission.get());
82 for (Part part : req.getParts()) {
83 if (log.isTraceEnabled())
84 log.trace("Part: " + part.getName() + ", " + part.getContentType());
85
86 if (part.getName().equals(XML_SUBMISSION_FILE)) {
87 Node xml = submission.addNode(XML_SUBMISSION_FILE, NodeType.NT_UNSTRUCTURED);
88 cmsSessionNode.getSession().importXML(xml.getPath(), part.getInputStream(),
89 ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
90
91 } else {
92 Node fileNode;
93 if (part.getName().endsWith(".jpg")) {
94 // Fix metadata
95 Path temp = Files.createTempFile("image", ".jpg");
96 try {
97 ImageProcessor imageProcessor = new ImageProcessor(() -> part.getInputStream(),
98 () -> Files.newOutputStream(temp));
99 imageProcessor.process();
100 fileNode = JcrUtils.copyStreamAsFile(submission, part.getName(),
101 Files.newInputStream(temp));
102 } finally {
103 Files.deleteIfExists(temp);
104 }
105 } else {
106 fileNode = JcrUtils.copyStreamAsFile(submission, part.getName(), part.getInputStream());
107 }
108 String contentType = part.getContentType();
109 if (contentType != null) {
110 fileNode.addMixin(NodeType.MIX_MIMETYPE);
111 fileNode.setProperty(Property.JCR_MIMETYPE, contentType);
112
113 }
114 if (part.getName().endsWith(".jpg") || part.getName().endsWith(".png")) {
115 // TODO meta data and thumbnails
116 }
117 }
118 }
119
120 cmsSessionNode.getSession().save();
121 try {
122 for (FormSubmissionListener submissionListener : submissionListeners) {
123 submissionListener.formSubmissionReceived(JcrContent.nodeToContent(submission));
124 }
125 } catch (Exception e) {
126 log.error("Cannot save submission, cancelling...", e);
127 submission.remove();
128 cmsSessionNode.getSession().save();
129 resp.setStatus(503);
130 return;
131 }
132
133 } catch (Exception e) {
134 log.error("Cannot save submission", e);
135 resp.setStatus(503);
136 return;
137 // } finally {
138 // Jcr.logout(session);
139 }
140
141 resp.setStatus(201);
142 resp.getWriter().write("<OpenRosaResponse xmlns=\"http://openrosa.org/http/response\">"
143 + "<message>Form Received!</message>" + "</OpenRosaResponse>");
144
145 }
146
147 // public void setRepository(Repository repository) {
148 // this.repository = repository;
149 // }
150
151 public synchronized void addSubmissionListener(FormSubmissionListener listener) {
152 submissionListeners.add(listener);
153 }
154
155 public synchronized void removeSubmissionListener(FormSubmissionListener listener) {
156 submissionListeners.remove(listener);
157 }
158
159 // public void setContentRepository(ContentRepository contentRepository) {
160 // this.contentRepository = contentRepository;
161 // }
162
163 public void setAppUserState(AppUserState appUserState) {
164 this.appUserState = appUserState;
165 }
166
167 }