I have several OSGi bundles (say A, B and C). Each of these bundles has its own Camel routes defined using Spring DM XML file.
I'd like to monitor each route by adding a wiretap at the beginning of each route. For example, the wiretaps would send data to a route defined in a different bundle (say Z)
...
<wiretap uri="direct-vm:data-gathering-route/>
...
In bundle Z, I would define the said route in a file named camelContext.xml. Its location is META-INF/spring, as follows:
<route>
<from uri="direct-vm:data-gathering-route"/>
...
</route>
The reason for defining this route in a separate bundle is because I don't want to repeat this in bundles A, B and C. So I hope I could import this route definition (within bundles A, B and C Camel Context files) using the Spring DM import statement, as follows:
<import resource="classpath:META-INF/spring/camelContext.xml"/>
When I deployed bundles A, B, C and Z in Karaf, it complains that it can't find the camelContext.xml file.
Am I approaching this the right way?
Thanks.
Related
Description
The general use case scenario is - in the world of application package dependency graph, we want to have a collection in parent package and we want to make it available for all children packages to add elements to the list, in other words, extending the list for higher level execution in the parent package.
The goal is let downstream applications able to inject elements to this higher level applications predefined collection so that we achieve federated model for elements while keeping overall execution control in the parent application package.
Example
Say we have 2 application packages
- parent package
- child/children package(s)
The children packages child listed parent package as build dependency
In parent package's spring configuration xml, we have a list that need to be injected with instances of a class really.fun.processor
<util:list id="myProcessors" value-type="really.fun.processor" />
If we host the classes and their instances (beans) in the child package (such as below beans), is it possible to inject back to the parent's list?
<bean name="funProcessor1" class="really.fun.processor"/>
<bean name="funProcessor2" class="really.fun.processor"/>
...
<bean name="funProcessorN" class="really.fun.processor"/>
Question
Is this possible in Spring? If so, what's recommended approaches for this use case?
Figured out the solution:
ComponentScan https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html
EnableAutoConfiguration https://docs.spring.io/spring-boot/docs/1.3.8.RELEASE/reference/html/using-boot-auto-configuration.html
Both are designed to solve the above use case very nicely.
I am experiencing problems with the order components are loaded when using OSGi declaratives services through Karaf.
I have this situation:
#Component
public class A implements IA
{
doSomething() {...}
}
#Component
public class B implements IB
{}
#Component
public class C implements IC
{
#Reference
IA a
#Reference
(cardinality = ReferenceCardinality.MULTIPLE,
policyOption = ReferencePolicyOption.GREEDY,
unbind = "doUnRegister" )
void doRegister(IB b)
{
a.doSomething()
}
void doUnregister(IB b)
{
...
}
}
A, B, and C are three distinct bundles.
When firing up Karaf, a B is registered and doRegister is called. However: service A is not ready (a is null).
I tried the following:
set the start level of A to something lower than B... Did not work
to pickup the registrations of B in a work-list and actually use A later when C was activated. Did not work AND the code was cluttered.
searched for a way to write this requirement through the annotation on doRegister - NOT possible.
I tried to use a service locator and get the context through an activate method on C - DID NOT WORK, it crashed Karaf.
I must clearly be missing something, is there anybody that have experienced similar problems and found a solution?
UPDATE:
Reference A a changed into IA a. Added forgotten information on Reference B().
Based upon the example code you provide, C wont be activated until A and B are present since the references to A and B are static, mandatory references. So start ordering is not relevant.
Also, references are set in the order they are written in the component description XML. When Bnd process the annotations into the component description XML, it writes the references out in order by the reference name. The reference name can be explicitly set and defaults to the name of the annotated member. So in your example code, a comes before doRegister, so the field a will be set before doRegister is called.
My guess is that, in your effort to reduce your actual code to this example, you have lost some important information to understand your problem. This would include the static/dynamic and mandatory/optional nature of your reference as well as the reference names.
I want to make my spring-boot configuration class A dependent on another configuration class B, i.e. A configuration is evaluated only if B configuration is evaluated.
In the real context, I have hundreds of Ai configurations and only one B, and I want to implement a way to exclude all the Ai configs by excluding only B during tests.
I tried the following:
#Configuration
#ConditionalOnBean(type = "org.my.B")
public class A1AutoConfiguration {
// ...
}
Where B is a unconditioned configuration class.
But when I run mvn spring-boot:run -Ddebug=true I see that A is never evaluated because B is missing. While the beans created inside B are in the application context, B itself is not.
I though I can make the Ai configuration classes dependent on beans created inside B but I don't like so much this solution.
Is there a cleaner (and working) way to implement such a dependency mechanism?
The key is to make sure that things are ordered correctly. It does not make any sense to request A to only apply if B is present if you can't make sure that B is evaluated first.
The hundreds part frightens me a bit. If As and B are auto-configuration, you can use the following
#AutoconfigureAfter(B.class)
#ConditionalOnBean(B.class)
public class A123AutoConfiguration { ...}
If As and B are not auto-configuration, you need to make sure B is processed first so you can't rely on regular classpath scanning for those.
I would say that such group of beans is suitable for separate library or sub-module, so that they are independent. Including mechanism can be component scanning on root package of such library or sub-module.
Other option is to use Spring profiles. Mark your beans with #Profile annotation and use #ActiveProfiles to enable certain group of beans during test.
Spring Boot has a config file named "application.properties" or "application.yml". My Spring Boot application is called "A".
My problem is that with these properties files when other applications depend on application A.
<dependency>
<groupId>org.baharan</groupId>
<artifactId>A</artifactId>
<version>1.0.1-releases</version>
<type>jar</type>
</dependency>
I have applications A, B and C.
B and C depend on A, so I had to move "application.properties" of A to B and C then B and C started successfully.
B and C share some property values, so I'd like to put
these common values into application.properties of A and only put project-specific values into B's and C's configuration.
I have three NodeEntities A, B, and C. A is the parent of B and C. C has a property of type Set. For all three entities I have also a PagingAndSortingRepository. The Spring Boot application is set up as in the example https://spring.io/guides/gs/accessing-neo4j-data-rest/.
Now there is a strange thing: If I browse the B-repository directly using the url localhost:8080/B I see all the parent properties that B inherits from A. But if I browse the Bs over C, like localhost:8080/C/0/B I see the Bs but all the inherited properties are empty. Is this a bug or is there something missing?
Do you have a sample project that reproduces this? Or at least share the code for the classes.
Could be that your B relationship needs to have a #Fetch annotation to be fully hydrated for the load.
Update
As I presumed, the transitive child is not loaded automatically, so if you really need the data there, then add the #Fetch annotation.
public class Composite extends Component {
#Fetch
private Set<Leaf> leaf;
....
}