package eu.hgross.blaubot.core.statemachine; import java.util.List; import eu.hgross.blaubot.core.BlaubotServerConnector; import eu.hgross.blaubot.core.ConnectionStateMachineConfig; import eu.hgross.blaubot.core.IBlaubotAdapter; import eu.hgross.blaubot.core.IBlaubotConnection; import eu.hgross.blaubot.core.IBlaubotDevice; import eu.hgross.blaubot.core.BlaubotConnectionManager; import eu.hgross.blaubot.core.ServerConnectionManager; import eu.hgross.blaubot.core.acceptor.ConnectionMetaDataDTO; import eu.hgross.blaubot.core.acceptor.discovery.BlaubotBeaconService; import eu.hgross.blaubot.core.connector.IBlaubotConnector; import eu.hgross.blaubot.core.statemachine.states.FreeState; import eu.hgross.blaubot.core.statemachine.states.IBlaubotState; import eu.hgross.blaubot.core.statemachine.states.StoppedState; import eu.hgross.blaubot.admin.AbstractAdminMessage; import eu.hgross.blaubot.admin.CensusMessage; import eu.hgross.blaubot.admin.PronouncePrinceAdminMessage; import eu.hgross.blaubot.messaging.BlaubotChannelManager; import eu.hgross.blaubot.messaging.IBlaubotAdminMessageListener; import eu.hgross.blaubot.util.Log; /** * Session object holding data which is shared across state changes. * * @author Henning Gross {@literal (mail.to@henning-gross.de)} * */ public class StateMachineSession { protected static final String LOG_TAG = "StateMachineSession"; private final ConnectionStateMachine connectionStateMachine; private final BlaubotChannelManager channelManager; private final BlaubotConnectionManager connectionManager; private final BlaubotBeaconService beaconService; private final IBlaubotDevice ownDevice; private CensusMessage lastCensusMessage; private PronouncePrinceAdminMessage lastPronouncePrinceAdminMessage; private ServerConnectionManager serverConnectionManager; public StateMachineSession(ConnectionStateMachine stateMachine, IBlaubotDevice ownDevice, ServerConnectionManager serverConnectionManager) { this.serverConnectionManager = serverConnectionManager; this.ownDevice = ownDevice; this.connectionStateMachine = stateMachine; this.connectionManager = stateMachine.blaubot.getConnectionManager(); this.beaconService = stateMachine.getBeaconService(); this.channelManager= connectionStateMachine.blaubot.getChannelManager(); channelManager.addAdminMessageListener(new IBlaubotAdminMessageListener() { @Override public void onAdminMessage(AbstractAdminMessage adminMessage) { if (adminMessage instanceof CensusMessage) { if (Log.logDebugMessages()) { Log.d(LOG_TAG, "Got a CencusMessage containing " + ((CensusMessage) adminMessage).getDeviceStates().size() + " devices."); } lastCensusMessage = (CensusMessage) adminMessage; } else if (adminMessage instanceof PronouncePrinceAdminMessage) { lastPronouncePrinceAdminMessage = (PronouncePrinceAdminMessage) adminMessage; } } }); this.connectionStateMachine.addConnectionStateMachineListener(new IBlaubotConnectionStateMachineListener() { @Override public void onStateMachineStopped() { } @Override public void onStateMachineStarted() { } @Override public void onStateChanged(IBlaubotState oldState, IBlaubotState state) { // we clear the cached messages if we go "offline" to free or stopped state if (state instanceof FreeState || state instanceof StoppedState) { clear(); } } }); } private void clear() { lastCensusMessage = null; lastPronouncePrinceAdminMessage = null; } public CensusMessage getLastCensusMessage() { return lastCensusMessage; } public PronouncePrinceAdminMessage getLastPronouncePrinceAdminMessage() { return lastPronouncePrinceAdminMessage; } public ConnectionStateMachine getConnectionStateMachine() { return connectionStateMachine; } public BlaubotChannelManager getChannelManager() { return channelManager; } public BlaubotConnectionManager getConnectionManager() { return connectionManager; } public BlaubotBeaconService getBeaconService() { return beaconService; } public List<IBlaubotAdapter> getAdapters() { return connectionStateMachine.blaubot.getAdapters(); } /** * Gets the server connection manager * * @return the server connection manager */ public ServerConnectionManager getServerConnectionManager() { return serverConnectionManager; } /** * Checks whether the given unique device id is a server unique device id. * * @param uniqueDeviceId the uid to check * @return the uniqueDeviceId or null, if unknown or not available */ public boolean isServerUniqueDeviceId(String uniqueDeviceId) { final BlaubotServerConnector serverConnector = getServerConnectionManager().getServerConnector(); if (serverConnector != null) { final boolean isServerUniqueDeviceId = serverConnector.getServerUniqueDeviceId().equals(uniqueDeviceId); if (isServerUniqueDeviceId) { return true; } } // no server connector attached or does not match the server unique device id but we could still be king and using a relay connection // check all available server connections (if any) for (IBlaubotConnection connection : getServerConnectionManager().getConnectionsToServer()) { if (connection.getRemoteDevice().getUniqueDeviceID().equals(uniqueDeviceId)) { return true; } } return false; } /** * @param uniqueId * the unique id to check * @return true, if we are the device with this uniqueId */ public boolean isOwnDevice(String uniqueId) { return getOwnDevice().getUniqueDeviceID().equals(uniqueId); } /** * Checks whether the other device is greater as our own device or nots. *f * @param blaubotDevice the blaubot device to check * @return true iff blaubotDevice is greater than our own device */ public boolean isGreaterThanOurDevice(IBlaubotDevice blaubotDevice) { if(ownDevice == blaubotDevice) { Log.w(LOG_TAG, "Comparing with myself"); return true; } // a.compareTo(b) // a<b -> <0 // a==b -> 0 // a>b -> >0 return ownDevice.compareTo(blaubotDevice) < 0; } public IBlaubotDevice getOwnDevice() { return ownDevice; } /** * Retrieves a guessed ConnectionStateMachineConfig based on the BeaconStore informations from the * registered connector's adapters. * * @param device the device to get the config for * @return the retrieved config or a default config, if not retrievable */ public ConnectionStateMachineConfig getConnectionStateMachineConfigForDevice(IBlaubotDevice device) { final List<ConnectionMetaDataDTO> lastKnownConnectionMetaData = beaconService.getBeaconStore().getLastKnownConnectionMetaData(device.getUniqueDeviceID()); // TODO: this gets the FIRST appropriate connector - there could be more final IBlaubotConnector connectorForDevice = connectionManager.getConnectorForDevice(device.getUniqueDeviceID()); ConnectionStateMachineConfig connectionStateMachineConfig; if(connectorForDevice == null) { if (Log.logWarningMessages()) { Log.w(LOG_TAG, "Could not retrieve specific config for device " + device + ", falling back to the most suitable config from attached connectors."); } List<IBlaubotConnector> connectionConnectors = connectionManager.getConnectionConnectors(); if (connectionConnectors.isEmpty()) { throw new RuntimeException("Could neither receive a specific csm config for device " + device + " nor a fallback csm config!"); } connectionStateMachineConfig = connectionConnectors.get(0).getAdapter().getConnectionStateMachineConfig(); } else { connectionStateMachineConfig = connectorForDevice.getAdapter().getConnectionStateMachineConfig(); } return connectionStateMachineConfig; } }