| /* |
| * 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.runtime.support; |
| |
| import java.io.InputStream; |
| import java.util.List; |
| import java.util.Properties; |
| import java.util.stream.Collectors; |
| |
| import javax.xml.bind.JAXBException; |
| |
| import org.apache.camel.CamelContext; |
| import org.apache.camel.Route; |
| import org.apache.camel.RoutesBuilder; |
| import org.apache.camel.RuntimeCamelException; |
| import org.apache.camel.ShutdownableService; |
| import org.apache.camel.component.properties.PropertiesComponent; |
| import org.apache.camel.impl.DefaultModelJAXBContextFactory; |
| import org.apache.camel.model.ModelCamelContext; |
| import org.apache.camel.model.RouteDefinition; |
| import org.apache.camel.quarkus.core.runtime.CamelRuntime; |
| import org.apache.camel.quarkus.core.runtime.InitializedEvent; |
| import org.apache.camel.quarkus.core.runtime.InitializingEvent; |
| import org.apache.camel.quarkus.core.runtime.StartedEvent; |
| import org.apache.camel.quarkus.core.runtime.StartingEvent; |
| import org.apache.camel.quarkus.core.runtime.StoppedEvent; |
| import org.apache.camel.quarkus.core.runtime.StoppingEvent; |
| import org.apache.camel.quarkus.core.runtime.CamelConfig.BuildTime; |
| import org.apache.camel.quarkus.core.runtime.CamelConfig.Runtime; |
| import org.apache.camel.spi.ModelJAXBContextFactory; |
| import org.apache.camel.spi.Registry; |
| import org.apache.camel.support.ResourceHelper; |
| import org.apache.camel.util.ObjectHelper; |
| import org.graalvm.nativeimage.ImageInfo; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import io.quarkus.arc.Arc; |
| import io.quarkus.arc.runtime.BeanContainer; |
| |
| public class FastCamelRuntime implements CamelRuntime { |
| |
| private static final Logger log = LoggerFactory.getLogger(FastCamelRuntime.class); |
| |
| protected CamelContext context; |
| protected BeanContainer beanContainer; |
| protected Registry registry; |
| protected Properties properties; |
| protected List<RoutesBuilder> builders; |
| protected BuildTime buildTimeConfig; |
| protected Runtime runtimeConfig; |
| protected ModelJAXBContextFactory jaxbContextFactory; |
| |
| @Override |
| public void init(BuildTime buildTimeConfig) { |
| this.buildTimeConfig = buildTimeConfig; |
| |
| if (buildTimeConfig.disableJaxb) { |
| jaxbContextFactory = () -> { |
| throw new UnsupportedOperationException(); |
| }; |
| } else { |
| jaxbContextFactory = new DefaultModelJAXBContextFactory(); |
| // The creation of the JAXB context is very time consuming, so always prepare it |
| // when running in native mode, but lazy create it in java mode so that we don't |
| // waste time if using java routes |
| if (ImageInfo.inImageBuildtimeCode()) { |
| try { |
| jaxbContextFactory.newJAXBContext(); |
| } catch (JAXBException e) { |
| throw RuntimeCamelException.wrapRuntimeCamelException(e); |
| } |
| } |
| } |
| |
| if (!buildTimeConfig.deferInitPhase) { |
| doInit(); |
| } |
| } |
| |
| @Override |
| public void start(Runtime runtimeConfig) throws Exception { |
| this.runtimeConfig = runtimeConfig; |
| if (buildTimeConfig.deferInitPhase) { |
| doInit(); |
| } |
| doStart(); |
| } |
| |
| @Override |
| public void stop() throws Exception { |
| doStop(); |
| } |
| |
| public void doInit() { |
| try { |
| this.context = createContext(); |
| |
| // Configure the camel context using properties in the form: |
| // |
| // camel.context.${name} = ${value} |
| // |
| RuntimeSupport.bindProperties(properties, context, PFX_CAMEL_CONTEXT); |
| |
| context.setLoadTypeConverters(false); |
| context.setModelJAXBContextFactory(jaxbContextFactory); |
| |
| PropertiesComponent pc = createPropertiesComponent(properties); |
| RuntimeSupport.bindProperties(pc.getInitialProperties(), pc, PFX_CAMEL_PROPERTIES); |
| context.addComponent("properties", pc); |
| |
| this.context.getTypeConverterRegistry().setInjector(this.context.getInjector()); |
| fireEvent(InitializingEvent.class, new InitializingEvent()); |
| this.context.init(); |
| fireEvent(InitializedEvent.class, new InitializedEvent()); |
| |
| loadRoutes(context); |
| } catch (Exception e) { |
| throw RuntimeCamelException.wrapRuntimeCamelException(e); |
| } |
| } |
| |
| public void doStart() throws Exception { |
| fireEvent(StartingEvent.class, new StartingEvent()); |
| context.start(); |
| fireEvent(StartedEvent.class, new StartedEvent()); |
| |
| if (runtimeConfig.dumpRoutes) { |
| dumpRoutes(); |
| } |
| } |
| |
| protected void doStop() throws Exception { |
| fireEvent(StoppingEvent.class, new StoppingEvent()); |
| context.stop(); |
| fireEvent(StoppedEvent.class, new StoppedEvent()); |
| if (context instanceof ShutdownableService) { |
| ((ShutdownableService) context).shutdown(); |
| } |
| } |
| |
| protected void loadRoutes(CamelContext context) throws Exception { |
| for (RoutesBuilder b : builders) { |
| context.addRoutes(b); |
| } |
| |
| List<String> routesUris = buildTimeConfig.routesUris.stream() |
| .filter(ObjectHelper::isNotEmpty) |
| .collect(Collectors.toList()); |
| if (ObjectHelper.isNotEmpty(routesUris)) { |
| log.debug("Loading xml routes from {}", routesUris); |
| ModelCamelContext mcc = context.adapt(ModelCamelContext.class); |
| for (String routesUri : routesUris) { |
| // TODO: if pointing to a directory, we should load all xmls in it |
| // (maybe with glob support in it to be complete) |
| try (InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(mcc, routesUri.trim())) { |
| mcc.addRouteDefinitions(is); |
| } |
| } |
| } else { |
| log.debug("No xml routes configured"); |
| } |
| |
| context.adapt(FastCamelContext.class).reifyRoutes(); |
| } |
| |
| protected CamelContext createContext() { |
| FastCamelContext context = new FastCamelContext(); |
| context.setRegistry(registry); |
| return context; |
| } |
| |
| protected <T> void fireEvent(Class<T> clazz, T event) { |
| Arc.container().beanManager().getEvent().select(clazz).fire(event); |
| } |
| |
| public void setBeanContainer(BeanContainer beanContainer) { |
| this.beanContainer = beanContainer; |
| } |
| |
| public void setRegistry(Registry registry) { |
| this.registry = registry; |
| } |
| |
| public void setProperties(Properties properties) { |
| this.properties = properties; |
| } |
| |
| @Override |
| public void addProperties(Properties properties) { |
| this.properties.putAll(properties); |
| } |
| |
| @Override |
| public void addProperty(String key, Object value) { |
| this.properties.put(key, value); |
| } |
| |
| public void setBuilders(List<RoutesBuilder> builders) { |
| this.builders = builders; |
| } |
| |
| public CamelContext getContext() { |
| return context; |
| } |
| |
| @Override |
| public Registry getRegistry() { |
| return registry; |
| } |
| |
| @Override |
| public BuildTime getBuildTimeConfig() { |
| return buildTimeConfig; |
| } |
| |
| @Override |
| public Runtime getRuntimeConfig() { |
| return runtimeConfig; |
| } |
| |
| protected PropertiesComponent createPropertiesComponent(Properties initialPoperties) { |
| PropertiesComponent pc = new PropertiesComponent(); |
| pc.setInitialProperties(initialPoperties); |
| |
| RuntimeSupport.bindProperties(properties, pc, PFX_CAMEL_PROPERTIES); |
| |
| return pc; |
| } |
| |
| protected void dumpRoutes() { |
| List<Route> routes = getContext().getRoutes(); |
| if (routes.isEmpty()) { |
| log.info("No route definitions"); |
| } else { |
| log.info("Route definitions:"); |
| for (Route route : routes) { |
| RouteDefinition def = (RouteDefinition) route.getRouteContext().getRoute(); |
| log.info(def.toString()); |
| } |
| } |
| } |
| |
| } |