package org.simantics.modeling.utils; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import org.simantics.Simantics; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.utils.CommonDBUtils; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingResources; import org.simantics.scl.runtime.function.Function; import org.simantics.utils.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import gnu.trove.list.array.TByteArrayList; public class DumpOntologyStructure { private static final Logger LOGGER = LoggerFactory.getLogger(DumpOntologyStructure.class); private Resource ontology; private Map names = new HashMap<>(); private Map parents = new HashMap<>(); private Map libraryFolders = new HashMap<>(); private Map contentDumps = new HashMap<>(); private void readNameAndParent(ReadGraph graph, Resource container, Resource r) throws DatabaseException { parents.put(r, container); names.put(r, NameUtils.getSafeName(graph, r)); } private Collection containers() { return parents.values(); } private void readHierarchy(ReadGraph graph, Resource container) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); for(Resource r : CommonDBUtils.objectsWithType(graph, container, L0.ConsistsOf, L0.Entity)) { try { readNameAndParent(graph, container, r); readHierarchy(graph, r); } catch (DatabaseException e) { LOGGER.error("Error while reading content dump hierarchy for " + r, e); } } } private void readGeneric(ReadGraph graph) throws DatabaseException { ModelingResources MOD = ModelingResources.getInstance(graph); for(Resource r : parents.keySet()) { if(contentDumps.containsKey(r)) continue; TByteArrayList result = new TByteArrayList(); try { TreeMap sortedTypes = new TreeMap<>(); for(Resource type : graph.getTypes(r)) { String uri = graph.getPossibleURI(type); if(uri != null) sortedTypes.put(uri, type); } for(Resource type : sortedTypes.values()) { try { Variable typeVariable = Variables.getVariable(graph, type); @SuppressWarnings("rawtypes") Function f = typeVariable.getPossiblePropertyValue(graph, MOD.contentDumpFunction); if(f != null) { @SuppressWarnings("unchecked") byte[] dump = (byte[])Simantics.applySCLRead(graph, f, r); if(dump != null) { result.add(dump); } } } catch (DatabaseException e) { LOGGER.error("Error while computing content dump for " + r, e); } } if(result.size() > 0) contentDumps.put(r, result.toArray()); } catch (DatabaseException e) { LOGGER.error("Error while computing content dump for " + r, e); } } } public DumpOntologyStructure read(ReadGraph graph, Resource ontology) throws DatabaseException { this.ontology = ontology; readHierarchy(graph, ontology); readGeneric(graph); return this; } private File escapeFile(File file) { if(file.exists()) return file; return new File(escapeFile(file.getParentFile()), FileUtils.escapeFileName(file.getName())); } public void write(File unsafeFolder) throws IOException { File folder = escapeFile(unsafeFolder); FileUtils.delete(folder.toPath()); folder.mkdirs(); writeDirectories(folder); writeResources(folder); } private File getFolder(File root, Resource library) { if(ontology.equals(library)) return root; Resource parent = parents.get(library); if(parent == null) throw new IllegalStateException("null parent for " + library); File parentFolder = getFolder(root, parent); return new File(parentFolder, FileUtils.escapeFileName(names.get(library))); } private File getFile(File rootFolder, Resource r) { Resource parent = parents.get(r); File folder = getFolder(rootFolder, parent); return new File(folder, FileUtils.escapeFileName(names.get(r))); } private void writeDirectories(File rootFolder) { for(Resource library : containers()) { File folder = getFolder(rootFolder, library); folder.mkdirs(); libraryFolders.put(library, folder); } } private void writeResources(File rootFolder) throws IOException { for(Resource r : parents.keySet()) { writeResource(rootFolder, r); } } private boolean isParent(Resource r) { return parents.values().contains(r); } private void writeResource(File rootFolder, Resource resource) throws IOException { byte[] dump = contentDumps.get(resource); if(dump == null) dump = "".getBytes(StandardCharsets.UTF_8); if(isParent(resource)) { if(dump.length > 0) FileUtils.writeFile(new File(getFolder(rootFolder, resource), "__contents__"), dump); } else { write(rootFolder, resource, dump); } } private void write(File rootFolder, Resource resource, byte[] bytes) throws IOException { FileUtils.writeFile(getFile(rootFolder, resource), bytes); } }