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