All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.camel.spring.spi.CamelBeanPostProcessor Maven / Gradle / Ivy

The newest version!
/*
 * 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.spring.spi;

import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

import org.apache.camel.BindToRegistry;
import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.Endpoint;
import org.apache.camel.Service;
import org.apache.camel.impl.engine.CamelPostProcessorHelper;
import org.apache.camel.impl.engine.DefaultCamelBeanPostProcessor;
import org.apache.camel.support.service.ServiceHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.Ordered;

/**
 * Spring specific {@link DefaultCamelBeanPostProcessor} which uses Spring {@link BeanPostProcessor} to post process
 * beans.
 *
 * @see DefaultCamelBeanPostProcessor
 */
public class CamelBeanPostProcessor
        implements org.apache.camel.spi.CamelBeanPostProcessor, CamelContextAware, BeanPostProcessor, ApplicationContextAware,
        Ordered {
    private static final Logger LOG = LoggerFactory.getLogger(CamelBeanPostProcessor.class);

    private final Set prototypeBeans = new LinkedHashSet<>();
    private CamelContext camelContext;
    private ApplicationContext applicationContext;
    private String camelId;
    private boolean bindToRegistrySupported;
    private Predicate lazyBeanStrategy;

    // must use a delegate, as we cannot extend DefaultCamelBeanPostProcessor, as this will cause the
    // XSD schema generator to include the DefaultCamelBeanPostProcessor as a type, which we do not want to
    private final DefaultCamelBeanPostProcessor delegate = new DefaultCamelBeanPostProcessor() {
        @Override
        public CamelContext getOrLookupCamelContext() {
            CamelContext answer = CamelBeanPostProcessor.this.camelContext;
            if (answer == null) {
                if (camelId != null) {
                    LOG.trace("Looking up CamelContext by id: {} from Spring ApplicationContext: {}", camelId,
                            applicationContext);
                    answer = applicationContext.getBean(camelId, CamelContext.class);
                } else {
                    // lookup by type and grab the single CamelContext if exists
                    LOG.trace("Looking up CamelContext by type from Spring ApplicationContext: {}", applicationContext);
                    Map contexts = applicationContext.getBeansOfType(CamelContext.class);
                    if (contexts.size() == 1) {
                        answer = contexts.values().iterator().next();
                    }
                }
                if (answer != null) {
                    // we found a camel context
                    CamelBeanPostProcessor.this.camelContext = answer;
                }
            }
            return answer;
        }

        @Override
        public void setCamelContext(CamelContext camelContext) {
            super.setCamelContext(camelContext);
            if (camelPostProcessorHelper != null) {
                camelPostProcessorHelper.setCamelContext(camelContext);
            }
        }

        @Override
        public boolean canPostProcessBean(Object bean, String beanName) {
            if (bean == null) {
                return false;
            }

            return super.canPostProcessBean(bean, beanName);
        }

        @Override
        protected boolean bindToRegistrySupported() {
            // do not support @BindToRegistry as spring and spring-boot has its own set of annotations for this
            return false;
        }

        @Override
        public CamelPostProcessorHelper getPostProcessorHelper() {
            // lets lazily create the post processor
            if (camelPostProcessorHelper == null) {
                camelPostProcessorHelper = new CamelPostProcessorHelper(camelContext) {

                    @Override
                    public CamelContext getCamelContext() {
                        CamelContext answer = CamelBeanPostProcessor.this.camelContext;
                        if (answer == null) {
                            // lets lazily lookup the camel context here
                            // as doing this will cause this context to be started immediately
                            // breaking the lifecycle ordering of different camel contexts
                            // so we only want to do this on demand
                            answer = delegate.getOrLookupCamelContext();
                        }
                        return answer;
                    }

                    @Override
                    protected RuntimeException createProxyInstantiationRuntimeException(
                            Class type, Endpoint endpoint, Exception e) {
                        return new BeanInstantiationException(
                                type, "Could not instantiate proxy of type " + type.getName() + " on endpoint " + endpoint, e);
                    }

                    @Override
                    protected boolean isSingleton(Object bean, String beanName) {
                        // no application context has been injected which means the bean
                        // has not been enlisted in Spring application context
                        if (applicationContext == null || beanName == null) {
                            return super.isSingleton(bean, beanName);
                        } else {
                            return applicationContext.isSingleton(beanName);
                        }
                    }

                    @Override
                    protected void startService(Service service, CamelContext context, Object bean, String beanName)
                            throws Exception {
                        if (isSingleton(bean, beanName)) {
                            getCamelContext().addService(service);
                        } else {
                            // only start service and do not add it to CamelContext
                            ServiceHelper.startService(service);
                            if (prototypeBeans.add(beanName)) {
                                // do not spam the log with WARN so do this only once per bean name
                                CamelBeanPostProcessor.LOG
                                        .warn("The bean with id [{}] is prototype scoped and cannot stop the injected "
                                              + " service when bean is destroyed: {}. You may want to stop the service "
                                              + "manually from the bean.", beanName, service);
                            }
                        }
                    }
                };
            }
            return camelPostProcessorHelper;
        }
    };

    public CamelBeanPostProcessor() {
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        try {
            return delegate.postProcessBeforeInitialization(bean, beanName);
        } catch (BeansException e) {
            throw e; // do not wrap already beans exceptions
        } catch (Exception e) {
            throw new BeanCreationException("Error post processing bean: " + beanName, e);
        }
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        try {
            return delegate.postProcessAfterInitialization(bean, beanName);
        } catch (Exception e) {
            // do not wrap already beans exceptions
            if (e instanceof BeansException) {
                throw (BeansException) e;
            }
            throw new BeanCreationException("Error post processing bean: " + beanName, e);
        }
    }

    @Override
    public int getOrder() {
        return LOWEST_PRECEDENCE;
    }

    // Properties
    // -------------------------------------------------------------------------

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public CamelContext getCamelContext() {
        return camelContext;
    }

    public void setCamelContext(CamelContext camelContext) {
        this.camelContext = camelContext;
        this.delegate.setCamelContext(camelContext);
    }

    public String getCamelId() {
        return camelId;
    }

    public void setCamelId(String camelId) {
        this.camelId = camelId;
    }

    public boolean isBindToRegistrySupported() {
        return bindToRegistrySupported;
    }

    public void setBindToRegistrySupported(boolean bindToRegistrySupported) {
        this.bindToRegistrySupported = bindToRegistrySupported;
    }

    @Override
    public void setEnabled(boolean enabled) {
        delegate.setEnabled(enabled);
    }

    @Override
    public boolean isEnabled() {
        return delegate.isEnabled();
    }

    @Override
    public void setLazyBeanStrategy(Predicate strategy) {
        this.lazyBeanStrategy = strategy;
    }

    @Override
    public Predicate getLazyBeanStrategy() {
        return lazyBeanStrategy;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy