public SendPingRequestEvent(
     final ID messageReference, final Channel channel, final PingRequest message) {
   super(
       messageReference,
       MessageEventType.SEND_PING_REQUEST,
       channel,
       Channels.future(channel, false),
       message);
 }
 private void sendByteArray(ChannelHandlerContext ctx, byte[] buffer) {
   try {
     Channel channel = ctx.getChannel();
     ChannelFuture future = Channels.future(ctx.getChannel());
     ChannelBuffer b = ChannelBuffers.dynamicBuffer();
     // first send encoded key bytes size
     b.writeInt(buffer.length);
     // then the public key
     b.writeBytes(buffer);
     Channels.write(ctx, future, b);
   } catch (Exception e) {
     e.printStackTrace();
   }
 }
  private void writeReset(final InetSocketAddress remoteEndpoint, final int messageID) {
    try {
      CoapMessage resetMessage = CoapMessage.createEmptyReset(messageID);
      ChannelFuture future = Channels.future(ctx.getChannel());

      Channels.write(this.getChannelHandlerContext(), future, resetMessage, remoteEndpoint);

      future.addListener(
          new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
              log.info("RST for message ID {} succesfully sent to {}.", messageID, remoteEndpoint);
            }
          });
    } catch (IllegalArgumentException e) {
      log.error("This should never happen.", e);
    }
  }
  private void writeEmptyAcknowledgement(
      final InetSocketAddress remoteAddress, final int messageID) {
    try {
      CoapMessage emptyAcknowledgement = CoapMessage.createEmptyAcknowledgement(messageID);

      ChannelFuture future = Channels.future(ctx.getChannel());
      Channels.write(ctx, future, emptyAcknowledgement, remoteAddress);

      future.addListener(
          new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
              log.info(
                  "Empty ACK for message ID {} succesfully sent to {}.", messageID, remoteAddress);
            }
          });
    } catch (IllegalArgumentException e) {
      log.error("This should never happen.", e);
    }
  }
 /* (non-Javadoc)
  * @see org.rzo.netty.ahessian.auth.AuthToken#sendPassword(org.jboss.netty.channel.ChannelHandlerContext)
  */
 public void sendPassword(ChannelHandlerContext ctx) {
   Channels.write(ctx, Channels.future(ctx.getChannel()), ChannelBuffers.wrappedBuffer(_password));
 }
Exemple #6
0
public class Robot {

  private static final InternalLogger LOGGER = InternalLoggerFactory.getInstance(Robot.class);

  private final List<ChannelFuture> bindFutures = new ArrayList<>();
  private final List<ChannelFuture> connectFutures = new ArrayList<>();

  private final Channel channel =
      new DefaultLocalClientChannelFactory().newChannel(pipeline(new SimpleChannelHandler()));
  private final ChannelFuture startedFuture = Channels.future(channel);
  private final ChannelFuture abortedFuture = Channels.future(channel);
  private final ChannelFuture finishedFuture = Channels.future(channel);

  private final DefaultChannelGroup serverChannels = new DefaultChannelGroup();
  private final DefaultChannelGroup clientChannels = new DefaultChannelGroup();

  private Configuration configuration;
  private ChannelFuture preparedFuture;
  private volatile boolean destroyed;

  private final ChannelAddressFactory addressFactory;
  private final BootstrapFactory bootstrapFactory;
  private final boolean createdBootstrapFactory;

  private ScriptProgress progress;

  private final ChannelHandler closeOnExceptionHandler = new CloseOnExceptionHandler();

  private final ConcurrentMap<String, Barrier> barriersByName =
      new ConcurrentHashMap<String, Barrier>();

  // tests
  public Robot() {
    this(newChannelAddressFactory());
  }

  private Robot(ChannelAddressFactory addressFactory) {
    this(
        addressFactory,
        newBootstrapFactory(
            Collections.<Class<?>, Object>singletonMap(
                ChannelAddressFactory.class, addressFactory)),
        true);
  }

  private Robot(
      ChannelAddressFactory addressFactory,
      BootstrapFactory bootstrapFactory,
      boolean createdBootstrapFactory) {

    this.addressFactory = addressFactory;
    this.bootstrapFactory = bootstrapFactory;
    this.createdBootstrapFactory = createdBootstrapFactory;

    ChannelFutureListener stopConfigurationListener = createStopConfigurationListener();
    this.abortedFuture.addListener(stopConfigurationListener);
    this.finishedFuture.addListener(stopConfigurationListener);
  }

