Skip to content

Commit

Permalink
Make BindToRegistry work outside of RouteBuilder classes
Browse files Browse the repository at this point in the history
Fixes #6479
  • Loading branch information
jamesnetherton committed Oct 2, 2024
1 parent 6236bb3 commit c7fc1c8
Show file tree
Hide file tree
Showing 15 changed files with 443 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,24 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.ApplicationArchivesBuildItem;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import org.apache.camel.BindToRegistry;
import org.apache.camel.quarkus.core.CamelBeanQualifierResolver;
import org.apache.camel.quarkus.core.CamelCapabilities;
import org.apache.camel.quarkus.core.CamelConfig;
import org.apache.camel.quarkus.core.CamelRecorder;
import org.apache.camel.quarkus.core.deployment.spi.CamelBeanBuildItem;
import org.apache.camel.quarkus.core.deployment.spi.CamelBeanQualifierResolverBuildItem;
import org.apache.camel.quarkus.core.deployment.spi.CamelContextBuildItem;
import org.apache.camel.quarkus.core.deployment.spi.CamelRegistryBuildItem;
import org.apache.camel.quarkus.core.deployment.spi.CamelRoutesBuilderClassBuildItem;
import org.apache.camel.quarkus.core.deployment.spi.CamelRuntimeBeanBuildItem;
import org.apache.camel.quarkus.core.deployment.spi.CamelRuntimeTaskBuildItem;
import org.apache.camel.quarkus.core.deployment.spi.CamelServiceDestination;
Expand All @@ -39,6 +45,10 @@
import org.apache.camel.quarkus.core.deployment.spi.ContainerBeansBuildItem;
import org.apache.camel.quarkus.core.deployment.util.CamelSupport;
import org.apache.camel.quarkus.core.deployment.util.PathFilter;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.ClassInfo.NestingType;
import org.jboss.jandex.DotName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -168,4 +178,52 @@ CamelRuntimeTaskBuildItem bindRuntimeBeansToRegistry(

return new CamelRuntimeTaskBuildItem("registry");
}

