Package org.jnode.net.nfs.nfs2.mount

Source Code of org.jnode.net.nfs.nfs2.mount.Mount1Client$Parameter

/*
* $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.net.nfs.nfs2.mount;

import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.acplt.oncrpc.OncRpcClient;
import org.acplt.oncrpc.OncRpcClientAuthUnix;
import org.acplt.oncrpc.OncRpcException;
import org.acplt.oncrpc.OncRpcProtocols;
import org.acplt.oncrpc.XdrAble;
import org.acplt.oncrpc.XdrDecodingStream;
import org.acplt.oncrpc.XdrEncodingStream;
import org.acplt.oncrpc.XdrVoid;
import org.apache.log4j.Logger;
import org.jnode.net.nfs.Protocol;

/**
*
* @author Andrei Dore
*/
public class Mount1Client {

    private static final Logger LOGGER = Logger.getLogger(Mount1Client.class);

    private static final int MOUNT_CODE = 100005;
    private static final int MOUNT_VERSION = 1;

    private static final int PROCEDURE_TEST = 0;
    private static final int PROCEDURE_MOUNT = 1;
    private static final int PROCEDURE_DUMP = 2;
    private static final int PROCEDURE_UNMOUNT = 3;
    private static final int PROCEDURE_EXPORT = 5;

    public static final int FILE_HANDLE_SIZE = 32;
    public static final int MAX_PATH_LENGHT = 1024;
    public static final int MAX_NAME_LENGHT = 255;

    public static final int MOUNT_OK = 0;
    private InetAddress host;
    private Protocol protocol;
    private int uid;
    private int gid;

    private List<OncRpcClient> rpcClientPool;
    private boolean closed;

    /**
     * Constructs a <code>Mount1Client</code> client stub proxy object from
     * which the MOUNTPROG remote program can be accessed.
     *
     * @param host
     *                Internet address of host where to contact the remote
     *                program.
     * @param protocol
     *                {@link org.acplt.oncrpc.OncRpcProtocols Protocol} to be
     *                used for ONC/RPC calls.
     */
    public Mount1Client(InetAddress host, Protocol protocol, int uid, int gid) {
        this.host = host;
        this.protocol = protocol;
        this.uid = uid;
        this.gid = gid;
        rpcClientPool = new LinkedList<OncRpcClient>();
    }

    private OncRpcClient createRpcClient() throws OncRpcException, IOException {
        OncRpcClient client =
                OncRpcClient.newOncRpcClient(host, MOUNT_CODE, MOUNT_VERSION,
                        protocol == Protocol.UDP ? OncRpcProtocols.ONCRPC_UDP
                                : OncRpcProtocols.ONCRPC_TCP);
        client.setTimeout(10000);
        if (uid != -1 && gid != -1) {
            client.setAuth(new OncRpcClientAuthUnix("test", uid, gid));
        }
        return client;
    }

    private synchronized OncRpcClient getRpcClient() throws OncRpcException, IOException {
        if (closed) {
            throw new IOException("The mount client it is closed");
        }

        if (rpcClientPool.size() == 0) {
            return createRpcClient();
        } else {
            return rpcClientPool.remove(0);
        }
    }

    private synchronized void releaseRpcClient(OncRpcClient client) throws IOException {
        if (closed) {
            throw new IOException("The mount client it is closed");
        }
        if (client != null) {
            rpcClientPool.add(client);
        }
    }

    private void call(final int functionId, final XdrAble parameter, final XdrAble result)
        throws MountException, IOException {
        int countCall = 0;
        OncRpcClient client = null;

        while (true) {
            try {
                countCall++;
                client = getRpcClient();
                client.call(functionId, parameter, result);
                break;
            } catch (Exception e) {
                // if we receive an exception we will close the client and next
                // time we will use another rpc client
                if (client != null) {
                    try {
                        client.close();
                    } catch (OncRpcException e1) {
                        // Ignore this
                    }
                    client = null;
                }

                if (e instanceof RuntimeException) {
                    throw (RuntimeException) e;
                }

                if (e instanceof OncRpcException) {
                    if (countCall > 5) {
                        throw new MountException(e.getMessage(), e);
                    } else {
                        LOGGER
                                .warn("An error occurs when nfs file system try to call the rpc method. Reason : " +
                                        e.getMessage() + ". It will try again");
                        continue;
                    }

                } else {
                    throw new MountException(e.getMessage(), e);
                }

            } finally {
                if (client != null) {
                    try {
                        releaseRpcClient(client);
                    } catch (IOException e) {
                        // ignore
                    }
                }
            }
        }
    }

    /**
     * Call remote procedure test.
     *
     * @throws OncRpcException
     *                 if an ONC/RPC error occurs.
     * @throws IOException
     *                 if an I/O error occurs.
     * @throws MountException
     */
    public void test() throws IOException, MountException {
        call(PROCEDURE_TEST, XdrVoid.XDR_VOID, XdrVoid.XDR_VOID);
    }

