]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - org.argeo.jcr/src/org/argeo/jcr/fs/BinaryChannel.java
First working JCR file system
[lgpl/argeo-commons.git] / org.argeo.jcr / src / org / argeo / jcr / fs / BinaryChannel.java
diff --git a/org.argeo.jcr/src/org/argeo/jcr/fs/BinaryChannel.java b/org.argeo.jcr/src/org/argeo/jcr/fs/BinaryChannel.java
new file mode 100644 (file)
index 0000000..ff4b4a1
--- /dev/null
@@ -0,0 +1,197 @@
+package org.argeo.jcr.fs;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+
+import javax.jcr.Binary;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.jcr.JcrUtils;
+
+public class BinaryChannel implements SeekableByteChannel {
+       private final Node file;
+       private Binary binary;
+       private boolean open = true;
+
+       private long position = 0;
+
+       // private ByteBuffer toWrite;
+       private FileChannel fc = null;
+
+       public BinaryChannel(Node file) throws RepositoryException, IOException {
+               this.file = file;
+               // int capacity = 1024 * 1024;
+               // this.toWrite = ByteBuffer.allocate(capacity);
+               if (file.isNodeType(NodeType.NT_FILE)) {
+                       if (file.hasNode(Property.JCR_CONTENT)) {
+                               Node data = file.getNode(Property.JCR_CONTENT);
+                               this.binary = data.getProperty(Property.JCR_DATA).getBinary();
+                       } else {
+                               Node data = file.addNode(Property.JCR_CONTENT, NodeType.NT_RESOURCE);
+                               try (InputStream in = new ByteArrayInputStream(new byte[0])) {
+                                       this.binary = data.getSession().getValueFactory().createBinary(in);
+                               }
+                       }
+               } else {
+                       throw new IllegalArgumentException(
+                                       "Unsupported file node " + file + " (" + file.getPrimaryNodeType() + ")");
+               }
+       }
+
+       @Override
+       public synchronized boolean isOpen() {
+               return open;
+       }
+
+       @Override
+       public synchronized void close() throws IOException {
+               if (isModified()) {
+                       Binary newBinary=null;
+                       try {
+                               Session session = file.getSession();
+                               // byte[] arr = new byte[(int) position];
+                               // toWrite.flip();
+                               // toWrite.get(arr);
+                               fc.position(0);
+                               InputStream in = Channels.newInputStream(fc);
+                               newBinary = session.getValueFactory().createBinary(in);
+                               file.getNode(Property.JCR_CONTENT).setProperty(Property.JCR_DATA, newBinary);
+                               session.save();
+                               open = false;
+                       } catch (RepositoryException e) {
+                               throw new JcrFsException("Cannot close " + file, e);
+                       }finally{
+                               JcrUtils.closeQuietly(newBinary);
+                               IOUtils.closeQuietly(fc);
+                       }
+               } else {
+                       clearReadState();
+                       open = false;
+               }
+       }
+
+       @Override
+       public int read(ByteBuffer dst) throws IOException {
+               if (isModified()) {
+                       return fc.read(dst);
+               } else {
+
+                       try {
+                               int read;
+//                             int capacity = dst.capacity();
+                               byte[] arr = dst.array();
+                               read = binary.read(arr, position);
+                               //dst.put(arr, 0, read);
+
+                               // try {
+                               // byte[] arr = dst.array();
+                               // read = binary.read(arr, position);
+                               // } catch (UnsupportedOperationException e) {
+                               // int capacity = dst.capacity();
+                               // byte[] arr = new byte[capacity];
+                               // read = binary.read(arr, position);
+                               // dst.put(arr);
+                               // }
+                               if (read != -1)
+                                       position = position + read;
+                               return read;
+                       } catch (RepositoryException e) {
+                               throw new JcrFsException("Cannot read into buffer", e);
+                       }
+               }
+       }
+
+       @Override
+       public int write(ByteBuffer src) throws IOException {
+               int written = getFileChannel().write(src);
+               return written;
+               // int byteCount = src.remaining();
+               // if (toWrite.remaining() < byteCount)
+               // throw new JcrFsException("Write buffer is full");
+               // toWrite.put(src);
+               // if (position < binarySize)
+               // position = binarySize + byteCount;
+               // else
+               // position = position + byteCount;
+               // return byteCount;
+       }
+
+       @Override
+       public long position() throws IOException {
+               if (isModified())
+                       return getFileChannel().position();
+               else
+                       return position;
+       }
+
+       @Override
+       public SeekableByteChannel position(long newPosition) throws IOException {
+               if (isModified()) {
+                       getFileChannel().position(position);
+               } else {
+                       this.position = newPosition;
+               }
+               return this;
+       }
+
+       @Override
+       public long size() throws IOException {
+               if (isModified()) {
+                       return getFileChannel().size();
+               } else {
+                       try {
+                               return binary.getSize();
+                       } catch (RepositoryException e) {
+                               throw new JcrFsException("Cannot get size", e);
+                       }
+               }
+       }
+
+       @Override
+       public SeekableByteChannel truncate(long size) throws IOException {
+               getFileChannel().truncate(size);
+               // if (size != size())
+               // throw new UnsupportedOperationException("Cannot truncate JCR
+               // binary");
+               return this;
+       }
+
+       private FileChannel getFileChannel() throws IOException {
+               try {
+                       if (fc == null) {
+                               Path tempPath = Files.createTempFile(getClass().getSimpleName(), null);
+                               fc = FileChannel.open(tempPath, StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE, StandardOpenOption.SPARSE);
+                               ReadableByteChannel readChannel = Channels.newChannel(binary.getStream());
+                               fc.transferFrom(readChannel, 0, binary.getSize());
+                               clearReadState();
+                       }
+                       return fc;
+               } catch (RepositoryException e) {
+                       throw new JcrFsException("Cannot get temp file channel", e);
+               }
+       }
+
+       private boolean isModified() {
+               return fc != null;
+       }
+       
+       private void clearReadState(){
+               position = -1;
+               JcrUtils.closeQuietly(binary);
+               binary=null;
+       }
+}