blob: 4468e2e32becc5f54335fb6d056ee90056c41985 [file] [log] [blame]
/*
* 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.core.deployment;
import java.util.List;
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.BeanContainerBuildItem;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Overridable;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.ApplicationArchivesBuildItem;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.ServiceStartBuildItem;
import io.quarkus.deployment.builditem.ShutdownContextBuildItem;
import io.quarkus.deployment.recording.RecorderContext;
import io.quarkus.runtime.RuntimeValue;
import org.apache.camel.CamelContext;
import org.apache.camel.quarkus.core.CamelConfig;
import org.apache.camel.quarkus.core.CamelMain;
import org.apache.camel.quarkus.core.CamelMainProducers;
import org.apache.camel.quarkus.core.CamelMainRecorder;
import org.apache.camel.quarkus.core.CamelProducers;
import org.apache.camel.quarkus.core.CamelRecorder;
import org.apache.camel.quarkus.core.Flags;
import org.apache.camel.spi.Registry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class BuildProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(BuildProcessor.class);
/*
* Build steps related to camel core.
*/
public static class Core {
@BuildStep
void beans(BuildProducer<AdditionalBeanBuildItem> beanProducer) {
beanProducer.produce(AdditionalBeanBuildItem.unremovableOf(CamelProducers.class));
}
@Record(ExecutionTime.STATIC_INIT)
@BuildStep
CamelRegistryBuildItem registry(
CamelRecorder recorder,
RecorderContext recorderContext,
ApplicationArchivesBuildItem applicationArchives,
List<CamelBeanBuildItem> registryItems) {
RuntimeValue<Registry> registry = recorder.createRegistry();
CamelSupport.services(applicationArchives)
.filter(si -> {
//
// by default all the service found in META-INF/service/org/apache/camel are
// bound to the registry but some of the services are then replaced or set
// to the camel context directly by extension so it does not make sense to
// instantiate them in this phase.
//
boolean blacklisted = si.path.endsWith("reactive-executor") || si.path.endsWith("platform-http");
if (blacklisted) {
LOGGER.debug("Ignore service: {}", si);
}
return !blacklisted;
})
.forEach(si -> {
LOGGER.debug("Binding bean with name: {}, type {}", si.name, si.type);
recorder.bind(
registry,
si.name,
recorderContext.classProxy(si.type)
);
});
for (CamelBeanBuildItem item : registryItems) {
LOGGER.debug("Binding bean with name: {}, type {}", item.getName(), item.getType());
recorder.bind(
registry,
item.getName(),
item.getType(),
item.getValue()
);
}
return new CamelRegistryBuildItem(registry);
}
@Overridable
@BuildStep
@Record(value = ExecutionTime.STATIC_INIT, optional = true)
public CamelModelJAXBContextFactoryBuildItem createJaxbContextFactory(CamelRecorder recorder) {
return new CamelModelJAXBContextFactoryBuildItem(recorder.newDisabledModelJAXBContextFactory());
}
@Overridable
@BuildStep
@Record(value = ExecutionTime.STATIC_INIT, optional = true)
public CamelXmlLoaderBuildItem createXmlLoader(CamelRecorder recorder) {
return new CamelXmlLoaderBuildItem(recorder.newDisabledXmlLoader());
}
@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void disableXmlReifiers(CamelRecorder recorder, List<FeatureBuildItem> features) {
if (features.stream().map(FeatureBuildItem::getInfo).noneMatch("camel-xml"::equals)) {
recorder.disableXmlReifiers();
}
}
@Record(ExecutionTime.STATIC_INIT)
@BuildStep
CamelContextBuildItem context(
CamelRecorder recorder,
CamelRegistryBuildItem registry,
CamelModelJAXBContextFactoryBuildItem contextFactory,
CamelXmlLoaderBuildItem xmlLoader,
BeanContainerBuildItem beanContainer,
CamelConfig.BuildTime buildTimeConfig) {
RuntimeValue<CamelContext> context = recorder.createContext(
registry.getRegistry(),
contextFactory.getContextFactory(),
xmlLoader.getXmlLoader(),
beanContainer.getValue(),
buildTimeConfig);
return new CamelContextBuildItem(context);
}
@Record(ExecutionTime.RUNTIME_INIT)
@BuildStep
CamelRuntimeRegistryBuildItem bindRuntimeBeansToRegistry(
CamelRecorder recorder,
CamelRegistryBuildItem registry,
List<CamelRuntimeBeanBuildItem> registryItems) {
for (CamelRuntimeBeanBuildItem item : registryItems) {
LOGGER.debug("Binding runtime bean with name: {}, type {}", item.getName(), item.getType());
recorder.bind(
registry.getRegistry(),
item.getName(),
item.getType(),
item.getValue()
);
}
return new CamelRuntimeRegistryBuildItem(registry.getRegistry());
}
}
/*
* Build steps related to camel main that are activated by default but can be
* disabled by setting quarkus.camel.disable-main = true
*/
public static class Main {
@Overridable
@BuildStep
@Record(value = ExecutionTime.STATIC_INIT, optional = true)
public CamelRoutesCollectorBuildItem createRoutesCollector(CamelMainRecorder recorder) {
return new CamelRoutesCollectorBuildItem(recorder.newDisabledXmlRoutesCollector());
}
@BuildStep(onlyIfNot = Flags.MainDisabled.class)
void beans(BuildProducer<AdditionalBeanBuildItem> beanProducer) {
beanProducer.produce(AdditionalBeanBuildItem.unremovableOf(CamelMainProducers.class));
}
@Overridable
@Record(value = ExecutionTime.RUNTIME_INIT, optional = true)
@BuildStep(onlyIfNot = Flags.MainDisabled.class)
CamelReactiveExecutorBuildItem reactiveExecutor(CamelMainRecorder recorder) {
return new CamelReactiveExecutorBuildItem(recorder.createReactiveExecutor());
}
/**
* This method is responsible to configure camel-main during static init phase which means
* discovering routes, listeners and services that need to be bound to the camel-main.
* <p>
* This method should not attempt to start or initialize camel-main as this need to be done
* at runtime.
*/
@SuppressWarnings("unchecked")
@Record(ExecutionTime.STATIC_INIT)
@BuildStep(onlyIfNot = Flags.MainDisabled.class)
CamelMainBuildItem main(
CombinedIndexBuildItem combinedIndex,
CamelMainRecorder recorder,
RecorderContext recorderContext,
CamelContextBuildItem context,
CamelRoutesCollectorBuildItem routesCollector,
List<CamelMainListenerBuildItem> listeners,
List<CamelRoutesBuilderBuildItem> routesBuilders,
BeanContainerBuildItem beanContainer) {
RuntimeValue<CamelMain> main = recorder.createCamelMain(
context.getCamelContext(),
routesCollector.getValue(),
beanContainer.getValue()
);
for (CamelMainListenerBuildItem listener : listeners) {
recorder.addListener(main, listener.getListener());
}
CamelSupport.getRouteBuilderClasses(combinedIndex.getIndex()).forEach(name -> {
recorder.addRouteBuilder(main, recorderContext.newInstance(name));
});
routesBuilders.forEach(routesBuilder -> {
recorder.addRouteBuilder(main, routesBuilder.getInstance());
});
return new CamelMainBuildItem(main);
}
/**
* This method is responsible to start camel-main ar runtime.
*
* @param recorder the recorder.
* @param main a reference to a {@link CamelMain}.
* @param registry a reference to a {@link Registry}; note that this parameter is here as placeholder to
* ensure the {@link Registry} is fully configured before starting camel-main.
* @param executor the {@link org.apache.camel.spi.ReactiveExecutor} to be configured on camel-main, this
* happens during {@link ExecutionTime#RUNTIME_INIT} because the executor may need to start
* threads and so on.
* @param shutdown a reference to a {@link io.quarkus.runtime.ShutdownContext} used to register shutdown logic.
* @param startList a placeholder to ensure camel-main start after the ArC container is fully initialized. This
* is required as under the hoods the camel registry may look-up beans form the
* container thus we need it to be fully initialized to avoid unexpected behaviors.
*/
@Record(ExecutionTime.RUNTIME_INIT)
@BuildStep(onlyIfNot = Flags.MainDisabled.class)
void start(
CamelMainRecorder recorder,
CamelMainBuildItem main,
CamelRuntimeRegistryBuildItem registry,
CamelReactiveExecutorBuildItem executor,
ShutdownContextBuildItem shutdown,
List<ServiceStartBuildItem> startList) {
recorder.setReactiveExecutor(main.getInstance(), executor.getInstance());
recorder.start(shutdown, main.getInstance());
}
}
}