Package org.jnode.protocol.nfs.nfs2

Source Code of org.jnode.protocol.nfs.nfs2.NFS2InputStream

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.protocol.nfs.nfs2;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URL;
import java.util.List;
import java.util.StringTokenizer;
import org.jnode.net.nfs.Protocol;
import org.jnode.net.nfs.nfs2.FileAttribute;
import org.jnode.net.nfs.nfs2.LookupResult;
import org.jnode.net.nfs.nfs2.NFS2Client;
import org.jnode.net.nfs.nfs2.NFS2Exception;
import org.jnode.net.nfs.nfs2.ReadFileResult;
import org.jnode.net.nfs.nfs2.mount.ExportEntry;
import org.jnode.net.nfs.nfs2.mount.Mount1Client;
import org.jnode.net.nfs.nfs2.mount.MountException;
import org.jnode.net.nfs.nfs2.mount.MountResult;

/**
* A NFS2InputStream obtains the bytes from a nfs2 connection.
* The URL is nfs://host/remotePath
* The remotePath contains also the export path.
*
* @author Andrei Dore
*/
public class NFS2InputStream extends InputStream {
    private static int DEFAULT_BUFFER_SIZE = NFS2Client.MAX_DATA;
    private byte[] buffer;
    private int bufferCount;
    private int bufferPosition;
    private long markFileOffset = -1;
    private int markLimit = -1;
    private Mount1Client mountClient;
    private NFS2Client nfsClient;
    private String mountDirectory;
    private long fileOffset;
    private byte[] fileHandle;
    private FileAttribute fileAttribute;

    public NFS2InputStream(URL url) throws IOException {
        // FIXME ... exception handling in this method should be reviewed.  At the very least,
        // there are places where finally clauses should be used.
        mountClient = new Mount1Client(InetAddress.getByName(url.getHost()), Protocol.TCP, -1, -1);
        nfsClient = new NFS2Client(InetAddress.getByName(url.getHost()), Protocol.TCP, -1, -1);
        String path = url.getPath();
        List<ExportEntry> exportList;
        try {
            exportList = mountClient.export();
        } catch (MountException e) {
            try {
                mountClient.close();
            } catch (IOException e1) {
                // ignore
            }
            throw new IOException(e.getMessage());
        } catch (IOException e) {
            try {
                mountClient.close();
            } catch (IOException e1) {
                // ignore
            }
            throw e;
        }

        ExportEntry exportEntry = null;
        for (ExportEntry e : exportList) {
            if (path.startsWith(e.getDirectory())) {
                if (exportEntry == null) {
                    exportEntry = e;
                } else {
                    if (exportEntry.getDirectory().length() < e.getDirectory().length()) {
                        exportEntry = e;
                    }
                }
            }
        }

        if (exportEntry == null) {
            throw new IOException("The path " + path + " it is not exported");
        }
        mountDirectory = exportEntry.getDirectory();
        MountResult mountResult;
        try {
            mountResult = mountClient.mount(mountDirectory);
        } catch (MountException e) {
            try {
                mountClient.close();
            } catch (IOException e1) {
                // ignore
            }
            throw new IOException(e.getMessage());
        } catch (IOException e) {
            try {
                mountClient.close();
            } catch (IOException e1) {
                // ignore
            }
            throw e;
        }

        byte[] tempFileHandle = mountResult.getFileHandle();

        try {
            String filePath = path.substring(exportEntry.getDirectory().length());
            StringTokenizer tokenizer = new StringTokenizer(filePath, "/");
            while (tokenizer.hasMoreElements()) {
                String t = tokenizer.nextToken();
                LookupResult lookup = nfsClient.lookup(tempFileHandle, t);
                if (lookup.getFileAttribute().getType() == FileAttribute.FILE) {
                    fileHandle = lookup.getFileHandle();
                    fileAttribute = lookup.getFileAttribute();
                    break;
                } else if (lookup.getFileAttribute().getType() == FileAttribute.DIRECTORY) {
                    tempFileHandle = lookup.getFileHandle();
                } else {
                    throw new IOException("The path contains an unknow resource: " + t +
                            ". It is not directory or file");
                }
            }
        } catch (NFS2Exception e) {
            try {
                close();
            } catch (IOException e1) {
                // ignore
            }
            throw new IOException(e.getMessage());
        } catch (IOException e) {
            try {
                close();
            } catch (IOException e1) {
                // ignore
            }
            throw e;
        }
        if (fileHandle == null) {
            throw new IOException("The target of the " + url.toString() + " it is not a file.");
        }
        buffer = new byte[DEFAULT_BUFFER_SIZE];
    }

