Is possible add a Listener to know when a Bean Service with a particular Interface is created. And when the bean with the same interface is destroyed???
What is the best way to do it? reading the list of injecting services
<reference-list
id="javoraiConceptProcessList"
interface="com.api.MyTask"
availability="optional"
></reference-list>
What is the way to know when the list values is changed?
I am using Gemini Blueprint(Spring)
See the blueprint documentation at IBM.
This is how to do it (below). So you specify bind and unbind methods on a bean that will be called.
public class ReferenceListener {
public void bind(ServiceReference reference) {
...
}
public void bind(Serializable service) {
...
}
public void unbind(ServiceReference reference) {
...
}
}
<reference-list id=”serviceReferenceListTwo” interface=”java.io.Serializable”
availability=”optional”>
<reference-listener
bind-method=”bind” unbind-method=”unbind”>
<bean class=“org.apache.geronimo.osgi.ReferenceListener”/>
</reference-listener>
</reference-list>
Related
As per spring's Event handling mechanism, we can use SpEL to select a specific handler under some circumstances. Taken from the spring doc.
public class EventXHandler {
private String handlerClassName;
#EventListener(condition = "#event.name == handlerClassName")
public void processBlockedListEvent(BlockedListEvent event) {
// notify appropriate parties via notificationAddress...
}
}
My question is; if I can access to the handler class' property in the spel.
No; you cannot do that.
If you know the bean name and add a public getter for the property, you can use
#event.name == #beanName.handlerClassName.
I need a flexible filters for FooEvents for multiple EventListeners all over my code.
I can use #EventListener(condition="event.enabled"), but my filters require many attributes of fooEvent to be analysed.
I was hoping that I could use a Predicate-Bean from my Application Context:
#Component
public class FooPredicate implements Predicate<FooEvent> {
public boolean test(FooEvent event) {...}
}
...
#EventListener(condition="${fooPredicate.test(event)}")
public void handle(FooEvent event) { ... }
But I get:
org.springframework.expression.spel.SpelEvaluationException: EL1011E:
Method call: Attempted to call method
test(org.springframework.context.PayloadApplicationEvent) on null
context object
Is it possible to use external, complex conditions for EventListerns? Or at least to define global listeners with complex conditions and inherit their behavior without repeating the full conditions?
You're using the wrong definition, as fooPredicate is a spring bean you need to use '#' instead of '#' to resolve it as a bean. see 10.5.13 Bean references
#EventListener(condition="#fooPredicate.test(#event)")
public void handle(FooEvent event) {
System.out.println();
}
I've the following bundles:
- GreetingAPI (bundle which defines the greeting() method) (Service)
- GreetingImpl1 (bundle which implements greeting() method for English mode)
- GreetingImpl2 (bundle which implements greeting() method for Italian mode)
- GreetingConsumer (bundle which uses the greeting service)
How Can I create a component (I suppose it's a factory) that based on a given language parameter lets the consumer bundle to use a different implementation of the service.
You're thinking about this the wrong way around. The provider should not register a different service depending on something that the consumer does, because the provider shouldn't know anything about the consumer.
Instead, you can have multiple providers of the same service but annotate them with appropriate metadata. Then the consumer of the service can choose whether or not to filter on specific properties.
For example, when we register a service we can add properties as follows (note that I am using the OSGi Declarative Services annotations, see OSGi Compendium Release 5, section 112.8):
#Component(property = "locale=en_GB")
public class MyGreetingImpl1 implements Greeting {
public String greet() { return "How do you do"; }
}
#Component(property = "locale=en_US")
public class MyGreetingImpl2 implements Greeting {
public String greet() { return "Howdy"; }
}
#Component(property = "locale=fr_FR")
public class MyGreetingImpl3 implements Greeting {
public String greet() { return "Bonjour"; }
}
Now the consumer can choose whichever language it wants using a target filter. Note the use of a wildcard, as the consumer in this case only cares about the language but not the country code:
#Component
public class GreetingConsumer {
#Reference(target = "(language=en*)")
public void setGreeting(Greeting greeting) { ... }
}
One of the possible solutions is to have some kind of a language manager. So your consumer has a language manager and not directly the greetings service
The manager is notified with the registration / deregistration of every language implementation of your GreetingAPI.
Your language manager keeps trace of the diffrent implementations. Your manager provides the right implementation of the target language (using an enum for example)
Example
public class LanguageManagerImpl implements LanguageManager {
//LanguageEnum can be used to distinguish the different languages
private Map<LanguageEnum, GreetingAPI> greetings = new HashMap<LanguageEnum, GreetingAPI>();
public void registerLanguage(GreetingAPI greeting) {
LanguageEnum language = greeting.getLanguageEnum();
//add the greetings to the map
}
public void deregisterLanguage(GreetingAPI greeting){
//remove your greeting from the map
}
public GreetingAPI getGreetingForLanguage(LanguageEnum language) {
return greetings.get(language);
}
}
If you are using blueprint, then you need to add to the language manager blueprint a reference-list with a refence listener on GreetingAPI
Otherwise you use traditional listeners
Example
<bean id="languageManager"
class="your.language.managerimpl.LanguageManagerImpl">
</bean>
<service ref="languageManager" interface="your.language.manager.interface.LanguageManager" />
<reference-list interface="your.greeting.interface.GreetingAPI"
availability="optional">
<reference-listener ref="languageManager"
bind-method="registerLanguage" unbind-method="deregisterLanguage" />
</reference-list>
I am having a series of odd errors in testing and deployment. They seem to indicate that some of my beans are not loading into the context, despite them being defined in applicationContext.xml.
Is there any way to check during testing which beans have actually been loaded? Or to find a complete list of beans loaded at run time?
Thanks,
b
At startup, Spring logs at info level the names of all the beans being loaded by a context. Or in code, you can use getBeanDefinitionNames() to get all the bean names.
if there is more than one context say if you are using spring mvc you can use something more powerful like this.
public class SampleContextApplicationListener implements ApplicationListener<ApplicationContextEvent> {
private Map<String,ApplicationContext> contextMap = new Hashtable<String,ApplicationContext>();
#Override
public void onApplicationEvent(ApplicationContextEvent event) {
if( event instanceof ContextStartedEvent || event instanceof ContextRefreshedEvent){
this.getContextMap().put(event.getApplicationContext().getDisplayName(), event.getApplicationContext());
}
}
public Map<String,ApplicationContext> getContextMap() {
return contextMap;
}
}
You can then inject the listener where it is needed, and extract the map of contextens and then interogate it for all its bean, using the getBeanDefinitionNames()
#Autowired
private StatusTestsApplicationListener listener;
My Requirement:
I have a service which takes care of persistence in my project. Let me call this service as PersistenceProvider service and lets assume it's residing in "my.persistenceservice" bundle.
Now, I have another bundle named "my.persitenceconsumer" bundle which referencing PersistenceProvider service using bind() unbind() method of one of the class named MyPersistenseConsumer. So when "my.persistenceconsumer" bundle starts, it will get reference of PersistenceProvider service using bind() method and MyPersistenceConsumer can use PersistenceProvider service
But, I also need to use this PersistenceProvider service from different classes in "my.persitenceconsumer" bundle.
My QUESTION is:
What is the best way to use such shared service within different classes (in same bundle)
One of the solution:
I can add Activator class in "my.persitenceconsumer" bundle .. having static getInstance() method. Which can be called by MyPersistenceConsumer.bind() and stores PersistenceProvider with Activator. Latter all classes in "my.persitenceconsumer" bundle can use PersistenceProvider using Activator class.
Here is the code:
public class MyPersistenceConsumer {
public void bindPersistenceProvider(PersistenceProvider ppRef) {
MyPersistenceConsumerActivator.getInstance().bindPersistenceProvider(ppRef);
}
}
public class MyPersistenceConsumerActivator {
static MyPersistenceConsumerActivator instance;
PersistenceProvider ppRef;
public static getInstance() {
return instance;
}
public void bindPersistenceProvider(PersistenceProvider ppRef) {
this.ppRef = ppRef;
}
public PersistenceProvider getPersistenceProvider() {
return ppRef;
}
public void start(BundleContext context) throws Exception {
instance = this;
}
}
public class MyClass1 {
public void usePersistenceProvider(){
PersistenceProvider pp Ref =
MyPersistenceConsumerActivator.getInstance().getPersistenceProvider();
}
}
public class MyClass2 {
public void usePersistenceProvider(){
PersistenceProvider pp Ref =
MyPersistenceConsumerActivator.getInstance().getPersistenceProvider();
}
}
At Last:
Does above is good way .. or is there a better way?
Singletons are an evilness that DS tries to eliminate. Singletons create brittle systems, they have the same problems as global vars.
The best solution is no-coupling. With DS I would use:
#Component
public class MyClass1 {
#Reference
void setPP( PersistenceProvider pp ) { ... }
}
And the same for MyClass2. If there is an instance relation between classes, pass the object around since you're already coupled then. As always, minimise coupling and maximise cohesion.
Factories and singletons are the exact evils OSGi tries to prevent for very good reasons.
There are two possibilities I would recommend:
Make the objects that use the persistence-service declarative services. This the SCR will handle all the lifecycle-management and you will get very modular and testable classes.
Alternatively, you can pass a reference to the persistence-service in the constructor of these objects. The only problem here is that you have to make sure that these objects to not try to access the persistence-service after it has gone away.
Either of these approaches is to be preferred over the singleton-based solution you proposed.