views:

205

answers:

9

I have the code of a simple game, where an AgentInterface must be implemented in order to create an agent controller for one of the characters in the game. GameState is a class the implements GameStateInterface, and an object that implements this interface can be passed to the agent, so the agent can read and analyze the data from game state, and the agent must return the appropriate action (returned as an int) that the character should take.

This is the AgentInterface that agents must implement:

public interface AgentInterface {
    // the return value specifies the direction of the joystick
    public int action(GameStateInterface gs);
}

Running the game with an agent called MyAgent:

    GameState gs = new GameState();
    AgentInterface agent = new MyAgent();
    while (true) {
        // more code here
        int bestAction = agent.action(gs)
        // more code here
    }

But, there is some information in GameState that the agent should NOT be able to access, since that would be cheating for the controller. But, doing a cast conversion from GameStateInterface to GameState would allow the agent to access information that is not defined in the GameStateInterface, like this:

public MyAgent implements AgentInterface {
    public int action(GameStateInterface gs) {
        int nLives = ((GameState) gs).nLivesRemaining; // IS IT POSSIBLE TO DENY/PREVENT THIS CAST??
        // Do more stuff here
        return BestAction;
    }
}

My question would be, is it possible to block a cast conversion? I know polymorphism is one of the main features of Java and Object-Oriented Programming Languages, but in cases like this I would like to avoid cast conversions.

I know this can be solved in many other ways, but I was curious to know if it is possible to do this.

Thanks in advance.

A: 

Nope, there is no way of doing this.

Best wishes,
Fabian

halfdan
A: 

I don't know if what you're describing is possible in Java. In other languages you can overload typecast operators and have them throw an exception or something, but this is not possible in Java. Your best bet is probably to do it in one of the "many other ways" you talked about.

iandisme
+7  A: 

As far as I know, it's not possible to intercept a typecast and deny it (say, by throwing a ClassCastException).

But instead of trying to deny the typecase, you can simply use the Proxy pattern to control access to the actual GameState object. Just implement a proxy class, which only implements the GameStateInterface and let it forward all method calls to the GameState object. Now, instead of passing the actual GameState object reference to the action method, you pass it wrapped by an instance of your proxy class.

Simon Lehmann
This seems like a good solution. +1
davidrobles
Warning - make sure that you have your Java security configured so that agent (i.e. untrusted) code cannot use the Reflection APIs. There are ways that someone could use reflection to access the private member of a proxy class to get hold of the GameState object.
Stephen C
+4  A: 

It's not possible to block a cast. However, you could define your game state in such a way that it can only be built from a specific place. One thing that comes to mind would be a private inner class implementing the interface, or a factory returning a private inner class instance

Steve B.
+4  A: 

The answer is simply "don't cast to GameState in your Agent code".

Alternatively, you can declare the GameState stuff as private. Or if you need to access it from a select few other classes, declare it as package-protected.

Anon.
+2  A: 

If you are concerned about the game state being changed by an agent, then create a bean copy of the state and pass that to the agent, rather than the real GameState object.

Prohibiting a cast doesn't sound possible (it is probably a unblockable JVM language spec feature), or I have never heard of it.

Nick Hristov
Yes, in fact an immutable bean copy was my first possible solution as well. I just wanted to know about other ways to go. +1
davidrobles
+3  A: 

In general, you can't prevent an object from being cast in Java. The code that receives a reference to your GameState will be able to call any non-private, non-protected method on that object. Even if you could prevent casting, it could still use reflection.

If the Agent code is under your control, just keep things simple and don't cast. If others write Agent classes, you could create a proxy class which takes a GameState object and only implements the methods of GameStateInterface.

class GameStateProxy implements GameStateInterface {
    private GameStateInterface state;

    public GameStateProxy(GameState state) {
        this.state = state;
    }

    public int someMethodInGameStateInterface(int x) {
        return state.someMethodInGameStateInterface(x);
    }

    // other methods ...
}

Then you could create a proxy and pass it like this:

GameStateInterface proxy = new GameStateProxy(gameState);
int bestAction = agent.action(proxy);

The code that receives a GameStateProxy would only have access to the methods in GameStateInterface.

Jay Conrod
but remember to set a SecurityManager to inhibit Reflection. Not that hard to get access to the private `state`...
Carlos Heuberger
+1  A: 

What we do is give out a jar with "Stubs" that you can compile against but it contains no implementation. When the actual product runs, we replace the stubs with a real jar.

But then in our case, we control where it runs.

In our case, also, we do exactly what you are asking. Any class has to request access to other classes (at runtime). I believe that's all custom implementation though and I'm not sure it will run on any JVM.

You can try to find/request/whatever the source code for the stuff I'm working on. There is a reference implementation available if you say you are interested in developing for cable boxes you might be able to get it. It's called the "tru2way" or "OCAP" reference stack implementation and I think the project is available on the java site somewhere. Might take a bit of googling--and I'm fairly sure you'll find it's all done in a special class loader or SecurityManager.

EDIT: I think I may be wrong. What we do is create "permissions" with the security manager based on the name of the class being accessed. When a thread tries to call a method on the class, we test it's permissions first (we write the code inside the "protected" class) and if the current thread does not have the permission identified by the name of the class, it throws an exception.

Same effect as you are after, but slower and more verbose. But then we have to prevent kids from watching pr0n.

Edit 2: (Sorry!!)

Looking at permission descriptions like this makes me believe it must be at least partially possible:

This grants code permission to query a class for its public, protected, default (package) access, and private fields and/or methods. Although the code would have access to the private and protected field and method names, it would not have access to the private/protected field data and would not be able to invoke any private methods. Nevertheless, malicious code may use this information to better aim an attack. Additionally, it may invoke any public methods and/or access public fields in the class. This could be dangerous if the code would normally not be able to invoke those methods and/or access the fields because it can't cast the object to the class/interface with those methods and fields.

Otherwise how could applets be prevented from instantiating and accessing arbitrary JVM classes? It's possible that the "Dangerous" paths are all blocked the same way we block our stuff--by reading checking permissions every time they are called--but that quote above makes it seem like there is more available and most classes are completely blocked by default.

This has interested me for a while but I never really looked into it.

Bill K
+1  A: 

One can only cast to an accessible type. By making GameState private, package-protected, or protected, you can restrict who can cast to it.

If you are running untrusted code, be sure to install a security manager, as reflection may be used to circumvent access modifiers in its absensce (c.f. Field.setAccessible)

meriton