content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.camel.quarkus.component.saga.it;
  
  import java.util.Map;
  
  import jakarta.enterprise.context.ApplicationScoped;
  import jakarta.inject.Inject;
  import jakarta.ws.rs.GET;
  import jakarta.ws.rs.Path;
  import jakarta.ws.rs.PathParam;
  import jakarta.ws.rs.Produces;
  import jakarta.ws.rs.core.MediaType;
  import jakarta.ws.rs.core.Response;
  import org.apache.camel.CamelContext;
  import org.apache.camel.quarkus.component.saga.it.lra.LraCreditService;
  import org.apache.camel.quarkus.component.saga.it.lra.LraService;
  import org.apache.camel.quarkus.component.saga.it.lra.LraTicketService;
  import org.jboss.logging.Logger;
  
  @Path("/saga")
  @ApplicationScoped
  public class SagaResource {
  
      private static final Logger LOG = Logger.getLogger(SagaResource.class);
  
      private static final String COMPONENT_SAGA = "saga";
  
      @Inject
      CamelContext context;
  
      @Inject
      OrderManagerService orderManagerService;
  
      @Inject
      CreditService creditService;
  
      @Inject
      LraCreditService lraCreditService;
  
      @Inject
      LraTicketService lraTicketService;
  
      @Inject
      LraService lraService;
  
      @Path("/load/component/saga")
      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public Response loadComponentSaga() throws Exception {
          /* This is an autogenerated test */
          if (context.getComponent(COMPONENT_SAGA) != null) {
              return Response.ok().build();
          }
          LOG.warnf("Could not load [%s] from the Camel context", COMPONENT_SAGA);
          return Response.status(500, COMPONENT_SAGA + " could not be loaded from the Camel context").build();
      }
  
      @Path("/test")
      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public Response buy() {
          try {
              // total credit is 100
              buy(20, false, false);
              buy(70, false, false);
              buy(20, false, true); // fail
              buy(5, false, false);
              buy(1, true, true); // fail
  
              // wait for the orders being cancelled
              Thread.sleep(500);
  
              if (orderManagerService.getOrders().size() == 3 && creditService.getCredit() == 5) {
                  return Response.ok().build();
              } else {
                  return Response.status(500, "not equal").build();
              }
          } catch (Exception e) {
              return Response.status(500, COMPONENT_SAGA + " is failed with " + e).build();
          }
      }
  
      private void buy(int amount, boolean failAtTheEnd, boolean shouldFail) throws RuntimeException {
          try {
              context.createFluentProducerTemplate().to("direct:saga").withHeader("amount", amount)
                      .withHeader("fail", failAtTheEnd).request();
  
              if (shouldFail) {
                  throw new RuntimeException("Exception not thrown");
              }
          } catch (Exception ex) {
              if (!shouldFail) {
                  throw new RuntimeException("Unexpected exception");
              }
          }
      }
  
      @Path("/lraSaga/{id}/{credit}/{trainCost}/{flightCost}")
      @GET
      @Produces(MediaType.APPLICATION_JSON)
      public Response lraSaga(@PathParam("id") int id,
              @PathParam("credit") int credit,
              @PathParam("trainCost") int trainCost,
              @PathParam("flightCost") int flightCost) throws InterruptedException {
  
          //initialize total credit
          lraCreditService.setTotalCredit(credit);
          lraTicketService.reset();
  
          try {
              context.createFluentProducerTemplate().to("direct:lraSaga")
                      .withHeader("id", id)
                      .withHeader("trainCost", trainCost)
                      .withHeader("flightCost", flightCost)
                      .request();
          } catch (Exception e) {
              return getResponse(500);
          }
  
          return getResponse(200);
      }
  
      private Response getResponse(int status) throws InterruptedException {
          // wait for the orders being cancelled
          Thread.sleep(500);
          Map result = Map.of("creditBalance", lraCreditService.getCredit(), "train",
                  lraTicketService.getTrain(),
                  "flight", lraTicketService.getFlight());
  
          return Response.status(status).entity(result).build();
      }
  
      @Path("/timeout/{timeout}")
      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public Response timeout(@PathParam("timeout") int timeout) throws InterruptedException {
          Object o = context.createFluentProducerTemplate().to("direct:newOrderTimeout5sec")
                  .withHeader("timeout", timeout)
                  .request();
          return Response.ok().entity(o).build();
      }
  
      @Path("/manualSaga/{complete}")
      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public Response manualSaga(@PathParam("complete") boolean complete) throws InterruptedException {
  
          lraService.setCompleted(false);
  
          context.createFluentProducerTemplate().to("direct:manualSaga")
                  .withHeader("shouldComplete", complete)
                  .request();
  
          return Response.ok().build();
      }
  
      @Path("/manualCompleted")
      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public Response manualCompensated() throws InterruptedException {
  
          return Response.ok().entity(lraService.isCompleted()).build();
      }
  
      @Path("/xmlSaga/{complete}")
      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public Response xmlSaga(@PathParam("complete") boolean complete) throws InterruptedException {
          lraService.setXmlCompleted(false);
          try {
              context.createFluentProducerTemplate().to("direct:xmlSaga")
                      .withHeader("complete", complete)
                      .request();
          } catch (Exception e) {
              return Response.status(500).entity(e.getCause().getMessage()).build();
          }
          //time to complete
          Thread.sleep(500);
          return Response.ok().entity(lraService.isXmlCompleted()).build();
      }
  }
  