2 Replies Latest reply on Dec 1, 2015 2:44 AM by hchiorean

    Error converting InputStream to a BinaryValue

    jessie_jie_xie

      Hi Guys,

       

      The creation and handling SNS nodes is OK in 4.5.0. Thank you very much!

       

      And now there is another issue when I am using CXF framework with ModeShape 4.5.0. Please see exception stack information below.

       

      Caused by: org.modeshape.jcr.value.ValueFormatException: Error converting InputStream to a BinaryValue

        at org.modeshape.jcr.value.binary.BinaryStoreValueFactory.create(BinaryStoreValueFactory.java:246)

        at org.modeshape.jcr.value.binary.BinaryStoreValueFactory.create(BinaryStoreValueFactory.java:49)

        at org.modeshape.jcr.JcrValueFactory.createBinary(JcrValueFactory.java:141)

        at org.modeshape.jcr.JcrValueFactory.createBinary(JcrValueFactory.java:41)

        at com.shidaits.cds.service.JcrOperation.updateResouce(JcrOperation.java:342)

        at com.shidaits.cds.service.JcrOperation.updateFile(JcrOperation.java:315)

        ... 47 more

      Caused by: org.modeshape.jcr.value.binary.BinaryStoreException: java.io.IOException: Stream Closed

        at org.modeshape.jcr.value.binary.FileSystemBinaryStore.storeValue(FileSystemBinaryStore.java:129)

        at org.modeshape.jcr.value.binary.BinaryStoreValueFactory.create(BinaryStoreValueFactory.java:244)

        ... 52 more

      Caused by: java.io.IOException: Stream Closed

        at java.io.FileInputStream.available(Native Method)

        at org.apache.cxf.attachment.DelegatingInputStream.available(DelegatingInputStream.java:78)

        at org.apache.cxf.helpers.IOUtils.consume(IOUtils.java:340)

        at org.apache.cxf.attachment.DelegatingInputStream.close(DelegatingInputStream.java:49)

        at org.modeshape.common.util.SecureHash$HashingInputStream.close(SecureHash.java:389)

        at org.modeshape.jcr.value.binary.FileSystemBinaryStore.storeValue(FileSystemBinaryStore.java:111)

        ... 53 more

       

      I found that in org.modeshape.jcr.value.binary.FileSystemBinaryStore, hashingStream has been closed in IoUtil.write(). After that when calling hasingStream.close(), the FileInputStream based class will throw IOException if available() function is called during its close(). Unfortunately, CXF constructs FileInputStream when the uploaded file size is larger than some threshhold.

       

          @Override

          public BinaryValue storeValue( InputStream stream, boolean markAsUnused ) throws BinaryStoreException {

              File tmpFile = null;

              BinaryValue value = null;

              try {

                  // Write the contents to a temporary file, and while we do grab the SHA-1 hash and the length ...

                  HashingInputStream hashingStream = SecureHash.createHashingStream(Algorithm.SHA_1, stream);

                  tmpFile = File.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX);

                  IoUtil.write(hashingStream, new BufferedOutputStream(new FileOutputStream(tmpFile)),

                               AbstractBinaryStore.MEDIUM_BUFFER_SIZE);

                  hashingStream.close();

       

       

       

      public int available() throws IOException

      Returns an estimate of the number of remaining bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream. The next invocation might be the same thread or another thread. A single read or skip of this many bytes will not block, but may read or skip fewer bytes.

      In some cases, a non-blocking read (or skip) may appear to be blocked when it is merely slow, for example when reading large files over slow networks.

      Overrides:
      available in class InputStream
      Returns:
      an estimate of the number of remaining bytes that can be read (or skipped over) from this input stream without blocking.
      Throws:
      IOException - if this file input stream has been closed by calling close or an I/O error occurs.
        • 1. Re: Error converting InputStream to a BinaryValue
          hchiorean

          I'm in 2 minds whether this is a bug in ModeShape or not:

           

          - on one hand, you are correct - that part of the code does close the input stream (hashing stream) twice. This isn't really required so we can easily make the change to remove the hashingStream.close call

          - on the other hand, the JavaDoc from the Closable interface states:

           

          /**
               * Closes this stream and releases any system resources associated
               * with it. If the stream is already closed then invoking this
               * method has no effect.
               *
               * <p> As noted in {@link AutoCloseable#close()}, cases where the
               * close may fail require careful attention. It is strongly advised
               * to relinquish the underlying resources and to internally
               * <em>mark</em> the {@code Closeable} as closed, prior to throwing
               * the {@code IOException}.
               *
               * @throws IOException if an I/O error occurs
               */
              public void close() throws IOException;
          
          

           

          meaning that the close method on any Closable should be idempotent. In other words, CXF does not respect this contract. From this perspective, the problem is with CXF's stream, not ModeShape.

          • 2. Re: Error converting InputStream to a BinaryValue
            hchiorean

            I've opened [MODE-2541] When storing binaries in the FS binary store, avoid storing the hasing stream twice - JBoss Issue Tracker, but as a minor task for 4.6. As explained above, I don't consider this a bug in ModeShape, but a problem with CXF's stream.