Package be.demmel.jgws

Source Code of be.demmel.jgws.LoginServer

package be.demmel.jgws;

import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.io.File;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.JAXBIntrospector;
import javax.xml.bind.Unmarshaller;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import be.demmel.jgws.cfg.jaxb.Binding;
import be.demmel.jgws.cfg.jaxb.Configuration;
import be.demmel.jgws.cfg.jaxb.Jpa;
import be.demmel.jgws.cfg.jaxb.LogBlackList;
import be.demmel.jgws.network.InboundPacketHandler;
import be.demmel.jgws.network.NettyServer;
import be.demmel.jgws.packets.Packet;
import be.demmel.jgws.packets.handlers.PacketHandler;
import be.demmel.jgws.packets.handlers.tools.EntityManagerFactoryTool;
import be.demmel.jgws.packets.serialization.PacketDeserializer;
import be.demmel.jgws.packets.serialization.PacketSerializer;
import be.demmel.jgws.rmi.GameServer;
import be.demmel.jgws.rmi.LoginServerPortal;
import be.demmel.jgws.rmi.LoginServerPortalImpl;
import be.demmel.jgws.rmi.RmiRegistry;
import be.demmel.jgws.utils.GeneralUtils;

// TODO; test coverage plugin
public class LoginServer {

  private static final Logger LOGGER = LoggerFactory.getLogger(LoginServer.class);
  private static final List<GameServer> availableGameServers = new ArrayList<>();
 
  public static void main(String... parameters) {
    Thread.currentThread().setName("Startup");
    LOGGER.info("The \"Java Guild Wars (Login)Server\" (version {}) is starting", Version.getVersion());

    try {
      Configuration loginServerConfiguration = getLoginServerConfiguration();

      // Retrieve the PacketDeserializers for every outgoing (login) packet
      Map<Integer, PacketDeserializer> packetDeserializers = GeneralUtils.getPacketDeserializers("be.demmel.jgws.packets.loginserver.inbound");
      // Retrieve the PacketSerializer for every incoming (login) packet
      Map<Class<? extends Packet>, PacketSerializer> packetSerializers = GeneralUtils.getPacketSerializers("be.demmel.jgws.packets.loginserver.outbound");

      // Retrieve the PacketHandlers for every incoming (login) packet
      Map<Class<? extends Packet>, PacketHandler> packetHandlers = GeneralUtils.getPacketHandlers("be.demmel.jgws.packets.handlers.login");

      Jpa jpaConfiguration = loginServerConfiguration.getJpa();

      Map<String, String> properties = new HashMap<>();
      properties.put("javax.persistence.jdbc.driver", jpaConfiguration.getDriver());
      properties.put("javax.persistence.jdbc.url", jpaConfiguration.getUrl());
      properties.put("javax.persistence.jdbc.user", jpaConfiguration.getUser());
      properties.put("javax.persistence.jdbc.password", jpaConfiguration.getPassword());

      final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("jgws", properties);
     
      EntityManagerFactoryTool.setEntityManagerFactory(entityManagerFactory);

      Binding bindingConfiguration = loginServerConfiguration.getBinding();
      String bindingIp = bindingConfiguration.getIp();
      int bindingPort = bindingConfiguration.getPort();
     
      ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
     
      final InboundPacketHandler<LoginServerSession> inboundPacketHandler = new InboundPacketHandler<LoginServerSession>(channels, packetHandlers, SessionKey.SESSSION_KEY);
     
      LogBlackList logBlackList = loginServerConfiguration.getLogBlackList();
      if(loginServerConfiguration.getLogBlackList() != null) { // don't log some inbound and outbound packets
        Set<Class<? extends Packet>> inboundPacketsLogBlackList = new HashSet<Class<? extends Packet>>(), outboundPacketsLogBlackList = new HashSet<Class<? extends Packet>>();
       
        for(String packet : logBlackList.getInbound().getPacket()) {
          inboundPacketsLogBlackList.add( (Class<? extends Packet>)Class.forName(packet));
        }
       
        for(String packet : logBlackList.getOutbound().getPacket()) {
          outboundPacketsLogBlackList.add( (Class<? extends Packet>)Class.forName(packet));
        }
       
        LoginServerChannelInitializer defaultChannelInitializer = new LoginServerChannelInitializer(packetDeserializers, inboundPacketHandler, packetSerializers, SessionKey.SESSSION_KEY, inboundPacketsLogBlackList, outboundPacketsLogBlackList);
       
        Thread serverThread = new Thread(new NettyServer<LoginServerSession>(new InetSocketAddress(bindingIp, bindingPort), defaultChannelInitializer));
        serverThread.start();
      } else {
        LoginServerChannelInitializer defaultChannelInitializer = new LoginServerChannelInitializer(packetDeserializers, inboundPacketHandler, packetSerializers, SessionKey.SESSSION_KEY);
       
        Thread serverThread = new Thread(new NettyServer<LoginServerSession>(new InetSocketAddress(bindingIp, bindingPort), defaultChannelInitializer));
        serverThread.start();
      }

      // Start the RMI server
      String portalUri = loginServerConfiguration.getPortalUri();
      URI serviceRmiUri = new URI(portalUri);
      RmiRegistry.INSTANCE.start(serviceRmiUri);
      LoginServerPortal gameServerPortal = new LoginServerPortalImpl();
      RmiRegistry.INSTANCE.bind(gameServerPortal);
      LOGGER.info("Login Server Commands RMI service ready");

      // The startup process went well. Log the event and keep the main thread alive
      LOGGER.info("The \"Java Guild Wars (Login)Server\" started");

      for (;;) {
        Thread.sleep(Long.MAX_VALUE);
      }
    } catch (Throwable throwable) {
      LOGGER.error("Initializing the \"Java Guild Wars (Login)Server\" failed because: ", throwable);
    }
  }

