]> git.argeo.org Git - gpl/argeo-suite.git/blob - org.argeo.app.core/src/org/argeo/app/odk/OdkUtils.java
Adapt to changes in Argeo Commons.
[gpl/argeo-suite.git] / org.argeo.app.core / src / org / argeo / app / odk / OdkUtils.java
1 package org.argeo.app.odk;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.net.URI;
7 import java.net.URISyntaxException;
8 import java.nio.charset.StandardCharsets;
9
10 import javax.jcr.ImportUUIDBehavior;
11 import javax.jcr.Node;
12 import javax.jcr.NodeIterator;
13 import javax.jcr.Property;
14 import javax.jcr.RepositoryException;
15 import javax.jcr.Session;
16 import javax.jcr.nodetype.NodeType;
17
18 import org.argeo.api.cms.CmsLog;
19 import org.argeo.app.api.EntityMimeType;
20 import org.argeo.app.api.EntityType;
21 import org.argeo.jcr.Jcr;
22 import org.argeo.jcr.JcrUtils;
23 import org.argeo.jcr.JcrxApi;
24 import org.argeo.util.DigestUtils;
25
26 /** Utilities around ODK. */
27 public class OdkUtils {
28 private final static CmsLog log = CmsLog.getLog(OdkUtils.class);
29
30 public static Node loadOdkForm(Node formBase, String name, InputStream in, InputStream... additionalNodes)
31 throws RepositoryException, IOException {
32 if (!formBase.isNodeType(EntityType.formSet.get()))
33 throw new IllegalArgumentException(
34 "Parent path " + formBase + " must be of type " + EntityType.formSet.get());
35 Node form = JcrUtils.getOrAdd(formBase, name, OrxListName.xform.get(), NodeType.MIX_VERSIONABLE);
36
37 String previousCsum = JcrxApi.getChecksum(form, JcrxApi.MD5);
38 String previousFormId = Jcr.get(form, OrxListName.formID.get());
39 String previousFormVersion = Jcr.get(form, OrxListName.version.get());
40
41 Session s = formBase.getSession();
42 s.importXML(form.getPath(), in, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
43
44 for (InputStream additionalIn : additionalNodes) {
45 s.importXML(form.getPath(), additionalIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
46 }
47 s.save();
48
49 // manage instances
50 // NodeIterator instances =
51 // form.getNodes("h:html/h:head/xforms:model/xforms:instance");
52 NodeIterator instances = form.getNode("h:html/h:head/xforms:model").getNodes("xforms:instance");
53 Node primaryInstance = null;
54 while (instances.hasNext()) {
55 Node instance = instances.nextNode();
56 if (primaryInstance == null) {
57 primaryInstance = instance;
58 } else {// secondary instances
59 String instanceId = instance.getProperty("id").getString();
60 URI instanceUri = null;
61 if (instance.hasProperty("src"))
62 try {
63 instanceUri = new URI(instance.getProperty("src").getString());
64 } catch (URISyntaxException e) {
65 throw new IllegalArgumentException("Instance " + instanceId + " has a badly formatted URI", e);
66 }
67 if (instanceUri != null) {
68 if ("jr".equals(instanceUri.getScheme())) {
69 String uuid;
70 String mimeType;
71 String encoding = StandardCharsets.UTF_8.name();
72 String type = instanceUri.getHost();
73 String path = instanceUri.getPath();
74 if ("file".equals(type)) {
75 if (!path.endsWith(".xml"))
76 throw new IllegalArgumentException("File uri " + instanceUri + " must end with .xml");
77 // Work around bug in ODK Collect not supporting paths
78 // path = path.substring(0, path.length() - ".xml".length());
79 // Node target = file.getSession().getNode(path);
80 uuid = path.substring(1, path.length() - ".xml".length());
81 mimeType = EntityMimeType.XML.getMimeType();
82 } else if ("file-csv".equals(type)) {
83 if (!path.endsWith(".csv"))
84 throw new IllegalArgumentException("File uri " + instanceUri + " must end with .csv");
85 // Work around bug in ODK Collect not supporting paths
86 // path = path.substring(0, path.length() - ".csv".length());
87 // Node target = file.getSession().getNode(path);
88 uuid = path.substring(1, path.length() - ".csv".length());
89 mimeType = EntityMimeType.CSV.getMimeType();
90 } else {
91 throw new IllegalArgumentException("Unsupported instance type " + type);
92 }
93 Node manifest = JcrUtils.getOrAdd(form, OrxManifestName.manifest.name(),
94 OrxManifestName.manifest.get());
95 Node file = JcrUtils.getOrAdd(manifest, instanceId);
96 file.addMixin(NodeType.MIX_MIMETYPE);
97 file.setProperty(Property.JCR_MIMETYPE, mimeType);
98 file.setProperty(Property.JCR_ENCODING, encoding);
99 Node target = file.getSession().getNodeByIdentifier(uuid);
100
101 // if (target.isNodeType(NodeType.NT_QUERY)) {
102 // Query query = target.getSession().getWorkspace().getQueryManager().getQuery(target);
103 // query.setLimit(10);
104 // QueryResult queryResult = query.execute();
105 // RowIterator rit = queryResult.getRows();
106 // while (rit.hasNext()) {
107 // Row row = rit.nextRow();
108 // for (Value value : row.getValues()) {
109 // System.out.print(value.getString());
110 // System.out.print(',');
111 // }
112 // System.out.print('\n');
113 // }
114 //
115 // }
116
117 if (target.isNodeType(NodeType.MIX_REFERENCEABLE)) {
118 file.setProperty(Property.JCR_ID, target);
119 if (file.hasProperty(Property.JCR_PATH))
120 file.getProperty(Property.JCR_PATH).remove();
121 } else {
122 file.setProperty(Property.JCR_PATH, target.getPath());
123 if (file.hasProperty(Property.JCR_ID))
124 file.getProperty(Property.JCR_ID).remove();
125 }
126 }
127 }
128 }
129 }
130
131 if (primaryInstance == null)
132 throw new IllegalArgumentException("No primary instance found in " + form);
133 if (!primaryInstance.hasNodes())
134 throw new IllegalArgumentException("No data found in primary instance of " + form);
135 NodeIterator primaryInstanceChildren = primaryInstance.getNodes();
136 Node data = primaryInstanceChildren.nextNode();
137 if (primaryInstanceChildren.hasNext())
138 throw new IllegalArgumentException("More than one data found in primary instance of " + form);
139 String formId = data.getProperty("id").getString();
140 if (previousFormId != null && !formId.equals(previousFormId))
141 log.warn("Form id of " + form + " changed from " + previousFormId + " to " + formId);
142 form.setProperty(OrxListName.formID.get(), formId);
143 String formVersion = data.getProperty("version").getString();
144
145 if (previousCsum == null)// save before checksuming
146 s.save();
147 String newCsum;
148 try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
149 s.exportDocumentView(form.getPath() + "/" + OdkNames.H_HTML, out, true, false);
150 newCsum = DigestUtils.digest(DigestUtils.MD5, out.toByteArray());
151 }
152 if (previousCsum == null) {
153 JcrxApi.addChecksum(form, newCsum);
154 JcrUtils.updateLastModified(form);
155 form.setProperty(OrxListName.version.get(), formVersion);
156 s.save();
157 s.getWorkspace().getVersionManager().checkpoint(form.getPath());
158 if (log.isDebugEnabled())
159 log.debug("New form " + form);
160 } else {
161 if (newCsum.equals(previousCsum)) {
162 // discard
163 s.refresh(false);
164 if (log.isDebugEnabled())
165 log.debug("Unmodified form " + form);
166 return form;
167 } else {
168 if (formVersion.equals(previousFormVersion)) {
169 s.refresh(false);
170 throw new IllegalArgumentException("Form " + form + " has been changed but version " + formVersion
171 + " has not been changed, discarding changes...");
172 }
173 form.setProperty(OrxListName.version.get(), formVersion);
174 JcrxApi.addChecksum(form, newCsum);
175 JcrUtils.updateLastModified(form);
176 s.save();
177 s.getWorkspace().getVersionManager().checkpoint(form.getPath());
178 if (log.isDebugEnabled()) {
179 log.debug("Updated form " + form);
180 log.debug("Previous csum " + previousCsum);
181 log.debug("New csum " + newCsum);
182 }
183 }
184 }
185 return form;
186 }
187
188 /** Singleton. */
189 private OdkUtils() {
190
191 }
192
193 }