Alejandro Acuña
2024-10-25 e51f4a713ed6e744c203c9493165584728a29c52
server library
47 files added
1 files modified
13471 ■■■■■ changed files
.gitignore 3 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/Model.java 2190 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/Server.java 450 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/ServerException.java 36 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/Shared.java 684 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/configuration/Configuration.java 165 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/configuration/ConfigurationGeneral.java 38 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/configuration/ConfigurationListener.java 32 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/configuration/ConfigurationListenerDEBUG.java 48 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/configuration/ConfigurationListenerHttp.java 58 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/configuration/ConfigurationMessages.java 32 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/configuration/ConfigurationNtpHttp.java 39 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/configuration/ConfigurationSecurity.java 40 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/configuration/ConfigurationTransactions.java 20 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/configuration/ConfigurationTransactionsService.java 21 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/Controller.java 28 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerDatabase.java 687 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerDevice.java 20 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerListener.java 462 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerListenerDebug.java 373 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerListenerHttp.java 798 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerListenerHttpWeb.java 637 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerListenerHttps.java 142 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerListenerHttpsWeb.java 109 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerListenerWEB.java 260 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerNtpHttp.java 232 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerProcessInformation.java 264 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerStatus.java 354 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerTransactions.java 271 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ControllerUserPermissions.java 216 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/FactoryController.java 110 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/ListenerImplementation.java 1791 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/controller/http/webpages/Page.java 573 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/gui/ArticPanel.java 178 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/gui/ArticWindow.java 442 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/gui/components/PanelClock.java 72 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/gui/components/PanelGeneric.java 30 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/gui/components/PanelProcess.java 123 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/gui/components/PanelProcess_Chart.java 140 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/gui/components/PanelProcess_Information.java 236 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/gui/components/PanelTraces.java 531 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/gui/components/PanelTracesHistorical.java 231 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/types/HttpAuthentication.java 190 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/types/HttpStatus.java 6 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/types/HttpToken.java 49 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/types/HttpTokenException.java 6 ●●●●● patch | view | raw | blame | history
servers/server/src/art/servers/types/IPv4.java 47 ●●●●● patch | view | raw | blame | history
servers/server/src/server.version.properties 7 ●●●●● patch | view | raw | blame | history
.gitignore
@@ -47,3 +47,6 @@
servers/gost-access-server/data/art.servers.gost-access-server/atex5/
servers/gost-access-server/manifest.mf
servers/gost-access-server - copia/
servers/server/build/
servers/server/nbproject/
servers/server/build.xml
servers/server/src/art/servers/Model.java
New file
@@ -0,0 +1,2190 @@
package art.servers;
import art.library.gui.flat.FlatDialog;
import art.library.interop.serialization.Serialization;
import art.library.model.devices.Device;
import art.library.model.devices.DeviceAction;
import art.library.model.devices.DeviceInformation;
import art.library.model.devices.DevicePersistenceAction;
import art.library.model.devices.DevicePersistenceHistorical;
import art.library.model.devices.DevicePersistenceTimeless;
import art.library.model.devices.DeviceRealtime;
import art.library.model.devices.DeviceSymbol;
import art.library.model.devices.application.Application;
import art.library.model.devices.colors.controller.RTZ32.types.eventstrolley.EventTrolley;
import art.library.model.devices.colors.controller.RTZ32.types.eventstrolley.EventTrolleyResult;
import art.library.model.transactions.traces.Trace;
import art.library.model.transactions.traces.TracePersistance;
import art.library.model.transactions.traces.TraceResult;
import art.library.persistence.Persistence;
import art.library.utils.resources.Resources;
import art.library.utils.synchro.Mutex;
import art.servers.configuration.Configuration;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.nio.file.Files;
import java.rmi.ServerException;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public abstract class Model
{
    public String filename = null;
    public String deviceClassName = null;
    public String deviceInformationClassName = null;
    protected List<Device> ldevice = new ArrayList<Device>();
    protected List<DeviceSymbol> lsymbols = new ArrayList<DeviceSymbol>();
    protected HashMap<String, Device> mdevice = new HashMap<String, Device>();
    protected long configurationSymbolsTimestamp = 0;
    protected Mutex mutexListDevices = new Mutex();
    protected Mutex mutexListSymbols = new Mutex();
    protected HashMap<String, Mutex> mmutex = new HashMap<String, Mutex>();
    public Model(Configuration configuration) throws Exception
    {
    }
    public Model(Configuration configuration, String filename, String deviceClassName, String deviceInformationClassName) throws Exception
    {
        this.filename = filename;
        this.deviceClassName = deviceClassName;
        this.deviceInformationClassName = deviceInformationClassName;
        readSymbols();
        configurationSymbolsTimestamp = System.currentTimeMillis();
        readDevices();
    }
    // <editor-fold defaultstate="collapsed" desc="Devices">
    public void clearDevices()
    {
        mutexListDevices.lockWrite();
        {
            ldevice.clear();
            mdevice.clear();
        }
        mutexListDevices.releaseWrite();
    }
    public void readDevices()
    {
        if (filename == null) return;
        mutexListDevices.lockWrite();
        try
        {
            ldevice.clear();
            mdevice.clear();
            // Read data from database file (--restore)
            if (Shared.restoreDevices == true)
            {
                Class clazzDevice = Class.forName(deviceClassName);
                Class<?> clazzArray = (Class<?>)Array.newInstance(clazzDevice, 0).getClass();
                List<Device> ldevice = (List<Device>)Serialization.deserialize(clazzArray, new File(art.servers.Shared.getApplicationName() + "."  + filename + ".database.json"));
                for (Device device : ldevice)
                {
                    if ((device instanceof Device) && (device.information.serverPort == Shared.configuration.listener.port) && (device.information.serverAddress.equalsIgnoreCase(Shared.configuration.listener.address)))
                    {
                        device.information.serverAddress = Shared.configuration.listener.address;
                        device.information.serverPort = Shared.configuration.listener.port;
                        device.information.serverAddressExternal = Shared.configuration.listener.addressExternal;
                        device.information.serverPortExternal = Shared.configuration.listener.portExternal;
                        this.ldevice.add(device);
                        this.mdevice.put(device.getIdentifier(), device);
                    }
                }
            }
            // Read data from database
            else if ((Shared.controllerDatabase != null) &&  (Shared.reloadDevices == false))
            {
                Class clazzDevice = Class.forName(deviceClassName);
                List<Device> ldevice = (List<Device>)DevicePersistenceTimeless.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.timeless_getObject(DevicePersistenceTimeless.class.getName(), "type = '" + clazzDevice.getName() + "'"));
                for (Device device : ldevice)
                {
                    try
                    {
                        if ((device instanceof Device) && (device.information.serverPort == Shared.configuration.listener.port) && (device.information.serverAddress.equalsIgnoreCase(Shared.configuration.listener.address)))
                        {
                            device.information.serverAddress = Shared.configuration.listener.address;
                            device.information.serverPort = Shared.configuration.listener.port;
                            device.information.serverAddressExternal = Shared.configuration.listener.addressExternal;
                            device.information.serverPortExternal = Shared.configuration.listener.portExternal;
                            this.ldevice.add(device);
                            this.mdevice.put(device.getIdentifier(), device);
                        }
                    }
                    catch (Exception exception)
                    {
                        Shared.println(device.getIdentifier(), exception.getMessage());
                    }
                }
            }
        }
        catch (Exception exception)
        {
            exception.printStackTrace();
            StringWriter sw = new StringWriter();
            exception.printStackTrace(new PrintWriter(sw));
            FlatDialog.showDialog(null, Shared.getMessage("Error"), exception.getMessage() + "\n\n" + sw.toString(), true, FlatDialog.DIALOG_INFORMATION);
            System.exit(0);
        }
        try
        {
            Class clazzDevice = Class.forName(deviceClassName);
            Class clazzInformation = Class.forName(deviceInformationClassName);
            DeviceInformation[] ldeviceInformation = null;
            if (new File(Shared.getApplicationName() + "." + filename + ".json").exists())
            {
                Class<?> clazzArray = (Class<?>)Array.newInstance(clazzInformation, 0).getClass();
                ldeviceInformation = Serialization.deserialize(clazzArray, new File(Shared.getApplicationName() + "."  + filename + ".json"));
            }
            for (DeviceInformation deviceInformation : ldeviceInformation)
            {
                if (mdevice.containsKey(deviceInformation.getIdentifier()) == false)
                {
                    addDevice(clazzDevice, deviceInformation);
                }
            }
        }
        catch (Exception exception)
        {
            exception.printStackTrace();
            StringWriter sw = new StringWriter();
            exception.printStackTrace(new PrintWriter(sw));
            FlatDialog.showDialog(null, Shared.getMessage("Error"), exception.getMessage() + "\n\n" + sw.toString(), true, FlatDialog.DIALOG_INFORMATION);
            System.exit(0);
        }
        for (Device device : ldevice)
        {
            device.information.serverServiceName = art.servers.Shared.controllerStatus.getApplication().getDeviceInformation().serverServiceName;
        }
        // Sort
        Collections.sort(ldevice, new Comparator<Device>()
        {
            public int compare(Device device1, Device device2)
            {
               return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
            }
        });
        // Database file
        if (Shared.restoreDevices == false)
        {
            try
            {
                FileOutputStream fos = new FileOutputStream(new File(art.servers.Shared.getApplicationName() + "."  + filename + ".database.json"));
                fos.write("[\n".getBytes());
                for (Device device : ldevice)
                {
                    fos.write(Serialization.toPrettyString(device).getBytes());
                    if (device != ldevice.get(ldevice.size() - 1)) fos.write(",".getBytes());
                }
                fos.write("]\n".getBytes());
                fos.close();
            }
            catch (Exception e)
            {
            }
        }
        mutexListDevices.releaseWrite();
    }
    protected void addDevice(Class clazzDevice, DeviceInformation information) throws Exception
    {
        Device device = mdevice.get(information.getIdentifier());
        long timestamp = System.currentTimeMillis();
        if (device == null)
        {
            Constructor<?> constructor = clazzDevice.getConstructor(String.class);
            Object object = constructor.newInstance(new Object[]{information.getIdentifier()});
            device = (Device)object;
            device.information = information;
            device.information.setCreationTimestamp(timestamp);
            device.information.serverAddress = Shared.configuration.listener.address;
            device.information.serverPort = Shared.configuration.listener.port;
            device.information.serverAddressExternal = Shared.configuration.listener.addressExternal;
            device.information.serverPortExternal = Shared.configuration.listener.portExternal;
            device.setLastTimestampInformationUpdate(timestamp);
            if (Shared.controllerDatabase != null)
            {
                Shared.controllerDatabase.timeless_updateOrAddObject(new DevicePersistenceTimeless(device));
                DevicePersistenceHistorical deviceHistorical = new DevicePersistenceHistorical(device);
                try
                {
                    Shared.controllerDatabase.historical_addOrUpdateObject(deviceHistorical);
                }
                catch (org.postgresql.util.PSQLException exception)
                {
                    if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
                        (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
                    {
                        Calendar calendar1 = Calendar.getInstance();
                        calendar1.setTimeInMillis(device.getLastTimestampUpdate());
                        calendar1.set(Calendar.DATE, 1);
                        calendar1.set(Calendar.HOUR_OF_DAY, 0);
                        calendar1.set(Calendar.MINUTE, 0);
                        calendar1.set(Calendar.SECOND, 0);
                        calendar1.set(Calendar.MILLISECOND, 0);
                        SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
                        String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
                        long startdate = calendar1.getTimeInMillis();
                        calendar1.add(Calendar.MONTH, 1);
                        long enddate = calendar1.getTimeInMillis();
                        String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
                        try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
                        executeAlterTableDevicesVacuum(true, tablename);
                        // Do again the insert
                        try
                        {
                            Shared.controllerDatabase.historical_addOrUpdateObject(deviceHistorical);
                        }
                        catch (Exception e)
                        {
                            Shared.println(Shared.getMessage("Model"), e);
                        }
                    }
                }
            }
            mdevice.put(device.getIdentifier(), device);
            ldevice.add(device);
        }
        else
        {
            if (Serialization.equals(device.information, information) == false)
            {
                device.information = information;
                device.setLastTimestampInformationUpdate(timestamp);
                Shared.controllerDatabase.timeless_updateOrAddObject(new DevicePersistenceTimeless(device));
                try
                {
                    Shared.controllerDatabase.historical_addOrUpdateObject(new DevicePersistenceHistorical(device));
                }
                catch (org.postgresql.util.PSQLException exception)
                {
                    if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
                        (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
                    {
                        Calendar calendar1 = Calendar.getInstance();
                        calendar1.setTimeInMillis(device.getLastTimestampUpdate());
                        calendar1.set(Calendar.DATE, 1);
                        calendar1.set(Calendar.HOUR_OF_DAY, 0);
                        calendar1.set(Calendar.MINUTE, 0);
                        calendar1.set(Calendar.SECOND, 0);
                        calendar1.set(Calendar.MILLISECOND, 0);
                        SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
                        String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
                        long startdate = calendar1.getTimeInMillis();
                        calendar1.add(Calendar.MONTH, 1);
                        long enddate = calendar1.getTimeInMillis();
                        String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
                        try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
                        executeAlterTableDevicesVacuum(true, tablename);
                        // Do again the insert
                        try
                        {
                            Shared.controllerDatabase.historical_addOrUpdateObject(new DevicePersistenceHistorical(device));
                        }
                        catch (Exception e)
                        {
                            Shared.println(Shared.getMessage("Model"), e);
                        }
                    }
                }
            }
        }
    }
    public void addDevices(DeviceInformation[] linformation) throws Exception
    {
        // Es ineficiente, pero hay que tener en cuenta que es una operación residual
        mutexListDevices.lockWrite();
        try
        {
            for (DeviceInformation information : linformation)
            {
                addDevice(Class.forName(this.deviceClassName), information);
            }
            Collections.sort(ldevice, new Comparator<Device>()
            {
                public int compare(Device device1, Device device2)
                {
                   return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
                }
            });
        }
        finally
        {
            mutexListDevices.releaseWrite();
        }
    }
    public boolean existsDevice(String identifier)
    {
        mutexListDevices.lockRead();
        try
        {
            return (mdevice.containsKey(identifier));
        }
        finally
        {
            mutexListDevices.releaseRead();
        }
    }
    public Device getDevice(String classname, int number)
    {
        for (Device device : ldevice)
        {
            if ((device.getClassName().equalsIgnoreCase(classname)) && (device.getDeviceInformation().number == number))
            {
                return device;
            }
        }
        return null;
    }
    public Device getDevice(String identifier) throws ServerException
    {
        mutexListDevices.lockRead();
        try
        {
            Device device = mdevice.get(identifier);
            if (device == null)
            {
                throw new ServerException("Device does not exists");
            }
            return device;
        }
        finally
        {
            mutexListDevices.releaseRead();
        }
    }
    public Device[] getDevices()
    {
        mutexListDevices.lockRead();
        try
        {
            return ldevice.toArray(new Device[ldevice.size()]);
        }
        finally
        {
            mutexListDevices.releaseRead();
        }
    }
    public Device[] getDevicesCopy()
    {
        mutexListDevices.lockRead();
        try
        {
            List<Device> result = new ArrayList<Device>();
            for (Device device : ldevice)
            {
                Device clone = Serialization.clone(device);
                clone.realtime = device.getDeviceRealtime();
                result.add(clone);
            }
            return result.toArray(new Device[result.size()]);
        }
        finally
        {
            mutexListDevices.releaseRead();
        }
    }
    public List<Device> getDevices(String group)
    {
        mutexListDevices.lockRead();
        try
        {
            List<Device> result = new ArrayList<Device>();
            for (Device device : ldevice)
            {
                try
                {
                    if (device.getDeviceInformation().group.equalsIgnoreCase(group))
                    {
                        result.add(device);
                    }
                }
                catch (Exception e)
                {
                }
            }
            return result;
        }
        finally
        {
            mutexListDevices.releaseRead();
        }
    }
    public Device[] getDevices(String[] lgroup)
    {
        if (lgroup == null)
        {
            return new Device[0];
        }
        if (lgroup.length == 0)
        {
            return new Device[0];
        }
        mutexListDevices.lockRead();
        try
        {
            List<Device> result = new ArrayList<Device>();
            for (String group : lgroup)
            {
                result.addAll(getDevices(group));
            }
            return result.toArray(new Device[result.size()]);
        }
        finally
        {
            mutexListDevices.releaseRead();
        }
    }
    public List<Device> getDevicesFromIdentifier(String[] lidentifier)
    {
        mutexListDevices.lockRead();
        try
        {
            List<Device> result = new ArrayList<Device>();
            for (String identifier : lidentifier)
            {
                try
                {
                    Device device = getDevice(identifier);
                    if (device != null)
                    {
                        result.add(device);
                    }
                }
                catch (Exception exception)
                {
                }
            }
            return result;
        }
        finally
        {
            mutexListDevices.releaseRead();
        }
    }
    public Device[] getDevices(long timestamp)
    {
        mutexListDevices.lockRead();
        try
        {
            List<Device> result = new ArrayList<Device>();
            for (Device device : ldevice)
            {
                if (device.getLastTimestampUpdate() > timestamp)
                {
                    result.add(device);
                }
            }
            return result.toArray(new Device[result.size()]);
        }
        finally
        {
            mutexListDevices.releaseRead();
        }
    }
    public Device[] getDevices(String identifier, long timestamp)
    {
        if (identifier == null) return getDevices(timestamp);
        mutexListDevices.lockRead();
        try
        {
            List<Device> result = new ArrayList<Device>();
            for (Device device : ldevice)
            {
                if (device.getIdentifier().equals(identifier))
                {
                    if (device.getLastTimestampUpdate() > timestamp)
                    {
                        result.add(device);
                    }
                }
            }
            return result.toArray(new Device[result.size()]);
        }
        finally
        {
            mutexListDevices.releaseRead();
        }
    }
    public Device[] getDevices(String identifier, long  timestamp1, long timestamp2) throws Exception
    {
        // Without mutex read, we are consulting historical database and creating new objects
        long timestamp = getLastTimestamp(identifier, timestamp1);
        String where = "type = '" + deviceClassName + "' AND timestamp >= " + timestamp + " AND timestamp < " + timestamp2;
        if (identifier != null)
        {
            if (identifier.length() > 0)
            {
                where = where + " AND identifier = '" + identifier + "'";
            }
        }
        List<Device> result = (List<Device>)DevicePersistenceHistorical.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.historical_getObject(DevicePersistenceHistorical.class.getName(), where));
        Collections.sort(result, new Comparator<Device>()
        {
            public int compare(Device device1, Device device2)
            {
               return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
            }
        });
        return result.toArray(new Device[result.size()]);
    }
    public Device[] getDevicesWhen(String identifier, long  timestamp) throws Exception
    {
        if (identifier == null) return getDevicesWhen(timestamp);
        // Without mutex read, we are consulting historical database and creating new objects
        String where = "type = '" + deviceClassName + "' AND timestamp <= " + timestamp + " AND identifier = '" + identifier + "' ORDER BY timestamp DESC limit 1";
        List<Device> result = (List<Device>)DevicePersistenceHistorical.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.historical_getObject(DevicePersistenceHistorical.class.getName(), where));
        Collections.sort(result, new Comparator<Device>()
        {
            public int compare(Device device1, Device device2)
            {
               return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
            }
        });
        return result.toArray(new Device[result.size()]);
    }
    public Device[] getDevicesNext(String identifier, long  timestamp) throws Exception
    {
        if (identifier == null) return getDevicesWhen(timestamp);
        // Without mutex read, we are consulting historical database and creating new objects
        String where = "type = '" + deviceClassName + "' AND timestamp > " + timestamp + " AND identifier = '" + identifier + "' ORDER BY timestamp ASC limit 1";
        List<Device> result = (List<Device>)DevicePersistenceHistorical.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.historical_getObject(DevicePersistenceHistorical.class.getName(), where));
        Collections.sort(result, new Comparator<Device>()
        {
            public int compare(Device device1, Device device2)
            {
               return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
            }
        });
        return result.toArray(new Device[result.size()]);
    }
    public Device[] getDevicesWhen(long  timestamp) throws Exception
    {
        List<Device> result = new ArrayList<Device>();
        for (Device device : getDevices()) result.addAll(Arrays.asList(getDevicesWhen(device.getIdentifier(), timestamp)));
        Collections.sort(result, new Comparator<Device>()
        {
            public int compare(Device device1, Device device2)
            {
               return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
            }
        });
        return result.toArray(new Device[result.size()]);
    }
    /**
     * Get device from external accesses, not from this server memory devices allocation.
     */
    public Device getDeviceExternal(String identifier) throws Exception
    {
        mutexListDevices.lockRead();
        // TODO: Timelessaccess for the moment. In the future we must include direct access to servers using Services pollsters
        try
        {
            String where = "identifier = '" + identifier + "'";
            List<Device> result = (List<Device>)DevicePersistenceTimeless.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.timeless_getObject(DevicePersistenceTimeless.class.getName(), where));
            return result.get(0);
        }
        finally
        {
            mutexListDevices.releaseRead();
        }
    }
    /**
     * Get devices from external accesses, not from this server memory devices allocation.
     */
    public Device[] getDevicesExternal(String type) throws Exception
    {
        mutexListDevices.lockRead();
        try
        {
            String where = "type = '" + type + "'";
            List<Device> result = (List<Device>)DevicePersistenceTimeless.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.timeless_getObject(DevicePersistenceTimeless.class.getName(), where));
            Collections.sort(result, new Comparator<Device>()
            {
                public int compare(Device device1, Device device2)
                {
                   return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
                }
            });
            return result.toArray(new Device[result.size()]);
        }
        finally
        {
            mutexListDevices.releaseRead();
        }
    }
    public boolean updateDevice(Device currentdevice, Device newdevice)
    {
        getMutex(currentdevice).lockWrite();
        boolean different = false;
        try
        {
            newdevice.getDeviceInformation().serverAddress = Shared.configuration.listener.address;
            newdevice.getDeviceInformation().serverPort = Shared.configuration.listener.port;
            newdevice.getDeviceInformation().serverAddressExternal = Shared.configuration.listener.addressExternal;
            newdevice.getDeviceInformation().serverPortExternal = Shared.configuration.listener.portExternal;
            newdevice.getDeviceInformation().serverServiceName = Shared.controllerStatus.getApplication().getDeviceInformation().serverServiceName;
            different = currentdevice.updateDevice(newdevice);
            if ((different == true) && (Shared.configuration.database != null))
            {
                Shared.controllerDatabase.timeless_updateOrAddObject(new DevicePersistenceTimeless(currentdevice));
            }
        }
        catch (Exception e)
        {
        }
        finally
        {
            getMutex(currentdevice).releaseWrite();
        }
        // newdevice sabemos que no cambiara porque nadie mas tiene la referencia
        try
        {
            if ((different == true) && (Shared.configuration.database != null))
            {
                Shared.controllerDatabase.historical_addObject(new DevicePersistenceHistorical(newdevice));
            }
        }
        catch (org.postgresql.util.PSQLException exception)
        {
            if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
                (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
            {
                Calendar calendar1 = Calendar.getInstance();
                calendar1.setTimeInMillis(newdevice.getLastTimestampUpdate());
                calendar1.set(Calendar.DATE, 1);
                calendar1.set(Calendar.HOUR_OF_DAY, 0);
                calendar1.set(Calendar.MINUTE, 0);
                calendar1.set(Calendar.SECOND, 0);
                calendar1.set(Calendar.MILLISECOND, 0);
                SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
                String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
                long startdate = calendar1.getTimeInMillis();
                calendar1.add(Calendar.MONTH, 1);
                long enddate = calendar1.getTimeInMillis();
                String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
                try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
                executeAlterTableDevicesVacuum(true, tablename);
                // Do again the insert
                try
                {
                    Shared.controllerDatabase.historical_addObject(new DevicePersistenceHistorical(newdevice));
                }
                catch (Exception e)
                {
                    Shared.println(Shared.getMessage("Model"), e);
                }
            }
        }
        catch (Exception e)
        {
        }
        return different;
    }
    public void updateDevice(Device device)
    {
        updateDevice(device, System.currentTimeMillis());
    }
    public void updateDevice(Device device, long timestamp)
    {
        getMutex(device).lockWrite();
        try
        {
            Device currentDevice = (Device)mdevice.get(device.getIdentifier());
            if (currentDevice == null)
            {
                device.getDeviceInformation().setCreationTimestamp(timestamp);
                device.setLastTimestampInformationUpdate(timestamp);
                if (device.getDeviceConfiguration() != null)
                {
                    device.setLastTimestampConfigurationUpdate(timestamp);
                }
                device.information.serverAddress = Shared.configuration.listener.address;
                device.information.serverPort = Shared.configuration.listener.port;
                if (Shared.configuration.database != null)
                {
                    Shared.controllerDatabase.timeless_updateOrAddObject(new DevicePersistenceTimeless(device));
                    try
                    {
                        Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
                    }
                    catch (org.postgresql.util.PSQLException exception)
                    {
                        if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
                            (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
                        {
                            Calendar calendar1 = Calendar.getInstance();
                            calendar1.setTimeInMillis(device.getLastTimestampUpdate());
                            calendar1.set(Calendar.DATE, 1);
                            calendar1.set(Calendar.HOUR_OF_DAY, 0);
                            calendar1.set(Calendar.MINUTE, 0);
                            calendar1.set(Calendar.SECOND, 0);
                            calendar1.set(Calendar.MILLISECOND, 0);
                            SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
                            String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
                            long startdate = calendar1.getTimeInMillis();
                            calendar1.add(Calendar.MONTH, 1);
                            long enddate = calendar1.getTimeInMillis();
                            String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
                            try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
                            executeAlterTableDevicesVacuum(true, tablename);
                            // Do again the insert
                            try
                            {
                                Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
                            }
                            catch (Exception e)
                            {
                                Shared.println(Shared.getMessage("Model"), e);
                            }
                        }
                    }
                }
                mdevice.put(device.getIdentifier(), device);
                ldevice.add(device);
            }
            else
            {
                System.out.println("3.UpdateDevice: " + currentDevice);
                if (currentDevice.updateDevice(device) == true)
                {
                    System.out.println("4.UpdateDevice: " + currentDevice);
                    if (Shared.configuration.database != null)
                    {
                        Shared.controllerDatabase.timeless_updateOrAddObject(new DevicePersistenceTimeless(device));
                        try
                        {
                            Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
                        }
                        catch (org.postgresql.util.PSQLException exception)
                        {
                            if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
                                (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
                            {
                                Calendar calendar1 = Calendar.getInstance();
                                calendar1.setTimeInMillis(device.getLastTimestampUpdate());
                                calendar1.set(Calendar.DATE, 1);
                                calendar1.set(Calendar.HOUR_OF_DAY, 0);
                                calendar1.set(Calendar.MINUTE, 0);
                                calendar1.set(Calendar.SECOND, 0);
                                calendar1.set(Calendar.MILLISECOND, 0);
                                SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
                                String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
                                long startdate = calendar1.getTimeInMillis();
                                calendar1.add(Calendar.MONTH, 1);
                                long enddate = calendar1.getTimeInMillis();
                                String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
                                try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
                                executeAlterTableDevicesVacuum(true, tablename);
                                // Do again the insert
                                try
                                {
                                    Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
                                }
                                catch (Exception e)
                                {
                                    Shared.println(Shared.getMessage("Model"), e);
                                }
                            }
                        }
                    }
                }
            }
        }
        catch (Exception e)
        {
        }
        finally
        {
            getMutex(device).releaseWrite();
        }
    }
    public void updateDeviceStatus(Device device, long timestamp)
    {
        try
        {
            if (device.getLastTimestampStatusUpdate() >= timestamp)
            {
                device.setLastTimestampStatusUpdate(device.getLastTimestampStatusUpdate() + 1);
            }
            else
            {
                device.setLastTimestampStatusUpdate(timestamp);
            }
            if (Shared.configuration.database != null)
            {
                try
                {
                    Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
                }
                catch (org.postgresql.util.PSQLException exception)
                {
                    if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) || (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
                    {
                        Calendar calendar1 = Calendar.getInstance();
                        calendar1.setTimeInMillis(device.getLastTimestampUpdate());
                        calendar1.set(Calendar.DATE, 1);
                        calendar1.set(Calendar.HOUR_OF_DAY, 0);
                        calendar1.set(Calendar.MINUTE, 0);
                        calendar1.set(Calendar.SECOND, 0);
                        calendar1.set(Calendar.MILLISECOND, 0);
                        SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
                        String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
                        long startdate = calendar1.getTimeInMillis();
                        calendar1.add(Calendar.MONTH, 1);
                        long enddate = calendar1.getTimeInMillis();
                        String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
                        try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
                        executeAlterTableDevicesVacuum(true, tablename);
                        // Do again the insert
                        try
                        {
                            Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
                        }
                        catch (Exception e)
                        {
                        }
                    }
                }
            }
        }
        catch (Exception e)
        {
        }
    }
    public void forceUpdateDeviceStatus(Device device, long timestamp)
    {
        try
        {
            device.forceLastTimestampStatusUpdate(timestamp);
            if (Shared.configuration.database != null)
            {
                try
                {
                    Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
                }
                catch (org.postgresql.util.PSQLException exception)
                {
                    if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) || (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
                    {
                        Calendar calendar1 = Calendar.getInstance();
                        calendar1.setTimeInMillis(device.getLastTimestampUpdate());
                        calendar1.set(Calendar.DATE, 1);
                        calendar1.set(Calendar.HOUR_OF_DAY, 0);
                        calendar1.set(Calendar.MINUTE, 0);
                        calendar1.set(Calendar.SECOND, 0);
                        calendar1.set(Calendar.MILLISECOND, 0);
                        SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
                        String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
                        long startdate = calendar1.getTimeInMillis();
                        calendar1.add(Calendar.MONTH, 1);
                        long enddate = calendar1.getTimeInMillis();
                        String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
                        try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
                        executeAlterTableDevicesVacuum(true, tablename);
                        // Do again the insert
                        try
                        {
                            Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
                        }
                        catch (Exception e)
                        {
                        }
                    }
                }
            }
        }
        catch (Exception e)
        {
        }
    }
    public void updateDevice(Device[] ldevice)
    {
        mutexListDevices.lockWrite();
        try
        {
            for (Device device : ldevice)
            {
                updateDevice(device);
            }
        }
        catch (Exception e)
        {
        }
        mutexListDevices.releaseWrite();
    }
    public void deleteDevices(String[] lidentifier) throws Exception
    {
        int errors = 0;
        for (String identifier : lidentifier)
        {
            getMutex(identifier).lockWrite();
            try
            {
                String where = "identifier = '" + identifier + "' AND type = '" + deviceClassName + "'";
                Shared.controllerDatabase.timeless_deleteObject(DevicePersistenceTimeless.class.getName(), where);
                mutexListDevices.lockWrite();
                {
                    ldevice.remove(mdevice.remove(identifier));
                }
                mutexListDevices.releaseWrite();
            }
            catch (Exception e)
            {
                errors = errors  + 1;
            }
            finally
            {
                getMutex(identifier).releaseWrite();
            }
        }
        if (errors > 0)
        {
            throw new ServerException(Shared.getMessage("Error deleting devices"));
        }
    }
    public Device cloneDevice(String identifier)
    {
        // No hace falta mutex porque los devices se cambia la referencia cada vez. No hay conflicto posible
        Device clon = null;
        try
        {
            clon = (Device)Serialization.clone(getDevice(identifier));
        }
        catch (Exception e)
        {
        }
        try
        {
            clon.realtime = (DeviceRealtime)Serialization.clone(getDevice(identifier).getDeviceRealtime());
        }
        catch (Exception e)
        {
        }
        return clon;
    }
    public Device cloneDevice(Device device)
    {
        try
        {
            return cloneDevice(device.getIdentifier());
        }
        catch (Exception e)
        {
        }
        return null;
    }
    public List<String> getGroups()
    {
        mutexListDevices.lockRead();
        try
        {
            Set<String> groups = new HashSet<>();
            for (Device device : ldevice)
            {
                try
                {
                    if (device.getDeviceInformation().group != null)
                    {
                        groups.add(device.getDeviceInformation().group);
                    }
                }
                catch (Exception e)
                {
                }
            }
            List<String> result = new ArrayList(groups);
            result.sort(String::compareToIgnoreCase);
            return result;
        }
        finally
        {
            mutexListDevices.releaseRead();
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Traces">
    public List<String> getTraceValues(String field, String application) throws Exception
    {
        ResultSet resultset = null;
        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
        List<String> result = new ArrayList<String>();
        try
        {
            {
                String command = "SELECT DISTINCT(" + field + ") FROM traces";
                if (application != null) command = "SELECT DISTINCT(" + field + ") FROM traces WHERE application = '" + application + "'";
                resultset = persistence.executeQuery(command);
                while (resultset.next())
                {
                    result.add(resultset.getString(1));
                }
                resultset.getStatement().close();
                resultset.close();
            }
        }
        catch (Exception exception)
        {
            throw exception;
        }
        finally
        {
            try{resultset.getStatement().close();} catch (Exception e){};
            try{resultset.close();} catch (Exception e){};
        }
        return result;
    }
    public List<Trace> getTraces(String language, long timestampfrom, long timestampto, String application, int limit) throws Exception
    {
        ResultSet resultset = null;
        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
        List<Trace> traces = new ArrayList<Trace>();
        try
        {
            String command = "SELECT value FROM traces WHERE timestamp >= " + timestampfrom + " AND timestamp <  " + timestampto;
            if (application != null) command = command + " AND application = '" + application + "'";
            command = command + " ORDER BY timestamp ASC";
            if (limit > 0) command = command + " LIMIT " + limit;
            resultset = persistence.executeQuery(command);
            while (resultset.next())
            {
                traces.add(((TracePersistance)Serialization.deserialize(TracePersistance.class, resultset.getString(1))).trace);
            }
            return traces;
        }
        finally
        {
            try{resultset.getStatement().close();} catch (Exception e){};
            try{resultset.close();} catch (Exception e){};
        }
    }
    private String getFilterEventController(String filter)
    {
        /*
        */
        try
        {
            String result = filter;
            return(result);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return(filter);
    }
    public TraceResult getEventsController(String language, long timestampfrom, long timestampto, int type, int limit, int offset, String filter, boolean viewTrolleyEvents, boolean viewMasterSlaveEvents) throws Exception
    {
        ResultSet resultset = null;
        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
        TraceResult result = new TraceResult();
        result.timestampfrom = timestampfrom;
        result.timestampto = timestampto;
        result.limit = limit;
        result.offset = offset;
        result.type = type;
        result.traces = new ArrayList<Trace>();
        try
        {
            String command = "SELECT COUNT(*) FROM traces WHERE timestamp >= " + timestampfrom + " AND timestamp <  " + timestampto;
            if (type > -1) command = command + " AND type = " + type;
            // if (filter != null) command = command + " AND " + getFilterEventController(filter.substring(0, filter.indexOf("ORDER")));
            resultset = persistence.executeQuery(command);
            if (resultset.next())
            {
                result.total = resultset.getInt(1);
            }
            try{resultset.close();} catch (Exception e){};
            command = "SELECT value FROM traces WHERE timestamp >= " + timestampfrom + " AND timestamp <  " + timestampto;
            if (type > -1) command = command + " AND type = " + type;
//            if (order == 1) command = command + " ORDER BY timestamp ASC";
//            else if (order == -1) command = command + " ORDER BY timestamp DESC";
            command = command + " ORDER BY timestamp DESC";
            // if (filter != null) command = command + " AND " + getFilterEventController(filter);
            if (limit > 0) command = command + " LIMIT " + limit;
            if (offset > -1) command = command + " OFFSET " + offset;
            System.out.println(command);
            resultset = persistence.executeQuery(command);
            while (resultset.next())
            {
                TracePersistance tracePersistance = Serialization.deserialize(TracePersistance.class, resultset.getString(1));
                if (tracePersistance.trace != null)
                {
                    result.traces.add(tracePersistance.trace);
                }
                else
                {
                    Trace trace = Serialization.deserialize(Trace.class, resultset.getString(1));
                    if (trace != null)
                    {
                        result.traces.add(trace);
                    }
                }
            }
            return result;
        }
        finally
        {
            try{resultset.getStatement().close();} catch (Exception e){};
            try{resultset.close();} catch (Exception e){};
        }
    }
    public TraceResult getTraces(String language, long timestampfrom, long timestampto, int type, int limit, int offset, int order, boolean viewTrolleyEvents, boolean viewMasterSlaveEvents) throws Exception
    {
        ResultSet resultset = null;
        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
        TraceResult result = new TraceResult();
        result.timestampfrom = timestampfrom;
        result.timestampto = timestampto;
        result.limit = limit;
        result.offset = offset;
        result.type = type;
        result.traces = new ArrayList<Trace>();
        try
        {
            String command = "SELECT COUNT(*) FROM traces WHERE timestamp >= " + timestampfrom + " AND timestamp <  " + timestampto;
            if (type > -1) command = command + " AND type = " + type;
            resultset = persistence.executeQuery(command);
            if (resultset.next())
            {
                result.total = resultset.getInt(1);
            }
            try{resultset.close();} catch (Exception e){};
            command = "SELECT value FROM traces WHERE timestamp >= " + timestampfrom + " AND timestamp <  " + timestampto;
            if (type > -1) command = command + " AND type = " + type;
            if (order == 1) command = command + " ORDER BY timestamp ASC";
            else if (order == -1) command = command + " ORDER BY timestamp DESC";
            if (limit > 0) command = command + " LIMIT " + limit;
            if (offset > -1) command = command + " OFFSET " + offset;
            System.out.println(command);
            resultset = persistence.executeQuery(command);
            while (resultset.next())
            {
                TracePersistance tracePersistance = Serialization.deserialize(TracePersistance.class, resultset.getString(1));
                if (tracePersistance.trace != null)
                {
                    result.traces.add(tracePersistance.trace);
                }
                else
                {
                    Trace trace = Serialization.deserialize(Trace.class, resultset.getString(1));
                    if (trace != null)
                    {
                        result.traces.add(trace);
                    }
                }
            }
            return result;
        }
        finally
        {
            try{resultset.getStatement().close();} catch (Exception e){};
            try{resultset.close();} catch (Exception e){};
        }
    }
    public TraceResult getTraces(TraceResult traceresult) throws Exception
    {
        ResultSet resultset = null;
        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
        try
        {
            {
                String command = "SELECT COUNT(*) FROM traces WHERE timestamp >= " + traceresult.timestampfrom + " AND timestamp <=  " + traceresult.timestampto;
                if (traceresult.type != Trace.TRACE_NONE) command = command + " AND type = '" + traceresult.type + "'";
                if (traceresult.username != null) command = command + " AND username = '" + traceresult.username + "'";
                if (traceresult.application != null) command = command + " AND application = '" + traceresult.application + "'";
                if (traceresult.service != null) command = command + " AND service = '" + traceresult.service + "'";
                resultset = persistence.executeQuery(command);
                resultset.next();
                traceresult.total = resultset.getLong(1);
                resultset.getStatement().close();
                resultset.close();
            }
            {
                String command = "SELECT value FROM traces WHERE timestamp >= " + traceresult.timestampfrom + " AND timestamp <=  " + traceresult.timestampto;
                if (traceresult.type != Trace.TRACE_NONE) command = command + " AND type = '" + traceresult.type + "'";
                if (traceresult.username != null) command = command + " AND username = '" + traceresult.username + "'";
                if (traceresult.application != null) command = command + " AND application = '" + traceresult.application + "'";
                if (traceresult.service != null) command = command + " AND service = '" + traceresult.service + "'";
                command = command + " ORDER BY timestamp ASC OFFSET " + traceresult.offset + " LIMIT " + traceresult.limit;
                resultset = persistence.executeQuery(command);
                while (resultset.next())
                {
                    traceresult.traces.add(((TracePersistance)Serialization.deserialize(TracePersistance.class, resultset.getString(1))).trace);
                }
                resultset.getStatement().close();
                resultset.close();
            }
        }
        finally
        {
            try{resultset.getStatement().close();} catch (Exception e){};
            try{resultset.close();} catch (Exception e){};
        }
        return traceresult;
    }
    public List<Trace> getLastTraces(String language, String application, int limit) throws Exception
    {
        ResultSet resultset = null;
        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
        List<Trace> traces = new ArrayList<Trace>();
        try
        {
            String command = "SELECT value FROM traces ";
            if (application != null) command = command + " WHERE application = '" + application + "'";
            command = command + " ORDER BY timestamp DESC";
            if (limit > 0) command = command + " LIMIT " + limit;
            resultset = persistence.executeQuery(command);
            while (resultset.next())
            {
                traces.add(((TracePersistance)Serialization.deserialize(TracePersistance.class, resultset.getString(1))).trace);
            }
            return traces;
        }
        finally
        {
            try{resultset.getStatement().close();} catch (Exception e){};
            try{resultset.close();} catch (Exception e){};
        }
    }
    // </editor-fold>
    public EventTrolleyResult getEventsTrolley(String language, long timestampfrom, long timestampto, int type, int limit, int offset, int order) throws Exception
    {
        ResultSet resultset = null;
        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
        EventTrolleyResult result = new EventTrolleyResult();
        result.timestampfrom = timestampfrom;
        result.timestampto = timestampto;
        result.limit = limit;
        result.offset = offset;
        result.type = type;
        result.events = new ArrayList<EventTrolley>();
        try
        {
            String command = "SELECT COUNT(*) FROM eventstrolley WHERE activation >= " + timestampfrom + " AND activation <  " + timestampto;
            if (type > -1) command = command + " AND type = " + type;
            resultset = persistence.executeQuery(command);
            if (resultset.next())
            {
                result.total = resultset.getInt(1);
            }
            try{resultset.close();} catch (Exception e){};
            command = "SELECT value FROM eventstrolley WHERE activation >= " + timestampfrom + " AND activation <  " + timestampto;
            if (type > -1) command = command + " AND type = " + type;
            if (order == 1) command = command + " ORDER BY activation ASC";
            else if (order == -1) command = command + " ORDER BY activation DESC";
            if (limit > 0) command = command + " LIMIT " + limit;
            if (offset > -1) command = command + " OFFSET " + offset;
            System.out.println(command);
            resultset = persistence.executeQuery(command);
            while (resultset.next())
            {
                result.events.add(((EventTrolley)Serialization.deserialize(EventTrolley.class, resultset.getString(1))));
            }
            return result;
        }
        finally
        {
            try{resultset.getStatement().close();} catch (Exception e){};
            try{resultset.close();} catch (Exception e){};
        }
    }
    // <editor-fold defaultstate="collapsed" desc="Symbols">
    public void readSymbols() throws Exception
    {
        mutexListSymbols.lockWrite();
        try
        {
            // for (int i=0; i<32; i++)
            for (float i=0; i<32; i+=0.5f)
            {
                for (String symbolName : Shared.configuration.symbols)
                {
                    DeviceSymbol symbol = new DeviceSymbol();
                    symbol.type = deviceClassName;
                    symbol.name = symbolName;
                    symbol.zoom = i;
                    int zoom = (int)i;
                    String resourceName = "data/" + Shared.getApplicationName() + "/symbols/" + i + "/" + symbolName + ".svg";
                    if (zoom == i)
                    {
                        resourceName = "data/" + Shared.getApplicationName() + "/symbols/" + zoom + "/" + symbolName + ".svg";
                    }
                    // String resourceName = "data/" + Shared.getApplicationName() + "/symbols/" + i + "/" + symbolName + ".svg";
                    File file = new File(resourceName);
                    if (file.exists() == true)
                    {
                        symbol.dataSVG = Files.readAllBytes(file.toPath());
                    }
                    else
                    {
                        symbol.dataSVG = Resources.getResourceBytes(resourceName);
                    }
                    if (symbol.dataSVG.length > 0)
                    {
                        lsymbols.add(symbol);
                    }
                }
            }
        }
        catch (Exception exception)
        {
            Shared.println(Shared.getMessage("Model"), exception);
        }
        finally
        {
            mutexListSymbols.releaseWrite();
        }
    }
    public DeviceSymbol[] getSymbols()
    {
        mutexListSymbols.lockRead();
        try
        {
            return lsymbols.toArray(new DeviceSymbol[lsymbols.size()]);
        }
        finally
        {
            mutexListSymbols.releaseRead();
        }
    }
    public DeviceSymbol[] getSymbols(long timestamp)
    {
        if (configurationSymbolsTimestamp > timestamp)
        {
            return getSymbols();
        }
        else
        {
            return new DeviceSymbol[0];
        }
    }
    public List<Object> getSymbolsNames(String type)
    {
        List<Object> result  = new ArrayList<Object> ();
        mutexListSymbols.lockRead();
        try
        {
            result.add("");
            for (DeviceSymbol symbol : lsymbols)
            {
                if (symbol.type.equalsIgnoreCase(type))
                {
                    result.add(symbol.name);
                }
            }
        }
        finally
        {
            mutexListSymbols.releaseRead();
        }
        return result;
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Application">
    public Application getApplicationService(String serviceName)
    {
        try
        {
            Device[] devices = getDevicesExternal(Application.class.getName());
            for (Device device : devices)
            {
                if (device instanceof Application)
                {
                    Application application = (Application)device;
                    if (application.getDeviceInformation().serverServiceName.equalsIgnoreCase(serviceName) == true)
                    {
                        return(application);
                    }
                }
            }
        }
        catch (Exception exception)
        {
        }
        return(null);
    }
    public Application[] getApplication(long timestamp) throws Exception
    {
        Application application = Shared.controllerStatus.getApplication();
        if (application.getLastTimestampUpdate() > timestamp)
        {
            return new Application[]{application};
        }
        return new Application[0];
    }
    public Application[] getApplication(long  timestamp1, long timestamp2) throws Exception
    {
        // Without mutex read, we are consulting historical database
        String identifier   =  Shared.controllerStatus.getApplication().getIdentifier();
        String where = "type = '" + deviceClassName + "' AND timestamp > " + timestamp1 + " AND timestamp < " + timestamp2;
        if (identifier != null)
        {
            if (identifier.length() > 0)
            {
                where = where + " AND identifier = '" + identifier + "'";
            }
        }
        List<Device> result = (List<Device>)DevicePersistenceHistorical.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.historical_getObject(DevicePersistenceHistorical.class.getName(), where));
        return result.toArray(new Application[result.size()]);
    }
    // A esta función sólo llama el servidor
    public void updateApplication(Application application)
    {
        // No metemos en exclusion, no podemos tener varias llamadas a la vez
        // Se controla en el ControllerStatus
        if (Shared.configuration.database != null)
        {
            try { Shared.controllerDatabase.timeless_updateOrAddObject(new DevicePersistenceTimeless(application)); } catch (Exception e) { }
            try
            {
                Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(application));
            }
            catch (org.postgresql.util.PSQLException exception)
            {
                if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
                    (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
                {
                    Calendar calendar1 = Calendar.getInstance();
                    calendar1.setTimeInMillis(application.getLastTimestampUpdate());
                    calendar1.set(Calendar.DATE, 1);
                    calendar1.set(Calendar.HOUR_OF_DAY, 0);
                    calendar1.set(Calendar.MINUTE, 0);
                    calendar1.set(Calendar.SECOND, 0);
                    calendar1.set(Calendar.MILLISECOND, 0);
                    SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
                    String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
                    long startdate = calendar1.getTimeInMillis();
                    calendar1.add(Calendar.MONTH, 1);
                    long enddate = calendar1.getTimeInMillis();
                    String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
                    try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
                    executeAlterTableDevicesVacuum(true, tablename);
                    // Do again the insert
                    try
                    {
                        Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(application));
                    }
                    catch (Exception e)
                    {
                        Shared.println(Shared.getMessage("Model"), e);
                    }
                }
            }
            catch (Exception e)
            {
            }
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Actions">
    public void addAction(DeviceAction action)
    {
        if (Shared.configuration.database != null)
        {
            // Insert action
            try
            {
                DevicePersistenceAction persistenceAction = new DevicePersistenceAction(action);
                try
                {
                    Shared.controllerDatabase.historical_addObject(persistenceAction);
                }
                catch (org.postgresql.util.PSQLException exception)
                {
                    if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
                        (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
                    {
                        Calendar calendar1 = Calendar.getInstance();
                        calendar1.setTimeInMillis(action.requestTimestamp);
                        calendar1.set(Calendar.DATE, 1);
                        calendar1.set(Calendar.HOUR_OF_DAY, 0);
                        calendar1.set(Calendar.MINUTE, 0);
                        calendar1.set(Calendar.SECOND, 0);
                        calendar1.set(Calendar.MILLISECOND, 0);
                        SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
                        String tablename = "actions_" + formato1.format(calendar1.getTimeInMillis());
                        long startdate = calendar1.getTimeInMillis();
                        calendar1.add(Calendar.MONTH, 1);
                        long enddate = calendar1.getTimeInMillis();
                        String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF actions FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
                        try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
                        executeAlterTableActionsVacuum(true, tablename);
                        // Do again the insert
                        try
                        {
                            Shared.controllerDatabase.historical_addObject(persistenceAction);
                        }
                        catch (Exception e)
                        {
                            Shared.println(Shared.getMessage("Model"), e);
                        }
                    }
                }
                catch (Exception e)
                {
                }
            }
            catch (Exception e)
            {
            }
        }
    }
    public List<DeviceAction> getActions()
    {
        return getActions(null);
    }
    public List<DeviceAction> getActions(long  timestamp1, long timestamp2)
    {
        String where = "timestamp > " + timestamp1 + " AND timestamp < " + timestamp2;
        return getActions(where);
    }
    public List<DeviceAction> getActions(long  timestamp1, long timestamp2, String where)
    {
        return getActions("timestamp > " + timestamp1 + " AND timestamp < " + timestamp2 + " AND " + where);
    }
    public List<DeviceAction> getActions(String where)
    {
        List<DeviceAction> result = null;
        try
        {
            if (Shared.configuration.database != null)
            {
                if (where == null)
                {
                    result = (List<DeviceAction>)DevicePersistenceAction.getActions((List<Object>)(List<?>)Shared.controllerDatabase.historical_getObject(DevicePersistenceAction.class.getName()));
                }
                else
                {
                    result = (List<DeviceAction>)DevicePersistenceAction.getActions((List<Object>)(List<?>)Shared.controllerDatabase.historical_getObject(DevicePersistenceAction.class.getName(), where));
                }
            }
        }
        catch (Exception e)
        {
        }
        return result;
    }
    // </editor-fold>
    public void executeAlterTableDevicesVacuum(boolean vacuum, String tablename)
    {
        try
        {
            String enabled = "true";
            if (vacuum == false) enabled = "false";
            String autovacuum_enabled = art.servers.Shared.getPropertyValueString("devices.autovacuum_enabled");
            String autovacuum_vacuum_scale_factor = art.servers.Shared.getPropertyValueString("devices.autovacuum_vacuum_scale_factor");
            String autovacuum_vacuum_threshold = art.servers.Shared.getPropertyValueString("devices.autovacuum_vacuum_threshold");
            String autovacuum_analyze_scale_factor = art.servers.Shared.getPropertyValueString("devices.autovacuum_analyze_scale_factor");
            String autovacuum_analyze_threshold = art.servers.Shared.getPropertyValueString("devices.autovacuum_analyze_threshold");
            if (autovacuum_enabled == null) autovacuum_enabled = enabled;
            if (autovacuum_vacuum_scale_factor == null) autovacuum_vacuum_scale_factor = "0.0";
            if (autovacuum_vacuum_threshold == null) autovacuum_vacuum_threshold = "1000";
            if (autovacuum_analyze_scale_factor == null) autovacuum_analyze_scale_factor = "0.0";
            if (autovacuum_analyze_threshold == null) autovacuum_analyze_threshold = "1000";
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_enabled = " + enabled + ", toast.autovacuum_enabled = " + enabled + ")");} catch (Exception e){};
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_vacuum_scale_factor = 0.0)");} catch (Exception e){};
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_vacuum_threshold = 1000)");} catch (Exception e){};
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_analyze_scale_factor = 0.0)");} catch (Exception e){};
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_analyze_threshold = 1000)");} catch (Exception e){};
        }
        catch (Exception exception)
        {
        }
    }
    public void executeAlterTableActionsVacuum(boolean vacuum, String tablename)
    {
        try
        {
            String enabled = "true";
            if (vacuum == false) enabled = "false";
            String autovacuum_enabled = art.servers.Shared.getPropertyValueString("actions.autovacuum_enabled");
            String autovacuum_vacuum_scale_factor = art.servers.Shared.getPropertyValueString("actions.autovacuum_vacuum_scale_factor");
            String autovacuum_vacuum_threshold = art.servers.Shared.getPropertyValueString("actions.autovacuum_vacuum_threshold");
            String autovacuum_analyze_scale_factor = art.servers.Shared.getPropertyValueString("actions.autovacuum_analyze_scale_factor");
            String autovacuum_analyze_threshold = art.servers.Shared.getPropertyValueString("actions.autovacuum_analyze_threshold");
            if (autovacuum_enabled == null) autovacuum_enabled = enabled;
            if (autovacuum_vacuum_scale_factor == null) autovacuum_vacuum_scale_factor = "0.0";
            if (autovacuum_vacuum_threshold == null) autovacuum_vacuum_threshold = "1000";
            if (autovacuum_analyze_scale_factor == null) autovacuum_analyze_scale_factor = "0.0";
            if (autovacuum_analyze_threshold == null) autovacuum_analyze_threshold = "1000";
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_enabled = " + enabled + ", toast.autovacuum_enabled = " + enabled + ")");} catch (Exception e){};
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_vacuum_scale_factor = 0.0)");} catch (Exception e){};
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_vacuum_threshold = 1000)");} catch (Exception e){};
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_analyze_scale_factor = 0.0)");} catch (Exception e){};
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_analyze_threshold = 1000)");} catch (Exception e){};
        }
        catch (Exception exception)
        {
        }
    }
    public void executeAlterTableTracesVacuum(boolean vacuum, String tablename)
    {
        try
        {
            String enabled = "true";
            if (vacuum == false) enabled = "false";
            String autovacuum_enabled = art.servers.Shared.getPropertyValueString("traces.autovacuum_enabled");
            String autovacuum_vacuum_scale_factor = art.servers.Shared.getPropertyValueString("traces.autovacuum_vacuum_scale_factor");
            String autovacuum_vacuum_threshold = art.servers.Shared.getPropertyValueString("traces.autovacuum_vacuum_threshold");
            String autovacuum_analyze_scale_factor = art.servers.Shared.getPropertyValueString("traces.autovacuum_analyze_scale_factor");
            String autovacuum_analyze_threshold = art.servers.Shared.getPropertyValueString("traces.autovacuum_analyze_threshold");
            if (autovacuum_enabled == null) autovacuum_enabled = enabled;
            if (autovacuum_vacuum_scale_factor == null) autovacuum_vacuum_scale_factor = "0.0";
            if (autovacuum_vacuum_threshold == null) autovacuum_vacuum_threshold = "1000";
            if (autovacuum_analyze_scale_factor == null) autovacuum_analyze_scale_factor = "0.0";
            if (autovacuum_analyze_threshold == null) autovacuum_analyze_threshold = "1000";
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_enabled = " + enabled + ", toast.autovacuum_enabled = " + enabled + ")");} catch (Exception e){};
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_vacuum_scale_factor = 0.0)");} catch (Exception e){};
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_vacuum_threshold = 1000)");} catch (Exception e){};
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_analyze_scale_factor = 0.0)");} catch (Exception e){};
            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_analyze_threshold = 1000)");} catch (Exception e){};
        }
        catch (Exception exception)
        {
        }
    }
    private long getLastTimestamp(String identifier, long timestamp1) throws ServerException, Exception
    {
        ResultSet result = null;
        try
        {
            String where = "type = '" + deviceClassName + "' AND timestamp <= " + timestamp1;
            if (identifier != null)
            {
                if (identifier.length() > 0)
                {
                    where = where + " AND identifier = '" + identifier + "'";
                }
            }
            String command = "SELECT timestamp FROM DEVICES WHERE " + where + " ORDER BY timestamp DESC limit 1";
            result = Shared.controllerDatabase.getHistoricalPersistance().get(0).executeQuery(command);
            result.next();
            long timestamp = result.getLong(1);
            return(timestamp);
        }
        catch (Exception e)
        {
            return(timestamp1);
        }
        finally
        {
           try { result.close(); } catch (Exception e) {};
        }
    }
    protected Mutex getMutex(Device device)
    {
        return getMutex(device.getIdentifier());
    }
    protected Mutex getMutex(String identifier)
    {
        Mutex mutex = (Mutex)mmutex.get(identifier);
        if (mutex == null)
        {
            mutex = new Mutex();
            mmutex.put(identifier, mutex);
        }
        return mutex;
    }
}
servers/server/src/art/servers/Server.java
New file
@@ -0,0 +1,450 @@
package art.servers;
import art.library.gui.FlatGUI;
import art.library.gui.flat.FlatDialog;
import art.library.interop.serialization.Serialization;
import art.library.model.devices.application.Application;
import art.library.model.devices.application.ApplicationAlarms;
import art.library.model.devices.application.ApplicationRealtime;
import art.library.model.devices.application.ApplicationStatus;
import art.library.persistence.PersistenceDatabaseParameters;
import art.library.utils.ArticProcesses;
import art.library.utils.licence.Licence;
import art.library.utils.resources.Resources;
import art.library.utils.windows.SystemProcess;
import art.servers.configuration.Configuration;
import art.servers.controller.ControllerDatabase;
import art.servers.controller.ControllerListener;
import art.servers.controller.ControllerListenerDebug;
import art.servers.controller.ControllerListenerHttp;
import art.servers.controller.ControllerListenerHttps;
import art.servers.controller.ControllerNtpHttp;
import art.servers.controller.ControllerProcessInformation;
import art.servers.controller.ControllerStatus;
import art.servers.controller.ControllerTransactions;
import art.servers.controller.ControllerUserPermissions;
import art.servers.gui.ArticWindow;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.io.File;
import java.io.FileOutputStream;
import java.net.InetAddress;
import java.security.cert.X509Certificate;
import java.util.Properties;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
public class Server
{
    public static void preinitialise(String[] args) throws Exception
    {
        preinitialise(args, Configuration.class);
    }
    public static void preinitialise(String[] args, Class configurationClass) throws Exception
    {
        Shared.debug = existParameter(args, "-debug");
        Shared.reloadDevices = existParameter(args, "--reload");
        Shared.restoreDevices = existParameter(args, "--restore");
        // Look and feel
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        // SSL accept key
        TrustManager[] trustAllCerts = new TrustManager[] {new MyTrustManager()};
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HostnameVerifier allHostsValid = new HostnameVerifier()
        {
            public boolean verify(String hostname, SSLSession session)
            {
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        // Configuration
        String configurationFile = getParameter(args, "-config");
        if (configurationFile != null)
        {
            Shared.configuration = (Configuration)Serialization.deserialize(configurationClass, new File(configurationFile));
        }
        else if (new File(Shared.getApplicationName() + ".json").exists())
        {
            Shared.configuration = (Configuration)Serialization.deserialize(configurationClass, new File(Shared.getApplicationName() + ".json"));
        }
        else
        {
            Shared.configuration = (Configuration)Serialization.deserialize(configurationClass, Resources.getResourceStream("data/" + Shared.getApplicationName() + ".json"));
        }
        if (existParameter(args, "-nogui") == false)
        {
            FlatGUI.initialise(Shared.configuration.general.language);
        }
        // Properties
        if (Shared.configuration.general.mproperties != null)
        {
            Properties properties = System.getProperties();
            for (String key : Shared.configuration.general.mproperties.keySet())
            {
                String value = Shared.configuration.general.mproperties.get(key);
                properties.setProperty(key, value);
            }
            System.setProperties(properties);
        }
        // License
        boolean license = true;
        if (existParameter(args, "-code") == true)
        {
            license = getParameter(args, "-code").equals(Shared.getApplicationCode());
        }
        if (existParameter(args, "--license") == true)
        {
            String password = getParameter(args, "--license");
            if ((password.equalsIgnoreCase("¡¡register!!") == true) || (password.equalsIgnoreCase("**register**") == true))
            {
                FileOutputStream fos = new FileOutputStream(new File(Shared.getApplicationName() + ".license"));
                fos.write(Licence.licenceGeneration(Licence.codeGeneration(Shared.getApplicationCode())).getBytes());
                fos.close();
            }
        }
        if (license == false)
        {
            if (Licence.hasLicence(Shared.getApplicationCode(), new File(Shared.getApplicationName() + ".license")) == false)
            {
                codeGeneration();
            }
        }
        // User and password database desencryption
        if (Shared.configuration.database != null)
        {
            for (PersistenceDatabaseParameters parameters : Shared.configuration.database)
            {
                parameters.user = Licence.decrypt(parameters.user);
                parameters.password = Licence.decrypt(parameters.password);
            }
        }
        // Application device, status
        Application application = new Application(Shared.configuration.application);
        application.status = new ApplicationStatus();
        application.alarms = new ApplicationAlarms();
        if (Shared.configuration.listener != null)
        {
            application.information.serverAddressExternal = Shared.configuration.listener.addressExternal;
            application.information.serverPortExternal = Shared.configuration.listener.portExternal;
        }
        Shared.controllerStatus = new ControllerStatus(application);
        Shared.lcontroller.add(Shared.controllerStatus);
        if (Shared.configuration.listener != null)
        {
            application.getDeviceInformation().serverAddress = Shared.configuration.listener.address;
            application.getDeviceInformation().serverPort = Shared.configuration.listener.port;
        }
        else
        {
            application.getDeviceInformation().serverAddress = InetAddress.getLocalHost().getHostAddress();
            application.getDeviceInformation().serverPort = 0;
        }
        // Is already running
        if (Shared.configuration.general.executableName != null)
        {
            long pid = ArticProcesses.getPID();
            for (SystemProcess process : ArticProcesses.getProcesses(Shared.configuration.general.executableName))
            {
                if (process.pid != pid)
                {
                    if (existParameter(args, "-nogui") == false)
                    {
                        JOptionPane.showMessageDialog(null, Shared.getMessage("Process %1 already opened").replace("%1", Shared.configuration.general.executableName), Shared.getMessage("Error"), JOptionPane.ERROR_MESSAGE);
                    }
                    else
                    {
                        System.out.println(Shared.getMessage("Process %1 already opened").replace("%1", Shared.configuration.general.executableName));
                    }
                    System.exit(0);
                }
            }
        }
        // Controller database
        if (Shared.configuration.database != null)
        {
            Shared.controllerDatabase = new ControllerDatabase(Shared.configuration);
            Shared.lcontroller.add(Shared.controllerDatabase);
        }
        // Controller user permissions
        Shared.controllerUserPermissions = new ControllerUserPermissions();
        // Controller process information
        Shared.controllerProcessInformation = new ControllerProcessInformation();
        // Controller transactions
        if (Shared.configuration.transactions != null)
        {
            Shared.controllerTransactions = new ControllerTransactions(Shared.configuration.transactions);
            Shared.lcontroller.add(Shared.controllerTransactions);
        }
        // Controller NTP HTTP
        if (Shared.configuration.controllerNTPHTTP != null)
        {
            Shared.controllerNtpHttp = new ControllerNtpHttp(Shared.configuration.controllerNTPHTTP);
            Shared.lcontroller.add(Shared.controllerNtpHttp);
        }
    }
    public static void postinitialise(String[] args) throws Exception
    {
        // Graphical interface
        if (existParameter(args, "-nogui") == false)
        {
            GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
            int screenWidth = gd.getDisplayMode().getWidth();
            int screenHeight = gd.getDisplayMode().getHeight();
            Shared.window = new ArticWindow();
            Shared.window.setLocation(Shared.configuration.general.windowX, Shared.configuration.general.windowY);
            Shared.window.setSize(Math.min(Shared.configuration.general.windowW, screenWidth), Math.min(Shared.configuration.general.windowH, screenHeight));
        }
        // Controller listener aluvisa
        if (Shared.configuration.listener != null)
        {
            Shared.controllerListener = new ControllerListener(Shared.configuration.listener);
            Shared.lcontroller.add(Shared.controllerListener);
        }
        // Controller listener http
        if (Shared.configuration.listenerHttp != null)
        {
            if (Shared.configuration.listenerHttp.readUser != null) Shared.configuration.listenerHttp.readUser = Licence.decrypt(Shared.configuration.listenerHttp.readUser);
            if (Shared.configuration.listenerHttp.readPassword != null) Shared.configuration.listenerHttp.readPassword = Licence.decrypt(Shared.configuration.listenerHttp.readPassword);
            if (Shared.configuration.listenerHttp.writeUser != null) Shared.configuration.listenerHttp.writeUser = Licence.decrypt(Shared.configuration.listenerHttp.writeUser);
            if (Shared.configuration.listenerHttp.writePassword != null) Shared.configuration.listenerHttp.writePassword = Licence.decrypt(Shared.configuration.listenerHttp.writePassword);
            Shared.controllerListenerHttp = new ControllerListenerHttp(Shared.configuration.listenerHttp);
            Shared.lcontroller.add(Shared.controllerListenerHttp);
        }
        // Controller listener https
        if (Shared.configuration.listenerHttps != null)
        {
            if (Shared.configuration.listenerHttps.readUser != null) Shared.configuration.listenerHttps.readUser = Licence.decrypt(Shared.configuration.listenerHttps.readUser);
            if (Shared.configuration.listenerHttps.readPassword != null) Shared.configuration.listenerHttps.readPassword = Licence.decrypt(Shared.configuration.listenerHttps.readPassword);
            if (Shared.configuration.listenerHttps.writeUser != null) Shared.configuration.listenerHttps.writeUser = Licence.decrypt(Shared.configuration.listenerHttps.writeUser);
            if (Shared.configuration.listenerHttps.writePassword != null) Shared.configuration.listenerHttps.writePassword = Licence.decrypt(Shared.configuration.listenerHttps.writePassword);
            if (Shared.configuration.listenerHttps.keystorePassword != null) Shared.configuration.listenerHttps.keystorePassword = Licence.decrypt(Shared.configuration.listenerHttps.keystorePassword);
            Shared.controllerListenerHttps = new ControllerListenerHttps(Shared.configuration.listenerHttps);
            Shared.lcontroller.add(Shared.controllerListenerHttps);
        }
        // Controller listener debug
        if (Shared.configuration.debug != null)
        {
            Shared.controllerListenerDEBUG = new ControllerListenerDebug(Shared.configuration.debug);
            Shared.controllerListenerDEBUG.start();
        }
        else if (Shared.configuration.logger != null)
        {
            Shared.controllerListenerDEBUG = new ControllerListenerDebug(Shared.configuration.logger);
            Shared.controllerListenerDEBUG.start();
        }
        // Start controller status
        Shared.controllerStatus.start();
        try
        {
            Application application = Shared.controllerStatus.getApplication();
            ApplicationRealtime realtime = (ApplicationRealtime)application.getDeviceRealtime();
            realtime.traces = Shared.model.getLastTraces(Shared.getLanguage(), Shared.getApplicationName(), ApplicationRealtime.MAX_TRACES);
        }
        catch (Exception exception)
        {
        }
        // Version
        System.out.println(Shared.getApplicationName() + ", version " + Shared.version());
        Shared.printVersion("art.library.adf", "adf.version.properties");
        Shared.printVersion("art.library.andigo", "andigo.version.properties");
        Shared.printVersion("art.library.flatgui", "flatgui.version.properties");
        Shared.printVersion("art.library.interop", "interop.version.properties");
        Shared.printVersion("art.library.model", "model.version.properties");
        Shared.printVersion("art.library.net", "net.version.properties");
        Shared.printVersion("art.library.osm", "osm.version.properties");
        Shared.printVersion("art.library.persistence", "persistence.version.properties");
        Shared.printVersion("art.library.server", "server.version.properties");
        Shared.printVersion("art.library.utils", "utils.version.properties");
    }
    public static String getParameter(String arguments[], String parameter)
    {
        try
        {
            for (int i=0; i<arguments.length; i++)
            {
               if (arguments[i].equalsIgnoreCase(parameter))
               {
                   return arguments[i+1];
               }
            }
        }
        catch (Exception e)
        {
        }
        return  null;
    }
    public static boolean existParameter(String arguments[], String parameter)
    {
        try
        {
            for (int i=0; i<arguments.length; i++)
            {
               if (arguments[i].equalsIgnoreCase(parameter))
               {
                   return true;
               }
            }
        }
        catch (Exception e)
        {
        }
        return  false;
    }
    public static void codeGeneration()
    {
        try
        {
            String code = Licence.codeGeneration(Shared.getApplicationCode());
            StringSelection stringSelection = new StringSelection(code);
            Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard();
            clpbrd.setContents(stringSelection, null);
            String message = Shared.getMessage("Copy below code and send to provider to activate product");
            message = message + "\n\n" + code + "\n\n";
            System.out.println(message);
            FlatDialog.showDialog(null, Shared.getMessage("License code"), message, true, FlatDialog.DIALOG_INFORMATION);
        }
        catch (Exception e)
        {
            try
            {
                String message = Shared.getMessage("Error in licence generation");
                message = message + "\n";
                message = message + Shared.getMessage("Contact provider to solve the problem");
                System.out.println(message);
                FlatDialog.showDialog(null, Shared.getMessage("Error"), message, true, FlatDialog.DIALOG_ERROR);
            }
            catch (Exception exception)
            {
            }
        }
        System.exit(0);
    }
    private static class MyTrustManager implements X509TrustManager
    {
        public java.security.cert.X509Certificate[] getAcceptedIssuers()
        {
            return null;
        }
        public void checkClientTrusted(X509Certificate[] certs, String authType)
        {
        }
        public void checkServerTrusted(X509Certificate[] certs, String authType)
        {
        }
    }
}
servers/server/src/art/servers/ServerException.java
New file
@@ -0,0 +1,36 @@
package art.servers;
import java.io.PrintWriter;
import java.io.StringWriter;
public class ServerException extends Exception
{
    private String message = null;
    public ServerException(String message)
    {
        this.message = message;
    }
    public ServerException(Exception exception)
    {
        this.message = exception.getMessage();
    }
    public String getMessage()
    {
        if (message != null) return message;
        return "Unexpected error";
    }
    public String getStackMessage()
    {
        StringWriter sw = new StringWriter();
        printStackTrace(new PrintWriter(sw));
        return (sw.toString());
    }
}
servers/server/src/art/servers/Shared.java
New file
@@ -0,0 +1,684 @@
package art.servers;
import art.library.model.devices.Device;
import art.library.model.devices.user.UserPermission;
import art.library.model.transactions.traces.Note;
import art.library.model.transactions.traces.Trace;
import art.library.utils.licence.Licence;
import art.library.utils.mail.MailMessage;
import art.library.utils.mail.SMTP;
import art.library.utils.mail.SMTPConfiguration;
import art.library.utils.resources.Resources;
import art.library.utils.synchro.Mutex;
import art.servers.configuration.Configuration;
import art.servers.controller.Controller;
import art.servers.controller.ControllerDatabase;
import art.servers.controller.ControllerDevice;
import art.servers.controller.ControllerListener;
import art.servers.controller.ControllerListenerDebug;
import art.servers.controller.ControllerListenerHttp;
import art.servers.controller.ControllerListenerHttps;
import art.servers.controller.ControllerNtpHttp;
import art.servers.controller.ControllerProcessInformation;
import art.servers.controller.ControllerStatus;
import art.servers.controller.ControllerTransactions;
import art.servers.controller.ControllerUserPermissions;
import art.servers.controller.FactoryController;
import art.servers.gui.ArticWindow;
import art.servers.types.HttpAuthentication;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class Shared
{
    private static String applicationCode = null;
    private static String applicationName = null;
    public static boolean debug = false;
    public static boolean reloadDevices = false;
    public static boolean restoreDevices = false;
    public static Configuration configuration = null;
    public static Model model = null;
    public static FactoryController factory = null;
    public static ControllerStatus controllerStatus = null;
    public static ControllerDatabase controllerDatabase = null;
    public static ControllerListener controllerListener = null;
    public static ControllerTransactions controllerTransactions = null;
    public static ControllerListenerHttp controllerListenerHttp = null;
    public static ControllerListenerHttps controllerListenerHttps = null;
    public static ControllerUserPermissions controllerUserPermissions = null;
    public static ControllerProcessInformation controllerProcessInformation = null;
    public static ControllerNtpHttp controllerNtpHttp = null;
    public static List<Controller> lcontroller = new ArrayList<Controller>();
    private static HashMap<String, UserPermission> usersPermissions = new HashMap<String, UserPermission>();
    public static ArticWindow window = null;
    public static ControllerListenerDebug controllerListenerDEBUG = null;
    private static Mutex mutexUserPermissions = new Mutex();
    public static int RESULT_OK = 0;
    public static int ERROR_WRONG_PASSWORD = 1;
    public static int ERROR_FIRST_ACCESS = 2;
    public static int ERROR_BLOCKED_USER = 3;
    public static int ERROR_BLOCKED_ADDRESS = 4;
    public static void setApplicationCode(String code)
    {
        Shared.applicationCode = code;
    }
    public static void setApplicationName(String name)
    {
        Shared.applicationName = name;
    }
    public static String getApplicationName()
    {
        return Shared.applicationName;
    }
    public static String getApplicationCode()
    {
        return Shared.applicationCode;
    }
    public static String getLanguage()
    {
        return configuration.general.language;
    }
    public static void setLanguage(String language)
    {
        try
        {
            configuration.setLanguage(language);
        }
        catch (Exception e)
        {
        }
    }
    public static String getMessage(String language, String identifier)
    {
        if (configuration == null) return identifier;
        return configuration.getMessage(language, identifier);
    }
    public static UserPermission getUserPermission(String username)
    {
        try
        {
            mutexUserPermissions.lockRead();
            return(usersPermissions.get(username));
        }
        catch (Exception e)
        {
            return(null);
        }
        finally
        {
            mutexUserPermissions.releaseRead();
        }
    }
    public static void setUserPermission(String username, UserPermission permission)
    {
        try
        {
            mutexUserPermissions.lockWrite();
            usersPermissions.put(username, permission);
        }
        catch (Exception e)
        {
        }
        finally
        {
            mutexUserPermissions.releaseWrite();
        }
    }
    public static String getMessage(String identifier)
    {
        try
        {
            return configuration.getMessage(identifier);
        }
        catch (Exception e)
        {
            return(identifier);
        }
    }
    public static <T>T getDeviceController(Device device) throws ServerException
    {
        return getDeviceController(device.getIdentifier());
    }
    public static <T>T getDeviceController(String identifier) throws ServerException
    {
        try
        {
            // Acceso a la lista sin mutex, en algun caso podria haber colisión si se elinina
            // algun dispositivo y se quita de la lista mientras estamos leyendo
            for (Controller controller : lcontroller)
            {
                if (controller instanceof ControllerDevice)
                {
                    ControllerDevice controllerDevice = (ControllerDevice)controller;
                    if (((Device)controllerDevice.getDevice()).getIdentifier().equals(identifier))
                    {
                        return (T)controller;
                    }
                }
            }
        }
        catch (Exception e)
        {
        }
        throw new ServerException("Device controller does not exists");
    }
    public static <T>T getDeviceController(String classname, int number) throws ServerException
    {
        try
        {
            // Acceso a la lista sin mutex, en algun caso podria haber colisión si se elinina
            // algun dispositivo y se quita de la lista mientras estamos leyendo
            for (Controller controller : lcontroller)
            {
                if (controller instanceof ControllerDevice)
                {
                    ControllerDevice controllerDevice = (ControllerDevice)controller;
                    Device device = ((Device)controllerDevice.getDevice());
                    if ((device.getClassName().equalsIgnoreCase(classname)) && (device.getDeviceInformation().number == number))
                    {
                        return (T)controller;
                    }
                }
            }
        }
        catch (Exception e)
        {
        }
        throw new ServerException("Device controller does not exists");
    }
    public static List<ControllerDevice> getDeviceControllers() throws ServerException
    {
        List<ControllerDevice> result  = new ArrayList<ControllerDevice>();
        try
        {
            // Acceso a la lista sin mutex, en algun caso podria haber colisión si se elinina
            // algun dispositivo y se quita de la lista mientras estamos leyendo
            for (Controller controller : lcontroller)
            {
                if (controller instanceof ControllerDevice)
                {
                    result.add((ControllerDevice)controller);
                }
            }
        }
        catch (Exception e)
        {
        }
        return(result);
    }
    public static boolean existsDeviceController(Device device)
    {
        return existsDeviceController(device.getIdentifier());
    }
    public static boolean existsDeviceController(String identifier)
    {
        try
        {
            for (Controller controller : lcontroller)
            {
                if (controller instanceof ControllerDevice)
                {
                    ControllerDevice controllerDevice = (ControllerDevice)controller;
                    if (((Device)controllerDevice.getDevice()).getIdentifier().equals(identifier))
                    {
                        return true;
                    }
                }
            }
        }
        catch (Exception e)
        {
        }
        return false;
    }
    public static boolean mailNotificacion(Device device, MailMessage message)
    {
        boolean result = true;
        for (SMTPConfiguration configuration : Shared.configuration.lsmtp)
        {
            try
            {
                configuration.smtpPassword = Licence.decrypt(configuration.smtpPassword);
            }
            catch (Exception e)
            {
            }
            try
            {
                try
                {
                    SMTP smtp = new SMTP(configuration);
                    smtp.send(message);
                }
                catch (Exception exception)
                {
                    result = false;
                }
            }
            catch (Exception e)
            {
            }
        }
        return result;
    }
    public static boolean isServerEnabled()
    {
        return true;
    }
    public static String version()
    {
        String message = "";
        try
        {
            String data = new String(Resources.getResourceData("version.properties"));
            data = data.replaceAll("(?m)^\\s*\\r?\\n|\\r?\\n\\s*(?!.*\\r?\\n)", "");
            String[] lines = data.split("\\r?\\n");
            message = message + (lines[2].replace("major=", "") + "." + lines[3].replace("minor=", "") + "." + lines[4].replace("revision=", "") + " " + lines[5].replace("=", " ") + ", " + lines[1].replace("date=", ""));
        }
        catch (Exception e)
        {
        }
        return message;
    }
    public static void printVersion(String applicationName, String fileName)
    {
        try
        {
            String data = new String(Resources.getResourceData(fileName));
            data = data.replaceAll("(?m)^\\s*\\r?\\n|\\r?\\n\\s*(?!.*\\r?\\n)", "");
            String[] lines = data.split("\\r?\\n");
            Shared.println(applicationName, "Version: " + (lines[2].replace("major=", "") + "." + lines[3].replace("minor=", "") + "." + lines[4].replace("revision=", "") + " " + lines[5].replace("=", " ") + ", " + lines[1].replace("date=", "")));
        }
        catch (Exception e)
        {
        }
    }
    public static Trace getTrace()
    {
        Trace trace = new Trace();
        trace.timestamp = System.currentTimeMillis();
        trace.username = Shared.getApplicationName();
        trace.application = Shared.getApplicationName();
        try
        {
            trace.sourceComputer = InetAddress.getLocalHost().getHostName();
            trace.destinationComputer = trace.sourceComputer;
        }
        catch (Exception e)
        {
        }
        return trace;
    }
    public static void exit()
    {
        for (Controller controller : Shared.lcontroller)
        {
            try { controller.close(); } catch (Exception e) { }
        }
        Timer timer = new Timer();
        timer.schedule(new TimerTask()
        {
            public void run ()
            {
                // Let some time to finish current operations
                System.exit(0);
            }
        }, 5000);
    }
    public static boolean getPropertyValueBoolean(String key)
    {
        try
        {
            return(Boolean.parseBoolean(System.getProperty(key)));
        }
        catch (Exception exception)
        {
        }
        return(false);
    }
    public static String getPropertyValueString(String key)
    {
        try
        {
            return(System.getProperty(key));
        }
        catch (Exception exception)
        {
        }
        return(null);
    }
    // <editor-fold defaultstate="collapsed" desc="prints">
    public static void println(Trace trace, boolean save)
    {
        try
        {
            controllerListenerDEBUG.println(trace, save);
        }
        catch (Exception e)
        {
        }
    }
    public static void println(String service, String message)
    {
        try
        {
            controllerListenerDEBUG.println(new Note(Trace.TRACE_INFORMATION, service + " | " + message), false);
        }
        catch (Exception e)
        {
        }
    }
    public static void println(String service, Exception exception)
    {
        try
        {
            controllerListenerDEBUG.println(new Note(Trace.TRACE_ERROR, service + " | " + exception.toString()), false);
        }
        catch (Exception e)
        {
        }
    }
    public static void printerr(String service, String message)
    {
        try
        {
            controllerListenerDEBUG.println(new Note(Trace.TRACE_ERROR, service + " | " + message), false);
        }
        catch (Exception e)
        {
        }
    }
    public static void printstack(String service, Exception exception)
    {
        try
        {
            StringWriter sw = new StringWriter();
            exception.printStackTrace(new PrintWriter(sw));
            controllerListenerDEBUG.println(new Note(Trace.TRACE_ERROR, service + " | " + sw.toString()), false);
        }
        catch (Exception e)
        {
        }
    }
    public static void printcorrect(String service, String message)
    {
        try
        {
            controllerListenerDEBUG.println(new Note(Trace.TRACE_CORRECT, service + " | " + message), false);
        }
        catch (Exception e)
        {
        }
    }
    public static void printwarning(String service, String message)
    {
        try
        {
            controllerListenerDEBUG.println(new Note(Trace.TRACE_WARNING, service + " | " + message), false);
        }
        catch (Exception e)
        {
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="traces">
    public static Trace traceInformation(String service, String action)
    {
        Trace trace = Trace.getTraceInformation(Shared.getApplicationName(), service, Shared.getMessage(action), Shared.getMessage("Success"));
        println(trace, true);
        return trace;
    }
    public static Trace traceInformation(String service, String action, String resource)
    {
        Trace trace = Trace.getTraceInformation(Shared.getApplicationName(), service, Shared.getMessage(action), Shared.getMessage("Success"));
        trace.resource = resource;
        println(trace, true);
        return trace;
    }
    public static Trace traceInformation(String service, String action, HttpAuthentication authentication, String language)
    {
        Trace trace = Trace.getTraceInformation(Shared.getApplicationName(), service, Shared.getMessage(language, action), Shared.getMessage(language, "Success"));
        if (authentication != null)
        {
            trace.username = authentication.username;
            trace.sourceComputer = authentication.address;
        }
        println(trace, true);
        return trace;
    }
    public static Trace traceInformation(String service, String action, String resource, HttpAuthentication authentication, String language)
    {
        Trace trace = Trace.getTraceInformation(Shared.getApplicationName(), service, Shared.getMessage(language, action), Shared.getMessage(language, "Success"));
        if (authentication != null)
        {
            trace.username = authentication.username;
            trace.sourceComputer = authentication.address;
        }
        trace.resource = resource;
        println(trace, true);
        return trace;
    }
    public static Trace traceError(String service, String action, Exception exception, HttpAuthentication authentication, String language)
    {
        Trace trace = Trace.getTraceError(Shared.getApplicationName(), service, Shared.getMessage(language, action), exception);
        if (authentication != null)
        {
            trace.username = authentication.username;
            trace.sourceComputer = authentication.address;
        }
        println(trace, true);
        return trace;
    }
    public static Trace traceError(String service, String action, String resource, Exception exception, HttpAuthentication authentication, String language)
    {
        Trace trace = Trace.getTraceError(Shared.getApplicationName(), service, Shared.getMessage(language, action), exception);
        if (authentication != null)
        {
            trace.username = authentication.username;
            trace.sourceComputer = authentication.address;
        }
        trace.resource = resource;
        println(trace, true);
        return trace;
    }
    public static Trace traceError(String service, String action, Exception exception)
    {
        Trace trace = Trace.getTraceError(Shared.getApplicationName(), service, Shared.getMessage(action), exception);
        println(trace, true);
        return trace;
    }
    public static Trace traceError(String service, String action, String resource, Exception exception)
    {
        Trace trace = Trace.getTraceError(Shared.getApplicationName(), service, Shared.getMessage(action), exception);
        trace.resource = resource;
        println(trace, true);
        return trace;
    }
    public static Trace traceError(String service, String action, String resource, String exception)
    {
        Trace trace = Trace.getTraceError(Shared.getApplicationName(), service, Shared.getMessage(action), exception);
        trace.resource = resource;
        println(trace, true);
        return trace;
    }
    public static Trace traceWarning(String service, String action, String resource)
    {
        Trace trace = Trace.getTraceWarning(Shared.getApplicationName(), service, Shared.getMessage(action), Shared.getMessage("Success"));
        trace.resource = Shared.getMessage(resource);
        println(trace, true);
        return trace;
    }
    public static Trace traceWarning(String service, String action, String resource, String result)
    {
        Trace trace = Trace.getTraceWarning(Shared.getApplicationName(), service, Shared.getMessage(action), Shared.getMessage(result));
        trace.resource = Shared.getMessage(resource);
        println(trace, true);
        return trace;
    }
    // </editor-fold>
}
servers/server/src/art/servers/configuration/Configuration.java
New file
@@ -0,0 +1,165 @@
package art.servers.configuration;
import art.library.model.devices.application.ApplicationInformation;
import art.library.persistence.PersistenceDatabaseParameters;
import art.library.utils.mail.SMTPConfiguration;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@JsonRootName(value = "Configuration")
public class Configuration
{
    @JsonProperty("General")
    public ConfigurationGeneral general = null;
    @JsonProperty("Application")
    public ApplicationInformation application = null;
    @JsonProperty("Listener")
    public ConfigurationListener listener = null;
    @JsonProperty("Listener http")
    public ConfigurationListenerHttp listenerHttp = null;
    @JsonProperty("Listener https")
    public ConfigurationListenerHttp listenerHttps = null;
    @JsonProperty("Listener web")
    public ConfigurationListenerHttp listenerWeb = null;
    @JsonProperty("NTP HTTP")
    public ConfigurationNtpHttp controllerNTPHTTP = null;
    @JsonProperty("Database")
    public List<PersistenceDatabaseParameters> database = null;
    @JsonProperty("SMTP")
    public List<SMTPConfiguration> lsmtp = null;
    @JsonProperty("Symbols")
    public List<String> symbols = null;
    @JsonProperty("Messages")
    public Map<String, ConfigurationMessages> lmessage = null;
    @JsonProperty("Transactions")
    public ConfigurationTransactions transactions = null;
    @JsonProperty("Listener debug")
    public ConfigurationListenerDEBUG debug = null;
    @JsonProperty("Logger")
    public ConfigurationListenerDEBUG logger = null;
    @JsonIgnore
    public String getMessage(String identifier)
    {
        try
        {
            ConfigurationMessages configurationMessages = (ConfigurationMessages)this.lmessage.get(general.language);
            return configurationMessages.getMessage(identifier);
        }
        catch (Exception e)
        {
        }
        return identifier;
    }
    @JsonIgnore
    public String getMessage(String language, String identifier)
    {
        try
        {
            ConfigurationMessages configurationMessages = (ConfigurationMessages)this.lmessage.get(language);
            return configurationMessages.getMessage(identifier);
        }
        catch (Exception e)
        {
        }
        return identifier;
    }
    @JsonIgnore
    public void setLanguage(String language) throws Exception
    {
        try
        {
            ConfigurationMessages configurationMessages = (ConfigurationMessages)this.lmessage.get(this.general.language);
            if (configurationMessages != null)
            {
                this.general.language = language;
                return;
            }
        }
        catch (Exception e)
        {
        }
        throw new Exception();
    }
    @JsonIgnore
    public Locale getLocale()
    {
        try
        {
            String language = this.general.language.substring(0, 2);
            String country = this.general.language.substring(3, 5);
            return new Locale(language, country);
        }
        catch (Exception e)
        {
        }
        return Locale.getDefault();
    }
    @JsonIgnore
    public void sortMessages()
    {
        for (String key : lmessage.keySet())
        {
            ConfigurationMessages configurationMessages = (ConfigurationMessages)this.lmessage.get(key);
            configurationMessages.sort();
        }
    }
    @JsonIgnore
    public PersistenceDatabaseParameters getDatabaseParameters(String area)
    {
        try
        {
            for (PersistenceDatabaseParameters parameters : database)
            {
                if (parameters.area.equalsIgnoreCase(area) == true) return(parameters);
            }
        }
        catch (Exception e)
        {
        }
        return null;
    }
}
servers/server/src/art/servers/configuration/ConfigurationGeneral.java
New file
@@ -0,0 +1,38 @@
package art.servers.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.HashMap;
import java.util.Map;
public class ConfigurationGeneral
{
    @JsonProperty("Language")
    public String language;
    @JsonProperty("Executable name")
    public String executableName = null;
    @JsonProperty("Window title")
    public String windowTitle = null;
    @JsonProperty("Window icon")
    public String windowIcon = null;
    @JsonProperty("Window x")
    public int windowX = 0;
    @JsonProperty("Window y")
    public int windowY = 0;
    @JsonProperty("Window w")
    public int windowW = 0;
    @JsonProperty("Window h")
    public int windowH = 0;
    @JsonProperty("Properties")
    public Map<String, String> mproperties = new HashMap<String, String>();
}
servers/server/src/art/servers/configuration/ConfigurationListener.java
New file
@@ -0,0 +1,32 @@
package art.servers.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
@JsonRootName(value = "Listener")
public class ConfigurationListener
{
    @JsonProperty("Address")
    public String address;
    @JsonProperty("Port")
    public int port;
    @JsonProperty("Address external")
    public String addressExternal;
    @JsonProperty("Port external")
    public int portExternal;
    @JsonProperty("Timeout")
    public int timeout;
    @JsonProperty("Connections")
    public int connections;
    @JsonProperty("Timeout connection")
    public int timeoutConnection = 0;
}
servers/server/src/art/servers/configuration/ConfigurationListenerDEBUG.java
New file
@@ -0,0 +1,48 @@
package art.servers.configuration;
import art.servers.types.IPv4;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.List;
public class ConfigurationListenerDEBUG
{
    @JsonProperty("Port")
    public int port = 0;
    @JsonProperty("Maximum connections")
    public int maximumConnections = 0;
    @JsonProperty("Allowed connections")
    public List<String> allowedConnections = new ArrayList<String>();
    @JsonIgnore
    public boolean allowed(String address)
    {
        try
        {
            if (allowedConnections.isEmpty() == true) return true;
            long address1 = IPv4.toLong(address);
            for (String connection : allowedConnections)
            {
                long address2 = IPv4.toLong(connection.substring(0, connection.indexOf("/")));
                long mask = IPv4.toLong(Integer.parseInt(connection.substring(connection.indexOf("/") + 1, connection.length())));
                if ((address1 & mask) == (address2 & mask)) return true;
            }
        }
        catch (Exception e)
        {
        }
        return false;
    }
}
servers/server/src/art/servers/configuration/ConfigurationListenerHttp.java
New file
@@ -0,0 +1,58 @@
package art.servers.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
@JsonRootName(value = "Listener http")
public class ConfigurationListenerHttp
{
    @JsonProperty("Port")
    public int port;
    @JsonProperty("Timeout")
    public int timeout;
    @JsonProperty("Read user")
    public String readUser = null;
    @JsonProperty("Read password")
    public String readPassword = null;
    @JsonProperty("Write user")
    public String writeUser = null;
    @JsonProperty("Write password")
    public String writePassword = null;
    @JsonProperty("Keystore location")
    public String keystoreLocation = null;
    @JsonProperty("Keystore password")
    public String keystorePassword = null;
    @JsonProperty("User attempts")
    public int userAttempts = 5;
    /**
     * Time in true
     */
    @JsonProperty("User banner time")
    public long bannerTime = 300;
    @JsonProperty("Token expiration time")
    public long tokenExpirationTime = 86400;
    @JsonProperty("Token inactivity time")
    public long tokenInactivityTime = 600;
}
servers/server/src/art/servers/configuration/ConfigurationMessages.java
New file
@@ -0,0 +1,32 @@
package art.servers.configuration;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class ConfigurationMessages
{
    @JsonProperty("Messages")
    public Map<String, String> messages = new HashMap<String, String>();
    @JsonIgnore
    public String getMessage(String identifier)
    {
        String result = messages.get(identifier);
        if (result == null) return identifier;
        return result;
    }
    @JsonIgnore
    public void sort()
    {
        Map<String, String> sortedMessages = new TreeMap<>(messages);
        messages = sortedMessages;
    }
}
servers/server/src/art/servers/configuration/ConfigurationNtpHttp.java
New file
@@ -0,0 +1,39 @@
package art.servers.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonPropertyOrder
({
    "URL",
    "Proxy address",
    "Proxy port",
    "Timeout",
    "Maximum allowed delay",
    "Polling"
})
public class ConfigurationNtpHttp
{
    @JsonProperty("URL")
    public String URL = null;
    @JsonProperty("Proxy address")
    public String proxyAddress = null;
    @JsonProperty("Proxy port")
    public int proxyPort = 0;
    @JsonProperty("Timeout")
    public int timeout = 0;
    @JsonProperty("Maximum allowed delay")
    public int maximumAllowedDelay = 0;
    @JsonProperty("Polling")
    public int polling = 0;
}
servers/server/src/art/servers/configuration/ConfigurationSecurity.java
New file
@@ -0,0 +1,40 @@
package art.servers.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonPropertyOrder
({
    "Read password",
    "Download password",
    "Write password",
    "Admin password",
    "Storage password",
    "System password"
})
public class ConfigurationSecurity
{
    @JsonProperty("Read password")
    public String readPassword = null;
    @JsonProperty("Download password")
    public String downloadPassword = null;
    @JsonProperty("Write password")
    public String writePassword = null;
    @JsonProperty("Admin password")
    public String adminPassword = null;
    @JsonProperty("Storage password")
    public String storagePassword = null;
    @JsonProperty("System password")
    public String systemPassword = null;
}
servers/server/src/art/servers/configuration/ConfigurationTransactions.java
New file
@@ -0,0 +1,20 @@
package art.servers.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import java.util.List;
@JsonRootName(value = "Configuration transactions")
public class ConfigurationTransactions
{
    @JsonProperty("Name")
    public String name;
    @JsonProperty("Polling")
    public int polling = 60;
    @JsonProperty("Transactions services")
    public List<ConfigurationTransactionsService> lservicesTransactions = null;
}
servers/server/src/art/servers/configuration/ConfigurationTransactionsService.java
New file
@@ -0,0 +1,21 @@
package art.servers.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
@JsonRootName(value = "Configuration transactions service")
public class ConfigurationTransactionsService
{
    @JsonProperty("Service")
    public String service;
    @JsonProperty("Address")
    public String address;
    @JsonProperty("Port")
    public int port;
    @JsonProperty("Timeout")
    public int timeout;
}
servers/server/src/art/servers/controller/Controller.java
New file
@@ -0,0 +1,28 @@
package art.servers.controller;
public class Controller extends Thread
{
    protected boolean exit = false;
    public void close()
    {
        exit = true;
    }
    public void pause(long timemillis)
    {
        try
        {
            sleep(timemillis);
        }
        catch (Exception exception)
        {
        }
    }
}
servers/server/src/art/servers/controller/ControllerDatabase.java
New file
@@ -0,0 +1,687 @@
package art.servers.controller;
import art.library.persistence.Persistence;
import art.library.persistence.PersistenceDatabase;
import art.library.persistence.PersistenceDatabaseParameters;
import art.library.utils.licence.Licence;
import art.library.utils.resources.Resources;
import art.servers.Shared;
import art.servers.configuration.Configuration;
import java.io.File;
import java.nio.file.Files;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
public class ControllerDatabase extends Controller
{
    private List<Persistence> lpersistenceTimeless = new ArrayList<Persistence>();
    private List<Persistence> lpersistenceHistorical = new ArrayList<Persistence>();
    private List<Persistence> lpersistence = new ArrayList<Persistence>();
    private String name = null;
    public ControllerDatabase(Configuration configuration) throws Exception
    {
        this.name = Shared.getMessage("Controller database");
        this.setName(name);
        for (PersistenceDatabaseParameters persistenceDatabaseParameters : configuration.database)
        {
            if (persistenceDatabaseParameters.area.equalsIgnoreCase("Timeless"))
            {
                PersistenceDatabase persistenceTimeless = new PersistenceDatabase(persistenceDatabaseParameters);
                lpersistenceTimeless.add(persistenceTimeless);
                lpersistence.add(persistenceTimeless);
            }
            else if (persistenceDatabaseParameters.area.equalsIgnoreCase("Historical"))
            {
                PersistenceDatabase persistenceHistorical = new PersistenceDatabase(persistenceDatabaseParameters);
                lpersistenceHistorical.add(persistenceHistorical);
                lpersistence.add(persistenceHistorical);
            }
        }
        reloadPLSQL();
        start();
    }
    public ControllerDatabase(List<PersistenceDatabaseParameters> lparameters) throws Exception
    {
        this.setName(this.getClass().getName() + " : " + this.getName());
        for (PersistenceDatabaseParameters persistenceDatabaseParameters : lparameters)
        {
            if (persistenceDatabaseParameters.area.equalsIgnoreCase("Timeless"))
            {
                PersistenceDatabase persistenceTimeless = new PersistenceDatabase(persistenceDatabaseParameters);
                lpersistenceTimeless.add(persistenceTimeless);
                lpersistence.add(persistenceTimeless);
            }
            else if (persistenceDatabaseParameters.area.equalsIgnoreCase("Historical"))
            {
                PersistenceDatabase persistenceHistorical = new PersistenceDatabase(persistenceDatabaseParameters);
                lpersistenceHistorical.add(persistenceHistorical);
                lpersistence.add(persistenceHistorical);
            }
        }
        reloadPLSQL();
        start();
    }
    public List<Persistence> getTimelessPersistance()
    {
        return lpersistenceTimeless;
    }
    public List<Persistence> getHistoricalPersistance()
    {
        return lpersistenceHistorical;
    }
    public void run()
    {
        long lastTimestamp = System.currentTimeMillis();
        for (Persistence persistence : lpersistence)
        {
            Shared.traceInformation(name, "Disconnecting",  persistence.getName());
        }
        while ((isInterrupted() == false) && (exit == false))
        {
            lastTimestamp = System.currentTimeMillis();
            {
                for (Persistence persistence : lpersistence)
                {
                    status(persistence);
                }
            }
            long timetowait = 5000 -(System.currentTimeMillis() - lastTimestamp);
            if (timetowait > 0)
            {
                try
                {
                    sleep(timetowait);
                }
                catch (Exception e)
                {
                }
            }
            try
            {
                reloadPLSQL();
            }
            catch (Exception e)
            {
            }
        }
        for (Persistence persistence : lpersistence)
        {
            persistence.close();
            Shared.traceInformation(name, "Finishing");
        }
    }
    private void reloadPLSQL()
    {
        for (Persistence persistence : lpersistence)
        {
            PersistenceDatabaseParameters persistenceDatabaseParameters = persistence.parameters;
            if (persistenceDatabaseParameters.PLSQL != null)
            {
                for (String path : persistenceDatabaseParameters.PLSQL)
                {
                    Connection connection = null;
                    PreparedStatement statement = null;
                    try
                    {
                        String superUser = Licence.decrypt(persistenceDatabaseParameters.superUser);
                        String superPassword = Licence.decrypt(persistenceDatabaseParameters.superPassword);
                        File file = new File(path);
                        if (file.exists() == false)
                        {
                            try
                            {
                                String plsql = new String(Resources.getResourceBytes(path));
                                if (persistenceDatabaseParameters.lastTimestampPlsqlUpdate == 0)
                                {
                                    connection = (Connection)DriverManager.getConnection(persistenceDatabaseParameters.connectionString, superUser, superPassword);
                                    connection.setAutoCommit(true);
                                    statement = connection.prepareStatement(plsql);
                                    statement.executeUpdate();
                                    persistenceDatabaseParameters.lastTimestampPlsqlUpdate = file.lastModified();
                                }
                            }
                            catch (Exception e)
                            {
                            }
                        }
                        else
                        {
                            try
                            {
                                if (file.lastModified() > persistenceDatabaseParameters.lastTimestampPlsqlUpdate)
                                {
                                    String plsql = new String(Files.readAllBytes(file.toPath()));
                                    connection = (Connection)DriverManager.getConnection(persistenceDatabaseParameters.connectionString, superUser, superPassword);
                                    connection.setAutoCommit(true);
                                    statement = connection.prepareStatement(plsql);
                                    statement.executeUpdate();
                                    persistenceDatabaseParameters.lastTimestampPlsqlUpdate = file.lastModified();
                                }
                            }
                            catch (Exception e)
                            {
                            }
                        }
                    }
                    catch (Exception e)
                    {
                    }
                    try { statement.close(); } catch (Exception e) { }
                    try { connection.close(); } catch (Exception e) { }
                }
            }
        }
    }
    private void status(Persistence persistence)
    {
        try
        {
            persistence.isConnected();
        }
        catch (Exception exception)
        {
            Shared.traceError(name, "Connecting", persistence.getName(), exception);
        }
    }
    /***************************************************************************
    /*
    /* Timeless
    /*
    ***************************************************************************/
    public boolean timeless_existObject(Object object) throws Exception
    {
        Exception exception = null;
        for (Persistence persistence : lpersistenceTimeless)
        {
            try
            {
                return persistence.existObject(object);
            }
            catch (Exception e)
            {
                exception = e;
            }
        }
        throw exception;
    }
    public boolean timeless_existObject(String className, String where) throws Exception
    {
        Exception exception = null;
        for (Persistence persistence : lpersistenceTimeless)
        {
            try
            {
                return persistence.existObject(className, where);
            }
            catch (Exception e)
            {
                exception = e;
            }
        }
        throw exception;
    }
    public void timeless_addObject(Object object) throws Exception
    {
        Exception exception = null;
        for (Persistence persistence : lpersistenceTimeless)
        {
            try
            {
                persistence.addObject(object);
            }
            catch (Exception e)
            {
                exception = e;
            }
        }
        if (exception != null) throw exception;
    }
    public void timeless_updateObject(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceTimeless)
        {
            persistence.updateObject(object);
        }
    }
    public void timeless_updateOrAddObject(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceTimeless)
        {
            persistence.updateOrAddObject(object);
        }
    }
    public List<Object> timeless_getObject(String className) throws Exception
    {
        Exception exception = null;
        for (Persistence persistence : lpersistenceTimeless)
        {
            try
            {
                return persistence.getObject(className);
            }
            catch (Exception e)
            {
                exception = e;
            }
        }
        throw exception;
    }
    public List<Object> timeless_getObject(String className, String where) throws Exception
    {
        Exception exception = null;
        for (Persistence persistence : lpersistenceTimeless)
        {
            try
            {
                return persistence.getObject(className, where);
            }
            catch (Exception e)
            {
                e.printStackTrace();
                exception = e;
            }
        }
        throw exception;
    }
    public void timeless_deleteObject(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceTimeless)
        {
            persistence.deleteObject(object);
        }
    }
    public void timeless_deleteObject(String className, String where) throws Exception
    {
        for (Persistence persistence : lpersistenceTimeless)
        {
            persistence.deleteObject(className, where);
        }
    }
    public void timeless_update(String sql) throws Exception
    {
        for (Persistence persistence : lpersistenceTimeless)
        {
            persistence.update(sql);
        }
    }
    public void timeless_addObject_asynchronous(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceTimeless)
        {
            persistence.addObject_asynchronous(object);
        }
    }
    public void timeless_updateObject_asynchronous(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceTimeless)
        {
            persistence.updateObject_asynchronous(object);
        }
    }
    public void timeless_updateOrAddObject_asynchronous(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceTimeless)
        {
            persistence.updateOrAddObject_asynchronous(object);
        }
    }
    public void timeless_update_asynchronous(String sql) throws Exception
    {
        for (Persistence persistence : lpersistenceTimeless)
        {
            persistence.update_asynchronous(sql);
        }
    }
    /***************************************************************************
    /*
    /* Historical
    /*
    ***************************************************************************/
    public boolean historical_existObject(Object object) throws Exception
    {
        Exception exception = null;
        for (Persistence persistence : lpersistenceHistorical)
        {
            try
            {
                return persistence.existObject(object);
            }
            catch (Exception e)
            {
                exception = e;
            }
        }
        throw exception;
    }
    public boolean historical_existObject(String className, String where) throws Exception
    {
        Exception exception = null;
        for (Persistence persistence : lpersistenceHistorical)
        {
            try
            {
                return persistence.existObject(className, where);
            }
            catch (Exception e)
            {
                exception = e;
            }
        }
        throw exception;
    }
    public void historical_addObject(Object object) throws Exception
    {
        Exception exception = null;
        for (Persistence persistence : lpersistenceHistorical)
        {
            try
            {
                persistence.addObject(object);
            }
            catch (Exception e)
            {
                exception = e;
            }
        }
        if (exception != null) throw exception;
    }
    public void historical_updateObject(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceHistorical)
        {
            persistence.updateObject(object);
        }
    }
    public void historical_addOrUpdateObject(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceHistorical)
        {
            persistence.addOrUpdateObject(object);
        }
    }
    public void historical_updateOrAddObject(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceHistorical)
        {
            persistence.updateOrAddObject(object);
        }
    }
    public List<Object> historical_getObject(String className) throws Exception
    {
        Exception exception = null;
        for (Persistence persistence : lpersistenceHistorical)
        {
            try
            {
                return persistence.getObject(className);
            }
            catch (Exception e)
            {
                exception = e;
            }
        }
        throw exception;
    }
    public List<Object> historical_getObject(String className, String where) throws Exception
    {
        return historical_getObject(className, where, 0);
    }
    public List<Object> historical_getObject(String className, String where, int top) throws Exception
    {
        Exception exception = null;
        for (Persistence persistence : lpersistenceHistorical)
        {
            try
            {
                return persistence.getObject(className, where);
            }
            catch (Exception e)
            {
                exception = e;
            }
        }
        throw exception;
    }
    public List<Object> historical_getObject_Summary(String className, String where) throws Exception
    {
        return historical_getObject_Summary(className, where, 0);
    }
    public List<Object> historical_getObject_Summary(String className, String where, int top) throws Exception
    {
        Exception exception = null;
        for (Persistence persistence : lpersistenceHistorical)
        {
            try
            {
                return persistence.getObjectSummary(className, where);
            }
            catch (Exception e)
            {
                exception = e;
            }
        }
        throw exception;
    }
    public void historical_deleteObject(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceHistorical)
        {
            persistence.deleteObject(object);
        }
    }
    public void historical_deleteObject(String className, String where) throws Exception
    {
        for (Persistence persistence : lpersistenceHistorical)
        {
            persistence.deleteObject(className, where);
        }
    }
    public void historical_update(String sql) throws Exception
    {
        for (Persistence persistence : lpersistenceHistorical)
        {
            persistence.update(sql);
        }
    }
    public void historical_addObject_asynchronous(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceHistorical)
        {
            persistence.addObject_asynchronous(object);
        }
    }
    public void historical_updateObject_asynchronous(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceHistorical)
        {
            persistence.updateObject_asynchronous(object);
        }
    }
    public void historical_addOrUpdateObject_asynchronous(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceHistorical)
        {
            persistence.addOrUpdateObject_asynchronous(object);
        }
    }
    public void historical_updateOrAddObject_asynchronous(Object object) throws Exception
    {
        for (Persistence persistence : lpersistenceHistorical)
        {
            persistence.updateOrAddObject_asynchronous(object);
        }
    }
    public void historical_update_asynchronous(String sql) throws Exception
    {
        for (Persistence persistence : lpersistenceHistorical)
        {
            persistence.update_asynchronous(sql);
        }
    }
}
servers/server/src/art/servers/controller/ControllerDevice.java
New file
@@ -0,0 +1,20 @@
package art.servers.controller;
import art.library.model.devices.Device;
public class ControllerDevice extends Controller
{
    private Device device;
    public ControllerDevice(Device device)
    {
        this.device = device;
    }
    public <T>T getDevice()
    {
        return (T)device;
    }
}
servers/server/src/art/servers/controller/ControllerListener.java
New file
@@ -0,0 +1,462 @@
package art.servers.controller;
import art.library.interop.serialization.Serialization;
import art.library.interop.serialization.SerializationException;
import art.library.utils.synchro.Mutex;
import art.servers.Shared;
import art.servers.configuration.ConfigurationListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ControllerListener extends Controller
{
    private ConfigurationListener configuration;
    private ServerSocket serverSocket;
    private List<Connection> lconnection = new ArrayList<Connection>();
    private ListenerImplementation implementation = null;
    private Mutex mutex = new Mutex();
    private String name = null;
    public String mask = "-";
    private HashMap<String, String> hblocked = new HashMap<String, String>();
    public ControllerListener(ConfigurationListener configuration)
    {
        this.name = Shared.getMessage("Controller listener");
        this.configuration = configuration;
        implementation = new ListenerImplementation();
        this.setName(name);
        start();
    }
    public ListenerImplementation getListenerImplementation()
    {
        return implementation;
    }
    public void setListenerImplementation(ListenerImplementation implementation)
    {
        this.implementation = implementation;
    }
    public void run()
    {
        Shared.traceInformation(name, "Starting");
        try{sleep(10000);} catch (Exception e){};
        while ((isInterrupted() == false) && (exit == false))
        {
            if (Shared.isServerEnabled() == true)
            {
                try
                {
                    connect();
                    Socket socket = serverSocket.accept();
                    mutex.lockWrite();
                    try
                    {
                        boolean connect = true;
                        try
                        {
                            if (socket.getInetAddress().getHostAddress().equals("10.207.33.229") == false && socket.getInetAddress().getHostAddress().indexOf(mask) >= 0)
                            {
                                connect = false;
                                socket.close();
                            }
                            else if (hblocked.containsKey(socket.getInetAddress().getHostAddress()) == true)
                            {
                                connect = false;
                                socket.close();
                            }
                        }
                        catch (Exception e)
                        {
                        }
                        if (connect == true)
                        {
                            if ((lconnection.size() <= configuration.connections) && (configuration.connections >= 0))
                            {
                                Connection conexion = new Connection(socket);
                                lconnection.add(conexion);
                                conexion.start();
                            }
                            else
                            {
                                Shared.println(name, Shared.getMessage("Maximum connections reached. Disconnecting") + " " + socket.getInetAddress().getHostAddress() + ":" + socket.getPort());
                                socket.close();
                            }
                        }
                    }
                    finally
                    {
                        mutex.releaseWrite();
                    }
                }
                catch (Exception e)
                {
                    disconnect();
                    try
                    {
                        sleep(100);
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }
            else
            {
                mutex.lockRead();
                try
                {
                    for (Connection connection : lconnection)
                    {
                        connection.interrupt();
                    }
                }
                finally
                {
                    mutex.releaseRead();
                }
            }
        }
        Shared.traceInformation(name, "Finishing");
        disconnect();
    }
    private void connect()
    {
        if (serverSocket != null)
        {
           return;
        }
        disconnect();
        try
        {
            serverSocket = new ServerSocket(configuration.port);
            serverSocket.setSoTimeout(configuration.timeout);
            Shared.traceInformation(name, "Listening", Shared.getMessage("Port") + " = " + configuration.port);
        }
        catch (Exception exception)
        {
            Shared.traceError(name, "Listening", Shared.getMessage("Port") + " = " + configuration.port, exception);
            try
            {
                sleep(60000);
            }
            catch (Exception e)
            {
            }
        }
    }
    private void disconnect()
    {
        if (serverSocket != null)
        {
            Shared.traceInformation(name, "Disconnecting");
            try
            {
                serverSocket.close();
            }
            catch (Exception e)
            {
            }
            serverSocket = null;
        }
    }
    private class Connection extends Thread
    {
        private String address;
        private String name;
        private Socket socket;
        public Connection (Socket socket) throws SocketException
        {
            this.address = socket.getInetAddress().getHostAddress();
            this.name = this.address + ":" + socket.getPort();
            this.socket = socket;
            this.socket.setSoTimeout(configuration.timeoutConnection);
            this.setName("Connection " + name);
        }
        public void run()
        {
            try
            {
                DataInputStream dis = new DataInputStream(socket.getInputStream());
                DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                while ((isInterrupted() == false) && (exit == false))
                {
                    if (hblocked.containsKey(socket.getInetAddress().getHostAddress()) == true)
                    {
                        throw new Exception("BLOCKED");
                    }
                    listen(this.address, dis, dos);
                }
            }
            catch (Exception e)
            {
            }
            close();
        }
        private void close()
        {
            try
            {
                socket.close();
            }
            catch (Exception e)
            {
            }
            mutex.lockWrite();
            {
                lconnection.remove(this);
            }
            mutex.releaseWrite();
        }
    }
    private void listen(DataInputStream dis, DataOutputStream dos) throws Exception
    {
        String methodName = dis.readUTF();
        String parameterClassName = dis.readUTF();
        byte[] parameterData = new byte[dis.readInt()];
        dis.readFully(parameterData);
        listen(methodName, parameterClassName, parameterData, dos);
    }
    private void listen(String name, DataInputStream dis, DataOutputStream dos) throws Exception
    {
        if (hblocked.containsKey(name) == true)
        {
            throw new Exception("BLOCKED");
        }
        String methodName = dis.readUTF();
        if (hblocked.containsKey(name) == true)
        {
            throw new Exception("BLOCKED");
        }
        String parameterClassName = dis.readUTF();
        if (hblocked.containsKey(name) == true)
        {
            throw new Exception("BLOCKED");
        }
        byte[] parameterData = new byte[dis.readInt()];
        if (hblocked.containsKey(name) == true)
        {
            throw new Exception("BLOCKED");
        }
        dis.readFully(parameterData);
        if ((name.indexOf("10.136.") >= 0) && (this.mask.length() > 2))
        {
            try
            {
                Object objectParameter = Serialization.decompress(Class.forName(parameterClassName), parameterData);
                art.library.interop.InteropParameters parameters = (art.library.interop.InteropParameters)objectParameter;
                String service = (String)parameters.getParameterValue("service");
                if (service.indexOf("transactions_") >= 0)
                {
                    String operation = (String)parameters.getParameterValue("operation");
                    if (operation.equalsIgnoreCase("getDevices") == true)
                    {
                        hblocked.put(name, name);
                        Shared.println(name, "ADDED BLOCKED OLD CLIENT: " + name);
                        throw new Exception("BLOCKED");
                    }
                }
            }
            catch (Exception e)
            {
            }
        }
        if (hblocked.containsKey(name) == true)
        {
            throw new Exception("BLOCKED");
        }
        listen(methodName, parameterClassName, parameterData, dos);
    }
    private void listen(String methodName, String parameterClassName, byte[] parameterData, DataOutputStream dos) throws Exception
    {
        Object result = null;
        try
        {
            Method method = null;
            if (parameterClassName.length() > 0)
            {
                Object objectParameter = Serialization.decompress(Class.forName(parameterClassName), parameterData);
                method = implementation.getClass().getMethod(methodName, objectParameter.getClass());
                result = method.invoke(implementation, objectParameter);
            }
            else
            {
                method = implementation.getClass().getMethod(methodName, new Class[]{});
                result = method.invoke(implementation, new Object[]{});
            }
            if (result != null)
            {
                dos.writeUTF(methodName);
                dos.writeUTF(result.getClass().getName());
                byte[] data = Serialization.compress(result);
                dos.writeInt(data.length);
                dos.write(data);
                dos.flush();
            }
            else if (method.getReturnType() == void.class)
            {
                dos.writeUTF(methodName);
                dos.writeUTF(void.class.getName());
                byte[] data = Serialization.compress(result);
                dos.writeInt(0);
                dos.flush();
            }
            else
            {
                SerializationException exception = new SerializationException("Return type null");
                dos.writeUTF(methodName);
                dos.writeUTF(exception.getClass().getName());
                dos.writeUTF(exception.getMessage());
                dos.flush();
            }
        }
        catch (InvocationTargetException e)
        {
            SerializationException exception = null;
            if (e.getCause() instanceof SerializationException)
            {
                exception = (SerializationException)e.getCause();
            }
            else
            {
                exception = (SerializationException)e.getCause();
            }
            dos.writeUTF(methodName);
            dos.writeUTF(exception.getClass().getName());
            if (exception.getStackMessage().length() > 0)
            {
                dos.writeUTF(exception.getStackMessage());
            }
            else
            {
                dos.writeUTF(exception.getMessage());
            }
            dos.flush();
        }
        catch (java.lang.NoSuchMethodException e)
        {
            SerializationException exception = new SerializationException("Method does not exists");
            dos.writeUTF(methodName);
            dos.writeUTF(exception.getClass().getName());
            dos.writeUTF(exception.getMessage());
            dos.flush();
        }
        catch (Exception e)
        {
            throw new SerializationException(e.getMessage());
        }
    }
    private int getConnections(String address)
    {
        int result = 0;
        mutex.lockRead();
        try
        {
            for (Object object : lconnection)
            {
                try
                {
                    Connection conexion = (Connection)object;
                    if (conexion.address.equals(address))
                    {
                        result = result + 1;
                    }
                }
                catch (Exception e)
                {
                }
            }
        }
        finally
        {
            mutex.releaseRead();
        }
        return result;
    }
}
servers/server/src/art/servers/controller/ControllerListenerDebug.java
New file
@@ -0,0 +1,373 @@
package art.servers.controller;
import art.library.model.devices.application.ApplicationRealtime;
import art.library.model.transactions.traces.Note;
import art.library.utils.synchro.Mutex;
import art.library.model.transactions.traces.Trace;
import art.library.model.transactions.traces.TracePersistance;
import art.servers.Shared;
import art.servers.configuration.ConfigurationListenerDEBUG;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
public class ControllerListenerDebug extends Thread
{
    private static String COLOR_BLACK = "\u001B[0;30;40m";
    private static String COLOR_RED = "\u001B[0;31;40m";
    private static String COLOR_GREEN = "\u001B[0;32;40m";
    private static String COLOR_YELLOW = "\u001B[0;33;40m";
    private static String COLOR_BLUE = "\u001B[0;34;40m";
    private static String COLOR_MAGENTA = "\u001B[0;35;40m";
    private static String COLOR_CYAN = "\u001B[0;36;40m";
    private static String COLOR_WHITE = "\u001B[0;37;40m";
    private static String COLOR_LIGHT_GRAY = "\u001B[0;33;37m";
    private static String COLOR_DARK_GRAY = "\u001B[0;33;90m";
    private static String COLOR_ORANGE = "\u001B[0;33;93m";
    private String name = null;
    private Mutex mutexConnection = new Mutex();
    private ServerSocket serverSocket = null;
    private List<DebugConnection> connections = new ArrayList<DebugConnection>();
    private ConfigurationListenerDEBUG configuration = null;
    public ControllerListenerDebug(ConfigurationListenerDEBUG configuration)
    {
        this.configuration = configuration;
        initialise();
    }
    private void initialise()
    {
        this.name = Shared.getMessage("Listener LOGGER");
        this.setName(name);
        // Terminal output
        DebugConnection connection = new DebugConnection(System.out);
        this.connections.add(connection);
        connection.start();
    }
    public void println(Object object, boolean save)
    {
        mutexConnection.lockRead();
        try
        {
            for (DebugConnection connection : connections)
            {
                connection.addMessage(object);
            }
        }
        catch (Exception e)
        {
        }
        mutexConnection.releaseRead();
        if ((save == true) && (Shared.controllerDatabase != null))
        {
            if (object instanceof Trace)
            {
                Trace trace = (Trace)object;
                try
                {
                    if (trace.username == null) trace.username = "-";
                    TracePersistance tracePersistance = new TracePersistance(trace);
                    Shared.controllerDatabase.getHistoricalPersistance().get(0).addObject_asynchronous(tracePersistance);
                    ApplicationRealtime realtime = (ApplicationRealtime)Shared.controllerStatus.getApplication().getDeviceRealtime();
                    realtime.addTrace(trace);
                }
                catch (Exception exception)
                {
                }
            }
        }
        if (Shared.window != null) Shared.window.addTrace(object);
    }
    public void run()
    {
        Shared.traceInformation(name, "Starting");
        while (isInterrupted() == false)
        {
            try
            {
                if (serverSocket == null)
                {
                    serverSocket = new ServerSocket(configuration.port);
                    serverSocket.setSoTimeout(0);
                }
                Socket clientSocket = serverSocket.accept();
                connection(clientSocket);
            }
            catch (Exception exception)
            {
                try
                {
                    sleep(100);
                }
                catch (Exception e)
                {
                }
            }
        }
        Shared.traceInformation(name, "Finishing");
    }
    private void connection(Socket clientSocket)
    {
        try
        {
            if (configuration.allowed(clientSocket.getLocalAddress().getHostAddress()))
            {
                if (connections.size() < configuration.maximumConnections)
                {
                    DebugConnection connection = new DebugConnection(clientSocket);
                    addConnection(connection);
                    connection.start();
                    return;
                }
                Shared.traceError(name, "Connecting", Shared.getMessage("Connection rejected due too many connections"), "");
            }
            else
            {
                Shared.traceWarning(name, "Connecting",  clientSocket.getLocalAddress().getHostAddress(), Shared.getMessage("Connection rejected due too many connections"));
            }
        }
        catch (Exception e)
        {
        }
        try
        {
            clientSocket.close();
        }
        catch (Exception e)
        {
        }
    }
    private void addConnection(DebugConnection connection) throws Exception
    {
        mutexConnection.lockWrite();
        try
        {
            connections.add(connection);
        }
        catch (Exception e)
        {
        }
        mutexConnection.releaseWrite();
    }
    private void removeConnection(DebugConnection connection)
    {
        mutexConnection.lockWrite();
        try
        {
            connections.remove(connection);
        }
        catch (Exception e)
        {
        }
        mutexConnection.releaseWrite();
    }
    private class DebugConnection extends Thread
    {
        private Socket socket = null;
        private PrintStream output = null;
        public List<Object> messages = new ArrayList<Object>();
        public Mutex mutex = new Mutex();
        public DebugConnection(Socket socket) throws Exception
        {
            this.socket = socket;
            String address = socket.getInetAddress().getHostAddress();
            String name = address + ":" + socket.getPort();
            this.setName("Logger connection " + name);
            this.output = new PrintStream(socket.getOutputStream());
        }
        public DebugConnection(PrintStream output)
        {
            this.setName("Logger screen");
            this.output = output;
        }
        public void addMessage(Object object)
        {
            mutex.lockWrite();
            {
               messages.add(object);
            }
            mutex.releaseWrite();
        }
        public void run()
        {
            try
            {
                while (isInterrupted() == false)
                {
                    if (messages.size() > 0)
                    {
                        Object object = messages.get(0);
                        if (object != null)
                        {
                            print(object);
                        }
                        messages.remove(0);
                    }
                    else
                    {
                        sleep(100);
                    }
                }
            }
            catch (Exception e)
            {
            }
            close();
        }
        private void print(Object object)
        {
            String color1 = COLOR_BLACK;
            String color2 = COLOR_BLACK;
            //if (out != System.out)
            {
                color1 = COLOR_WHITE;
                color2 = COLOR_WHITE;
            }
            if (object instanceof Trace)
            {
                Trace trace = (Trace)object;
                switch (trace.type)
                {
                    case Trace.TRACE_INFORMATION: color2 = COLOR_CYAN; break;
                    case Trace.TRACE_WARNING: color2 = COLOR_YELLOW; break;
                    case Trace.TRACE_ERROR: color2 = COLOR_RED; break;
                    case Trace.TRACE_SUCCESS: color2 = COLOR_GREEN; break;
                }
                print(trace, color1, color2);
            }
            else if (object instanceof Note)
            {
                Note note = (Note)object;
                switch (note.type)
                {
                    case Trace.TRACE_INFORMATION: color2 = COLOR_CYAN; break;
                    case Trace.TRACE_WARNING: color2 = COLOR_YELLOW; break;
                    case Trace.TRACE_ERROR: color2 = COLOR_RED; break;
                    case Trace.TRACE_SUCCESS: color2 = COLOR_GREEN; break;
                }
                print(note, color1, color2);
            }
        }
        private void print(Trace trace, String color1, String color2)
        {
            SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss.SSS"));
            output.println(color1 + formato1.format(trace.timestamp));
            output.print("{");
            if (trace.sourceComputer != null) output.print("\r\n\t" + color1 + "Source computer" + " : " + color2 + trace.sourceComputer);
            if (trace.destinationComputer != null) output.print("\r\n\t" + color1 + "Destination computer" + " : " + color2 + trace.destinationComputer);
            if (trace.username != null) output.print("\r\n\t" + color1 + "User" + " : " + color2 + trace.username);
            if (trace.application != null) output.print("\r\n\t" + color1 + "Application" + " : " + color2 + trace.application);
            if (trace.service != null) output.print("\r\n\t" + color1 + "Service" + " : " + color2 + trace.service);
            if (trace.action != null) output.print("\r\n\t" + color1 + "Action" + " : " + color2 + trace.action);
            if (trace.resource != null) output.print("\r\n\t" + color1 + "Resource" + " : " + color2 + trace.resource);
            if (trace.result != null) output.print("\r\n\t" + color1 + "Result" + " : " + color2 + trace.result);
            if ((trace.stack != null) && (trace.stack.length() > 0)) output.print("\r\n\t" + color1 + "Stack" + " : " + color2 + trace.stack);
            output.print(color1 + "\r\n}\r\n\r\n");
        }
        private void print(Note note, String color1, String color2)
        {
            SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss.SSS"));
            if (note.service != null)
            {
                output.println(color1 + formato1.format(note.timestamp) + " : " + COLOR_LIGHT_GRAY + note.service + " | " + color2 + note.message);
            }
            else
            {
                output.println(color1 + formato1.format(note.timestamp) + " : " + color2 + note.message);
            }
        }
        public void close()
        {
            try { socket.close(); }  catch (Exception e) {}
            try { removeConnection(this); }  catch (Exception e) {}
        }
    }
}
servers/server/src/art/servers/controller/ControllerListenerHttp.java
New file
@@ -0,0 +1,798 @@
package art.servers.controller;
import art.library.interop.InteropParameter;
import art.library.interop.InteropParameters;
import art.library.interop.InteropResponse;
import art.library.interop.serialization.Serialization;
import art.library.interop.serialization.SerializationException;
import art.library.utils.licence.Licence;
import art.servers.ServerException;
import art.servers.Shared;
import art.servers.configuration.ConfigurationListenerHttp;
import art.servers.types.HttpAuthentication;
import com.sun.net.httpserver.BasicAuthenticator;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import static jdk.nashorn.tools.ShellFunctions.input;
public class ControllerListenerHttp extends Controller
{
    protected String name = null;
    protected HttpServer server = null;
    protected ConfigurationListenerHttp configuration = null;
    protected ListenerImplementation implementation = null;
    public ControllerListenerHttp(ConfigurationListenerHttp configuration)
    {
        this.name = Shared.getMessage("Listener http");
        this.setName(this.getClass().getName() + " : " + name);
        this.configuration = configuration;
        start();
    }
    public ListenerImplementation getListenerImplementation()
    {
        if (implementation != null) return implementation;
        return Shared.controllerListener.getListenerImplementation();
    }
    public void setListenerImplementation(ListenerImplementation implementation)
    {
        this.implementation = implementation;
    }
    public void run()
    {
        Shared.traceInformation(name, "Starting");
        while ((isInterrupted() == false) && (exit == false))
        {
            try
            {
                if (server == null)
                {
                    connect();
                }
                sleep(1000);
            }
            catch (Exception e)
            {
            }
        }
        Shared.traceInformation(name, "Finishing");
    }
    protected void connect()
    {
        try
        {
            server = HttpServer.create(new InetSocketAddress(configuration.port), 0);
            contexts();
            server.setExecutor(Executors.newCachedThreadPool());
            server.start();
            Shared.traceInformation(name, "Disconnecting",  Shared.getMessage("Port") + " = " + configuration.port);
            return;
        }
        catch (Exception exception)
        {
            Shared.traceError(name, "Disconnecting",  Shared.getMessage("Port") + " = " + configuration.port, exception);
        }
    }
    protected void contexts()
    {
        HttpContext context1 = server.createContext("/login", new login());
        HttpContext context2 = server.createContext("/art", new artic());
        HttpContext context3 = server.createContext("/get", new get());
        HttpContext context4 = server.createContext("/set", new set());
        HttpContext context5 = server.createContext("/session", new session());
        HttpContext context6 = server.createContext("/gis", new gis());
        HttpContext context7 = server.createContext("/saml", new saml());
        HttpContext context8 = server.createContext("/logout", new logout());
        if (configuration.readUser != null)
        {
            context3.setAuthenticator(new BasicAuthenticator(configuration.readUser)
            {
                public boolean checkCredentials(String user, String pwd)
                {
                    return user.equals(configuration.readUser) && pwd.equals(configuration.readPassword);
                }
            });
        }
        if (configuration.writeUser != null)
        {
            context4.setAuthenticator(new BasicAuthenticator(configuration.writeUser)
            {
                public boolean checkCredentials(String user, String pwd)
                {
                    return user.equals(configuration.writeUser) && pwd.equals(configuration.writePassword);
                }
            });
        }
    }
    protected class login implements HttpHandler
    {
        public void handle(HttpExchange httpExchange) throws IOException
        {
            String language = null;
            try
            {
                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
                String type = (parameters.hasParameter("type") == true) ? (String)parameters.getParameterValue("type") : "text";
                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
                InteropResponse response = getListenerImplementation().login(parameters, type, httpExchange.getRemoteAddress().getHostName());
                result(httpExchange, response);
            }
            catch (Exception e)
            {
                e.printStackTrace();
                result(httpExchange, 400, language, e);
            }
        }
    }
    protected class logout implements HttpHandler
    {
        public void handle(HttpExchange httpExchange) throws IOException
        {
            String language = null;
            try
            {
                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
                InteropResponse response = getListenerImplementation().logout(parameters, httpExchange.getRemoteAddress().getHostName());
                result(httpExchange, response);
            }
            catch (Exception e)
            {
                e.printStackTrace();
                result(httpExchange, 400, language, e);
            }
        }
    }
    protected class artic implements HttpHandler
    {
        String language = null;
        public void handle(HttpExchange httpExchange) throws IOException
        {
            try
            {
                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
                String operation = (String)parameters.getParameterValue("operation");
                // No operation, operation comes in URL
                    if (operation == null)
                    {
                        String path = httpExchange.getRequestURI().getPath();
                        if (path.startsWith("/artic"))
                        {
                            operation = path.replace("/artic", "");
                        }
                        else if (path.startsWith("/art"))
                        {
                            operation = path.replace("/art", "");
                        }
                        if (httpExchange.getRequestMethod().equalsIgnoreCase("GET") == true)
                        {
                            operation = "get" + operation;
                        }
                        else if (httpExchange.getRequestMethod().equalsIgnoreCase("PUT") == true)
                        {
                            operation = "set" + operation;
                        }
                        else if (httpExchange.getRequestMethod().equalsIgnoreCase("POST") == true)
                        {
                            operation = "set" + operation;
                        }
                        // example POST /artic/fisrt/second -> setFistSecond
                        // example PY T /artic/fisrt/second -> setFistSecond
                        // example GET  /artic/fisrt/second -> getFistSecond
                        operation = operation.replace("/", " ");
                        operation = Arrays.stream(operation.split("\\s+"))
                                .map(word -> Character.toUpperCase(word.charAt(0)) + word.substring(1))
                                .collect(Collectors.joining(" ")).replaceAll(" ", "");
                        operation = operation.substring(0,1).toLowerCase() + operation.substring(1, operation.length());
                        parameters.addParameter("operation", operation);
                    }
                int tokenStatus = checkToken(parameters, httpExchange.getRemoteAddress().getHostName());
                if (tokenStatus != 200)
                {
                    result(httpExchange, tokenStatus, "Invalid authentication or invalid token");
                }
                InteropResponse response = getListenerImplementation().artic(parameters);
                result(httpExchange, response);
            }
            catch (Exception exception)
            {
                Shared.println(Shared.getMessage("Model"), exception);
                exception.printStackTrace();
                result(httpExchange, 400, language, exception);
            }
        }
    }
    protected class gis implements HttpHandler
    {
        public void handle(HttpExchange httpExchange) throws IOException
        {
            try
            {
                String uri = httpExchange.getRequestURI().getRawQuery();
                InteropResponse response = getListenerImplementation().gis(uri);
                result(httpExchange, response);
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
                result(httpExchange, 400, "", exception);
            }
        }
    }
    protected class saml implements HttpHandler
    {
        public void handle(HttpExchange httpExchange) throws IOException
        {
            try
            {
                InteropParameters parameters = new InteropParameters();
                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
                InteropResponse response = getListenerImplementation().saml(parameters);
                result(httpExchange, response);
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
                result(httpExchange, 400, "", exception);
            }
        }
    }
    private int checkToken(InteropParameters parameters, String remoteAddress)
    {
        try
        {
            HttpAuthentication authentication = Serialization.deserialize(HttpAuthentication.class, Licence.decrypt((String)parameters.getParameterValue("token")));
            if (authentication.isTokenValid(remoteAddress) == false)
            {
                return 401; // Page expired
            }
            parameters.addParameter("username", authentication.username);
            parameters.addParameter("computer", authentication.address);
            authentication.lastRequestTimestamp = System.currentTimeMillis();
            return 200;
        }
        catch (Exception e)
        {
        }
        try
        {
            String[] login = ((String)parameters.getParameterValue("token")).split(",");
            String username = login[0];
            String password = login[1];
            HttpAuthentication authentication = getListenerImplementation().login(username, password, remoteAddress);
            String token = URLDecoder.decode(authentication.getHttpToken().token, StandardCharsets.UTF_8.toString());
            parameters.setParameter("token", token);
            authentication.lastRequestTimestamp = System.currentTimeMillis();
            parameters.addParameter("username", authentication.username);
            parameters.addParameter("computer", authentication.address);
            return 200;
        }
        catch (Exception exception)
        {
            Shared.println(Shared.getMessage("Model"), exception);
        }
        return 401; // Invalid token, unauthorized
    }
    protected class get implements HttpHandler
    {
        String language = null;
        public void handle(HttpExchange httpExchange) throws IOException
        {
            try
            {
                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
                InteropResponse response = getListenerImplementation().get(parameters);
                result(httpExchange, response);
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
                result(httpExchange, 400, language, exception);
            }
        }
    }
    protected class set implements HttpHandler
    {
        public void handle(HttpExchange httpExchange) throws IOException
        {
            String language = null;
            try
            {
                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
                InteropResponse response = getListenerImplementation().set(parameters);
                result(httpExchange, response);
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
                result(httpExchange, 400, language, exception);
            }
        }
    }
    protected class session implements HttpHandler
    {
        public void handle(HttpExchange httpExchange) throws IOException
        {
            String language = null;
            try
            {
                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
                String token = (parameters.hasParameter("token") == true) ? (String)parameters.getParameterValue("token") : "";
                if (checkToken(language, token) == false)
                {
                    throw new SerializationException(Shared.getMessage(language, "Invalid session"));
                }
                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
                InteropResponse response = getListenerImplementation().session(parameters);
                result(httpExchange, response);
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
                result(httpExchange, 400, language, exception);
            }
        }
    }
     private boolean checkToken(String language, String token)
     {
         try
         {
            InteropParameters parameters = new InteropParameters();
            parameters.addParameter(new InteropParameter("service", "transactions"));
            parameters.addParameter(new InteropParameter("operation", "checkToken"));
            parameters.addParameter(new InteropParameter("language", language));
            parameters.addParameter(new InteropParameter("token", token));
            InteropResponse response = Shared.controllerTransactions.set(parameters);
            boolean result = (Boolean)response.getValue()[0];
            if (result == true) return true;
         }
         catch (Exception e)
         {
         }
         return false;
     }
    // <editor-fold defaultstate="collapsed" desc="Request body">
    private byte[] getRequestBody(HttpExchange httpExchange) throws Exception
    {
        ByteArrayOutputStream bos = null;
        try
        {
            InputStream input = httpExchange.getRequestBody();
            bos = new ByteArrayOutputStream();
            byte[] buffer = new byte[8196];
            int length;
            while ((length = input.read(buffer)) != -1)
            {
                bos.write(buffer, 0, length);
            }
            return bos.toByteArray();
        }
        catch (Exception exception)
        {
            Shared.println(Shared.getMessage("Model"), exception);
            throw exception;
        }
        finally
        {
            try { bos.close(); } catch (Exception ex) {};
            httpExchange.getRequestBody().close();
        }
    }
     // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Response">
    protected void result(HttpExchange httpExchange, int httpErrorCode,  byte[] data) throws Exception
    {
        try
        {
            httpExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
            httpExchange.getResponseHeaders().set("Accept", "*/*");
            httpExchange.sendResponseHeaders(httpErrorCode, data.length);
            httpExchange.getResponseBody().write(data);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            httpExchange.getResponseBody().close();
        }
    }
    protected void result(HttpExchange httpExchange, InteropResponse response)
    {
        // https://www.sitepoint.com/mime-types-complete-list/
        // httpExchange.getResponseHeaders().set("Content-Type", "text/html; charset=" + StandardCharsets.UTF_8);
        // httpExchange.getResponseHeaders().set("Content-Type", "application/pdf"; charset=" + StandardCharsets.UTF_8);
        // httpExchange.getResponseHeaders().set("Content-Type", "application/vnd.ms-excel"; charset=" + StandardCharsets.UTF_8);
        httpExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
        httpExchange.getResponseHeaders().set("Accept", "*/*");
        if (httpExchange.getRequestMethod().equalsIgnoreCase("OPTIONS"))
        {
            httpExchange.getResponseHeaders().add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
            httpExchange.getResponseHeaders().add("Access-Control-Allow-Headers", "Content-Type,Authorization");
            try
            {
                httpExchange.sendResponseHeaders(204, -1);
            }
            catch (Exception e)
            {
            }
            httpExchange.close();
            return;
        }
        if (response.mime == null)
        {
            httpExchange.getResponseHeaders().set("Content-Type", "application/json; charset=" + StandardCharsets.UTF_8);
        }
        else
        {
            httpExchange.getResponseHeaders().set("Content-Type", response.mime + "; charset=" + StandardCharsets.UTF_8);
        }
        // Check if response is a file
        if (response.name != null)
        {
            try
            {
                // For filenames with polish characters
                byte[] filenameBytes = response.name.getBytes("UTF-8");
                String filename = "";
                for (byte character : filenameBytes) filename += (char)(character & 0xFF);
                httpExchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + filename + "\"");
            }
            catch (Exception e)
            {
                httpExchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + response.name + "\"");
            }
        }
        // Check mime text/plain
        if (response.mime != null)
        {
            if (response.mime.equalsIgnoreCase("text/plain"))
            {
                try
                {
                    byte[] data = ((String)response.getValue()[0]).getBytes();
                    result(httpExchange, 200, data);
                    httpExchange.close();
                    return;
                }
                catch (Exception exception)
                {
                    manageException(httpExchange, exception);
                }
                return;
            }
            else if (response.mime.equalsIgnoreCase("application/json"))
            {
                try
                {
                    if (response.array == true)
                    {
                        String message = Serialization.toString(response.getValue());
                        result(httpExchange, 200, message.getBytes());
                    }
                    else
                    {
                        String message = Serialization.toString(response.getValue()[0]);
                        result(httpExchange, 200, message.getBytes());
                    }
                }
                catch (Exception e)
                {
                    manageException(httpExchange, e);
                }
                return;
            }
        }
        // Try send raw bytes
        try
        {
            if (response.getValue().length == 0)
            {
                String message = Serialization.toString(response.getValue());
                result(httpExchange, 200, message.getBytes());
                httpExchange.close();
                return;
            }
            byte[] data = (byte[])response.getValue()[0];
            result(httpExchange, 200, data);
            httpExchange.close();
            return;
        }
        catch (ClassCastException exception)
        {
        }
        catch (Exception exception)
        {
            manageException(httpExchange, exception);
        }
        // Default JSON
        try
        {
            if (response.array == false)
            {
                String message = Serialization.toString(response.getValue()[0]);
                result(httpExchange, 200, message.getBytes());
                httpExchange.close();
                return;
            }
            else
            {
                if (response.getValue().length == 0)
                {
                    String message = Serialization.toString(response.getValue());
                    result(httpExchange, 200, message.getBytes());
                    httpExchange.close();
                    return;
                }
                else
                {
                    String message = Serialization.toString(response.getValue());
                    result(httpExchange, 200, message.getBytes());
                    httpExchange.close();
                    return;
                }
            }
        }
        catch (Exception exception)
        {
            manageException(httpExchange, exception);
        }
    }
    protected void result (HttpExchange httpExchange, int httpErrorCode, String language, Exception exception)
    {
        if (((exception instanceof SerializationException) || (exception instanceof ServerException)) && (exception.getMessage() != null))
        {
            result(httpExchange, httpErrorCode, Shared.getMessage(language, exception.getMessage()));
        }
        else if ((exception instanceof SerializationException) && (((SerializationException)exception).getStackMessage() != null))
        {
            result(httpExchange, httpErrorCode, ((SerializationException)exception).getStackMessage());
        }
        else if ((exception instanceof ServerException) && (((ServerException)exception).getStackMessage() != null))
        {
            result(httpExchange, httpErrorCode, ((ServerException)exception).getStackMessage());
        }
        else
        {
            StringWriter sw = new StringWriter();
            exception.printStackTrace(new PrintWriter(sw));
            String message = sw.toString();
            result(httpExchange, httpErrorCode, message);
        }
    }
    protected void result (HttpExchange httpExchange, int httpErrorCode, String message)
    {
        try
        {
            if (message != null)
            {
                result(httpExchange, httpErrorCode, message.getBytes());
            }
            else
            {
                result(httpExchange, httpErrorCode, new String().getBytes());
            }
        }
        catch (Exception e)
        {
            manageException(httpExchange, e);
        }
    }
     // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Exception">
    private void manageException (HttpExchange httpExchange, Exception exception)
    {
        try
        {
            httpExchange.close();
        }
        catch (Exception e)
        {
        }
        if (exception instanceof IOException)
        {
            String message = exception.toString().toLowerCase();
            if (message.contains("an established connection was aborted by the software in your host machine") == true)
            {
                if (server != null)
                {
                    Shared.traceError(name, "Disconnecting", exception);
                    try{server.stop(10);} catch (Exception ex){};
                    server = null;
                    connect();
                }
            }
        }
    }
     // </editor-fold>
}
servers/server/src/art/servers/controller/ControllerListenerHttpWeb.java
New file
@@ -0,0 +1,637 @@
package art.servers.controller;
import art.library.interop.InteropParameter;
import art.library.interop.InteropParameters;
import art.library.interop.InteropResponse;
import art.library.interop.serialization.Serialization;
import art.library.interop.serialization.SerializationException;
import art.library.utils.licence.Licence;
import art.servers.Shared;
import art.servers.configuration.Configuration;
import art.servers.configuration.ConfigurationListenerHttp;
import art.servers.configuration.ConfigurationSecurity;
import art.servers.types.HttpAuthentication;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.rmi.ServerException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
public class ControllerListenerHttpWeb extends Thread
{
    protected String name = null;
    protected ConfigurationListenerHttp configuration = null;
    protected HttpServer server = null;
    protected ListenerImplementation listenerImplementation = null;
    protected ConfigurationSecurity security = null;
    public List<HttpAuthentication> autentications = new ArrayList<HttpAuthentication>();
    public ControllerListenerHttpWeb(ConfigurationListenerHttp configuration, ConfigurationSecurity security)
    {
        this.name = Shared.getMessage("Listener HTTPS");
        this.configuration = configuration;
        this.security = security;
        this.listenerImplementation = new ListenerImplementation();
        this.setName(name);
    }
    public void run()
    {
        Shared.traceInformation(name, "Starting");
        while (isInterrupted() == false)
        {
            try
            {
                if (server == null)
                {
                    connect();
                }
                sleep(1000);
            }
            catch (Exception e)
            {
            }
        }
        Shared.traceInformation(name, "Finishing");
    }
    protected void connect()
    {
        try
        {
            server = HttpServer.create(new InetSocketAddress(configuration.port), 0);
            contexts();
            server.setExecutor(Executors.newCachedThreadPool());
            server.start();
            return;
        }
        catch (Exception e)
        {
        }
    }
    protected void contexts()
    {
        server.createContext("/login", new login());
        server.createContext("/art", new art());
    }
    protected class login implements HttpHandler
    {
        public void handle(HttpExchange httpExchange) throws IOException
        {
            String language = null;
            try
            {
                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
                String type = (parameters.hasParameter("type") == true) ? (String)parameters.getParameterValue("type") : "text";
                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
                InteropResponse response = login(parameters, type, httpExchange.getRemoteAddress().getHostName());
                result(httpExchange, response);
            }
            catch (Exception e)
            {
                result(httpExchange, 400, language, e);
            }
        }
        private InteropResponse login(InteropParameters parameters, String type, String address) throws SerializationException
        {
            String language = (String)parameters.getParameterValue("language");
            try
            {
                String username = (String)parameters.getParameterValue("username");
                String password = (String)parameters.getParameterValue("password");
                HttpAuthentication authentication = login(username, password, address);
                if (type.equalsIgnoreCase("json"))
                {
                    InteropResponse response = new InteropResponse(authentication.getHttpToken());
                    Object[] objects = response.getValue();
                    return response;
                }
                else
                {
                    InteropResponse response = new InteropResponse(authentication.getHttpToken().token);
                    response.mime = "text/plain";
                    return response;
                }
            }
            catch (Exception e)
            {
               StringWriter sw = new StringWriter();
               e.printStackTrace(new PrintWriter(sw));
               throw new SerializationException(Shared.getMessage(language, "Authentication error"));
            }
        }
        private HttpAuthentication login(String username, String password, String address) throws Exception
        {
            // Check user autentication
            Configuration configuration = (Configuration)Shared.configuration;
            HttpAuthentication authentication = new HttpAuthentication(username, password, address);
            if ((username.equals("read")) && (password.equals(Licence.decrypt(security.readPassword))))
            {
                authentication.profileWebServer = HttpAuthentication.PROFILE_READ;
            }
            else if ((username.equals("write")) && (password.equals(Licence.decrypt(security.writePassword))))
            {
                authentication.profileWebServer = HttpAuthentication.PROFILE_WRITE;
            }
            else if ((username.equals("admin")) && (password.equals(Licence.decrypt(security.adminPassword))))
            {
                authentication.profileWebServer = HttpAuthentication.PROFILE_ADMIN;
            }
            else
            {
                throw new Exception("Autentication error");
            }
            return authentication;
        }
    }
    protected class art implements HttpHandler
    {
        public void handle(HttpExchange httpExchange) throws IOException
        {
            String language = null;
            try
            {
                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
                int tokenStatus = checkToken(httpExchange, parameters);
                if (tokenStatus != 200)
                {
                    result(httpExchange, tokenStatus, Shared.getMessage(language, "Invalid token"));
                }
                else
                {
                    parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
                    String operation = (String)parameters.getParameterValue("operation");
                    Method method = listenerImplementation.getClass().getMethod(operation, parameters.getClass());
                    InteropResponse response = (InteropResponse)method.invoke(listenerImplementation, parameters);
                    result(httpExchange, response);
                }
            }
            catch (Exception exception)
            {
                result(httpExchange, 400, language, exception);
            }
        }
    }
    protected int checkToken(HttpExchange httpExchange, InteropParameters parameters)
    {
        Configuration configuration = (Configuration)Shared.configuration;
        try
        {
            HttpAuthentication authentication = Serialization.deserialize(HttpAuthentication.class, Licence.decrypt((String)parameters.getParameterValue("token")));
            authentication.updateExpirationTimestamp();
            if (authentication.isTokenValid(httpExchange.getRemoteAddress().getHostName()) == false)
            {
                return 401; // Page expired
            }
            authentication.lastRequestTimestamp = System.currentTimeMillis();
            return 200;
        }
        catch (Exception e)
        {
        }
        try
        {
            String[] login = ((String)parameters.getParameterValue("token")).split(",");
            String username = login[0];
            String password = login[1];
            if ((username.equals("read")) && (password.equals(Licence.decrypt(security.readPassword))))
            {
                HttpAuthentication authentication = new HttpAuthentication(username, password, httpExchange.getRemoteAddress().getHostName(), HttpAuthentication.PROFILE_READ);
                authentication.updateExpirationTimestamp();
                String token = URLDecoder.decode(authentication.getHttpToken().token, StandardCharsets.UTF_8.toString());
                parameters.setParameter("token", token);
                authentication.lastRequestTimestamp = System.currentTimeMillis();
                return 200;
            }
            if ((username.equals("write")) && (password.equals(Licence.decrypt(security.writePassword))))
            {
                HttpAuthentication authentication = new HttpAuthentication(username, password, httpExchange.getRemoteAddress().getHostName(), HttpAuthentication.PROFILE_WRITE);
                authentication.updateExpirationTimestamp();
                String token = URLDecoder.decode(authentication.getHttpToken().token, StandardCharsets.UTF_8.toString());
                parameters.setParameter("token", token);
                authentication.lastRequestTimestamp = System.currentTimeMillis();
                return 200;
            }
            if ((username.equals("admin")) && (password.equals(Licence.decrypt(security.adminPassword))))
            {
                HttpAuthentication authentication = new HttpAuthentication(username, password, httpExchange.getRemoteAddress().getHostName(), HttpAuthentication.PROFILE_ADMIN);
                authentication.updateExpirationTimestamp();
                String token = URLDecoder.decode(authentication.getHttpToken().token, StandardCharsets.UTF_8.toString());
                parameters.setParameter("token", token);
                authentication.lastRequestTimestamp = System.currentTimeMillis();
                return 200;
            }
        }
        catch (Exception e)
        {
        }
        try
        {
            HttpAuthentication authentication = getAuthentication(httpExchange);
            authentication.updateExpirationTimestamp();
            String token = URLDecoder.decode(authentication.getHttpToken().token, StandardCharsets.UTF_8.toString());
            parameters.addParameter("token", token);
            authentication.lastRequestTimestamp = System.currentTimeMillis();
            return 200;
        }
        catch (Exception e)
        {
        }
        return 401; // Invalid token, unauthorized
    }
    public HttpAuthentication getAuthentication(HttpExchange httpExchange)
    {
        String address = httpExchange.getRemoteAddress().getHostName();
        String userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
        for (HttpAuthentication current : autentications)
        {
            if ((current.userAgent.equals(userAgent)) && (current.address.equals(address)))
            {
                return current;
            }
        }
        return null;
    }
    // <editor-fold defaultstate="collapsed" desc="Request body">
    protected byte[] getRequestBody(HttpExchange httpExchange) throws Exception
    {
        ByteArrayOutputStream bos = null;
        try
        {
            InputStream input = httpExchange.getRequestBody();
            bos = new ByteArrayOutputStream();
            byte[] buffer = new byte[8196];
            int length;
            while ((length = input.read(buffer)) != -1)
            {
                bos.write(buffer, 0, length);
            }
            return bos.toByteArray();
        }
        catch (Exception exception)
        {
            throw exception;
        }
        finally
        {
            try { bos.close(); } catch (Exception ex) {};
            httpExchange.getRequestBody().close();
        }
    }
     // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Response">
    protected void result(HttpExchange httpExchange, int httpErrorCode,  byte[] data) throws Exception
    {
        try
        {
            httpExchange.sendResponseHeaders(httpErrorCode, data.length);
            httpExchange.getResponseBody().write(data);
        }
        finally
        {
            try { httpExchange.getResponseBody().close(); } catch (Exception e) {}
            try { httpExchange.close(); } catch (Exception e) {}
        }
    }
    protected void result(HttpExchange httpExchange, InteropResponse response)
    {
        // https://www.sitepoint.com/mime-types-complete-list/
        // httpExchange.getResponseHeaders().set("Content-Type", "text/html; charset=" + StandardCharsets.UTF_8);
        // httpExchange.getResponseHeaders().set("Content-Type", "application/pdf"; charset=" + StandardCharsets.UTF_8);
        // httpExchange.getResponseHeaders().set("Content-Type", "application/vnd.ms-excel"; charset=" + StandardCharsets.UTF_8);
        httpExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
        if (httpExchange.getRequestMethod().equalsIgnoreCase("OPTIONS"))
        {
            httpExchange.getResponseHeaders().add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
            httpExchange.getResponseHeaders().add("Access-Control-Allow-Headers", "Content-Type,Authorization");
            try
            {
                httpExchange.sendResponseHeaders(204, -1);
            }
            catch (Exception e)
            {
            }
            httpExchange.close();
            return;
        }
        if (response.mime == null)
        {
            httpExchange.getResponseHeaders().set("Content-Type", "application/json; charset=" + StandardCharsets.UTF_8);
        }
        else
        {
            httpExchange.getResponseHeaders().set("Content-Type", response.mime + "; charset=" + StandardCharsets.UTF_8);
        }
        // Check if response is a file
        if (response.name != null)
        {
            try
            {
                // For filenames with polish characters
                byte[] filenameBytes = response.name.getBytes("UTF-8");
                String filename = "";
                for (byte character : filenameBytes) filename += (char)(character & 0xFF);
                httpExchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + filename + "\"");
            }
            catch (Exception e)
            {
                httpExchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + response.name + "\"");
            }
        }
        // Check mime text/plain
        if (response.mime != null)
        {
            if (response.mime.equalsIgnoreCase("text/plain"))
            {
                try
                {
                    byte[] data = ((String)response.getValue()[0]).getBytes();
                    result(httpExchange, 200, data);
                    httpExchange.close();
                    return;
                }
                catch (Exception exception)
                {
                    manageException(httpExchange, exception);
                }
                return;
            }
            else if (response.mime.equalsIgnoreCase("application/json"))
            {
                 try
                {
                    if (response.array == true)
                    {
                        String message = Serialization.toString(response.getValue());
                        result(httpExchange, 200, message.getBytes());
                    }
                    else
                    {
                        String message = Serialization.toString(response.getValue()[0]);
                        result(httpExchange, 200, message.getBytes());
                    }
                }
                catch (Exception e)
                {
                    manageException(httpExchange, e);
                }
                return;
            }
        }
        // Try send raw bytes
        try
        {
            byte[] data = (byte[])response.getValue()[0];
            result(httpExchange, 200, data);
            httpExchange.close();
            return;
        }
        catch (Exception exception)
        {
            manageException(httpExchange, exception);
        }
        // Default JSON
        try
        {
            if (response.array == false)
            {
                String message = Serialization.toString(response.getValue()[0]);
                result(httpExchange, 200, message.getBytes());
                httpExchange.close();
                return;
            }
            else
            {
                if (response.getValue().length == 0)
                {
                    String message = Serialization.toString(response.getValue());
                    result(httpExchange, 200, message.getBytes());
                    httpExchange.close();
                    return;
                }
                else
                {
                    String message = Serialization.toString(response.getValue());
                    result(httpExchange, 200, message.getBytes());
                    httpExchange.close();
                    return;
                }
            }
        }
        catch (Exception exception)
        {
            manageException(httpExchange, exception);
        }
    }
    protected void result (HttpExchange httpExchange, int httpErrorCode, String language, Exception exception)
    {
        Throwable throwable = exception.getCause();
        if (throwable != null)
        {
            if ((throwable instanceof SerializationException) || (throwable instanceof ServerException))
            {
                result(httpExchange, httpErrorCode, Shared.getMessage(language, throwable.getMessage()));
            }
        }
        if ((exception instanceof SerializationException) || (exception instanceof ServerException))
        {
            result(httpExchange, httpErrorCode, Shared.getMessage(language, exception.getMessage()));
        }
        StringWriter sw = new StringWriter();
        exception.printStackTrace(new PrintWriter(sw));
        String message = sw.toString();
        result(httpExchange, httpErrorCode, message);
    }
    protected void result (HttpExchange httpExchange, int httpErrorCode, String message)
    {
        try
        {
            result(httpExchange, httpErrorCode, message.getBytes());
        }
        catch (Exception e)
        {
            manageException(httpExchange, e);
        }
    }
     // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Exception">
    protected void manageException (HttpExchange httpExchange, Exception exception)
    {
        try
        {
            httpExchange.close();
        }
        catch (Exception e)
        {
        }
        if (exception instanceof IOException)
        {
            String message = exception.toString().toLowerCase();
            if (message.contains("an established connection was aborted by the software in your host machine") == true)
            {
                if (server != null)
                {
                    try{server.stop(10);} catch (Exception ex){};
                    server = null;
                    connect();
                }
            }
        }
    }
     // </editor-fold>
}
servers/server/src/art/servers/controller/ControllerListenerHttps.java
New file
@@ -0,0 +1,142 @@
package art.servers.controller;
import art.library.utils.resources.Resources;
import art.servers.Shared;
import art.servers.configuration.ConfigurationListenerHttp;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsParameters;
import com.sun.net.httpserver.HttpsServer;
import java.io.File;
import java.io.FileInputStream;
import java.net.InetSocketAddress;
import java.security.KeyStore;
import java.util.concurrent.Executors;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManagerFactory;
public class ControllerListenerHttps extends ControllerListenerHttp
{
    // keytool -genkey -v -keystore x:\test\https\artic_key.keystore -alias artic -keyalg RSA -keysize 2048 -validity 10000
    public ControllerListenerHttps(ConfigurationListenerHttp configuration)
    {
        super(configuration);
        this.name = Shared.getMessage("Listener https");
        this.setName(this.getClass().getName() + " : " + name);
    }
    public void run()
    {
        Shared.traceInformation(name, "Starting");
        while ((isInterrupted() == false) && (exit == false))
        {
            try
            {
                if (server == null)
                {
                    connect();
                }
                sleep(1000);
            }
            catch (Exception e)
            {
            }
        }
        Shared.traceInformation(name, "Finishing");
    }
    protected void connect()
    {
        try
        {
            // Setup the socket address
            InetSocketAddress address = new InetSocketAddress(configuration.port);
            // initialise the HTTPS server
            server = HttpsServer.create(address, 0);
            SSLContext sslContext = SSLContext.getInstance("TLS");
            // initialise the keystore
            char[] password = configuration.keystorePassword.toCharArray();
            KeyStore ks = KeyStore.getInstance("JKS");
            if ((new File(configuration.keystoreLocation)).exists() == true)
            {
                ks.load(new FileInputStream(configuration.keystoreLocation), password);
            }
            else
            {
                ks.load(Resources.getResourceStream(configuration.keystoreLocation), password);
            }
            // setup the key manager factory
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(ks, password);
            // setup the trust manager factory
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(ks);
            // setup the HTTPS context and parameters
            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
            ((HttpsServer)server).setHttpsConfigurator(new HttpsConfigurator(sslContext)
            {
                public void configure(HttpsParameters params)
                {
                    try
                    {
                        // initialise the SSL context
                        SSLContext c = SSLContext.getDefault();
                        SSLEngine engine = c.createSSLEngine();
                        params.setNeedClientAuth(false);
                        params.setCipherSuites(engine.getEnabledCipherSuites());
                        params.setProtocols(engine.getEnabledProtocols());
                        // get the default parameters
                        SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
                        params.setSSLParameters(defaultSSLParameters);
                    }
                    catch (Exception e)
                    {
                    }
                }
            });
            contexts();
            server.setExecutor(Executors.newCachedThreadPool());
            server.start();
            Shared.traceInformation(name, "Listening",  Shared.getMessage("Port") + " = " + configuration.port);
            return;
        }
        catch (Exception exception)
        {
            Shared.traceError(name, "Listening",  Shared.getMessage("Port") + " = " + configuration.port, exception);
        }
    }
}
servers/server/src/art/servers/controller/ControllerListenerHttpsWeb.java
New file
@@ -0,0 +1,109 @@
package art.servers.controller;
import art.library.utils.licence.Licence;
import art.library.utils.resources.Resources;
import art.servers.configuration.ConfigurationListenerHttp;
import art.servers.configuration.ConfigurationSecurity;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsParameters;
import com.sun.net.httpserver.HttpsServer;
import java.io.File;
import java.io.FileInputStream;
import java.net.InetSocketAddress;
import java.security.KeyStore;
import java.util.concurrent.Executors;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManagerFactory;
public class ControllerListenerHttpsWeb extends ControllerListenerHttpWeb
{
    public ControllerListenerHttpsWeb(ConfigurationListenerHttp configuration, ConfigurationSecurity security)
    {
        super(configuration, security);
    }
    protected void connect()
    {
        try
        {
            // Setup the socket address
            InetSocketAddress address = new InetSocketAddress(configuration.port);
            // initialise the HTTPS server
            server = HttpsServer.create(address, 0);
            SSLContext sslContext = SSLContext.getInstance("TLS");
            // initialise the keystore
            char[] password = Licence.decrypt(configuration.keystorePassword).toCharArray();
            KeyStore ks = KeyStore.getInstance("JKS");
            if ((new File(configuration.keystoreLocation)).exists() == true)
            {
                ks.load(new FileInputStream(configuration.keystoreLocation), password);
            }
            else
            {
                ks.load(Resources.getResourceStream(configuration.keystoreLocation), password);
            }
            // setup the key manager factory
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(ks, password);
            // setup the trust manager factory
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(ks);
            // setup the HTTPS context and parameters
            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
            ((HttpsServer)server).setHttpsConfigurator(new HttpsConfigurator(sslContext)
            {
                public void configure(HttpsParameters params)
                {
                    try
                    {
                        // initialise the SSL context
                        SSLContext c = SSLContext.getDefault();
                        SSLEngine engine = c.createSSLEngine();
                        params.setNeedClientAuth(false);
                        params.setCipherSuites(engine.getEnabledCipherSuites());
                        params.setProtocols(engine.getEnabledProtocols());
                        // get the default parameters
                        SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
                        params.setSSLParameters(defaultSSLParameters);
                    }
                    catch (Exception e)
                    {
                    }
                }
            });
            contexts();
            server.setExecutor(Executors.newCachedThreadPool());
            server.start();
            return;
        }
        catch (Exception exception)
        {
            exception.printStackTrace();
        }
    }
}
servers/server/src/art/servers/controller/ControllerListenerWEB.java
New file
@@ -0,0 +1,260 @@
package art.servers.controller;
import art.library.interop.InteropParameters;
import art.library.utils.licence.Licence;
import art.library.utils.resources.Resources;
import art.servers.Shared;
import art.servers.configuration.ConfigurationListenerHttp;
import art.servers.configuration.ConfigurationSecurity;
import art.servers.types.HttpAuthentication;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
public class ControllerListenerWEB extends ControllerListenerHttpsWeb
{
    private List<HttpAuthentication> autentications = new ArrayList<HttpAuthentication>();
    public ControllerListenerWEB(ConfigurationListenerHttp configuration, ConfigurationSecurity configurationSecutiry)
    {
        super(configuration, configurationSecutiry);
    }
    public void contexts()
    {
        super.contexts();
        server.createContext("/", new entry());
        server.createContext("/connect", new connect());
        server.createContext("/logout", new disconnect());
    }
    public class entry implements HttpHandler
    {
        public void handle(HttpExchange httpExchange) throws IOException
        {
            String language = null;
            try
            {
                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
                byte[] data = null;
                File file = new File("data/" + Shared.getApplicationName() + "/html/login.html");
                if (file.exists() == true)
                {
                    data = Files.readAllBytes(file.toPath());
                }
                else
                {
                    data = Resources.getResourceBytes("data/" + Shared.getApplicationName() + "/html/login.html");
                }
                result(httpExchange, 200, data);
            }
            catch (Exception exception)
            {
                result(httpExchange, 400, language, exception);
            }
        }
    }
    protected class connect implements HttpHandler
    {
        public void handle(HttpExchange httpExchange) throws IOException
        {
            String language = null;
            try
            {
                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
                String username = (String)parameters.getParameterValue("username");
                String password = (String)parameters.getParameterValue("password");
                HttpAuthentication authentication = new HttpAuthentication(username, password, httpExchange.getRemoteAddress().getHostName());
                authentication.userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
                if ((username.equals("read")) && (password.equals(Licence.decrypt(security.readPassword))))
                {
                    authentication.profileWebServer = HttpAuthentication.PROFILE_READ;
                }
                else if ((username.equals("write")) && (password.equals(Licence.decrypt(security.writePassword))))
                {
                    authentication.profileWebServer = HttpAuthentication.PROFILE_WRITE;
                }
                else if ((username.equals("admin")) && (password.equals(Licence.decrypt(security.adminPassword))))
                {
                    authentication.profileWebServer = HttpAuthentication.PROFILE_ADMIN;
                }
                else if ((username.equals("download")) && (password.equals(Licence.decrypt(security.downloadPassword))))
                {
                    authentication.profileWebServer = HttpAuthentication.PROFILE_DOWNLOAD;
                }
                else
                {
                    throw new Exception("Autentication error");
                }
                addAuthentication(authentication);
                result(httpExchange, 200, new byte[0]);
            }
            catch (Exception exception)
            {
                result(httpExchange, 400, Shared.getMessage(language, "Autentication error"));
            }
        }
    }
    protected class disconnect implements HttpHandler
    {
        public void handle(HttpExchange httpExchange) throws IOException
        {
            String language = null;
            try
            {
                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
                authenticationRemove(httpExchange);
                byte[] data = null;
                File file = new File("data/" + Shared.getApplicationName() + "/html/login.html");
                if (file.exists() == true)
                {
                    data = Files.readAllBytes(file.toPath());
                }
                else
                {
                    data = Resources.getResourceBytes("data/" + Shared.getApplicationName() + "/html/login.html");
                }
                result(httpExchange, 200, data);
            }
            catch (Exception exception)
            {
                result(httpExchange, 400, language, exception);
            }
        }
    }
    public HttpAuthentication getAuthentication(HttpExchange httpExchange)
    {
        String address = httpExchange.getRemoteAddress().getHostName();
        String userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
        for (HttpAuthentication current : autentications)
        {
            if ((current.userAgent.equals(userAgent)) && (current.address.equals(address)))
            {
                return current;
            }
        }
        return null;
    }
    private void addAuthentication(HttpAuthentication authentication)
    {
        for (HttpAuthentication current : autentications)
        {
            if ((current.userAgent.equals(authentication.userAgent)) && (current.address.equals(authentication.address)))
            {
                autentications.remove(current);
            }
        }
        autentications.add(authentication);
    }
    public boolean authenticationValid(HttpExchange httpExchange)
    {
        String address = httpExchange.getRemoteAddress().getHostName();
        String userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
        for (HttpAuthentication current : autentications)
        {
            if ((current.userAgent.equals(userAgent)) && (current.address.equals(address)))
            {
                return true;
            }
        }
        return false;
    }
    public boolean authenticationExpired(HttpExchange httpExchange)
    {
        String address = httpExchange.getRemoteAddress().getHostName();
        String userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
        for (HttpAuthentication current : autentications)
        {
            if ((current.userAgent.equals(userAgent)) && (current.address.equals(address)))
            {
                // TODO
            }
        }
        return false;
    }
    public void authenticationRemove(HttpExchange httpExchange)
    {
        String address = httpExchange.getRemoteAddress().getHostName();
        String userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
        List<HttpAuthentication> removes = new ArrayList<HttpAuthentication>();
        for (HttpAuthentication current : autentications)
        {
            if ((current.userAgent.equals(userAgent)) && (current.address.equals(address)))
            {
                removes.add(current);
            }
        }
        for (HttpAuthentication remove : removes)
        {
            autentications.remove(remove);
        }
    }
}
servers/server/src/art/servers/controller/ControllerNtpHttp.java
New file
@@ -0,0 +1,232 @@
package art.servers.controller;
import art.servers.Shared;
import art.servers.configuration.ConfigurationNtpHttp;
import com.sun.jna.platform.win32.Advapi32;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinBase;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.ptr.IntByReference;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
public class ControllerNtpHttp extends Controller
{
    private ConfigurationNtpHttp configuration = null;
    private String name = null;
    public ControllerNtpHttp(ConfigurationNtpHttp configuration)
    {
        this.name = Shared.getMessage("NTP HTTP");
        this.configuration = configuration;
        Timer timer = new Timer();
        timer.schedule(new TimerTask()
        {
            public void run()
            {
               update();
            }
         }, 0, configuration.polling * 1000);
    }
    private void update()
    {
        try
        {
            long t0 = System.currentTimeMillis();
            String date = getDate(configuration.URL, configuration.timeout, configuration.timeout);
            SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
            long t1 = System.currentTimeMillis();
            long delay = t1 - t0;
            long timestamp = dateFormat.parse(date).getTime() + delay;
            long difference = Math.abs(System.currentTimeMillis() - timestamp);
            if (difference > configuration.maximumAllowedDelay)
            {
                SetLocalTime(timestamp, null);
            }
            Shared.println(name, Shared.getMessage("Time difference") + " = " + difference + " " + Shared.getMessage("ms"));
        }
        catch (Exception exception)
        {
            Shared.printerr(name, exception.getMessage());
        }
    }
    private String getDate(String url, int connectionTimeout, int readTimeout) throws Exception
    {
        HttpURLConnection connection = null;
        ByteArrayOutputStream outputStreamBody = null;
        try
        {
              // Connect to the web server endpoint
              URL httpurl = new URL(url);
              if ((configuration.proxyAddress != null) && (configuration.proxyPort > 0))
              {
                 Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(configuration.proxyAddress, configuration.proxyPort));
                 connection = (HttpURLConnection)httpurl.openConnection(proxy);
              }
              else
              {
                 connection = (HttpURLConnection)httpurl.openConnection();
              }
              connection.setConnectTimeout(connectionTimeout);
              connection.setReadTimeout(readTimeout);
              // Write header
              connection.setRequestMethod("GET");
              connection.addRequestProperty("User-Agent", "ALUVISA");
              connection.addRequestProperty("Content-Type", "application/octet-stream");
              connection.setDoOutput(true);
              // Read answer
              int responseCode = connection.getResponseCode();
              if (responseCode == 200)
              {
                  return connection.getHeaderField("Date");
              }
              else
              {
                  throw new Exception("Response code, " + responseCode);
              }
        }
        catch (Exception exception)
        {
            throw exception;
        }
        finally
        {
            // Disconnect
            try { outputStreamBody.close(); } catch (Exception e) {};
            try { connection.disconnect(); } catch (Exception e) {};
        }
    }
    private static boolean SetLocalTime(long timestamp, String password) throws Exception
    {
        String os = System.getProperty("os.name").toLowerCase();
        if (os.contains("win"))
        {
            // Operating system is based on Windows
            WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(1);
            WinNT.TOKEN_PRIVILEGES oldtp = new WinNT.TOKEN_PRIVILEGES(1);
            WinNT.LUID luid = new WinNT.LUID();
            WinNT.HANDLEByReference hTokenRef = new WinNT.HANDLEByReference();
            if (!Advapi32.INSTANCE.OpenProcessToken(Kernel32.INSTANCE.GetCurrentProcess(), WinNT.TOKEN_ADJUST_PRIVILEGES | WinNT.TOKEN_QUERY, hTokenRef))
            {
                throw new Exception("HTTP clock. Error. OpenProcessToken");
            }
            WinNT.HANDLE hToken = hTokenRef.getValue();
            if (!Advapi32.INSTANCE.LookupPrivilegeValue(null, WinNT.SE_SYSTEMTIME_NAME, luid))
            {
                Kernel32.INSTANCE.CloseHandle(hToken);
                throw new Exception("HTTP clock. Error. LookupPrivilegeValue");
            }
            tp.PrivilegeCount = new WinDef.DWORD(1);
            tp.Privileges = new WinNT.LUID_AND_ATTRIBUTES[1];
            tp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(luid, new WinDef.DWORD(WinNT.SE_PRIVILEGE_ENABLED));
            IntByReference retSize = new IntByReference(0);
            if (!Advapi32.INSTANCE.AdjustTokenPrivileges(hToken, false, tp, tp.size(), oldtp, retSize))
            {
                Kernel32.INSTANCE.CloseHandle(hToken);
                throw new Exception("HTTP clock. Error. AdjustTokenPrivileges");
            }
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(timestamp);
            WinBase.SYSTEMTIME st = new WinBase.SYSTEMTIME();
            st.wYear = (short)calendar.get(Calendar.YEAR);
            st.wMonth = (short)(calendar.get(Calendar.MONTH) + 1);
            st.wDay = (short)calendar.get(Calendar.DAY_OF_MONTH);
            st.wHour = (short)calendar.get(Calendar.HOUR_OF_DAY);
            st.wMinute = (short)calendar.get(Calendar.MINUTE);
            st.wSecond = (short)calendar.get(Calendar.SECOND);
            st.wMilliseconds = (short)calendar.get(Calendar.MILLISECOND);
            st.wDayOfWeek = (short)calendar.get(Calendar.DAY_OF_WEEK);
            boolean  result = Kernel32.INSTANCE.SetLocalTime(st);
            int error = Kernel32.INSTANCE.GetLastError();
            Kernel32.INSTANCE.CloseHandle(hToken);
            return result;
        }
        else if (os.contains("osx"))
        {
            // Operating system is Apple OSX based
        }
        else if (os.contains("nix") || os.contains("aix") || os.contains("nux"))
        {
            // Operating system is based on Linux/Unix/*AIX
            SimpleDateFormat formato1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
            String[] command = {"/bin/bash", "-c", "echo " + password + " | sudo -S date --set='" + formato1.format(timestamp) + "'"};
            //String[] cmd = {"echo " + password + " | sudo -S date --set='" + formato1.format(timestamp) + "'"};
            Process process = Runtime.getRuntime().exec(command);
            int exitValue = process.waitFor();
            if (exitValue != 0)
            {
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                String result = new String();
                String line = null;
                while ((line = reader.readLine()) != null) result = result + line + "\r\n";
                throw new Exception(result);
            }
            else
            {
                return true;
            }
        }
        return false;
    }
}
servers/server/src/art/servers/controller/ControllerProcessInformation.java
New file
@@ -0,0 +1,264 @@
package art.servers.controller;
import art.library.model.devices.application.ApplicationStatus;
import art.library.model.devices.application.status.ApplicationStatusMemory;
import art.library.model.devices.application.status.ApplicationStatusOperatingSystem;
import art.library.model.devices.application.status.ApplicationStatusRuntime;
import art.library.model.devices.application.status.ApplicationStatusThread;
import art.library.utils.windows.System32;
import com.sun.management.OperatingSystemMXBean;
import static java.lang.Thread.sleep;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadMXBean;
import java.util.Enumeration;
import java.util.Hashtable;
import art.servers.Shared;
public class ControllerProcessInformation extends Controller
{
    public float cores = Runtime.getRuntime().availableProcessors();
    public long systemTime = 0;
    public long systemProcessesUsageTime = 0;
    public long cpuLoadPercentage = 0;
    public double processorPercentage = 0;
    private String name = null;
    private ApplicationStatus status = null;
    public ControllerProcessInformation()
    {
        this.name = Shared.getMessage("Controller process information");
        this.setName("Controller process information");
        this.status = new ApplicationStatus();
        start();
    }
    public ApplicationStatus getApplicationStatus()
    {
        return status;
    }
    public void run()
    {
        Shared.traceInformation(name, Shared.getMessage("Starting"));
        // Update realtime
        while ((isInterrupted() == false) && (exit == false))
        {
            long timestamp = System.currentTimeMillis();
            try
            {
                if (Shared.isServerEnabled() == true)
                {
                    update();
                }
            }
            catch (Exception exception)
            {
            }
            long timetowait = (1000 - (System.currentTimeMillis() - timestamp));
            try
            {
                if (timetowait > 0)
                {
                    sleep(timetowait);
                }
            }
            catch (Exception e)
            {
            }
        }
        Shared.traceInformation(name, Shared.getMessage("Finishing"));
    }
    public void update()
    {
        if ((System.getProperty("os.name").toLowerCase().contains("windows") == true))
        {
            windows();
        }
        long timestamp = System.currentTimeMillis();
        memoryMXBean(status, timestamp);
        threadMXBean(status, timestamp);
        runtimeMXBean(status, timestamp);
        operatingSystemMXBean(status, timestamp);
    }
    // <editor-fold defaultstate="collapsed" desc="Windows">
    private void windows()
    {
        try
        {
            Hashtable systemProcesses = (Hashtable)System32.listProcessesHashtable();
            // CPU del sistema
            long newsystemProcessesUsageTime = 0;
            long newsystemTime = System.currentTimeMillis();
            Enumeration enumeration = systemProcesses.elements();
            while (enumeration.hasMoreElements())
            {
                art.library.utils.windows.SystemProcess systemProcess = (art.library.utils.windows.SystemProcess)enumeration.nextElement();
                newsystemProcessesUsageTime = newsystemProcessesUsageTime + systemProcess.lpKernelTime + systemProcess.lpUserTime;
            }
            this.processorPercentage = (((float)(newsystemProcessesUsageTime - this.systemProcessesUsageTime) / (float)(newsystemTime - this.systemTime)) / this.cores) * 100.0f;
            if (this.processorPercentage < 0) Shared.controllerProcessInformation.processorPercentage = 0;
            this.systemTime = newsystemTime;
            this.systemProcessesUsageTime =  newsystemProcessesUsageTime;
        }
        catch (Exception exception)
        {
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="MX">
    private void memoryMXBean(ApplicationStatus status, long timestamp)
    {
        try
        {
            MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
            if (status.memory == null) status.memory = new ApplicationStatusMemory();
            status.memory.timestamp = timestamp;
            MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
            MemoryUsage nonheapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage();
            status.memory.heapMemoryUsage_init = heapMemoryUsage.getInit();
            status.memory.heapMemoryUsage_max = heapMemoryUsage.getMax();
            status.memory.heapMemoryUsage_used = heapMemoryUsage.getUsed();
            status.memory.heapMemoryUsage_committed = heapMemoryUsage.getCommitted();
            status.memory.nonheapMemoryUsage_init = nonheapMemoryUsage.getInit();
            status.memory.nonheapMemoryUsage_max = nonheapMemoryUsage.getMax();
            status.memory.nonheapMemoryUsage_used = nonheapMemoryUsage.getUsed();
            status.memory.nonheapMemoryUsage_committed = nonheapMemoryUsage.getCommitted();
            status.memory.usedMemory = status.memory.heapMemoryUsage_committed +  status.memory.nonheapMemoryUsage_used; // status.memory.heapMemoryUsage_init
         }
        catch (Exception e)
        {
        }
    }
    private void threadMXBean(ApplicationStatus status, long timestamp)
    {
        try
        {
            ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
            if (status.thread == null) status.thread = new ApplicationStatusThread();
            status.thread.timestamp = timestamp;
            status.thread.totalStartedThreadCount = threadMXBean.getTotalStartedThreadCount();
            status.thread.threadCount = threadMXBean.getThreadCount();
            status.thread.peakThreadCount = threadMXBean.getPeakThreadCount();
            status.thread.daemonThreadCount = threadMXBean.getDaemonThreadCount();
        }
        catch (Exception e)
        {
        }
    }
    private void runtimeMXBean(ApplicationStatus status, long timestamp)
    {
        try
        {
            RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
            if (status.runtime == null) status.runtime = new ApplicationStatusRuntime();
            status.runtime.timestamp = timestamp;
            status.runtime.startTime = runtimeMXBean.getStartTime();
            status.runtime.upTime = runtimeMXBean.getUptime();
            status.runtime.userTimeZone = runtimeMXBean.getSystemProperties().get("Time zone");
            status.runtime.javaVmSpecificationVersion = runtimeMXBean.getSystemProperties().get("java.vm.specification.version");
            status.runtime.javaRuntimeVersion = runtimeMXBean.getSystemProperties().get("java.runtime.version");
            status.runtime.javaClassVersion = runtimeMXBean.getSystemProperties().get("java.class.version");
            status.runtime.userCountry = runtimeMXBean.getSystemProperties().get("user.country");
            status.runtime.userLanguage = runtimeMXBean.getSystemProperties().get("user.language");
            status.runtime.userTimeZone = runtimeMXBean.getSystemProperties().get("user.timezone");
        }
        catch (Exception e)
        {
        }
    }
    private void operatingSystemMXBean(ApplicationStatus status, long timestamp)
    {
        try
        {
            OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
            if (status.system == null) status.system = new ApplicationStatusOperatingSystem();
            status.system.timestamp = timestamp;
            status.system.committedVirtualMemorySize = operatingSystemMXBean.getCommittedVirtualMemorySize();
            status.system.name = operatingSystemMXBean.getName();
            status.system.version = operatingSystemMXBean.getVersion();
            status.system.arch = operatingSystemMXBean.getArch();
            status.system.freePhysicalMemorySize = operatingSystemMXBean.getFreePhysicalMemorySize();
            status.system.freeSwapSpaceSize = operatingSystemMXBean.getFreeSwapSpaceSize();
            status.system.processCpuLoad = operatingSystemMXBean.getProcessCpuLoad();
            status.system.processCpuTime = operatingSystemMXBean.getProcessCpuTime() / operatingSystemMXBean.getAvailableProcessors();
            status.system.systemCpuLoad = operatingSystemMXBean.getSystemCpuLoad();
            status.system.totalPhysicalMemorySize = operatingSystemMXBean.getTotalPhysicalMemorySize();
            status.system.totalSwapSpaceSize = operatingSystemMXBean.getTotalSwapSpaceSize();
            status.system.systemLoadAverage = operatingSystemMXBean.getSystemLoadAverage() / operatingSystemMXBean.getAvailableProcessors();
            status.system.availableProcessors = operatingSystemMXBean.getAvailableProcessors();
            status.system.totalPhysicalMemorySize = operatingSystemMXBean.getTotalPhysicalMemorySize();
            status.system.systemLoadAverage = this.processorPercentage;
        }
        catch (Exception e)
        {
        }
    }
    // </editor-fold>
}
servers/server/src/art/servers/controller/ControllerStatus.java
New file
@@ -0,0 +1,354 @@
package art.servers.controller;
import art.library.model.devices.DeviceStatus;
import art.library.model.devices.application.Application;
import art.library.model.devices.application.ApplicationAlarms;
import art.library.model.devices.application.ApplicationInformation;
import art.library.model.devices.application.ApplicationStatus;
import art.library.model.devices.application.status.ApplicationStatusMemory;
import art.library.model.devices.application.status.ApplicationStatusOperatingSystem;
import art.library.model.devices.application.status.ApplicationStatusRuntime;
import art.library.model.devices.application.status.ApplicationStatusThread;
import art.library.utils.synchro.Mutex;
import art.servers.Shared;
import com.sun.management.OperatingSystemMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadMXBean;
import javax.management.MBeanServerConnection;
public class ControllerStatus extends Controller
{
    private Application application = null;
    private Mutex mutexPersistance = new Mutex();
    public ControllerStatus(Application application)
    {
        this.setName("Controller status");
        this.application = application;
        try
        {
            ApplicationStatus status = (ApplicationStatus)this.application.getDeviceStatus();
            status.started = System.currentTimeMillis();
        }
        catch (Exception e)
        {
        }
    }
    public Application getApplication()
    {
        return application;
    }
    public int getAlarms()
    {
        try
        {
           return 0;
        }
        catch (Exception e)
        {
        }
        return DeviceStatus.STATUS_UNKNOWN;
    }
    public void run()
    {
        try
        {
            // Get the stored timeless application if exists
            // If not we use the application from process configuration file
            Application[] timelessApplication = Shared.model.getApplication(0);
            application.information = timelessApplication[0].information;
        }
        catch (Exception e)
        {
        }
        Shared.traceInformation(getName(), "Starting");
        long lastTimestamp = System.currentTimeMillis();
        while ((isInterrupted() == false) && (exit == false))
        {
            // Update current process information
            lastTimestamp = System.currentTimeMillis();
            memoryMXBean(application, lastTimestamp);
            threadMXBean(application, lastTimestamp);
            runtimeMXBean(application, lastTimestamp);
            operatingSystemMXBean(application, lastTimestamp);
            updateAlarms(application, lastTimestamp);
            application.setAlarm("alarm_offline", false);
            if (application.getLastTimestampStatusUpdate() > lastTimestamp)
            {
                application.setLastTimestampStatusUpdate(application.getLastTimestampStatusUpdate() + 1);
            }
            else
            {
                application.setLastTimestampStatusUpdate(lastTimestamp);
            }
            if (application.getLastTimestampUpdate() > lastTimestamp)
            {
                application.setLastTimestampUpdate(application.getLastTimestampUpdate() + 1);
            }
            else
            {
                application.setLastTimestampUpdate(lastTimestamp);
            }
            updatePersistence(application);
            long timetowait = application.getDeviceInformation().hearbeat -(System.currentTimeMillis() - lastTimestamp);
            if (timetowait > 0)
            {
                try
                {
                    sleep(timetowait);
                }
                catch (Exception e)
                {
                }
            }
        }
        Shared.traceInformation(getName(), "Finishing");
    }
    private void updatePersistence(Application application)
    {
        mutexPersistance.lockWrite();
        try
        {
            Shared.model.updateApplication(application);
        }
        catch (Exception e)
        {
        }
        finally
        {
            mutexPersistance.releaseWrite();
        }
    }
    private void memoryMXBean(Application application, long timestamp)
    {
        try
        {
            MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
            ApplicationStatus status = application.getDeviceStatus();
            if (status.memory == null) status.memory = new ApplicationStatusMemory();
            status.memory.timestamp = timestamp;
            MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
            MemoryUsage nonheapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage();
            status.memory.heapMemoryUsage_init = heapMemoryUsage.getInit();
            status.memory.heapMemoryUsage_max = heapMemoryUsage.getMax();
            status.memory.heapMemoryUsage_used = heapMemoryUsage.getUsed();
            status.memory.heapMemoryUsage_committed = heapMemoryUsage.getCommitted();
            status.memory.nonheapMemoryUsage_init = nonheapMemoryUsage.getInit();
            status.memory.nonheapMemoryUsage_max = nonheapMemoryUsage.getMax();
            status.memory.nonheapMemoryUsage_used = nonheapMemoryUsage.getUsed();
            status.memory.nonheapMemoryUsage_committed = nonheapMemoryUsage.getCommitted();
         }
        catch (Exception e)
        {
        }
    }
    private void threadMXBean(Application application, long timestamp)
    {
        try
        {
            ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
            ApplicationStatus status = application.getDeviceStatus();
            if (status.thread == null) status.thread = new ApplicationStatusThread();
            status.thread.timestamp = timestamp;
            long[] threadsid = threadMXBean.getAllThreadIds();
            long threadCpuTime = 0;
            long threadUserTime = 0;
            for (long threadid : threadsid)
            {
                try
                {
                    long currentThreadCpuTime = threadMXBean.getThreadCpuTime(threadid);
                    long currentThreadUserTime = threadMXBean.getThreadUserTime(threadid);
                    if (currentThreadCpuTime > 0) threadCpuTime = threadCpuTime + currentThreadCpuTime;
                    if (currentThreadUserTime > 0) threadUserTime = threadUserTime + currentThreadUserTime;
                }
                catch (Exception e)
                {
                }
            }
            status.thread.totalStartedThreadCount = threadMXBean.getTotalStartedThreadCount();
            status.thread.threadCount = threadMXBean.getThreadCount();
            status.thread.peakThreadCount = threadMXBean.getPeakThreadCount();
            status.thread.daemonThreadCount = threadMXBean.getDaemonThreadCount();
        }
        catch (Exception e)
        {
        }
    }
    private void runtimeMXBean(Application application, long timestamp)
    {
        try
        {
            RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
            ApplicationStatus status = application.getDeviceStatus();
            if (status.runtime == null) status.runtime = new ApplicationStatusRuntime();
            status.runtime.timestamp = timestamp;
            status.runtime.startTime = runtimeMXBean.getStartTime();
            status.runtime.upTime = runtimeMXBean.getUptime();
            status.runtime.userTimeZone = runtimeMXBean.getSystemProperties().get("os.timezone");
            status.runtime.javaVmSpecificationVersion = runtimeMXBean.getSystemProperties().get("java.vm.specification.version");
            status.runtime.javaRuntimeVersion = runtimeMXBean.getSystemProperties().get("java.runtime.version");
            status.runtime.javaClassVersion = runtimeMXBean.getSystemProperties().get("java.class.version");
            status.runtime.userCountry = runtimeMXBean.getSystemProperties().get("user.country");
            status.runtime.userLanguage = runtimeMXBean.getSystemProperties().get("user.language");
            status.runtime.userTimeZone = runtimeMXBean.getSystemProperties().get("user.timezone");
         }
        catch (Exception e)
        {
        }
    }
    private long nanoBefore = 0;
    private long cpuBefore = 0;
    private void operatingSystemMXBean(Application application, long timestamp)
    {
        try
        {
            OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
            ApplicationStatus status = application.getDeviceStatus();
            if (status.system == null) status.system = new ApplicationStatusOperatingSystem();
            status.system.timestamp = timestamp;
            status.system.committedVirtualMemorySize = operatingSystemMXBean.getCommittedVirtualMemorySize();
            status.system.freePhysicalMemorySize = operatingSystemMXBean.getFreePhysicalMemorySize();
            status.system.freeSwapSpaceSize = operatingSystemMXBean.getFreeSwapSpaceSize();
            status.system.processCpuLoad = operatingSystemMXBean.getProcessCpuLoad();
            status.system.processCpuTime = operatingSystemMXBean.getProcessCpuTime();
            status.system.systemCpuLoad = operatingSystemMXBean.getSystemCpuLoad();
            status.system.totalPhysicalMemorySize = operatingSystemMXBean.getTotalPhysicalMemorySize();
            status.system.totalSwapSpaceSize = operatingSystemMXBean.getTotalSwapSpaceSize();
            status.system.systemLoadAverage = operatingSystemMXBean.getSystemLoadAverage();
            status.system.availableProcessors = operatingSystemMXBean.getAvailableProcessors();
            status.system.totalPhysicalMemorySize = operatingSystemMXBean.getTotalPhysicalMemorySize();
            status.system.name = operatingSystemMXBean.getName();
            status.system.version = operatingSystemMXBean.getVersion();
            status.system.arch = operatingSystemMXBean.getArch();
            if (status.system.systemLoadAverage == -1)
            {
                MBeanServerConnection mbsc = ManagementFactory.getPlatformMBeanServer();
                OperatingSystemMXBean osMBean = ManagementFactory.newPlatformMXBeanProxy(
                mbsc, ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, OperatingSystemMXBean.class);
                if (nanoBefore == 0)
                {
                    long cpuBefore = osMBean.getProcessCpuTime();
                    long nanoBefore = System.nanoTime();
                }
                long cpuAfter = osMBean.getProcessCpuTime();
                long nanoAfter = System.nanoTime();
                if (nanoAfter > nanoBefore)
                {
                    status.system.systemLoadAverage = ((cpuAfter-cpuBefore)*100L)/ (nanoAfter-nanoBefore);
                }
                nanoBefore = nanoAfter;
                cpuBefore = cpuAfter;
            }
        }
        catch (Exception e)
        {
        }
    }
    private void updateAlarms(Application application, long timestamp)
    {
        try
        {
            ApplicationInformation information = application.getDeviceInformation();
            ApplicationStatus status = application.getDeviceStatus();
            ApplicationAlarms alarms = application.getDeviceAlarms();
            application.setAlarm("alarm_threads_error", (status.thread.threadCount >=  information.threshold_threads_error),timestamp);
            application.setAlarm("alarm_threads_warning", (status.thread.threadCount >=  information.threshold_threads_warning) && (alarms.alarm_threads_error == 0), timestamp);
            float memoryCommited = (status.memory.heapMemoryUsage_committed + status.memory.nonheapMemoryUsage_committed);
            float memoryused = (status.memory.heapMemoryUsage_used + status.memory.nonheapMemoryUsage_used);
            float memoryLoad = 0.0f;
            if (memoryCommited > 0) memoryLoad = memoryused / memoryCommited;
            application.setAlarm("alarm_memory_error", (memoryLoad >=  information.threshold_memory_error),timestamp);
            application.setAlarm("alarm_memory_warning", (memoryLoad >=  information.threshold_memory_warning) && (alarms.alarm_memory_error == 0), timestamp);
            application.setAlarm("alarm_processCpuLoad_error", (status.system.processCpuLoad >= information.threshold_processCpuLoad_error),timestamp);
            application.setAlarm("alarm_processCpuLoad_warning", (status.system.processCpuLoad >= information.threshold_processCpuLoad_warning) && (alarms.alarm_processCpuLoad_error == 0), timestamp);
            application.setAlarm("alarm_systemCpuLoad_error", (status.system.systemCpuLoad >= information.threshold_systemCpuLoad_error),timestamp);
            application.setAlarm("alarm_systemCpuLoad_warning", (status.system.systemCpuLoad >= information.threshold_systemCpuLoad_warning) && (alarms.alarm_systemCpuLoad_error == 0), timestamp);
        }
        catch (Exception e)
        {
        }
    }
}
servers/server/src/art/servers/controller/ControllerTransactions.java
New file
@@ -0,0 +1,271 @@
package art.servers.controller;
import art.library.interop.InteropParameter;
import art.library.interop.InteropParameters;
import art.library.interop.InteropResponse;
import art.library.interop.serialization.Serialization;
import art.library.interop.serialization.SerializationException;
import art.library.model.devices.Device;
import art.library.model.devices.application.ApplicationInformation;
import art.servers.Shared;
import art.servers.configuration.ConfigurationTransactions;
import art.servers.configuration.ConfigurationTransactionsService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ControllerTransactions extends Controller
{
    private ConfigurationTransactions configuration = null;
    private ApplicationInformation[] lapplication = new ApplicationInformation[0];
    private ConfigurationTransactionsService currentTransactionsService = null;
    public ControllerTransactions(ConfigurationTransactions configuration)
    {
        this.configuration = configuration;
        this.setName("Controller transactions");
        start();
    }
    public ApplicationInformation[] getApplications()
    {
        return lapplication;
    }
    public ApplicationInformation[] getApplications(String service)
    {
        List<ApplicationInformation> result = new ArrayList<ApplicationInformation>();
        for (ApplicationInformation applicationInformation : lapplication)
        {
            if ((applicationInformation.serverServiceName != null)  && (applicationInformation.serverServiceName.equals(service)))
            {
                result.add(applicationInformation);
            }
        }
        return result.toArray(new ApplicationInformation[result.size()]);
    }
    public void run()
    {
        Shared.traceInformation(configuration.name, "Starting");
        long lastTimestamp = System.currentTimeMillis();
        while ((isInterrupted() == false) && (exit == false))
        {
            if (Shared.isServerEnabled() == true)
            {
                try
                {
                    // reload
                    reload();
                    // Wait
                    long timesleep = (configuration.polling * 1000) - (System.currentTimeMillis() - lastTimestamp);
                    if ((timesleep > 0) && (timesleep < (configuration.polling * 1000)))
                    {
                        sleep(timesleep);
                    }
                    // Update devices
                    long currentTimestamp = System.currentTimeMillis();
                    lastTimestamp = currentTimestamp;
                }
                catch (Exception e)
                {
                }
            }
        }
        Shared.traceInformation(configuration.name, "Finishing");
    }
    private void reload()
    {
        for (ConfigurationTransactionsService configurationTransactionsService : configuration.lservicesTransactions)
        {
            try
            {
                InteropParameters parameters = new InteropParameters();
                parameters.addParameter(new InteropParameter("operation", "getApplicationsInformation"));
                parameters.addParameter(new InteropParameter("language", Shared.configuration.general.language));
                InteropResponse response = (InteropResponse)Serialization.invoke("get", parameters, configurationTransactionsService.address, configurationTransactionsService.port, configurationTransactionsService.timeout);
                ApplicationInformation[] lapplication = Arrays.copyOf(response.getValue(), response.getValue().length, ApplicationInformation[].class);
                if (lapplication.length > 0)
                {
                    currentTransactionsService = configurationTransactionsService;
                    this.lapplication = lapplication;
                    return;
                }
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
            }
        }
    }
    public InteropResponse set (InteropParameters parameters) throws  SerializationException
    {
        try
        {
            return (InteropResponse)Serialization.invoke("set", parameters, currentTransactionsService.address, currentTransactionsService.port, currentTransactionsService.timeout);
        }
        catch (Exception exception)
        {
        }
        throw new SerializationException("Operation error (transactions server)");
    }
    public InteropResponse get (InteropParameters parameters) throws  SerializationException
    {
        try
        {
            return (InteropResponse)Serialization.invoke("get", parameters, currentTransactionsService.address, currentTransactionsService.port, currentTransactionsService.timeout);
        }
        catch (Exception exception)
        {
        }
        throw new SerializationException("Operation error (transactions server)");
    }
    public Device getDevice(String service, String identifier) throws SerializationException
    {
        try
        {
            for (ApplicationInformation application : getApplications(service))
            {
                try
                {
                    InteropParameters parameters = new InteropParameters();
                    parameters.addParameter(new InteropParameter("service", application.serverServiceName));
                    parameters.addParameter(new InteropParameter("operation", "getDevice"));
                    parameters.addParameter(new InteropParameter("identifier", identifier));
                    parameters.addParameter(new InteropParameter("language", Shared.configuration.general.language));
                    InteropResponse response = (InteropResponse)Serialization.invoke("get", parameters, application.serverAddress, application.serverPort, 30000);
                    return (Device)response.getValue()[0];
                }
                catch (Exception exception)
                {
                }
            }
        }
        catch (Exception e)
        {
        }
        throw new SerializationException("Device not found");
    }
    public List<Device> getDevices(String service) throws SerializationException
    {
        List<Device> result = new ArrayList<Device>();
        ApplicationInformation[] applications = getApplications(service);
        for (ApplicationInformation application : applications)
        {
            if (service.equalsIgnoreCase(application.serverServiceName))
            {
                try
                {
                    InteropParameters parameters = new InteropParameters();
                    parameters.addParameter(new InteropParameter("service", application.serverServiceName));
                    parameters.addParameter(new InteropParameter("operation", "getDevices"));
                    parameters.addParameter(new InteropParameter("language", Shared.configuration.general.language));
                    InteropResponse response = (InteropResponse)Serialization.invoke("get", parameters, application.serverAddress, application.serverPort, 30000);
                    Device[] devices = Arrays.copyOf(response.getValue(), response.getValue().length, Device[].class);
                    result.addAll(Arrays.asList(devices));
                }
                catch (Exception exception)
                {
                }
            }
        }
        return result;
    }
    public List<Device> getDevices() throws SerializationException
    {
        List<Device> result = new ArrayList<Device>();
        for (ApplicationInformation application : getApplications())
        {
            try
            {
                InteropParameters parameters = new InteropParameters();
                parameters.addParameter(new InteropParameter("service", application.serverServiceName));
                parameters.addParameter(new InteropParameter("operation", "getDevices"));
                parameters.addParameter(new InteropParameter("language", Shared.configuration.general.language));
                InteropResponse response = (InteropResponse)Serialization.invoke("get", parameters, application.serverAddress, application.serverPort, 30000);
                Device[] devices = Arrays.copyOf(response.getValue(), response.getValue().length, Device[].class);
                result.addAll(Arrays.asList(devices));
            }
            catch (Exception exception)
            {
            }
        }
        return result;
    }
    public ApplicationInformation getApplication(String service) throws SerializationException
    {
        for (ApplicationInformation application : getApplications(service))
        {
            if (service.equalsIgnoreCase(application.serverServiceName))
            {
                return(application);
            }
        }
        throw new SerializationException("Application not found");
    }
}
servers/server/src/art/servers/controller/ControllerUserPermissions.java
New file
@@ -0,0 +1,216 @@
package art.servers.controller;
import art.library.model.devices.user.User;
import art.library.model.devices.user.UserPermission;
import art.library.model.transactions.traces.Trace;
import art.library.utils.licence.Licence;
import art.library.utils.synchro.Mutex;
import art.servers.Shared;
import static java.lang.Thread.sleep;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ControllerUserPermissions extends Controller
{
    private HashMap<String, UserPermission> permissions = new HashMap<String, UserPermission>();
    private Mutex mutexUserPermissions = new Mutex();
    private String name = null;
    public ControllerUserPermissions()
    {
        this.name = Shared.getMessage("Controller user permissions");
        this.setName(name);
        start();
    }
    public void run()
    {
        Shared.traceInformation(name, "Starting");
        long lastTimestamp = System.currentTimeMillis();
        while ((isInterrupted() == false) && (exit == false))
        {
            if (Shared.isServerEnabled() == true)
            {
                try
                {
                    // reload
                    // reload();  // LO quito a ver si baja el consumo de memoria
                    // Wait
                    long timesleep = (300000) - (System.currentTimeMillis() - lastTimestamp);
                    if ((timesleep > 0) && (timesleep < 300000))
                    {
                        sleep(timesleep);
                    }
                }
                catch (Exception e)
                {
                }
            }
            try{sleep(50);} catch (Exception exception){};
        }
        Shared.println(Trace.getTraceInformation(Shared.getApplicationName(), name, Shared.getMessage("Finishing"), Shared.getMessage("Success")), true);
    }
    private void reload()
    {
        try
        {
            for (String username : getUsernames())
            {
                try
                {
                    User user = (User)Shared.model.getDeviceExternal(Licence.encrypt(username));
                    setUserPermission(username, user.getDeviceConfiguration().permissions);
                }
                catch (Exception e)
                {
                    User user = (User)Shared.model.getDeviceExternal(username);
                    setUserPermission(username, user.getDeviceConfiguration().permissions);
                }
            }
        }
        catch (Exception e)
        {
        }
    }
    public UserPermission getUserPermission(String username)
    {
        mutexUserPermissions.lockRead();
        UserPermission permission = permissions.get(username);
        mutexUserPermissions.releaseRead();
        try
        {
            if (permission == null)
            {
                try
                {
                    User user = (User)Shared.model.getDeviceExternal(Licence.encrypt(username));
                    permission = user.getDeviceConfiguration().permissions;
                    setUserPermission(username, permission);
                }
                catch (Exception e)
                {
                    User user = (User)Shared.model.getDeviceExternal(username);
                    permission = user.getDeviceConfiguration().permissions;
                    setUserPermission(username, permission);
                }
            }
            return permission;
        }
        catch (Exception e)
        {
        }
        return null;
    }
    public UserPermission getUserPermission(String profile, String username)
    {
        mutexUserPermissions.lockRead();
        UserPermission permission = permissions.get(username);
        mutexUserPermissions.releaseRead();
        try
        {
            if (permission == null)
            {
                try
                {
                    User user = (User)Shared.model.getDeviceExternal(Licence.encrypt(username));
                    permission = user.getDeviceConfiguration().permissions;
                    setUserPermission(username, permission);
                }
                catch (Exception e)
                {
                    User user = (User)Shared.model.getDeviceExternal(username);
                    permission = user.getDeviceConfiguration().permissions;
                    setUserPermission(username, permission);
                }
            }
            if (permission != null) return permission;
        }
        catch (Exception e)
        {
        }
        return getUserPermission(profile);
    }
    private List<String> getUsernames()
    {
        mutexUserPermissions.lockRead();
        try
        {
            return new ArrayList<String>(permissions.keySet());
        }
        catch (Exception e)
        {
            return(null);
        }
        finally
        {
            mutexUserPermissions.releaseRead();
        }
    }
    private void setUserPermission(String username, UserPermission permission)
    {
        mutexUserPermissions.lockWrite();
        try
        {
            permissions.put(username, permission);
        }
        catch (Exception e)
        {
        }
        finally
        {
            mutexUserPermissions.releaseWrite();
        }
    }
}
servers/server/src/art/servers/controller/FactoryController.java
New file
@@ -0,0 +1,110 @@
package art.servers.controller;
import art.library.model.devices.Device;
import art.servers.Shared;
import java.util.HashMap;
public class FactoryController extends Thread
{
    public HashMap<ControllerDevice, Long> timestamps = new HashMap<ControllerDevice, Long>();
    public FactoryController()
    {
        super();
        this.setName("Factory controller");
    }
    public void run()
    {
        while (true)
        {
            try
            {
                // Add controllers
                for (Device device : Shared.model.getDevices())
                {
                    if (Shared.existsDeviceController(device) == false)
                    {
                        ControllerDevice controller = addController(device);
                        timestamps.put(controller, device.getLastTimestampInformationUpdate());
                    }
                }
            }
            catch (Exception e)
            {
            }
            try
            {
                // Remove controllers
                for (Controller controller : Shared.lcontroller)
                {
                    if (controller instanceof ControllerDevice)
                    {
                        Device device = ((ControllerDevice)controller).getDevice();
                        if (Shared.model.existsDevice(device.getIdentifier()) == false)
                        {
                            removeController((ControllerDevice)controller);
                        }
                        else if ((Long)timestamps.get(controller) != device.getLastTimestampInformationUpdate())
                        {
                            // Information has changed, we delete controller and will be executed again
                            // May be some changes in connections changed
                            removeController((ControllerDevice)controller);
                        }
                    }
                }
            }
            catch (Exception e)
            {
            }
            try
            {
                sleep(5000);
            }
            catch (Exception e)
            {
            }
        }
    }
    public ControllerDevice addController(Device device)
    {
        return null;
    }
    public void removeController(ControllerDevice controller)
    {
        try
        {
            timestamps.remove(controller);
            controller.close();
            Shared.lcontroller.remove(controller);
            if (Shared.window != null)
            {
                Device device = controller.getDevice();
                Shared.window.getArticPanel().removeTab(Shared.getMessage(device.information.name));
            }
        }
        catch (Exception e)
        {
        }
    }
}
servers/server/src/art/servers/controller/ListenerImplementation.java
New file
@@ -0,0 +1,1791 @@
package art.servers.controller;
import art.library.interop.InteropParameter;
import art.library.interop.InteropParameters;
import art.library.interop.InteropResponse;
import art.library.interop.serialization.Serialization;
import art.library.interop.serialization.SerializationException;
import art.library.model.devices.Device;
import art.library.model.devices.DeviceInformation;
import art.library.model.devices.DeviceRealtime;
import art.library.model.devices.application.ApplicationRealtime;
import art.library.model.devices.user.User;
import art.library.model.devices.user.UserPermission;
import art.library.model.devices.user.configuration.ConfigurationLockLogin;
import art.library.model.general.ModelFile;
import art.library.model.transactions.traces.Trace;
import art.library.model.transactions.traces.TraceResult;
import art.library.utils.licence.Licence;
import art.library.utils.resources.Resources;
import art.servers.ServerException;
import art.servers.Shared;
import art.servers.types.HttpAuthentication;
import art.servers.types.HttpToken;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;
import java.util.stream.Stream;
public class ListenerImplementation
{
    public InteropResponse logout(InteropParameters parameters, String address) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        String username = (String)parameters.getParameterValue("username");
        String resource = Shared.getMessage(language, "Username") + " : " + username;
        resource += ", " + Shared.getMessage(language, "Address") + " : " + address;
        Shared.traceInformation(Shared.getApplicationName(), Shared.getMessage(language, "Logout"), resource, null, language);
        return(new InteropResponse(true));
    }
    public InteropResponse login(InteropParameters parameters, String type, String address) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        ConfigurationLockLogin lockLogin = new ConfigurationLockLogin();
        lockLogin.maximumAddressAttempts = 5;
        lockLogin.maximumUserAttempts = 5;
        lockLogin.minutesUserLocked = 5;
        lockLogin.minutesAddressLocked = 5;
        return(login(parameters, type, address, lockLogin));
    }
    public InteropResponse login(InteropParameters parameters, String type, String address, ConfigurationLockLogin lockLogin) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        String username = (String)parameters.getParameterValue("username");
        String password = (String)parameters.getParameterValue("password");
        HttpAuthentication authentication = null;
        String resource = null;
        try
        {
            resource = Shared.getMessage(language, "Username") + " : " + username;
            resource += ", " + Shared.getMessage(language, "Address") + " : " + address;
            authentication = login(username, password, address, lockLogin);
            if (type.equalsIgnoreCase("json"))
            {
                HttpToken httptoken = authentication.getHttpToken();
                if ((httptoken.resultCode == Shared.RESULT_OK) || (httptoken.resultCode == Shared.ERROR_FIRST_ACCESS))
                {
                    Shared.traceInformation(Shared.getApplicationName(), "Login", username, authentication, language);
                }
                else if (httptoken.resultCode == Shared.ERROR_WRONG_PASSWORD)
                {
                   Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, new SerializationException(Shared.getMessage(language, "Wrong username or password")), authentication, language);
                }
                else if (httptoken.resultCode == Shared.ERROR_BLOCKED_ADDRESS)
                {
                   Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, new SerializationException(Shared.getMessage(language, "Blocked address")), authentication, language);
                }
                else if (httptoken.resultCode == Shared.ERROR_BLOCKED_USER)
                {
                   Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, new SerializationException(Shared.getMessage(language, "Blocked user")), authentication, language);
                }
                InteropResponse response = new InteropResponse(httptoken);
                return response;
            }
            else
            {
                HttpToken httptoken = authentication.getHttpToken();
                if ((httptoken.resultCode == Shared.RESULT_OK) || (httptoken.resultCode == Shared.ERROR_FIRST_ACCESS))
                {
                    Shared.traceInformation(Shared.getApplicationName(), "Login", username, authentication, language);
                }
                else if (httptoken.resultCode == Shared.ERROR_WRONG_PASSWORD)
                {
                   Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, new SerializationException(Shared.getMessage(language, "Wrong username or password")), authentication, language);
                }
                else if (httptoken.resultCode == Shared.ERROR_BLOCKED_ADDRESS)
                {
                   Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, new SerializationException(Shared.getMessage(language, "Blocked address")), authentication, language);
                }
                else if (httptoken.resultCode == Shared.ERROR_BLOCKED_USER)
                {
                   Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, new SerializationException(Shared.getMessage(language, "Blocked user")), authentication, language);
                }
                InteropResponse response = new InteropResponse(httptoken.token);
                response.mime = "text/plain";
                return response;
            }
        }
        catch (Exception exception)
        {
           Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, exception, authentication, language);
           throw new SerializationException(Shared.getMessage(language, "Authentication error"));
        }
    }
    public HttpAuthentication login(String username, String password, String address) throws Exception
    {
        ConfigurationLockLogin lockLogin = new ConfigurationLockLogin();
        lockLogin.maximumAddressAttempts = 5;
        lockLogin.maximumUserAttempts = 5;
        lockLogin.minutesUserLocked = 5;
        lockLogin.minutesAddressLocked = 5;
        return(login(username, password, address, lockLogin));
    }
    private HttpAuthentication login(String username, String password, String address, ConfigurationLockLogin lockLogin) throws Exception
    {
        // Check user autenthication
        User user = null;
        // TODO: esto cada vez es muy ineficiente, revisar.......
        try
        {
            user = (User)Shared.model.getDeviceExternal(Licence.encrypt(username));
        }
        catch (Exception e)
        {
            try
            {
                Shared.printstack(username, e);
                user = (User)Shared.model.getDeviceExternal(username);
            }
            catch (Exception ex)
            {
                // TODO Check blocked address
                Shared.printstack(username, e);
                HttpAuthentication authentication = new HttpAuthentication(username, password, address, Shared.ERROR_WRONG_PASSWORD, Shared.getMessage("Authentication error"));
                return(authentication);
            }
        }
        // TODO : volver a poner
/*
        if (user.getDeviceInformation().password.equals(Licence.encrypt(password)) == false)
        {
            // Check blocked users
            // Increase in 1 userstatus.loginErrors
            // If loginErrors >= 5 then
            //      block user
            //      if (userstatus.unlockTimestamp > 0) nothing to do
            //      else user.unlockTimestamp = currenttime + configuration.minutesBlocked
            // return error_wrong_password
            User newuser = Serialization.clone(user);
            UserStatus status = newuser.getDeviceStatus();
            if (status == null)
            {
                newuser.status = new UserStatus();
                status = newuser.getDeviceStatus();
            }
            status.loginErrors = status.loginErrors + 1;
            if (status.loginErrors >= lockLogin.maximumUserAttempts)
            {
                if (status.unlockTimestamp <= 0)
                {
                    status.unlockTimestamp = System.currentTimeMillis() + (lockLogin.minutesUserLocked * 60000L);
                }
            }
            Shared.model.updateDevice(user, newuser);
            HttpAuthentication authentication = new HttpAuthentication(username, password, address, Shared.ERROR_WRONG_PASSWORD, Shared.getMessage("Authentication error, passsword error"));
            return(authentication);
        }
        // Check correct accesses
        // if (currenttime < userstatus.unlockTimestamp) return error_blocked_user
        // userstatus.loginErrors = 0
        // user.unlockTimestamp = -1
        // return ok
        User newuser = Serialization.clone(user);
        UserStatus status = newuser.getDeviceStatus();
        if (status == null)
        {
            newuser.status = new UserStatus();
            status = newuser.getDeviceStatus();
        }
        if (System.currentTimeMillis() < status.unlockTimestamp)
        {
            HttpAuthentication authentication = new HttpAuthentication(username, password, address, Shared.ERROR_BLOCKED_USER, Shared.getMessage("Authentication error, blocked user"));
            return(authentication);
        }
        if (status.lastLogin < 0)
        {
            status.loginErrors = 0;
            status.unlockTimestamp = -1;
            status.lastLogin = System.currentTimeMillis();
            Shared.model.updateDevice(user, newuser);
            HttpAuthentication authentication = new HttpAuthentication(username, password, address, Shared.ERROR_FIRST_ACCESS, Shared.getMessage("Authentication error, first access"));
            return(authentication);
        }
        status.loginErrors = 0;
        status.unlockTimestamp = -1;
        status.lastLogin = System.currentTimeMillis();
        Shared.model.updateDevice(user, newuser);
*/
        HttpAuthentication authentication = new HttpAuthentication(username, password, address, user.getDeviceInformation().group);
        return authentication;
    }
    public InteropResponse art(InteropParameters parameters) throws SerializationException
    {
        return artic(parameters);
    }
    public InteropResponse artic(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            // Check permissions
            HttpAuthentication authentication = getHttpAuthentication(parameters);
            UserPermission permission = Shared.controllerUserPermissions.getUserPermission(authentication.username);
            if (permission.hasPermissionsParameters(Shared.getApplicationName(), parameters) == false)
            {
                throw new SerializationException(Shared.getMessage(language, "Not allowed"));
            }
            String operation = (String)parameters.getParameterValue("operation");
            Method method = this.getClass().getMethod(operation, parameters.getClass());
            InteropResponse response = (InteropResponse)method.invoke(this, parameters);
            return response;
        }
        catch (NoSuchMethodException e)
        {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            throw new SerializationException(Shared.getMessage(language, "Bad operation"), sw.toString());
        }
        catch (InvocationTargetException e)
        {
            if (e.getCause() instanceof SerializationException) throw (SerializationException)e.getCause();
            Throwable cause = e.getCause();
            StringWriter sw = new StringWriter();
            cause.printStackTrace(new PrintWriter(sw));
            throw new SerializationException(Shared.getMessage(language, cause.getMessage()), sw.toString());
        }
        catch (Exception e)
        {
           StringWriter sw = new StringWriter();
           e.printStackTrace(new PrintWriter(sw));
           throw new SerializationException(Shared.getMessage(language, e.getMessage()), sw.toString());
        }
    }
    public InteropResponse articweb(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String operation = (String)parameters.getParameterValue("operation");
            Method method = this.getClass().getMethod(operation, parameters.getClass());
            InteropResponse response = (InteropResponse)method.invoke(this, parameters);
            return response;
        }
        catch (NoSuchMethodException e)
        {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            throw new SerializationException(Shared.getMessage(language, "Bad operation"), sw.toString());
        }
        catch (InvocationTargetException e)
        {
            if (e.getCause() instanceof SerializationException) throw (SerializationException)e.getCause();
            Throwable cause = e.getCause();
            StringWriter sw = new StringWriter();
            cause.printStackTrace(new PrintWriter(sw));
            throw new SerializationException(Shared.getMessage(language, cause.getMessage()), sw.toString());
        }
        catch (Exception e)
        {
           StringWriter sw = new StringWriter();
           e.printStackTrace(new PrintWriter(sw));
           throw new SerializationException(Shared.getMessage(language, e.getMessage()), sw.toString());
        }
    }
    public InteropResponse gis(String uri) throws SerializationException
    {
        // Implemented by bridge application
       throw new SerializationException("Not available");
    }
    public InteropResponse saml(InteropParameters parameters) throws SerializationException
    {
       // Implemented by bridge application
       throw new SerializationException("Not available");
    }
    public InteropResponse get(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        String operation = null;
        try
        {
            operation = (String)parameters.getParameterValue("operation");
            if ((operation.indexOf("get") != 0) && (operation.indexOf("list") != 0))
            {
                throw new Exception("Not allowed");
            }
            Method method = this.getClass().getMethod(operation, parameters.getClass());
            InteropResponse response = (InteropResponse)method.invoke(this, parameters);
            return response;
        }
        catch (NoSuchMethodException e)
        {
            Shared.printstack("Listener", e);
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            throw new SerializationException(Shared.getMessage(language, "Bad operation"), sw.toString());
        }
        catch (InvocationTargetException e)
        {
            if (e.getCause() instanceof SerializationException) throw (SerializationException)e.getCause();
            Throwable cause = e.getCause();
            StringWriter sw = new StringWriter();
            cause.printStackTrace(new PrintWriter(sw));
            throw new SerializationException(Shared.getMessage(language, cause.getMessage()), sw.toString());
        }
        catch (Exception e)
        {
           StringWriter sw = new StringWriter();
           e.printStackTrace(new PrintWriter(sw));
           throw new SerializationException(Shared.getMessage(language, e.getMessage()), sw.toString());
        }
    }
    public InteropResponse set(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String operation = (String)parameters.getParameterValue("operation");
            Method method = this.getClass().getMethod(operation, parameters.getClass());
            InteropResponse response = (InteropResponse)method.invoke(this, parameters);
            return response;
        }
        catch (NoSuchMethodException e)
        {
            Shared.printstack("Listener", e);
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            throw new SerializationException(Shared.getMessage(language, "Bad operation"), sw.toString());
        }
        catch (InvocationTargetException e)
        {
            if (e.getCause() instanceof SerializationException) throw (SerializationException)e.getCause();
            Throwable cause = e.getCause();
            StringWriter sw = new StringWriter();
            cause.printStackTrace(new PrintWriter(sw));
            throw new SerializationException(Shared.getMessage(language, cause.getMessage()), sw.toString());
        }
        catch (Exception e)
        {
           Shared.printstack("Listener", e);
           StringWriter sw = new StringWriter();
           e.printStackTrace(new PrintWriter(sw));
           throw new SerializationException(Shared.getMessage(language, e.getMessage()), sw.toString());
        }
    }
    public InteropResponse session(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String operation = (String)parameters.getParameterValue("operation");
            Method method = this.getClass().getMethod(operation, parameters.getClass());
            InteropResponse response = (InteropResponse)method.invoke(this, parameters);
            return response;
        }
        catch (NoSuchMethodException e)
        {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            throw new SerializationException(Shared.getMessage(language, "Bad operation"), sw.toString());
        }
        catch (InvocationTargetException e)
        {
            Throwable cause = e.getCause();
            if (!(cause instanceof ServerException)) cause.printStackTrace();
            StringWriter sw = new StringWriter();
            cause.printStackTrace(new PrintWriter(sw));
            throw new SerializationException(Shared.getMessage(language, cause.getMessage()), sw.toString());
        }
        catch (Exception e)
        {
           StringWriter sw = new StringWriter();
           e.printStackTrace(new PrintWriter(sw));
           throw new SerializationException(Shared.getMessage(language, e.getMessage()));
        }
    }
    // <editor-fold defaultstate="collapsed" desc="Devices">
    public InteropResponse getGroups(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            List<String> lgroup = Shared.model.getGroups();
            String[] result = lgroup.toArray(new String[lgroup.size()]);
            return new InteropResponse(result);
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    // http:///gddkia-lublin-dk.pl:7017/get?operation=getDevices&timestamp=0
    // http:///gddkia-lublin-dk.pl:7017/get?operation=getDevices&identifier=location-krzewica-1&from=0&to=99999999999999
    // http:///gddkia-lublin-dk.pl:7017/get?operation=getDevices&when=1522308992106;
    // http:///gddkia-lublin-dk.pl:7017/get?operation=getDevices&when=2018-03-28T10:15:00.000Z;
    public InteropResponse getDevices(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String identifier = (String)parameters.getParameterValue("identifier");
            if (identifier == null) identifier = (parameters.hasParameter("device") == true) ? (String)parameters.getParameterValue("device") : null;
            String username = (String)parameters.getParameterValue("username");
            User user = null;
            if (username != null)
            {
                try{user = (User)Shared.model.getDeviceExternal(identifier);} catch (Exception e){};
                if (user == null)
                {
                    try{user = (User)Shared.model.getDeviceExternal(Licence.encrypt(identifier));} catch (Exception e){};
                }
            }
            if (parameters.hasParameter("timestamp"))
            {
                long timestamp = getTimestamp((String)parameters.getParameterValue("timestamp"));
                Device[] devices = checkDevices(user, Shared.model.getDevices(identifier, timestamp));
                return new InteropResponse(devices);
            }
            else if (parameters.hasParameter("groups"))
            {
                String[] lGroup = getStringArray(parameters.getParameter("groups"));
                return new InteropResponse(Shared.model.getDevices(lGroup));
            }
            else if ((parameters.hasParameter("from")) && (parameters.hasParameter("to")))
            {
                long timestamp1 = getTimestamp((String)parameters.getParameterValue("from"));
                long timestamp2 = getTimestamp((String)parameters.getParameterValue("to"));
                return new InteropResponse(Shared.model.getDevices(identifier, (long)timestamp1, (long)timestamp2));
            }
            else if (parameters.hasParameter("when"))
            {
                long timestamp = getTimestamp((String)parameters.getParameterValue("when"));
                return new InteropResponse(Shared.model.getDevicesWhen(identifier, (long)timestamp));
            }
            else if (parameters.hasParameter("next"))
            {
                long timestamp = getTimestamp((String)parameters.getParameterValue("next"));
                return new InteropResponse(Shared.model.getDevicesNext(identifier, (long)timestamp));
            }
            else
            {
                return new InteropResponse(Shared.model.getDevices(0));
            }
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    public InteropResponse getDevicesInformation(InteropParameters parameters) throws SerializationException
    {
        return new InteropResponse(getDevicesInformation((Device[])getDevices(parameters).getValue()));
    }
    public InteropResponse getDevicesConfiguration(InteropParameters parameters) throws SerializationException
    {
        return new InteropResponse(getDevicesConfiguration((Device[])getDevices(parameters).getValue()));
    }
    public InteropResponse getDevicesStatus(InteropParameters parameters) throws SerializationException
    {
        return new InteropResponse(getDevicesStatus((Device[])getDevices(parameters).getValue()));
    }
    public InteropResponse getDevicesAlarms(InteropParameters parameters) throws SerializationException
    {
        return new InteropResponse(getDevicesAlarms((Device[])getDevices(parameters).getValue()));
    }
    public InteropResponse getDevicesStatusAlarms(InteropParameters parameters) throws SerializationException
    {
        return new InteropResponse(getDevicesStatusAlarms((Device[])getDevices(parameters).getValue()));
    }
    public InteropResponse getDevice(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String identifier = (String)parameters.getParameterValue("identifier");
            if (identifier == null) identifier = (parameters.hasParameter("device") == true) ? (String)parameters.getParameterValue("device") : null;
            return new InteropResponse(Shared.model.getDevice(identifier));
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    public InteropResponse getDeviceInformation(InteropParameters parameters) throws SerializationException
    {
        return new InteropResponse(getDeviceInformation((Device)getDevice(parameters).getValue()[0]));
    }
    public InteropResponse getDeviceConfiguration(InteropParameters parameters) throws SerializationException
    {
        return new InteropResponse(getDeviceConfiguration((Device)getDevice(parameters).getValue()[0]));
    }
    public InteropResponse getDeviceStatus(InteropParameters parameters) throws SerializationException
    {
        return new InteropResponse(getDeviceStatus((Device)getDevice(parameters).getValue()[0]));
    }
    public InteropResponse getDeviceAlarms(InteropParameters parameters) throws SerializationException
    {
        return new InteropResponse(getDeviceAlarms((Device)getDevice(parameters).getValue()[0]));
    }
    public InteropResponse getDeviceStatusAlarms(InteropParameters parameters) throws SerializationException
    {
        return new InteropResponse(getDeviceStatusAlarms((Device)getDevice(parameters).getValue()[0]));
    }
    public InteropResponse existDevice(InteropParameters parameters) throws SerializationException
    {
        String language = (String) parameters.getParameterValue("language");
        try
        {
            String identifier = (String)parameters.getParameterValue("identifier");
            if (identifier == null) identifier = (parameters.hasParameter("device") == true) ? (String)parameters.getParameterValue("device") : null;
            return new InteropResponse(Shared.model.existsDevice(identifier));
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    public InteropResponse addDevice (InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        String bodyContent = null;
        try
        {
            Class clazzDevice = Class.forName(Shared.model.deviceClassName);
            bodyContent = (String)parameters.getParameterValue("body-content");
            Device device = (Device)Serialization.deserialize(clazzDevice, bodyContent);
            addDevices(language, bodyContent);
            Shared.model.updateDevice(new Device[]{device});
            return new InteropResponse(new Boolean(true));
        }
        catch (ClassCastException exception)
        {
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
        return addDevices(language, bodyContent);
    }
    public InteropResponse addDevices (InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        String bodyContent = null;
        try
        {
            System.out.println("1.AddDevices: " + Shared.model.deviceClassName);
            Class clazzDevice = Class.forName(Shared.model.deviceClassName);
            System.out.println("2.AddDevices: " + clazzDevice);
            // bodyContent = (String)parameters.getParameterValue("body-content");
            Class<?> clazzArray = (Class<?>)Array.newInstance(clazzDevice, 0).getClass();
            Device[] ldevice = parameters.getBodyContentValue(clazzArray);
            // System.out.println("3.AddDevices: " + bodyContent);
            // Device[] ldevice = (Device[])Serialization.deserialize(clazzArray, bodyContent);
            System.out.println("4.AddDevices: " + ldevice);
            if ((ldevice != null) && (ldevice.length > 0))
            {
                System.out.println("5.AddDevices: " + ldevice[0]);
                if (ldevice[0] != null)
                {
                    System.out.println("6.AddDevices: " + ldevice[0].getIdentifier());
                    Shared.model.addDevices(Stream.of(ldevice).map(dev -> dev.getDeviceInformation()).toArray(DeviceInformation[]::new));
                    Shared.model.updateDevice(ldevice);
                    return new InteropResponse(new Boolean(true));
                }
            }
        }
        catch (ClassCastException exception)
        {
            exception.printStackTrace();
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
        return addDevices(language, bodyContent);
    }
    private InteropResponse addDevices (String language, String bodyContent) throws SerializationException
    {
        try
        {
            Class clazzInformation = Class.forName(Shared.model.deviceInformationClassName);
            Class<?> clazzArray = (Class<?>)Array.newInstance(clazzInformation, 0).getClass();
            DeviceInformation[] linformation = (DeviceInformation[])(Serialization.deserialize(clazzArray, bodyContent));
            Shared.model.addDevices(linformation);
            return new InteropResponse(new Boolean(true));
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    public InteropResponse deleteDevice (InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String identifier = null;
            if (parameters.hasParameter("device") == true)
            {
                identifier = (String)parameters.getParameterValue("device");
            }
            else if (parameters.hasParameter("identifier") == true)
            {
                identifier = (String)parameters.getParameterValue("identifier");
            }
            Shared.model.deleteDevices(new String[]{identifier});
            return new InteropResponse(new Boolean(true));
        }
        catch (ServerException exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()));
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    public InteropResponse deleteDevices (InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String[] lidentifier = new String[0];
            if (parameters.hasParameter("devices") == true)
            {
                lidentifier = ((String)parameters.getParameterValue("devices")).split(",");
            }
            else if (parameters.hasParameter("identifiers") == true)
            {
                lidentifier = ((String)parameters.getParameterValue("identifiers")).split(",");
            }
            else
            {
                lidentifier = (String[])Serialization.deserialize(String[].class, (String)parameters.getParameterValue("body-content"));
            }
            Shared.model.deleteDevices(lidentifier);
            return new InteropResponse(new Boolean(true));
        }
        catch (ServerException exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()));
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    public InteropResponse getDeviceRealtime(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String identifier = (String)parameters.getParameterValue("identifier");
            if (identifier == null) identifier = (parameters.hasParameter("device") == true) ? (String)parameters.getParameterValue("device") : null;
            long timestamp = (parameters.hasParameter("timestamp") == true) ? Long.parseLong((String)parameters.getParameterValue("timestamp")) : 0;
            DeviceRealtime realtime = Shared.model.getDevice(identifier).getDeviceRealtime();
            if (realtime.lastTimestampUpdate > timestamp) return new InteropResponse(realtime);
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
        throw new SerializationException("Realtime does not exists");
    }
    public InteropResponse getDevicesRealtime(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        long timestamp = (parameters.hasParameter("timestamp") == true) ? Long.parseLong((String)parameters.getParameterValue("timestamp")) : 0;
        try
        {
            List<DeviceRealtime> lrealtime = new ArrayList<DeviceRealtime>();
            Device[] ldevice = art.servers.Shared.model.getDevicesCopy();
            for (Device device : ldevice)
            {
                DeviceRealtime realtime = device.getDeviceRealtime();
                if (realtime != null)
                {
                    if (realtime.lastTimestampUpdate > timestamp)
                    {
                        realtime.identifier = device.getIdentifier();
                        lrealtime.add(realtime);
                    }
                }
            }
            return new InteropResponse(lrealtime.toArray(new DeviceRealtime[lrealtime.size()]));
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    private Device[] getDevicesInformation(Device[] ldevice) throws SerializationException
    {
        Device[] result = new Device[ldevice.length];
        for (int i=0; i<ldevice.length; i++)
        {
            result[i] = Serialization.clone((Device)ldevice[i]);
            result[i].configuration = null;
            result[i].status = null;
            result[i].alarms = null;
        }
        return result;
    }
    private Device[] getDevicesConfiguration(Device[] ldevice) throws SerializationException
    {
        Device[] result = new Device[ldevice.length];
        for (int i=0; i<ldevice.length; i++)
        {
            result[i] = Serialization.clone((Device)ldevice[i]);
            result[i].information = new DeviceInformation();
            result[i].information.setIdentifier(((Device)ldevice[i]).getIdentifier());
            result[i].status = null;
            result[i].alarms = null;
        }
        return result;
    }
    private Device[] getDevicesStatus(Device[] ldevice) throws SerializationException
    {
        Device[] result = new Device[ldevice.length];
        for (int i=0; i<ldevice.length; i++)
        {
            result[i] = Serialization.clone((Device)ldevice[i]);
            result[i].information = new DeviceInformation();
            result[i].information.setIdentifier(((Device)ldevice[i]).getIdentifier());
            result[i].configuration = null;
            result[i].alarms = null;
        }
        return result;
    }
    private Device[] getDevicesAlarms(Device[] ldevice) throws SerializationException
    {
        Device[] result = new Device[ldevice.length];
        for (int i=0; i<ldevice.length; i++)
        {
            result[i] = Serialization.clone((Device)ldevice[i]);
            result[i].information = new DeviceInformation();
            result[i].information.setIdentifier(((Device)ldevice[i]).getIdentifier());
            result[i].configuration = null;
            result[i].status = null;
        }
        return result;
    }
    private Device[] getDevicesStatusAlarms(Device[] ldevice) throws SerializationException
    {
        Device[] result = new Device[ldevice.length];
        for (int i=0; i<ldevice.length; i++)
        {
            result[i] = Serialization.clone((Device)ldevice[i]);
            result[i].information = new DeviceInformation();
            result[i].information.setIdentifier(((Device)ldevice[i]).getIdentifier());
            result[i].configuration = null;
        }
        return result;
    }
    private Device getDeviceInformation(Device device) throws SerializationException
    {
        Device result = Serialization.clone(device);
        result.configuration = null;
        result.status = null;
        result.alarms = null;
        return result;
    }
    private Device getDeviceConfiguration(Device device) throws SerializationException
    {
        Device result = Serialization.clone(device);
        result.information = new DeviceInformation();
        result.information.setIdentifier(device.getIdentifier());
        result.status = null;
        result.alarms = null;
        return result;
    }
    private Device getDeviceStatus(Device device) throws SerializationException
    {
        Device result = Serialization.clone(device);
        result.information = new DeviceInformation();
        result.information.setIdentifier(device.getIdentifier());
        result.configuration = null;
        result.alarms = null;
        return result;
    }
    private Device getDeviceAlarms(Device device) throws SerializationException
    {
        Device result = Serialization.clone(device);
        result.information = new DeviceInformation();
        result.information.setIdentifier(device.getIdentifier());
        result.status = null;
        result.configuration = null;
        return result;
    }
    private Device getDeviceStatusAlarms(Device device) throws SerializationException
    {
        Device result = Serialization.clone(device);
        result.information = new DeviceInformation();
        result.information.setIdentifier(device.getIdentifier());
        result.configuration = null;
        return result;
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Symbols">
    public InteropResponse getSymbols(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            if (parameters.hasParameter("timestamp"))
            {
                long timestamp = Long.parseLong((String)parameters.getParameterValue("timestamp"));
                return new InteropResponse(Shared.model.getSymbols(timestamp));
            }
            else
            {
                return new InteropResponse(Shared.model.getSymbols(0));
            }
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Scalable Vector Graphics">
    public InteropResponse listScalableVectorGraphics (InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String identifier = (String)parameters.getParameterValue("identifier");
            if (identifier == null) identifier = (String)parameters.getParameterValue("device");
            File folder = new File("data/" + Shared.getApplicationName() + "/svgs/" + identifier + "/");
            List<ModelFile> lfiles = new ArrayList<ModelFile>();
            for (File file : folder.listFiles())
            {
                ModelFile modelFile = new ModelFile();
                modelFile.name = file.getName().substring(0, file.getName().lastIndexOf('.'));
                modelFile.mime = "image/svg+xml";
                lfiles.add(modelFile);
            }
            InteropResponse response = new InteropResponse(lfiles);
            return response;
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    public InteropResponse getScalableVectorGraphics (InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String identifier = (String)parameters.getParameterValue("identifier");
            if (identifier == null) identifier = (String)parameters.getParameterValue("device");
            String name = (String)parameters.getParameterValue("name");
            if (name != null)
            {
                String filename = "data/" + Shared.getApplicationName() + "/svgs/" + identifier + "/" + name + ".svg";
                byte[] data = Resources.getExternalFileBytes(filename);
                if (data.length == 0) data = Resources.getResourceBytes(filename);
                InteropResponse response = new InteropResponse(data);
                response.mime = "image/svg+xml";
                return response;
            }
            else
            {
                File folder = new File("data/" + Shared.getApplicationName() + "/svgs/" + identifier + "/");
                List<ModelFile> lfiles = new ArrayList<ModelFile>();
                for (File file : folder.listFiles())
                {
                    ModelFile modelFile = new ModelFile();
                    modelFile.data = Files.readAllBytes(file.toPath());
                    modelFile.name = file.getName().substring(0, file.getName().lastIndexOf('.'));
                    modelFile.mime = "image/svg+xml";
                    lfiles.add(modelFile);
                }
                InteropResponse response = new InteropResponse(lfiles);
                return response;
            }
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    public InteropResponse addScalableVectorGraphics (InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String identifier = (String)parameters.getParameterValue("identifier");
            if (identifier == null) identifier = (String)parameters.getParameterValue("device");
            String name = (String)parameters.getParameterValue("name");
            byte[] data = parameters.getParameterValue("body-content");
            String filename = "data/" + Shared.getApplicationName() + "/svgs/" + identifier + "/" + name + ".svg";
            File file = new File(filename);
            file.getParentFile().mkdirs();
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(data);
            fos.close();
            return new InteropResponse(new Boolean(true));
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    public InteropResponse removeScalableVectorGraphics (InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String identifier = (String)parameters.getParameterValue("identifier");
            if (identifier == null) identifier = (String)parameters.getParameterValue("device");
            String name = (String)parameters.getParameterValue("name");
            String filename = "data/" + Shared.getApplicationName() + "/svgs/" + identifier + "/" + name + ".svg";
            File file = new File(filename);
            return new InteropResponse(new Boolean(file.delete()));
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Application">
    public InteropResponse getApplication(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            if (parameters.hasParameter("timestamp"))
            {
                long timestamp = Long.parseLong((String)parameters.getParameterValue("timestamp"));
                return new InteropResponse(Shared.model.getApplication(timestamp));
            }
            else if ((parameters.hasParameter("from")) && (parameters.hasParameter("to")))
            {
                long timestamp1 = Long.parseLong((String)parameters.getParameterValue("from"));
                long timestamp2 = Long.parseLong((String)parameters.getParameterValue("to"));
                return new InteropResponse(Shared.model.getApplication((long)timestamp1, (long)timestamp2));
            }
            else if (parameters.getParametersNumber() == 1)
            {
                return new InteropResponse(Shared.model.getApplication(0));
            }
            else
            {
                throw new Exception("Bad parameters");
            }
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Documents">
    public InteropResponse listDocuments(InteropParameters parameters) throws SerializationException
    {
        String language = parameters.getParameterValue("language");
        try
        {
            String folder = (String)parameters.getParameterValue("folder");
            List<String> ldocument = new ArrayList<String>();
            File directory = new File("documents/" + folder);
            if (directory.exists() == false) throw new ServerException("No documents");
            for (File file : directory.listFiles()) ldocument.add(file.getName());
            InteropResponse response = new InteropResponse(ldocument.toArray(new String[ldocument.size()]));
            return response;
        }
        catch (ServerException exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()));
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    public InteropResponse getDocument(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String name = (String)parameters.getParameterValue("name");
            String folder = (String)parameters.getParameterValue("folder");
            File file = new File("documents/" + folder + "/" + name);
            if (file.exists() == false) throw new ServerException("Document does not exists");
            byte[] data = new byte[(int)file.length()];
            FileInputStream fis = new FileInputStream(file);
            fis.read(data);
            fis.close();
            InteropResponse response = new InteropResponse(data);
            return response;
        }
        catch (ServerException exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()));
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    public InteropResponse addDocument(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String name = parameters.getParameterValue("name");
            String folder = (String)parameters.getParameterValue("folder");
            byte[] data = parameters.getParameterValue("body-content");
            File file = new File("documents/" + folder + "/" + name);
            file.getParentFile().mkdirs();
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(data);
            fos.close();
            return new InteropResponse(new Boolean(true));
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    public InteropResponse deleteDocument(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String name = (parameters.hasParameter("name") == true) ? (String)parameters.getParameterValue("name") : null;
            String folder = (String)parameters.getParameterValue("folder");
            File file = new File("documents/" + folder + "/" + name);
            if (file.exists() == true) return new InteropResponse(new Boolean(file.delete()));
            throw new ServerException("Document does not exists");
        }
        catch (ServerException exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()));
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Maps">
    public InteropResponse listMaps(InteropParameters parameters) throws SerializationException
    {
        String language = parameters.getParameterValue("language");
        try
        {
            String identifier = (String)parameters.getParameterValue("device");
            List<String> maps = new ArrayList<String>();
            File folder = new File("data/" + Shared.getApplicationName() + "/maps/" + identifier);
            if (folder.exists() == false) throw new SerializationException(Shared.getMessage(language, "No maps"));
            for (File file : folder.listFiles()) maps.add(file.getName().replace(".svg", ""));
            InteropResponse response = new InteropResponse(maps.toArray(new String[maps.size()]));
            return response;
        }
        catch (SerializationException exception)
        {
            throw exception;
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    public InteropResponse getMap(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String identifier = (String)parameters.getParameterValue("device");
            String name = (String)parameters.getParameterValue("name");
            File file = new File("data/" + Shared.getApplicationName() + "/maps/" + identifier + "/" + name + ".svg");
            if (file.exists() == false) throw new SerializationException(Shared.getMessage(language, "Map does not exists"));
            byte[] data = new byte[(int)file.length()];
            FileInputStream fis = new FileInputStream(file);
            fis.read(data);
            fis.close();
            InteropResponse response = new InteropResponse(data);
            response.mime = "image/svg+xml";
            return response;
        }
        catch (SerializationException exception)
        {
            throw exception;
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    public InteropResponse addMap(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String identifier = (String)parameters.getParameterValue("device");
            String name = parameters.getParameterValue("name");
            byte[] data = parameters.getParameterValue("body-content");
            File file = new File("data/" + Shared.getApplicationName() + "/maps/" + identifier + "/" + name + ".svg");
            file.getParentFile().mkdirs();
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
            bos.write(data);
            bos.close();
            return new InteropResponse(new Boolean(true));
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    public InteropResponse deleteMap(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String identifier = (String)parameters.getParameterValue("device");
            String name = parameters.getParameterValue("name");
            File file = new File("data/" + Shared.getApplicationName() + "/maps/" + identifier + "/" + name + ".svg");
            if (file.exists() == true) return new InteropResponse(new Boolean(file.delete()));
            throw new SerializationException(Shared.getMessage(language, "Map does not exists"));
        }
        catch (SerializationException exception)
        {
            throw exception;
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Traces">
    public InteropResponse getTraceValues (InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            String field = (String)parameters.getParameterValue("field");
            List<String> traces = Shared.model.getTraceValues(field, Shared.getApplicationName());
            InteropResponse response = new InteropResponse(traces, true);
            return response;
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    public InteropResponse getTraces (InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            TraceResult result = new TraceResult();
            if (parameters.hasParameter("timestamp") == true)
            {
                long timestamp = getTimestamp((String)parameters.getParameterValue("timestamp"));
                ApplicationRealtime realtime = (ApplicationRealtime)Shared.controllerStatus.getApplication().getDeviceRealtime();
                result.traces = realtime.getTraces(timestamp);
                result.timestampfrom = timestamp;
                result.application = Shared.getApplicationName();
            }
            else
            {
                result.timestampfrom = getTimestamp((String)parameters.getParameterValue("from"));
                result.timestampto = getTimestamp((String)parameters.getParameterValue("to"));
                result.type = (parameters.hasParameter("type") == true) ? Integer.parseInt((String)parameters.getParameterValue("type")) : Trace.TRACE_NONE;
                result.username = (String)parameters.getParameterValue("username");
                result.application = Shared.getApplicationName();
                result.service = (String)parameters.getParameterValue("controller");
                result.offset = (parameters.hasParameter("offset") == true) ? Integer.parseInt((String)parameters.getParameterValue("offset")) : 0;
                result.limit = (parameters.hasParameter("limit") == true) ? Integer.parseInt((String)parameters.getParameterValue("limit")) : 1000;
                result.limit = Math.min(1000, result.limit);
            }
            InteropResponse response = new InteropResponse(Shared.model.getTraces(result), false);
            return response;
        }
        catch (Exception exception)
        {
            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Others">
    public InteropResponse heartbeat(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            return new InteropResponse(new Boolean(true));
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    public InteropResponse restart(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            Shared.exit();
            return new InteropResponse(new Boolean(true));
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    public InteropResponse disable(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            Shared.controllerStatus.getApplication().alarms.clear();
            Shared.controllerStatus.getApplication().setAlarm("alarm_disabled", true);
            Shared.model.clearDevices();
            return new InteropResponse(new Boolean(true));
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    public InteropResponse enable(InteropParameters parameters) throws SerializationException
    {
        String language = (String)parameters.getParameterValue("language");
        try
        {
            Shared.model.readDevices();
            Shared.controllerStatus.getApplication().setAlarm("alarm_disabled", false);
            return new InteropResponse(new Boolean(true));
        }
        catch (Exception e)
        {
            throw getException(language, e);
        }
    }
    public static InteropResponse shell(InteropParameters parameters)
    {
        try
        {
            String command = (String)parameters.getParameterValue("command");
            Process process = Runtime.getRuntime().exec(command);
            process.getOutputStream().close();
            BufferedReader stderr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            String error = "";
            String line;
            while ((line = stderr.readLine()) != null) error = error + line + "\r\n";
            stderr.close();
            if (error.length() == 0) return new InteropResponse(true);
        }
        catch (Exception e)
        {
        }
        return new InteropResponse(false);
    }
    protected HttpAuthentication getHttpAuthentication(InteropParameters parameters) throws SerializationException
    {
        try
        {
            String[] login = ((String)parameters.getParameterValue("token")).split(",");
            String username = login[0];
            String password = login[1];
            String computer = (String)parameters.getParameterValue("computer");
            HttpAuthentication authentication = login(username, password, computer);
            return authentication;
        }
        catch (Exception exception)
        {
        }
        try
        {
            String token = Licence.decrypt((String)parameters.getParameterValue("token"));
            HttpAuthentication authentication = (HttpAuthentication)Serialization.deserialize(HttpAuthentication.class, token);
            return authentication;
        }
        catch (Exception exception)
        {
        }
        throw new SerializationException("Authentication token error");
    }
   // </editor-fold>
    private Device[] checkDevices (User user, Device[] devices)
    {
        try
        {
            if (user == null) return(devices);
            List<Device> list = new ArrayList<Device>();
            for (Device device : devices)
            {
                if ((user.getDeviceInformation().municipality != null) && (device.getDeviceInformation().municipality != null) &&
                    (user.getDeviceInformation().municipality.equalsIgnoreCase(device.getDeviceInformation().municipality)))
                {
                    list.add(device);
                }
            }
            return(list.toArray(new Device[0]));
        }
        catch (Exception e)
        {
            return(devices);
        }
    }
    // <editor-fold defaultstate="collapsed" desc="static">
    protected static SerializationException getException(String language, Exception exception)
    {
        StringWriter sw = new StringWriter();
        exception.printStackTrace(new PrintWriter(sw));
        return new SerializationException(Shared.getMessage(language, exception.getMessage()), sw.toString());
    }
    protected static String[] getStringArray(InteropParameter parameter)
    {
        if (parameter.getValue() instanceof String[])
        {
            return (String[])parameter.getValue();
        }
        return ((String)parameter.getValue()).split(",");
    }
    public static long getTimestamp(String timestamp)
    {
        try
        {
            if ((timestamp.contains("/") == false) && (timestamp.contains("-") == false))
            {
                if (timestamp.length() == 4) return new SimpleDateFormat("HHmm").parse(timestamp).getTime();
                if (timestamp.length() == 6) return new SimpleDateFormat("HHmmss").parse(timestamp).getTime();
                if (timestamp.length() == 9) return new SimpleDateFormat("HHmmssSSS").parse(timestamp).getTime();
                if (timestamp.length() == 8) return new SimpleDateFormat("yyyyMMdd").parse(timestamp).getTime();
                if (timestamp.length() == 10) return new SimpleDateFormat("yyyyMMddHH").parse(timestamp).getTime();
                if (timestamp.length() == 12) return new SimpleDateFormat("yyyyMMddHHmm").parse(timestamp).getTime();
                if (timestamp.length() == 14) return new SimpleDateFormat("yyyyMMddHHmmss").parse(timestamp).getTime();
                if (timestamp.length() == 17) return new SimpleDateFormat("yyyyMMddHHmmssSSS").parse(timestamp).getTime();
            }
            if (timestamp.indexOf("Z") == 23)
            {
                SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                ISO8601DATEFORMAT.setTimeZone(TimeZone.getTimeZone("GMT"));
                return ISO8601DATEFORMAT.parse(timestamp).getTime();
            }
            if ((timestamp.indexOf("/") == 4) && (timestamp.length() == 7)) return new SimpleDateFormat("yyyy/MM").parse(timestamp).getTime();
            if ((timestamp.indexOf("/") == 2) && (timestamp.length() == 7)) return new SimpleDateFormat("MM/yyyy").parse(timestamp).getTime();
            if ((timestamp.indexOf("-") == 4) && (timestamp.length() == 7)) return new SimpleDateFormat("yyyy-MM").parse(timestamp).getTime();
            if ((timestamp.indexOf("-") == 2) && (timestamp.length() == 7)) return new SimpleDateFormat("MM-yyyy").parse(timestamp).getTime();
            if ((timestamp.indexOf("/") == 4) && (timestamp.length() == 10)) return new SimpleDateFormat("yyyy/MM/dd").parse(timestamp).getTime();
            if ((timestamp.indexOf("/") == 2) && (timestamp.length() == 10)) return new SimpleDateFormat("dd/MM/yyyy").parse(timestamp).getTime();
            if ((timestamp.indexOf("-") == 4) && (timestamp.length() == 10)) return new SimpleDateFormat("yyyy-MM-dd").parse(timestamp).getTime();
            if ((timestamp.indexOf("-") == 2) && (timestamp.length() == 10)) return new SimpleDateFormat("dd-MM-yyyy").parse(timestamp).getTime();
            if ((timestamp.indexOf("/") == 4) && (timestamp.length() == 16)) return new SimpleDateFormat("yyyy/MM/dd HH:mm").parse(timestamp).getTime();
            if ((timestamp.indexOf("/") == 2) && (timestamp.length() == 16)) return new SimpleDateFormat("dd/MM/yyyy HH:mm").parse(timestamp).getTime();
            if ((timestamp.indexOf("-") == 4) && (timestamp.length() == 16)) return new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(timestamp).getTime();
            if ((timestamp.indexOf("-") == 2) && (timestamp.length() == 16)) return new SimpleDateFormat("dd-MM-yyyy HH:mm").parse(timestamp).getTime();
            if ((timestamp.indexOf("/") == 4) && (timestamp.length() == 19)) return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(timestamp).getTime();
            if ((timestamp.indexOf("/") == 2) && (timestamp.length() == 19)) return new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").parse(timestamp).getTime();
            if ((timestamp.indexOf("-") == 4) && (timestamp.length() == 19)) return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(timestamp).getTime();
            if ((timestamp.indexOf("-") == 2) && (timestamp.length() == 19)) return new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").parse(timestamp).getTime();
            if ((timestamp.indexOf("/") == 4) && (timestamp.length() == 23)) return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS").parse(timestamp).getTime();
            if ((timestamp.indexOf("/") == 2) && (timestamp.length() == 23)) return new SimpleDateFormat("dd/MM/yyyy HH:mm:ss.SSS").parse(timestamp).getTime();
            if ((timestamp.indexOf("-") == 4) && (timestamp.length() == 23)) return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(timestamp).getTime();
            if ((timestamp.indexOf("-") == 2) && (timestamp.length() == 23)) return new SimpleDateFormat("dd-MM-yyyy HH:mm:ss.SSS").parse(timestamp).getTime();
            return Long.parseLong(timestamp);
        }
        catch (Exception exception)
        {
        }
        return 0;
    }
    // </editor-fold>
}
servers/server/src/art/servers/controller/http/webpages/Page.java
New file
@@ -0,0 +1,573 @@
package art.servers.controller.http.webpages;
import art.servers.Shared;
import art.servers.types.HttpAuthentication;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
public class Page
{
    public HttpAuthentication authentication = null;
    public String html = null;
    public Page(HttpAuthentication authentication)
    {
        this.authentication = authentication;
    }
    public byte[] toHTML() throws Exception
    {
        return new byte[0];
    }
    // <editor-fold defaultstate="collapsed" desc="Values">
    protected String value_double(long value)
    {
        DecimalFormat formato1 = new DecimalFormat("###,###,###");
        return formato1.format(value);
    }
    protected String value_double(double value)
    {
        DecimalFormat formato1 = new DecimalFormat("###,###,###.#");
        return  formato1.format(value);
    }
    protected String value_datetime(long timestamp)
    {
        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss"));
        if (timestamp == 0) return "";
        return formato1.format(timestamp);
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="tr">
    protected String tr_string(String tag, String value)
    {
        if (value != null)
        {
            return "<tr><td>" + Shared.getMessage(tag) + "</td><td>" + value + "</td></tr>";
        }
        else
        {
            return "<tr><td>" + Shared.getMessage(tag) + "</td><td></td></tr>";
        }
    }
    protected String tr_string(String tag, String value, String units)
    {
        if (value != null)
        {
            return "<tr><td>" + Shared.getMessage(tag) + "</td><td>" + value + " " + units + "</td></tr>";
        }
        else
        {
            return "<tr><td>" + Shared.getMessage(tag) + "</td><td></td></tr>";
        }
    }
    protected String tr_integer(String tag, long value, String units)
    {
        DecimalFormat formato1 = new DecimalFormat("###,###,###");
        return "<tr><td>" + Shared.getMessage(tag) + "</td><td>" + formato1.format(value) + " " + units + "</td></tr>";
    }
    protected String tr_double(String tag, double value, String units)
    {
        DecimalFormat formato1 = new DecimalFormat("###,###,###.#");
        return "<tr><td>" + Shared.getMessage(tag) + "</td><td>" + formato1.format(value) + " " + units + "</td></tr>";
    }
    protected String tr_boolean(String tag, boolean value, boolean reverse)
    {
        if (reverse == false)
        {
            if (value == true)
            {
                return "<tr><td>" + Shared.getMessage(tag) + "</td><td><label>" + Shared.getMessage("Yes") + "</label><span class=\"icon_ok\"></span></td></tr>";
            }
            else
            {
                return "<tr><td>" + Shared.getMessage(tag) + "</td><td><label>" + Shared.getMessage("No") + "</label><span class=\"icon_ko\"></span></td></tr>";
            }
        }
        else
        {
            if (value == false)
            {
                return "<tr><td>" + Shared.getMessage(tag) + "</td><td><label>" + Shared.getMessage("No") + "</label><span class=\"icon_ok\"></span></td></tr>";
            }
            else
            {
                return "<tr><td>" + Shared.getMessage(tag) + "</td><td><label>" + Shared.getMessage("Yes") + "</label><span class=\"icon_ko\"></span></td></tr>";
            }
        }
    }
    protected String tr_datetimeicon(String tag, long timestamp)
    {
        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss"));
        if (timestamp > 0)
        {
            return "<tr><td>" + tag + "</td><td><span class=\"icon_ko\"></span><label>" + formato1.format(timestamp) + "</label></td></tr>";
        }
        else
        {
            return "<tr><td>" + tag + "</td><td><span class=\"icon_ok\"></span><label></label></td></tr>";
        }
    }
    protected String tr_datetime(String tag, long timestamp)
    {
        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss"));
        if (timestamp == 0)
        {
            return "<tr><td>" + tag + "</td><td></td></tr>";
        }
        else
        {
            return "<tr><td>" + tag + "</td><td>" + formato1.format(timestamp) + "</td></tr>";
        }
    }
    protected String tr_datetimemillis(String tag, long timestamp)
    {
        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss.SSS"));
        if (timestamp == 0)
        {
            return "<tr><td>" + tag + "</td><td></td></tr>";
        }
        else
        {
            return "<tr><td>" + tag + "</td><td>" + formato1.format(timestamp) + "</td></tr>";
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Fields">
    public List<String> getFields(String html) throws Exception
    {
        List<String> result = new ArrayList<String>();
        int current = 0;
        try
        {
            while (current >=0)
            {
                int index1 = html.indexOf("{{", current);
                int index2 = html.indexOf("}}", index1 + 3) + 2;
                result.add(html.substring(index1, index2));
                current = index2 + 1;
            }
        }
        catch (Exception e)
        {
        }
        return result;
    }
    protected String invoke(String html, String field)
    {
        try
        {
            String[] values = field.replace("{{", "").replaceAll("}}", "").split(";");
            if ((values[0].equalsIgnoreCase("read") == true) && (values[2].equalsIgnoreCase("this") == true))
            {
                return html.replace(field, getValue(this, values[3]).toString());
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return html.replace(field, "");
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Reflection">
    protected Object getValue(Object object, String name) throws Exception
    {
        int indice = name.indexOf(".");
        if (indice > 0)
        {
            // Es un campo de una clase
            String nombreClase = name.substring(0, indice);
            String nombreRestante = name.substring(indice + 1, name.length());
            try
            {
                Field field = getDeclaredField(object.getClass(), nombreClase);
                field.setAccessible(true);
                Object child = field.get(object);
                Object value = getValue(child, nombreRestante);
                if (value == null) return "";
                return value;
            }
            catch (Exception e)
            {
                try
                {
                    Method method = getDeclaredMethod(object.getClass(), nombreClase);
                    method.setAccessible(true);
                    Object child = method.invoke(object, new Object[0]);
                    Object value = getValue(child, nombreRestante);
                    if (value == null) return "";
                    return value;
                }
                catch (Exception exception)
                {
                    return "";
                }
            }
        }
        else
        {
            try
            {
                Field field = null;
                int fieldArrayIndex = 0;
                // Array
                if (name.indexOf("@") > 0)
                {
                    String[] tokens = name.split("@");
                    field = getDeclaredField(object.getClass(), tokens[0]);
                    fieldArrayIndex = Integer.parseInt(tokens[1]);
                    field.setAccessible(true);
                    return getValue(field.get(object), fieldArrayIndex);
                }
                field = getDeclaredField(object.getClass(), name);
                field.setAccessible(true);
                return field.get(object);
            }
            catch (Exception e)
            {
                try
                {
                    Method method = getDeclaredMethod(object.getClass(), name);
                    method.setAccessible(true);
                    return method.invoke(object, new Object[0]);
                }
                catch (Exception exception)
                {
                    return "";
                }
            }
        }
    }
    protected Object getValue(Object object, String name, Object parameter) throws Exception
    {
        int indice = name.indexOf(".");
        if (indice > 0)
        {
            // Es un campo de una clase
            String nombreClase = name.substring(0, indice);
            String nombreRestante = name.substring(indice + 1, name.length());
            try
            {
                Method method = getDeclaredMethod(object.getClass(), nombreClase);
                method.setAccessible(true);
                Object child = method.invoke(object, parameter);
                return getValue(child, nombreRestante, parameter);
            }
            catch (Exception exception)
            {
                return null;
            }
        }
        else
        {
            try
            {
                Method method = getDeclaredMethod(object.getClass(), name);
                method.setAccessible(true);
                return method.invoke(object, parameter);
            }
            catch (Exception exception)
            {
                return "";
            }
        }
    }
    protected Method getDeclaredMethod(Class clazz, String name) throws NoSuchMethodException
    {
        try
        {
            Method method = clazz.getDeclaredMethod(name);
            return method;
        }
        catch (NoSuchMethodException e)
        {
            for (Method declaredMethod : clazz.getDeclaredMethods())
            {
                if (declaredMethod.getName().equals(name))
                {
                    return declaredMethod;
                }
            }
            if (clazz.getSuperclass() != null)
            {
                return getDeclaredMethod(clazz.getSuperclass(), name);
            }
        }
        catch (Exception e)
        {
            if (clazz.getSuperclass() != null)
            {
                return getDeclaredMethod(clazz.getSuperclass(), name);
            }
        }
        throw new NoSuchMethodException();
    }
    protected Field getDeclaredField(Class clase, String name) throws NoSuchFieldException
    {
        try
        {
            return clase.getDeclaredField(name);
        }
        catch (NoSuchFieldException e)
        {
            Class superclase = clase.getSuperclass();
            return getDeclaredField(superclase, name);
        }
    }
    protected void setValue(String name, Object value, Object object) throws Exception
    {
        if ((name == null) || (object == null)) return;
        int indice = name.indexOf(".");
        if (indice > 0)
        {
            // Es un campo de una clase
            String nombreClase = name.substring(0, indice);
            String nombreRestante = name.substring(indice + 1, name.length());
            Field field = object.getClass().getDeclaredField(nombreClase);
            field.setAccessible(true);
            Object child = field.get(object);
            setValue(nombreRestante, value, child);
        }
        else
        {
            try
            {
                Field field = null;
                int fieldArrayIndex = 0;
                // Array
                if (name.indexOf("@") > 0)
                {
                    String[] tokens = name.split("@");
                    field = getDeclaredField(object.getClass(), tokens[0]);
                    fieldArrayIndex = Integer.parseInt(tokens[1]);
                }
                else
                {
                    field = getDeclaredField(object.getClass(), name);
                }
                field.setAccessible(true);
                Class classType = field.getType();
                if (value instanceof String)
                {
                    if (classType.isAssignableFrom(Boolean.class) || classType.isAssignableFrom(boolean.class))field.set(object, ((String)value).equalsIgnoreCase("true"));
                    else if (classType.isAssignableFrom(Byte.class) || classType.isAssignableFrom(byte.class)) field.set(object, Byte.parseByte((String)value));
                    else if (classType.isAssignableFrom(Short.class) || classType.isAssignableFrom(short.class)) field.set(object, Short.parseShort((String)value));
                    else if (classType.isAssignableFrom(Integer.class) || classType.isAssignableFrom(int.class)) field.set(object, Integer.parseInt((String)value));
                    else if (classType.isAssignableFrom(Long.class) || classType.isAssignableFrom(long.class)) field.set(object, Long.parseLong((String)value));
                    else if (classType.isAssignableFrom(Float.class) || classType.isAssignableFrom(float.class)) field.set(object, Float.parseFloat((String)value));
                    else if (classType.isAssignableFrom(Double.class) || classType.isAssignableFrom(double.class)) field.set(object, Double.parseDouble((String)value));
                    else if (classType.isAssignableFrom(String.class)) field.set(object, value);
                    else if (classType.isArray() == true)
                    {
                        Class<?> componentType = classType.getComponentType();
                        if ((componentType.isAssignableFrom(Boolean.class)) || componentType.isAssignableFrom(boolean.class))
                        {
                            boolean[] array = (boolean[])field.get(object); Array.set(array, fieldArrayIndex, ((String)value).equalsIgnoreCase("true"));
                        }
                        else if ((componentType.isAssignableFrom(Byte.class)) || componentType.isAssignableFrom(byte.class))
                        {
                            byte[] array = (byte[])field.get(object); Array.set(array, fieldArrayIndex, Byte.parseByte((String)value));
                        }
                        else if ((componentType.isAssignableFrom(Short.class)) || componentType.isAssignableFrom(short.class))
                        {
                            short[] array = (short[])field.get(object); Array.set(array, fieldArrayIndex, Short.parseShort((String)value));
                        }
                        else if ((componentType.isAssignableFrom(Integer.class)) || componentType.isAssignableFrom(int.class))
                        {
                            int[] array = (int[])field.get(object); Array.set(array, fieldArrayIndex, Integer.parseInt((String)value));
                        }
                        else if ((componentType.isAssignableFrom(Long.class)) || componentType.isAssignableFrom(long.class))
                        {
                            long[] array = (long[])field.get(object); Array.set(array, fieldArrayIndex, Long.parseLong((String)value));
                        }
                        else if ((componentType.isAssignableFrom(Float.class)) || componentType.isAssignableFrom(float.class))
                        {
                            float[] array = (float[])field.get(object); Array.set(array, fieldArrayIndex, Float.parseFloat((String)value));
                        }
                        else if ((componentType.isAssignableFrom(Double.class)) || componentType.isAssignableFrom(double.class))
                        {
                            double[] array = (double[])field.get(object); Array.set(array, fieldArrayIndex, Double.parseDouble((String)value));
                        }
                        else
                        {
                        }
                    }
                    else field.set(object, value);
                }
                else
                {
                    field.set(object, value);
                }
            }
            catch (Exception e)
            {
                for (Method method : object.getClass().getDeclaredMethods())
                {
                    if (method.getName().equals(name))
                    {
                        Object finalvalue = value;
                        Class classType = method.getParameterTypes()[0];
                        if (value instanceof String)
                        {
                            if (classType.isAssignableFrom(Boolean.class) || classType.isAssignableFrom(boolean.class)) finalvalue = new Boolean(value.toString().equalsIgnoreCase("true"));
                            else if (classType.isAssignableFrom(Byte.class) || classType.isAssignableFrom(byte.class)) finalvalue = new Byte(value.toString());
                            else if (classType.isAssignableFrom(Short.class) || classType.isAssignableFrom(short.class)) finalvalue = new Short(value.toString());
                            else if (classType.isAssignableFrom(Integer.class) || classType.isAssignableFrom(int.class)) finalvalue = new Integer(value.toString());
                            else if (classType.isAssignableFrom(Long.class) || classType.isAssignableFrom(long.class)) finalvalue = new Long(value.toString());
                            else if (classType.isAssignableFrom(Float.class) || classType.isAssignableFrom(float.class)) finalvalue = new Float(value.toString());
                            else if (classType.isAssignableFrom(Double.class) || classType.isAssignableFrom(double.class))finalvalue = new Double(value.toString());
                            else if (classType.isAssignableFrom(String.class)) finalvalue = value.toString();
                        }
                        method.setAccessible(true);
                        method.invoke(object, finalvalue);
                        return;
                    }
                }
            }
        }
    }
    protected Object getValue(Object value, int arrayIndex)
    {
        try
        {
            if(value.getClass().isArray())
            {
                if(value instanceof Object[])
                {
                    return ((Object[])value)[arrayIndex];
                }
                else // box primitive arrays
                {
                    return Array.get(value, arrayIndex); // automatic boxing
                }
            }
        }
        catch (Exception e)
        {
        }
        return null;
    }
    // </editor-fold>
}
servers/server/src/art/servers/gui/ArticPanel.java
New file
@@ -0,0 +1,178 @@
package art.servers.gui;
import art.library.gui.flat.FlatButton;
import art.library.gui.flat.FlatPanel;
import art.library.gui.flat.FlatTabbedPane;
import art.library.utils.resources.Resources;
import art.servers.Shared;
import art.servers.gui.components.PanelGeneric;
import art.servers.gui.components.PanelProcess;
import art.servers.gui.components.PanelTraces;
import art.servers.gui.components.PanelTracesHistorical;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class ArticPanel extends PanelGeneric
{
    public FlatTabbedPane flatTabbedPane = null;
    private List<PanelGeneric> lPanel = new ArrayList<PanelGeneric>();
    private FlatButton buttonReload = null;
    private ArticWindow window = null;
    public PanelProcess panelSystem = null;
    public PanelTraces panelLogger = null;
    public PanelTraces panelTraces = null;
    public PanelTracesHistorical panelTracesHistorical = null;
    public ArticPanel(ArticWindow window)
    {
        this.window = window;
        flatTabbedPane = new FlatTabbedPane();
        flatTabbedPane.allowTitleChange(false);
        flatTabbedPane.allowTitleChange(false);
        {
            panelSystem = new PanelProcess(window);
            lPanel.add(panelSystem);
            flatTabbedPane.addTab(Shared.getMessage("Process"), panelSystem);
            flatTabbedPane.addChangeListener(new MyChangeListener());
        }
        {
            panelLogger = new PanelTraces(window);
            lPanel.add(panelLogger);
            flatTabbedPane.addTab(Shared.getMessage("Logger"), panelLogger);
            flatTabbedPane.addChangeListener(new MyChangeListener());
        }
        flatTabbedPane.allowTitleChange(false);
        {
            panelTraces = new PanelTraces(window);
            lPanel.add(panelTraces);
            flatTabbedPane.addTab(Shared.getMessage("Traces"), panelTraces);
            flatTabbedPane.addChangeListener(new MyChangeListener());
        }
        flatTabbedPane.allowTitleChange(false);
        {
            panelTracesHistorical = new PanelTracesHistorical(window);
            lPanel.add(panelTracesHistorical);
            flatTabbedPane.addTab(Shared.getMessage("Traces historical"), panelTracesHistorical);
            flatTabbedPane.addChangeListener(new MyChangeListener());
        }
        buttonReload = new FlatButton(Shared.getMessage("&Reload"));
        buttonReload.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/arrows.png"));
        buttonReload.setPreferredSize(new Dimension(buttonReload.getStringWidth(), 0));
        buttonReload.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                reload();
            }
        });
        buttonReload.revalidate();
        window.addButtonMenu(buttonReload);
        window.addButtonSeparator();
        this.setLayout(new BorderLayout());
        FlatPanel panel1 = new FlatPanel();
        panel1.setLayout(new BorderLayout());
        panel1.setBorder(new EmptyBorder(10,5,5,5));
        panel1.add(flatTabbedPane, BorderLayout.CENTER);
        this.add(panel1, BorderLayout.CENTER);
        lPanel.get(0).selection();
        flatTabbedPane.setSelectedIndex(0);
    }
    public void addTab(String name, PanelGeneric panel)
    {
        lPanel.add(panel);
        flatTabbedPane.addTab(name, panel);
    }
    public void removeTab(String name)
    {
        for (int i=0; i<flatTabbedPane.getTabCount(); i++)
        {
            if (flatTabbedPane.getTitleAt(i).equalsIgnoreCase(name))
            {
                flatTabbedPane.removeTabAt(i);
                lPanel.remove(flatTabbedPane.getComponentAt(i));
            }
        }
    }
    public ArticWindow getWindow()
    {
        return window;
    }
    public void reload()
    {
        try
        {
            for (PanelGeneric panel : lPanel)
            {
                panel.reload();
            }
        }
        catch (Exception e)
        {
        }
    }
    public void timer()
    {
        try
        {
            for (PanelGeneric panel : lPanel)
            {
                panel.timer();
            }
        }
        catch (Exception e)
        {
        }
    }
    private class MyChangeListener implements ChangeListener
    {
        public void stateChanged(ChangeEvent e)
        {
            for (PanelGeneric panel : lPanel) panel.deselection();
            if (flatTabbedPane.getSelectedComponent() != null)
            {
                ((PanelGeneric)flatTabbedPane.getSelectedComponent()).selection();
                ((PanelGeneric)flatTabbedPane.getSelectedComponent()).reload();
            }
        }
    }
}
servers/server/src/art/servers/gui/ArticWindow.java
New file
@@ -0,0 +1,442 @@
package art.servers.gui;
import art.library.gui.FlatGUI;
import art.library.gui.flat.FlatButton;
import art.library.gui.flat.FlatDialog;
import art.library.gui.flat.FlatMenu;
import art.library.gui.flat.FlatMenuBar;
import art.library.gui.flat.FlatMenuItem;
import art.library.gui.flat.FlatToggleButton;
import art.library.gui.flat.FlatWindow;
import art.library.model.transactions.traces.Trace;
import art.library.utils.resources.Resources;
import art.servers.Shared;
import art.servers.gui.components.PanelClock;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.MouseInfo;
import java.awt.PointerInfo;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
public class ArticWindow extends FlatWindow
{
    protected ArticWindow window;
    protected MenuListener menuListener;
    protected MyActionListener myActionListener;
    protected javax.swing.Timer secondTimer = null;
    private FlatButton buttonExit = null;
    private FlatButton buttonHide = null;
    private FlatMenuItem menuExit = null;
    private FlatMenuItem menuHide = null;
    private PanelClock panelReloj;
    private ArticPanel articPanel;
    public ArticWindow()
    {
        super();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.window = this;
        myActionListener = new MyActionListener();
        this.setIcon(Resources.getResourceURL(Shared.configuration.general.windowIcon));
        this.setTitle(Shared.configuration.general.windowTitle);
        this.setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        secondTimer = new javax.swing.Timer(1000, new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                timer();
            }
        });
        menuWindow();
        menuBar();
        menuButtons();
        content();
        footer();
        reload();
        secondTimer.start();
        systemTry();
        addWindowListener(new WindowAdapter()
        {
            @Override
            public void windowClosing(WindowEvent evt)
            {
                int answer = FlatDialog.showDialog(ArticWindow.this, Shared.getMessage("Closing"), Shared.getMessage("Do you really want to close?"), true, FlatDialog.DIALOG_QUESTION);
                if (answer == JOptionPane.YES_OPTION)
                {
                    Shared.exit();
                }
            }
        });
    }
    public void addTrace(Object object)
    {
        if (object instanceof Trace)
        {
            articPanel.panelTraces.addTrace(object);
        }
        articPanel.panelLogger.addTrace(object);
    }
    public ArticPanel getArticPanel()
    {
        return articPanel;
    }
    private void menuWindow()
    {
    }
    private void menuBar()
    {
        FlatMenuBar menuBar = new FlatMenuBar();
        FlatMenu menu = new FlatMenu();
        menu.setText(Shared.getMessage("&File"));
        menuExit = new FlatMenuItem();
        menuExit.setText(Shared.getMessage("E&xit"));
        menuExit.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                salir(true);
            }
        });
        menuHide = new FlatMenuItem();
        menuHide.setText(Shared.getMessage("&Hide"));
        menuHide.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                setVisible(false);
            }
        });
        menu.add(menuHide);
        menu.addSeparator();
        menu.add(menuExit);
        menuBar.add(menu);
        this.setMenuBar(menuBar);
    }
    private void menuButtons()
    {
        JToolBar toolbar = new JToolBar();
        this.setMenuButtons(toolbar);
        buttonExit = new FlatButton(Shared.getMessage("E&xit"));
        buttonExit.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/exit10.png"));
        buttonExit.setPreferredSize(new Dimension(buttonExit.getStringWidth(), 0));
        buttonExit.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                salir(true);
            }
        });
        buttonHide = new FlatButton(Shared.getMessage("&Hide"));
        buttonHide.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/hide.png"));
        buttonHide.setPreferredSize(new Dimension(buttonHide.getStringWidth(), 0));
        buttonHide.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                setVisible(false);
            }
        });
        this.addButtonMenu(buttonExit);
        this.addButtonMenu(buttonHide);
        this.addButtonSeparator();
    }
    private void footer()
    {
        panelReloj = new PanelClock();
        setFooter(panelReloj, new Dimension(24, 24));
    }
    public void messageFooter(String text)
    {
        panelReloj.message(text);
    }
    private void content()
    {
        articPanel = new ArticPanel(this);
        this.setContent(articPanel);
        articPanel.selection();
    }
    private void salir(boolean ask)
    {
        if (ask == true)
        {
            int answer = FlatDialog.showDialog(ArticWindow.this, Shared.getMessage("Closing"), Shared.getMessage("Do you really want to close?"), true, FlatDialog.DIALOG_QUESTION);
            if (answer != JOptionPane.YES_OPTION) return;
        }
        Shared.traceInformation(Shared.getMessage("Graphic interface"), "Finishing");
        Shared.exit();
    }
    public void reload()
    {
        articPanel.reload();
        panelReloj.reload();
    };
    public void grants() {};
    public void help() {};
    public void timer()
    {
        if (this.isShowing() == true)
        {
            panelReloj.timer();
            articPanel.timer();
        }
    }
    public void edit(boolean value) {};
    public void setMenuListener(MenuListener menuListener)
    {
        this.menuListener = menuListener;
    }
    public MenuListener getMenuListener()
    {
        return menuListener;
    }
    public void startGUI()
    {
        Runnable runnable = new Runnable()
        {
            public void run()
            {
                showGUI(true);
            }
        };
        SwingUtilities.invokeLater(runnable);
    }
    public void showGUI(int x, int y, int w, int h, boolean resizable, boolean automaticSystemLocation)
    {
        setLocation(x, y);
        if (automaticSystemLocation == true)
        {
            setLocationByPlatform(true);
        }
        setPreferredSize(new Dimension(w, h));
        setResizable(resizable);
        setVisible(true);
        pack();
    }
    public void showGUI(boolean automaticSystemLocation)
    {
        PointerInfo pointerInfo = MouseInfo.getPointerInfo();
        GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
        int x = (int) pointerInfo.getLocation().getX();
        int y = (int) pointerInfo.getLocation().getY();
        int screenWidth = gd.getDisplayMode().getWidth();
        int screenHeight = gd.getDisplayMode().getHeight();
        int w = screenWidth - (x % screenWidth);
        int h = screenHeight - (y % screenHeight);
        setLocation(x, y);
        if (automaticSystemLocation == true)
        {
            setLocationByPlatform(true);
        }
        setPreferredSize(new Dimension(w, h));
        setResizable(true);
        setVisible(true);
        pack();
    }
    private class MyActionListener implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            String action = null;
            if (e.getSource() instanceof FlatMenuItem)
            {
                FlatMenuItem menuItem = (FlatMenuItem) e.getSource();
                action = menuItem.getName();
            }
            else if (e.getSource() instanceof FlatButton)
            {
                FlatButton button = (FlatButton) e.getSource();
                action = button.getName();
            }
            else if (e.getSource() instanceof FlatToggleButton)
            {
                FlatToggleButton button = (FlatToggleButton) e.getSource();
                action = button.getName();
            }
            MenuListener listener = window.getMenuListener();
            if ((action != null) && (listener != null))
            {
                if (listener != null)
                {
                    listener.menuSelection(action);
                }
            }
        }
    }
    private SystemTray tray = null;
    private TrayIcon trayIcon = null;
    private Image icon_STATUS = Resources.getResourceImage("data/" + Shared.getApplicationName() + "/icons/16x16/status-white.png");
    private void systemTry()
    {
        try
        {
            if (!SystemTray.isSupported())
            {
                return;
            }
            PopupMenu popup = new PopupMenu();
            trayIcon = new TrayIcon(icon_STATUS, Shared.configuration.general.windowTitle);
            trayIcon.setPopupMenu(popup);
            tray = SystemTray.getSystemTray();
            MenuItem aboutItem = new MenuItem(Shared.configuration.general.windowTitle);
            aboutItem.setFont(getFont().deriveFont(Font.BOLD));
            MenuItem lookItem = new MenuItem(Shared.getMessage("Look"));
            MenuItem showItem = new MenuItem(Shared.getMessage("Show"));
            MenuItem hideItem = new MenuItem(Shared.getMessage("Hide"));
            MenuItem exitItem = new MenuItem(Shared.getMessage("Exit"));
            //Add components to pop-up menu
            popup.add(aboutItem);
            popup.addSeparator();
            popup.add(lookItem);
            popup.addSeparator();
            popup.add(showItem);
            popup.add(hideItem);
            popup.addSeparator();
            popup.add(exitItem);
            lookItem.addActionListener(new java.awt.event.ActionListener()
            {
                public void actionPerformed(java.awt.event.ActionEvent evt)
                {
                    FlatGUI.initialise();
                    repaint();
                }
            });
            showItem.addActionListener(new java.awt.event.ActionListener()
            {
                public void actionPerformed(java.awt.event.ActionEvent evt)
                {
                    setExtendedState(JFrame.NORMAL);
                    setVisible(true);
                }
            });
            hideItem.addActionListener(new java.awt.event.ActionListener()
            {
                public void actionPerformed(java.awt.event.ActionEvent evt)
                {
                    setVisible(false);
                }
            });
            exitItem.addActionListener(new java.awt.event.ActionListener()
            {
                public void actionPerformed(java.awt.event.ActionEvent evt)
                {
                    salir(false);
                }
            });
            tray.add(trayIcon);
        }
        catch (Exception e)
        {
        }
    }
    public abstract class MenuListener
    {
        public abstract void menuSelection(String option);
    }
}
servers/server/src/art/servers/gui/components/PanelClock.java
New file
@@ -0,0 +1,72 @@
package art.servers.gui.components;
import art.library.gui.flat.FlatLabel;
import art.library.utils.resources.Resources;
import art.servers.Shared;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.text.SimpleDateFormat;
import javax.swing.SwingConstants;
public class PanelClock extends PanelGeneric
{
    private FlatLabel message = null;
    private FlatLabel clock = null;
    public PanelClock()
    {
        this.setLayout(new BorderLayout());
        message = new FlatLabel();
        clock = new FlatLabel();
        clock.setPreferredSize(new Dimension(224, 25));
        clock.getLook().horizontalAlignment = SwingConstants.RIGHT;
        message.getLook().horizontalAlignment = SwingConstants.LEFT;
        message.setIcon(Resources.getResourceURL("data/art.library.server/icons/16x16/group2.png"));
        clock.setIcon(Resources.getResourceURL("data/art.library.server/icons/16x16/schedule2.png"));
        clock.revalidate();
        message.revalidate();
        this.add(message, BorderLayout.CENTER);
        this.add(clock, BorderLayout.EAST);
    }
    public void reload()
    {
        SimpleDateFormat formato1 = new SimpleDateFormat("EEEE, d MMMM yyyy HH:mm:ss", Shared.configuration.getLocale());
        String text = formato1.format(System.currentTimeMillis());
        clock.setText(text);
        clock.setPreferredSize(new Dimension(clock.getStringWidth() + 8, 21));
    }
    public void timer()
    {
        reload();
    }
    public void message(String text)
    {
        if (text != null)
        {
            if (text.length()> 0)
            {
                this.message.setText(text);
            }
            else
            {
                this.message.setText(text);
            }
        }
        else
        {
            this.message.setText("");
        }
    }
}
servers/server/src/art/servers/gui/components/PanelGeneric.java
New file
@@ -0,0 +1,30 @@
package art.servers.gui.components;
import art.library.gui.flat.FlatPanel;
import art.servers.gui.ArticPanel;
import art.servers.gui.ArticWindow;
import java.awt.Component;
public class PanelGeneric extends FlatPanel
{
    public void reload() {}
    public void timer() {}
    public void selection() {}
    public void deselection() {}
    public ArticWindow getWindow(Component component)
    {
        if ((component instanceof ArticPanel) == true)
        {
            return ((ArticPanel)component).getWindow();
        }
        return getWindow(component.getParent());
    }
}
servers/server/src/art/servers/gui/components/PanelProcess.java
New file
@@ -0,0 +1,123 @@
package art.servers.gui.components;
import art.library.gui.flat.FlatPanel;
import art.library.gui.flat.FlatSplitPane;
import art.library.gui.flat.FlatWindow;
import art.library.model.devices.application.ApplicationStatus;
import art.servers.Shared;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JSplitPane;
public class PanelProcess extends PanelGeneric
{
    private FlatWindow window = null;
    private FlatSplitPane flatSplitPane1 = null;
    private PanelProcess_Information panelSystem_Information = null;
    private PanelProcess_Chart panelSystem_CPU = null;
    private PanelProcess_Chart panelSystem_Memory = null;
    private PanelProcess_Chart panelProcess_CPU = null;
    private PanelProcess_Chart panelProcess_Memory = null;
    public PanelProcess(FlatWindow window)
    {
        this.window = window;
        initialise();
    }
    public void selection()
    {
    }
    public void deselection()
    {
    }
    public void timer()
    {
        ApplicationStatus status = Shared.controllerProcessInformation.getApplicationStatus();
        if (panelSystem_Information != null) panelSystem_Information.reload(status);
        if (panelSystem_CPU != null) panelSystem_CPU.reload(status.system.systemCpuLoad * 100);
        if (panelSystem_Memory != null)
        {
            long totalPhysicalMemory = status.system.totalPhysicalMemorySize / 1048576;
            long usedMemory = (status.system.totalPhysicalMemorySize - status.system.freePhysicalMemorySize) / 1048576;
            panelSystem_Memory.reload(totalPhysicalMemory, usedMemory);
        }
        if (panelProcess_CPU != null) panelProcess_CPU.reload(status.system.processCpuLoad * 100);
        if (panelProcess_Memory != null)
        {
            long totalPhysicalMemory = status.memory.heapMemoryUsage_max / 1048576;
            long usedMemory = status.memory.usedMemory / 1048576L;
            panelProcess_Memory.reload(totalPhysicalMemory, usedMemory);
        }
    }
    private void initialise()
    {
        flatSplitPane1 = new FlatSplitPane();
        {
            FlatPanel panel1 = new FlatPanel();
            {
                panelSystem_Information = new PanelProcess_Information();
                panel1.setLayout(new BorderLayout());
                panel1.add(panelSystem_Information, BorderLayout.CENTER);
            }
            FlatPanel panel2 = new FlatPanel();
            {
                panelSystem_CPU = new PanelProcess_Chart("System %CPU", "System %CPU");
                panelSystem_Memory = new PanelProcess_Chart("System, used memory (MB)", "System, used memory (MB)");
                panelProcess_CPU = new PanelProcess_Chart("Process %CPU", "Process %CPU");
                panelProcess_Memory = new PanelProcess_Chart("Process, used memory (MB)", "Process, used memory (MB)");
                panel2.setLayout(new GridLayout(2, 2));
                panel2.add(panelSystem_CPU);
                panel2.add(panelSystem_Memory);
                panel2.add(panelProcess_CPU);
                panel2.add(panelProcess_Memory);
            }
            flatSplitPane1.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
            flatSplitPane1.setLeftComponent(panel1);
            flatSplitPane1.setRightComponent(panel2);
            flatSplitPane1.setOneTouchExpandable();
            flatSplitPane1.changeDividerSize(16);
            flatSplitPane1.addComponentListener(new ComponentAdapter()
            {
                public void componentResized(ComponentEvent e)
                {
                    flatSplitPane1.setDividerLocation(480);
                }
            });
        }
        this.setLayout(new BorderLayout());
        this.add(flatSplitPane1, BorderLayout.CENTER);
    }
}
servers/server/src/art/servers/gui/components/PanelProcess_Chart.java
New file
@@ -0,0 +1,140 @@
package art.servers.gui.components;
import art.library.gui.flat.FlatButton;
import art.library.gui.flat.FlatPanel;
import art.servers.Shared;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.data.Range;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
public class PanelProcess_Chart extends FlatPanel
{
    private JFreeChart chart1;
    private DefaultCategoryDataset dataset1;
    private String title = null;
    private String description = null;
    private Color background = new FlatButton().getLook().colorForegroundSelected;
    public PanelProcess_Chart(String title, String description)
    {
        this.title = title;
        this.description = description;
        initialise();
    }
    public void reload(double value)
    {
        try
        {
            dataset1.clear();
            dataset1.addValue(value, "", "");
            CategoryPlot plot = chart1.getCategoryPlot();
            BarRenderer renderer = (BarRenderer)plot.getRenderer();
            renderer.setSeriesPaint(0, background);
        }
        catch (Exception e)
        {
        }
    }
    public void reload(double total, double value)
    {
        try
        {
            CategoryPlot plot = chart1.getCategoryPlot();
            NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
            rangeAxis.setRange(new Range(0,total));
            dataset1.clear();
            dataset1.addValue(value, "", "");
            BarRenderer renderer = (BarRenderer)plot.getRenderer();
            renderer.setSeriesPaint(0, background);
        }
        catch (Exception e)
        {
        }
    }
    private void initialise()
    {
        dataset1 = new DefaultCategoryDataset();
        chart1 = createChart(dataset1, 0, 100);
        ChartPanel chartPanel1 = new ChartPanel(chart1);
        this.setLayout(new java.awt.BorderLayout());
        this.add(chartPanel1, BorderLayout.CENTER);
    }
    private JFreeChart createChart (CategoryDataset dataset, double min, double max)
    {
        // create the chart...
        final JFreeChart chart = ChartFactory.createBarChart
        (
            Shared.getMessage(title),    // chart title
            "",                          // domain axis label
            "",                          // range axis label
            dataset,                     // data
            PlotOrientation.VERTICAL,    // orientation
            false,                       // include legend
            false,                       // tooltips?
            false                        // URLs?
        );
        FlatButton reference = new FlatButton();
        chart.setTitle(new org.jfree.chart.title.TextTitle(Shared.getMessage(description), reference.getFont().deriveFont(Font.PLAIN, 12)));
        chart.setBackgroundPaint(this.getBackground());
        // get a reference to the plot for further customisation...
        CategoryPlot plot = chart.getCategoryPlot();
        plot.setBackgroundPaint(Color.black);
        plot.setForegroundAlpha(1.0f);
        plot.setDomainGridlinePaint(reference.getLook().colorForegroundRollover);
        plot.setRangeGridlinePaint(reference.getLook().colorForegroundRollover);
        // set the range axis to display integers only...
        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        rangeAxis.setRange(new Range(min,max));
        rangeAxis.setVisible(true);
        // disable bar outlines...
        BarRenderer renderer = (BarRenderer)plot.getRenderer();
        renderer.setDrawBarOutline(true);
        renderer.setShadowVisible(false);
        // set up gradient paints for series...
        CategoryAxis domainAxis = plot.getDomainAxis();
        domainAxis.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 6.0));
        domainAxis.setVisible(false);
        return chart;
    }
}
servers/server/src/art/servers/gui/components/PanelProcess_Information.java
New file
@@ -0,0 +1,236 @@
package art.servers.gui.components;
import art.library.gui.flat.FlatPanel;
import art.library.gui.flat.FlatTabbedPane;
import art.library.gui.flat.FlatTableInput;
import art.library.model.devices.application.ApplicationStatus;
import art.library.utils.common.DateUtils;
import art.servers.Shared;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import javax.swing.SwingConstants;
public class PanelProcess_Information extends FlatPanel
{
    private FlatTableInput table1 = null;
    private FlatTableInput table2 = null;
    private FlatTableInput table3 = null;
    private FlatTableInput table4 = null;
    public PanelProcess_Information()
    {
        initialise();
    }
    public void reload(ApplicationStatus status)
    {
        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss"));
        DecimalFormat formato2 = new DecimalFormat("###,###.##");
        table1.setValue(Shared.getMessage("Timestamp"), formato1.format(status.system.timestamp));
        table1.setValue(Shared.getMessage("Name"), status.system.name);
        table1.setValue(Shared.getMessage("Version"), status.system.version);
        table1.setValue(Shared.getMessage("Architecture"), status.system.arch);
        table1.setValue(Shared.getMessage("Available processors"), status.system.availableProcessors);
        table1.setValue(Shared.getMessage("System cpu current"), String.format("%.1f", status.system.systemCpuLoad * 100));
        table1.setValue(Shared.getMessage("System cpu average"), String.format("%.1f", status.system.systemLoadAverage));
        table1.setValue(Shared.getMessage("Total physical memory size"), formato2.format(status.system.totalPhysicalMemorySize/1048576L));
        table1.setValue(Shared.getMessage("Used physical memory size"), formato2.format((status.system.totalPhysicalMemorySize - status.system.freePhysicalMemorySize) / 1048576));
        table1.setValue(Shared.getMessage("Free physical memory size"), formato2.format(status.system.freePhysicalMemorySize/1048576L));
        table1.setValue(Shared.getMessage("Committed virtual memory size"), formato2.format(status.system.committedVirtualMemorySize/1048576L));
        table1.setValue(Shared.getMessage("Total swap space size"), formato2.format(status.system.totalSwapSpaceSize/1048576L));
        table1.setValue(Shared.getMessage("Free swap space size"), formato2.format(status.system.freeSwapSpaceSize/1048576L));
        table2.setValue(Shared.getMessage("Timestamp"), formato1.format(status.runtime.timestamp));
        table2.setValue(Shared.getMessage("Start time"), formato1.format(status.runtime.startTime));
        table2.setValue(Shared.getMessage("Up time"), DateUtils.getTimeddHHMMSS(status.runtime.upTime));
        table2.setValue(Shared.getMessage("Process cpu time"), DateUtils.getTimeddHHMMSS(status.system.processCpuTime/1000000L));
        table2.setValue(Shared.getMessage("Process cpu current"), String.format("%.1f", status.system.processCpuLoad * 100));
        table2.setValue(Shared.getMessage("Process cpu average"), String.format("%.1f", 100*(((double)status.system.processCpuTime/1000000)/(double)status.runtime.upTime)));
        table2.setValue(Shared.getMessage("Java specification version"), status.runtime.javaVmSpecificationVersion);
        table2.setValue(Shared.getMessage("Java runtime version"), status.runtime.javaRuntimeVersion);
        table2.setValue(Shared.getMessage("Java class  version"), status.runtime.javaClassVersion);
        table2.setValue(Shared.getMessage("Time zone"), status.runtime.userTimeZone);
        table2.setValue(Shared.getMessage("Country"), status.runtime.userCountry);
        table2.setValue(Shared.getMessage("Language"), status.runtime.userLanguage);
        table3.setValue(Shared.getMessage("Timestamp"), formato1.format(status.memory.timestamp));
        table3.setValue(Shared.getMessage("Used memory"), formato2.format(status.memory.usedMemory/1048576L));
        table3.setValue(Shared.getMessage("Heap memory usage init"), formato2.format(status.memory.heapMemoryUsage_init/1048576L));
        table3.setValue(Shared.getMessage("Heap memory usage used"), formato2.format(status.memory.heapMemoryUsage_used/1048576L));
        table3.setValue(Shared.getMessage("Heap memory usage commited"), formato2.format(status.memory.heapMemoryUsage_committed/1048576L));
        table3.setValue(Shared.getMessage("Heap memory usage max"), formato2.format(status.memory.heapMemoryUsage_max/1048576L));
        table3.setValue(Shared.getMessage("Non heap memory usage init"), formato2.format(status.memory.nonheapMemoryUsage_init/1048576L));
        table3.setValue(Shared.getMessage("Non heap memory usage used"), formato2.format(status.memory.nonheapMemoryUsage_used/1048576L));
        table3.setValue(Shared.getMessage("Non heap memory usage commited"), formato2.format(status.memory.nonheapMemoryUsage_committed/1048576L));
        table3.setValue(Shared.getMessage("Non heap memory usage max"), formato2.format(status.memory.nonheapMemoryUsage_max/1048576L));
        table4.setValue(Shared.getMessage("Timestamp"), formato1.format(status.thread.timestamp));
        table4.setValue(Shared.getMessage("Thread count"), formato2.format(status.thread.threadCount));
        table4.setValue(Shared.getMessage("Peak thread count"), formato2.format(status.thread.peakThreadCount));
        table4.setValue(Shared.getMessage("Total started thread count"), formato2.format(status.thread.totalStartedThreadCount));
        table4.setValue(Shared.getMessage("Daemon thread count"), formato2.format(status.thread.daemonThreadCount));
    }
    private void initialise()
    {
        FlatPanel panel1 = new FlatPanel();
        {
        }
        FlatPanel panel2 = new FlatPanel();
        {
            FlatTabbedPane flatTabbedPane1 = new FlatTabbedPane();
            {
                FlatPanel panel2_1 = new FlatPanel();
                {
                    table1 = new FlatTableInput(250);
                    {
                        table1.addTextField(Shared.getMessage("Timestamp"), 22);
                        table1.addTextField(Shared.getMessage("Name"), 22);
                        table1.addTextField(Shared.getMessage("Version"), 22);
                        table1.addTextField(Shared.getMessage("Architecture"), 22);
                        table1.addTextField(Shared.getMessage("Available processors"), 22);
                        table1.addTextField(Shared.getMessage("System cpu current"), 22);
                        table1.addTextField(Shared.getMessage("System cpu average"), 22);
                        table1.addTextField(Shared.getMessage("Total physical memory size"), 22);
                        table1.addTextField(Shared.getMessage("Used physical memory size"), 22);
                        table1.addTextField(Shared.getMessage("Free physical memory size"), 22);
                        table1.addTextField(Shared.getMessage("Committed virtual memory size"), 22);
                        table1.addTextField(Shared.getMessage("Total swap space size"), 22);
                        table1.addTextField(Shared.getMessage("Free swap space size"), 22);
                        table1.setMeasurementUnits(Shared.getMessage("System cpu current"), Shared.getMessage("%"), 100, SwingConstants.CENTER);
                        table1.setMeasurementUnits(Shared.getMessage("System cpu average"), Shared.getMessage("%"), 100, SwingConstants.CENTER);
                        table1.setMeasurementUnits(Shared.getMessage("Total physical memory size"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table1.setMeasurementUnits(Shared.getMessage("Used physical memory size"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table1.setMeasurementUnits(Shared.getMessage("Free physical memory size"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table1.setMeasurementUnits(Shared.getMessage("Committed virtual memory size"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table1.setMeasurementUnits(Shared.getMessage("Total swap space size"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table1.setMeasurementUnits(Shared.getMessage("Free swap space size"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table1.setEditable(false);
                        table1.revalidate();
                    }
                    panel2_1.setLayout(new BorderLayout());
                    panel2_1.setPreferredSize(new Dimension(0, table1.getDimensionHeight() + 1));
                    panel2_1.add(table1.getScrollPane(), BorderLayout.CENTER);
                    flatTabbedPane1.addTab(Shared.getMessage("System"), panel2_1);
                }
                FlatPanel panel2_2 = new FlatPanel();
                {
                    table2 = new FlatTableInput(250);
                    {
                        table2.addTextField(Shared.getMessage("Timestamp"), 22);
                        table2.addTextField(Shared.getMessage("Start time"), 22);
                        table2.addTextField(Shared.getMessage("Up time"), 22);
                        table2.addTextField(Shared.getMessage("Process cpu time"), 22);
                        table2.addTextField(Shared.getMessage("Process cpu current"), 22);
                        table2.addTextField(Shared.getMessage("Process cpu average"), 22);
                        table2.addTextField(Shared.getMessage("Java specification version"), 22);
                        table2.addTextField(Shared.getMessage("Java runtime version"), 22);
                        table2.addTextField(Shared.getMessage("Java class  version"), 22);
                        table2.addTextField(Shared.getMessage("Time zone"), 22);
                        table2.addTextField(Shared.getMessage("Country"), 22);
                        table2.addTextField(Shared.getMessage("Language"), 22);
                        table2.setMeasurementUnits(Shared.getMessage("Up time"), Shared.getMessage("d,HH:mm:ss"), 100, SwingConstants.CENTER);
                        table2.setMeasurementUnits(Shared.getMessage("Process cpu time"), Shared.getMessage("d, HH:mm:ss"), 100, SwingConstants.CENTER);
                        table2.setMeasurementUnits(Shared.getMessage("Process cpu current"), Shared.getMessage("%"), 100, SwingConstants.CENTER);
                        table2.setMeasurementUnits(Shared.getMessage("Process cpu average"), Shared.getMessage("%"), 100, SwingConstants.CENTER);
                        table2.setEditable(false);
                        table2.revalidate();
                    }
                    panel2_2.setLayout(new BorderLayout());
                    panel2_2.setPreferredSize(new Dimension(0, table2.getDimensionHeight() + 1));
                    panel2_2.add(table2.getScrollPane(), BorderLayout.CENTER);
                    flatTabbedPane1.addTab(Shared.getMessage("Process runtime"), panel2_2);
                }
                FlatPanel panel2_3 = new FlatPanel();
                {
                    table3 = new FlatTableInput(250);
                    {
                        table3.addTextField(Shared.getMessage("Timestamp"), 22);
                        table3.addTextField(Shared.getMessage("Used memory"), 22);
                        table3.addTextField(Shared.getMessage("Heap memory usage init"), 22);
                        table3.addTextField(Shared.getMessage("Heap memory usage used"), 22);
                        table3.addTextField(Shared.getMessage("Heap memory usage commited"), 22);
                        table3.addTextField(Shared.getMessage("Heap memory usage max"), 22);
                        table3.addTextField(Shared.getMessage("Non heap memory usage init"), 22);
                        table3.addTextField(Shared.getMessage("Non heap memory usage used"), 22);
                        table3.addTextField(Shared.getMessage("Non heap memory usage commited"), 22);
                        table3.addTextField(Shared.getMessage("Non heap memory usage max"), 22);
                        table3.setMeasurementUnits(Shared.getMessage("Heap memory usage init"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Heap memory usage used"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Heap memory usage commited"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Heap memory usage max"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Non heap memory usage init"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Non heap memory usage used"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Non heap memory usage commited"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Non heap memory usage max"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
                        table3.setEditable(false);
                        table3.revalidate();
                    }
                    panel2_3.setLayout(new BorderLayout());
                    panel2_3.setPreferredSize(new Dimension(0, table3.getDimensionHeight() + 1));
                    panel2_3.add(table3.getScrollPane(), BorderLayout.CENTER);
                    flatTabbedPane1.addTab(Shared.getMessage("Process memory"), panel2_3);
                }
                FlatPanel panel2_4 = new FlatPanel();
                {
                    table4 = new FlatTableInput(250);
                    {
                        table4.addTextField(Shared.getMessage("Timestamp"), 22);
                        table4.addTextField(Shared.getMessage("Total started thread count"), 22);
                        table4.addTextField(Shared.getMessage("Thread count"), 22);
                        table4.addTextField(Shared.getMessage("Peak thread count"), 22);
                        table4.addTextField(Shared.getMessage("Daemon thread count"), 22);
                        table4.setEditable(false);
                        table4.revalidate();
                    }
                    panel2_4.setLayout(new BorderLayout());
                    panel2_4.setPreferredSize(new Dimension(0, table4.getDimensionHeight() + 1));
                    panel2_4.add(table4.getScrollPane(), BorderLayout.CENTER);
                    flatTabbedPane1.addTab(Shared.getMessage("Process threads"), panel2_4);
                }
            }
            panel2.setLayout(new BorderLayout());
            panel2.setPreferredSize(new Dimension(0, table1.getDimensionHeight() + 1));
            panel2.add(flatTabbedPane1, BorderLayout.CENTER);
        }
        this.setLayout(new BorderLayout());
        this.add(panel1, BorderLayout.NORTH);
        this.add(panel2, BorderLayout.CENTER);
    }
}
servers/server/src/art/servers/gui/components/PanelTraces.java
New file
@@ -0,0 +1,531 @@
package art.servers.gui.components;
import art.library.gui.FlatGUI;
import art.library.gui.flat.FlatButton;
import art.library.gui.flat.FlatScrollPane;
import art.library.gui.flat.FlatToggleButton;
import art.library.gui.flat.FlatWindow;
import art.library.model.transactions.traces.Note;
import art.library.model.transactions.traces.Trace;
import art.library.utils.resources.Resources;
import art.library.utils.synchro.Mutex;
import art.servers.Shared;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Element;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
public class PanelTraces extends PanelGeneric
{
    public static final int SCREEN_RESET = 0;
    public static final int SCREEN_BRIGHT = 1;
    public static final int SCREEN_DIM = 2;
    public static final int SCREEN_BLINK = 3;
    public static final int SCREEN_UNDERLINE = 4;
    public static final int SCREEN_REVERSE = 7;
    public static final int SCREEN_HIDDEN = 8;
    public static final int SCREEN_BLACK = 0;
    public static final int SCREEN_RED = 1;
    public static final int SCREEN_GREEN = 2;
    public static final int SCREEN_YELLOW = 3;
    public static final int SCREEN_BLUE = 4;
    public static final int SCREEN_MAGENTA = 5;
    public static final int SCREEN_CYAN = 6;
    public static final int SCREEN_WHITE = 7;
    protected Color myblack = new Color(35,35,35);
    protected FlatScrollPane scrollPane = new FlatScrollPane();
    protected DefaultStyledDocument document = new DefaultStyledDocument();
    protected JTextPane textpane = new JTextPane(document);
    protected StyleContext context = new StyleContext();
    protected Style style = context.getStyle(StyleContext.DEFAULT_STYLE);
    protected boolean autoscroll = true;
    protected int totalLines = 1000;
    protected FlatToggleButton buttonView = null;
    protected FlatButton buttonCopy = null;
    protected FlatButton buttonTrash = null;
    protected FlatToggleButton buttonAutoscroll = null;
    protected FlatWindow window = null;
    protected List<Object> traces = new ArrayList<Object>();
    protected Mutex mutex = new Mutex();
    public PanelTraces(FlatWindow window, int totalLines)
    {
        this.window = window;
        this.totalLines = totalLines;
        this.
        initialise();
    }
    public PanelTraces(FlatWindow window)
    {
        this.window = window;
        initialise();
    }
    public void selection()
    {
        try
        {
            window.addButtonSeparator();
            window.addButtonMenu(buttonView);
            window.addButtonMenu(buttonCopy);
            window.addButtonMenu(buttonTrash);
            window.addButtonMenu(buttonAutoscroll);
        }
        catch (Exception e)
        {
        }
    }
    public void deselection()
    {
        try
        {
            window.removeComponentMenu(buttonView);
            window.removeComponentMenu(buttonCopy);
            window.removeComponentMenu(buttonTrash);
            window.removeComponentMenu(buttonAutoscroll);
        }
        catch (Exception e)
        {
        }
    }
    protected void initialise()
    {
        buttonView = new FlatToggleButton(Shared.getMessage("&View"));
        buttonView.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/list.png"));
        buttonView.setPreferredSize(new Dimension(buttonView.getStringWidth(), 0));
        buttonView.setPreferredSize(new Dimension(buttonView.getStringWidth(), 0));
        buttonView.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                view(buttonView.isSelected());
            }
        });
        buttonCopy = new FlatButton(Shared.getMessage("&Copy"));
        buttonCopy.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/copy.png"));
        buttonCopy.setPreferredSize(new Dimension(buttonCopy.getStringWidth(), 0));
        buttonCopy.setPreferredSize(new Dimension(buttonCopy.getStringWidth(), 0));
        buttonCopy.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                copyToClipboard();
            }
        });
        buttonTrash = new FlatButton(Shared.getMessage("Clea&r"));
        buttonTrash.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/clear.png"));
        buttonTrash.setPreferredSize(new Dimension(buttonTrash.getStringWidth(), 0));
        buttonTrash.setPreferredSize(new Dimension(buttonTrash.getStringWidth(), 0));
        buttonTrash.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                clear();
            }
        });
        buttonAutoscroll = new FlatToggleButton(Shared.getMessage("&Autoscroll"));
        buttonAutoscroll.setSelected(true);
        buttonAutoscroll.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/escalator-down.png"));
        buttonAutoscroll.setPreferredSize(new Dimension(buttonAutoscroll.getStringWidth(), 0));
        buttonAutoscroll.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                autoscroll(buttonAutoscroll.isSelected());
            }
        });
        document = new DefaultStyledDocument();
        textpane = new JTextPane(document);
        //textpane.setContentType("text/html;charset=UTF-8");
        textpane.setEditable(false);
        textpane.setEditable(false);
        textpane.setBackground(myblack);
        textpane.setMargin(new Insets(10,10,10,10));
        StyleConstants.setSpaceAbove(style, 10);
        StyleConstants.setSpaceBelow(style, 10);
        StyleConstants.setFontSize(style, 12);
        StyleConstants.setFontFamily(style, "Monospaced");
        StyleConstants.setForeground(style, Color.white);
        StyleConstants.setBackground(style, myblack);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.getViewport().setBackground(Color.black);
        scrollPane.getViewport().add(textpane);
        this.getLook().background = FlatGUI.lookDesign.getColor("button.color.rollover.background");
        this.setLayout(new BorderLayout());
        this.add(scrollPane, BorderLayout.CENTER);
        scrollPane.setVisible(false);
        TimerTask timerTask = new TimerTask()
        {
            public void run()
            {
                reload();
            }
        };
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(timerTask, 0, 1000);
    }
    public void addTrace(Object object)
    {
        mutex.lockWrite();
        {
            traces.add(object);
        }
        mutex.releaseWrite();
    }
    public void reload()
    {
        try
        {
            List<Object> localtraces = new ArrayList<Object>();
            mutex.lockWrite();
            {
                localtraces.addAll(this.traces);
                this.traces.clear();
            }
            mutex.releaseWrite();
            SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss.SSS"));
            for(Object object : localtraces)
            {
                String result = "";
                if (object instanceof Trace)
                {
                    Trace trace = (Trace)object;
                    result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK);
                    result = result + formato1.format(trace.timestamp) + "\n";
                    switch (trace.type)
                    {
                        case Trace.TRACE_NONE: result = result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK); break;
                        case Trace.TRACE_INFORMATION:  result = result = result + color(SCREEN_RESET, SCREEN_CYAN, SCREEN_BLACK); break;
                        case Trace.TRACE_WARNING: result = result + color(SCREEN_RESET, SCREEN_YELLOW, SCREEN_BLACK); break;
                        case Trace.TRACE_ERROR: result = result + color(SCREEN_RESET, SCREEN_RED, SCREEN_BLACK); break;
                        case Trace.TRACE_CORRECT: result = result + color(SCREEN_RESET, SCREEN_RED, SCREEN_BLACK); break;
                    }
                    result = result + "{\n";
                    if (trace.sourceComputer != null) result = result + "   " + Shared.getMessage("Source") + " : " + trace.sourceComputer + "\n";
                    if (trace.username != null) result = result + "   " + Shared.getMessage("Username") + " : " + trace.username + "\n";
                    if (trace.profile != null) result = result + "   " + Shared.getMessage("Profile") + " : " + trace.profile + "\n";
                    if (trace.service != null) result = result + "   " + Shared.getMessage("Service") + " : " + trace.service + "\n";
                    if (trace.action != null) result = result + "   " + Shared.getMessage("Action") + " : " + trace.action + "\n";
                    if (trace.resource != null) result = result + "   " + Shared.getMessage("Resource") + " : " + trace.resource + "\n";
                    if (trace.result != null) result = result + "   " + Shared.getMessage("Result") + " : " + trace.result + "\n";
                    if (trace.stack != null) result = result + "   " + Shared.getMessage("Stack") + " : " + trace.stack + "\n";
                    result = result + "}\n";
                    newLine(result);
                }
                else if (object instanceof Note)
                {
                    Note note = (Note)object;
                    result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK);
                    result = result + formato1.format(note.timestamp) + " : ";
                    switch (note.type)
                    {
                        case Trace.TRACE_NONE: result = result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK); break;
                        case Trace.TRACE_INFORMATION:  result = result = result + color(SCREEN_RESET, SCREEN_CYAN, SCREEN_BLACK); break;
                        case Trace.TRACE_WARNING: result = result + color(SCREEN_RESET, SCREEN_YELLOW, SCREEN_BLACK); break;
                        case Trace.TRACE_ERROR: result = result + color(SCREEN_RESET, SCREEN_RED, SCREEN_BLACK); break;
                        case Trace.TRACE_CORRECT: result = result + color(SCREEN_RESET, SCREEN_GREEN, SCREEN_BLACK); break;
                    }
                    result = result + note.message;
                    newLine(result);
                }
                else
                {
                    result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK);
                    result = result + formato1.format(System.currentTimeMillis()) + " : ";
                    result = result + color(SCREEN_RESET, SCREEN_CYAN, SCREEN_BLACK);
                    result = result + object.toString().trim();
                    newLine(result);
                }
            }
        }
        catch (Exception e)
        {
        }
    }
    public void view(boolean value)
    {
        scrollPane.setVisible(value);
    }
    public void autoscroll(boolean value)
    {
        this.autoscroll = value;
    }
    public void copyToClipboard()
    {
        try
        {
            Clipboard clpbrd = Toolkit.getDefaultToolkit ().getSystemClipboard ();
            clpbrd.setContents (new StringSelection (textpane.getDocument().getText(0, textpane.getDocument().getLength())), null);
        }
        catch (Exception e)
        {
        }
    }
    public void clear()
    {
        try
        {
            document.remove(0,document.getLength());
        }
        catch (Exception e)
        {
        }
    }
    public void newLine(String text)
    {
       try
       {
          List<Message> lmessage = getMessages(text);
          for (Message message : lmessage)
          {
              if (message.foreground != null) StyleConstants.setForeground(style, message.foreground);
              if (message.background != null) StyleConstants.setBackground(style, message.background);
              document.insertString(document.getLength(), message.text, style);
          }
          document.insertString(document.getLength(), "\n", style);
          if (autoscroll == true)
          {
              textpane.setCaretPosition(textpane.getDocument().getLength());
          }
          if (totalLines > 0)
          {
             Element root = textpane.getDocument().getDefaultRootElement();
             while (root.getElementCount() > totalLines)
             {
                 Element first = root.getElement(0);
                 textpane.getDocument().remove(first.getStartOffset(), first.getEndOffset());
             }
          }
       }
       catch (Exception e)
       {
       }
    }
    protected List getMessages(String text)
    {
        byte[] data = text.getBytes();
        List<Message> lmessage = new ArrayList<Message>();
        int position = 0;
        while (position >= 0) position = nextMessage(data, position, lmessage);
        return lmessage;
    }
    protected int nextMessage(byte[] data, int position, List<Message> lmessage)
    {
        for (int i=0; i<data.length; i++)
        {
            int position1 = getCharacter(data, position, (byte)27);
            int position2 = getCharacter(data, position1 + 10, (byte)27);
            if (position2 == -1) position2 = data.length;
            if (position1 == -1)
            {
                byte[] aux1 = new byte[0];
                Message message = new Message(new String(aux1), new String(data));
                lmessage.add(message);
                return -1;
            }
            byte[] aux1 = new byte[10];
            byte[] aux2 = new byte[position2-position1-10];
            System.arraycopy(data, position1, aux1, 0, aux1.length);
            System.arraycopy(data, position1+10, aux2, 0, aux2.length);
            Message message = new Message(new String(aux1), new String(aux2));
            lmessage.add(message);
            if (position2 == data.length) return -1;
            return position2;
        }
        return -1;
    }
    protected int getCharacter(byte[] data, int position, byte character)
    {
        if (position < 0) return -1;
        for (int i=position; i<data.length; i++)
        {
            if (data[i] == character)
            {
                return i;
            }
        }
        return -1;
    }
    // 
    // %c[%d;%d;%dm   --> ESC[attributes;foreground;brackground
    //
    // ESC : 27
    //
    // attributes
    //    SCREEN_RESET      0
    //    SCREEN_BRIGHT     1
    //    SCREEN_DIM        2
    //    SCREEN_BLINK      3
    //    SCREEN_UNDERLINE  4
    //    SCREEN_REVERSE    7
    //    SCREEN_HIDDEN     8
    //
    // colors
    //    SCREEN_BLACK      0
    //    SCREEN_RED        1
    //    SCREEN_GREEN      2
    //    SCREEN_YELLOW     3
    //    SCREEN_BLUE       4
    //    SCREEN_MAGENTA    5
    //    SCREEN_CYAN       6
    //    SCREEN_WHITE      7
    protected class Message
    {
        public String text;
        public Color foreground = null;
        public Color background = null;
        public Message(String control, String text)
        {
            this.text = text;
            if (control.length() == 10)
            {
                foreground = color(Integer.parseInt(control.substring(4,6)) - 30);
                background = color(Integer.parseInt(control.substring(4,6)) - 40);
            }
        }
        protected Color color(int color)
        {
            switch (color)
            {
                case 0 : return myblack;
                case 1 : return Color.red;
                case 2 : return Color.green;
                case 3 : return Color.yellow;
                case 4 : return Color.blue;
                case 5 : return Color.magenta;
                case 6 : return Color.cyan;
                case 7 : return Color.white;
            }
            return myblack;
        }
    }
    protected static String color (int attributes, int foreground, int background)
    {
       return "\033[" + attributes + ";" + (foreground + 30) + ";" + (background + 40) + "m";
    }
}
servers/server/src/art/servers/gui/components/PanelTracesHistorical.java
New file
@@ -0,0 +1,231 @@
package art.servers.gui.components;
import art.library.gui.flat.FlatButton;
import art.library.gui.flat.FlatDatePicker;
import art.library.gui.flat.FlatLabel;
import art.library.gui.flat.FlatPanel;
import art.library.gui.flat.FlatTextField;
import art.library.gui.flat.FlatWindow;
import art.library.model.transactions.traces.Trace;
import art.servers.Shared;
import static art.servers.gui.components.PanelTraces.color;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.swing.SwingConstants;
public class PanelTracesHistorical extends PanelTraces
{
    private FlatDatePicker datePicker1 = null;
    private FlatDatePicker datePicker2 = null;
    private FlatButton button1 = null;
    private FlatTextField textfield1 = null;
    private int totalTraces = 100;
    public PanelTracesHistorical(FlatWindow window)
    {
        super(window, 0);
        this.initialisePanelTracesHistorical();
    }
    protected void initialisePanelTracesHistorical()
    {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        datePicker1 = new FlatDatePicker(FlatDatePicker.TYPE_PICKER_DAY, SwingConstants.LEFT, true, false);
        datePicker1.setLocale(Shared.configuration.getLocale());
        datePicker1.setTimestamp(calendar.getTimeInMillis());
        calendar.add(Calendar.DATE, 1);
        datePicker2 = new FlatDatePicker(FlatDatePicker.TYPE_PICKER_DAY, SwingConstants.LEFT, true, false);
        datePicker2.setLocale(Shared.configuration.getLocale());
        datePicker2.setTimestamp(calendar.getTimeInMillis());
        FlatPanel panel1 = new FlatPanel();
        {
            FlatPanel panel1_1 = new FlatPanel();
            {
                FlatPanel panel1_1_1 = new FlatPanel();
                {
                    panel1_1_1.setRaisedBorder(0, 0, 0, 1);
                    panel1_1_1.setLayout(new BorderLayout());
                    panel1_1_1.add(datePicker1, BorderLayout.CENTER);
                }
                FlatPanel panel1_1_2 = new FlatPanel();
                {
                    panel1_1_2.setRaisedBorder(0, 1, 0, 1);
                    panel1_1_2.setLayout(new BorderLayout());
                    panel1_1_2.add(datePicker2, BorderLayout.CENTER);
                }
                FlatPanel panel1_1_3 = new FlatPanel();
                {
                    FlatPanel panel1_1_3_1 = new FlatPanel();
                    {
                        FlatLabel label1 = new FlatLabel("Limit");
                        textfield1 = new FlatTextField();
                        textfield1.setText("" + totalTraces);
                        textfield1.setNumeric(true, 1, 1000);
                        panel1_1_3_1.setLayout(new GridLayout(1, 2));
                        panel1_1_3_1.add(label1);
                        panel1_1_3_1.add(textfield1);
                    }
                    panel1_1_3.setLayout(new BorderLayout());
                    panel1_1_3.setPanelMargins(new Insets(4, 4, 4, 4));
                    panel1_1_3.setRaisedBorder(0, 1, 0, 0);
                    panel1_1_3.add(panel1_1_3_1, BorderLayout.CENTER);
                }
                panel1_1.setLayout(new GridLayout(1, 3));
                panel1_1.add(panel1_1_1);
                panel1_1.add(panel1_1_2);
                panel1_1.add(panel1_1_3);
                panel1_1.setRaisedBorder(0,0,1,0);
            }
            FlatPanel panel1_2 = new FlatPanel();
            {
                button1 = new FlatButton(Shared.getMessage("Execute"));
                button1.getLook().horizontalAlignment = SwingConstants.CENTER;
                panel1_2.setPreferredSize(new Dimension(44,44));
                panel1_2.setLayout(new BorderLayout());
                panel1_2.add(button1, BorderLayout.CENTER);
                panel1_2.setRaisedBorder(1,0,1,0);
                panel1_2.setPanelMargins(new Insets(4, 4, 4, 4));
            }
            panel1.setPreferredSize(new Dimension(0,80));
            panel1.setLayout(new BorderLayout());
            panel1.add(panel1_1, BorderLayout.CENTER);
            panel1.add(panel1_2, BorderLayout.SOUTH);
            button1.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    listTraces();
                }
            });
        }
        this.add(panel1, BorderLayout.NORTH);
    }
    public void addTrace(Object object)
    {
        mutex.lockWrite();
        {
            traces.add(object);
        }
        mutex.releaseWrite();
    }
    public void reload()
    {
    }
    public void view(boolean value)
    {
        scrollPane.setVisible(value);
    }
    private void listTraces()
    {
        clear();
        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss.SSS"));
        try
        {
            totalTraces = Integer.parseInt(textfield1.getText());
        }
        catch (Exception e)
        {
            totalTraces = 100;
            textfield1.setText("" + totalTraces );
        }
        try
        {
            long from = datePicker1.getCalendar().getTimeInMillis();
            long to = datePicker2.getCalendar().getTimeInMillis();
            List<Trace> ltrace =  Shared.model.getTraces(Shared.getLanguage(), from, to, Shared.getApplicationName(), totalTraces);
            for (Trace trace : ltrace)
            {
                String result = "";
                result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK);
                result = result + formato1.format(trace.timestamp) + "\n";
                switch (trace.type)
                {
                    case Trace.TRACE_NONE: result = result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK); break;
                    case Trace.TRACE_INFORMATION:  result = result = result + color(SCREEN_RESET, SCREEN_CYAN, SCREEN_BLACK); break;
                    case Trace.TRACE_WARNING: result = result + color(SCREEN_RESET, SCREEN_YELLOW, SCREEN_BLACK); break;
                    case Trace.TRACE_ERROR: result = result + color(SCREEN_RESET, SCREEN_RED, SCREEN_BLACK); break;
                    case Trace.TRACE_CORRECT: result = result + color(SCREEN_RESET, SCREEN_GREEN, SCREEN_BLACK); break;
                }
                result = result + "{\n";
                if (trace.sourceComputer != null) result = result + "   " + Shared.getMessage("Source") + " : " + trace.sourceComputer + "\n";
                if (trace.username != null) result = result + "   " + Shared.getMessage("Username") + " : " + trace.username + "\n";
                if (trace.profile != null) result = result + "   " + Shared.getMessage("Profile") + " : " + trace.profile + "\n";
                if (trace.service != null) result = result + "   " + Shared.getMessage("Service") + " : " + trace.service + "\n";
                if (trace.action != null) result = result + "   " + Shared.getMessage("Action") + " : " + trace.action + "\n";
                if (trace.resource != null) result = result + "   " + Shared.getMessage("Resource") + " : " + trace.resource + "\n";
                if (trace.result != null) result = result + "   " + Shared.getMessage("Result") + " : " + trace.result + "\n";
                if (trace.stack != null) result = result + "   " + Shared.getMessage("Stack") + " : " + trace.stack + "\n";
                result = result + "}\n";
                newLine(result);
                addTrace(trace);
            }
        }
        catch (Exception e)
        {
        }
        scrollPane.getViewport().setViewPosition(new Point(0,0));
        buttonView.setSelected(true);
        scrollPane.setVisible(true);
    }
}
servers/server/src/art/servers/types/HttpAuthentication.java
New file
@@ -0,0 +1,190 @@
package art.servers.types;
import art.library.interop.serialization.Serialization;
import art.library.model.devices.Device;
import art.library.model.devices.user.User;
import art.library.utils.licence.Licence;
import art.servers.Shared;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@JsonPropertyOrder
({
    "Username",
    "Password",
    "Address",
    "Creation",
    "Expiration",
    "Inactivity",
    "Profile web"
})
public class HttpAuthentication
{
    @JsonProperty("Username")
    public String username = null;
    @JsonProperty("Password")
    public String password = null;
    @JsonProperty("Address")
    public String address = null;
    @JsonProperty("Creation")
    public long tokenCreationTimestamp = 0;
    @JsonProperty("Expiration")
    public long tokenExpirationTimestamp = 0;
    /**
     * Inactivity to expire in seconds
     */
    @JsonProperty("Inactivity")
    public long inactivity = 300;
    /**
     * For WEB access
     */
    public static final byte PROFILE_NONE = 0;
    public static final byte PROFILE_DOWNLOAD = 1;
    public static final byte PROFILE_READ = 2;
    public static final byte PROFILE_WRITE = 3;
    public static final byte PROFILE_ADMIN = 4;
    @JsonProperty("Profile web")
    public int profileWebServer = HttpAuthentication.PROFILE_NONE;
    /**
     * JsonProperty("Result code")<br>
     * Code representing the result status of login request<br>
     * Possible values are:<br>
     * 0 : Ok<br>
     * 1 : Wrong user/password<br>
     * 2 : First access, password must be changed<br>
     * 3 : Username blocked<br>
     * 4 : Ip address blocked
     */
    @JsonProperty("Result code")
    public int resultCode = 0;
    @JsonProperty("Result message")
    public String resultMessage = null;
    @JsonProperty("User profile")
    public String profile = null;
    @JsonIgnore
    public User user = null;
    @JsonIgnore
    public long lastRequestTimestamp = 0;
    @JsonIgnore
    public String userAgent = null;
    public HttpAuthentication()
    {
    }
    @JsonIgnore
    public HttpAuthentication(String username, String password, String address) throws Exception
    {
        this.username = username;
        this.password = password;
        this.address = address;
        this.tokenCreationTimestamp = System.currentTimeMillis();
        this.tokenExpirationTimestamp = this.tokenCreationTimestamp;
    }
    @JsonIgnore
    public HttpAuthentication(String username, String password, String address, int resultCode, String resultMessage) throws Exception
    {
        this.username = username;
        this.password = password;
        this.address = address;
        this.resultCode = resultCode;
        this.resultMessage = resultMessage;
        this.tokenCreationTimestamp = System.currentTimeMillis();
        this.tokenExpirationTimestamp = this.tokenCreationTimestamp;
    }
    @JsonIgnore
    public HttpAuthentication(String username, String password, String address, String profile) throws Exception
    {
        this.username = username;
        this.password = password;
        this.address = address;
        this.profile = profile;
        this.tokenCreationTimestamp = System.currentTimeMillis();
        this.tokenExpirationTimestamp = this.tokenCreationTimestamp;
    }
    public HttpAuthentication(String username, String password, String address, byte profile) throws Exception
    {
        this.username = username;
        this.password = password;
        this.address = address;
        this.profileWebServer = profile;
        this.tokenExpirationTimestamp = this.tokenCreationTimestamp;
        this.tokenExpirationTimestamp = System.currentTimeMillis();
    }
    @JsonIgnore
    public boolean isTokenValid(String remoteAddress) throws Exception
    {
        if (remoteAddress.equalsIgnoreCase(address) == false) return false;
        if (tokenExpirationTimestamp == tokenCreationTimestamp) return true;
        //TODO, update lastRequestTimestamp
        //if ((lastRequestTimestamp > 0) && (System.currentTimeMillis() - lastRequestTimestamp) > (inactivity * 1000L)) return false;
        return (tokenExpirationTimestamp >= System.currentTimeMillis());
    }
    @JsonIgnore
    public HttpToken getHttpToken() throws Exception
    {
        HttpToken httptoken = new HttpToken();
        if ((this.resultCode == Shared.RESULT_OK) || (this.resultCode == Shared.ERROR_FIRST_ACCESS))
        {
            httptoken.token = URLEncoder.encode(Licence.encrypt(Serialization.toString(this)), StandardCharsets.UTF_8.toString());
        }
        httptoken.profile = this.profile;
        httptoken.resultCode = this.resultCode;
        httptoken.resultMessage = this.resultMessage;
        return httptoken;
    }
    @JsonIgnore
    public void updateExpirationTimestamp()
    {
        // TODO
    }
}
servers/server/src/art/servers/types/HttpStatus.java
New file
@@ -0,0 +1,6 @@
package art.servers.types;
public class HttpStatus
{
}
servers/server/src/art/servers/types/HttpToken.java
New file
@@ -0,0 +1,49 @@
package art.servers.types;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonPropertyOrder
({
    "Token",
    "Profile",
    "Result code",
    "Result message"
})
public class HttpToken
{
    @JsonProperty("Token")
    public String token = null;
    /**
     * JsonProperty("Profile")
     */
    @JsonProperty("Profile")
    public String profile = null;
    /**
     * JsonProperty("Result code")<br>
     * Code representing the result status of login request<br>
     * Possible values are:<br>
     * 0 : Ok<br>
     * 1 : Wrong user/password<br>
     * 2 : First access, password must be changed<br>
     * 3 : Username blocked<br>
     * 4 : Ip address blocked
     */
    @JsonProperty("Result code")
    public int resultCode = 0;
    /**
     * JsonProperty("Result message")
     */
    @JsonProperty("Result message")
    public String resultMessage = null;
}
servers/server/src/art/servers/types/HttpTokenException.java
New file
@@ -0,0 +1,6 @@
package art.servers.types;
public class HttpTokenException extends Exception
{
}
servers/server/src/art/servers/types/IPv4.java
New file
@@ -0,0 +1,47 @@
package art.servers.types;
public class IPv4
{
    public static long toLong(int mask) throws Exception
    {
        long result = 0xFFFFFFFFL;
        for(int i=0; i<(32-mask); i++)
        {
            result = result ^ ((long)1 << i);
        }
        return result;
    }
    public static long toLong(String ipAddress) throws Exception
    {
        if (ipAddress == null || ipAddress.isEmpty()) throw new Exception();
        String[] octets = ipAddress.split(java.util.regex.Pattern.quote("."));
        if (octets.length != 4) throw new Exception();
        long ip = 0;
        for (int i = 3; i >= 0; i--)
        {
            long octet = Long.parseLong(octets[3 - i]);
            if (octet > 255 || octet < 0) throw new Exception();
            ip |= octet << (i * 8);
        }
        return ip;
    }
    public static String toString (long ip) throws Exception
    {
        if (ip > 4294967295l || ip < 0) throw new Exception();
        StringBuilder ipAddress = new StringBuilder();
        for (int i = 3; i >= 0; i--)
        {
            int shift = i * 8;
            ipAddress.append((ip & (0xff << shift)) >> shift);
            if (i > 0)  ipAddress.append(".");
        }
        return ipAddress.toString();
    }
}
servers/server/src/server.version.properties
New file
@@ -0,0 +1,7 @@
#Thu, 24 Oct 2024 11:50:41 +0200
date=24/10/2024
major=1
minor=0
revision=0
build=89