JavaEE CDI in Weld: Generic Events? - events

I have an idea for a specific event handling based on generics, but seems like Weld can't handle them. I asked google but couldn't find an alternative CDI extension for this.
Question: is there a CDI extension, that can handle event propagation of generic-typed events?
In the following the explicit problem I have.
I have three general events, EntityCreated, EntityChanged and EntityDeleted. The base class for them is defined like this:
public abstract class DatabaseEvent<TargetType> {
public TargetType target;
public DatabaseEvent(TargetType target) {
this.target = target;
}
}
The events then are simple inherited classes:
public class EntityCreatedEvent<TargetType> extends DatabaseEvent<TargetType> {
public EntityCreatedEvent(TargetType target) {
super(target);
}
}
I fire them like this:
public abstract class MyHome<EntityType> {
private EntityType entity;
#Inject
Event<EntityCreatedEvent<EntityType>> entityCreatedEvent;
public void fireCreatedEvent() {
EntityCreatedEvent<EntityType> payload = new EntityCreatedEvent<EntityType>(entity);
entityCreatedEvent.fire(payload);
}
}
I want to observe them like this:
public void handleProjectCreated(#Observes EntityCreatedEvent<Project> event) { ... }
When launching the server Weld tells me it can't handle generic-typed events. The CDI-way of doing things would be to use additional qualifiers instead of the generics to distiguish them, e.g.:
public void handleProjectCreated(#Observes #ProjectEvent EntityCreatedEvent event) { ... }
However, I fire the events from that MyHome base class, where I can't just fire with the #ProjectEvent: it might not be a project but another type.
My solution up to now is to skip that typing altogether and handle them like this:
public void handleProjectCreated(#Observes EntityCreatedEvent event) {
if(event.target instanceof Project) { ... }
}
This solution is okay, but not perfect.

I guess you can do this with dinamically binding qualifier members. This is what your code would look like:
public abstract class MyHome {
private EntityType entity;
#Inject
Event<EntityCreatedEvent> entityCreatedEvent;
public void fireCreatedEvent() {
entityCreatedEvent.select(getTypeBinding()).fire(new EntityCreatedEvent(entity));
}
private TypeBinding getTypeBinding() {
return new TypeBinding() {
public Class<? extends EntityType> value() {return entity.getClass();}
};
}
#Qualifier
#Target({ PARAMETER, FIELD })
#Retention(RUNTIME)
public #interface EntityTypeQualifier {
Class<? extends EntityType> value();
}
public abstract class TypeBinding extends AnnotationLiteral<EntityTypeQualifier> implements EntityTypeQualifier {}
//Observers
public void handleEntityType1Created(#Observes #EntityTypeQualifier(EntityType1.class) EntityCreatedEvent event) {}
public void handleEntityType2Created(#Observes #EntityTypeQualifier(EntityType2.class) EntityCreatedEvent event) {}

As this CDI issue points it is not possible to fire an without having the type of T at runtime.
But, if you have the type of T (i.e. you have an instance) you can use the Event as an Instance, and select the event to be fired using a dynamic type literal.

Related

overriding virtual event

I've got the following code
public delegate void NotificacaoScanner(NotifScanner e);
// interface
public interface IScanner
{
event NotificacaoScanner onFinalLeitura;
}
// abstract class that implements the interface
public abstract class ScannerGCPerif : IScanner
{
public virtual event NotificacaoScanner onFinalLeitura;
{
add { throw new NotImplementedException("Event not available for this service"); }
remove { throw new NotImplementedException("Event not available for this service"); }
}
}
// concrete class that implements the abstract class
public class ScannerBurroughs : ScannerGCPerif
{
public override event NotificacaoScanner onFinalLeitura;
}
Why when I subscribe the onFinalLeitura event of a ScannerBurroughs instance, it insists on execute the event declaration of the base class (ScannerGCPerif), where the exception is?
I ran your code and I did not get an exception. Let me explain what happens:
You override the event in your concrete class, but you do not provide implementation for adding and removing event handlers so the compiler generates the following code:
public class ScannerBurroughs : ScannerGCPerif
{
private NotificacaoScanner _onFinalLeitura; // Declare a private delegate
public override event NotificacaoScanner onFinalLeitura
{
add { _onFinalLeitura += value; }
remove { _onFinalLeitura -= value; }
}
}
Behind the scenes it adds a private delegate and autoimplements the add / remove event accessors. The base implementation never gets called when you subscribe. Try explicitly implementing the accessors, put some breakpoints in your code and see what happens.

Spring - Qualify injection candidates by designated environment

Edit:
Perhaps a more concise way to ask this question is: Does Spring provide a way for me to resolve ambiguous candidates at injection time by providing my own listener/factory/decision logic?
In fact, arguably the #Environmental qualifier on the member field below is unnecessary: if an #Inject-ion is ambiguous... let me help? In fact, #ResolveWith(EnvironmentalResolver.class) would be alright too..
When Spring attempts to inject a dependency (using annotations) I understand that I need to #Qualifier an #Inject point if I am to have multiple components that implement that interface.
What I'd like to do is something like this:
class MyFoo implements Foo {
#Inject
#Environmental
private Bar bar;
}
#Environmental(Environment.Production)
class ProductionBar implements Bar {
}
#Environmental({Environment.Dev, Environment.Test})
class DevAndTestBar implements Bar {
}
I would expect that I need to create some kind of ambiguity resolver which would look something (vaguely) like this:
class EnvironmentalBeanAmbiguityResolver {
// set from configuration, read as a system environment variable, etc.
private Environment currentEnvironment;
public boolean canResolve(Object beanDefinition) {
// true if definition has the #Environmental annotation on it
}
public Object resolve(Collection<Object> beans) {
for (Object bean : beans) {
// return bean if bean #Environmental.values[] contains currentEnvironment
}
throw new RuntimeException(...);
}
}
One example of where this would be useful is we have a service that contacts end-users. Right now I just have a hacked together AOP aspect that before the method call to the "MailSender', checks for a "Production" environment flag and if it is not set, it sends the email to us instead of the users email. I'd like to instead of wrapping this in an AOP aspect specific to mail sending, instead be able to differentiate services based on the current environment. Sometime's it is just a matter of "production" or "not production" as I've demonstrated above, but a per-environment definition works too.
I think this can be reused for region too... e.g. #Regional and #Regional(Region.UnitedStates) and so on and so forth.
I'd imagine #Environmental would actually be a #Qualifier that way if you wanted to depend directly on something environmental you could (an #Environmental(Production) bean would likely depend directly on an #Environmental(Production) collaborator - so no ambiguity for lower level items --- same a #Regional(US) item would depend on other #Regional(US) items expiclitly and would bypass my yet-to-be-understood BeanAmbiguityResolver)
Thanks.
I think I solved this!
Consider the following:
public interface Ambiguity {
public boolean isSatisfiedBy(BeanDefinitionHolder holder);
}
#Target({ METHOD, CONSTRUCTOR, FIELD })
#Retention(RUNTIME)
public #interface Ambiguous {
Class<? extends Ambiguity> value();
}
#Target(TYPE)
#Retention(RUNTIME)
public #interface Environmental {
public static enum Environment {
Development, Testing, Production
};
Environment[] value() default {};
}
#Named
public class EnvironmentalAmbiguity implements Ambiguity {
/* This can be set via a property in applicationContext.xml, which Spring
can use place holder, environment variable, etc. */
Environment env = Environment.Development;
#Override
public boolean isSatisfiedBy(BeanDefinitionHolder holder) {
BeanDefinition bd = holder.getBeanDefinition();
RootBeanDefinition rbd = (RootBeanDefinition) bd;
Class<?> bc = rbd.getBeanClass();
Environmental env = bc.getAnnotation(Environmental.class);
return (env == null) ? false : hasCorrectValue(env);
}
private boolean hasCorrectValue(Environmental e) {
for (Environment env : e.value()) {
if (env.equals(this.env)) {
return true;
}
}
return false;
}
}
#Named
public class MySuperDuperBeanFactoryPostProcessor implements
BeanFactoryPostProcessor, AutowireCandidateResolver {
private DefaultListableBeanFactory beanFactory;
private AutowireCandidateResolver defaultResolver;
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg)
throws BeansException {
if (arg instanceof DefaultListableBeanFactory) {
beanFactory = (DefaultListableBeanFactory) arg;
defaultResolver = beanFactory.getAutowireCandidateResolver();
beanFactory.setAutowireCandidateResolver(this);
return;
}
throw new FatalBeanException(
"BeanFactory was not a DefaultListableBeanFactory");
}
#Override
public Object getSuggestedValue(DependencyDescriptor descriptor) {
return defaultResolver.getSuggestedValue(descriptor);
}
#Override
public boolean isAutowireCandidate(BeanDefinitionHolder holder,
DependencyDescriptor descriptor) {
Ambiguity ambiguity = getAmbiguity(descriptor);
if (ambiguity == null) {
return defaultResolver.isAutowireCandidate(holder, descriptor);
}
return ambiguity.isSatisfiedBy(holder);
}
private Ambiguity getAmbiguity(DependencyDescriptor descriptor) {
Ambiguous ambiguous = getAmbiguousAnnotation(descriptor);
if (ambiguous == null) {
return null;
}
Class<? extends Ambiguity> ambiguityClass = ambiguous.value();
return beanFactory.getBean(ambiguityClass);
}
private Ambiguous getAmbiguousAnnotation(DependencyDescriptor descriptor) {
Field field = descriptor.getField();
if (field == null) {
MethodParameter methodParameter = descriptor.getMethodParameter();
if (methodParameter == null) {
return null;
}
return methodParameter.getParameterAnnotation(Ambiguous.class);
}
return field.getAnnotation(Ambiguous.class);
}
}
Now if I have an interface MyInterface and two classes that implement it MyFooInterface and MyBarInterface like this:
public interface MyInterface {
public String getMessage();
}
#Named
#Environmental({ Environment.Testing, Environment.Production })
public class MyTestProdInterface implements MyInterface {
#Override
public String getMessage() {
return "I don't always test my code, but when I do, I do it in production!";
}
}
#Named
#Environmental(Environment.Development)
public class DevelopmentMyInterface implements MyInterface {
#Override
public String getMessage() {
return "Developers, developers, developers, developers!";
}
}
If I want to #Inject MyInterface I would get the same multiple bean definition error that one would expect. But I can add #Ambiguous(EnvironmentalAmbiguity.class) and then the EnvironmentalAmbiguity will tell which bean definition it is satisfied by.
Another approach would have been to use a List and go through them all seeing if they are satisfied by a given bean definition, this would mean that the dependnecy wouldn't need the #Ambiguous annotation. That might be more "IoC-ish" but I also thought it might perform poorly. I have not tested that.

Dynamically fire CDI event with qualifier with members

I'm trying to use CDI events in my backend services, on JBoss AS6 - ideally with maximum code reuse.
I can see from the docs I can cut down on the qualifier annotation classes I have to create by using a qualifier with members e.g.
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface Type {
TypeEnum value();
}
I can observe this with
public void onTypeAEvent(#Observes #Type(TypeEnum.TYPEA) String eventMsg) {...}
So far, so good. However, to further cut down on the number of classes needed, I want to have one EventFirer class, where the qualifier of the event thrown is dynamic. Not a problem with qualifiers without members:
public class DynamicEventFirer {
#Inject #Any private Event<String> event;
public void fireEvent(AnnotationLiteral<?> eventQualifier){
event.select(eventQualifier).fire("FIRED");
}
}
then called like
dynamicEventFirer.fireEvent(new AnnotationLiteral<Type>() {});
But what about when the qualifier should have members? Looking at the code for AnnotationLiteral, it's certainly setup for members, and the class element comment has the example:
new PayByQualifier() { public PaymentMethod value() { return CHEQUE; } }
This makes sense to me - you're overriding the value() method of the annotation interface. However, when I tried this myself:
dynamicEventFirer.fireEvent(new AnnotationLiteral<Type>() {
public TypeEnum value() {
return TypeEnum.TYPEA;
}
});
I receive the exception
java.lang.RuntimeException: class uk.co.jam.concept.events.MemberQualifierEventManager$1 does not implement the annotation type with members uk.co.jam.concept.events.Type
at javax.enterprise.util.AnnotationLiteral.getMembers(AnnotationLiteral.java:69)
at javax.enterprise.util.AnnotationLiteral.hashCode(AnnotationLiteral.java:281)
at java.util.HashMap.getEntry(HashMap.java:344)
at java.util.HashMap.containsKey(HashMap.java:335)
at java.util.HashSet.contains(HashSet.java:184)
at org.jboss.weld.util.Beans.mergeInQualifiers(Beans.java:939)
at org.jboss.weld.bean.builtin.FacadeInjectionPoint.<init>(FacadeInjectionPoint.java:29)
at org.jboss.weld.event.EventImpl.selectEvent(EventImpl.java:96)
at org.jboss.weld.event.EventImpl.select(EventImpl.java:80)
at uk.co.jam.concept.events.DynamicEventFirer.fireEvent(DynamicEventFirer.java:20)
Can anyone see what I'm doing wrong? MemberQualifierEventManager is an ApplicationScoped bean which calls on DynamicEventFirer to fire the event.
Thanks,
Ben
There's a slightly cleaner way to do it based on your post:
public class TypeQualifier extends AnnotationLiteral<Type> implements Type{
private TypeEnum type;
public TypeQualifier(TypeEnum t) {
this.type = t;
}
public TypeEnum value() {
return type;
}
}
then just fire like this:
dynamicEventFirer.fireEvent(new TypeQualifier(TypeEnum.TYPEA));
You need to declare an abstract TypeQualifier that extends AnnotationLiteral and implements Type
abstract class TypeQualifier extends AnnotationLiteral<Type> implements Type{}
and use it like this
dynamicEventFirer.fireEvent(new TypeQualifier() {
public TypeEnum value() {
return TypeEnum.TYPEA;
}
});
and later if you want to fire an event with TypeEnum.TYPEB
dynamicEventFirer.fireEvent(new TypeQualifier() {
public TypeEnum value() {
return TypeEnum.TYPEB;
}
});

Can I use inter-type declaration to add a property?

We have domain objects that extend an abstract base class to support a timestamp
abstract class TimestampedObject {
private Date timestamp;
public Date getTimestamp(){return timestamp;}
public void setTimestamp(final Date timestamp){this.timestamp = timestamp;}
}
But this clutters our hierarchy.
Could we use Spring AOP introductions or Aspectj ITDs to achieve this ?
An example right out of the AspectJ in Action book (from memory not tested) would go something like this:
public interface Timestamped {
long getTimestamp();
void setTimestamp();
public static interface Impl extends Timestamped {
public static aspect Implementation {
private long Timestamped.Impl.timestamp;
public long Timestamped.Impl.getTimestamp(){ return timestamp; }
public void Timestamped.Impl.setTimestamp(long in) { timestamp = in; }
}
}
//and then your classes would use it like this:
public class SomeClass implements Timestamped.Impl {
private void someFunc() {
setTimestamp(12);
long t = getTimestamp();
}
}
Not sure if the book had it that way or not but I usually create a separate Impl interface (as shown above) that just extends the main one so that some of my classes can implement timestamping differently without acquiring the ITD implementation. Like so :
public class SomeOtherClass implements Timestamped {
private long myOwnPreciousTimestamp;
public long getTimestamp() {
//Oh! I don't know should I give it to you?!
//I know, I will only give you a half of my timestamp
return myOwnPreciousTimestamp/2;
}
//etc.....
}
Yes, this is exactly what ITDs are for.

Dependencies waiting to be satisifed

I'm trying to abstract some simple tasks for some very simple objects.
In my domain model, there are a number of different objects which basically serve as a way to tag (classify) a "Program." The Business Logic says a program can have as many of these as its wants, but no tags of the same type (e.g., "County") can have the same name, and you can't delete a tag while it has programs linked to it.
This is built on MVC3 with S#arp 2.0.
The domain model has an abstract base class NamedEntity : Entity which defines
public string Name { get; set; }
among other properties.
Specific types extend this class to add whatever makes them unique (if anything), such as Topic, which is a heirarchical structure and so has additional properties for that.
I wanted to create INamedEntityTasks<T> where T: NamedEntity and then have a base version of this for handling routine tasks like bool CheckForDuplicateName(string Name) which would run access its INamedEntityQueries<T> object and call T FindByName(string Name)
If a subclass needed to add more rules prior to delete (e.g. a topic with children can't be deleted), then it just overrides the virtual method from the base class.
Structure:
MyProject.Infrastructure has INamedEntityQueries<T> and NamedEntityQueries<T> as well as ITopicQueries : INamedEntityQueries<Topic> and TopicQueries: NamedEntityQueries<T>, ITopicQueries
MyProject.Domain.Contracts.Tasks has INamedEntityTasks<T> and ITopicTasks : INamedEntityTasks<Topic>
MyProject.Tasks has NamedEntityTasks<T> and TopicTasks: NamedEntityTasks<Topic>, ITopicTasks
My TopicsController won't run because of a missing dependency that I can't figure out.
The exact exception is
Can't create component
'MyProject.web.mvc.controllers.topicscontroller'
as it has dependencies to be
satisfied.
MyProject.web.mvc.controllers.topicscontroller
is waiting for the following
dependencies:
Services:
- MyProject.Infrastructure.Queries.ITopicQueries
which was not registered.
- MyProject.Domain.Contracts.Tasks.ITopicTasks
which was registered but is also
waiting for dependencies.
MyProject.Tasks.TopicTasks is waiting
for the following dependencies:
Services:
- MyProject.Infrastructure.Queries.INamedEntityQueries`1[[MyProject.Domain.Topic,
MyProject.Domain, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null]]
which was not registered.
I checked the container in ComponentRegistrar with a breakpoint and it shows 3 potentially misconfigured:
"MyProject.Tasks.NamedEntityTasks`1" NamedEntityTasks`1
"MyProject.Tasks.TopicTasks" ITopicTasks / TopicTasks
"MyProject.web.mvc.controllers.topicscontroller" TopicsController`TopicsController`
Any help would be appreciated.
You don't need the IFooTasks interface, just use an abstract base class, then IFooBarTasks and IFooBazTasks will be registered with Castle Windsor by the standard ComponentRegistrar in S#arp Architecture:
public abstract class Foo
{
public void Foo1();
public void Foo2();
}
public class FooBar : Foo
{
public void FooBar1();
}
public class FooBaz : Foo
{
public void FooBaz1();
}
public interface IFooTasks
{
void Foo1();
void Foo2();
}
public interface IFooBarTasks : IFooTasks
{
void FooBar1();
}
public interface IFooBazTasks : IFooTasks
{
void FooBaz1();
}
public abstract class FooTasks : IFooTasks
{
public void Foo1()
{
// Foo1 implementation
}
public void Foo2()
{
// Foo2 implementation
}
}
public class FooBarTasks : FooTasks, IFooBarTasks
{
public void FooBar1()
{
// FooBar1 implementation
}
}
public class FooBazTasks : FooTasks, IFooBazTasks
{
public void FooBaz1()
{
// FooBaz1 implementation
}
}

Resources