  // TODO: provide what's needed to remove gameservers
  public static void addGameServer(GameServer gameServer) {
    LOGGER.info("Adding Game Server: {}", gameServer);
    availableGameServers.add(gameServer);
  }

  public static GameServer getBestGameServer() {
    // FIXME: selection should be based on utilization of all the GameServer instances
    // How do I define that at the GS side? and how do I transfer that here? Ping each GS for stats every XXX ms ? to avoid
    // over-utilization, do I add a max additions thresholds "before new check" ?
    synchronized (availableGameServers) {
      if (availableGameServers.isEmpty()) {
        return null;
      } else {
        return availableGameServers.get(0);
      }
    }
  }

  // TODO: generic code in the core!
  private static <T> T validateAndUnmarshal(Class<T> docClass, File xmlFile, String schemaLocation) throws JAXBException, SAXException {
    String packageName = docClass.getPackage().getName();
    JAXBContext jc = JAXBContext.newInstance(packageName);
    Unmarshaller u = jc.createUnmarshaller();

    SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    URL url = LoginServer.class.getResource(schemaLocation);
    Schema mySchema = sf.newSchema(url);

    u.setSchema(mySchema);
    return (T) JAXBIntrospector.getValue(u.unmarshal(xmlFile));
  }

  private static Configuration getLoginServerConfiguration() throws JAXBException, SAXException {
    try {
      String configurationFileLocation = System.getProperty("configurationFile");

      if (configurationFileLocation == null) {
        LOGGER.error("The \"configurationFile\" system property must be set");
        throw new RuntimeException("The \"configurationFile\" system property must be set");
      }

      File configurationFile = new File(configurationFileLocation);
      if (!configurationFile.exists()) {
        LOGGER.error("The given \"configurationFile\" system property point to a non-existing file");
        throw new RuntimeException("The given \"configurationFile\" system property points to a non-existing file");
      }
      return validateAndUnmarshal(Configuration.class, configurationFile, "/loginserverConfiguration.xsd");
    } catch (Throwable t) {
      throw t;
    }
  }
}
TOP

Related Classes of be.demmel.jgws.LoginServer

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.