@Record(ExecutionTime.STATIC_INIT)
@BuildStep
void processBindToRegistryAnnotations(
Capabilities capabilities,
CombinedIndexBuildItem combinedIndex,
ContainerBeansBuildItem containerBeans,
List<CamelRoutesBuilderClassBuildItem> camelRoutes,
CamelContextBuildItem camelContextBuildItem,
CamelRecorder recorder) {

// java-joor-dsl has its own discovery mechanism for @BindToRegistry annotations
if (!capabilities.isPresent(CamelCapabilities.JAVA_JOOR_DSL)) {
// Process all classes containing occurrences of BindToRegistry, excluding existing known beans
combinedIndex.getIndex()
.getAnnotations(DotName.createSimple(BindToRegistry.class))
.stream()
.map(annotationInstance -> {
AnnotationTarget target = annotationInstance.target();
ClassInfo classInfo = null;
if (target.kind().equals(AnnotationTarget.Kind.CLASS)) {
classInfo = target.asClass();
}

if (target.kind().equals(AnnotationTarget.Kind.FIELD)) {
classInfo = target.asField().declaringClass();
}

if (target.kind().equals(AnnotationTarget.Kind.METHOD)) {
classInfo = target.asMethod().declaringClass();
}
return classInfo;
})
.filter(Objects::nonNull)
.filter(classInfo -> camelRoutes.stream()
.noneMatch(routeBuilder -> !classInfo.nestingType().equals(NestingType.TOP_LEVEL)
&& routeBuilder.getDotName().equals(classInfo.enclosingClass())))
.map(ClassInfo::name)
.filter(name -> containerBeans.getClasses().stream()
.noneMatch(containerBean -> containerBean.equals(name)))
.map(DotName::toString)
.distinct()
.forEach(beanClassName -> {
recorder.postProcessBeanAndBindToRegistry(camelContextBuildItem.getCamelContext(),
CamelSupport.loadClass(beanClassName, Thread.currentThread().getContextClassLoader()));
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* 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;

import io.quarkus.test.QuarkusUnitTest;
import jakarta.inject.Inject;
import org.apache.camel.BindToRegistry;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spi.Registry;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import static org.junit.jupiter.api.Assertions.assertNotNull;

class CamelBindToRegistryTest {
@RegisterExtension
static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class));

@Inject
Registry registry;

@Test
void bindBeansToRegistry() {
assertNotNull(registry.lookupByName("ServiceA"));
assertNotNull(registry.lookupByName("anotherServiceA"));
assertNotNull(registry.lookupByName("serviceB"));
assertNotNull(registry.lookupByName("ServiceC"));
assertNotNull(registry.lookupByName("ServiceD"));
}

@BindToRegistry
public static class ServiceA {
}

public static class ServiceB {
@BindToRegistry("anotherServiceA")
private ServiceA serviceA = new ServiceA();
}

@BindToRegistry
public static class ServiceC {
@BindToRegistry
public ServiceB serviceB() {
return new ServiceB();
}
}

public static class Routes extends RouteBuilder {
@Override
public void configure() throws Exception {
from("direct:start").log("Hello World");
}

@BindToRegistry
public static class ServiceD {
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public final class CamelCapabilities {
public static final String CLOUD_EVENTS = "org.apache.camel.cloudevents";
public static final String CORE = "org.apache.camel";
public static final String DSL_MODELINE = "org.apache.camel.dsl.modeline";
public static final String JAVA_JOOR_DSL = "org.apache.camel.java.joor.dsl";
public static final String XML = "org.apache.camel.xml";
public static final String XML_IO_DSL = "org.apache.camel.xml.io.dsl";
public static final String XML_JAXB = "org.apache.camel.xml.jaxb";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.apache.camel.impl.engine.DefaultReactiveExecutor;
import org.apache.camel.quarkus.core.FastFactoryFinderResolver.Builder;
import org.apache.camel.spi.BeanProxyFactory;
import org.apache.camel.spi.CamelBeanPostProcessor;
import org.apache.camel.spi.ComponentNameResolver;
import org.apache.camel.spi.FactoryFinderResolver;
import org.apache.camel.spi.ModelJAXBContextFactory;
Expand Down Expand Up @@ -211,4 +212,16 @@ public RuntimeValue<PackageScanClassResolver> createPackageScanClassResolver(
Set<? extends Class<?>> packageScanClassCache) {
return new RuntimeValue<>(new CamelQuarkusPackageScanClassResolver(packageScanClassCache));
}

public void postProcessBeanAndBindToRegistry(RuntimeValue<CamelContext> camelContextRuntimeValue, Class<?> beanType) {
try {
CamelContext camelContext = camelContextRuntimeValue.getValue();
Object bean = beanType.getDeclaredConstructor().newInstance();
CamelBeanPostProcessor beanPostProcessor = PluginHelper.getBeanPostProcessor(camelContext);
beanPostProcessor.postProcessBeforeInitialization(bean, bean.getClass().getName());
beanPostProcessor.postProcessAfterInitialization(bean, bean.getClass().getName());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
5 changes: 5 additions & 0 deletions extensions/java-joor-dsl/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-maven-plugin</artifactId>
<configuration>
<capabilities>
<provides>org.apache.camel.java.joor.dsl</provides>
</capabilities>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ public String route(@PathParam("route") String route) {
return template.requestBody("direct:" + route, null, String.class);
}

@Path("/route/{route}/{beanName}")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String invokeBindToRegistryBean(@PathParam("route") String route, @PathParam("beanName") String beanName) {
return template.requestBodyAndHeader("direct:" + route, beanName, "beanName", beanName, String.class);
}

@Path("/beanMethodInHeader")
@POST
@Consumes(MediaType.TEXT_PLAIN)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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.bean.bind;

import io.quarkus.runtime.annotations.RegisterForReflection;

@RegisterForReflection(fields = false)
public class BindToRegistryBean {
public String hello(String name) {
return "Hello " + name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.bean.bind;

import io.quarkus.runtime.annotations.RegisterForReflection;
import org.apache.camel.BindToRegistry;

@RegisterForReflection(fields = false)
@BindToRegistry
public class BindToRegistryOnClassBean {
public String hello(String name) {
return "Hello " + name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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.bean.bind;

import org.apache.camel.BindToRegistry;

public class BindToRegistryOnFieldBean {
@BindToRegistry("bindToRegistryByField")
private BindToRegistryBean bean = new BindToRegistryBean();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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.bean.bind;

import org.apache.camel.BindToRegistry;

public class BindToRegistryOnMethodBean {
@BindToRegistry
public BindToRegistryBean bindToRegistryOnMethod() {
return new BindToRegistryBean();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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.bean.bind;

import io.quarkus.runtime.annotations.RegisterForReflection;
import org.apache.camel.BindToRegistry;

public class BindToRegistryParentBean {
@RegisterForReflection(fields = false)
@BindToRegistry
public static class NestedBindToRegistryBean {
public String hello(String name) {
return "Hello " + name;
}
}
}
Loading

0 comments on commit c7fc1c8

Please sign in to comment.