| /* |
| * 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.commons.vfs.util; |
| |
| import org.apache.commons.vfs.Capability; |
| import org.apache.commons.vfs.FileObject; |
| import org.apache.commons.vfs.FileSystemException; |
| import org.apache.commons.vfs.RandomAccessContent; |
| |
| import javax.mail.internet.SharedInputStream; |
| import java.io.BufferedInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| /** |
| * A wrapper to an FileObject to get a {@link javax.mail.internet.SharedInputStream} |
| * |
| * @author <a href="mailto:imario@apache.org">imario@apache.org</a> |
| * @version $Revision$ $Date$ |
| */ |
| public class SharedRandomContentInputStream extends BufferedInputStream implements SharedInputStream |
| { |
| private final Set createdStreams; |
| private final FileObject fo; |
| private final long fileStart; |
| private final long fileEnd; |
| |
| private long pos; |
| private long resetCount; |
| |
| private SharedRandomContentInputStream(final Set createdStreams, final FileObject fo, final long fileStart, final long fileEnd, final InputStream is) throws FileSystemException |
| { |
| super(is); |
| |
| if (!fo.getFileSystem().hasCapability(Capability.RANDOM_ACCESS_READ)) |
| { |
| throw new FileSystemException("vfs.util/missing-capability.error", Capability.RANDOM_ACCESS_READ); |
| } |
| |
| this.fo = fo; |
| this.fileStart = fileStart; |
| this.fileEnd = fileEnd; |
| this.createdStreams = createdStreams; |
| |
| synchronized(createdStreams) |
| { |
| createdStreams.add(this); |
| } |
| } |
| |
| public SharedRandomContentInputStream(final FileObject fo) throws FileSystemException |
| { |
| this(new HashSet(), fo, 0, -1, fo.getContent().getInputStream()); |
| } |
| |
| |
| public synchronized int read() throws IOException |
| { |
| if (checkEnd()) |
| { |
| return -1; |
| } |
| int r = super.read(); |
| pos++; |
| resetCount++; |
| return r; |
| } |
| |
| public synchronized int read(byte b[], int off, int len) throws IOException |
| { |
| if (checkEnd()) |
| { |
| return -1; |
| } |
| |
| if (fileEnd > -1 && calcFilePosition(len) > fileEnd) |
| { |
| // we can not read past our end |
| len = (int) (fileEnd - getFilePosition()); |
| } |
| |
| int nread = super.read(b, off, len); |
| pos+=nread; |
| resetCount+=nread; |
| return nread; |
| } |
| |
| public synchronized long skip(long n) throws IOException |
| { |
| if (checkEnd()) |
| { |
| return -1; |
| } |
| |
| if (fileEnd > -1 && calcFilePosition(n) > fileEnd) |
| { |
| // we can not skip past our end |
| n = fileEnd - getFilePosition(); |
| } |
| |
| long nskip = super.skip(n); |
| pos+=nskip; |
| resetCount+=nskip; |
| return nskip; |
| } |
| |
| /* |
| public synchronized int available() throws IOException |
| { |
| long realFileEnd = fileEnd; |
| if (realFileEnd < 0) |
| { |
| realFileEnd = fo.getContent().getSize(); |
| } |
| if (realFileEnd < 0) |
| { |
| // we cant determine if there is really something available |
| return 8192; |
| } |
| |
| long available = realFileEnd - (fileStart + pos); |
| if (available > Integer.MAX_VALUE) |
| { |
| return Integer.MAX_VALUE; |
| } |
| |
| return (int) available; |
| } |
| */ |
| |
| private boolean checkEnd() |
| { |
| return fileEnd > -1 && (getFilePosition() >= fileEnd); |
| } |
| |
| protected long getFilePosition() |
| { |
| return fileStart + pos; |
| } |
| |
| protected long calcFilePosition(long nadd) |
| { |
| return getFilePosition()+nadd; |
| } |
| |
| public synchronized void mark(int readlimit) |
| { |
| super.mark(readlimit); |
| resetCount = 0; |
| } |
| |
| public synchronized void reset() throws IOException |
| { |
| super.reset(); |
| pos-=resetCount; |
| resetCount=0; |
| } |
| |
| public long getPosition() |
| { |
| return pos; |
| } |
| |
| |
| public void close() throws IOException |
| { |
| super.close(); |
| |
| synchronized(createdStreams) |
| { |
| createdStreams.remove(this); |
| } |
| } |
| |
| public InputStream newStream(long start, long end) |
| { |
| try |
| { |
| long newFileStart = this.fileStart+start; |
| long newFileEnd = end<0?this.fileEnd:this.fileStart+end; |
| |
| RandomAccessContent rac = fo.getContent().getRandomAccessContent(RandomAccessMode.READ); |
| rac.seek(newFileStart); |
| return new SharedRandomContentInputStream( |
| createdStreams, |
| fo, |
| newFileStart, |
| newFileEnd, |
| rac.getInputStream()); |
| } |
| catch (IOException e) |
| { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public void closeAll() throws IOException |
| { |
| synchronized(createdStreams) |
| { |
| SharedRandomContentInputStream[] streams = new SharedRandomContentInputStream[createdStreams.size()]; |
| createdStreams.toArray(streams); |
| for (int i = 0; i<streams.length; i++) |
| { |
| streams[i].close(); |
| } |
| } |
| } |
| } |