1 /*******************************************************************************
2 * Copyright (c) 2013 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.graphfile.util;
14 import java.io.ByteArrayInputStream;
16 import java.io.FileInputStream;
17 import java.io.FileOutputStream;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.nio.ByteBuffer;
21 import java.nio.channels.FileChannel;
22 import java.nio.file.Path;
23 import java.util.Collection;
24 import java.util.HashMap;
27 import org.simantics.Simantics;
28 import org.simantics.databoard.Bindings;
29 import org.simantics.databoard.util.binary.RandomAccessBinary;
30 import org.simantics.db.ReadGraph;
31 import org.simantics.db.Resource;
32 import org.simantics.db.WriteGraph;
33 import org.simantics.db.common.request.ReadRequest;
34 import org.simantics.db.common.request.WriteRequest;
35 import org.simantics.db.common.request.WriteResultRequest;
36 import org.simantics.db.common.utils.LiteralFileUtil;
37 import org.simantics.db.exception.DatabaseException;
38 import org.simantics.db.exception.DoesNotContainValueException;
39 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
40 import org.simantics.db.exception.NoSingleResultException;
41 import org.simantics.db.exception.ServiceException;
42 import org.simantics.db.request.Read;
43 import org.simantics.db.service.ClusteringSupport;
44 import org.simantics.graphfile.ontology.GraphFileResource;
45 import org.simantics.layer0.Layer0;
48 * @author Marko Luukkainen
50 public class GraphFileUtil {
53 public static boolean USE_RANDOM_ACCESS_BINARY = true;
55 * Creates a temp file of a graphFile.
58 * @throws DatabaseException
60 public static File toTempFile(final Resource res)throws DatabaseException {
61 return Simantics.getSession().syncRequest(new Read<File>() {
63 public File perform(ReadGraph graph) throws DatabaseException {
64 return toTempFile(graph, res);
70 * Creates a temp file of a graphFile.
74 * @throws DatabaseException
76 public static File toTempFile(ReadGraph graph, Resource res)throws DatabaseException {
78 GraphFileResource gf = GraphFileResource.getInstance(graph);
79 String filename = graph.getPossibleRelatedValue(res, gf.HasResourceName);
81 filename = graph.getRelatedValue(res, Layer0.getInstance(graph).HasName);
83 int index = filename.lastIndexOf(".");
87 name = filename.substring(0,index);
88 ext = filename.substring(index+1);
92 if (name.length() < 3) {
93 for (int i = name.length(); i < 3; i++)
97 File file = File.createTempFile(name, "."+ ext);
98 writeDataToFile(graph, res, file);
100 } catch (Exception e) {
101 throw new DatabaseException(e);
105 public static void writeDataToFile(final Resource res, final File file) throws DatabaseException{
106 Simantics.getSession().syncRequest(new ReadRequest() {
109 public void run(ReadGraph graph) throws DatabaseException {
111 writeDataToFile(graph, res, file);
112 } catch (IOException e) {
113 throw new DatabaseException(e);
120 * Writes contents of a graphFile to file.
124 * @throws DatabaseException
125 * @throws IOException
127 public static void writeDataToFile(ReadGraph graph, Resource res, File file) throws DatabaseException, IOException {
129 GraphFileResource gf = GraphFileResource.getInstance(graph);
130 if (USE_RANDOM_ACCESS_BINARY) {
131 Resource filedata = graph.getSingleObject(res, gf.HasFiledata);
132 LiteralFileUtil.copyRandomAccessBinaryToFile(graph, filedata, file);
135 byte[] data = graph.getRelatedValue(res, gf.HasFiledata);
136 FileOutputStream fos = new FileOutputStream(file);
142 Long lastModified = graph.getPossibleRelatedValue(res, gf.LastModified);
143 if (lastModified != null)
144 file.setLastModified(lastModified);
148 * Updates contents of a graphFile, including the name.
151 * @throws DatabaseException
153 public static void toGraph(final String filename, final Resource graphFile)throws DatabaseException {
154 Simantics.getSession().syncRequest(new WriteRequest() {
156 public void perform(WriteGraph graph) throws DatabaseException {
158 toGraph(graph, filename,graphFile);
159 } catch (IOException e) {
160 throw new DatabaseException(e);
167 * Updates contents of a graphFile, including the name.
171 * @throws DatabaseException
172 * @throws IOException
174 public static void toGraph(WriteGraph graph, String filename, Resource graphFile) throws DatabaseException, IOException {
175 File file = new File(filename);
177 throw new IOException("File " + filename + " not found.");
179 toGraph(graph, file, graphFile);
183 * Updates contents of a graphFile, including the name.
187 * @throws DatabaseException
188 * @throws IOException
190 public static void toGraph(WriteGraph graph, File file, Resource graphFile) throws DatabaseException, IOException {
192 writeDataToGraph(graph, file, graphFile);
193 String name = file.getName();
194 GraphFileResource gf = GraphFileResource.getInstance(graph);
195 graph.claimLiteral(graphFile, gf.HasResourceName, name);
200 * Writes contents of a file to a graphFile (data and time stamp).
204 * @throws IOException
205 * @throws ManyObjectsForFunctionalRelationException
206 * @throws ServiceException
208 public static void writeDataToGraph(WriteGraph graph, File file, Resource graphFile) throws IOException, DatabaseException{
209 GraphFileResource gf = GraphFileResource.getInstance(graph);
210 if (USE_RANDOM_ACCESS_BINARY) {
212 Resource fileData = graph.getPossibleObject(graphFile, gf.HasFiledata);
213 RandomAccessBinary rab = null;
214 if (fileData == null) {
215 Layer0 l0 = Layer0.getInstance(graph);
216 ClusteringSupport cs = graph.getService(ClusteringSupport.class);
217 fileData = graph.newResource(cs.createCluster());
218 graph.claim(fileData, l0.InstanceOf, l0.ByteArray);
219 graph.claim(graphFile, gf.HasFiledata, fileData);
220 rab = graph.createRandomAccessBinary(fileData, Bindings.BYTE_ARRAY.type(), null);
222 rab = graph.getRandomAccessBinary(fileData);
224 LiteralFileUtil.copyRandomAccessBinaryFromFile(file, rab);
226 FileInputStream stream = new FileInputStream(file);
227 FileChannel chan = stream.getChannel();
228 long lsize = chan.size();
229 if (lsize > Integer.MAX_VALUE)
230 throw new IOException("File is too big");
231 int size = (int)lsize;
232 final byte[] array = new byte[size];
233 ByteBuffer buf = ByteBuffer.wrap(array);
235 size -= chan.read(buf);
237 graph.claimLiteral(graphFile, gf.HasFiledata, array);
242 graph.claimLiteral(graphFile, gf.LastModified, file.lastModified());
246 public static void writeDataToGraph(WriteGraph graph, byte data[], Resource graphFile) throws IOException, DatabaseException {
247 GraphFileResource gf = GraphFileResource.getInstance(graph);
248 if (USE_RANDOM_ACCESS_BINARY) {
249 Resource fileData = graph.getPossibleObject(graphFile, gf.HasFiledata);
250 if (fileData == null) {
251 Layer0 l0 = Layer0.getInstance(graph);
252 ClusteringSupport cs = graph.getService(ClusteringSupport.class);
253 fileData = graph.newResource(cs.createCluster());
254 graph.claim(fileData, l0.InstanceOf, l0.ByteArray);
255 graph.claim(graphFile, gf.HasFiledata, fileData);
256 graph.createRandomAccessBinary(fileData, Bindings.BYTE_ARRAY.type(), data);
258 InputStream input = new ByteArrayInputStream(data);
259 LiteralFileUtil.copyStreamToRandomAccessBinary(graph, input, fileData);
262 graph.claimLiteral(graphFile, gf.HasFiledata, data);
264 graph.claimLiteral(graphFile, gf.LastModified, System.currentTimeMillis());
268 * Writes contents of a file to a graphFile (data and time stamp).
271 * @throws DatabaseException
273 public static void writeDataToGraph(final File file, final Resource graphFile) throws DatabaseException {
274 Simantics.getSession().syncRequest(new WriteRequest() {
277 public void perform(WriteGraph graph) throws DatabaseException {
279 writeDataToGraph(graph, file, graphFile);
280 } catch (IOException e) {
281 throw new DatabaseException(e);
288 public static void syncFolderToGraph(WriteGraph g, File folder, Resource folderRes) throws Exception {
289 File subFiles[] = folder.listFiles();
290 Layer0 l0 = Layer0.getInstance(g);
291 GraphFileResource gf = GraphFileResource.getInstance(g);
292 Collection<Resource> subFileResources = g.getObjects(folderRes, gf.HasFile);
293 Collection<Resource> subFolderResources = g.getObjects(folderRes, gf.HasFolder);
295 Map<Resource,File> matching = new HashMap<Resource, File>();
297 for (File f : subFiles) {
298 String name = f.getName();
299 if (f.isDirectory()) {
300 Resource matchingFolder = findWithName(g, subFolderResources, name);
302 if (matchingFolder != null) {
303 if (matching.containsKey(matchingFolder))
304 throw new Exception("Matching folder already in use" + f.getAbsolutePath() + " " + matchingFolder);
306 matching.put(matchingFolder, f);
307 syncFolderToGraph(g, f, matchingFolder);
309 matchingFolder = g.newResource();
310 g.claim(matchingFolder, l0.InstanceOf, gf.Folder);
311 g.claimLiteral(matchingFolder, gf.HasResourceName, name);
312 g.claimLiteral(matchingFolder, l0.HasName, name);
313 g.claim(folderRes, gf.HasFolder, matchingFolder);
314 matching.put(matchingFolder, f);
315 syncFolderToGraph(g, f, matchingFolder);
318 Resource fileRes = findWithName(g, subFileResources, name);
319 if (fileRes != null) {
320 if (matching.containsKey(fileRes))
321 throw new Exception("Matching file already in use" + f.getAbsolutePath() + " " + fileRes);
322 matching.put(fileRes, f);
323 toGraph(g, f, fileRes);
325 fileRes = g.newResource();
326 g.claim(fileRes, l0.InstanceOf, gf.File);
327 g.claimLiteral(fileRes, gf.HasResourceName, name);
328 g.claimLiteral(fileRes, l0.HasName, name);
329 g.claim(folderRes, gf.HasFile, fileRes);
330 matching.put(fileRes, f);
331 toGraph(g, f, fileRes);
335 // delete resources, which have no matching file (or folder)
336 for (Resource subFolder : subFolderResources) {
337 if (!matching.containsKey(subFolder))
341 for (Resource subFolder : subFileResources) {
342 if (!matching.containsKey(subFolder))
347 public static void writeFolderToDisk(ReadGraph g, Resource folderRes, File folder) throws DatabaseException, IOException{
349 GraphFileResource gf = GraphFileResource.getInstance(g);
350 for (Resource subFolder : g.getObjects(folderRes, gf.HasFolder)) {
351 String name = g.getRelatedValue(subFolder, gf.HasResourceName);
353 if (name.length() == 0)
354 throw new DatabaseException("Empty folder name for " + subFolder);
356 File newFolder = new File(folder.getAbsolutePath() + "/" + name);
357 if (!newFolder.mkdir()) {
358 throw new DatabaseException("Could not create folder " + name + " for resource " + subFolder);
360 writeFolderToDisk(g, subFolder, newFolder);
362 for (Resource fileRes : g.getObjects(folderRes, gf.HasFile)) {
363 String name = g.getRelatedValue(fileRes, gf.HasResourceName);
364 File file = new File(folder.getAbsolutePath() + "/" + name);
365 writeDataToFile(g, fileRes, file);
369 public static void syncFolderToGraph(WriteGraph g, File folder, Resource folderRes, ToGraphHelper helper) throws Exception {
370 File subFiles[] = folder.listFiles();
371 GraphFileResource gf = GraphFileResource.getInstance(g);
372 Collection<Resource> subFileResources = g.getObjects(folderRes, gf.HasFile);
373 Collection<Resource> subFolderResources = g.getObjects(folderRes, gf.HasFolder);
375 Map<Resource,File> matching = new HashMap<Resource, File>();
377 for (File f : subFiles) {
378 String name = f.getName();
379 if (f.isDirectory()) {
380 Resource matchingFolder = helper.findFolder(g, subFolderResources, name);
382 if (matchingFolder != null) {
383 if (matching.containsKey(matchingFolder))
384 throw new Exception("Matching folder already in use" + f.getAbsolutePath() + " " + matchingFolder);
386 matching.put(matchingFolder, f);
387 syncFolderToGraph(g, f, matchingFolder,helper);
389 matchingFolder = helper.createFolder(g, name);
390 g.claim(folderRes, gf.HasFolder, matchingFolder);
391 matching.put(matchingFolder, f);
392 syncFolderToGraph(g, f, matchingFolder,helper);
395 Resource fileRes = helper.findFile(g, subFileResources, name);
396 if (fileRes != null) {
397 if (matching.containsKey(fileRes))
398 throw new Exception("Matching file already in use" + f.getAbsolutePath() + " " + fileRes);
399 matching.put(fileRes, f);
400 toGraph(g, f, fileRes);
402 fileRes = helper.createFile(g, name);
403 g.claim(folderRes, gf.HasFile, fileRes);
404 matching.put(fileRes, f);
405 toGraph(g, f, fileRes);
409 // delete resources, which have no matching file (or folder)
410 for (Resource subFolder : subFolderResources) {
411 if (!matching.containsKey(subFolder))
415 for (Resource subFolder : subFileResources) {
416 if (!matching.containsKey(subFolder))
421 public static interface ToGraphHelper {
422 public Resource findFolder(ReadGraph g, Collection<Resource> subFolderResources, String name) throws DatabaseException;
423 public Resource createFolder(WriteGraph g, String name) throws DatabaseException;
424 public Resource findFile(ReadGraph g, Collection<Resource> subFileResources, String name) throws DatabaseException;
425 public Resource createFile(WriteGraph g, String name) throws DatabaseException;
428 public static interface ToDiskHelper {
429 public String getName(ReadGraph g, Resource systemResource) throws DatabaseException;
432 public static void writeFolderToDisk(ReadGraph g, Resource folderRes, File folder, ToDiskHelper helper) throws DatabaseException, IOException{
433 GraphFileResource gf = GraphFileResource.getInstance(g);
434 for (Resource subFolder : g.getObjects(folderRes, gf.HasFolder)) {
435 String name = helper.getName(g, subFolder);
437 if (name.length() == 0)
438 throw new DatabaseException("Empty folder name for " + subFolder);
440 File newFolder = new File(folder.getAbsolutePath() + "/" + name);
441 if (!newFolder.mkdir()) {
442 throw new DatabaseException("Could not create folder " + name + " for resource " + subFolder);
444 writeFolderToDisk(g, subFolder, newFolder, helper);
446 for (Resource fileRes : g.getObjects(folderRes, gf.HasFile)) {
447 String name = helper.getName(g, fileRes);
448 File file = new File(folder.getAbsolutePath() + "/" + name);
449 writeDataToFile(g, fileRes, file);
453 public static interface ToDiskHelper2 extends ToDiskHelper {
454 public Resource findFolder(ReadGraph g, Collection<Resource> subFolderResources, String name) throws DatabaseException;
455 public Resource findFile(ReadGraph g, Collection<Resource> subFileResources, String name) throws DatabaseException;
458 public static void syncFolderToDisk(ReadGraph g, Resource folderRes, File folder, ToDiskHelper2 helper) throws Exception {
459 File subFiles[] = folder.listFiles();
460 GraphFileResource gf = GraphFileResource.getInstance(g);
461 Collection<Resource> subFileResources = g.getObjects(folderRes, gf.HasFile);
462 Collection<Resource> subFolderResources = g.getObjects(folderRes, gf.HasFolder);
464 Map<Resource,File> matching = new HashMap<Resource, File>();
466 for (File f : subFiles) {
467 String name = f.getName();
468 if (f.isDirectory()) {
469 Resource matchingFolder = helper.findFolder(g, subFolderResources, name);
471 if (matchingFolder != null) {
472 if (matching.containsKey(matchingFolder))
473 throw new Exception("Matching folder already in use" + f.getAbsolutePath() + " " + matchingFolder);
475 matching.put(matchingFolder, f);
476 syncFolderToDisk(g, matchingFolder, f, helper);
478 deleteDirectoryStructure(f);
481 Resource fileRes = helper.findFile(g, subFileResources, name);
482 if (fileRes != null) {
483 if (matching.containsKey(fileRes))
484 throw new Exception("Matching file already in use" + f.getAbsolutePath() + " " + fileRes);
485 matching.put(fileRes, f);
486 writeDataToFile(g, fileRes, f);
489 throw new Exception("Cannot delete file " + f.getAbsolutePath());
493 // create files and folders, which have no matching graphFile (or folder)
494 for (Resource subFolder : subFolderResources) {
495 if (!matching.containsKey(subFolder)) {
496 String name = helper.getName(g, subFolder);
498 if (name.length() == 0)
499 throw new DatabaseException("Empty folder name for " + subFolder);
501 File newFolder = new File(folder.getAbsolutePath() + "/" + name);
502 if (!newFolder.mkdir()) {
503 throw new DatabaseException("Could not create folder " + name + " for resource " + subFolder);
505 writeFolderToDisk(g, subFolder, newFolder, helper);
509 for (Resource fileRes : subFileResources) {
510 if (!matching.containsKey(fileRes)) {
511 String name = helper.getName(g, fileRes);
512 File file = new File(folder.getAbsolutePath() + "/" + name);
513 writeDataToFile(g, fileRes, file);
521 public static Resource findWithName(ReadGraph g, Collection<Resource> resources, String name) throws ServiceException, NoSingleResultException, DoesNotContainValueException {
522 GraphFileResource gf = GraphFileResource.getInstance(g);
523 for (Resource r : resources)
524 if (name.equals(g.getRelatedValue(r, gf.HasResourceName)))
530 * Deletes the directory and all it contents.
534 public static void deleteDirectoryStructure(File dir) throws Exception{
535 deleteDirectoryStructure(dir, true);
539 * Deletes the directory's contents, but does not delete the directory.
543 public static void clearDirectoryStructure(File dir) throws Exception{
544 deleteDirectoryStructure(dir, false);
547 private static void deleteDirectoryStructure(File dir, boolean deleteDir) throws Exception{
548 File subFiles[] = dir.listFiles();
549 for (File f : subFiles) {
551 deleteDirectoryStructure(f,true);
554 throw new Exception("Cannot delete file " + f.getAbsolutePath());
559 throw new Exception("Cannot delete folder " + dir.getAbsolutePath());
564 public static Resource createFileReference(final Resource parent, final Path path) throws DatabaseException {
565 return Simantics.getSession().syncRequest(new WriteResultRequest<Resource>() {
568 public Resource perform(WriteGraph graph) throws DatabaseException {
569 Layer0 L0 = Layer0.getInstance(graph);
570 GraphFileResource GF = GraphFileResource.getInstance(graph);
571 Resource file = graph.newResource();
572 graph.claim(file, L0.PartOf, parent);
573 graph.claim(file, L0.InstanceOf, GF.File);
574 String name = path.getFileName().toString();
575 graph.claimLiteral(file, L0.HasName, name, Bindings.STRING);
576 graph.claimLiteral(file, GF.SystemPath, path.toAbsolutePath().toString(), Bindings.STRING);