/** * Copyright (C) 2010-2017 Structr GmbH * * This file is part of Structr <http://structr.org>. * * Structr is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * Structr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Structr. If not, see <http://www.gnu.org/licenses/>. */ package org.structr.files.cmis.wrapper; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.StandardOpenOption; import org.apache.chemistry.opencmis.commons.data.ContentStream; import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException; import org.structr.cmis.common.CMISExtensionsData; import org.structr.web.entity.FileBase; /** * An implementation of the CMIS ContentStream interface using a MappedByteBuffer. * * */ public class CMISContentStream extends CMISExtensionsData implements ContentStream { private String contentType = null; private String name = null; private long length = 0L; private File file = null; private long offset = 0L; public CMISContentStream(final FileBase file, final BigInteger offset, final BigInteger length) { this.contentType = file.getProperty(FileBase.contentType); this.name = file.getName(); this.file = file.getFileOnDisk(); this.offset = offset != null ? offset.longValue() : 0L; this.length = length != null ? length.longValue() : file.getSize(); } @Override public long getLength() { return length; } @Override public BigInteger getBigLength() { return BigInteger.valueOf(length); } @Override public String getMimeType() { return contentType; } @Override public String getFileName() { return name; } @Override public InputStream getStream() { try { final FileChannel channel = FileChannel.open(file.toPath(), StandardOpenOption.READ); final long mappedLength = Math.max(0, Math.min(channel.size() - offset, length)); final MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, offset, mappedLength); return new MappedInputStream(buffer); } catch (IOException ioex) { throw new CmisConstraintException(ioex.getMessage()); } } // ----- nested classes ----- private class MappedInputStream extends InputStream { private MappedByteBuffer buffer = null; public MappedInputStream(final MappedByteBuffer buffer) { this.buffer = buffer; } @Override public int read() throws IOException { if (buffer.remaining() > 0) { return buffer.get(); } return -1; } @Override public int read(final byte b[]) throws IOException { return read(b, 0, b.length); } @Override public int read(final byte b[], final int off, final int len) throws IOException { final int length = Math.min(buffer.remaining(), len); buffer.get(b, off, length); if (length == 0) { return -1; } return length; } @Override public long skip(final long n) throws IOException { final int currentPosition = Long.valueOf(buffer.position()).intValue(); final int skip = Math.min(buffer.remaining(), Long.valueOf(n).intValue()); buffer.position(currentPosition + skip); return skip; } @Override public int available() throws IOException { return buffer.remaining(); } @Override public void close() throws IOException { } @Override public synchronized void mark(int readlimit) { buffer.mark(); } @Override public synchronized void reset() throws IOException { buffer.reset(); } @Override public boolean markSupported() { return true; } } }