    @Override
    public synchronized int read() throws IOException {
        if (bufferPosition >= bufferCount) {
            if (fillBuffer() == 0) {
                return -1;
            }
        }
        int data = buffer[bufferPosition] & 0xFF;
        bufferPosition++;
        return data;
    }

    @Override
    public synchronized int read(byte[] b, int off, int len) throws IOException {
        if (len == 0) {
            return 0;
        }
        int readBytes = 0;
        while (true) {
            if (readBytes == len) {
                return readBytes;
            }
            int avail = bufferCount - bufferPosition;
            if (avail == 0) {
                if (fillBuffer() == 0) {
                    if (readBytes == 0) {
                        return -1;
                    }
                    return readBytes;
                }
            }
            int count = Math.min(len - readBytes, bufferCount - bufferPosition);
            System.arraycopy(buffer, bufferPosition, b, off + readBytes, count);
            readBytes += count;
            bufferPosition += count;
        }
    }

    @Override
    public synchronized int available() throws IOException {
        return bufferCount - bufferPosition;
    }

    private int fillBuffer() throws IOException {
        if (fileOffset >= fileAttribute.getSize()) {
            return 0;
        }
        ReadFileResult readFileResult;
        try {
            readFileResult = nfsClient.readFile(fileHandle, (int) fileOffset, DEFAULT_BUFFER_SIZE);
        } catch (NFS2Exception e) {
            throw new IOException(e.getMessage());
        }
        fileAttribute = readFileResult.getFileAttribute();
        fileOffset += readFileResult.getData().length;
        System.arraycopy(readFileResult.getData(), 0, buffer, 0, readFileResult.getData().length);
        bufferPosition = 0;
        bufferCount = readFileResult.getData().length;
        return bufferCount;
    }

    @Override
    public synchronized void mark(int readlimit) {
        this.markLimit = readlimit;
        this.markFileOffset = fileOffset;
    }

    @Override
    public boolean markSupported() {
        return true;
    }

    @Override
    public synchronized void reset() throws IOException {
        if (markFileOffset == -1 && markLimit == -1) {
            throw new IOException("The mark was not set. Use mark method to set the mark");
        }
        if (fileOffset - markFileOffset > markLimit) {
            throw new IOException("The mark limit exced.");
        }
        fileOffset = markFileOffset;

        // reset the buffer
        bufferPosition = 0;
        bufferCount = 0;

        // TODO Optimize this. If the mark it is buffer don't reset the buffer.
        // Unfortunately it is not a simple modification in this method.
    }

    public synchronized long skip(long n) throws IOException {
        if (n <= 0) {
            return 0;
        }
        if (n < bufferCount - bufferPosition) {
            // It is inside of the buffer
            bufferPosition += n;
            return n;
        } else {
            // It is outside of the buffer: reset the buffer
            bufferCount = 0;
            bufferPosition = 0;
            if (fileOffset + n - (bufferCount - bufferPosition) < fileAttribute.getSize()) {
                fileOffset += n - (bufferCount - bufferPosition);
                return n;
            } else {
                long skipBytes = fileAttribute.getSize() - fileOffset;
                fileOffset = fileAttribute.getSize();
                return skipBytes;
            }
        }
    }

    // TODO Remove the synch in the future
    @Override
    public synchronized void close() throws IOException {
        if (mountClient != null) {
            try {
                mountClient.unmount(mountDirectory);
            } catch (MountException e) {
                // FIXME ... ignore?
            }
            try {
                mountClient.close();
            } catch (IOException e) {
                // FIXME ... ignore?
            }
        }
        if (nfsClient != null) {
            try {
                nfsClient.close();
            } catch (IOException e) {
                // FIXME ... ignore?
            }
        }
    }
}
TOP

Related Classes of org.jnode.protocol.nfs.nfs2.NFS2InputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.