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