如何自动将数据复制到新的RMI线程? [英] How to automatically copy data to new RMI threads?

查看:225
本文介绍了如何自动将数据复制到新的RMI线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在调整一个小的rmi客户端 - 服务器应用程序。我写过几件事:

I am adapting a little rmi client-server application. I have written several things :

HelloInterface -> A Hello World interface for RMI
Server -> The server app'
Client -> The client app'

没什么特别的,但是......我把手放在一个新的RMISecurityManager中,它调用JNI方法并检查单独用户的权限:

Nothing special, but... I have put my hands in a new RMISecurityManager, which calls a JNI method and checks the permission for a separate user:

package rmi;
import java.rmi.RMISecurityManager;
import java.io.*;

public class NativeRMISecurityManager extends RMISecurityManager
{
    private boolean unix;
    protected static ThreadLocal user = new ThreadLocal();

    /*
     * On interdit l'utilisation du constructeur par defaut
     * pour obliger l'utilisation du constructeur avec user. 
     */
    private NativeRMISecurityManager()
    {
        super();
    }

    public NativeRMISecurityManager (final String user)
    {
        super();
        String OS = System.getProperty("os.name").toLowerCase();
        unix = (OS.compareTo("windows") != 0); /* Assume that if not 
                            * windows, then "UNIX/POSIX" 
                            */
        /*
         * ThreadLocal's user : Each thread is considered 
         * to have different access rights to the machine
         */

        NativeRMISecurityManager.user.set(user);

        if (!unix)
        {
            System.out.println("Systeme : "+OS);
        }
    }

    public void checkRead(String file)
    {
        super.checkRead(file);
        /*
         * If we are on a **IX platform we want to check that 
         * the _user_ has access rights.
         */
        if (unix)
        {
            String str_user = (String)NativeRMISecurityManager.user.get();

            if (file == null)
            {
                throw new SecurityException("file = NULL !!!");
            }
        if (str_user == null)
            {
                throw new SecurityException("user = NULL in the ThreadLocal!!!");
            }

            int ret = c_checkRead(
                    file, 
                    str_user
                    );
            if (ret != 0)
            {
                throw new SecurityException("Access error: " + file);
            }
        }
    }

    public native int c_checkRead(String file, String user);
}

在Server类中我正在这样做:

In the Server class I'm doing that :

String user = "my_user";
System.setSecurityManager(new NativeRMISecurityManager(user));

此类似乎在Server的主线程中有效。现在问题是当我尝试连接到该Server类并查找注册表时。
我得到了这个例外:

This class seems to work in the Server's main thread. Now the problem is when I try and connect to that Server class and lookup the Registry. I get that exception :

Exception in thread "RMI TCP Connection(1)-192.168.42.207"     java.lang.ExceptionInInitializerError
        at sun.rmi.transport.StreamRemoteCall.getInputStream(StreamRemoteCall.java:111)
        at sun.rmi.transport.Transport.serviceCall(Transport.java:118)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:466)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:707)
        at java.lang.Thread.run(Thread.java:595)
Caused by: java.lang.SecurityException: user = NULL dans le ThreadLocal!!!
        at rmi.NativeRMISecurityManager.checkRead(NativeRMISecurityManager.java:62)
        at java.io.File.exists(File.java:700)
        at java.lang.ClassLoader$3.run(ClassLoader.java:1689)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1686)
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1668)
        at java.lang.Runtime.loadLibrary0(Runtime.java:822)
        at java.lang.System.loadLibrary(System.java:993)
        at sun.security.action.LoadLibraryAction.run(LoadLibraryAction.java:50)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.server.MarshalInputStream.<clinit>(MarshalInputStream.java:97)
        ... 5 more

恕我直言这是一个(隐式)创建一个线程并将NativeRMISecurityManager作为其默认的SecurityManage r。

IMHO the meaning of this is that a thread is (implicitly) created and gets the NativeRMISecurityManager as its default SecurityManager.

