]> git.argeo.org Git - lgpl/argeo-commons.git/blob - fs/BinaryChannel.java
Prepare next development cycle
[lgpl/argeo-commons.git] / fs / BinaryChannel.java
1 package org.argeo.jcr.fs;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.nio.ByteBuffer;
7 import java.nio.channels.Channels;
8 import java.nio.channels.FileChannel;
9 import java.nio.channels.ReadableByteChannel;
10 import java.nio.channels.SeekableByteChannel;
11 import java.nio.file.Files;
12 import java.nio.file.Path;
13 import java.nio.file.StandardOpenOption;
14
15 import javax.jcr.Binary;
16 import javax.jcr.Node;
17 import javax.jcr.Property;
18 import javax.jcr.RepositoryException;
19 import javax.jcr.Session;
20 import javax.jcr.nodetype.NodeType;
21
22 import org.apache.commons.io.IOUtils;
23 import org.argeo.jcr.JcrUtils;
24
25 public class BinaryChannel implements SeekableByteChannel {
26 private final Node file;
27 private Binary binary;
28 private boolean open = true;
29
30 private long position = 0;
31
32 // private ByteBuffer toWrite;
33 private FileChannel fc = null;
34
35 public BinaryChannel(Node file) throws RepositoryException, IOException {
36 this.file = file;
37 // int capacity = 1024 * 1024;
38 // this.toWrite = ByteBuffer.allocate(capacity);
39 if (file.isNodeType(NodeType.NT_FILE)) {
40 if (file.hasNode(Property.JCR_CONTENT)) {
41 Node data = file.getNode(Property.JCR_CONTENT);
42 this.binary = data.getProperty(Property.JCR_DATA).getBinary();
43 } else {
44 Node data = file.addNode(Property.JCR_CONTENT, NodeType.NT_RESOURCE);
45 try (InputStream in = new ByteArrayInputStream(new byte[0])) {
46 this.binary = data.getSession().getValueFactory().createBinary(in);
47 }
48 }
49 } else {
50 throw new IllegalArgumentException(
51 "Unsupported file node " + file + " (" + file.getPrimaryNodeType() + ")");
52 }
53 }
54
55 @Override
56 public synchronized boolean isOpen() {
57 return open;
58 }
59
60 @Override
61 public synchronized void close() throws IOException {
62 if (isModified()) {
63 Binary newBinary=null;
64 try {
65 Session session = file.getSession();
66 // byte[] arr = new byte[(int) position];
67 // toWrite.flip();
68 // toWrite.get(arr);
69 fc.position(0);
70 InputStream in = Channels.newInputStream(fc);
71 newBinary = session.getValueFactory().createBinary(in);
72 file.getNode(Property.JCR_CONTENT).setProperty(Property.JCR_DATA, newBinary);
73 session.save();
74 open = false;
75 } catch (RepositoryException e) {
76 throw new JcrFsException("Cannot close " + file, e);
77 }finally{
78 JcrUtils.closeQuietly(newBinary);
79 IOUtils.closeQuietly(fc);
80 }
81 } else {
82 clearReadState();
83 open = false;
84 }
85 }
86
87 @Override
88 public int read(ByteBuffer dst) throws IOException {
89 if (isModified()) {
90 return fc.read(dst);
91 } else {
92
93 try {
94 int read;
95 // int capacity = dst.capacity();
96 byte[] arr = dst.array();
97 read = binary.read(arr, position);
98 //dst.put(arr, 0, read);
99
100 // try {
101 // byte[] arr = dst.array();
102 // read = binary.read(arr, position);
103 // } catch (UnsupportedOperationException e) {
104 // int capacity = dst.capacity();
105 // byte[] arr = new byte[capacity];
106 // read = binary.read(arr, position);
107 // dst.put(arr);
108 // }
109 if (read != -1)
110 position = position + read;
111 return read;
112 } catch (RepositoryException e) {
113 throw new JcrFsException("Cannot read into buffer", e);
114 }
115 }
116 }
117
118 @Override
119 public int write(ByteBuffer src) throws IOException {
120 int written = getFileChannel().write(src);
121 return written;
122 // int byteCount = src.remaining();
123 // if (toWrite.remaining() < byteCount)
124 // throw new JcrFsException("Write buffer is full");
125 // toWrite.put(src);
126 // if (position < binarySize)
127 // position = binarySize + byteCount;
128 // else
129 // position = position + byteCount;
130 // return byteCount;
131 }
132
133 @Override
134 public long position() throws IOException {
135 if (isModified())
136 return getFileChannel().position();
137 else
138 return position;
139 }
140
141 @Override
142 public SeekableByteChannel position(long newPosition) throws IOException {
143 if (isModified()) {
144 getFileChannel().position(position);
145 } else {
146 this.position = newPosition;
147 }
148 return this;
149 }
150
151 @Override
152 public long size() throws IOException {
153 if (isModified()) {
154 return getFileChannel().size();
155 } else {
156 try {
157 return binary.getSize();
158 } catch (RepositoryException e) {
159 throw new JcrFsException("Cannot get size", e);
160 }
161 }
162 }
163
164 @Override
165 public SeekableByteChannel truncate(long size) throws IOException {
166 getFileChannel().truncate(size);
167 // if (size != size())
168 // throw new UnsupportedOperationException("Cannot truncate JCR
169 // binary");
170 return this;
171 }
172
173 private FileChannel getFileChannel() throws IOException {
174 try {
175 if (fc == null) {
176 Path tempPath = Files.createTempFile(getClass().getSimpleName(), null);
177 fc = FileChannel.open(tempPath, StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE, StandardOpenOption.SPARSE);
178 ReadableByteChannel readChannel = Channels.newChannel(binary.getStream());
179 fc.transferFrom(readChannel, 0, binary.getSize());
180 clearReadState();
181 }
182 return fc;
183 } catch (RepositoryException e) {
184 throw new JcrFsException("Cannot get temp file channel", e);
185 }
186 }
187
188 private boolean isModified() {
189 return fc != null;
190 }
191
192 private void clearReadState(){
193 position = -1;
194 JcrUtils.closeQuietly(binary);
195 binary=null;
196 }
197 }