All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy