@Override
 public void stop() throws ServletException {
   ThreadSetupAction.Handle handle = deployment.getThreadSetupAction().setup(null);
   try {
     try {
       for (Lifecycle object : deployment.getLifecycleObjects()) {
         object.stop();
       }
     } finally {
       if (executor != null) {
         executor.release();
       }
       if (asyncExecutor != null) {
         asyncExecutor.release();
       }
       executor = null;
       asyncExecutor = null;
     }
   } finally {
     handle.tearDown();
     if (executor != null) {
       executor.release();
     }
     if (asyncExecutor != null) {
       asyncExecutor.release();
     }
     executor = null;
     asyncExecutor = null;
   }
   deployment.getDeploymentInfo().getSessionManager().stop();
   state = State.DEPLOYED;
 }
  /** Launch process and waits until it's down */
  public void launch(Monitored mp) {
    if (!lifecycle.tryToMoveTo(Lifecycle.State.STARTING)) {
      throw new IllegalStateException("Already started");
    }
    monitored = mp;

    try {
      LoggerFactory.getLogger(getClass()).info("Starting " + getKey());
      Runtime.getRuntime().addShutdownHook(shutdownHook);
      stopWatcher.start();

      monitored.start();
      boolean ready = false;
      while (!ready) {
        ready = monitored.isReady();
        Thread.sleep(20L);
      }

      // notify monitor that process is ready
      commands.setReady();

      if (lifecycle.tryToMoveTo(Lifecycle.State.STARTED)) {
        monitored.awaitStop();
      }
    } catch (Exception e) {
      LoggerFactory.getLogger(getClass()).warn("Fail to start " + getKey(), e);

    } finally {
      stop();
    }
  }
 @Override
 public void start() throws Exception {
   this.lifecycles = loadLifecycles();
   for (Lifecycle lifecycle : this.lifecycles) {
     lifecycle.start();
   }
   super.start();
 }
  /**
   * Set the Valve instance that has been distinguished as the basic Valve for this Pipeline (if
   * any). Prior to setting the basic Valve, the Valve's <code>setContainer()</code> will be called,
   * if it implements <code>Contained</code>, with the owning Container as an argument. The method
   * may throw an <code>IllegalArgumentException</code> if this Valve chooses not to be associated
   * with this Container, or <code>IllegalStateException</code> if it is already associated with a
   * different Container.
   *
   * @param valve Valve to be distinguished as the basic Valve
   */
  public void setBasic(GlassFishValve valve) {

    // Change components if necessary
    GlassFishValve oldBasic = null;
    synchronized (this) {
      oldBasic = this.basic;
    }
    if (oldBasic == valve) {
      return;
    }

    // Stop the old component if necessary
    if (oldBasic != null) {
      synchronized (this) {
        if (started && (oldBasic instanceof Lifecycle)) {
          try {
            ((Lifecycle) oldBasic).stop();
          } catch (LifecycleException e) {
            log.log(Level.SEVERE, SET_BASIC_STOP_EXCEPTION, e);
          }
        }
      }
      if (oldBasic instanceof Contained) {
        try {
          ((Contained) oldBasic).setContainer(null);
        } catch (Throwable t) {
          // Ignore
        }
      }
    }

    // Start the new component if necessary
    if (valve == null) {
      return;
    }
    if (valve instanceof Contained) {
      ((Contained) valve).setContainer(this.container);
    }
    /** CR 6411114 if (valve instanceof Lifecycle) { */
    // START CR 6411114
    // Start the valve if the pipeline has already been started
    if (started && (valve instanceof Lifecycle)) {
      // END CR 6411114
      try {
        ((Lifecycle) valve).start();
      } catch (LifecycleException e) {
        log.log(Level.SEVERE, SET_BASIC_START_EXCEPTION, e);
        return;
      }
    }

    synchronized (this) {
      this.basic = valve;
    }
  }
 @Override
 public void stop() throws Exception {
   for (Lifecycle lifecycle : reverseLifecycles()) {
     try {
       lifecycle.stop();
     } catch (Throwable t) {
       LOG.error("Failed to stop Lifecycle: " + lifecycle.getClass().getName(), t);
     }
   }
   super.stop();
 }
  /**
   * Remove the specified Valve from the pipeline associated with this Container, if it is found;
   * otherwise, do nothing. If the Valve is found and removed, the Valve's <code>setContainer(null)
   * </code> method will be called if it implements <code>Contained</code>.
   *
   * @param valve Valve to be removed
   */
  public void removeValve(GlassFishValve valve) {

    // Locate this Valve in our list
    int j = -1;
    for (int i = 0; i < valves.length; i++) {
      if (valve == valves[i]) {
        j = i;
        break;
      }
    }
    if (j < 0) return;

    // Remove this valve from our list
    GlassFishValve results[] = new GlassFishValve[valves.length - 1];
    int n = 0;
    for (int i = 0; i < valves.length; i++) {
      if (i == j) continue;
      results[n++] = valves[i];
    }
    valves = results;
    try {
      if (valve instanceof Contained) ((Contained) valve).setContainer(null);
    } catch (Throwable t) {;
    }

    // Stop this valve if necessary
    if (started) {
      if (valve instanceof ValveBase) {
        if (((ValveBase) valve).isStarted()) {
          try {
            ((Lifecycle) valve).stop();
          } catch (LifecycleException e) {
            log.log(Level.SEVERE, REMOVE_VALVE_EXCEPTION, e);
          }
        }
      } else if (valve instanceof Lifecycle) {
        try {
          ((Lifecycle) valve).stop();
        } catch (LifecycleException e) {
          log.log(Level.SEVERE, REMOVE_VALVE_EXCEPTION, e);
        }
      }

      /**
       * CR 6411114 (MBean deregistration moved to ValveBase.stop()) // Unregister the removed valve
       * unregisterValve(valve);
       */
    }
  }
  /**
   * Add a new Valve to the end of the pipeline associated with this Container. Prior to adding the
   * Valve, the Valve's <code>setContainer()</code> method will be called, if it implements <code>
   * Contained</code>, with the owning Container as an argument. The method may throw an <code>
   * IllegalArgumentException</code> if this Valve chooses not to be associated with this Container,
   * or <code>IllegalStateException</code> if it is already associated with a different Container.
   *
   * @param valve Valve to be added
   * @exception IllegalArgumentException if this Container refused to accept the specified Valve
   * @exception IllegalArgumentException if the specified Valve refuses to be associated with this
   *     Container
   * @exception IllegalStateException if the specified Valve is already associated with a different
   *     Container
   */
  public void addValve(GlassFishValve valve) {

    if (firstTcValve != null) {
      // Wrap GlassFish-style valve inside Tomcat-style valve
      addValve(new TomcatValveAdapter(valve));
      return;
    }

    // Validate that we can add this Valve
    if (valve instanceof Contained) ((Contained) valve).setContainer(this.container);

    // Start the new component if necessary
    if (started) {
      if (valve instanceof Lifecycle) {
        try {
          ((Lifecycle) valve).start();
        } catch (LifecycleException e) {
          log.log(Level.SEVERE, ADD_VALVE_EXCEPTION, e);
        }
      }
      /**
       * CR 6411114 (MBean registration moved to ValveBase.start()) // Register the newly added
       * valve registerValve(valve);
       */
    }

    // Add this Valve to the set associated with this Pipeline
    GlassFishValve results[] = new GlassFishValve[valves.length + 1];
    System.arraycopy(valves, 0, results, 0, valves.length);
    results[valves.length] = valve;
    valves = results;
  }
  /**
   * Gracefully shut down active use of the public methods of this Component.
   *
   * @exception IllegalStateException if this component has not been started
   * @exception LifecycleException if this component detects a fatal error that needs to be reported
   */
  public synchronized void stop() throws LifecycleException {

    // Validate and update our current component state
    if (!started) throw new LifecycleException(rb.getString(PIPLINE_NOT_STARTED));

    started = false;

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(STOP_EVENT, null);

    // Stop the Valves in our pipeline (including the basic), if any
    if ((basic != null) && (basic instanceof Lifecycle)) ((Lifecycle) basic).stop();
    /**
     * CR 6411114 (MBean deregistration moved to ValveBase.stop()) if( basic!=null ) {
     * unregisterValve(basic); }
     */
    for (int i = 0; i < valves.length; i++) {
      if (valves[i] instanceof Lifecycle) ((Lifecycle) valves[i]).stop();
      /** CR 6411114 (MBean deregistration moved to ValveBase.stop()) unregisterValve(valves[i]); */
    }

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
  }
  public void testPojoStyleBean() throws Exception {
    List expected = Arrays.asList(Lifecycle.values());
    InitialContext ctx = new InitialContext();

    {
      WidgetBean.lifecycle.clear();

      Object object = ctx.lookup("WidgetBeanLocal");

      assertTrue("instanceof widget", object instanceof Widget);

      Widget widget = (Widget) object;

      // Do a business method...
      Stack<Lifecycle> lifecycle = widget.getLifecycle();
      assertNotNull("lifecycle", lifecycle);
      assertSame("lifecycle", lifecycle, WidgetBean.lifecycle);

      // Check the lifecycle of the bean
      assertEquals(join("\n", expected), join("\n", lifecycle));
    }
    {
      WidgetBean.lifecycle.clear();

      Object object = ctx.lookup("WidgetBeanLocalBean");

      assertTrue("instanceof widget", object instanceof WidgetBean);

      WidgetBean widget = (WidgetBean) object;

      // Do a business method...
      Stack<Lifecycle> lifecycle = widget.getLifecycle();
      assertNotNull("lifecycle", lifecycle);
      assertSame("lifecycle", lifecycle, WidgetBean.lifecycle);

      // Check the lifecycle of the bean
      assertEquals(
          Lifecycle.CONSTRUCTOR + "\n" + Lifecycle.BUSINESS_METHOD + "\n", join("\n", lifecycle));
    }
    {
      WidgetBean.lifecycle.clear();

      Object object = ctx.lookup("WidgetBeanRemote");

      assertTrue("instanceof widget", object instanceof RemoteWidget);

      RemoteWidget remoteWidget = (RemoteWidget) object;

      // Do a business method...
      Stack<Lifecycle> lifecycle = remoteWidget.getLifecycle();
      assertNotNull("lifecycle", lifecycle);
      assertNotSame("lifecycle", lifecycle, WidgetBean.lifecycle);

      // Check the lifecycle of the bean
      assertEquals(Lifecycle.BUSINESS_METHOD + "\n", join("\n", lifecycle));
    }
  }
 @Override
 public void stopAsync() {
   if (lifecycle.tryToMoveTo(Lifecycle.State.STOPPING)) {
     stopperThread =
         new StopperThread(
             monitored,
             commands,
             Long.parseLong(props.nonNullValue(PROPERTY_TERMINATION_TIMEOUT)));
     stopperThread.start();
     stopWatcher.stopWatching();
   }
 }
 /** Blocks until stopped in a timely fashion (see {@link org.sonar.process.StopperThread}) */
 void stop() {
   stopAsync();
   try {
     // stopperThread is not null for sure
     // join() does nothing if thread already finished
     stopperThread.join();
     lifecycle.tryToMoveTo(Lifecycle.State.STOPPED);
   } catch (InterruptedException e) {
     // nothing to do, the process is going to be exited
   }
   exit.exit(0);
 }
  @Override
  public HttpHandler start() throws ServletException {
    ThreadSetupAction.Handle handle = deployment.getThreadSetupAction().setup(null);
    try {
      deployment.getDeploymentInfo().getSessionManager().start();
      for (Lifecycle object : deployment.getLifecycleObjects()) {
        object.start();
      }
      HttpHandler root = deployment.getServletHandler();

      // create the executor, if it exists
      if (deployment.getDeploymentInfo().getExecutorFactory() != null) {
        try {
          executor = deployment.getDeploymentInfo().getExecutorFactory().createInstance();
          root =
              new AttachmentHandler<>(
                  HttpServerExchange.DISPATCH_EXECUTOR, root, executor.getInstance());
        } catch (InstantiationException e) {
          throw new RuntimeException(e);
        }
      }
      if (deployment.getDeploymentInfo().getExecutorFactory() != null) {
        if (deployment.getDeploymentInfo().getAsyncExecutorFactory() != null) {
          try {
            asyncExecutor =
                deployment.getDeploymentInfo().getAsyncExecutorFactory().createInstance();
            root =
                new AttachmentHandler<>(
                    AsyncContextImpl.ASYNC_EXECUTOR, root, asyncExecutor.getInstance());
          } catch (InstantiationException e) {
            throw new RuntimeException(e);
          }
        }
      }
      state = State.STARTED;
      return root;
    } finally {
      handle.tearDown();
    }
  }
  /**
   * Set the Valve instance that has been distinguished as the basic Valve for this Pipeline (if
   * any). Prioer to setting the basic Valve, the Valve's <code>setContainer()</code> will be
   * called, if it implements <code>Contained</code>, with the owning Container as an argument. The
   * method may throw an <code>IllegalArgumentException</code> if this Valve chooses not to be
   * associated with this Container, or <code>IllegalStateException</code> if it is already
   * associated with a different Container.
   *
   * @param valve Valve to be distinguished as the basic Valve
   */
  public void setBasic(Valve valve) {

    // Change components if necessary
    Valve oldBasic = this.basic;
    if (oldBasic == valve) return;

    // Stop the old component if necessary
    if (oldBasic != null) {
      if (started && (oldBasic instanceof Lifecycle)) {
        try {
          ((Lifecycle) oldBasic).stop();
        } catch (LifecycleException e) {
          log("StandardPipeline.setBasic: stop", e);
        }
      }
      if (oldBasic instanceof Contained) {
        try {
          ((Contained) oldBasic).setContainer(null);
        } catch (Throwable t) {;
        }
      }
    }

    // Start the new component if necessary
    if (valve == null) return;
    if (valve instanceof Contained) {
      ((Contained) valve).setContainer(this.container);
    }
    if (valve instanceof Lifecycle) {
      try {
        ((Lifecycle) valve).start();
      } catch (LifecycleException e) {
        log("StandardPipeline.setBasic: start", e);
        return;
      }
    }
    this.basic = valve;
  }
  /** Add Tomcat-style valve. */
  public synchronized void addValve(Valve valve) {

    /*
     * Check if this is a GlassFish-style valve that was compiled
     * against the old org.apache.catalina.Valve interface (from
     * GlassFish releases prior to V3), which has since been renamed
     * to org.glassfish.web.valve.GlassFishValve (in V3)
     */
    if (isGlassFishValve(valve)) {
      try {
        addValve(new GlassFishValveAdapter(valve));
      } catch (Exception e) {
        String msg = MessageFormat.format(rb.getString(ADD_TOMCAT_STYLE_VALVE_EXCEPTION), valve);
        log.log(Level.SEVERE, msg, e);
      }
      return;
    }

    if (valve instanceof Contained) ((Contained) valve).setContainer(this.container);

    // Start the new Valve if necessary
    if (started) {
      if (valve instanceof Lifecycle) {
        try {
          ((Lifecycle) valve).start();
        } catch (LifecycleException e) {
          log.log(Level.SEVERE, ADD_VALVE_EXCEPTION, e);
        }
      }
    }

    if (firstTcValve == null) {
      firstTcValve = lastTcValve = valve;
    } else {
      lastTcValve.setNext(valve);
      lastTcValve = valve;
    }

    if (basic != null) {
      valve.setNext((Valve) basic);
    }
  }
  /**
   * Gracefully shut down active use of the public methods of this Component.
   *
   * @throws LifecycleException if this component detects a fatal error that needs to be reported
   */
  public synchronized void stop() throws LifecycleException {

    // Validate and update our current component state
    if (!started) throw new LifecycleException(sm.getString("standardPipeline.notStarted"));

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(STOP_EVENT, null);
    started = false;

    // Stop the Valves in our pipeline (including the basic), if any
    if ((basic != null) && (basic instanceof Lifecycle)) ((Lifecycle) basic).stop();
    for (int i = 0; i < valves.length; i++) {
      if (valves[i] instanceof Lifecycle) ((Lifecycle) valves[i]).stop();
    }

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
  }
  /**
   * Add a new Valve to the end of the pipeline associated with this Container. Prior to adding the
   * Valve, the Valve's <code>setContainer()</code> method will be called, if it implements <code>
   * Contained</code>, with the owning Container as an argument. The method may throw an <code>
   * IllegalArgumentException</code> if this Valve chooses not to be associated with this Container,
   * or <code>IllegalStateException</code> if it is already associated with a different Container.
   *
   * @param valve Valve to be added
   * @throws IllegalArgumentException if this Container refused to accept the specified Valve
   * @throws IllegalArgumentException if the specifie Valve refuses to be associated with this
   *     Container
   * @throws IllegalStateException if the specified Valve is already associated with a different
   *     Container
   */
  public void addValve(Valve valve) {

    // Validate that we can add this Valve
    if (valve instanceof Contained) ((Contained) valve).setContainer(this.container);

    // Start the new component if necessary
    if (started && (valve instanceof Lifecycle)) {
      try {
        ((Lifecycle) valve).start();
      } catch (LifecycleException e) {
        log("StandardPipeline.addValve: start: ", e);
      }
    }

    // Add this Valve to the set associated with this Pipeline
    synchronized (valves) {
      Valve results[] = new Valve[valves.length + 1];
      System.arraycopy(valves, 0, results, 0, valves.length);
      results[valves.length] = valve;
      valves = results;
    }
  }
  /**
   * Remove the specified Valve from the pipeline associated with this Container, if it is found;
   * otherwise, do nothing. If the Valve is found and removed, the Valve's <code>setContainer(null)
   * </code> method will be called if it implements <code>Contained</code>.
   *
   * @param valve Valve to be removed
   */
  public void removeValve(Valve valve) {

    synchronized (valves) {

      // Locate this Valve in our list
      int j = -1;
      for (int i = 0; i < valves.length; i++) {
        if (valve == valves[i]) {
          j = i;
          break;
        }
      }
      if (j < 0) return;

      // Remove this valve from our list
      Valve results[] = new Valve[valves.length - 1];
      int n = 0;
      for (int i = 0; i < valves.length; i++) {
        if (i == j) continue;
        results[n++] = valves[i];
      }
      valves = results;
      try {
        if (valve instanceof Contained) ((Contained) valve).setContainer(null);
      } catch (Throwable t) {;
      }
    }

    // Stop this valve if necessary
    if (started && (valve instanceof Lifecycle)) {
      try {
        ((Lifecycle) valve).stop();
      } catch (LifecycleException e) {
        log("StandardPipeline.removeValve: stop: ", e);
      }
    }
  }
 Lifecycle.State getState() {
   return lifecycle.getState();
 }
 boolean isStarted() {
   return lifecycle.getState() == Lifecycle.State.STARTED;
 }
Example #20
0
  public static void main(String[] args) {

    System.setProperty("catalina.base", System.getProperty("user.dir"));
    Connector connector = new HttpConnector();

    Wrapper wrapper1 = new StandardWrapper();
    wrapper1.setName("Primitive");
    wrapper1.setServletClass("PrimitiveServlet");
    Wrapper wrapper2 = new StandardWrapper();
    wrapper2.setName("Modern");
    wrapper2.setServletClass("ModernServlet");

    Context context = new StandardContext();
    // StandardContext's start method adds a default mapper
    context.setPath("/app1");
    context.setDocBase("app1");

    context.addChild(wrapper1);
    context.addChild(wrapper2);

    LifecycleListener listener = new SimpleContextConfig();
    ((Lifecycle) context).addLifecycleListener(listener);

    Host host = new StandardHost();
    host.addChild(context);
    host.setName("localhost");
    host.setAppBase("webapps");

    Loader loader = new WebappLoader();
    context.setLoader(loader);
    // context.addServletMapping(pattern, name);
    context.addServletMapping("/Primitive", "Primitive");
    context.addServletMapping("/Modern", "Modern");

    Engine engine = new StandardEngine();
    engine.addChild(host);
    engine.setDefaultHost("localhost");

    Service service = new StandardService();
    service.setName("Stand-alone Service");
    Server server = new StandardServer();
    server.addService(service);
    service.addConnector(connector);

    // StandardService class's setContainer will call all its connector's setContainer method
    service.setContainer(engine);

    // Start the new server
    if (server instanceof Lifecycle) {
      try {
        server.initialize();
        ((Lifecycle) server).start();
        server.await();
        // the program waits until the await method returns,
        // i.e. until a shutdown command is received.
      } catch (LifecycleException e) {
        e.printStackTrace(System.out);
      }
    }

    // Shut down the server
    if (server instanceof Lifecycle) {
      try {
        ((Lifecycle) server).stop();
      } catch (LifecycleException e) {
        e.printStackTrace(System.out);
      }
    }
  }
  private void testFailover(Lifecycle lifecycle, URL baseURL1, URL baseURL2) throws Exception {
    HttpClient client = TestHttpClientUtils.promiscuousCookieHttpClient();

    URI uri1 = SimpleServlet.createURI(baseURL1);
    URI uri2 = SimpleServlet.createURI(baseURL2);

    this.establishTopology(baseURL1, NODES);

    try {
      HttpResponse response = client.execute(new HttpGet(uri1));
      try {
        Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode());
        Assert.assertEquals(
            1, Integer.parseInt(response.getFirstHeader(SimpleServlet.VALUE_HEADER).getValue()));
        Map.Entry<String, String> entry = parseSessionRoute(response);
        Assert.assertEquals(NODE_1, entry.getValue());
        Assert.assertEquals(
            entry.getKey(), response.getFirstHeader(SimpleServlet.SESSION_ID_HEADER).getValue());
      } finally {
        HttpClientUtils.closeQuietly(response);
      }

      // Let's do this twice to have more debug info if failover is slow.
      response = client.execute(new HttpGet(uri1));
      try {
        Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode());
        Assert.assertEquals(
            2, Integer.parseInt(response.getFirstHeader(SimpleServlet.VALUE_HEADER).getValue()));
        Map.Entry<String, String> entry = parseSessionRoute(response);
        if (entry != null) {
          Assert.assertEquals(NODE_1, entry.getValue());
          Assert.assertEquals(
              entry.getKey(), response.getFirstHeader(SimpleServlet.SESSION_ID_HEADER).getValue());
        }
      } finally {
        HttpClientUtils.closeQuietly(response);
      }

      // Gracefully undeploy from/shutdown the 1st container.
      lifecycle.stop(NODE_1);

      this.establishTopology(baseURL2, NODE_2);

      // Now check on the 2nd server

      response = client.execute(new HttpGet(uri2));
      try {
        Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode());
        Assert.assertEquals(
            "Session failed to replicate after container 1 was shutdown.",
            3,
            Integer.parseInt(response.getFirstHeader(SimpleServlet.VALUE_HEADER).getValue()));
        Map.Entry<String, String> entry = parseSessionRoute(response);
        Assert.assertEquals(NODE_2, entry.getValue());
        Assert.assertEquals(
            entry.getKey(), response.getFirstHeader(SimpleServlet.SESSION_ID_HEADER).getValue());
      } finally {
        HttpClientUtils.closeQuietly(response);
      }

      // Let's do one more check.
      response = client.execute(new HttpGet(uri2));
      try {
        Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode());
        Assert.assertEquals(
            4, Integer.parseInt(response.getFirstHeader(SimpleServlet.VALUE_HEADER).getValue()));
        Map.Entry<String, String> entry = parseSessionRoute(response);
        if (entry != null) {
          Assert.assertEquals(NODE_2, entry.getValue());
          Assert.assertEquals(
              entry.getKey(), response.getFirstHeader(SimpleServlet.SESSION_ID_HEADER).getValue());
        }
      } finally {
        HttpClientUtils.closeQuietly(response);
      }

      lifecycle.start(NODE_1);

      this.establishTopology(baseURL2, NODES);

      response = client.execute(new HttpGet(uri2));
      try {
        Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode());
        Assert.assertEquals(
            "Session failed to replicate after container 1 was brough up.",
            5,
            Integer.parseInt(response.getFirstHeader(SimpleServlet.VALUE_HEADER).getValue()));
        Map.Entry<String, String> entry = parseSessionRoute(response);
        if (entry != null) {
          Assert.assertEquals(NODE_1, entry.getValue());
          Assert.assertEquals(
              entry.getKey(), response.getFirstHeader(SimpleServlet.SESSION_ID_HEADER).getValue());
        }
      } finally {
        HttpClientUtils.closeQuietly(response);
      }

      // The previous and next requests intentially hit the non-owning node
      this.nonOwnerTask.run();

      // Let's do this twice to have more debug info if failover is slow.
      response = client.execute(new HttpGet(uri2));
      try {
        Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode());
        Assert.assertEquals(
            6, Integer.parseInt(response.getFirstHeader(SimpleServlet.VALUE_HEADER).getValue()));
        Map.Entry<String, String> entry = parseSessionRoute(response);
        if (entry != null) {
          Assert.assertEquals(NODE_1, entry.getValue());
          Assert.assertEquals(
              entry.getKey(), response.getFirstHeader(SimpleServlet.SESSION_ID_HEADER).getValue());
        }
      } finally {
        HttpClientUtils.closeQuietly(response);
      }

      // Until graceful undeploy is supported, we need to wait for replication to complete before
      // undeploy (WFLY-6769).
      if (lifecycle instanceof RedeployLifecycle) {
        Thread.sleep(GRACE_TIME_TO_REPLICATE);
      }

      // Gracefully undeploy from/shutdown the 1st container.
      lifecycle.stop(NODE_2);

      this.establishTopology(baseURL1, NODE_1);

      // Now check on the 2nd server

      response = client.execute(new HttpGet(uri1));
      try {
        Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode());
        Assert.assertEquals(
            "Session failed to replicate after container 1 was shutdown.",
            7,
            Integer.parseInt(response.getFirstHeader(SimpleServlet.VALUE_HEADER).getValue()));
        Map.Entry<String, String> entry = parseSessionRoute(response);
        if (entry != null) {
          Assert.assertEquals(NODE_1, entry.getValue());
          Assert.assertEquals(
              entry.getKey(), response.getFirstHeader(SimpleServlet.SESSION_ID_HEADER).getValue());
        }
      } finally {
        HttpClientUtils.closeQuietly(response);
      }

      // Let's do one more check.
      response = client.execute(new HttpGet(uri1));
      try {
        Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode());
        Assert.assertEquals(
            8, Integer.parseInt(response.getFirstHeader(SimpleServlet.VALUE_HEADER).getValue()));
        Map.Entry<String, String> entry = parseSessionRoute(response);
        if (entry != null) {
          Assert.assertEquals(NODE_1, entry.getValue());
          Assert.assertEquals(
              entry.getKey(), response.getFirstHeader(SimpleServlet.SESSION_ID_HEADER).getValue());
        }
      } finally {
        HttpClientUtils.closeQuietly(response);
      }

      lifecycle.start(NODE_2);

      this.establishTopology(baseURL1, NODES);

      response = client.execute(new HttpGet(uri1));
      try {
        Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode());
        Assert.assertEquals(
            "Session failed to replicate after container 1 was brought up.",
            9,
            Integer.parseInt(response.getFirstHeader(SimpleServlet.VALUE_HEADER).getValue()));
        Map.Entry<String, String> entry = parseSessionRoute(response);
        if (entry != null) {
          Assert.assertEquals(NODE_2, entry.getValue());
          Assert.assertEquals(
              entry.getKey(), response.getFirstHeader(SimpleServlet.SESSION_ID_HEADER).getValue());
        }
      } finally {
        HttpClientUtils.closeQuietly(response);
      }

      // Let's do this twice to have more debug info if failover is slow.
      response = client.execute(new HttpGet(uri1));
      try {
        Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode());
        Assert.assertEquals(
            10, Integer.parseInt(response.getFirstHeader(SimpleServlet.VALUE_HEADER).getValue()));
        Map.Entry<String, String> entry = parseSessionRoute(response);
        if (entry != null) {
          Assert.assertEquals(NODE_2, entry.getValue());
          Assert.assertEquals(
              entry.getKey(), response.getFirstHeader(SimpleServlet.SESSION_ID_HEADER).getValue());
        }
      } finally {
        HttpClientUtils.closeQuietly(response);
      }
    } finally {
      HttpClientUtils.closeQuietly(client);
    }
  }