This project has retired. For details please refer to its Attic page.
JcrBinary xref

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.chemistry.opencmis.jcr;
21  
22  import javax.jcr.Binary;
23  import javax.jcr.RepositoryException;
24  import java.io.ByteArrayInputStream;
25  import java.io.File;
26  import java.io.FileInputStream;
27  import java.io.FileNotFoundException;
28  import java.io.FileOutputStream;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.io.OutputStream;
32  import java.io.RandomAccessFile;
33  
34  /**
35   * <code>JcrBinary</code> implements the JCR <code>Binary</code> interface.
36   * This is mostly a copy from org.apache.jackrabbit.value.BinaryImpl in
37   * Apache Jackrabbit's jcr-commons module. 
38   */
39  public class JcrBinary implements Binary {
40  
41      /**
42       * empty array
43       */
44      private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
45  
46      /**
47       * max size for keeping tmp data in memory
48       */
49      private static final int MAX_BUFFER_SIZE = 0x10000;
50  
51      /**
52       * underlying tmp file
53       */
54      private final File tmpFile;
55  
56      /**
57       * buffer for small-sized data
58       */
59      private byte[] buffer = EMPTY_BYTE_ARRAY;
60  
61      public static final Binary EMPTY = new JcrBinary(EMPTY_BYTE_ARRAY);
62  
63      /**
64       * Creates a new <code>JcrBinary</code> instance from an <code>InputStream</code>.
65       * The contents of the stream is spooled to a temporary file or to a byte buffer
66       * if its size is smaller than {@link #MAX_BUFFER_SIZE}.
67       * The input stream is closed by this implementation.
68       *
69       * @param in  stream to be represented as a <code>JcrBinary</code> instance
70       * @throws IOException if an error occurs while reading from the stream or
71       *      writing to the temporary file
72       */
73      public JcrBinary(InputStream in) throws IOException {
74          byte[] spoolBuffer = new byte[0x2000];
75          int read;
76          int len = 0;
77          OutputStream out = null;
78          File spoolFile = null;
79          try {
80              while ((read = in.read(spoolBuffer)) > 0) {
81                  if (out != null) {
82                      // spool to temp file
83                      out.write(spoolBuffer, 0, read);
84                      len += read;
85                  }
86                  else if (len + read > MAX_BUFFER_SIZE) {
87                      // threshold for keeping data in memory exceeded;
88                      // create temp file and spool buffer contents
89  
90                      spoolFile = File.createTempFile("bin", null, null);
91                      out = new FileOutputStream(spoolFile);
92                      out.write(buffer, 0, len);
93                      out.write(spoolBuffer, 0, read);
94                      buffer = null;
95                      len += read;
96                  }
97                  else {
98                      // reallocate new buffer and spool old buffer contents
99                      byte[] newBuffer = new byte[len + read];
100                     System.arraycopy(buffer, 0, newBuffer, 0, len);
101                     System.arraycopy(spoolBuffer, 0, newBuffer, len, read);
102                     buffer = newBuffer;
103                     len += read;
104                 }
105             }
106         }
107         finally {
108             in.close();
109             if (out != null) {
110                 out.close();
111             }
112         }
113 
114         // init fields
115         tmpFile = spoolFile;
116     }
117 
118     /**
119      * Creates a new <code>JcrBinary</code> instance from a <code>byte[]</code> array.
120      * 
121      * @param buffer byte array to be represented as a <code>JcrBinary</code> instance
122      */
123     public JcrBinary(byte[] buffer) {
124         if (buffer == null) {
125             throw new IllegalArgumentException("buffer must be non-null");
126         }
127         this.buffer = buffer;
128         tmpFile = null;
129     }
130 
131     public InputStream getStream() throws RepositoryException {
132         if (tmpFile != null) {
133             try {
134                 // this instance is backed by a temp file
135                 return new FileInputStream(tmpFile);
136             }
137             catch (FileNotFoundException e) {
138                 throw new RepositoryException("already disposed");
139             }
140         }
141         else {
142             // this instance is backed by an in-memory buffer
143             return new ByteArrayInputStream(buffer);
144         }
145     }
146 
147     public int read(byte[] b, long position) throws IOException, RepositoryException {
148         if (tmpFile != null) {
149             // this instance is backed by a temp file
150             RandomAccessFile raf = new RandomAccessFile(tmpFile, "r");
151             try {
152                 raf.seek(position);
153                 return raf.read(b);
154             }
155             finally {
156                 raf.close();
157             }
158         }
159         else {
160             // this instance is backed by an in-memory buffer
161             int length = Math.min(b.length, buffer.length - (int) position);
162             if (length > 0) {
163                 System.arraycopy(buffer, (int) position, b, 0, length);
164                 return length;
165             }
166             else {
167                 return -1;
168             }
169         }
170     }
171 
172     public long getSize() throws RepositoryException {
173         if (tmpFile != null) {
174             // this instance is backed by a temp file
175             return tmpFile.exists() ? tmpFile.length() : -1;
176         }
177         else {
178             // this instance is backed by an in-memory buffer
179             return buffer.length;
180         }
181     }
182 
183     public void dispose() {
184         if (tmpFile != null) {
185             // this instance is backed by a temp file
186             tmpFile.delete();
187         }
188         else {
189             // this instance is backed by an in-memory buffer
190             buffer = EMPTY_BYTE_ARRAY;
191         }
192     }
193 
194 }