Package marauroa.common.net

Source Code of marauroa.common.net.MessageFactory

/* $Id: MessageFactory.java,v 1.48 2010/11/26 20:05:17 martinfuchs Exp $ */
/***************************************************************************
*                      (C) Copyright 2003 - Marauroa                      *
***************************************************************************
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/
package marauroa.common.net;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Map;

import marauroa.common.Log4J;
import marauroa.common.Utility;
import marauroa.common.game.Attributes;
import marauroa.common.net.message.Message;
import marauroa.common.net.message.MessageC2SAction;
import marauroa.common.net.message.MessageC2SChooseCharacter;
import marauroa.common.net.message.MessageC2SCreateAccount;
import marauroa.common.net.message.MessageC2SCreateCharacter;
import marauroa.common.net.message.MessageC2SKeepAlive;
import marauroa.common.net.message.MessageC2SLoginRequestKey;
import marauroa.common.net.message.MessageC2SLoginSendNonceNameAndPassword;
import marauroa.common.net.message.MessageC2SLoginSendNonceNamePasswordAndSeed;
import marauroa.common.net.message.MessageC2SLoginSendPromise;
import marauroa.common.net.message.MessageC2SLogout;
import marauroa.common.net.message.MessageC2SOutOfSync;
import marauroa.common.net.message.MessageC2STransferACK;
import marauroa.common.net.message.MessageP2SCreateAccount;
import marauroa.common.net.message.MessageP2SCreateCharacter;
import marauroa.common.net.message.MessageS2CCharacterList;
import marauroa.common.net.message.MessageS2CChooseCharacterACK;
import marauroa.common.net.message.MessageS2CChooseCharacterNACK;
import marauroa.common.net.message.MessageS2CConnectNACK;
import marauroa.common.net.message.MessageS2CCreateAccountACK;
import marauroa.common.net.message.MessageS2CCreateAccountNACK;
import marauroa.common.net.message.MessageS2CCreateCharacterACK;
import marauroa.common.net.message.MessageS2CCreateCharacterNACK;
import marauroa.common.net.message.MessageS2CInvalidMessage;
import marauroa.common.net.message.MessageS2CLoginACK;
import marauroa.common.net.message.MessageS2CLoginMessageNACK;
import marauroa.common.net.message.MessageS2CLoginNACK;
import marauroa.common.net.message.MessageS2CLoginSendKey;
import marauroa.common.net.message.MessageS2CLoginSendNonce;
import marauroa.common.net.message.MessageS2CLogoutACK;
import marauroa.common.net.message.MessageS2CLogoutNACK;
import marauroa.common.net.message.MessageS2CPerception;
import marauroa.common.net.message.MessageS2CServerInfo;
import marauroa.common.net.message.MessageS2CTransfer;
import marauroa.common.net.message.MessageS2CTransferREQ;

/**
* MessageFactory is the class that is in charge of building the messages from
* the stream of bytes.
*
* MessageFactory follows the singleton pattern.
*
*/
public class MessageFactory {

  /** the logger instance. */
  private static final marauroa.common.Logger logger = Log4J.getLogger(Attributes.class);

  /** A factory to create messages instance from an integer code. */
  private static Map<Integer, Class<?>> factoryArray;

  /**
   * Singleton instance
   */
  private static MessageFactory messageFactory;

  /**
   * Constructor
   *
   */
  private MessageFactory() {
    register();
  }

  /**
   * This method returns an instance of MessageFactory
   *
   * @return A shared instance of MessageFactory
   */
  public static MessageFactory getFactory() {
    if (messageFactory == null) {
      factoryArray = new HashMap<Integer, Class<?>>();
      messageFactory = new MessageFactory();
    }
    return messageFactory;
  }

