import java.io.File;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
-import org.simantics.databoard.Bindings;
+import org.simantics.Simantics;
import org.simantics.db.ReadGraph;
import org.simantics.db.Resource;
-import org.simantics.db.common.NamedResource;
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.graphfile.ontology.GraphFileResource;
import org.simantics.layer0.Layer0;
-import org.simantics.structural.stubs.StructuralResource2;
-import org.simantics.structural2.variables.Connection;
-import org.simantics.structural2.variables.VariableConnectionPointDescriptor;
+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 Set<Resource> containers = new HashSet<>();
- private Set<Resource> folders = new HashSet<>();
+
private Map<Resource, String> names = new HashMap<>();
- private Map<Resource,Resource> parents = new HashMap<>();
+ private Map<Resource,Resource> parents = new TreeMap<>();
private Map<Resource, File> libraryFolders = new HashMap<>();
- private Set<Resource> modules = new HashSet<>();
- private Map<Resource, String> moduleCodes = new HashMap<>();
- private Set<Resource> pgraphs = new HashSet<>();
- private Map<Resource, String> pgraphCodes = new HashMap<>();
- private Set<Resource> graphFiles = new HashSet<>();
- private Map<Resource, byte[]> graphFileBytes = new HashMap<>();
- private Set<Resource> componentTypes = new HashSet<>();
- private Map<Resource, String> componentTypeDumps = new HashMap<>();
- private Set<Resource> components = new HashSet<>();
- private Map<Resource, String> componentDumps = new HashMap<>();
+ private Map<Resource, byte[]> contentDumps = new HashMap<>();
private void readNameAndParent(ReadGraph graph, Resource container, Resource r) throws DatabaseException {
+ String name = NameUtils.getSafeName(graph, r);
parents.put(r, container);
- names.put(r, NameUtils.getSafeName(graph, r));
- }
-
- private void readLibraries(ReadGraph graph, Resource container) throws DatabaseException {
- Layer0 L0 = Layer0.getInstance(graph);
- for(Resource r : CommonDBUtils.objectsWithType(graph, container, L0.ConsistsOf, L0.Library)) {
- folders.add(r);
- names.put(r, NameUtils.getSafeName(graph, r));
- parents.put(r, container);
- readNameAndParent(graph, container, r);
- readLibraries(graph, r);
+ names.put(r, FileUtils.escapeFileName(name));
+ }
+
+ /*
+ * This shall return containers sorted by full path.
+ * This makes processing order stable and ensures that
+ * directories are processed before their contents.
+ */
+ private Collection<Resource> sortedContainers(File rootFolder) {
+ Set<Resource> parentSet = new HashSet<Resource>(parents.values());
+ TreeMap<String,Resource> result = new TreeMap<>();
+ for(Resource r : parentSet) {
+ File f = getFolder(rootFolder, r);
+ result.put(f.getAbsolutePath(), r);
}
- containers.addAll(folders);
- }
-
- private void readComponentTypes(ReadGraph graph) throws DatabaseException {
- Layer0 L0 = Layer0.getInstance(graph);
- StructuralResource2 STR = StructuralResource2.getInstance(graph);
- for(Resource container : containers) {
- for(Resource r : CommonDBUtils.objectsWithType(graph, container, L0.ConsistsOf, STR.ComponentType)) {
- folders.add(r);
- componentTypes.add(r);
- readNameAndParent(graph, container, r);
- ComponentTypePropertiesResult data = graph.syncRequest(new HeadlessComponentTypePropertiesResultRequest(r));
- StringBuilder dump = new StringBuilder();
- for(ComponentTypeViewerPropertyInfo pi : data.getProperties()) {
- dump.append(pi.name);
- dump.append(" ");
- dump.append(pi.type);
- dump.append(" ");
- dump.append(pi.defaultValue);
- if(pi.unit != null) {
- dump.append(" ");
- dump.append(pi.unit);
- }
- dump.append(" ");
- dump.append(pi.label);
- if(pi.description != null) {
- dump.append(" ");
- dump.append(pi.description);
- }
- dump.append("\n");
- }
- for(NamedResource nr : data.getConnectionPoints()) {
- dump.append("cp ");
- dump.append(nr.getName());
- dump.append("\n");
+ return result.values();
+ }
+
+ private Collection<Resource> sortedResources(File rootFolder) {
+ TreeMap<String,Resource> result = new TreeMap<>();
+ for(Resource r : parents.keySet()) {
+ byte[] dump = contentDumps.get(r);
+ if(dump == null)
+ dump = "".getBytes(StandardCharsets.UTF_8);
+ if(isParent(r)) {
+ if(dump.length > 0) {
+ File f = new File(getFolder(rootFolder, r), "__contents__");
+ result.put(f.getAbsolutePath(), r);
}
- componentTypeDumps.put(r, dump.toString());
+ } else {
+ File f = getFile(rootFolder, r);
+ result.put(f.getAbsolutePath(), r);
}
}
- containers.addAll(folders);
+ return result.values();
}
- private void readComposites(ReadGraph graph) throws DatabaseException {
+ private void readHierarchy(ReadGraph graph, Resource container) throws DatabaseException {
Layer0 L0 = Layer0.getInstance(graph);
- StructuralResource2 STR = StructuralResource2.getInstance(graph);
- for(Resource container : containers) {
- for(Resource r : CommonDBUtils.objectsWithType(graph, container, L0.ConsistsOf, STR.Composite)) {
- folders.add(r);
+ 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);
}
}
- containers.addAll(folders);
}
- private void readComponents(ReadGraph graph) throws DatabaseException {
- Layer0 L0 = Layer0.getInstance(graph);
- StructuralResource2 STR = StructuralResource2.getInstance(graph);
- for(Resource container : containers) {
- for(Resource r : CommonDBUtils.objectsWithType(graph, container, L0.ConsistsOf, STR.Component)) {
- if(folders.contains(r))
- continue;
- components.add(r);
- readNameAndParent(graph, container, r);
- Variable v = Variables.getVariable(graph, r);
- TreeMap<String,Variable> properties = new TreeMap<>();
- for(Variable property : v.getProperties(graph))
- properties.put(property.getName(graph), property);
- StringBuilder dump = new StringBuilder();
- for(Variable property : properties.values()) {
- String possibleValue = property.getPossiblePropertyValue(graph, "HasDisplayValue", Bindings.STRING);
- if(possibleValue != null) {
- dump.append(property.getName(graph));
- dump.append(" ");
- dump.append(possibleValue);
- dump.append("\n");
- }
- if(property.getClassifications(graph).contains(StructuralResource2.URIs.ConnectionRelation)) {
- dump.append(property.getName(graph));
- Connection c = property.getValue(graph);
- for(VariableConnectionPointDescriptor desc : c.getConnectionPointDescriptors(graph, null)) {
- dump.append(" ");
- dump.append(desc.getRelativeRVI(graph, v));
+ 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<String,Resource> 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);
+ }
}
- dump.append("\n");
+ } catch (DatabaseException e) {
+ LOGGER.error("Error while computing content dump for " + r, e);
}
}
- componentDumps.put(r, dump.toString());
- }
- }
- }
-
- private void readSCLModules(ReadGraph graph) throws DatabaseException {
- Layer0 L0 = Layer0.getInstance(graph);
- for(Resource container : containers) {
- for(Resource r : CommonDBUtils.objectsWithType(graph, container, L0.ConsistsOf, L0.SCLModule)) {
- String code = graph.getPossibleRelatedValue(r, L0.SCLModule_definition, Bindings.STRING);
- if(code != null) {
- moduleCodes.put(r, code);
- }
- modules.add(r);
- readNameAndParent(graph, container, r);
- }
- }
- }
-
- private void readPGraphs(ReadGraph graph) throws DatabaseException {
- Layer0 L0 = Layer0.getInstance(graph);
- for(Resource container : containers) {
- for(Resource r : CommonDBUtils.objectsWithType(graph, container, L0.ConsistsOf, L0.PGraph)) {
- String code = graph.getPossibleRelatedValue(r, L0.PGraph_definition, Bindings.STRING);
- if(code != null) {
- pgraphCodes.put(r, code);
- }
- pgraphs.add(r);
- readNameAndParent(graph, container, r);
+ if(result.size() > 0)
+ contentDumps.put(r, result.toArray());
+ } catch (DatabaseException e) {
+ LOGGER.error("Error while computing content dump for " + r, e);
}
}
}
- private void readGraphFiles(ReadGraph graph) throws DatabaseException {
- Layer0 L0 = Layer0.getInstance(graph);
- GraphFileResource GF = GraphFileResource.getInstance(graph);
- for(Resource container : containers) {
- for(Resource r : CommonDBUtils.objectsWithType(graph, container, L0.ConsistsOf, GF.File)) {
- byte[] bytes = graph.getPossibleRelatedValue(r, GF.HasFiledata, Bindings.BYTE_ARRAY);
- if(bytes != null) {
- graphFileBytes.put(r, bytes);
- }
- graphFiles.add(r);
- readNameAndParent(graph, container, r);
- }
- }
- }
-
- public void read(ReadGraph graph, Resource ontology) throws DatabaseException {
+ public DumpOntologyStructure read(ReadGraph graph, Resource ontology) throws DatabaseException {
this.ontology = ontology;
- containers.add(ontology);
- readLibraries(graph, ontology);
- readComponentTypes(graph);
- readComposites(graph);
- readComponents(graph);
- readSCLModules(graph);
- readPGraphs(graph);
- readGraphFiles(graph);
+ readHierarchy(graph, ontology);
+ readGeneric(graph);
+ return this;
}
-
- private File escapeFile(File file) {
+ 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);
- if(folder.exists())
- FileUtils.deleteAll(folder);
- folder.mkdirs();
- writeLibraries(folder);
- writeSCLModules(folder);
- writePGraphs(folder);
- writeGraphFiles(folder);
- writeComponentTypes(folder);
- writeComponents(folder);
+ FileUtils.delete(folder.toPath());
+ folder.getParentFile().mkdirs();
+ writeDirectories(folder);
+ writeResources(folder);
+ }
+
+ Resource getParent(Resource r) {
+ return parents.get(r);
}
private File getFolder(File root, Resource library) {
if(ontology.equals(library))
return root;
- Resource parent = parents.get(library);
+ Resource parent = getParent(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 getParentFolder(File root, Resource r) {
- Resource parent = parents.get(r);
- return getFolder(root, parent);
+ return new File(parentFolder, names.get(library));
}
- private File getFile(File root, Resource r) {
- return new File(getParentFolder(root, r), FileUtils.escapeFileName(names.get(r)));
+ private File getFile(File rootFolder, Resource r) {
+ Resource parent = getParent(r);
+ File folder = getFolder(rootFolder, parent);
+ return new File(folder, names.get(r));
}
- private void writeLibraries(File rootFolder) {
- for(Resource library : folders) {
- File folder = getFolder(rootFolder, library);
- folder.mkdirs();
- libraryFolders.put(library, folder);
+ private File makeUnique(File original, Resource r) {
+ int counter = 2;
+ File file = new File(original.getParent(), original.getName());
+ File test = file;
+ while(test.exists()) {
+ // Here we have a name clash with small and big letters! (windows)
+ test = new File(file.getParent(), file.getName() + "____" + (counter++));
}
+ // Enforce this renaming in future operations also
+ names.put(r, test.getName());
+ return test;
}
- private void writeSCLModules(File rootFolder) throws IOException {
- for(Resource r : modules) {
- FileUtils.writeFile(getFile(rootFolder, r), moduleCodes.get(r).getBytes());
+ private void writeDirectories(File rootFolder) {
+ // Here stuff shall be returned in alphabetical order
+ for(Resource library : sortedContainers(rootFolder)) {
+ File folder = makeUnique(getFolder(rootFolder, library), library);
+ folder.mkdirs();
+ libraryFolders.put(library, folder);
}
}
-
- private void writePGraphs(File rootFolder) throws IOException {
- for(Resource r : pgraphs) {
- FileUtils.writeFile(getFile(rootFolder, r), pgraphCodes.get(r).getBytes());
+
+ private void writeResources(File rootFolder) throws IOException {
+ // Here stuff shall be returned in alphabetical order
+ for(Resource r : sortedResources(rootFolder)) {
+ writeResource(rootFolder, r);
}
}
- private void writeGraphFiles(File rootFolder) throws IOException {
- for(Resource r : graphFiles) {
- FileUtils.writeFile(getFile(rootFolder, r), graphFileBytes.get(r));
- }
+ private boolean isParent(Resource r) {
+ return parents.values().contains(r);
}
- private void writeComponentTypes(File rootFolder) throws IOException {
- for(Resource r : componentTypes) {
- File folder = getFolder(rootFolder, r);
- File file = new File(folder, "__interface__");
- FileUtils.writeFile(file, componentTypeDumps.get(r).getBytes());
+ 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 writeComponents(File rootFolder) throws IOException {
- for(Resource r : components) {
- FileUtils.writeFile(getFile(rootFolder, r), componentDumps.get(r).getBytes());
- }
+ private void write(File rootFolder, Resource resource, byte[] bytes) throws IOException {
+ FileUtils.writeFile(makeUnique(getFile(rootFolder, resource), resource), bytes);
}
-
-}
+
+}
\ No newline at end of file