package mightypork.utils.patterns.subscription; import java.util.HashSet; import java.util.Set; /** * Message subsystem (broadcaster with clients) to which clients can subscribe.
* If more than one type of message is needed, {@link MessageBus} is a better * choice. * * @author MightyPork * @param message type * @param client (subscriber) type */ public final class MessageChannel, CLIENT> implements Subscribable { private Set clients = new HashSet(); private Class clientClass; private Class messageClass; public MessageChannel(Class messageClass, Class clientClass) { if(messageClass == null || clientClass == null) throw new IllegalArgumentException("Null Message or Client class."); this.clientClass = clientClass; this.messageClass = messageClass; } @Override public boolean addSubscriber(Object client) { if (!canSubscribe(client)) return false; clients.add(clientClass.cast(client)); return true; } @Override public void removeSubscriber(Object client) { clients.remove(client); } /** * Try to broadcast a message.
* If message is of wrong type, false is returned. * * @param message a message to send * @return true if message was sent */ public boolean broadcast(Object message) { if (!canBroadcast(message)) return false; MESSAGE evt = messageClass.cast(message); for (CLIENT client : clients) { sendTo(client, evt); } return true; } /** * Send a message to a client * * @param client target client * @param message message to send */ private void sendTo(CLIENT client, MESSAGE message) { ((Handleable) message).handleBy(client); } /** * Check if the given message can be broadcasted by this * {@link MessageChannel} * * @param maybeMessage event object * @return can be broadcasted */ private boolean canBroadcast(Object maybeMessage) { return messageClass.isInstance(maybeMessage); } /** * Check if a client can subscribe to this {@link MessageChannel} * * @param maybeClient client asking for subscription * @return can subscribe */ public boolean canSubscribe(Object maybeClient) { return clientClass.isInstance(maybeClient); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + clientClass.getName().hashCode(); result = prime * result + messageClass.getName().hashCode(); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof MessageChannel)) return false; MessageChannel other = (MessageChannel) obj; if (!clientClass.getName().equals(other.clientClass.getName())) return false; if (!messageClass.getName().equals(other.messageClass.getName())) return false; return true; } @Override public String toString() { return "CHANNEL( "+messageClass.getSimpleName()+" -> "+clientClass.getSimpleName()+" )"; } /** * Create an instance for given types * * @param messageClass event class * @param clientClass client class * @return the broadcaster */ public static , F_CLIENT> MessageChannel create(Class messageClass, Class clientClass) { return new MessageChannel(messageClass, clientClass); } }