/******************************************************************************* * Copyright 2015 Klaus Pfeiffer - klaus@allpiper.com * * 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 com.jfastnet; import com.jfastnet.events.EventLog; import com.jfastnet.idprovider.IIdProvider; import com.jfastnet.messages.MessagePart; import com.jfastnet.processors.IMessageReceiverPostProcessor; import com.jfastnet.processors.IMessageReceiverPreProcessor; import com.jfastnet.processors.IMessageSenderPostProcessor; import com.jfastnet.processors.IMessageSenderPreProcessor; import com.jfastnet.state.ClientStates; import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; import lombok.extern.slf4j.Slf4j; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.*; /** @author Klaus Pfeiffer - klaus@allpiper.com */ @Slf4j @Getter @Accessors(chain = true) public class State { /** UDP peer system to use. (e.g. KryoNetty) */ private IPeer udpPeer; /** Provides the message ids. */ public IIdProvider idProvider; /** Are we the host? Server sets this to true on creation. */ @Setter private boolean isHost; /** The server holds track of its clients. */ private final ClientStates clientStates; /** Client will only receive messages, if connected. */ public volatile boolean connected = false; public volatile boolean connectionFailed = false; private final EventLog eventLog; /** Stacked messages can be temporarily disabled. e.g. if the packet size * of the stacked messages is too big. */ @Setter private boolean enableStackedMessages = true; /** Used for receiving bigger messages. Only one byte array buffer may * be processed at any given time. */ private SortedMap<Long, SortedMap<Integer, MessagePart>> byteArrayBufferMap = new TreeMap<>(); /** Map of all added processors. */ private final Map<Class, Object> processorMap = new HashMap<>(); /** List of systems that need to be processed every tick. */ private final List<ISimpleProcessable> processables = new ArrayList<>(); private final List<IMessageSenderPreProcessor> messageSenderPreProcessors = new ArrayList<>(); private final List<IMessageSenderPostProcessor> messageSenderPostProcessors = new ArrayList<>(); private final List<IMessageReceiverPreProcessor> messageReceiverPreProcessors = new ArrayList<>(); private final List<IMessageReceiverPostProcessor> messageReceiverPostProcessors = new ArrayList<>(); @Getter private Config config; public State(Config config) { this.config = config; this.eventLog = new EventLog(config, this); createIdProvider(config); createUdpPeer(config); createProcessors(config); clientStates = new ClientStates(config); } private void createIdProvider(Config config) { try { Constructor[] constructors = config.idProviderClass.getConstructors(); // Search full-blown constructor for (Constructor constructor : constructors) { Class[] parameterTypes = constructor.getParameterTypes(); if (parameterTypes.length == 2 && parameterTypes[0] == Config.class && parameterTypes[1] == State.class) { idProvider = (IIdProvider) constructor.newInstance(config, this); } } if (idProvider == null) { // Try default constructor idProvider = config.idProviderClass.newInstance(); } } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { log.error("Couldn't create id provider {}", config.udpPeerClass, e); } } private void createUdpPeer(Config config) { try { Constructor[] constructors = config.udpPeerClass.getConstructors(); // Search full-blown constructor for (Constructor constructor : constructors) { Class[] parameterTypes = constructor.getParameterTypes(); if (parameterTypes.length == 2 && parameterTypes[0] == Config.class && parameterTypes[1] == State.class) { udpPeer = (IPeer) constructor.newInstance(config, this); } } if (udpPeer == null) { // Try default constructor udpPeer = config.udpPeerClass.newInstance(); } } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { log.error("Couldn't create udp peer {}", config.udpPeerClass, e); } } private void createProcessors(Config config) { config.processorClasses.forEach(processorClass -> { try { Constructor[] constructors = processorClass.getConstructors(); // Search full-blown constructor for (Constructor constructor : constructors) { Class[] parameterTypes = constructor.getParameterTypes(); if (parameterTypes.length == 2 && parameterTypes[0] == Config.class && parameterTypes[1] == State.class) { addProcessor(constructor.newInstance(config, this)); return; } } // Try default constructor addProcessor(processorClass.newInstance()); } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { log.error("Couldn't create processor object {}", processorClass, e); } }); } public void addProcessor(Object processor) { processorMap.put(processor.getClass(), processor); if (processor instanceof ISimpleProcessable) { ISimpleProcessable processable = (ISimpleProcessable) processor; processables.add(processable); } if (processor instanceof IMessageSenderPreProcessor) { IMessageSenderPreProcessor messageSenderPreProcessor = (IMessageSenderPreProcessor) processor; messageSenderPreProcessors.add(messageSenderPreProcessor); } if (processor instanceof IMessageSenderPostProcessor) { IMessageSenderPostProcessor messageSenderPostProcessor = (IMessageSenderPostProcessor) processor; messageSenderPostProcessors.add(messageSenderPostProcessor); } if (processor instanceof IMessageReceiverPreProcessor) { IMessageReceiverPreProcessor messageReceiverPreProcessor = (IMessageReceiverPreProcessor) processor; messageReceiverPreProcessors.add(messageReceiverPreProcessor); } if (processor instanceof IMessageReceiverPostProcessor) { IMessageReceiverPostProcessor messageReceiverPostProcessor = (IMessageReceiverPostProcessor) processor; messageReceiverPostProcessors.add(messageReceiverPostProcessor); } } public <E> E getProcessorOf(Class<E> clazz) { return (E) processorMap.get(clazz); } }