1 package org.simantics.modeling.utils;
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.HashSet;
11 import java.util.TreeMap;
13 import org.simantics.Simantics;
14 import org.simantics.db.ReadGraph;
15 import org.simantics.db.Resource;
16 import org.simantics.db.common.utils.CommonDBUtils;
17 import org.simantics.db.common.utils.NameUtils;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.db.layer0.variable.Variable;
20 import org.simantics.db.layer0.variable.Variables;
21 import org.simantics.layer0.Layer0;
22 import org.simantics.modeling.ModelingResources;
23 import org.simantics.scl.runtime.function.Function;
24 import org.simantics.utils.FileUtils;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
28 import gnu.trove.list.array.TByteArrayList;
30 public class DumpOntologyStructure {
32 private static final Logger LOGGER = LoggerFactory.getLogger(DumpOntologyStructure.class);
34 private Resource ontology;
36 private Map<Resource, String> names = new HashMap<>();
37 private Map<Resource,Resource> parents = new TreeMap<>();
38 private Map<Resource, File> libraryFolders = new HashMap<>();
39 private Map<Resource, byte[]> contentDumps = new HashMap<>();
41 private void readNameAndParent(ReadGraph graph, Resource container, Resource r) throws DatabaseException {
42 String name = NameUtils.getSafeName(graph, r);
43 parents.put(r, container);
44 names.put(r, FileUtils.escapeFileName(name));
48 * This shall return containers sorted by full path.
49 * This makes processing order stable and ensures that
50 * directories are processed before their contents.
52 private Collection<Resource> sortedContainers(File rootFolder) {
53 Set<Resource> parentSet = new HashSet<Resource>(parents.values());
54 TreeMap<String,Resource> result = new TreeMap<>();
55 for(Resource r : parentSet) {
56 File f = getFolder(rootFolder, r);
57 result.put(f.getAbsolutePath(), r);
59 return result.values();
62 private Collection<Resource> sortedResources(File rootFolder) {
63 TreeMap<String,Resource> result = new TreeMap<>();
64 for(Resource r : parents.keySet()) {
65 byte[] dump = contentDumps.get(r);
67 dump = "".getBytes(StandardCharsets.UTF_8);
70 File f = new File(getFolder(rootFolder, r), "__contents__");
71 result.put(f.getAbsolutePath(), r);
74 File f = getFile(rootFolder, r);
75 result.put(f.getAbsolutePath(), r);
78 return result.values();
81 private void readHierarchy(ReadGraph graph, Resource container) throws DatabaseException {
82 Layer0 L0 = Layer0.getInstance(graph);
83 for(Resource r : CommonDBUtils.objectsWithType(graph, container, L0.ConsistsOf, L0.Entity)) {
85 readNameAndParent(graph, container, r);
86 readHierarchy(graph, r);
87 } catch (DatabaseException e) {
88 LOGGER.error("Error while reading content dump hierarchy for " + r, e);
93 private void readGeneric(ReadGraph graph) throws DatabaseException {
94 ModelingResources MOD = ModelingResources.getInstance(graph);
95 for(Resource r : parents.keySet()) {
96 if(contentDumps.containsKey(r))
98 TByteArrayList result = new TByteArrayList();
100 TreeMap<String,Resource> sortedTypes = new TreeMap<>();
101 for(Resource type : graph.getTypes(r)) {
102 String uri = graph.getPossibleURI(type);
104 sortedTypes.put(uri, type);
106 for(Resource type : sortedTypes.values()) {
108 Variable typeVariable = Variables.getVariable(graph, type);
109 @SuppressWarnings("rawtypes")
110 Function f = typeVariable.getPossiblePropertyValue(graph, MOD.contentDumpFunction);
112 @SuppressWarnings("unchecked")
113 byte[] dump = (byte[])Simantics.applySCLRead(graph, f, r);
118 } catch (DatabaseException e) {
119 LOGGER.error("Error while computing content dump for " + r, e);
122 if(result.size() > 0)
123 contentDumps.put(r, result.toArray());
124 } catch (DatabaseException e) {
125 LOGGER.error("Error while computing content dump for " + r, e);
130 public DumpOntologyStructure read(ReadGraph graph, Resource ontology) throws DatabaseException {
131 this.ontology = ontology;
132 readHierarchy(graph, ontology);
137 private File escapeFile(File file) {
140 return new File(escapeFile(file.getParentFile()), FileUtils.escapeFileName(file.getName()));
143 public void write(File unsafeFolder) throws IOException {
144 File folder = escapeFile(unsafeFolder);
145 FileUtils.delete(folder.toPath());
146 folder.getParentFile().mkdirs();
147 writeDirectories(folder);
148 writeResources(folder);
151 Resource getParent(Resource r) {
152 return parents.get(r);
155 private File getFolder(File root, Resource library) {
156 if(ontology.equals(library))
158 Resource parent = getParent(library);
160 throw new IllegalStateException("null parent for " + library);
161 File parentFolder = getFolder(root, parent);
162 return new File(parentFolder, names.get(library));
165 private File getFile(File rootFolder, Resource r) {
166 Resource parent = getParent(r);
167 File folder = getFolder(rootFolder, parent);
168 return new File(folder, names.get(r));
171 private File makeUnique(File original, Resource r) {
173 File file = new File(original.getParent(), original.getName());
175 while(test.exists()) {
176 // Here we have a name clash with small and big letters! (windows)
177 test = new File(file.getParent(), file.getName() + "____" + (counter++));
179 // Enforce this renaming in future operations also
180 names.put(r, test.getName());
184 private void writeDirectories(File rootFolder) {
185 // Here stuff shall be returned in alphabetical order
186 for(Resource library : sortedContainers(rootFolder)) {
187 File folder = makeUnique(getFolder(rootFolder, library), library);
189 libraryFolders.put(library, folder);
193 private void writeResources(File rootFolder) throws IOException {
194 // Here stuff shall be returned in alphabetical order
195 for(Resource r : sortedResources(rootFolder)) {
196 writeResource(rootFolder, r);
200 private boolean isParent(Resource r) {
201 return parents.values().contains(r);
204 private void writeResource(File rootFolder, Resource resource) throws IOException {
205 byte[] dump = contentDumps.get(resource);
207 dump = "".getBytes(StandardCharsets.UTF_8);
208 if(isParent(resource)) {
210 FileUtils.writeFile(new File(getFolder(rootFolder, resource), "__contents__"), dump);
212 write(rootFolder, resource, dump);
216 private void write(File rootFolder, Resource resource, byte[] bytes) throws IOException {
217 FileUtils.writeFile(makeUnique(getFile(rootFolder, resource), resource), bytes);