Beispiel #1
0
    public RemoteInvocationHandler(Connection connection, final int objectID) {
      super();
      this.connection = connection;
      this.objectID = objectID;

      responseListener =
          new Listener() {
            @Override
            public void received(Connection connection, Object object) {
              if (!(object instanceof InvokeMethodResult)) {
                return;
              }
              InvokeMethodResult invokeMethodResult = (InvokeMethodResult) object;
              if (invokeMethodResult.objectID != objectID) {
                return;
              }

              responseTable.put(invokeMethodResult.responseID, invokeMethodResult);

              lock.lock();
              try {
                responseCondition.signalAll();
              } finally {
                lock.unlock();
              }
            }

            @Override
            public void disconnected(Connection connection) {
              close();
            }
          };
      connection.addListener(responseListener);
    }
Beispiel #2
0
    private Object waitForResponse(byte responseID) {
      if (connection.getEndPoint().getUpdateThread() == Thread.currentThread()) {
        throw new IllegalStateException(
            "Cannot wait for an RMI response on the connection's update thread.");
      }

      long endTime = System.currentTimeMillis() + timeoutMillis;

      while (true) {
        long remaining = endTime - System.currentTimeMillis();
        if (responseTable.containsKey(responseID)) {
          InvokeMethodResult invokeMethodResult = responseTable.get(responseID);
          responseTable.remove(responseID);
          lastResponseID = null;
          return invokeMethodResult.result;
        } else {
          if (remaining <= 0) {
            throw new TimeoutException("Response timed out.");
          }

          lock.lock();
          try {
            responseCondition.await(remaining, TimeUnit.MILLISECONDS);
          } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(e);
          } finally {
            lock.unlock();
          }
        }
      }
    }
Beispiel #3
0
  /**
   * Causes this ObjectSpace to stop listening to the connections for method invocation messages.
   */
  public void close() {
    Connection[] connections = this.connections;
    for (Connection connection : connections) {
      connection.removeListener(invokeListener);
    }

    synchronized (instancesLock) {
      ArrayList<Connection> temp = new ArrayList(Arrays.asList(instances));
      temp.remove(this);
      instances = temp.toArray(new ObjectSpace[temp.size()]);
    }

    if (TRACE) {
      trace("kryonet", "Closed ObjectSpace.");
    }
  }
Beispiel #4
0
  /**
   * Removes the specified connection, it will no longer be able to access objects registered in
   * this ObjectSpace.
   */
  public void removeConnection(Connection connection) {
    if (connection == null) {
      throw new IllegalArgumentException("connection cannot be null.");
    }

    connection.removeListener(invokeListener);

    synchronized (connectionsLock) {
      ArrayList<Connection> temp = new ArrayList(Arrays.asList(connections));
      temp.remove(connection);
      connections = temp.toArray(new Connection[temp.size()]);
    }

    if (TRACE) {
      trace("kryonet", "Removed connection from ObjectSpace: " + connection);
    }
  }
Beispiel #5
0
  /**
   * Allows the remote end of the specified connection to access objects registered in this
   * ObjectSpace.
   */
  public void addConnection(Connection connection) {
    if (connection == null) {
      throw new IllegalArgumentException("connection cannot be null.");
    }

    synchronized (connectionsLock) {
      Connection[] newConnections = new Connection[connections.length + 1];
      newConnections[0] = connection;
      System.arraycopy(connections, 0, newConnections, 1, connections.length);
      connections = newConnections;
    }

    connection.addListener(invokeListener);

    if (TRACE) {
      trace("kryonet", "Added connection to ObjectSpace: " + connection);
    }
  }
Beispiel #6
0
 void close() {
   connection.removeListener(responseListener);
 }