有人会对此有任何建议吗?

Would somebody have any advice concerning that ?

推荐答案


IMHO这意味着(隐式)创建一个线程并将NativeRMISecurityManager作为其默认的SecurityManager。

IMHO the meaning of this is that a thread is (implicitly) created and gets the NativeRMISecurityManager as its default SecurityManager.

这是事实,虽然它不是你错误的原因;问题与ThreadLocal的使用有关。 ThreadLocal的关键属性是每个调用线程都有自己的值。在这种情况下,用户由初始化NativeRMISecurityManager的线程设置,并将其设置为系统安全管理器(可能是主线程)。

This is true, though it is not the cause of your error; the problem has to do with the use of ThreadLocal. The key property of a ThreadLocal is that every calling thread has its own value. In this case "user" is being set by (and for) the thread that initializes the NativeRMISecurityManager and sets it as the System Security Manager (presumably the main thread).

但是,其他一些线程(通过它看起来是RMI消息处理线程)正在调用checkRead() - 但是从未为此线程设置user字段!因此,该值返回为null。

However, some other thread (by the look of it the RMI message handling thread) is calling checkRead() - but the "user" field was never set for this thread! Thus the value comes back as null.

除非有某些理由让不同的线程具有不同的值 - 我无法从您的示例中辨别出一个 - 我建议制作user字段a)String,而不是ThreadLocal,b)非静态。这应该可以解决你的null值问题。

Unless there is some reason to have different threads have different values - and I cannot discern one from your example - I would recommend making the "user" field a) a String, not a ThreadLocal and b) non-static. That should solve your null value problem.

但是,假设它是一个需求/设计约束,当前架构的问题是只有实例化NativeRMISecurityManager的线程实际上有一个用户 - 每个其他线程都为空。

However, presuming that it is a requirement / design constraint, the trouble with the current architecture is that only the thread that instantiates the NativeRMISecurityManager actually gets to have a user - every other thread gets null.

在深入研究这个问题时,我想我需要更好地理解你的问题域到提供有关修复的任何有用的建议。此外,Java的安全架构没有任何快速或肮脏的东西。但是我会在一些假设下尽我所能:

In delving into this with a little more depth, I think I need a better understanding of your problem domain to offer any helpful suggestions as to a fix. Further, there is nothing quick or dirty about Java's Security Architecture. However I will do my best working under a few assumptions:


  1. 系统创建的线程被认为是可信的

  2. 代码创建的线程必须指定用户

  3. 子线程应该继承创建线程的用户

潜在实施:

public class NativeRMISecurityManager extends RMISecurityManager {

    private static final boolean UNIX;

    static {
        String OS = System.getProperty("os.name").toLowerCase();
        UNIX = (OS.compareTo("windows") != 0); /* Assume that if not 
                                                * windows, then "UNIX/POSIX" 
                                                */
    }

    protected static InheritableThreadLocal<String> user =
        new InheritableThreadLocal<String>();

    public static setThreadUser(String username) {
        user.set(username);
    }


    public NativeRMISecurityManager(String initialUser) {
        super();
        // Set the user for the thread that constructs the security manager
        // All threads created as a child of that thread will inherit the user
        // All threads not created as a child of that thread will have a 'null' user
        setThreadUser(initialUser);
    }


    public void checkRead(String file) {
        super.checkRead(file);
        /*
         * If we are on a **IX platform we want to check that 
         * the _user_ has access rights.
         */
        if (UNIX)
        {
            if (file == null)
            {
                throw new SecurityException("file = NULL !!!");
            }

            String str_user = NativeRMISecurityManager.user.get();

            if (str_user != null)
            {
                // Note: sanitize input to native method
                int ret = c_checkRead(file, str_user);

                if (ret != 0)
                {
                    throw new SecurityException("Access error: " + file);
                }
            }

            // Assume a system thread and allow access
        }
    }

    public native int c_checkRead(String file, String user);
}

这篇关于如何自动将数据复制到新的RMI线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