    /**
     * Call remote procedure mount.
     *
     * @param path parameter (of type DirPath) to the remote procedure call.
     * @return Result from remote procedure call (of type MountResult).
     * @throws OncRpcException
     *                 if an ONC/RPC error occurs.
     * @throws IOException
     *                 if an I/O error occurs.
     * @throws MountException
     */
    public MountResult mount(final String path) throws IOException, MountException {
        XdrAble mountParameter = new Parameter() {
            public void xdrEncode(XdrEncodingStream xdrEncodingStream)
                throws OncRpcException, IOException {
                xdrEncodingStream.xdrEncodeString(path);
            }
        };

        final MountResult result = new MountResult();
        XdrAble mountResult = new Result() {
            public void xdrDecode(XdrDecodingStream xdrDecodingStream)
                throws OncRpcException, IOException {
                result.setFileHandle(readFileHandle(xdrDecodingStream));
            }
        };
        call(PROCEDURE_MOUNT, mountParameter, new ResultWithCode(mountResult));
        return result;
    }

    public List<RemoteMountFileSystem> dump() throws IOException, MountException {
        final List<RemoteMountFileSystem> remoteMountFileSystemList =
                new ArrayList<RemoteMountFileSystem>();
        XdrAble dumpResult = new Result() {
            public void xdrDecode(XdrDecodingStream xdrDecodingStream)
                throws OncRpcException, IOException {
                while (xdrDecodingStream.xdrDecodeBoolean()) {
                    String host = xdrDecodingStream.xdrDecodeString();
                    String remoteDirectory = xdrDecodingStream.xdrDecodeString();
                    RemoteMountFileSystem remoteMountFileSystem =
                            new RemoteMountFileSystem(host, remoteDirectory);
                    remoteMountFileSystemList.add(remoteMountFileSystem);
                }
            }
        };
        call(PROCEDURE_DUMP, XdrVoid.XDR_VOID, dumpResult);
        return remoteMountFileSystemList;
    }

    public List<ExportEntry> export() throws IOException, MountException {
        final List<ExportEntry> exportEntryList = new ArrayList<ExportEntry>();
        XdrAble dumpResult = new Result() {
            public void xdrDecode(XdrDecodingStream xdrDecodingStream)
                throws OncRpcException, IOException {
                while (xdrDecodingStream.xdrDecodeBoolean()) {
                    String path = readPath(xdrDecodingStream);
                    List<String> groupList = readGroup(xdrDecodingStream);
                    ExportEntry exportEntry = new ExportEntry(path, groupList);
                    exportEntryList.add(exportEntry);
                }
            }

            private List<String> readGroup(XdrDecodingStream xdrDecodingStream)
                throws OncRpcException, IOException {
                List<String> groupList = new ArrayList<String>();
                while (xdrDecodingStream.xdrDecodeBoolean()) {
                    String group = readName(xdrDecodingStream);
                    groupList.add(group);
                }
                return groupList;
            }
        };
        call(PROCEDURE_EXPORT, XdrVoid.XDR_VOID, dumpResult);
        return exportEntryList;
    }

    public void unmount(final String dirPath) throws IOException, MountException {
        XdrAble mountParameter = new Parameter() {
            public void xdrEncode(XdrEncodingStream xdrEncodingStream)
                throws OncRpcException, IOException {
                xdrEncodingStream.xdrEncodeString(dirPath);
            }
        };
        call(PROCEDURE_UNMOUNT, mountParameter, XdrVoid.XDR_VOID);
    }

    private String readPath(XdrDecodingStream xdrDecodingStream)
        throws OncRpcException, IOException {
        return xdrDecodingStream.xdrDecodeString();
    }

    private String readName(XdrDecodingStream xdrDecodingStream)
        throws OncRpcException, IOException {
        return xdrDecodingStream.xdrDecodeString();
    }

    private byte[] readFileHandle(XdrDecodingStream xdrDecodingStream)
        throws OncRpcException, IOException {
        return xdrDecodingStream.xdrDecodeOpaque(Mount1Client.FILE_HANDLE_SIZE);
    }

    private abstract class Parameter implements XdrAble {
        public void xdrDecode(XdrDecodingStream arg0) throws OncRpcException, IOException {
        }
    }

    private abstract class Result implements XdrAble {
        public void xdrEncode(XdrEncodingStream arg0) throws OncRpcException, IOException {
        }
    }

    private class ResultWithCode implements XdrAble {
        private int resultCode;
        private XdrAble xdrAble;

        public ResultWithCode(XdrAble xdrAble) {
            this.xdrAble = xdrAble;
        }

        public void xdrEncode(XdrEncodingStream xdr) throws OncRpcException, IOException {
        }

        public void xdrDecode(XdrDecodingStream xdr) throws OncRpcException, IOException {
            resultCode = xdr.xdrDecodeInt();
            if (resultCode == 0) {
                xdrAble.xdrDecode(xdr);
            } else {
                throw new OncRpcException("An error occur when system try to mount. Error code: " +
                        resultCode);
            }
        }

        public int getResultCode() {
            return resultCode;
        }
    }

    // TODO Remove the synch in the future
    public synchronized void close() throws IOException {
        closed = true;
        List<OncRpcException> exceptionList = new ArrayList<OncRpcException>();
        for (OncRpcClient client : rpcClientPool) {
            try {
                client.close();
            } catch (OncRpcException e) {
                exceptionList.add(e);
            }
        }

        if (exceptionList.size() != 0) {
            StringBuilder builder = new StringBuilder();
            builder.append("An error occurs when the mount client close connections. Reason:");
            for (OncRpcException anExceptionList : exceptionList) {
                builder.append(anExceptionList.getMessage());
                builder.append('.');
            }
            throw new IOException(builder.toString());
        }
    }
}
TOP

Related Classes of org.jnode.net.nfs.nfs2.mount.Mount1Client$Parameter

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.