Beispiel #7
0
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
      if (method.getDeclaringClass() == RemoteObject.class) {
        String name = method.getName();
        if (name.equals("close")) {
          close();
          return null;
        } else if (name.equals("setResponseTimeout")) {
          timeoutMillis = (Integer) args[0];
          return null;
        } else if (name.equals("setNonBlocking")) {
          nonBlocking = (Boolean) args[0];
          return null;
        } else if (name.equals("setTransmitReturnValue")) {
          transmitReturnValue = (Boolean) args[0];
          return null;
        } else if (name.equals("setTransmitExceptions")) {
          transmitExceptions = (Boolean) args[0];
          return null;
        } else if (name.equals("waitForLastResponse")) {
          if (lastResponseID == null) {
            throw new IllegalStateException("There is no last response to wait for.");
          }
          return waitForResponse(lastResponseID);
        } else if (name.equals("getLastResponseID")) {
          if (lastResponseID == null) {
            throw new IllegalStateException("There is no last response ID.");
          }
          return lastResponseID;
        } else if (name.equals("waitForResponse")) {
          if (!transmitReturnValue && !transmitExceptions && nonBlocking) {
            throw new IllegalStateException(
                "This RemoteObject is currently set to ignore all responses.");
          }
          return waitForResponse((Byte) args[0]);
        } else if (name.equals("getConnection")) {
          return connection;
        } else {
          // Should never happen, for debugging purposes only
          throw new RuntimeException(
              "Invocation handler could not find RemoteObject method. Check ObjectSpace.java");
        }
      } else if (method.getDeclaringClass() == Object.class) {
        if (method.getName().equals("toString")) {
          return "<proxy>";
        }
        try {
          return method.invoke(proxy, args);
        } catch (Exception ex) {
          throw new RuntimeException(ex);
        }
      }

      InvokeMethod invokeMethod = new InvokeMethod();
      invokeMethod.objectID = objectID;
      invokeMethod.method = method;
      invokeMethod.args = args;

      // The only time a invocation doesn't need a response is if it's async
      // and no return values or exceptions are wanted back.
      boolean needsResponse = transmitReturnValue || transmitExceptions || !nonBlocking;
      if (needsResponse) {
        byte responseID;
        synchronized (this) {
          // Increment the response counter and put it into the first six bits of the
          // responseID byte
          responseID = nextResponseNum++;
          if (nextResponseNum == 64) {
            nextResponseNum = 1; // Keep number under 2^6, avoid 0 (see else statement
            // below)
          }
        }
        // Pack return value and exception info into the top two bits
        if (transmitReturnValue) {
          responseID |= kReturnValMask;
        }
        if (transmitExceptions) {
          responseID |= kReturnExMask;
        }
        invokeMethod.responseID = responseID;
      } else {
        invokeMethod.responseID = 0; // A response info of 0 means to not respond
      }
      int length = connection.sendTCP(invokeMethod);
      if (DEBUG) {
        String argString = "";
        if (args != null) {
          argString = Arrays.deepToString(args);
          argString = argString.substring(1, argString.length() - 1);
        }
        debug(
            "kryonet",
            connection
                + " sent: "
                + method.getDeclaringClass().getSimpleName()
                + "#"
                + method.getName()
                + "("
                + argString
                + ") ("
                + length
                + ")");
      }

      if (invokeMethod.responseID != 0) {
        lastResponseID = invokeMethod.responseID;
      }
      if (nonBlocking) {
        Class returnType = method.getReturnType();
        if (returnType.isPrimitive()) {
          if (returnType == int.class) {
            return 0;
          }
          if (returnType == boolean.class) {
            return Boolean.FALSE;
          }
          if (returnType == float.class) {
            return 0f;
          }
          if (returnType == char.class) {
            return (char) 0;
          }
          if (returnType == long.class) {
            return 0l;
          }
          if (returnType == short.class) {
            return (short) 0;
          }
          if (returnType == byte.class) {
            return (byte) 0;
          }
          if (returnType == double.class) {
            return 0d;
          }
        }
        return null;
      }
      try {
        Object result = waitForResponse(invokeMethod.responseID);
        if ((result != null) && (result instanceof Exception)) {
          throw (Exception) result;
        } else {
          return result;
        }
      } catch (TimeoutException ex) {
        throw new TimeoutException(
            "Response timed out: " + method.getDeclaringClass().getName() + "." + method.getName());
      }
    }
Beispiel #8
0
  /**
   * Invokes the method on the object and, if necessary, sends the result back to the connection
   * that made the invocation request. This method is invoked on the update thread of the {@link
   * EndPoint} for this ObjectSpace and unless an {@link #setExecutor(Executor) executor} has been
   * set.
   *
   * @param connection The remote side of this connection requested the invocation.
   */
  protected void invoke(Connection connection, Object target, InvokeMethod invokeMethod) {
    if (DEBUG) {
      String argString = "";
      if (invokeMethod.args != null) {
        argString = Arrays.deepToString(invokeMethod.args);
        argString = argString.substring(1, argString.length() - 1);
      }
      debug(
          "kryonet",
          connection
              + " received: "
              + target.getClass().getSimpleName()
              + "#"
              + invokeMethod.method.getName()
              + "("
              + argString
              + ")");
    }

    byte responseID = invokeMethod.responseID;
    boolean transmitReturnVal = (responseID & kReturnValMask) == kReturnValMask;
    boolean transmitExceptions = (responseID & kReturnExMask) == kReturnExMask;

    Object result = null;
    Method method = invokeMethod.method;
    try {
      result = method.invoke(target, invokeMethod.args);
      // Catch exceptions caused by the Method#invoke
    } catch (InvocationTargetException ex) {
      if (transmitExceptions) {
        result = ex.getCause();
      } else {
        throw new RuntimeException(
            "Error invoking method: "
                + method.getDeclaringClass().getName()
                + "."
                + method.getName(),
            ex);
      }
    } catch (Exception ex) {
      throw new RuntimeException(
          "Error invoking method: " + method.getDeclaringClass().getName() + "." + method.getName(),
          ex);
    }

    if (responseID == 0) {
      return;
    }

    InvokeMethodResult invokeMethodResult = new InvokeMethodResult();
    invokeMethodResult.objectID = invokeMethod.objectID;
    invokeMethodResult.responseID = responseID;

    // Do not return non-primitives if transmitReturnVal is false
    if (!transmitReturnVal && !invokeMethod.method.getReturnType().isPrimitive()) {
      invokeMethodResult.result = null;
    } else {
      invokeMethodResult.result = result;
    }

    int length = connection.sendTCP(invokeMethodResult);
    if (DEBUG) {
      debug("kryonet", connection + " sent: " + result + " (" + length + ")");
    }
  }