--- /dev/null
+package org.simantics.document;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.document.DocumentResource;
+import org.simantics.layer0.Layer0;
+/**
+ * Util class for managing document versions
+ *
+ * Document version history mode is searched with relations:
+ * 1. l0.PartOf
+ * 2. l0.IsOwnedBy
+ * 3. l0.IsDependencyOf
+ *
+ * If library is not found, history mode is assumed to be flat.
+ *
+ * In order to have working tree history, the library must contain proper configuration for relations:
+ * doc.HasLibraryRelation
+ * doc.HasVersionType
+ *
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public class DocumentVersionUtils {
+
+ public enum VersionMode{FLAT,TREE};
+
+
+ /**
+ * Adds a new document version.
+ *
+ * Expects that newDocument is not part of document version chain, and oldDocument does not have newer version.
+ *
+ * @param graph
+ * @param oldDocument
+ * @param newDocument
+ * @param relation
+ * @throws DatabaseException
+ */
+ public static void createNewVersion(WriteGraph graph, Resource oldDocument, Resource newDocument, Resource relation) throws DatabaseException{
+ DocumentResource doc = DocumentResource.getInstance(graph);
+ if (graph.hasStatement(oldDocument, doc.HasNewerVersion))
+ throw new DatabaseException("Document " + NameUtils.getSafeName(graph, oldDocument) +" has already new version");
+
+ Resource inverse = graph.getInverse(relation);
+ Resource lib = graph.getSingleObject(oldDocument, inverse);
+ String modeString = graph.getPossibleRelatedValue(lib, doc.HasVersionType);
+ VersionMode mode = VersionMode.FLAT;
+ if (modeString != null)
+ mode = VersionMode.valueOf(modeString);
+
+ graph.claim(oldDocument, doc.HasNewerVersion, newDocument);
+ graph.claim(lib, relation, newDocument);
+
+ if (mode == VersionMode.TREE) {
+ graph.deny(lib,relation,oldDocument);
+ graph.claim(newDocument,relation,oldDocument);
+ }
+ FileDocumentUtil.createUniqueName(graph, newDocument);
+ }
+
+ /**
+ * Sets document version relationship between two documents.
+ *
+ * If the documents are already part of the same version chain this method does nothing.
+ *
+ * If documents are already set to some version chain with given relation, this method replaces the exiting links.
+ *
+ * @param graph
+ * @param document1
+ * @param document2
+ * @param versionRel
+ * @throws DatabaseException
+ */
+ public static void setVersion(WriteGraph graph, Resource document1, Resource document2, Resource versionRel) throws DatabaseException {
+ DocumentResource doc = DocumentResource.getInstance(graph);
+ // document type must match
+ if (!graph.getSingleType(document2, doc.Document).equals(graph.getSingleType(document1, doc.Document)))
+ return;
+ if (!versionRel.equals(doc.HasNewerVersion) && !(versionRel.equals(doc.HasOlderVersion)))
+ throw new IllegalArgumentException("Unknow version relation + " + graph.getPossibleURI(versionRel));
+
+ Resource versionRelInv = graph.getInverse(versionRel);
+ // toSet must not be part of the document's version history
+ Resource r = document1;
+ while (r != null) {
+ if (r.equals(document2))
+ return;
+ r = graph.getPossibleObject(r, versionRel);
+ }
+
+ r = document2;
+ while (r != null) {
+ if (r.equals(document1))
+ return;
+ r = graph.getPossibleObject(r, versionRel);
+ }
+ // At the moment document revision history is linear (no branching).
+ Resource document1Ver = graph.getPossibleObject(document1, versionRel);
+ if (document1Ver != null)
+ unsetVersion(graph, document1, document1Ver, versionRel);
+ Resource document2Ver = graph.getPossibleObject(document2, versionRelInv);
+ if (document2Ver != null)
+ unsetVersion(graph, document2, document2Ver, versionRelInv);
+
+ graph.claim(document1, versionRel, document2);
+
+ Resource lib = getLib(graph, document1);
+ if (lib != null) {
+ Resource relation = graph.getPossibleObject(lib, doc.HasLibraryRelation);
+ String type= graph.getPossibleRelatedValue(lib, doc.HasVersionType);
+ if ("TREE".equals(type) && relation != null) {
+ if (versionRel.equals(doc.HasOlderVersion)) {
+ graph.deny(document2, graph.getInverse(relation));
+ graph.claim(document1,relation,document2);
+ } else {
+ graph.deny(document1, graph.getInverse(relation));
+ graph.claim(document2,relation,document1);
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Unlinks document version relationship between two documents.
+ * @param graph
+ * @param document1
+ * @param document2
+ * @param versionRel
+ * @throws DatabaseException
+ */
+ public static void unsetVersion(WriteGraph graph, Resource document1, Resource document2, Resource versionRel) throws DatabaseException {
+ DocumentResource doc = DocumentResource.getInstance(graph);
+ if (!versionRel.equals(doc.HasNewerVersion) && !(versionRel.equals(doc.HasOlderVersion)))
+ throw new IllegalArgumentException("Unknow version relation + " + graph.getPossibleURI(versionRel));
+
+ graph.deny(document1, versionRel,document2);
+ Resource lib = getLib(graph, document1);
+ if (lib != null) {
+ Resource relation = graph.getPossibleObject(lib, doc.HasLibraryRelation);
+ String type= graph.getPossibleRelatedValue(lib, doc.HasVersionType);
+ if ("TREE".equals(type) && relation != null) {
+ if (versionRel.equals(doc.HasOlderVersion)) {
+ graph.deny(document1, relation);
+ graph.claim(lib,relation,document2);
+ FileDocumentUtil.createUniqueName(graph, document2);
+ } else {
+ graph.deny(document1, graph.getInverse(relation));
+ graph.claim(lib,relation,document1);
+ FileDocumentUtil.createUniqueName(graph, document1);
+ }
+ }
+
+ }
+ }
+
+ private static Resource getLib(ReadGraph graph, Resource document) throws DatabaseException {
+ Layer0 l0 = Layer0.getInstance(graph);
+ DocumentResource doc = DocumentResource.getInstance(graph);
+ Resource r = document;
+ while (true) {
+ Resource lib = graph.getPossibleObject(r, l0.PartOf);
+ if (lib == null)
+ lib = graph.getPossibleObject(r, l0.IsOwnedBy);
+ if (lib == null)
+ lib = graph.getPossibleObject(r, l0.IsDependencyOf);
+ if (lib == null)
+ return null;
+ if (!graph.isInstanceOf(lib, doc.Document))
+ return lib;
+ r = lib;
+ }
+ }
+}