/** * * Copyright (c) 2009-2016 Freedomotic team http://freedomotic.com * * This file is part of Freedomotic * * 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, or (at your option) any later version. * * This Program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * Freedomotic; see the file COPYING. If not, see * <http://www.gnu.org/licenses/>. */ package com.freedomotic.plugins.devices.simulation; import com.freedomotic.api.EventTemplate; import com.freedomotic.api.Protocol; import com.freedomotic.events.LocationEvent; import com.freedomotic.exceptions.PluginStartupException; import com.freedomotic.exceptions.UnableToExecuteException; import com.freedomotic.model.geometry.FreedomPoint; import com.freedomotic.reactions.Command; import com.freedomotic.things.EnvObjectLogic; import com.freedomotic.things.GenericPerson; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.DataInputStream; import java.io.IOException; import java.io.PrintStream; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.StringTokenizer; /** * * @author Enrico Nicoletti */ public class TrackingReadSocket extends Protocol { private static final Logger LOG = LoggerFactory.getLogger(TrackingReadSocket.class); private ServerSocket serverSocket; private final int SOCKET_SERVER_PORT = configuration.getIntProperty("socket-server-port", 7777); private final int MAX_CONNECTIONS = configuration.getIntProperty("max-connections", -1); private final String STOP_CONNECTION_CHAR = configuration.getStringProperty("stop-connection-char", "."); /** * */ public TrackingReadSocket() { super("Tracking Simulator (Read Socket)", "/simulation/tracking-simulator-read-socket.xml"); setDescription("Simulates tracking system. Positions read from a socket (port:" + SOCKET_SERVER_PORT + ")"); setPollingWait(-1); } @Override public void onStart() throws PluginStartupException { try { createServerSocket(); } catch (IOException ioe) { throw new PluginStartupException("IOException on socket listening: \"{}\"", ioe); } } /** * Creates a server socket. * * @throws IOException */ private void createServerSocket() throws IOException { try { serverSocket = new ServerSocket(); serverSocket.setReuseAddress(true); serverSocket.bind(new InetSocketAddress(SOCKET_SERVER_PORT)); LOG.info("Start listening to server socket \"{}:{}\"", serverSocket.getInetAddress(), serverSocket.getLocalPort()); } catch (IOException ioe) { throw ioe; } } /** * Parses the string input. * * @param in input string to parse */ private void parseInput(String in) { int id = 0; int x = -1; int y = -1; FreedomPoint location; StringTokenizer tokenizer = null; try { tokenizer = new StringTokenizer(in); id = Integer.parseInt(tokenizer.nextToken()); x = Integer.parseInt(tokenizer.nextToken()); y = Integer.parseInt(tokenizer.nextToken()); location = new FreedomPoint(x, y); movePerson(id, location); } catch (Exception ex) { LOG.error("Error while parsing client input. \n {} \ntoken count: {}", in, tokenizer.countTokens()); } } /** * Moves a 'Person' thing to a specific location. * * @param userId user's id associated to its address field * @param location new location */ private void movePerson(int userId, FreedomPoint location) { for (EnvObjectLogic object : getApi().things().findAll()) { if ((object instanceof GenericPerson) && (object.getPojo().getPhisicalAddress().equalsIgnoreCase(String.valueOf(userId)))) { GenericPerson person = (GenericPerson) object; LocationEvent event = new LocationEvent(this, person.getPojo().getUUID(), location); notifyEvent(event); } } } @Override protected void onRun() { int i = 0; while ((i++ < MAX_CONNECTIONS) || (MAX_CONNECTIONS == -1)) { try { ClientInputReader clientConnection; Socket clientSocket = serverSocket.accept(); clientConnection = new ClientInputReader(clientSocket); Thread t = new Thread(clientConnection); t.start(); } catch (IOException ioe) { LOG.error("IOException on socket listen: \"{}\"", ioe); } } } @Override public void onStop() { try { serverSocket.close(); } catch (IOException ex) { LOG.error("IOException on socket closing: \"{}\"", ex); } } @Override protected void onCommand(Command c) throws IOException, UnableToExecuteException { //do nothing } @Override protected boolean canExecute(Command c) { //do nothing return true; } @Override protected void onEvent(EventTemplate event) { //do nothing } /** * This class reads data input from clients until "stop-connection-char" is * received. * */ private class ClientInputReader implements Runnable { private Socket client; ClientInputReader(Socket client) { this.client = client; LOG.info("New client connected to server on \"{}\"", client.getInetAddress()); } public void run() { try { String line; // Get input from the client DataInputStream in = new DataInputStream(client.getInputStream()); while (((line = in.readLine()) != null) && !line.equals(STOP_CONNECTION_CHAR) && isRunning()) { LOG.info("Readed from socket: \"{}\"", line); parseInput(line); } LOG.info("Closing socket connection \"{}\"", client.getInetAddress()); client.close(); } catch (IOException ioe) { LOG.error("IOException on socket listening: \"{}\"", ioe); } } } }