package ch.retorte.intervalmusiccompositor.messagebus;
import static com.google.common.collect.Lists.newArrayList;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.util.List;
import ch.retorte.intervalmusiccompositor.spi.messagebus.MessageHandler;
import ch.retorte.intervalmusiccompositor.spi.messagebus.MessageProducer;
import ch.retorte.intervalmusiccompositor.spi.messagebus.MessageSubscriber;
import com.google.common.collect.Lists;
/**
* The message bus implements the {@link MessageSubscriber} as well as the {@link MessageProducer} and directs sent messages to the right recipients. It is the
* main backbone of message transfer of this software.
*
* @author nw
*/
public class MessageBus implements MessageProducer, MessageSubscriber {
//---- Fields
private LogBuffer logBuffer = new LogBuffer();
private List<MessageHandler<? super Message>> messageHandlers = newArrayList();
private boolean storeMessages;
//---- Constructor
public MessageBus(boolean storeMessages) {
this.storeMessages = storeMessages;
}
@Override
public void send(Message message) {
conditionallyStore(message);
messageHandlers.stream()
.filter(handler -> canHandleMessageType(handler, message))
.forEach(handler -> new Thread(() -> handler.handle(message)).start());
}
private void conditionallyStore(Message message) {
if (storeMessages && message instanceof StringMessage) {
LocalDateTime date = null;
String caller = null;
if (message instanceof DebugMessage) {
date = ((DebugMessage) message).getDate();
caller = ((DebugMessage) message).getCallerClassName();
}
store(date, caller, ((StringMessage) message).getMessage());
}
}
private void store(LocalDateTime date, String caller, String message) {
logBuffer.append(date, caller, message);
}
private boolean canHandleMessageType(MessageHandler<? super Message> handler, Message message) {
for (Type t : getGenericTypes(handler)) {
if (((Class<?>) t).isAssignableFrom(message.getClass())) {
return true;
}
}
return false;
}
private List<Type> getGenericTypes(MessageHandler<? super Message> handler) {
Type[] genericInterfaces = handler.getClass().getGenericInterfaces();
if (genericInterfaces.length == 0) {
return Lists.newArrayList();
}
ParameterizedType firstGenericInterface = (ParameterizedType) genericInterfaces[0];
return Lists.newArrayList(firstGenericInterface.getActualTypeArguments());
}
public LogBuffer getLogBuffer() {
return logBuffer;
}
@Override
@SuppressWarnings("unchecked")
public void addHandler(MessageHandler<? extends Message> messageHandler) {
messageHandlers.add((MessageHandler<? super Message>) messageHandler);
}
}