Work on ODK manifest support.
[gpl/argeo-suite.git] / knowledge / org.argeo.support.odk / src / org / argeo / support / odk / OdkUtils.java
index 4c106a29b2a7dfd007ce2cb6cead390a34a09ce4..0e73295b6f3d6c3f1ab7744d3b9bf9290160781f 100644 (file)
@@ -3,9 +3,13 @@ package org.argeo.support.odk;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
 
 import javax.jcr.ImportUUIDBehavior;
 import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.nodetype.NodeType;
@@ -13,6 +17,7 @@ import javax.jcr.nodetype.NodeType;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.entity.EntityType;
+import org.argeo.jcr.Jcr;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.jcr.JcrxApi;
 import org.argeo.util.DigestUtils;
@@ -25,9 +30,11 @@ public class OdkUtils {
                if (!formBase.isNodeType(EntityType.formSet.get()))
                        throw new IllegalArgumentException(
                                        "Parent path " + formBase + " must be of type " + EntityType.formSet.get());
-               Node form = JcrUtils.getOrAdd(formBase, name, OrxListType.xform.get(), NodeType.MIX_SIMPLE_VERSIONABLE);
+               Node form = JcrUtils.getOrAdd(formBase, name, OrxListName.xform.get(), NodeType.MIX_VERSIONABLE);
 
                String previousCsum = JcrxApi.getChecksum(form, JcrxApi.MD5);
+               String previousFormId = Jcr.get(form, OrxListName.formID.get());
+               String previousFormVersion = Jcr.get(form, OrxListName.version.get());
 
                Session s = formBase.getSession();
 //             String res = "/odk/apafSession.odk.xml";
@@ -35,6 +42,65 @@ public class OdkUtils {
                s.importXML(form.getPath(), in, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
 //             }
 
+               // manage instances
+               // NodeIterator instances =
+               // form.getNodes("h:html/h:head/xforms:model/xforms:instance");
+               NodeIterator instances = form.getNode("h:html/h:head/xforms:model").getNodes("xforms:instance");
+               Node primaryInstance = null;
+               while (instances.hasNext()) {
+                       Node instance = instances.nextNode();
+                       if (primaryInstance == null) {
+                               primaryInstance = instance;
+                       } else {// secondary instances
+                               String instanceId = instance.getProperty("id").getString();
+                               URI instanceUri = null;
+                               if (instance.hasProperty("src"))
+                                       try {
+                                               instanceUri = new URI(instance.getProperty("src").getString());
+                                       } catch (URISyntaxException e) {
+                                               throw new IllegalArgumentException("Instance " + instanceId + " has a badly formatted URI", e);
+                                       }
+                               if (instanceUri != null) {
+                                       if ("jr".equals(instanceUri.getScheme())) {
+                                               String type = instanceUri.getHost();
+                                               if ("file".equals(type)) {
+                                                       Node manifest = JcrUtils.getOrAdd(form, OrxManifestName.manifest.name(),
+                                                                       OrxManifestName.manifest.get());
+                                                       Node file = JcrUtils.getOrAdd(manifest, instanceId);
+                                                       String path = instanceUri.getPath();
+                                                       if (!path.endsWith(".xml"))
+                                                               throw new IllegalArgumentException("File uri " + instanceUri + " must end with .xml");
+                                                       path = path.substring(0, path.length() - ".xml".length());
+                                                       Node target = file.getSession().getNode(path);
+                                                       if (target.isNodeType(NodeType.MIX_REFERENCEABLE)) {
+                                                               file.setProperty(Property.JCR_ID, target);
+                                                               if (file.hasProperty(Property.JCR_PATH))
+                                                                       file.getProperty(Property.JCR_PATH).remove();
+                                                       } else {
+                                                               file.setProperty(Property.JCR_PATH, target.getPath());
+                                                               if (file.hasProperty(Property.JCR_ID))
+                                                                       file.getProperty(Property.JCR_ID).remove();
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               if (primaryInstance == null)
+                       throw new IllegalArgumentException("No primary instance found in " + form);
+               if (!primaryInstance.hasNodes())
+                       throw new IllegalArgumentException("No data found in primary instance of " + form);
+               NodeIterator primaryInstanceChildren = primaryInstance.getNodes();
+               Node data = primaryInstanceChildren.nextNode();
+               if (primaryInstanceChildren.hasNext())
+                       throw new IllegalArgumentException("More than one data found in primary instance of " + form);
+               String formId = data.getProperty("id").getString();
+               if (previousFormId != null && !formId.equals(previousFormId))
+                       log.warn("Form id of " + form + " changed from " + previousFormId + " to " + formId);
+               form.setProperty(OrxListName.formID.get(), formId);
+               String formVersion = data.getProperty("version").getString();
+
                if (previousCsum == null)// save before checksuming
                        s.save();
                String newCsum;
@@ -45,6 +111,7 @@ public class OdkUtils {
                if (previousCsum == null) {
                        JcrxApi.addChecksum(form, newCsum);
                        JcrUtils.updateLastModified(form);
+                       form.setProperty(OrxListName.version.get(), formVersion);
                        s.save();
                        s.getWorkspace().getVersionManager().checkpoint(form.getPath());
                        if (log.isDebugEnabled())
@@ -57,6 +124,12 @@ public class OdkUtils {
                                        log.debug("Unmodified form " + form);
                                return;
                        } else {
+                               if (formVersion.equals(previousFormVersion)) {
+                                       s.refresh(false);
+                                       throw new IllegalArgumentException("Form " + form + " has been changed but version " + formVersion
+                                                       + " has not been changed, discarding changes...");
+                               }
+                               form.setProperty(OrxListName.version.get(), formVersion);
                                JcrxApi.addChecksum(form, newCsum);
                                JcrUtils.updateLastModified(form);
                                s.save();