1 package org
.argeo
.jcr
.fs
;
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
;
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
;
22 import org
.argeo
.jcr
.JcrUtils
;
24 /** A read/write {@link SeekableByteChannel} based on a {@link Binary}. */
25 public class BinaryChannel
implements SeekableByteChannel
{
26 private final Node file
;
27 private Binary binary
;
28 private boolean open
= true;
30 private long position
= 0;
32 private FileChannel fc
= null;
34 public BinaryChannel(Node file
, Path path
) throws RepositoryException
, IOException
{
36 Session session
= file
.getSession();
37 synchronized (session
) {
38 if (file
.isNodeType(NodeType
.NT_FILE
)) {
39 if (file
.hasNode(Node
.JCR_CONTENT
)) {
40 Node data
= file
.getNode(Property
.JCR_CONTENT
);
41 this.binary
= data
.getProperty(Property
.JCR_DATA
).getBinary();
43 Node data
= file
.addNode(Node
.JCR_CONTENT
, NodeType
.NT_UNSTRUCTURED
);
44 data
.addMixin(NodeType
.MIX_LAST_MODIFIED
);
45 try (InputStream in
= new ByteArrayInputStream(new byte[0])) {
46 this.binary
= data
.getSession().getValueFactory().createBinary(in
);
48 data
.setProperty(Property
.JCR_DATA
, this.binary
);
51 String mime
= Files
.probeContentType(path
);
52 // String mime = fileTypeMap.getContentType(file.getName());
53 data
.setProperty(Property
.JCR_MIMETYPE
, mime
);
55 session
.refresh(true);
60 throw new IllegalArgumentException(
61 "Unsupported file node " + file
+ " (" + file
.getPrimaryNodeType() + ")");
67 public synchronized boolean isOpen() {
72 public synchronized void close() throws IOException
{
74 Binary newBinary
= null;
76 Session session
= file
.getSession();
77 synchronized (session
) {
79 InputStream in
= Channels
.newInputStream(fc
);
80 newBinary
= session
.getValueFactory().createBinary(in
);
81 file
.getNode(Property
.JCR_CONTENT
).setProperty(Property
.JCR_DATA
, newBinary
);
82 session
.refresh(true);
87 } catch (RepositoryException e
) {
88 throw new IOException("Cannot close " + file
, e
);
90 JcrUtils
.closeQuietly(newBinary
);
91 // IOUtils.closeQuietly(fc);
103 public int read(ByteBuffer dst
) throws IOException
{
110 byte[] arr
= dst
.array();
111 read
= binary
.read(arr
, position
);
114 position
= position
+ read
;
116 } catch (RepositoryException e
) {
117 throw new IOException("Cannot read into buffer", e
);
123 public int write(ByteBuffer src
) throws IOException
{
124 int written
= getFileChannel().write(src
);
129 public long position() throws IOException
{
131 return getFileChannel().position();
137 public SeekableByteChannel
position(long newPosition
) throws IOException
{
139 getFileChannel().position(position
);
141 this.position
= newPosition
;
147 public long size() throws IOException
{
149 return getFileChannel().size();
152 return binary
.getSize();
153 } catch (RepositoryException e
) {
154 throw new IOException("Cannot get size", e
);
160 public SeekableByteChannel
truncate(long size
) throws IOException
{
161 getFileChannel().truncate(size
);
165 private FileChannel
getFileChannel() throws IOException
{
168 Path tempPath
= Files
.createTempFile(getClass().getSimpleName(), null);
169 fc
= FileChannel
.open(tempPath
, StandardOpenOption
.WRITE
, StandardOpenOption
.READ
,
170 StandardOpenOption
.DELETE_ON_CLOSE
, StandardOpenOption
.SPARSE
);
171 ReadableByteChannel readChannel
= Channels
.newChannel(binary
.getStream());
172 fc
.transferFrom(readChannel
, 0, binary
.getSize());
176 } catch (RepositoryException e
) {
177 throw new IOException("Cannot get temp file channel", e
);
181 private boolean isModified() {
185 private void clearReadState() {
187 JcrUtils
.closeQuietly(binary
);