  public ChannelFuture getPreparedFuture() {
    return preparedFuture;
  }

  public ChannelFuture getStartedFuture() {
    return startedFuture;
  }

  public ChannelFuture prepare(String expectedScript) throws Exception {

    if (preparedFuture != null) {
      throw new IllegalStateException("Script already prepared");
    }

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Expected script:\n" + expectedScript);
    }

    final ScriptParser parser = new Parser();
    AstScriptNode scriptAST =
        parser.parse(new ByteArrayInputStream(expectedScript.getBytes(UTF_8)));

    final ScriptValidator validator = new ScriptValidator();
    validator.validate(scriptAST);

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Parsed script:\n" + scriptAST);
    }

    RegionInfo scriptInfo = scriptAST.getRegionInfo();
    progress = new ScriptProgress(scriptInfo, expectedScript);

    final GenerateConfigurationVisitor visitor =
        new GenerateConfigurationVisitor(bootstrapFactory, addressFactory);
    configuration =
        scriptAST.accept(visitor, new GenerateConfigurationVisitor.State(barriersByName));

    preparedFuture = prepareConfiguration();

    return preparedFuture;
  }

  // ONLY used for testing, TODO, remove and use TestSpecification instead
  ChannelFuture prepareAndStart(String script) throws Exception {
    ChannelFuture preparedFuture = prepare(script);
    preparedFuture.addListener(
        new ChannelFutureListener() {
          @Override
          public void operationComplete(ChannelFuture future) throws Exception {
            start();
          }
        });
    return startedFuture;
  }

  public ChannelFuture start() throws Exception {

    if (preparedFuture == null || !preparedFuture.isDone()) {
      throw new IllegalStateException("Script has not been prepared or is still preparing");
    } else if (startedFuture.isDone()) {
      throw new IllegalStateException("Script has already been started");
    }

    // ensure prepare has completed before start can progress
    preparedFuture.addListener(
        new ChannelFutureListener() {
          @Override
          public void operationComplete(ChannelFuture future) throws Exception {
            try {
              startConfiguration();
              startedFuture.setSuccess();
            } catch (Exception ex) {
              startedFuture.setFailure(ex);
            }
          }
        });

    return startedFuture;
  }

  public ChannelFuture abort() {

    abortedFuture.setSuccess();

    return finishedFuture;
  }

  public ChannelFuture finish() {

    return finishedFuture;
  }

  public String getObservedScript() {
    return (progress != null) ? progress.getObservedScript() : null;
  }

  public boolean isDestroyed() {
    return destroyed;
  }

  public boolean destroy() {

    if (destroyed) {
      return true;
    }

    abort();

    if (createdBootstrapFactory) {
      try {
        bootstrapFactory.shutdown();
        bootstrapFactory.releaseExternalResources();
      } catch (Exception e) {
        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Caught exception releasing resources", e);
        }
        return false;
      }
    }

    return destroyed = true;
  }

  private ChannelFuture prepareConfiguration() throws Exception {

    List<ChannelFuture> completionFutures = new ArrayList<>();
    ChannelFutureListener streamCompletionListener = createStreamCompletionListener();
    for (ChannelPipeline pipeline : configuration.getClientAndServerPipelines()) {
      CompletionHandler completionHandler = pipeline.get(CompletionHandler.class);
      ChannelFuture completionFuture = completionHandler.getHandlerFuture();
      completionFutures.add(completionFuture);
      completionFuture.addListener(streamCompletionListener);
    }

    ChannelFuture executionFuture = new CompositeChannelFuture<>(channel, completionFutures);
    ChannelFutureListener executionListener = createScriptCompletionListener();
    executionFuture.addListener(executionListener);

    return prepareServers();
  }

  private ChannelFuture prepareServers() throws Exception {

    /* Accept's ... Robot acting as a server */
    for (ServerBootstrapResolver serverResolver : configuration.getServerResolvers()) {
      ServerBootstrap server = serverResolver.resolve();
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Binding to address " + server.getOption("localAddress"));
      }

      /* Keep track of the client channels */
      server.setParentHandler(
          new SimpleChannelHandler() {
            @Override
            public void childChannelOpen(ChannelHandlerContext ctx, ChildChannelStateEvent e)
                throws Exception {
              clientChannels.add(e.getChildChannel());
            }

            @Override
            public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
                throws Exception {
              Channel channel = ctx.getChannel();
              channel.close();
            }
          });

      // Bind Asynchronously
      ChannelFuture bindFuture = server.bindAsync();

      // Add to out serverChannel Group
      serverChannels.add(bindFuture.getChannel());

      // Add to our list of bindFutures so we can cancel them later on a possible abort
      bindFutures.add(bindFuture);

      // Listen for the bindFuture.
      RegionInfo regionInfo = (RegionInfo) server.getOption("regionInfo");
      bindFuture.addListener(
          createBindCompleteListener(regionInfo, serverResolver.getNotifyBarrier()));
    }

    return new CompositeChannelFuture<>(channel, bindFutures);
  }

  private void startConfiguration() throws Exception {
    /* Connect to any clients */
    for (final ClientBootstrapResolver clientResolver : configuration.getClientResolvers()) {
      Barrier awaitBarrier = clientResolver.getAwaitBarrier();
      if (awaitBarrier != null) {
        awaitBarrier
            .getFuture()
            .addListener(
                new ChannelFutureListener() {

                  @Override
                  public void operationComplete(ChannelFuture future) throws Exception {
                    connectClient(clientResolver);
                  }
                });
      } else {
        connectClient(clientResolver);
      }
    }
  }

  private void connectClient(ClientBootstrapResolver clientResolver) throws Exception {
    final RegionInfo regionInfo = clientResolver.getRegionInfo();
    ClientBootstrap client = clientResolver.resolve();

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("[id:           ] connect " + client.getOption("remoteAddress"));
    }

    ChannelFuture connectFuture = client.connect();
    connectFutures.add(connectFuture);
    clientChannels.add(connectFuture.getChannel());
    connectFuture.addListener(createConnectCompleteListener(regionInfo));
  }

  private void stopConfiguration() throws Exception {

    if (configuration == null) {
      // abort received but script not prepared, therefore entire script failed
      if (progress == null) {
        progress = new ScriptProgress(newSequential(0, 0), "");
      }
      RegionInfo scriptInfo = progress.getScriptInfo();
      progress.addScriptFailure(scriptInfo);
    } else {
      // stopping the configuration will implicitly trigger the script complete listener
      // to handle incomplete script that is being aborted by canceling the finish future

      // clear out the pipelines for new connections to avoid impacting the observed script
      for (ServerBootstrapResolver serverResolver : configuration.getServerResolvers()) {
        ServerBootstrap server = serverResolver.resolve();
        server.setPipelineFactory(pipelineFactory(pipeline(closeOnExceptionHandler)));
      }
      for (ClientBootstrapResolver clientResolver : configuration.getClientResolvers()) {
        ClientBootstrap client = clientResolver.resolve();
        client.setPipelineFactory(pipelineFactory(pipeline(closeOnExceptionHandler)));
      }

      // remove each handler from the configuration pipelines
      // this will trigger failures for any handlers on a pipeline for an incomplete stream
      // including pipelines not yet associated with any channel
      for (ChannelPipeline pipeline : configuration.getClientAndServerPipelines()) {
        stopStream(pipeline);
      }

      // cancel any pending binds and connects
      for (ChannelFuture bindFuture : bindFutures) {
        bindFuture.cancel();
      }

      for (ChannelFuture connectFuture : connectFutures) {
        connectFuture.cancel();
      }

      // close server and client channels
      final ChannelGroupFuture closeFuture = serverChannels.close();
      closeFuture.addListener(
          new ChannelGroupFutureListener() {
            @Override
            public void operationComplete(final ChannelGroupFuture future) {
              clientChannels.close();
            }
          });

      for (AutoCloseable resource : configuration.getResources()) {
        try {
          resource.close();
        } catch (Exception e) {
          // ignore
        }
      }
    }
  }

  private void stopStream(final ChannelPipeline pipeline) {
    if (pipeline.isAttached()) {

      // avoid race between pipeline clean up and channel events on same pipeline
      // by executing the pipeline clean up on the I/O worker thread
      pipeline.execute(
          new Runnable() {
            @Override
            public void run() {
              stopStreamAligned(pipeline);
            }
          });
    } else {
      // no race if not attached
      stopStreamAligned(pipeline);
    }
  }

  private void stopStreamAligned(final ChannelPipeline pipeline) {
    for (ChannelHandler handler : pipeline.toMap().values()) {
      // note: removing this handler can trigger script completion
      //       which in turn can re-attempt to stop this pipeline
      pipeline.remove(handler);
    }

    // non-empty pipeline required to avoid warnings
    if (pipeline.getContext(closeOnExceptionHandler) == null) {
      pipeline.addLast("closeOnException", closeOnExceptionHandler);
    }
  }

  private ChannelFutureListener createBindCompleteListener(
      final RegionInfo regionInfo, final Barrier notifyBarrier) {
    return new ChannelFutureListener() {
      @Override
      public void operationComplete(final ChannelFuture bindFuture) throws Exception {

        if (bindFuture.isSuccess()) {
          if (LOGGER.isDebugEnabled()) {
            Channel boundChannel = bindFuture.getChannel();
            SocketAddress localAddress = boundChannel.getLocalAddress();
            LOGGER.debug("Successfully bound to " + localAddress);
          }

          if (notifyBarrier != null) {
            ChannelFuture barrierFuture = notifyBarrier.getFuture();
            barrierFuture.setSuccess();
          }
        } else {
          Throwable cause = bindFuture.getCause();
          String message = format("accept failed: %s", cause.getMessage());
          progress.addScriptFailure(regionInfo, message);

          // fail each pipeline that required this bind to succeed
          List<ChannelPipeline> acceptedPipelines = configuration.getServerPipelines(regionInfo);
          for (ChannelPipeline acceptedPipeline : acceptedPipelines) {
            stopStream(acceptedPipeline);
          }
        }
      }
    };
  }

  private ChannelFutureListener createConnectCompleteListener(final RegionInfo regionInfo) {
    return new ChannelFutureListener() {
      @Override
      public void operationComplete(ChannelFuture connectFuture) throws Exception {
        if (connectFuture.isCancelled()) {
          // This is more that the connect never really fired, as in the case of a barrier, or the
          // the connect
          // is still in process here, so an empty line annotates that it did not do a connect, an
          // actual connect
          // failure should fail the future
          progress.addScriptFailure(regionInfo, "");
        } else if (!connectFuture.isSuccess()) {
          Throwable cause = connectFuture.getCause();
          String message = format("connect failed: %s", cause.getMessage());
          progress.addScriptFailure(regionInfo, message);
        }
      }
    };
  }

  private ChannelFutureListener createStreamCompletionListener() {
    return new ChannelFutureListener() {
      @Override
      public void operationComplete(ChannelFuture completionFuture) throws Exception {
        if (!completionFuture.isSuccess()) {
          Throwable cause = completionFuture.getCause();
          if (cause instanceof ScriptProgressException) {
            ScriptProgressException exception = (ScriptProgressException) cause;
            progress.addScriptFailure(exception.getRegionInfo(), exception.getMessage());
          } else {
            LOGGER.warn("Unexpected exception", cause);
          }
        }
      }
    };
  }

  private ChannelFutureListener createScriptCompletionListener() {
    ChannelFutureListener executionListener =
        new ChannelFutureListener() {

          @Override
          public void operationComplete(final ChannelFuture future) throws Exception {

            if (LOGGER.isDebugEnabled()) {
              // detect observed script
              String observedScript = progress.getObservedScript();
              LOGGER.debug("Observed script:\n" + observedScript);
            }

            if (abortedFuture.isDone()) {
              // abort complete, trigger finished future
              finishedFuture.setSuccess();
            } else {
              // execution complete, trigger finished future
              finishedFuture.setSuccess();
            }
          }
        };

    return executionListener;
  }

  private ChannelFutureListener createStopConfigurationListener() {
    return new ChannelFutureListener() {
      @Override
      public void operationComplete(ChannelFuture future) throws Exception {
        stopConfiguration();
      }
    };
  }

  @Sharable
  private static final class CloseOnExceptionHandler extends SimpleChannelHandler {

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
      // avoid stack overflow when exception happens on close
      if (TRUE != ctx.getAttachment()) {
        ctx.setAttachment(TRUE);
        // close channel and avoid warning logged by default exceptionCaught implementation
        Channel channel = ctx.getChannel();
        channel.close();
      } else {
        // log exception during close
        super.exceptionCaught(ctx, e);
      }
    }
  }

  public Map<String, Barrier> getBarriersByName() {
    return barriersByName;
  }

  public void notifyBarrier(String barrierName) throws Exception {
    final Barrier barrier = barriersByName.get(barrierName);
    if (barrier == null) {
      throw new Exception(
          "Can not notify a barrier that does not exist in the script: " + barrierName);
    }
    barrier.getFuture().setSuccess();
  }

  public ChannelFuture awaitBarrier(String barrierName) throws Exception {
    final Barrier barrier = barriersByName.get(barrierName);
    if (barrier == null) {
      throw new Exception(
          "Can not notify a barrier that does not exist in the script: " + barrierName);
    }
    return barrier.getFuture();
  }
}