com.jdon.async.EventMessageFirer Maven / Gradle / Ivy
/*
* Copyright 2003-2009 the original author or authors.
* Licensed 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 com.jdon.async;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInvocation;
import com.jdon.annotation.model.Receiver;
import com.jdon.annotation.model.Send;
import com.jdon.async.disruptor.DisruptorFactory;
import com.jdon.async.disruptor.DisruptorForCommandFactory;
import com.jdon.async.disruptor.EventDisruptor;
import com.jdon.async.future.EventResultFuture;
import com.jdon.async.future.FutureDirector;
import com.jdon.async.future.FutureListener;
import com.jdon.container.pico.Startable;
import com.jdon.controller.model.ModelUtil;
import com.jdon.domain.message.Command;
import com.jdon.domain.message.DomainMessage;
import com.jdon.domain.message.consumer.ModelConsumerMethodHolder;
import com.jdon.domain.model.injection.ModelProxyInjection;
import com.jdon.util.Debug;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
public class EventMessageFirer implements Startable {
public final static String module = EventMessageFirer.class.getName();
private DisruptorFactory disruptorFactory;
private DisruptorForCommandFactory disruptorForCommandFactory;
private FutureDirector futureDirector;
private ModelProxyInjection modelProxyInjection;
public EventMessageFirer(DisruptorFactory disruptorFactory, DisruptorForCommandFactory disruptorForCommandFactory, FutureDirector futureDirector,
ModelProxyInjection modelProxyInjection) {
super();
this.disruptorFactory = disruptorFactory;
this.disruptorForCommandFactory = disruptorForCommandFactory;
this.futureDirector = futureDirector;
this.modelProxyInjection = modelProxyInjection;
}
public void start() {
}
public void stop() {
if (futureDirector != null) {
futureDirector.stop();
futureDirector = null;
}
}
public void fire(DomainMessage domainMessage, Send send, FutureListener futureListener) {
EventResultFuture eventMessageFuture = new EventResultFuture(send.value(), futureListener, domainMessage);
eventMessageFuture.setAsyn(send.asyn());
domainMessage.setEventResultHandler(eventMessageFuture);
futureDirector.fire(domainMessage);
}
public void fire(DomainMessage domainMessage, Send send) {
String topic = send.value();
if (disruptorForCommandFactory.isContain(topic)) {
return;
}
if (!disruptorFactory.isContain(topic)) {
Debug.logError(" no found any consumer annonated with @Consumer or its methods with @OnEvent for topic=" + topic, module);
return;
}
try {
Disruptor disruptor = disruptorFactory.getDisruptor(topic);
if (disruptor == null) {
Debug.logWarning("not create disruptor for " + topic, module);
return;
}
RingBuffer ringBuffer = disruptor.getRingBuffer();
long sequence = ringBuffer.next();
EventDisruptor eventDisruptor = (EventDisruptor) ringBuffer.get(sequence);
if (eventDisruptor == null)
return;
eventDisruptor.setTopic(topic);
eventDisruptor.setDomainMessage(domainMessage);
ringBuffer.publish(sequence);
} catch (Exception e) {
Debug.logError("fire error: " + e.getMessage() + " for" + send.value() + " from:" + domainMessage.getEventSource() + " ", module);
} finally {
}
}
public void fireToModel(DomainMessage domainMessage, Send send, MethodInvocation invocation) {
String topic = send.value();
if (disruptorFactory.isContain(topic))
return;
ModelConsumerMethodHolder modelConsumerMethodHolder = disruptorForCommandFactory.getModelConsumerMethodHolder(topic);
if (modelConsumerMethodHolder == null) {
Debug.logError(" no found any consumer annonated with @OnCommand for topic=" + topic, module);
return;
}
Object[] arguments = invocation.getArguments();
if (arguments.length == 0) {
Debug.logError("there is no a destination parameter(@Receiver) in this method:" + invocation.getMethod().getName() + topic, module);
return;
}
Object model = fetchCommandReceiver(invocation.getMethod(), arguments);
if (model == null || !ModelUtil.isModel(model)) {
Debug.logError(" there is no a destination parameter(@Receiver) in this method:" + invocation.getMethod().getName()
+ " or the destination class not annotated with @Model", module);
return;
}
//
modelProxyInjection.injectProperties(model);
// target model is the owner of the disruptor, single thread to modify
// aggregate root model's state.
((Command) domainMessage).setDestination(model);
Disruptor disruptor = disruptorForCommandFactory.getDisruptor(topic);
if (disruptor == null) {
Debug.logWarning("not create command disruptor for " + topic, module);
return;
}
try {
RingBuffer ringBuffer = disruptor.getRingBuffer();
long sequence = ringBuffer.next();
EventDisruptor eventDisruptor = (EventDisruptor) ringBuffer.get(sequence);
if (eventDisruptor == null)
return;
eventDisruptor.setTopic(topic);
eventDisruptor.setDomainMessage(domainMessage);
ringBuffer.publish(sequence);
} catch (Exception e) {
Debug.logError("fireToModel error: " + send.value() + " domainMessage:" + domainMessage.getEventSource() + " mode:"
+ arguments[0].getClass().getName(), module);
} finally {
}
}
private Object fetchCommandReceiver(Method method, Object[] arguments) {
int i = 0;
Annotation[][] paramAnnotations = method.getParameterAnnotations();
for (Annotation[] anns : paramAnnotations) {
Object parameter = arguments[i++];
for (Annotation annotation : anns) {
if (annotation instanceof Receiver) {
return parameter;
}
}
}
return null;
}
}