  /**
   * Register messages with its code.
   *
   */
  private void register() {
    register(Message.MessageType.C2S_ACTION, MessageC2SAction.class);
    register(Message.MessageType.C2S_CHOOSECHARACTER, MessageC2SChooseCharacter.class);
    register(Message.MessageType.C2S_LOGOUT, MessageC2SLogout.class);
    register(Message.MessageType.S2C_CHARACTERLIST, MessageS2CCharacterList.class);
    register(Message.MessageType.S2C_CHOOSECHARACTER_ACK, MessageS2CChooseCharacterACK.class);
    register(Message.MessageType.S2C_CHOOSECHARACTER_NACK, MessageS2CChooseCharacterNACK.class);
    register(Message.MessageType.S2C_LOGIN_ACK, MessageS2CLoginACK.class);
    register(Message.MessageType.S2C_LOGIN_NACK, MessageS2CLoginNACK.class);
    register(Message.MessageType.S2C_LOGOUT_ACK, MessageS2CLogoutACK.class);
    register(Message.MessageType.S2C_LOGOUT_NACK, MessageS2CLogoutNACK.class);
    register(Message.MessageType.S2C_PERCEPTION, MessageS2CPerception.class);
    register(Message.MessageType.C2S_OUTOFSYNC, MessageC2SOutOfSync.class);
    register(Message.MessageType.C2S_KEEPALIVE, MessageC2SKeepAlive.class);
    register(Message.MessageType.S2C_SERVERINFO, MessageS2CServerInfo.class);
    register(Message.MessageType.S2C_INVALIDMESSAGE, MessageS2CInvalidMessage.class);
    register(Message.MessageType.S2C_TRANSFER_REQ, MessageS2CTransferREQ.class);
    register(Message.MessageType.C2S_TRANSFER_ACK, MessageC2STransferACK.class);
    register(Message.MessageType.S2C_TRANSFER, MessageS2CTransfer.class);
    register(Message.MessageType.C2S_LOGIN_REQUESTKEY, MessageC2SLoginRequestKey.class);
    register(Message.MessageType.C2S_LOGIN_SENDNONCENAMEANDPASSWORD,
            MessageC2SLoginSendNonceNameAndPassword.class);
    register(Message.MessageType.S2C_LOGIN_SENDKEY, MessageS2CLoginSendKey.class);
    register(Message.MessageType.S2C_LOGIN_SENDNONCE, MessageS2CLoginSendNonce.class);
    register(Message.MessageType.C2S_LOGIN_SENDPROMISE, MessageC2SLoginSendPromise.class);
    register(Message.MessageType.C2S_CREATEACCOUNT, MessageC2SCreateAccount.class);
    register(Message.MessageType.S2C_CREATEACCOUNT_ACK, MessageS2CCreateAccountACK.class);
    register(Message.MessageType.S2C_CREATEACCOUNT_NACK, MessageS2CCreateAccountNACK.class);
    register(Message.MessageType.C2S_CREATECHARACTER, MessageC2SCreateCharacter.class);
    register(Message.MessageType.S2C_CREATECHARACTER_ACK, MessageS2CCreateCharacterACK.class);
    register(Message.MessageType.S2C_CREATECHARACTER_NACK, MessageS2CCreateCharacterNACK.class);
    register(Message.MessageType.S2C_CONNECT_NACK, MessageS2CConnectNACK.class);
    register(Message.MessageType.C2S_LOGIN_SENDNONCENAMEPASSWORDANDSEED,
        MessageC2SLoginSendNonceNamePasswordAndSeed.class);
    register(Message.MessageType.S2C_LOGIN_MESSAGE_NACK, MessageS2CLoginMessageNACK.class);
    register(Message.MessageType.P2S_CREATECHARACTER, MessageP2SCreateCharacter.class);
    register(Message.MessageType.P2S_CREATEACCOUNT, MessageP2SCreateAccount.class);
  }

  /**
   * Adds a new message class to the factory and link it with a code.
   * @param index the code to use.
   * @param messageClass the class of the message to add.
   */
  private void register(Message.MessageType index, Class<?> messageClass) {
    factoryArray.put(index.ordinal(), messageClass);
  }

  /**
   * Returns a object of the right class from a stream of serialized data.
   *
   * @param data
   *            the serialized data
   * @param channel
   *            the source of the message needed to build the object.
   * @return a message of the right class
   * @throws IOException
   *             in case of problems with the message
   * @throws InvalidVersionException
   *             if the message version doesn't match
   */
  public Message getMessage(byte[] data, SocketChannel channel) throws IOException,
          InvalidVersionException {
    return getMessage(data, channel, 0);
  }

  /**
   * Returns a object of the right class from a stream of serialized data.
   *
   * @param data
   *            the serialized data
   * @param channel
   *            the source of the message needed to build the object.
   * @param offset
   *            where to start reading in the data-array.
   * @return a message of the right class
   * @throws IOException
   *             in case of problems with the message
   * @throws InvalidVersionException
   *             if the message version doesn't match
   */
  public Message getMessage(byte[] data, SocketChannel channel, int offset) throws IOException,
          InvalidVersionException {
    /*
     * Check the version of the network protocol.
     */
    int networkProtocolVersion = data[offset];
    if (networkProtocolVersion < NetConst.NETWORK_PROTOCOL_VERSION_MIN
        || networkProtocolVersion > NetConst.NETWORK_PROTOCOL_VERSION_MAX) {
      logger.error("Message has incorrect protocol version (" + networkProtocolVersion + ") expected (" + NetConst.NETWORK_PROTOCOL_VERSION_MIN + " < x < " + NetConst.NETWORK_PROTOCOL_VERSION_MAX + ")");
      logger.error("Message is: " + Utility.dumpByteArray(data));
      throw new InvalidVersionException(data[offset]);
    }


    int messageTypeIndex = data[offset + 1];
    /*
     * Now we check if we have this message class implemented.
     */
    if (factoryArray.containsKey(messageTypeIndex)) {
      Message tmp = null;
      try {
        Class<?> messageType = factoryArray.get(messageTypeIndex);
        tmp = (Message) messageType.newInstance();
        tmp.setProtocolVersion(networkProtocolVersion);
        ByteArrayInputStream in = new ByteArrayInputStream(data);
        if (offset > 0) {
          in.skip(offset);
        }
        InputSerializer s = new InputSerializer(in);
        s.setProtocolVersion(networkProtocolVersion);

        tmp.readObject(s);
        tmp.setSocketChannel(channel);
        s.close();
        return tmp;
      } catch (Exception e) {
        logger.error("error in getMessage", e);
        throw new IOException(e.getMessage());
      }
    } else {
      logger.warn("Message type [" + messageTypeIndex + "] is not registered in the MessageFactory");
      throw new IOException("Message type [" + messageTypeIndex + "] is not registered in the MessageFactory");
    }
  }
}
TOP

Related Classes of marauroa.common.net.MessageFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.