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.k.quarkus;
  
  import java.util.Collection;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.List;
  import java.util.Optional;
  import java.util.Properties;
  import java.util.concurrent.atomic.AtomicBoolean;
  
  import io.quarkus.arc.Arc;
  import io.quarkus.arc.ArcContainer;
  import io.quarkus.arc.InstanceHandle;
  import io.quarkus.runtime.Quarkus;
  import org.apache.camel.CamelContext;
  import org.apache.camel.RoutesBuilder;
  import org.apache.camel.main.BaseMainSupport;
  import org.apache.camel.main.MainListener;
  import org.apache.camel.main.RoutesCollector;
  import org.apache.camel.spi.Resource;
  
  public final class Application {
  
      private Application() {
      }
  
      /**
       * The camel-k runtime impl based on camel-quarkus
       */
      public static class Runtime implements org.apache.camel.k.Runtime {
          private final BaseMainSupport main;
          private final AtomicBoolean stopped;
  
          public Runtime(BaseMainSupport main) {
              this.main = main;
              this.main.configure().setAutoConfigurationLogSummary(false);
              this.stopped = new AtomicBoolean();
          }
  
          @Override
          public CamelContext getCamelContext() {
              return main.getCamelContext();
          }
  
          @Override
          public void addRoutes(RoutesBuilder builder) {
              main.configure().addRoutesBuilder(builder);
          }
  
          @Override
          public void setProperties(Properties properties) {
              main.setOverrideProperties(properties);
          }
  
          @Override
          public void stop() throws Exception {
              if (!this.stopped.compareAndExchange(false, true)) {
                  Quarkus.asyncExit();
              }
          }
      }
  
      /**
       * Adapts main events to camel-k runtime lifecycle
       */
      public static class ListenerAdapter implements MainListener {
          private final org.apache.camel.k.Runtime.Listener[] listeners;
  
          public ListenerAdapter(List<org.apache.camel.k.Runtime.Listener> listeners) {
              this.listeners = listeners.stream()
                  .sorted(Comparator.comparingInt(org.apache.camel.k.Runtime.Listener::getOrder))
                  .toArray(org.apache.camel.k.Runtime.Listener[]::new);
          }
  
          @Override
          public void beforeInitialize(BaseMainSupport main) {
              invokeListeners(org.apache.camel.k.Runtime.Phase.Initializing);
              invokeListeners(org.apache.camel.k.Runtime.Phase.ConfigureProperties);
          }
  
          @Override
          public void beforeConfigure(BaseMainSupport main) {
              invokeListeners(org.apache.camel.k.Runtime.Phase.ConfigureRoutes);
          }
  
          @Override
          public void afterConfigure(BaseMainSupport main) {
              invokeListeners(org.apache.camel.k.Runtime.Phase.ConfigureContext);
          }
  
          @Override
          public void beforeStart(BaseMainSupport main) {
              invokeListeners(org.apache.camel.k.Runtime.Phase.Starting);
          }
  
          @Override
          public void afterStart(BaseMainSupport main) {
              invokeListeners(org.apache.camel.k.Runtime.Phase.Started);
          }
  
          @Override
          public void beforeStop(BaseMainSupport main) {
              invokeListeners(org.apache.camel.k.Runtime.Phase.Stopping);
          }
  
          @Override
          public void afterStop(BaseMainSupport main) {
              invokeListeners(org.apache.camel.k.Runtime.Phase.Stopped);
          }
  
          private void invokeListeners(org.apache.camel.k.Runtime.Phase phase) {
              org.apache.camel.k.Runtime runtime = instance(org.apache.camel.k.Runtime.class)
                  .orElseThrow(() -> new IllegalStateException("Unable to fine a Runtime instance"));
  
              for (int i = 0; i < listeners.length; i ++) {
                  listeners[i].accept(phase, runtime);
              }
          }
      }
  
      /**
       * Since routes are programmatically loaded, create a no-hop collector
       */
      public static class NoRoutesCollector implements RoutesCollector {
          private boolean ignoreLoadingError;
  
          @Override
          public Collection<RoutesBuilder> collectRoutesFromDirectory(CamelContext camelContext, String excludePattern, String includePattern) {
              return Collections.emptyList();
          }
  
          @Override
          public Collection<Resource> findRouteResourcesFromDirectory(CamelContext camelContext, String excludePattern, String includePattern) {
              return Collections.emptyList();
          }
  
          @Override
          public List<RoutesBuilder> collectRoutesFromRegistry(CamelContext camelContext, String excludePattern, String includePattern) {
              return Collections.emptyList();
          }
  
          @Override
          public boolean isIgnoreLoadingError() {
              return ignoreLoadingError;
          }
  
          @Override
          public void setIgnoreLoadingError(boolean ignoreLoadingError) {
              this.ignoreLoadingError = ignoreLoadingError;
          }
      }
  
      // *********************************
      //
      // Helpers
      //
      // *********************************
  
      public static Optional<ArcContainer> container() {
          return Optional.of(Arc.container());
      }
  
      public static <T> Optional<T> instance(Class<T> type) {
          return container()
              .map(container -> container.instance(type))
              .map(InstanceHandle::get);
      }
  }
  