Ejemplo n.º 1
0
 /**
  * Aborts the connection in response to an error.
  *
  * @param e The error that caused the connection to be aborted. Never null.
  */
 @java.lang.SuppressWarnings("ToArrayCallWithZeroLengthArrayArgument")
 @SuppressWarnings(
     "ITA_INEFFICIENT_TO_ARRAY") // intentionally; race condition on listeners otherwise
 protected void terminate(IOException e) {
   try {
     synchronized (this) {
       if (e == null) throw new IllegalArgumentException();
       outClosed = inClosed = e;
       try {
         transport.closeRead();
       } catch (IOException x) {
         logger.log(Level.WARNING, "Failed to close down the reader side of the transport", x);
       }
       try {
         synchronized (pendingCalls) {
           for (Request<?, ?> req : pendingCalls.values()) req.abort(e);
           pendingCalls.clear();
         }
         synchronized (executingCalls) {
           for (Request<?, ?> r : executingCalls.values()) {
             java.util.concurrent.Future<?> f = r.future;
             if (f != null) f.cancel(true);
           }
           executingCalls.clear();
         }
       } finally {
         notifyAll();
       }
     } // JENKINS-14909: leave synch block
   } finally {
     if (e instanceof OrderlyShutdown) e = null;
     for (Listener l : listeners.toArray(new Listener[0])) l.onClosed(this, e);
   }
 }
Ejemplo n.º 2
0
  /**
   * Sends a command to the remote end and executes it there.
   *
   * <p>This is the lowest layer of abstraction in {@link Channel}. {@link Command}s are executed on
   * a remote system in the order they are sent.
   */
  /*package*/ synchronized void send(Command cmd) throws IOException {
    if (outClosed != null) throw new ChannelClosedException(outClosed);
    if (logger.isLoggable(Level.FINE)) logger.fine("Send " + cmd);

    transport.write(cmd, cmd instanceof CloseCommand);
    commandsSent++;
  }
Ejemplo n.º 3
0
  /**
   * Creates a new channel.
   *
   * @param name See {@link #Channel(String, ExecutorService, Mode, InputStream, OutputStream,
   *     OutputStream, boolean, ClassLoader)}
   * @param exec See {@link #Channel(String, ExecutorService, Mode, InputStream, OutputStream,
   *     OutputStream, boolean, ClassLoader)}
   * @param transport The transport that we run {@link Channel} on top of.
   * @param base See {@link #Channel(String, ExecutorService, Mode, InputStream, OutputStream,
   *     OutputStream, boolean, ClassLoader)}
   * @param restricted See {@link #Channel(String, ExecutorService, Mode, InputStream, OutputStream,
   *     OutputStream, boolean, ClassLoader)}
   * @since 2.13
   */
  public Channel(
      String name,
      ExecutorService exec,
      CommandTransport transport,
      boolean restricted,
      ClassLoader base)
      throws IOException {
    this.name = name;
    this.executor = new InterceptingExecutorService(exec);
    this.isRestricted = restricted;
    this.underlyingOutput = transport.getUnderlyingStream();

    if (base == null) base = getClass().getClassLoader();
    this.baseClassLoader = base;

    if (export(this, false) != 1)
      throw new AssertionError(); // export number 1 is reserved for the channel itself
    remoteChannel = RemoteInvocationHandler.wrap(this, 1, IChannel.class, true, false);

    this.remoteCapability = transport.getRemoteCapability();
    this.pipeWriter = new PipeWriter(createPipeWriterExecutor());

    this.transport = transport;

    transport.setup(
        this,
        new CommandReceiver() {
          public void handle(Command cmd) {
            lastHeard = System.currentTimeMillis();
            if (logger.isLoggable(Level.FINE)) logger.fine("Received " + cmd);
            try {
              cmd.execute(Channel.this);
            } catch (Throwable t) {
              logger.log(
                  Level.SEVERE,
                  "Failed to execute command " + cmd + " (channel " + Channel.this.name + ")",
                  t);
              logger.log(Level.SEVERE, "This command is created here", cmd.createdAt);
            }
          }

          public void terminate(IOException e) {
            Channel.this.terminate(e);
          }
        });
  }
Ejemplo n.º 4
0
  /*package*/ Channel(ChannelBuilder settings, CommandTransport transport) throws IOException {
    this.name = settings.getName();
    this.executor = new InterceptingExecutorService(settings.getExecutors());
    this.isRestricted = settings.isRestricted();
    this.underlyingOutput = transport.getUnderlyingStream();
    this.jarCache = settings.getJarCache();

    this.baseClassLoader = settings.getBaseLoader();

    if (export(this, false) != 1)
      throw new AssertionError(); // export number 1 is reserved for the channel itself
    remoteChannel = RemoteInvocationHandler.wrap(this, 1, IChannel.class, true, false);

    this.remoteCapability = transport.getRemoteCapability();
    this.pipeWriter = new PipeWriter(createPipeWriterExecutor());

    this.transport = transport;

    this.jarLoader =
        new JarLoaderImpl(); // TODO: figure out a mechanism to allow the user to share this across
    // Channels
    setProperty(JarLoader.OURS, export(JarLoader.class, jarLoader, false));

    transport.setup(
        this,
        new CommandReceiver() {
          public void handle(Command cmd) {
            lastHeard = System.currentTimeMillis();
            if (logger.isLoggable(Level.FINE)) logger.fine("Received " + cmd);
            try {
              cmd.execute(Channel.this);
            } catch (Throwable t) {
              logger.log(
                  Level.SEVERE,
                  "Failed to execute command " + cmd + " (channel " + Channel.this.name + ")",
                  t);
              logger.log(Level.SEVERE, "This command is created here", cmd.createdAt);
            }
          }

          public void terminate(IOException e) {
            Channel.this.terminate(e);
          }
        });
  }
Ejemplo n.º 5
0
  /**
   * Closes the channel.
   *
   * @param diagnosis If someone (either this side or the other side) tries to use a channel that's
   *     already closed, they'll get a stack trace indicating that the channel has already been
   *     closed. This diagnosis, if provided, will further chained to that exception, providing more
   *     contextual information about why the channel was closed.
   * @since 2.8
   */
  public synchronized void close(Throwable diagnosis) throws IOException {
    if (outClosed != null) return; // already closed

    send(new CloseCommand(this, diagnosis));
    outClosed =
        new IOException()
            .initCause(
                diagnosis); // last command sent. no further command allowed. lock guarantees that
    // no command will slip inbetween
    try {
      transport.closeWrite();
    } catch (IOException e) {
      // there's a race condition here.
      // the remote peer might have already responded to the close command
      // and closed the connection, in which case our close invocation
      // could fail with errors like
      // "java.io.IOException: The pipe is being closed"
      // so let's ignore this error.
    }

    // termination is done by CloseCommand when we received it.
  }