You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fm...@apache.org on 2015/10/31 13:24:27 UTC

svn commit: r1711615 - in /chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src: main/java/org/apache/chemistry/opencmis/client/util/ test/java/org/apache/chemistry/opencmis/client/runtime/

Author: fmui
Date: Sat Oct 31 12:24:27 2015
New Revision: 1711615

URL: http://svn.apache.org/viewvc?rev=1711615&view=rev
Log:
added ContentStreamUtils

Added:
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/util/ContentStreamUtils.java
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/test/java/org/apache/chemistry/opencmis/client/runtime/ContentStreamUtilsTest.java
Modified:
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/util/FileUtils.java

Added: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/util/ContentStreamUtils.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/util/ContentStreamUtils.java?rev=1711615&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/util/ContentStreamUtils.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/util/ContentStreamUtils.java Sat Oct 31 12:24:27 2015
@@ -0,0 +1,413 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.util;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import org.apache.chemistry.opencmis.commons.data.ContentStream;
+import org.apache.chemistry.opencmis.commons.data.MutableContentStream;
+import org.apache.chemistry.opencmis.commons.impl.IOUtils;
+import org.apache.chemistry.opencmis.commons.impl.MimeTypes;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
+
+/**
+ * Methods to create {@link ContentStream} objects.
+ */
+public final class ContentStreamUtils {
+
+    private static final String OCTETSTREAM = "application/octet-stream";
+
+    private ContentStreamUtils() {
+    }
+
+    // --- generic ---
+
+    /**
+     * Creates a content stream object for an InputStream.
+     * 
+     * @param filename
+     *            name of the content stream
+     * @param length
+     *            length of the stream in bytes
+     * @param mimetype
+     *            content MIME type
+     * @param stream
+     *            the InputStream
+     * 
+     * @return a {@link MutableContentStream} object
+     */
+    public static MutableContentStream createContentStream(String filename, long length, String mimetype,
+            InputStream stream) {
+        return createContentStream(filename, length < 0 ? null : BigInteger.valueOf(length), mimetype, stream);
+    }
+
+    /**
+     * Creates a content stream object for an InputStream.
+     * 
+     * @param filename
+     *            name of the content stream
+     * @param length
+     *            length of the stream in bytes
+     * @param mimetype
+     *            content MIME type
+     * @param stream
+     *            the InputStream
+     * 
+     * @return a {@link MutableContentStream} object
+     */
+    public static MutableContentStream createContentStream(String filename, BigInteger length, String mimetype,
+            InputStream stream) {
+        return new ContentStreamImpl(checkFilename(filename), length, checkMIMEType(mimetype), stream);
+    }
+
+    // --- byte arrays ---
+
+    /**
+     * Creates a content stream object from a byte array.
+     * 
+     * The MIME type is set to "application/octet-stream".
+     * 
+     * @param filename
+     *            name of the content stream
+     * @param contentBytes
+     *            content bytes
+     * 
+     * @return a {@link MutableContentStream} object
+     */
+    public static MutableContentStream createByteArrayContentStream(String filename, byte[] contentBytes) {
+        return createByteArrayContentStream(filename, contentBytes, OCTETSTREAM);
+    }
+
+    /**
+     * Creates a content stream object from a byte array.
+     * 
+     * @param filename
+     *            name of the content stream
+     * @param contentBytes
+     *            the content bytes
+     * @param mimetype
+     *            content MIME type
+     * 
+     * @return a {@link MutableContentStream} object
+     * 
+     */
+    public static MutableContentStream createByteArrayContentStream(String filename, byte[] contentBytes,
+            String mimetype) {
+        if (contentBytes == null) {
+            return createContentStream(filename, null, mimetype, null);
+        }
+
+        return createContentStream(filename, contentBytes.length, mimetype, new AutoCloseInputStream(
+                new ByteArrayInputStream(contentBytes)));
+    }
+
+    // --- strings ---
+
+    /**
+     * Creates a content stream object from a string.
+     * 
+     * The MIME type is set to "text/plain".
+     * 
+     * @param filename
+     *            name of the content stream
+     * @param content
+     *            the content string
+     * 
+     * @return a {@link MutableContentStream} object
+     */
+    public static MutableContentStream createTextContentStream(String filename, String content) {
+        return createTextContentStream(filename, content, "text/plain; charset=UTF-8");
+    }
+
+    /**
+     * Creates a content stream object from a string.
+     * 
+     * @param filename
+     *            name of the content stream
+     * @param content
+     *            the content string
+     * @param mimetype
+     *            content MIME type
+     * 
+     * @return a {@link MutableContentStream} object
+     */
+    public static MutableContentStream createTextContentStream(String filename, String content, String mimetype) {
+        byte[] contentBytes = IOUtils.toUTF8Bytes(content);
+        return createByteArrayContentStream(filename, contentBytes, checkMIMEType(mimetype));
+    }
+
+    // --- files ---
+
+    /**
+     * Creates a content stream object from file.
+     * 
+     * The MIME type is guessed from the file name and the content.
+     * 
+     * @param file
+     *            the file
+     * 
+     * @return a {@link MutableContentStream} object
+     */
+    public static MutableContentStream createFileContentStream(File file) throws FileNotFoundException {
+        return createFileContentStream(file.getName(), file, MimeTypes.getMIMEType(file));
+    }
+
+    /**
+     * Creates a content stream object from file.
+     * 
+     * The MIME type is guessed from the file name and the content.
+     * 
+     * @param filename
+     *            name of the content stream
+     * @param file
+     *            the file
+     * 
+     * @return a {@link MutableContentStream} object
+     */
+    public static MutableContentStream createFileContentStream(String filename, File file) throws FileNotFoundException {
+        return createFileContentStream(filename, file, MimeTypes.getMIMEType(file));
+    }
+
+    /**
+     * Creates a content stream object from file.
+     * 
+     * @param file
+     *            the file
+     * @param mimetype
+     *            content MIME type
+     * 
+     * @return a {@link MutableContentStream} object
+     */
+    public static MutableContentStream createFileContentStream(File file, String mimetype) throws FileNotFoundException {
+        return createFileContentStream(file.getName(), file, mimetype);
+    }
+
+    /**
+     * Creates a content stream object from file.
+     * 
+     * @param filename
+     *            name of the content stream
+     * @param file
+     *            the file
+     * @param mimetype
+     *            content MIME type
+     * 
+     * @return a {@link MutableContentStream} object
+     */
+    public static MutableContentStream createFileContentStream(String filename, File file, String mimetype)
+            throws FileNotFoundException {
+        return createContentStream(filename, file.length(), mimetype, new AutoCloseInputStream(new BufferedInputStream(
+                new FileInputStream(file))));
+    }
+
+    // --- helpers ---
+
+    private static String checkFilename(String filename) {
+        if (filename == null || filename.length() == 0) {
+            return "content";
+        }
+
+        return filename;
+    }
+
+    private static String checkMIMEType(String mimetype) {
+        if (mimetype == null) {
+            return OCTETSTREAM;
+        }
+
+        String result = mimetype.trim();
+        if (result.length() < 3) {
+            return OCTETSTREAM;
+        }
+
+        return result;
+    }
+
+    // --- classes ---
+
+    /**
+     * InputStream that gets closed when the end of the stream is reached or the
+     * underlying stream throws an exception.
+     */
+    public static class AutoCloseInputStream extends InputStream {
+
+        protected InputStream stream;
+
+        public AutoCloseInputStream(InputStream in) {
+            stream = in;
+        }
+
+        @Override
+        public int read() throws IOException {
+            if (stream != null) {
+                int b = -1;
+
+                try {
+                    b = stream.read();
+                } catch (IOException ioe) {
+                    closeQuietly();
+                    throw ioe;
+                }
+
+                if (b == -1) {
+                    close();
+                }
+
+                return b;
+            } else {
+                throw new IOException("Stream is already closed!");
+            }
+        }
+
+        @Override
+        public int read(byte[] b) throws IOException {
+            if (stream != null) {
+                int l = -1;
+
+                try {
+                    l = stream.read(b);
+                } catch (IOException ioe) {
+                    closeQuietly();
+                    throw ioe;
+                }
+
+                if (l == -1) {
+                    close();
+                }
+
+                return l;
+            } else {
+                throw new IOException("Stream is already closed!");
+            }
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            if (stream != null) {
+                int l = -1;
+
+                try {
+                    l = stream.read(b, off, len);
+                } catch (IOException ioe) {
+                    closeQuietly();
+                    throw ioe;
+                }
+
+                if (l == -1) {
+                    close();
+                }
+
+                return l;
+            } else {
+                throw new IOException("Stream is already closed!");
+            }
+        }
+
+        @Override
+        public long skip(long n) throws IOException {
+            if (stream != null) {
+                try {
+                    return stream.skip(n);
+                } catch (IOException ioe) {
+                    closeQuietly();
+                    throw ioe;
+                }
+            } else {
+                throw new IOException("Stream is already closed!");
+            }
+        }
+
+        @Override
+        public int available() throws IOException {
+            if (stream != null) {
+                try {
+                    return stream.available();
+                } catch (IOException ioe) {
+                    closeQuietly();
+                    throw ioe;
+                }
+            } else {
+                throw new IOException("Stream is already closed!");
+            }
+        }
+
+        @Override
+        public void close() throws IOException {
+            if (stream != null) {
+                stream.close();
+                stream = null;
+            }
+        }
+
+        public void closeQuietly() {
+            if (stream != null) {
+                try {
+                    stream.close();
+                } catch (final IOException ioe) {
+                    // ignore
+                } finally {
+                    stream = null;
+                }
+            }
+        }
+
+        @Override
+        public synchronized void mark(int readlimit) {
+            if (stream != null) {
+                stream.mark(readlimit);
+            }
+        }
+
+        @Override
+        public synchronized void reset() throws IOException {
+            if (stream != null) {
+                try {
+                    stream.reset();
+                } catch (IOException ioe) {
+                    closeQuietly();
+                    throw ioe;
+                }
+            } else {
+                throw new IOException("Stream is already closed!");
+            }
+        }
+
+        @Override
+        public boolean markSupported() {
+            if (stream != null) {
+                return stream.markSupported();
+            }
+
+            return false;
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            closeQuietly();
+            super.finalize();
+        }
+    }
+}

