-/*******************************************************************************\r
- * Copyright (c) 2013 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.graphfile.util;\r
-\r
-import java.io.File;\r
-import java.io.FileInputStream;\r
-import java.io.FileOutputStream;\r
-import java.io.IOException;\r
-import java.nio.ByteBuffer;\r
-import java.nio.channels.FileChannel;\r
-import java.nio.file.Path;\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.Map;\r
-\r
-import org.simantics.Simantics;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.util.binary.RandomAccessBinary;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.request.ReadRequest;\r
-import org.simantics.db.common.request.WriteRequest;\r
-import org.simantics.db.common.request.WriteResultRequest;\r
-import org.simantics.db.common.utils.LiteralFileUtil;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.DoesNotContainValueException;\r
-import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;\r
-import org.simantics.db.exception.NoSingleResultException;\r
-import org.simantics.db.exception.ServiceException;\r
-import org.simantics.db.request.Read;\r
-import org.simantics.db.service.ClusteringSupport;\r
-import org.simantics.graphfile.ontology.GraphFileResource;\r
-import org.simantics.layer0.Layer0;\r
-\r
-/**\r
- * @author Marko Luukkainen\r
- */\r
-public class GraphFileUtil {\r
- \r
- \r
- public static boolean USE_RANDOM_ACCESS_BINARY = true;\r
- /**\r
- * Creates a temp file of a graphFile.\r
- * @param res\r
- * @return\r
- * @throws DatabaseException\r
- */\r
- public static File toTempFile(final Resource res)throws DatabaseException {\r
- return Simantics.getSession().syncRequest(new Read<File>() {\r
- @Override\r
- public File perform(ReadGraph graph) throws DatabaseException {\r
- return toTempFile(graph, res);\r
- }\r
- });\r
- }\r
-\r
- /**\r
- * Creates a temp file of a graphFile.\r
- * @param graph\r
- * @param res\r
- * @return\r
- * @throws DatabaseException\r
- */\r
- public static File toTempFile(ReadGraph graph, Resource res)throws DatabaseException {\r
-\r
- GraphFileResource gf = GraphFileResource.getInstance(graph);\r
- String filename = graph.getRelatedValue(res, gf.HasResourceName);\r
- \r
- int index = filename.lastIndexOf(".");\r
- String name = "";\r
- String ext = "";\r
- if (index > 0) {\r
- name = filename.substring(0,index);\r
- ext = filename.substring(index+1);\r
- } else {\r
- name = filename;\r
- }\r
- if (name.length() < 3) {\r
- for (int i = name.length(); i < 3; i++)\r
- name += "_";\r
- }\r
- try {\r
- File file = File.createTempFile(name, "."+ ext);\r
- writeDataToFile(graph, res, file);\r
- return file;\r
- } catch (Exception e) {\r
- throw new DatabaseException(e);\r
- }\r
- }\r
- \r
- public static void writeDataToFile(final Resource res, final File file) throws DatabaseException{\r
- Simantics.getSession().syncRequest(new ReadRequest() {\r
- \r
- @Override\r
- public void run(ReadGraph graph) throws DatabaseException {\r
- try {\r
- writeDataToFile(graph, res, file);\r
- } catch (IOException e) {\r
- throw new DatabaseException(e);\r
- }\r
- }\r
- });\r
- }\r
- \r
- /**\r
- * Writes contents of a graphFile to file.\r
- * @param graph\r
- * @param res\r
- * @param file\r
- * @throws DatabaseException\r
- * @throws IOException\r
- */\r
- public static void writeDataToFile(ReadGraph graph, Resource res, File file) throws DatabaseException, IOException {\r
- \r
- GraphFileResource gf = GraphFileResource.getInstance(graph);\r
- if (USE_RANDOM_ACCESS_BINARY) {\r
- Resource filedata = graph.getSingleObject(res, gf.HasFiledata);\r
- LiteralFileUtil.copyRandomAccessBinaryToFile(graph, filedata, file);\r
- } else {\r
- \r
- byte[] data = graph.getRelatedValue(res, gf.HasFiledata);\r
- FileOutputStream fos = new FileOutputStream(file);\r
- fos.write(data);\r
- fos.flush();\r
- fos.close();\r
- \r
- }\r
- Long lastModified = graph.getPossibleRelatedValue(res, gf.LastModified);\r
- if (lastModified != null)\r
- file.setLastModified(lastModified);\r
- }\r
-\r
- /**\r
- * Updates contents of a graphFile, including the name.\r
- * @param filename\r
- * @param graphFile\r
- * @throws DatabaseException\r
- */\r
- public static void toGraph(final String filename, final Resource graphFile)throws DatabaseException {\r
- Simantics.getSession().syncRequest(new WriteRequest() {\r
- @Override\r
- public void perform(WriteGraph graph) throws DatabaseException {\r
- try {\r
- toGraph(graph, filename,graphFile);\r
- } catch (IOException e) {\r
- throw new DatabaseException(e);\r
- }\r
- }\r
- });\r
- }\r
- \r
- /**\r
- * Updates contents of a graphFile, including the name.\r
- * @param graph\r
- * @param filename\r
- * @param graphFile\r
- * @throws DatabaseException\r
- * @throws IOException\r
- */\r
- public static void toGraph(WriteGraph graph, String filename, Resource graphFile) throws DatabaseException, IOException {\r
- File file = new File(filename);\r
- if (!file.exists())\r
- throw new IOException("File " + filename + " not found.");\r
- \r
- toGraph(graph, file, graphFile);\r
- }\r
- \r
- /**\r
- * Updates contents of a graphFile, including the name.\r
- * @param graph\r
- * @param file\r
- * @param graphFile\r
- * @throws DatabaseException\r
- * @throws IOException\r
- */\r
- public static void toGraph(WriteGraph graph, File file, Resource graphFile) throws DatabaseException, IOException {\r
-\r
- writeDataToGraph(graph, file, graphFile);\r
- String name = file.getName();\r
- GraphFileResource gf = GraphFileResource.getInstance(graph);\r
- graph.claimLiteral(graphFile, gf.HasResourceName, name);\r
- \r
- }\r
- \r
- /**\r
- * Writes contents of a file to a graphFile (data and time stamp).\r
- * @param graph\r
- * @param file\r
- * @param graphFile\r
- * @throws IOException\r
- * @throws ManyObjectsForFunctionalRelationException\r
- * @throws ServiceException\r
- */\r
- public static void writeDataToGraph(WriteGraph graph, File file, Resource graphFile) throws IOException, DatabaseException{\r
- GraphFileResource gf = GraphFileResource.getInstance(graph);\r
- if (USE_RANDOM_ACCESS_BINARY) {\r
- \r
- Resource fileData = graph.getPossibleObject(graphFile, gf.HasFiledata);\r
- RandomAccessBinary rab = null;\r
- if (fileData == null) {\r
- Layer0 l0 = Layer0.getInstance(graph);\r
- ClusteringSupport cs = graph.getService(ClusteringSupport.class);\r
- fileData = graph.newResource(cs.createCluster());\r
- graph.claim(fileData, l0.InstanceOf, l0.ByteArray);\r
- graph.claim(graphFile, gf.HasFiledata, fileData);\r
- rab = graph.createRandomAccessBinary(fileData, Bindings.BYTE_ARRAY.type(), null);\r
- } else {\r
- rab = graph.getRandomAccessBinary(fileData);\r
- }\r
- LiteralFileUtil.copyRandomAccessBinaryFromFile(file, rab);\r
- } else {\r
- FileInputStream stream = new FileInputStream(file);\r
- FileChannel chan = stream.getChannel();\r
- long lsize = chan.size();\r
- if (lsize > Integer.MAX_VALUE)\r
- throw new IOException("File is too big");\r
- int size = (int)lsize;\r
- final byte[] array = new byte[size];\r
- ByteBuffer buf = ByteBuffer.wrap(array);\r
- while (size > 0)\r
- size -= chan.read(buf);\r
- \r
- graph.claimLiteral(graphFile, gf.HasFiledata, array);\r
- chan.close();\r
- stream.close();\r
- }\r
-\r
- graph.claimLiteral(graphFile, gf.LastModified, file.lastModified());\r
- \r
- }\r
- \r
- public static void writeDataToGraph(WriteGraph graph, byte data[], Resource graphFile) throws IOException, ManyObjectsForFunctionalRelationException, ServiceException {\r
- \r
- GraphFileResource gf = GraphFileResource.getInstance(graph);\r
- graph.claimLiteral(graphFile, gf.HasFiledata, data);\r
- graph.claimLiteral(graphFile, gf.LastModified, 0L);\r
- }\r
- \r
- /**\r
- * Writes contents of a file to a graphFile (data and time stamp).\r
- * @param file\r
- * @param graphFile\r
- * @throws DatabaseException\r
- */\r
- public static void writeDataToGraph(final File file, final Resource graphFile) throws DatabaseException {\r
- Simantics.getSession().syncRequest(new WriteRequest() {\r
- \r
- @Override\r
- public void perform(WriteGraph graph) throws DatabaseException {\r
- try {\r
- writeDataToGraph(graph, file, graphFile);\r
- } catch (IOException e) {\r
- throw new DatabaseException(e);\r
- }\r
- \r
- }\r
- });\r
- }\r
- \r
- public static void syncFolderToGraph(WriteGraph g, File folder, Resource folderRes) throws Exception {\r
- File subFiles[] = folder.listFiles();\r
- Layer0 l0 = Layer0.getInstance(g);\r
- GraphFileResource gf = GraphFileResource.getInstance(g);\r
- Collection<Resource> subFileResources = g.getObjects(folderRes, gf.HasFile);\r
- Collection<Resource> subFolderResources = g.getObjects(folderRes, gf.HasFolder);\r
- \r
- Map<Resource,File> matching = new HashMap<Resource, File>();\r
- \r
- for (File f : subFiles) {\r
- String name = f.getName();\r
- if (f.isDirectory()) {\r
- Resource matchingFolder = findWithName(g, subFolderResources, name);\r
-\r
- if (matchingFolder != null) {\r
- if (matching.containsKey(matchingFolder))\r
- throw new Exception("Matching folder already in use" + f.getAbsolutePath() + " " + matchingFolder);\r
- \r
- matching.put(matchingFolder, f);\r
- syncFolderToGraph(g, f, matchingFolder);\r
- } else {\r
- matchingFolder = g.newResource();\r
- g.claim(matchingFolder, l0.InstanceOf, gf.Folder);\r
- g.claimLiteral(matchingFolder, gf.HasResourceName, name);\r
- g.claimLiteral(matchingFolder, l0.HasName, name);\r
- g.claim(folderRes, gf.HasFolder, matchingFolder);\r
- matching.put(matchingFolder, f);\r
- syncFolderToGraph(g, f, matchingFolder);\r
- }\r
- } else { //file\r
- Resource fileRes = findWithName(g, subFileResources, name);\r
- if (fileRes != null) {\r
- if (matching.containsKey(fileRes))\r
- throw new Exception("Matching file already in use" + f.getAbsolutePath() + " " + fileRes);\r
- matching.put(fileRes, f);\r
- toGraph(g, f, fileRes);\r
- } else {\r
- fileRes = g.newResource();\r
- g.claim(fileRes, l0.InstanceOf, gf.File);\r
- g.claimLiteral(fileRes, gf.HasResourceName, name);\r
- g.claimLiteral(fileRes, l0.HasName, name);\r
- g.claim(folderRes, gf.HasFile, fileRes);\r
- matching.put(fileRes, f);\r
- toGraph(g, f, fileRes);\r
- }\r
- }\r
- }\r
- // delete resources, which have no matching file (or folder)\r
- for (Resource subFolder : subFolderResources) {\r
- if (!matching.containsKey(subFolder))\r
- g.deny(subFolder);\r
- }\r
- \r
- for (Resource subFolder : subFileResources) {\r
- if (!matching.containsKey(subFolder))\r
- g.deny(subFolder);\r
- }\r
- }\r
- \r
- public static void writeFolderToDisk(ReadGraph g, Resource folderRes, File folder) throws DatabaseException, IOException{\r
-\r
- GraphFileResource gf = GraphFileResource.getInstance(g);\r
- for (Resource subFolder : g.getObjects(folderRes, gf.HasFolder)) {\r
- String name = g.getRelatedValue(subFolder, gf.HasResourceName);\r
-\r
- if (name.length() == 0)\r
- throw new DatabaseException("Empty folder name for " + subFolder);\r
- \r
- File newFolder = new File(folder.getAbsolutePath() + "/" + name);\r
- if (!newFolder.mkdir()) {\r
- throw new DatabaseException("Could not create folder " + name + " for resource " + subFolder);\r
- }\r
- writeFolderToDisk(g, subFolder, newFolder);\r
- }\r
- for (Resource fileRes : g.getObjects(folderRes, gf.HasFile)) {\r
- String name = g.getRelatedValue(fileRes, gf.HasResourceName);\r
- File file = new File(folder.getAbsolutePath() + "/" + name);\r
- writeDataToFile(g, fileRes, file);\r
- }\r
- }\r
- \r
- public static void syncFolderToGraph(WriteGraph g, File folder, Resource folderRes, ToGraphHelper helper) throws Exception {\r
- File subFiles[] = folder.listFiles();\r
- GraphFileResource gf = GraphFileResource.getInstance(g);\r
- Collection<Resource> subFileResources = g.getObjects(folderRes, gf.HasFile);\r
- Collection<Resource> subFolderResources = g.getObjects(folderRes, gf.HasFolder);\r
- \r
- Map<Resource,File> matching = new HashMap<Resource, File>();\r
- \r
- for (File f : subFiles) {\r
- String name = f.getName();\r
- if (f.isDirectory()) {\r
- Resource matchingFolder = helper.findFolder(g, subFolderResources, name);\r
-\r
- if (matchingFolder != null) {\r
- if (matching.containsKey(matchingFolder))\r
- throw new Exception("Matching folder already in use" + f.getAbsolutePath() + " " + matchingFolder);\r
- \r
- matching.put(matchingFolder, f);\r
- syncFolderToGraph(g, f, matchingFolder,helper);\r
- } else {\r
- matchingFolder = helper.createFolder(g, name);\r
- g.claim(folderRes, gf.HasFolder, matchingFolder);\r
- matching.put(matchingFolder, f);\r
- syncFolderToGraph(g, f, matchingFolder,helper);\r
- }\r
- } else { //file\r
- Resource fileRes = helper.findFile(g, subFileResources, name);\r
- if (fileRes != null) {\r
- if (matching.containsKey(fileRes))\r
- throw new Exception("Matching file already in use" + f.getAbsolutePath() + " " + fileRes);\r
- matching.put(fileRes, f);\r
- toGraph(g, f, fileRes);\r
- } else {\r
- fileRes = helper.createFile(g, name);\r
- g.claim(folderRes, gf.HasFile, fileRes);\r
- matching.put(fileRes, f);\r
- toGraph(g, f, fileRes);\r
- }\r
- }\r
- }\r
- // delete resources, which have no matching file (or folder)\r
- for (Resource subFolder : subFolderResources) {\r
- if (!matching.containsKey(subFolder))\r
- g.deny(subFolder);\r
- }\r
- \r
- for (Resource subFolder : subFileResources) {\r
- if (!matching.containsKey(subFolder))\r
- g.deny(subFolder);\r
- }\r
- }\r
- \r
- public static interface ToGraphHelper {\r
- public Resource findFolder(ReadGraph g, Collection<Resource> subFolderResources, String name) throws DatabaseException;\r
- public Resource createFolder(WriteGraph g, String name) throws DatabaseException;\r
- public Resource findFile(ReadGraph g, Collection<Resource> subFileResources, String name) throws DatabaseException;\r
- public Resource createFile(WriteGraph g, String name) throws DatabaseException;\r
- }\r
- \r
- public static interface ToDiskHelper {\r
- public String getName(ReadGraph g, Resource systemResource) throws DatabaseException;\r
- }\r
- \r
- public static void writeFolderToDisk(ReadGraph g, Resource folderRes, File folder, ToDiskHelper helper) throws DatabaseException, IOException{\r
- GraphFileResource gf = GraphFileResource.getInstance(g);\r
- for (Resource subFolder : g.getObjects(folderRes, gf.HasFolder)) {\r
- String name = helper.getName(g, subFolder);\r
-\r
- if (name.length() == 0)\r
- throw new DatabaseException("Empty folder name for " + subFolder);\r
- \r
- File newFolder = new File(folder.getAbsolutePath() + "/" + name);\r
- if (!newFolder.mkdir()) {\r
- throw new DatabaseException("Could not create folder " + name + " for resource " + subFolder);\r
- }\r
- writeFolderToDisk(g, subFolder, newFolder, helper);\r
- }\r
- for (Resource fileRes : g.getObjects(folderRes, gf.HasFile)) {\r
- String name = helper.getName(g, fileRes);\r
- File file = new File(folder.getAbsolutePath() + "/" + name);\r
- writeDataToFile(g, fileRes, file);\r
- }\r
- }\r
- \r
- public static interface ToDiskHelper2 extends ToDiskHelper {\r
- public Resource findFolder(ReadGraph g, Collection<Resource> subFolderResources, String name) throws DatabaseException;\r
- public Resource findFile(ReadGraph g, Collection<Resource> subFileResources, String name) throws DatabaseException;\r
- }\r
- \r
- public static void syncFolderToDisk(ReadGraph g, Resource folderRes, File folder, ToDiskHelper2 helper) throws Exception {\r
- File subFiles[] = folder.listFiles();\r
- GraphFileResource gf = GraphFileResource.getInstance(g);\r
- Collection<Resource> subFileResources = g.getObjects(folderRes, gf.HasFile);\r
- Collection<Resource> subFolderResources = g.getObjects(folderRes, gf.HasFolder);\r
- \r
- Map<Resource,File> matching = new HashMap<Resource, File>();\r
- \r
- for (File f : subFiles) {\r
- String name = f.getName();\r
- if (f.isDirectory()) {\r
- Resource matchingFolder = helper.findFolder(g, subFolderResources, name);\r
-\r
- if (matchingFolder != null) {\r
- if (matching.containsKey(matchingFolder))\r
- throw new Exception("Matching folder already in use" + f.getAbsolutePath() + " " + matchingFolder);\r
- \r
- matching.put(matchingFolder, f);\r
- syncFolderToDisk(g, matchingFolder, f, helper);\r
- } else {\r
- deleteDirectoryStructure(f);\r
- }\r
- } else { //file\r
- Resource fileRes = helper.findFile(g, subFileResources, name);\r
- if (fileRes != null) {\r
- if (matching.containsKey(fileRes))\r
- throw new Exception("Matching file already in use" + f.getAbsolutePath() + " " + fileRes);\r
- matching.put(fileRes, f);\r
- writeDataToFile(g, fileRes, f);\r
- } else {\r
- if (!f.delete())\r
- throw new Exception("Cannot delete file " + f.getAbsolutePath());\r
- }\r
- }\r
- }\r
- // create files and folders, which have no matching graphFile (or folder)\r
- for (Resource subFolder : subFolderResources) {\r
- if (!matching.containsKey(subFolder)) {\r
- String name = helper.getName(g, subFolder);\r
-\r
- if (name.length() == 0)\r
- throw new DatabaseException("Empty folder name for " + subFolder);\r
- \r
- File newFolder = new File(folder.getAbsolutePath() + "/" + name);\r
- if (!newFolder.mkdir()) {\r
- throw new DatabaseException("Could not create folder " + name + " for resource " + subFolder);\r
- }\r
- writeFolderToDisk(g, subFolder, newFolder, helper);\r
- }\r
- }\r
- \r
- for (Resource fileRes : subFileResources) {\r
- if (!matching.containsKey(fileRes)) {\r
- String name = helper.getName(g, fileRes);\r
- File file = new File(folder.getAbsolutePath() + "/" + name);\r
- writeDataToFile(g, fileRes, file);\r
- }\r
- }\r
- \r
- }\r
- \r
- \r
- \r
- public static Resource findWithName(ReadGraph g, Collection<Resource> resources, String name) throws ServiceException, NoSingleResultException, DoesNotContainValueException {\r
- GraphFileResource gf = GraphFileResource.getInstance(g);\r
- for (Resource r : resources)\r
- if (name.equals(g.getRelatedValue(r, gf.HasResourceName)))\r
- return r;\r
- return null;\r
- }\r
- \r
- /**\r
- * Deletes the directory and all it contents.\r
- * @param dir\r
- * @throws Exception\r
- */\r
- public static void deleteDirectoryStructure(File dir) throws Exception{\r
- deleteDirectoryStructure(dir, true);\r
- }\r
- \r
- /**\r
- * Deletes the directory's contents, but does not delete the directory.\r
- * @param dir\r
- * @throws Exception\r
- */\r
- public static void clearDirectoryStructure(File dir) throws Exception{\r
- deleteDirectoryStructure(dir, false);\r
- }\r
- \r
- private static void deleteDirectoryStructure(File dir, boolean deleteDir) throws Exception{\r
- File subFiles[] = dir.listFiles();\r
- for (File f : subFiles) {\r
- if (f.isDirectory())\r
- deleteDirectoryStructure(f,true);\r
- else\r
- if (!f.delete()) {\r
- throw new Exception("Cannot delete file " + f.getAbsolutePath());\r
- }\r
- }\r
- if (deleteDir) {\r
- if (!dir.delete()) {\r
- throw new Exception("Cannot delete folder " + dir.getAbsolutePath());\r
- }\r
- }\r
- }\r
-\r
- public static Resource createFileReference(final Resource parent, final Path path) throws DatabaseException {\r
- return Simantics.getSession().syncRequest(new WriteResultRequest<Resource>() {\r
-\r
- @Override\r
- public Resource perform(WriteGraph graph) throws DatabaseException {\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- GraphFileResource GF = GraphFileResource.getInstance(graph);\r
- Resource file = graph.newResource();\r
- graph.claim(file, L0.PartOf, parent);\r
- graph.claim(file, L0.InstanceOf, GF.File);\r
- String name = path.getFileName().toString();\r
- graph.claimLiteral(file, L0.HasName, name, Bindings.STRING);\r
- graph.claimLiteral(file, GF.SystemPath, path.toAbsolutePath().toString(), Bindings.STRING);\r
- return file;\r
- }\r
- });\r
- }\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2013 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.graphfile.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.simantics.Simantics;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.util.binary.RandomAccessBinary;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.common.request.WriteResultRequest;
+import org.simantics.db.common.utils.LiteralFileUtil;
+import org.simantics.db.common.utils.Logger;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.DoesNotContainValueException;
+import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
+import org.simantics.db.exception.NoSingleResultException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.db.request.Read;
+import org.simantics.db.service.ClusteringSupport;
+import org.simantics.db.service.TransferableGraphSupport;
+import org.simantics.graphfile.ontology.GraphFileResource;
+import org.simantics.layer0.Layer0;
+
+/**
+ * @author Marko Luukkainen
+ */
+public class GraphFileUtil {
+
+
+ public static boolean USE_RANDOM_ACCESS_BINARY = true;
+ /**
+ * Creates a temp file of a graphFile.
+ * @param res
+ * @return
+ * @throws DatabaseException
+ */
+ public static File toTempFile(final Resource res)throws DatabaseException {
+ return Simantics.getSession().syncRequest(new Read<File>() {
+ @Override
+ public File perform(ReadGraph graph) throws DatabaseException {
+ return toTempFile(graph, res);
+ }
+ });
+ }
+
+ /**
+ * Creates a temp file of a graphFile.
+ * @param graph
+ * @param res
+ * @return
+ * @throws DatabaseException
+ */
+ public static File toTempFile(ReadGraph graph, Resource res)throws DatabaseException {
+
+ GraphFileResource gf = GraphFileResource.getInstance(graph);
+ String filename = graph.getPossibleRelatedValue(res, gf.HasResourceName);
+ if (filename == null)
+ filename = graph.getRelatedValue(res, Layer0.getInstance(graph).HasName);
+
+ int index = filename.lastIndexOf(".");
+ String name = "";
+ String ext = "";
+ if (index > 0) {
+ name = filename.substring(0,index);
+ ext = filename.substring(index+1);
+ } else {
+ name = filename;
+ }
+ if (name.length() < 3) {
+ for (int i = name.length(); i < 3; i++)
+ name += "_";
+ }
+ try {
+ File file = File.createTempFile(name, "."+ ext);
+ writeDataToFile(graph, res, file);
+ return file;
+ } catch (Exception e) {
+ throw new DatabaseException(e);
+ }
+ }
+
+ public static void writeDataToFile(final Resource res, final File file) throws DatabaseException{
+ Simantics.getSession().syncRequest(new ReadRequest() {
+
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+ try {
+ writeDataToFile(graph, res, file);
+ } catch (IOException e) {
+ throw new DatabaseException(e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Writes contents of a graphFile to file.
+ * @param graph
+ * @param res
+ * @param file
+ * @throws DatabaseException
+ * @throws IOException
+ */
+ public static void writeDataToFile(ReadGraph graph, Resource res, File file) throws DatabaseException, IOException {
+
+ GraphFileResource gf = GraphFileResource.getInstance(graph);
+ if (USE_RANDOM_ACCESS_BINARY) {
+ Resource filedata = graph.getSingleObject(res, gf.HasFiledata);
+ LiteralFileUtil.copyRandomAccessBinaryToFile(graph, filedata, file);
+ } else {
+
+ byte[] data = graph.getRelatedValue(res, gf.HasFiledata);
+ FileOutputStream fos = new FileOutputStream(file);
+ fos.write(data);
+ fos.flush();
+ fos.close();
+
+ }
+ Long lastModified = graph.getPossibleRelatedValue(res, gf.LastModified);
+ if (lastModified != null)
+ file.setLastModified(lastModified);
+ }
+
+ /**
+ * Updates contents of a graphFile, including the name.
+ * @param filename
+ * @param graphFile
+ * @throws DatabaseException
+ */
+ public static void toGraph(final String filename, final Resource graphFile)throws DatabaseException {
+ Simantics.getSession().syncRequest(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+ try {
+ toGraph(graph, filename,graphFile);
+ } catch (IOException e) {
+ throw new DatabaseException(e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Updates contents of a graphFile, including the name.
+ * @param graph
+ * @param filename
+ * @param graphFile
+ * @throws DatabaseException
+ * @throws IOException
+ */
+ public static void toGraph(WriteGraph graph, String filename, Resource graphFile) throws DatabaseException, IOException {
+ File file = new File(filename);
+ if (!file.exists())
+ throw new IOException("File " + filename + " not found.");
+
+ toGraph(graph, file, graphFile);
+ }
+
+ /**
+ * Updates contents of a graphFile, including the name.
+ * @param graph
+ * @param file
+ * @param graphFile
+ * @throws DatabaseException
+ * @throws IOException
+ */
+ public static void toGraph(WriteGraph graph, File file, Resource graphFile) throws DatabaseException, IOException {
+
+ writeDataToGraph(graph, file, graphFile);
+ String name = file.getName();
+ GraphFileResource gf = GraphFileResource.getInstance(graph);
+ graph.claimLiteral(graphFile, gf.HasResourceName, name);
+
+ }
+
+ /**
+ * Writes contents of a file to a graphFile (data and time stamp).
+ * @param graph
+ * @param file
+ * @param graphFile
+ * @throws IOException
+ * @throws ManyObjectsForFunctionalRelationException
+ * @throws ServiceException
+ */
+ public static void writeDataToGraph(WriteGraph graph, File file, Resource graphFile) throws IOException, DatabaseException{
+ GraphFileResource gf = GraphFileResource.getInstance(graph);
+ if (USE_RANDOM_ACCESS_BINARY) {
+
+ Resource fileData = graph.getPossibleObject(graphFile, gf.HasFiledata);
+ RandomAccessBinary rab = null;
+ if (fileData == null) {
+ Layer0 l0 = Layer0.getInstance(graph);
+ ClusteringSupport cs = graph.getService(ClusteringSupport.class);
+ fileData = graph.newResource(cs.createCluster());
+ graph.claim(fileData, l0.InstanceOf, l0.ByteArray);
+ graph.claim(graphFile, gf.HasFiledata, fileData);
+ rab = graph.createRandomAccessBinary(fileData, Bindings.BYTE_ARRAY.type(), null);
+ } else {
+ rab = graph.getRandomAccessBinary(fileData);
+ }
+ LiteralFileUtil.copyRandomAccessBinaryFromFile(file, rab);
+ } else {
+ FileInputStream stream = new FileInputStream(file);
+ FileChannel chan = stream.getChannel();
+ long lsize = chan.size();
+ if (lsize > Integer.MAX_VALUE)
+ throw new IOException("File is too big");
+ int size = (int)lsize;
+ final byte[] array = new byte[size];
+ ByteBuffer buf = ByteBuffer.wrap(array);
+ while (size > 0)
+ size -= chan.read(buf);
+
+ graph.claimLiteral(graphFile, gf.HasFiledata, array);
+ chan.close();
+ stream.close();
+ }
+
+ graph.claimLiteral(graphFile, gf.LastModified, file.lastModified());
+
+ }
+
+ public static void writeDataToGraph(WriteGraph graph, byte data[], Resource graphFile) throws IOException, DatabaseException {
+ GraphFileResource gf = GraphFileResource.getInstance(graph);
+ if (USE_RANDOM_ACCESS_BINARY) {
+ Resource fileData = graph.getPossibleObject(graphFile, gf.HasFiledata);
+ if (fileData == null) {
+ Layer0 l0 = Layer0.getInstance(graph);
+ ClusteringSupport cs = graph.getService(ClusteringSupport.class);
+ fileData = graph.newResource(cs.createCluster());
+ graph.claim(fileData, l0.InstanceOf, l0.ByteArray);
+ graph.claim(graphFile, gf.HasFiledata, fileData);
+ graph.createRandomAccessBinary(fileData, Bindings.BYTE_ARRAY.type(), data);
+ } else {
+ InputStream input = new ByteArrayInputStream(data);
+ LiteralFileUtil.copyStreamToRandomAccessBinary(graph, input, fileData);
+ }
+ } else {
+ graph.claimLiteral(graphFile, gf.HasFiledata, data);
+ }
+ graph.claimLiteral(graphFile, gf.LastModified, System.currentTimeMillis());
+ }
+
+ /**
+ * Writes contents of a file to a graphFile (data and time stamp).
+ * @param file
+ * @param graphFile
+ * @throws DatabaseException
+ */
+ public static void writeDataToGraph(final File file, final Resource graphFile) throws DatabaseException {
+ Simantics.getSession().syncRequest(new WriteRequest() {
+
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+ try {
+ writeDataToGraph(graph, file, graphFile);
+ } catch (IOException e) {
+ throw new DatabaseException(e);
+ }
+
+ }
+ });
+ }
+
+ public static void syncFolderToGraph(WriteGraph g, File folder, Resource folderRes) throws Exception {
+ File subFiles[] = folder.listFiles();
+ Layer0 l0 = Layer0.getInstance(g);
+ GraphFileResource gf = GraphFileResource.getInstance(g);
+ Collection<Resource> subFileResources = g.getObjects(folderRes, gf.HasFile);
+ Collection<Resource> subFolderResources = g.getObjects(folderRes, gf.HasFolder);
+
+ Map<Resource,File> matching = new HashMap<Resource, File>();
+
+ for (File f : subFiles) {
+ String name = f.getName();
+ if (f.isDirectory()) {
+ Resource matchingFolder = findWithName(g, subFolderResources, name);
+
+ if (matchingFolder != null) {
+ if (matching.containsKey(matchingFolder))
+ throw new Exception("Matching folder already in use" + f.getAbsolutePath() + " " + matchingFolder);
+
+ matching.put(matchingFolder, f);
+ syncFolderToGraph(g, f, matchingFolder);
+ } else {
+ matchingFolder = g.newResource();
+ g.claim(matchingFolder, l0.InstanceOf, gf.Folder);
+ g.claimLiteral(matchingFolder, gf.HasResourceName, name);
+ g.claimLiteral(matchingFolder, l0.HasName, name);
+ g.claim(folderRes, gf.HasFolder, matchingFolder);
+ matching.put(matchingFolder, f);
+ syncFolderToGraph(g, f, matchingFolder);
+ }
+ } else { //file
+ Resource fileRes = findWithName(g, subFileResources, name);
+ if (fileRes != null) {
+ if (matching.containsKey(fileRes))
+ throw new Exception("Matching file already in use" + f.getAbsolutePath() + " " + fileRes);
+ matching.put(fileRes, f);
+ toGraph(g, f, fileRes);
+ } else {
+ fileRes = g.newResource();
+ g.claim(fileRes, l0.InstanceOf, gf.File);
+ g.claimLiteral(fileRes, gf.HasResourceName, name);
+ g.claimLiteral(fileRes, l0.HasName, name);
+ g.claim(folderRes, gf.HasFile, fileRes);
+ matching.put(fileRes, f);
+ toGraph(g, f, fileRes);
+ }
+ }
+ }
+ // delete resources, which have no matching file (or folder)
+ for (Resource subFolder : subFolderResources) {
+ if (!matching.containsKey(subFolder))
+ g.deny(subFolder);
+ }
+
+ for (Resource subFolder : subFileResources) {
+ if (!matching.containsKey(subFolder))
+ g.deny(subFolder);
+ }
+ }
+
+ public static void writeFolderToDisk(ReadGraph g, Resource folderRes, File folder) throws DatabaseException, IOException{
+
+ GraphFileResource gf = GraphFileResource.getInstance(g);
+ for (Resource subFolder : g.getObjects(folderRes, gf.HasFolder)) {
+ String name = g.getRelatedValue(subFolder, gf.HasResourceName);
+
+ if (name.length() == 0)
+ throw new DatabaseException("Empty folder name for " + subFolder);
+
+ File newFolder = new File(folder.getAbsolutePath() + "/" + name);
+ if (!newFolder.mkdir()) {
+ throw new DatabaseException("Could not create folder " + name + " for resource " + subFolder);
+ }
+ writeFolderToDisk(g, subFolder, newFolder);
+ }
+ for (Resource fileRes : g.getObjects(folderRes, gf.HasFile)) {
+ String name = g.getRelatedValue(fileRes, gf.HasResourceName);
+ File file = new File(folder.getAbsolutePath() + "/" + name);
+ writeDataToFile(g, fileRes, file);
+ }
+ }
+
+ public static void syncFolderToGraph(WriteGraph g, File folder, Resource folderRes, ToGraphHelper helper) throws Exception {
+ File subFiles[] = folder.listFiles();
+ GraphFileResource gf = GraphFileResource.getInstance(g);
+ Collection<Resource> subFileResources = g.getObjects(folderRes, gf.HasFile);
+ Collection<Resource> subFolderResources = g.getObjects(folderRes, gf.HasFolder);
+
+ Map<Resource,File> matching = new HashMap<Resource, File>();
+
+ for (File f : subFiles) {
+ String name = f.getName();
+ if (f.isDirectory()) {
+ Resource matchingFolder = helper.findFolder(g, subFolderResources, name);
+
+ if (matchingFolder != null) {
+ if (matching.containsKey(matchingFolder))
+ throw new Exception("Matching folder already in use" + f.getAbsolutePath() + " " + matchingFolder);
+
+ matching.put(matchingFolder, f);
+ syncFolderToGraph(g, f, matchingFolder,helper);
+ } else {
+ matchingFolder = helper.createFolder(g, name);
+ g.claim(folderRes, gf.HasFolder, matchingFolder);
+ matching.put(matchingFolder, f);
+ syncFolderToGraph(g, f, matchingFolder,helper);
+ }
+ } else { //file
+ Resource fileRes = helper.findFile(g, subFileResources, name);
+ if (fileRes != null) {
+ if (matching.containsKey(fileRes))
+ throw new Exception("Matching file already in use" + f.getAbsolutePath() + " " + fileRes);
+ matching.put(fileRes, f);
+ toGraph(g, f, fileRes);
+ } else {
+ fileRes = helper.createFile(g, name);
+ g.claim(folderRes, gf.HasFile, fileRes);
+ matching.put(fileRes, f);
+ toGraph(g, f, fileRes);
+ }
+ }
+ }
+ // delete resources, which have no matching file (or folder)
+ for (Resource subFolder : subFolderResources) {
+ if (!matching.containsKey(subFolder))
+ g.deny(subFolder);
+ }
+
+ for (Resource subFolder : subFileResources) {
+ if (!matching.containsKey(subFolder))
+ g.deny(subFolder);
+ }
+ }
+
+ public static interface ToGraphHelper {
+ public Resource findFolder(ReadGraph g, Collection<Resource> subFolderResources, String name) throws DatabaseException;
+ public Resource createFolder(WriteGraph g, String name) throws DatabaseException;
+ public Resource findFile(ReadGraph g, Collection<Resource> subFileResources, String name) throws DatabaseException;
+ public Resource createFile(WriteGraph g, String name) throws DatabaseException;
+ }
+
+ public static interface ToDiskHelper {
+ public String getName(ReadGraph g, Resource systemResource) throws DatabaseException;
+ }
+
+ public static void writeFolderToDisk(ReadGraph g, Resource folderRes, File folder, ToDiskHelper helper) throws DatabaseException, IOException{
+ GraphFileResource gf = GraphFileResource.getInstance(g);
+ for (Resource subFolder : g.getObjects(folderRes, gf.HasFolder)) {
+ String name = helper.getName(g, subFolder);
+
+ if (name.length() == 0)
+ throw new DatabaseException("Empty folder name for " + subFolder);
+
+ File newFolder = new File(folder.getAbsolutePath() + "/" + name);
+ if (!newFolder.mkdir()) {
+ throw new DatabaseException("Could not create folder " + name + " for resource " + subFolder);
+ }
+ writeFolderToDisk(g, subFolder, newFolder, helper);
+ }
+ for (Resource fileRes : g.getObjects(folderRes, gf.HasFile)) {
+ String name = helper.getName(g, fileRes);
+ File file = new File(folder.getAbsolutePath() + "/" + name);
+ writeDataToFile(g, fileRes, file);
+ }
+ }
+
+ public static interface ToDiskHelper2 extends ToDiskHelper {
+ public Resource findFolder(ReadGraph g, Collection<Resource> subFolderResources, String name) throws DatabaseException;
+ public Resource findFile(ReadGraph g, Collection<Resource> subFileResources, String name) throws DatabaseException;
+ }
+
+ public static void syncFolderToDisk(ReadGraph g, Resource folderRes, File folder, ToDiskHelper2 helper) throws Exception {
+ File subFiles[] = folder.listFiles();
+ GraphFileResource gf = GraphFileResource.getInstance(g);
+ Collection<Resource> subFileResources = g.getObjects(folderRes, gf.HasFile);
+ Collection<Resource> subFolderResources = g.getObjects(folderRes, gf.HasFolder);
+
+ Map<Resource,File> matching = new HashMap<Resource, File>();
+
+ for (File f : subFiles) {
+ String name = f.getName();
+ if (f.isDirectory()) {
+ Resource matchingFolder = helper.findFolder(g, subFolderResources, name);
+
+ if (matchingFolder != null) {
+ if (matching.containsKey(matchingFolder))
+ throw new Exception("Matching folder already in use" + f.getAbsolutePath() + " " + matchingFolder);
+
+ matching.put(matchingFolder, f);
+ syncFolderToDisk(g, matchingFolder, f, helper);
+ } else {
+ deleteDirectoryStructure(f);
+ }
+ } else { //file
+ Resource fileRes = helper.findFile(g, subFileResources, name);
+ if (fileRes != null) {
+ if (matching.containsKey(fileRes))
+ throw new Exception("Matching file already in use" + f.getAbsolutePath() + " " + fileRes);
+ matching.put(fileRes, f);
+ writeDataToFile(g, fileRes, f);
+ } else {
+ if (!f.delete())
+ throw new Exception("Cannot delete file " + f.getAbsolutePath());
+ }
+ }
+ }
+ // create files and folders, which have no matching graphFile (or folder)
+ for (Resource subFolder : subFolderResources) {
+ if (!matching.containsKey(subFolder)) {
+ String name = helper.getName(g, subFolder);
+
+ if (name.length() == 0)
+ throw new DatabaseException("Empty folder name for " + subFolder);
+
+ File newFolder = new File(folder.getAbsolutePath() + "/" + name);
+ if (!newFolder.mkdir()) {
+ throw new DatabaseException("Could not create folder " + name + " for resource " + subFolder);
+ }
+ writeFolderToDisk(g, subFolder, newFolder, helper);
+ }
+ }
+
+ for (Resource fileRes : subFileResources) {
+ if (!matching.containsKey(fileRes)) {
+ String name = helper.getName(g, fileRes);
+ File file = new File(folder.getAbsolutePath() + "/" + name);
+ writeDataToFile(g, fileRes, file);
+ }
+ }
+
+ }
+
+
+
+ public static Resource findWithName(ReadGraph g, Collection<Resource> resources, String name) throws ServiceException, NoSingleResultException, DoesNotContainValueException {
+ GraphFileResource gf = GraphFileResource.getInstance(g);
+ for (Resource r : resources)
+ if (name.equals(g.getRelatedValue(r, gf.HasResourceName)))
+ return r;
+ return null;
+ }
+
+ /**
+ * Deletes the directory and all it contents.
+ * @param dir
+ * @throws Exception
+ */
+ public static void deleteDirectoryStructure(File dir) throws Exception{
+ deleteDirectoryStructure(dir, true);
+ }
+
+ /**
+ * Deletes the directory's contents, but does not delete the directory.
+ * @param dir
+ * @throws Exception
+ */
+ public static void clearDirectoryStructure(File dir) throws Exception{
+ deleteDirectoryStructure(dir, false);
+ }
+
+ private static void deleteDirectoryStructure(File dir, boolean deleteDir) throws Exception{
+ File subFiles[] = dir.listFiles();
+ for (File f : subFiles) {
+ if (f.isDirectory())
+ deleteDirectoryStructure(f,true);
+ else
+ if (!f.delete()) {
+ throw new Exception("Cannot delete file " + f.getAbsolutePath());
+ }
+ }
+ if (deleteDir) {
+ if (!dir.delete()) {
+ throw new Exception("Cannot delete folder " + dir.getAbsolutePath());
+ }
+ }
+ }
+
+ public static Resource createFileReference(final Resource parent, final Path path) throws DatabaseException {
+ return Simantics.getSession().syncRequest(new WriteResultRequest<Resource>() {
+
+ @Override
+ public Resource perform(WriteGraph graph) throws DatabaseException {
+ Layer0 L0 = Layer0.getInstance(graph);
+ GraphFileResource GF = GraphFileResource.getInstance(graph);
+ Resource file = graph.newResource();
+ graph.claim(file, L0.PartOf, parent);
+ graph.claim(file, L0.InstanceOf, GF.File);
+ String name = path.getFileName().toString();
+ graph.claimLiteral(file, L0.HasName, name, Bindings.STRING);
+ graph.claimLiteral(file, GF.SystemPath, path.toAbsolutePath().toString(), Bindings.STRING);
+ return file;
+ }
+ });
+ }
+
+ /**
+ * SCL java binding cannot make difference between methods that have two versions, one with Read/WriteGraph, and one without.
+ * Hence we have to introduce a set of methods which have no alternate versions.
+ */
+
+
+ public static void writeDataToGraphSCLhack(WriteGraph graph, File file, Resource graphFile) throws IOException, DatabaseException{
+ writeDataToGraph(graph, file, graphFile);
+
+ }
+
+ public static File toTempFileSCLhack(ReadGraph graph, Resource res)throws DatabaseException {
+ return toTempFile(graph, res);
+ }
+
+ public static void writeDataToFileSCLhack(ReadGraph graph, Resource res, File file) throws DatabaseException, IOException {
+ writeDataToFile(graph, res, file);
+ }
+
+ public static void toGraphSCLhack(WriteGraph graph, String filename, Resource graphFile) throws DatabaseException, IOException {
+ toGraph(graph, filename, graphFile);
+ }
+
+
+ public static byte[] getData(ReadGraph graph, Resource graphFile) throws DatabaseException{
+ GraphFileResource GF = GraphFileResource.getInstance(graph);
+ Resource fileData = graph.getSingleObject(graphFile, GF.HasFiledata);
+ TransferableGraphSupport tgs = graph.getService(TransferableGraphSupport.class);
+ InputStream input = tgs.getValueStream(graph, fileData);
+ DataInputStream di = new DataInputStream(input);
+ try {
+ int length = di.readInt();
+ byte[] content = new byte[length];
+ di.read(content);
+ return content;
+ } catch (IOException e) {
+ Logger.defaultLogError(e);
+ }
+ return null;
+ }
+
+ public static String getDataAsString(ReadGraph graph, Resource graphFile) throws DatabaseException{
+ byte[] content = getData(graph, graphFile);
+ String s = new String(content);
+ return s;
+ }
+
+}