/* * Copyright (C) 2011 Rhegium Team * * 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 org.rhegium.internal.network.protocol; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.jboss.netty.buffer.ChannelBufferInputStream; import org.rhegium.api.network.Message; import org.rhegium.api.network.MessageHandler; import org.rhegium.api.network.MessageListener; import org.rhegium.api.network.MessageType; import org.rhegium.api.network.MessageTypeHandler; import org.rhegium.api.network.MessageTypeService; import org.rhegium.api.network.ProtocolConfigurationException; import org.rhegium.api.network.protocol.FailureMessage; import org.rhegium.api.network.protocol.ProtocolMessageTypeHandler; import org.rhegium.api.network.socket.SendingClient; import com.google.inject.Inject; public class DefaultProtocolMessageTypeHandler implements ProtocolMessageTypeHandler { private final Map<MessageType, MessageTypeDefinition<?>> messageTypeDefinitions; private final Set<MessageListener> listeners = new HashSet<MessageListener>(); @Inject private MessageTypeService messageTypeService; public DefaultProtocolMessageTypeHandler() { messageTypeDefinitions = new HashMap<MessageType, MessageTypeDefinition<?>>(); } @Override @SuppressWarnings("unchecked") public <M extends Message> void registerMessageHandler(Class<M> messageClass) { if (messageClass == null) { throw new ProtocolConfigurationException("messageClass cannot be null"); } if (!messageClass.isAnnotationPresent(MessageTypeHandler.class)) { throw new ProtocolConfigurationException( "You cannot register messageType not annotated with MessageTypeHandler"); } try { MessageTypeHandler typeHandler = messageClass.getAnnotation(MessageTypeHandler.class); registerMessageHandler(messageClass, (MessageHandler<M>) typeHandler.value().newInstance()); } catch (Exception e) { throw new ProtocolConfigurationException("You cannot register messageClass", e); } } @Override public <M extends Message> void registerMessageHandler(Class<M> messageClass, MessageHandler<M> messageHandler) { if (messageClass == null) { throw new ProtocolConfigurationException("messageClass cannot be null"); } if (messageHandler == null) { throw new ProtocolConfigurationException("messageHandler cannot be null"); } try { Message message = messageClass.newInstance(); MessageType messageType = message.getMessageType(); messageTypeDefinitions.put(messageType, new MessageTypeDefinition<M>(messageType, messageClass, messageHandler)); } catch (Exception e) { throw new ProtocolConfigurationException("You cannot register messageClass " + messageClass, e); } } @Override public Message handlePacket(ChannelBufferInputStream stream) throws Exception { final long messageTypeId = stream.readLong(); final MessageType messageType = messageTypeService.findByMessageTypeId(messageTypeId); if (messageType == null) { throw new ProtocolConfigurationException("MessageType with id " + messageTypeId + " is not registered"); } MessageTypeDefinition<?> definition = messageTypeDefinitions.get(messageType); try { return definition.getMessageClass().newInstance(); } catch (Exception e) { // Just log the problem but do not throw it new ProtocolConfigurationException("Message class could not be instantiated", e).printStackTrace(); } return null; } @Override public void handleMessage(Message message, SendingClient client) throws Exception { MessageType messageType = message.getMessageType(); MessageTypeDefinition<?> definition = messageTypeDefinitions.get(messageType); if (definition == null) { // FailureMessage has totally different handling if (message instanceof FailureMessage) { return; } throw new ProtocolConfigurationException("No MessageHandler registered for MessageType " + messageType); } if (!definition.getMessageType().equals(messageType)) { throw new ProtocolConfigurationException("MessageHandlers do not equal"); } if (!definition.getMessageClass().equals(message.getClass())) { throw new ProtocolConfigurationException("MessageHandler MessageType " + messageType + " cannot handle messages of type " + message.getClass()); } processMessage(message, client, definition); for (MessageListener messageListener : getMessageListeners()) { messageListener.messageReceived(message.getMessageType(), message, client); } } @Override public void addMessageListener(MessageListener listener) { listeners.add(listener); } @Override public void removeMessageListener(MessageListener listener) { listeners.remove(listener); } @Override public Collection<MessageListener> getMessageListeners() { return Collections.unmodifiableCollection(listeners); } @SuppressWarnings("unchecked") private <M extends Message> void processMessage(M message, SendingClient client, MessageTypeDefinition<?> definition) throws Exception { MessageHandler<M> messageHandler = (MessageHandler<M>) definition.getMessageHandler(); messageHandler.handleMessage(message, client); } private class MessageTypeDefinition<M extends Message> { private final MessageType messageType; private final Class<M> messageClass; private final MessageHandler<M> messageHandler; public MessageTypeDefinition(MessageType messageType, Class<M> messageClass, MessageHandler<M> messageHandler) { this.messageType = messageType; this.messageClass = messageClass; this.messageHandler = messageHandler; } public MessageType getMessageType() { return messageType; } public Class<M> getMessageClass() { return messageClass; } public MessageHandler<M> getMessageHandler() { return messageHandler; } } }