]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.jcr/src/org/argeo/jcr/fs/BinaryChannel.java
b90bb900ae129827768f277831a86e17a128f018
[lgpl/argeo-commons.git] / org.argeo.jcr / src / org / argeo / jcr / 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 data.setProperty(Property.JCR_DATA, this.binary);
49 data.getSession().save();
50 }
51 } else {
52 throw new IllegalArgumentException(
53 "Unsupported file node " + file + " (" + file.getPrimaryNodeType() + ")");
54 }
55 }
56
57 @Override
58 public synchronized boolean isOpen() {
59 return open;
60 }
61
62 @Override
63 public synchronized void close() throws IOException {
64 if (isModified()) {
65 Binary newBinary = null;
66 try {
67 Session session = file.getSession();
68 // byte[] arr = new byte[(int) position];
69 // toWrite.flip();
70 // toWrite.get(arr);
71 fc.position(0);
72 InputStream in = Channels.newInputStream(fc);
73 newBinary = session.getValueFactory().createBinary(in);
74 file.getNode(Property.JCR_CONTENT).setProperty(Property.JCR_DATA, newBinary);
75 session.save();
76 open = false;
77 } catch (RepositoryException e) {
78 throw new JcrFsException("Cannot close " + file, e);
79 } finally {
80 JcrUtils.closeQuietly(newBinary);
81 IOUtils.closeQuietly(fc);
82 }
83 } else {
84 clearReadState();
85 open = false;
86 }
87 }
88
89 @Override
90 public int read(ByteBuffer dst) throws IOException {
91 if (isModified()) {
92 return fc.read(dst);
93 } else {
94
95 try {
96 int read;
97 // int capacity = dst.capacity();
98 byte[] arr = dst.array();
99 read = binary.read(arr, position);
100 // dst.put(arr, 0, read);
101
102 // try {
103 // byte[] arr = dst.array();
104 // read = binary.read(arr, position);
105 // } catch (UnsupportedOperationException e) {
106 // int capacity = dst.capacity();
107 // byte[] arr = new byte[capacity];
108 // read = binary.read(arr, position);
109 // dst.put(arr);
110 // }
111 if (read != -1)
112 position = position + read;
113 return read;
114 } catch (RepositoryException e) {
115 throw new JcrFsException("Cannot read into buffer", e);
116 }
117 }
118 }
119
120 @Override
121 public int write(ByteBuffer src) throws IOException {
122 int written = getFileChannel().write(src);
123 return written;
124 // int byteCount = src.remaining();
125 // if (toWrite.remaining() < byteCount)
126 // throw new JcrFsException("Write buffer is full");
127 // toWrite.put(src);
128 // if (position < binarySize)
129 // position = binarySize + byteCount;
130 // else
131 // position = position + byteCount;
132 // return byteCount;
133 }
134
135 @Override
136 public long position() throws IOException {
137 if (isModified())
138 return getFileChannel().position();
139 else
140 return position;
141 }
142
143 @Override
144 public SeekableByteChannel position(long newPosition) throws IOException {
145 if (isModified()) {
146 getFileChannel().position(position);
147 } else {
148 this.position = newPosition;
149 }
150 return this;
151 }
152
153 @Override
154 public long size() throws IOException {
155 if (isModified()) {
156 return getFileChannel().size();
157 } else {
158 try {
159 return binary.getSize();
160 } catch (RepositoryException e) {
161 throw new JcrFsException("Cannot get size", e);
162 }
163 }
164 }
165
166 @Override
167 public SeekableByteChannel truncate(long size) throws IOException {
168 getFileChannel().truncate(size);
169 // if (size != size())
170 // throw new UnsupportedOperationException("Cannot truncate JCR
171 // binary");
172 return this;
173 }
174
175 private FileChannel getFileChannel() throws IOException {
176 try {
177 if (fc == null) {
178 Path tempPath = Files.createTempFile(getClass().getSimpleName(), null);
179 fc = FileChannel.open(tempPath, StandardOpenOption.WRITE, StandardOpenOption.READ,
180 StandardOpenOption.DELETE_ON_CLOSE, StandardOpenOption.SPARSE);
181 ReadableByteChannel readChannel = Channels.newChannel(binary.getStream());
182 fc.transferFrom(readChannel, 0, binary.getSize());
183 clearReadState();
184 }
185 return fc;
186 } catch (RepositoryException e) {
187 throw new JcrFsException("Cannot get temp file channel", e);
188 }
189 }
190
191 private boolean isModified() {
192 return fc != null;
193 }
194
195 private void clearReadState() {
196 position = -1;
197 JcrUtils.closeQuietly(binary);
198 binary = null;
199 }
200 }