5bb3d9ca21c95d30bb5d96200d41caade8bf59df
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / utils / DumpOntologyStructure.java
1 package org.simantics.modeling.utils;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.nio.charset.StandardCharsets;
6 import java.util.Collection;
7 import java.util.HashMap;
8 import java.util.Map;
9 import java.util.TreeMap;
10
11 import org.simantics.Simantics;
12 import org.simantics.db.ReadGraph;
13 import org.simantics.db.Resource;
14 import org.simantics.db.common.utils.CommonDBUtils;
15 import org.simantics.db.common.utils.NameUtils;
16 import org.simantics.db.exception.DatabaseException;
17 import org.simantics.db.layer0.variable.Variable;
18 import org.simantics.db.layer0.variable.Variables;
19 import org.simantics.layer0.Layer0;
20 import org.simantics.modeling.ModelingResources;
21 import org.simantics.scl.runtime.function.Function;
22 import org.simantics.utils.FileUtils;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 import gnu.trove.list.array.TByteArrayList;
27
28 public class DumpOntologyStructure {
29
30     private static final Logger LOGGER = LoggerFactory.getLogger(DumpOntologyStructure.class);
31
32     private Resource ontology;
33
34     private Map<Resource, String> names = new HashMap<>();
35     private Map<Resource,Resource> parents = new HashMap<>();
36     private Map<Resource, File> libraryFolders = new HashMap<>();
37     private Map<Resource, byte[]> contentDumps = new HashMap<>();
38
39     private void readNameAndParent(ReadGraph graph, Resource container, Resource r) throws DatabaseException {
40         parents.put(r, container);
41         names.put(r, NameUtils.getSafeName(graph, r));
42     }
43
44     private Collection<Resource> containers() {
45         return parents.values();
46     }
47
48     private void readHierarchy(ReadGraph graph, Resource container) throws DatabaseException {
49         Layer0 L0 = Layer0.getInstance(graph);
50         for(Resource r : CommonDBUtils.objectsWithType(graph, container, L0.ConsistsOf, L0.Entity)) {
51             try {
52                 readNameAndParent(graph, container, r);
53                 readHierarchy(graph, r);
54             } catch (DatabaseException e) {
55                 LOGGER.error("Error while reading content dump hierarchy for " + r, e);
56             }
57         }
58     }
59
60     private void readGeneric(ReadGraph graph) throws DatabaseException {
61         ModelingResources MOD = ModelingResources.getInstance(graph);
62         for(Resource r : parents.keySet()) {
63             if(contentDumps.containsKey(r))
64                 continue;
65             TByteArrayList result = new TByteArrayList();
66             try {
67                 TreeMap<String,Resource> sortedTypes = new TreeMap<>();
68                 for(Resource type : graph.getTypes(r)) {
69                     String uri = graph.getPossibleURI(type);
70                     if(uri != null)
71                         sortedTypes.put(uri, type);
72                 }
73                 for(Resource type : sortedTypes.values()) {
74                     try {
75                         Variable typeVariable = Variables.getVariable(graph, type);
76                         @SuppressWarnings("rawtypes")
77                         Function f = typeVariable.getPossiblePropertyValue(graph, MOD.contentDumpFunction);
78                         if(f != null) {
79                             @SuppressWarnings("unchecked")
80                             byte[] dump = (byte[])Simantics.applySCLRead(graph, f, r);
81                             if(dump != null) {
82                                 result.add(dump);
83                             }
84                         }
85                     } catch (DatabaseException e) {
86                         LOGGER.error("Error while computing content dump for " + r, e);
87                     }
88                 }
89                 if(result.size() > 0)
90                     contentDumps.put(r, result.toArray());
91             } catch (DatabaseException e) {
92                 LOGGER.error("Error while computing content dump for " + r, e);
93             }
94         }
95     }
96
97     public DumpOntologyStructure read(ReadGraph graph, Resource ontology) throws DatabaseException {
98         this.ontology = ontology;
99         readHierarchy(graph, ontology);
100         readGeneric(graph);
101         return this;
102     }
103
104     private File escapeFile(File file) {
105         if(file.exists())
106             return file;
107         return new File(escapeFile(file.getParentFile()), FileUtils.escapeFileName(file.getName()));
108     }
109
110     public void write(File unsafeFolder) throws IOException {
111         File folder = escapeFile(unsafeFolder);
112         FileUtils.delete(folder.toPath());
113         folder.mkdirs();
114         writeDirectories(folder);
115         writeResources(folder);
116     }
117
118     private File getFolder(File root, Resource library) {
119         if(ontology.equals(library))
120             return root;
121         Resource parent = parents.get(library);
122         if(parent == null)
123             throw new IllegalStateException("null parent for " + library);
124         File parentFolder = getFolder(root, parent);
125         return new File(parentFolder, FileUtils.escapeFileName(names.get(library))); 
126     }
127
128     private File getFile(File rootFolder, Resource r) {
129         Resource parent = parents.get(r);
130         File folder = getFolder(rootFolder, parent);
131         return new File(folder, FileUtils.escapeFileName(names.get(r)));
132     }
133
134     private void writeDirectories(File rootFolder) {
135         for(Resource library : containers()) {
136             File folder = getFolder(rootFolder, library);
137             folder.mkdirs();
138             libraryFolders.put(library, folder);
139         }
140     }
141
142     private void writeResources(File rootFolder) throws IOException {
143         for(Resource r : parents.keySet()) {
144             writeResource(rootFolder, r);
145         }
146     }
147
148     private boolean isParent(Resource r) {
149         return parents.values().contains(r);
150     }
151
152     private void writeResource(File rootFolder, Resource resource) throws IOException {
153         byte[] dump = contentDumps.get(resource);
154         if(dump == null)
155             dump = "".getBytes(StandardCharsets.UTF_8);
156         if(isParent(resource)) {
157             if(dump.length > 0)
158                 FileUtils.writeFile(new File(getFolder(rootFolder, resource), "__contents__"), dump);
159         } else {
160             write(rootFolder, resource, dump);
161         }
162     }
163
164     private void write(File rootFolder, Resource resource, byte[] bytes) throws IOException {
165         FileUtils.writeFile(getFile(rootFolder, resource), bytes);
166     }
167
168 }