package org.simantics.document.ui.graphfile; 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 * */ 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"); //$NON-NLS-1$ //$NON-NLS-2$ 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)); //$NON-NLS-1$ 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) { //$NON-NLS-1$ 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)); //$NON-NLS-1$ 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) { //$NON-NLS-1$ 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; } } }