Modified: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/util/FileUtils.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/util/FileUtils.java?rev=1711615&r1=1711614&r2=1711615&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/util/FileUtils.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/util/FileUtils.java Sat Oct 31 12:24:27 2015
@@ -18,15 +18,11 @@
  */
 package org.apache.chemistry.opencmis.client.util;
 
-import java.io.ByteArrayInputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.PrintStream;
-import java.math.BigInteger;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -41,10 +37,7 @@ import org.apache.chemistry.opencmis.com
 import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
 import org.apache.chemistry.opencmis.commons.enums.VersioningState;
 import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
-import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
 import org.apache.chemistry.opencmis.commons.impl.IOUtils;
-import org.apache.chemistry.opencmis.commons.impl.MimeTypes;
-import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
 
 /**
  * A set of utility methods that simplify file and folder operations.
@@ -126,25 +119,17 @@ public final class FileUtils {
         Folder parentFolder = getFolder(parentIdOrPath, session);
 
         String name = file.getName();
-        String mimetype = MimeTypes.getMIMEType(file);
 
         Map<String, Object> properties = new HashMap<String, Object>();
         properties.put(PropertyIds.OBJECT_TYPE_ID, type);
         properties.put(PropertyIds.NAME, name);
 
-        InputStream stream = new FileInputStream(file);
-        ContentStream contentStream = new ContentStreamImpl(name, BigInteger.valueOf(file.length()), mimetype, stream);
+        ContentStream contentStream = ContentStreamUtils.createFileContentStream(name, file);
 
         try {
             return parentFolder.createDocument(properties, contentStream, versioningState);
         } finally {
-            if (stream != null) {
-                try {
-                    stream.close();
-                } catch (IOException ioe) {
-                    throw new CmisRuntimeException("Cannot close source stream!", ioe);
-                }
-            }
+            IOUtils.closeQuietly(contentStream);
         }
     }
 
@@ -177,16 +162,13 @@ public final class FileUtils {
         properties.put(PropertyIds.OBJECT_TYPE_ID, type);
         properties.put(PropertyIds.NAME, name);
 
-        byte[] contentBytes = new byte[0];
-        if (content != null) {
-            contentBytes = IOUtils.toUTF8Bytes(content);
-        }
-
-        ByteArrayInputStream bais = new ByteArrayInputStream(contentBytes);
-        ContentStream contentStream = new ContentStreamImpl(name, BigInteger.valueOf(contentBytes.length),
-                "text/plain", bais);
+        ContentStream contentStream = ContentStreamUtils.createTextContentStream(name, content);
 
-        return parentFolder.createDocument(properties, contentStream, versioningState);
+        try {
+            return parentFolder.createDocument(properties, contentStream, versioningState);
+        } finally {
+            IOUtils.closeQuietly(contentStream);
+        }
     }
 
     /**

Added: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/test/java/org/apache/chemistry/opencmis/client/runtime/ContentStreamUtilsTest.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/test/java/org/apache/chemistry/opencmis/client/runtime/ContentStreamUtilsTest.java?rev=1711615&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/test/java/org/apache/chemistry/opencmis/client/runtime/ContentStreamUtilsTest.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/test/java/org/apache/chemistry/opencmis/client/runtime/ContentStreamUtilsTest.java Sat Oct 31 12:24:27 2015
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.runtime;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.Locale;
+
+import org.apache.chemistry.opencmis.client.util.ContentStreamUtils;
+import org.apache.chemistry.opencmis.client.util.ContentStreamUtils.AutoCloseInputStream;
+import org.apache.chemistry.opencmis.commons.data.MutableContentStream;
+import org.apache.chemistry.opencmis.commons.impl.IOUtils;
+import org.junit.Test;
+
+public class ContentStreamUtilsTest {
+
+    private static final String CONTENT = "content";
+    private static final byte[] CONTENT_BYTES = IOUtils.toUTF8Bytes(CONTENT);
+
+    @Test
+    public void testTextContentStream() throws IOException {
+        MutableContentStream contentStream = ContentStreamUtils.createTextContentStream("filename", CONTENT);
+
+        assertNotNull(contentStream);
+        assertEquals("filename", contentStream.getFileName());
+        assertEquals("text/plain; charset=UTF-8", contentStream.getMimeType());
+        assertEquals(CONTENT_BYTES.length, contentStream.getLength());
+        assertNotNull(contentStream.getStream());
+        assertTrue(contentStream.getStream() instanceof ContentStreamUtils.AutoCloseInputStream);
+
+        AutoCloseInputStream in = (AutoCloseInputStream) contentStream.getStream();
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        if (in.markSupported()) {
+            in.mark(1024);
+            in.read();
+            in.reset();
+        }
+
+        assertEquals(CONTENT_BYTES.length, in.available());
+
+        IOUtils.copy(in, out);
+
+        assertArrayEquals(CONTENT_BYTES, out.toByteArray());
+
+        try {
+            in.read();
+            fail();
+        } catch (IOException ioe) {
+            // excpeted
+        }
+
+        assertFalse(in.markSupported());
+    }
+
+    @Test
+    public void testEmptyContentStream() throws IOException {
+        MutableContentStream contentStream = ContentStreamUtils.createByteArrayContentStream(null, new byte[0]);
+
+        assertNotNull(contentStream);
+        assertEquals("content", contentStream.getFileName());
+        assertEquals("application/octet-stream", contentStream.getMimeType());
+        assertEquals(0, contentStream.getLength());
+        assertEquals(BigInteger.ZERO, contentStream.getBigLength());
+        assertNotNull(contentStream.getStream());
+
+        InputStream in = (InputStream) contentStream.getStream();
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        IOUtils.copy(in, out);
+
+        assertEquals(0, out.toByteArray().length);
+
+        contentStream.setFileName("myFile");
+        assertEquals("myFile", contentStream.getFileName());
+        contentStream.setMimeType("mime/type");
+        assertEquals("mime/type", contentStream.getMimeType());
+
+        try {
+            in.read();
+            fail();
+        } catch (IOException ioe) {
+            // excpeted
+        }
+    }
+
+    @Test
+    public void testNullContentStream() throws IOException {
+        MutableContentStream contentStream = ContentStreamUtils.createByteArrayContentStream(null, null, null);
+
+        assertNotNull(contentStream);
+        assertEquals("content", contentStream.getFileName());
+        assertEquals("application/octet-stream", contentStream.getMimeType());
+        assertEquals(-1, contentStream.getLength());
+        assertNull(contentStream.getBigLength());
+        assertNull(contentStream.getStream());
+    }
+
+    @Test
+    public void testFileContentStream() throws IOException {
+        File tmpFile = File.createTempFile("test", ".txt");
+
+        FileOutputStream fos = new FileOutputStream(tmpFile);
+        fos.write(CONTENT_BYTES);
+        fos.close();
+
+        MutableContentStream contentStream = ContentStreamUtils.createFileContentStream(tmpFile);
+
+        assertNotNull(contentStream);
+        assertEquals(tmpFile.getName(), contentStream.getFileName());
+        assertTrue(contentStream.getMimeType().toLowerCase(Locale.ENGLISH).startsWith("text/plain"));
+        assertEquals(CONTENT_BYTES.length, contentStream.getLength());
+        assertNotNull(contentStream.getStream());
+        assertTrue(contentStream.getStream() instanceof ContentStreamUtils.AutoCloseInputStream);
+
+        AutoCloseInputStream in = (AutoCloseInputStream) contentStream.getStream();
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        IOUtils.copy(in, out);
+
+        assertArrayEquals(CONTENT_BYTES, out.toByteArray());
+
+        try {
+            in.read();
+            fail();
+        } catch (IOException ioe) {
+            // excpeted
+        }
+
+        in.closeQuietly();
+    }
+}