bck
Alejandro Acuña
2024-11-11 f1cb4443aede6d4657bdc3396c8914d3a9f4fa93
bck
1 files deleted
22 files modified
1336 ■■■■■ changed files
libraries/server/data/art.library.server/icons/24x24/Thumbs.db patch | view | raw | blame | history
libraries/server/nbproject/build-impl.xml 5 ●●●●● patch | view | raw | blame | history
libraries/server/nbproject/genfiles.properties 4 ●●●● patch | view | raw | blame | history
libraries/server/nbproject/project.properties 3 ●●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/Model.java 317 ●●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/Server.java 87 ●●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/Shared.java 32 ●●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/configuration/ConfigurationListener.java 3 ●●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/controller/Controller.java 13 ●●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/controller/ControllerListener.java 87 ●●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/controller/ControllerListenerDebug.java 164 ●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/controller/ControllerListenerHttp.java 10 ●●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/controller/ControllerListenerHttpsWeb.java 3 ●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/controller/ControllerProcessInformation.java 27 ●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/controller/ControllerStatus.java 2 ●●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/controller/FactoryController.java 2 ●●● patch | view | raw | blame | history
libraries/server/src/art/servers/controller/ListenerImplementation.java 74 ●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/gui/components/PanelProcess.java 2 ●●● patch | view | raw | blame | history
libraries/server/src/art/servers/gui/components/PanelProcess_Information.java 41 ●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/gui/components/PanelTraces.java 2 ●●●●● patch | view | raw | blame | history
libraries/server/src/art/servers/gui/components/PanelTracesHistorical.java 1 ●●●● patch | view | raw | blame | history
libraries/server/src/server.version.properties 6 ●●●● patch | view | raw | blame | history
servers/cameraserver_coruña/art.servers.cameraserver.cameras.json 451 ●●●●● patch | view | raw | blame | history
libraries/server/data/art.library.server/icons/24x24/Thumbs.db
Binary files differ
libraries/server/nbproject/build-impl.xml
@@ -46,8 +46,8 @@
        <property file="${user.properties.file}"/>
        <!-- The two properties below are usually overridden -->
        <!-- by the active platform. Just a fallback. -->
        <property name="default.javac.source" value="1.6"/>
        <property name="default.javac.target" value="1.6"/>
        <property name="default.javac.source" value="1.8"/>
        <property name="default.javac.target" value="1.8"/>
    </target>
    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
        <property file="nbproject/configs/${config}.properties"/>
@@ -1686,6 +1686,7 @@
    </target>
    <target depends="init,compile-test-single,-init-test-run-module-properties,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
    <target depends="init,compile-test-single,-init-test-run-module-properties,-debug-start-debugger-test,-debug-start-debuggee-test-method" name="debug-test-method"/>
    <target depends="debug-test-method" name="debug-single-method"/>
    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
    </target>
libraries/server/nbproject/genfiles.properties
@@ -4,5 +4,5 @@
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=f4081494
nbproject/build-impl.xml.script.CRC32=1dfb4f50
nbproject/build-impl.xml.stylesheet.CRC32=f89f7d21@1.95.0.48
nbproject/build-impl.xml.script.CRC32=007078dc
nbproject/build-impl.xml.stylesheet.CRC32=12e0a6c2@1.105.0.48
libraries/server/nbproject/project.properties
@@ -20,6 +20,9 @@
javac.processormodulepath=
javac.test.modulepath=\
    ${javac.modulepath}
javadoc.html5=false
jlink.launcher=false
jlink.launcher.name=server
main.class=Server
run.classpath=\
    ${javac.classpath}:\
libraries/server/src/art/servers/Model.java
@@ -1,5 +1,6 @@
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;
@@ -10,6 +11,8 @@
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;
@@ -19,6 +22,8 @@
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;
@@ -150,7 +155,11 @@
        }
        catch (Exception exception)
        {   
            Shared.println(Shared.getMessage("Model"), 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);
        }
@@ -181,7 +190,10 @@
        catch (Exception exception)
        {
            exception.printStackTrace();
            Shared.println(Shared.getMessage("Model"), exception);
            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);
        }       
        
        
@@ -463,6 +475,30 @@
    
        
    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();
@@ -938,8 +974,10 @@
            }
            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));
@@ -1062,6 +1100,61 @@
    
    
    
    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();
@@ -1124,9 +1217,6 @@
    }    
    
    
    public Device cloneDevice(String identifier)
    {
        // No hace falta mutex porque los devices se cambia la referencia cada vez. No hay conflicto posible
@@ -1279,6 +1369,158 @@
    
    
    
    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
    {
@@ -1366,6 +1608,60 @@
    // </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
@@ -1374,7 +1670,8 @@
                
        try
        {
            for (int i=0; i<32; i++)
            // for (int i=0; i<32; i++)
            for (float i=0; i<32; i+=0.5f)
            {
                for (String symbolName : Shared.configuration.symbols)
                {
@@ -1382,8 +1679,14 @@
                    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)
libraries/server/src/art/servers/Server.java
@@ -23,10 +23,14 @@
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;
@@ -50,7 +54,6 @@
            
    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");
@@ -118,31 +121,31 @@
        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)
//            {
//                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();
//            }
//        }
        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
@@ -155,6 +158,8 @@
                parameters.password = Licence.decrypt(parameters.password);
            }
        }
        // Application device, status
        Application application = new Application(Shared.configuration.application);
@@ -199,6 +204,7 @@
                    }
                    else
                    {
                        System.out.println(Shared.getMessage("Process %1 already opened").replace("%1", Shared.configuration.general.executableName));
                    }
                    System.exit(0);
@@ -233,6 +239,7 @@
            Shared.lcontroller.add(Shared.controllerTransactions);
        }
        
        // Controller NTP HTTP
        
        if (Shared.configuration.controllerNTPHTTP != null)
@@ -241,20 +248,25 @@
            Shared.lcontroller.add(Shared.controllerNtpHttp);
        }
    }public static void postinitialise(String[] args) throws Exception
    }
    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));
//        }
        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
@@ -319,6 +331,7 @@
        
        // 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");
@@ -388,6 +401,7 @@
            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)
@@ -397,6 +411,7 @@
                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)
libraries/server/src/art/servers/Shared.java
@@ -109,6 +109,7 @@
    public static String getMessage(String language, String identifier)
    {
        if (configuration == null) return identifier;
        return configuration.getMessage(language, identifier);
    }
    
@@ -154,7 +155,14 @@
    
    public static String getMessage(String identifier)
    {
        return configuration != null ? configuration.getMessage(identifier) : identifier;
        try
        {
            return configuration.getMessage(identifier);
        }
        catch (Exception e)
        {
            return(identifier);
        }
    }
    
@@ -513,6 +521,18 @@
        
    
    
    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
@@ -631,6 +651,16 @@
    }    
            
        
    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"));
libraries/server/src/art/servers/configuration/ConfigurationListener.java
@@ -25,5 +25,8 @@
    @JsonProperty("Connections")
    public int connections;
    @JsonProperty("Timeout connection")
    public int timeoutConnection = 0;
    
}
libraries/server/src/art/servers/controller/Controller.java
@@ -10,6 +10,19 @@
        exit = true;
    }
    
    public void pause(long timemillis)
    {
        try
        {
            sleep(timemillis);
        }
        catch (Exception exception)
        {
        }
    }
}
libraries/server/src/art/servers/controller/ControllerListener.java
@@ -13,6 +13,7 @@
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
@@ -24,6 +25,9 @@
    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)
    {
@@ -52,6 +56,7 @@
    {
        Shared.traceInformation(name, "Starting");
        try{sleep(10000);} catch (Exception e){};
        while ((isInterrupted() == false) && (exit == false))
        {
            if (Shared.isServerEnabled() == true)
@@ -65,6 +70,27 @@
                    
                    try
                    {
                        boolean connect = true;
                        try
                        {
                            if (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);
@@ -77,6 +103,7 @@
                            socket.close();
                        }
                    }
                    }
                    finally
                    {
                        mutex.releaseWrite();
@@ -85,6 +112,14 @@
                catch (Exception e)
                {
                    disconnect();
                    try
                    {
                        sleep(100);
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }
            else
@@ -181,7 +216,7 @@
            this.address = socket.getInetAddress().getHostAddress();
            this.name = this.address + ":" + socket.getPort();
            this.socket = socket;
            this.socket.setSoTimeout(0);
            this.socket.setSoTimeout(configuration.timeoutConnection);
            this.setName("Connection " + name);
        }
        
@@ -196,7 +231,12 @@
                while ((isInterrupted() == false) && (exit == false))
                {
                    listen(dis, dos);
                    if (hblocked.containsKey(socket.getInetAddress().getHostAddress()) == true)
                    {
                        throw new Exception("BLOCKED");
                    }
                    listen(this.address, dis, dos);
                }
            }
            catch (Exception e)
@@ -244,10 +284,52 @@
    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);     
    }
@@ -337,7 +419,6 @@
        }
        catch (Exception e)
        {
            e.printStackTrace();
            throw new SerializationException(e.getMessage());
        }
    }    
libraries/server/src/art/servers/controller/ControllerListenerDebug.java
@@ -1,11 +1,13 @@
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;
@@ -15,23 +17,43 @@
public class ControllerListenerDebug extends Thread
{
    public static final int TYPE_INFORMATION = 1;
    public static final int TYPE_WARNING = 2;
    public static final int TYPE_ERROR = 3;
    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> lconnection = new ArrayList<DebugConnection>();
    private List<DebugConnection> connections = new ArrayList<DebugConnection>();
    private ConfigurationListenerDEBUG configuration = null;
    
    
    public ControllerListenerDebug(ConfigurationListenerDEBUG configuration)
    {
        this.configuration = configuration;
        this.name = Shared.getMessage("Listener DEBUG");
        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();
    }
    
    
@@ -42,7 +64,7 @@
        
        try
        {
            for (DebugConnection connection : lconnection)
            for (DebugConnection connection : connections)
            {
                connection.addMessage(object);
            }
@@ -63,9 +85,9 @@
                {
                    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);
                    Shared.controllerDatabase.getHistoricalPersistance().get(0).addObject_asynchronous(tracePersistance);
                }
                catch (Exception exception)
                {
@@ -73,17 +95,11 @@
            }
        }        
        
        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss.SSS"));
        System.out.println(formato1.format(System.currentTimeMillis()) + " : " + object);
        if (Shared.window != null) Shared.window.addTrace(object);
    }
    
    public void run()
    {
        Shared.traceInformation(name, "Starting");
@@ -119,6 +135,7 @@
    
    
    private void connection(Socket clientSocket)
    {
        try
@@ -126,7 +143,7 @@
            
            if (configuration.allowed(clientSocket.getLocalAddress().getHostAddress()))
            {
                if (lconnection.size() < configuration.maximumConnections)
                if (connections.size() < configuration.maximumConnections)
                {
                    DebugConnection connection = new DebugConnection(clientSocket);
                    addConnection(connection);
@@ -134,7 +151,7 @@
                    return;
                }
                
                Shared.traceError(name, "Connecting", Shared.getMessage("Connection rejected due too many connections"), null);
                Shared.traceError(name, "Connecting", Shared.getMessage("Connection rejected due too many connections"), "");
            }
            else
            {
@@ -158,16 +175,13 @@
    
    
    
    private void addConnection(DebugConnection connection) throws Exception
    {
        mutexConnection.lockWrite();
        
        try
        {
            lconnection.add(connection);
            connections.add(connection);
        }
        catch (Exception e)
        {
@@ -179,15 +193,13 @@
    
    
    private void removeConnection(DebugConnection connection)
    {
        mutexConnection.lockWrite();
        
        try
        {
            lconnection.remove(connection);
            connections.remove(connection);
        }
        catch (Exception e)
        {
@@ -204,15 +216,23 @@
    private class DebugConnection extends Thread
    {
        private Socket socket = null;
        public List<Object> ltrace = new ArrayList<Object>();
        private PrintStream output = null;
        public List<Object> messages = new ArrayList<Object>();
        public Mutex mutex = new Mutex();
        
        public DebugConnection(Socket socket)
        public DebugConnection(Socket socket) throws Exception
        {
            this.socket = socket;
            String address = socket.getInetAddress().getHostAddress();
            String name = address + ":" + socket.getPort();
            this.setName("DebugConnection " + name);
            this.setName("Logger connection " + name);
            this.output = new PrintStream(socket.getOutputStream());
        }
        public DebugConnection(PrintStream output)
        {
            this.setName("Logger screen");
            this.output = output;
        }
        
        
@@ -220,7 +240,7 @@
        {   
            mutex.lockWrite();
            {
               ltrace.add(object);
               messages.add(object);
            }
            mutex.releaseWrite();
        }
@@ -233,16 +253,16 @@
            {
                while (isInterrupted() == false)
                {
                    if (ltrace.size() > 0)
                    if (messages.size() > 0)
                    {
                        String message = ltrace.get(0).toString() + "\r\n";
                        Object object = messages.get(0);
                        
                        if (message != null)
                        if (object != null)
                        {
                            socket.getOutputStream().write(message.getBytes());
                            print(object);
                        }
                        
                        ltrace.remove(0);
                        messages.remove(0);
                    }
                    else
                    {
@@ -259,6 +279,84 @@
        
        
        
        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) {}
@@ -268,4 +366,8 @@
    }
    
    
}
libraries/server/src/art/servers/controller/ControllerListenerHttp.java
@@ -162,6 +162,7 @@
            }
            catch (Exception e)
            {
                e.printStackTrace();
                result(httpExchange, 400, language, e);
            }
        }
@@ -188,6 +189,7 @@
            }
            catch (Exception e)
            {
                e.printStackTrace();
                result(httpExchange, 400, language, e);
            }
        }
@@ -221,6 +223,7 @@
            catch (Exception exception)
            {
                Shared.println(Shared.getMessage("Model"), exception);
                exception.printStackTrace();
                result(httpExchange, 400, language, exception);
            }
        }
@@ -241,6 +244,7 @@
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
                result(httpExchange, 400, "", exception);
            }
        }
@@ -262,6 +266,7 @@
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
                result(httpExchange, 400, "", exception);
            }
        }
@@ -334,6 +339,7 @@
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
                result(httpExchange, 400, language, exception);
            }
        }
@@ -358,6 +364,7 @@
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
                result(httpExchange, 400, language, exception);
            }
        }
@@ -390,6 +397,7 @@
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
                result(httpExchange, 400, language, exception);
            }
        }
@@ -470,6 +478,7 @@
        try
        {
            httpExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
            httpExchange.getResponseHeaders().set("Accept", "*/*");
            httpExchange.sendResponseHeaders(httpErrorCode, data.length);
            httpExchange.getResponseBody().write(data);
        }
@@ -493,6 +502,7 @@
        // 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")) 
        {
libraries/server/src/art/servers/controller/ControllerListenerHttpsWeb.java
@@ -97,8 +97,9 @@
            return;
            
        }
        catch (Exception e)
        catch (Exception exception)
        {
            exception.printStackTrace();
        }        
    }
    
libraries/server/src/art/servers/controller/ControllerProcessInformation.java
@@ -169,6 +169,8 @@
            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)
        {
@@ -185,27 +187,6 @@
            ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
            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.threadCpuTime = threadCpuTime;
            status.thread.threadUserTime = threadUserTime;
            status.thread.totalStartedThreadCount = threadMXBean.getTotalStartedThreadCount();
            status.thread.threadCount = threadMXBean.getThreadCount();
            status.thread.peakThreadCount = threadMXBean.getPeakThreadCount();
@@ -259,11 +240,11 @@
            status.system.freePhysicalMemorySize = operatingSystemMXBean.getFreePhysicalMemorySize();
            status.system.freeSwapSpaceSize = operatingSystemMXBean.getFreeSwapSpaceSize();
            status.system.processCpuLoad = operatingSystemMXBean.getProcessCpuLoad();
            status.system.processCpuTime = operatingSystemMXBean.getProcessCpuTime();
            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();
            status.system.systemLoadAverage = operatingSystemMXBean.getSystemLoadAverage() / operatingSystemMXBean.getAvailableProcessors();
            status.system.availableProcessors = operatingSystemMXBean.getAvailableProcessors();
            status.system.totalPhysicalMemorySize = operatingSystemMXBean.getTotalPhysicalMemorySize();
            status.system.systemLoadAverage = this.processorPercentage;
libraries/server/src/art/servers/controller/ControllerStatus.java
@@ -226,8 +226,6 @@
                }
            }
            
            status.thread.threadCpuTime = threadCpuTime;
            status.thread.threadUserTime = threadUserTime;
            status.thread.totalStartedThreadCount = threadMXBean.getTotalStartedThreadCount();
            status.thread.threadCount = threadMXBean.getThreadCount();
            status.thread.peakThreadCount = threadMXBean.getPeakThreadCount();
libraries/server/src/art/servers/controller/FactoryController.java
@@ -8,7 +8,7 @@
public class FactoryController extends Thread
{
    private HashMap<ControllerDevice, Long> timestamps = new HashMap<ControllerDevice, Long>();
    public HashMap<ControllerDevice, Long> timestamps = new HashMap<ControllerDevice, Long>();
            
            
    public FactoryController()
libraries/server/src/art/servers/controller/ListenerImplementation.java
@@ -11,7 +11,6 @@
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.UserStatus;
import art.library.model.devices.user.configuration.ConfigurationLockLogin;
import art.library.model.general.ModelFile;
import art.library.model.transactions.traces.Trace;
@@ -38,6 +37,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;
import java.util.stream.Stream;
public class ListenerImplementation 
@@ -156,6 +156,8 @@
        User user = null;
        // TODO: esto cada vez es muy ineficiente, revisar.......
        try
        {
            user = (User)Shared.model.getDeviceExternal(Licence.encrypt(username));
@@ -177,6 +179,9 @@
            }
        }
        // TODO : volver a poner
/*
        if (user.getDeviceInformation().password.equals(Licence.encrypt(password)) == false)
        {
            // Check blocked users
@@ -243,6 +248,7 @@
        status.unlockTimestamp = -1;
        status.lastLogin = System.currentTimeMillis();
        Shared.model.updateDevice(user, newuser);
*/
        HttpAuthentication authentication = new HttpAuthentication(username, password, address, user.getDeviceInformation().group);
        return authentication;
@@ -392,7 +398,6 @@
        }
        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()); 
@@ -516,11 +521,22 @@
        {
            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"));
                return new InteropResponse(Shared.model.getDevices(identifier, timestamp));
                Device[] devices = checkDevices(user, Shared.model.getDevices(identifier, timestamp));
                return new InteropResponse(devices);
            }
            else if (parameters.hasParameter("groups"))
            {
@@ -666,6 +682,7 @@
            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));
        }
@@ -690,14 +707,22 @@
        
        try
        {
            System.out.println("1.AddDevices: " + Shared.model.deviceClassName);
            Class clazzDevice = Class.forName(Shared.model.deviceClassName);
            bodyContent = (String)parameters.getParameterValue("body-content");
            System.out.println("2.AddDevices: " + clazzDevice);
            // bodyContent = (String)parameters.getParameterValue("body-content");
            Class<?> clazzArray = (Class<?>)Array.newInstance(clazzDevice, 0).getClass();
            Device[] ldevice = (Device[])Serialization.deserialize(clazzArray, bodyContent);
            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));
                }
@@ -705,6 +730,7 @@
        }
        catch (ClassCastException exception)
        {
            exception.printStackTrace();
        }
        catch (Exception exception)
        {
@@ -788,6 +814,7 @@
            }
            
            Shared.model.deleteDevices(lidentifier);
            return new InteropResponse(new Boolean(true));
        }
        catch (ServerException exception)
@@ -836,7 +863,8 @@
        {
            List<DeviceRealtime> lrealtime = new ArrayList<DeviceRealtime>();
            for (Device device : Shared.model.getDevices())
            Device[] ldevice = art.servers.Shared.model.getDevicesCopy();
            for (Device device : ldevice)
            {
                DeviceRealtime realtime = device.getDeviceRealtime();
                
@@ -845,13 +873,12 @@
                    if (realtime.lastTimestampUpdate > timestamp) 
                    {
                        realtime.identifier = device.getIdentifier();
                        lrealtime.add(device.getDeviceRealtime());
                        lrealtime.add(realtime);
                    }
                }
            }
            return new InteropResponse(lrealtime.toArray(new DeviceRealtime[lrealtime.size()]));
        }
        catch (Exception e)
        {
@@ -1653,6 +1680,30 @@
   // </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)
@@ -1664,7 +1715,7 @@
    
    
    
    private static String[] getStringArray(InteropParameter parameter)
    protected static String[] getStringArray(InteropParameter parameter)
    {
        if (parameter.getValue() instanceof String[])
        {
@@ -1710,6 +1761,11 @@
            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();
libraries/server/src/art/servers/gui/components/PanelProcess.java
@@ -56,7 +56,7 @@
        if (panelProcess_Memory != null) 
        {
            long totalPhysicalMemory = status.memory.heapMemoryUsage_max / 1048576;
            long usedMemory = (status.memory.heapMemoryUsage_committed +  status.memory.nonheapMemoryUsage_used - totalPhysicalMemory) / 1048576;
            long usedMemory = status.memory.usedMemory / 1048576L;
            panelProcess_Memory.reload(totalPhysicalMemory, usedMemory);
        }
    }
libraries/server/src/art/servers/gui/components/PanelProcess_Information.java
@@ -62,22 +62,21 @@
        table2.setValue(Shared.getMessage("Language"), status.runtime.userLanguage);
        
        table3.setValue(Shared.getMessage("Timestamp"), formato1.format(status.memory.timestamp));
        table3.setValue(Shared.getMessage("Heap memory usage init"), formato2.format(status.memory.heapMemoryUsage_init/1024L));
        table3.setValue(Shared.getMessage("Heap memory usage used"), formato2.format(status.memory.heapMemoryUsage_used/1024L));
        table3.setValue(Shared.getMessage("Heap memory usage commited"), formato2.format(status.memory.heapMemoryUsage_committed/1024L));
        table3.setValue(Shared.getMessage("Heap memory usage max"), formato2.format(status.memory.heapMemoryUsage_max/1024L));
        table3.setValue(Shared.getMessage("Non heap memory usage init"), formato2.format(status.memory.nonheapMemoryUsage_init/1024L));
        table3.setValue(Shared.getMessage("Non heap memory usage used"), formato2.format(status.memory.nonheapMemoryUsage_used/1024L));
        table3.setValue(Shared.getMessage("Non heap memory usage commited"), formato2.format(status.memory.nonheapMemoryUsage_committed/1024L));
        table3.setValue(Shared.getMessage("Non heap memory usage max"), formato2.format(status.memory.nonheapMemoryUsage_max/1024L));
        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));
        table4.setValue(Shared.getMessage("Thread cpu timer"), DateUtils.getTimeddHHMMSS(status.thread.threadCpuTime/1000000L));  // threadCpuTime nanoseconds, getTimeddHHMMSS millis
        table4.setValue(Shared.getMessage("Thread user time"), DateUtils.getTimeddHHMMSS(status.thread.threadUserTime/1000000L));  // threadUserTime nanoseconds, getTimeddHHMMSS millis
    }
@@ -151,7 +150,8 @@
                        table2.addTextField(Shared.getMessage("Country"), 22);
                        table2.addTextField(Shared.getMessage("Language"), 22);
                        
                        table2.setMeasurementUnits(Shared.getMessage("Process cpu time"), Shared.getMessage("seconds"), 100, SwingConstants.CENTER);
                        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);
                        
@@ -170,6 +170,7 @@
                    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);
@@ -179,14 +180,14 @@
                        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("KB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Heap memory usage used"), Shared.getMessage("KB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Heap memory usage commited"), Shared.getMessage("KB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Heap memory usage max"), Shared.getMessage("KB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Non heap memory usage init"), Shared.getMessage("KB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Non heap memory usage used"), Shared.getMessage("KB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Non heap memory usage commited"), Shared.getMessage("KB"), 100, SwingConstants.CENTER);
                        table3.setMeasurementUnits(Shared.getMessage("Non heap memory usage max"), Shared.getMessage("KB"), 100, SwingConstants.CENTER);
                        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();
@@ -208,8 +209,6 @@
                        table4.addTextField(Shared.getMessage("Thread count"), 22);
                        table4.addTextField(Shared.getMessage("Peak thread count"), 22);
                        table4.addTextField(Shared.getMessage("Daemon thread count"), 22);
                        table4.addTextField(Shared.getMessage("Thread cpu timer"), 22);
                        table4.addTextField(Shared.getMessage("Thread user time"), 22);
                        table4.setEditable(false);
                        table4.revalidate();
                    }
libraries/server/src/art/servers/gui/components/PanelTraces.java
@@ -253,6 +253,7 @@
                        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";
@@ -278,6 +279,7 @@
                        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;
libraries/server/src/art/servers/gui/components/PanelTracesHistorical.java
@@ -197,6 +197,7 @@
                    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";
libraries/server/src/server.version.properties
@@ -1,7 +1,7 @@
#Thu, 30 Nov 2023 10:36:40 +0100
#Mon, 24 Jun 2024 18:08:28 +0200
date=30/11/2023
date=24/06/2024
major=1
minor=0
revision=0
build=8
build=74
servers/cameraserver_coruña/art.servers.cameraserver.cameras.json
@@ -10999,456 +10999,5 @@
            "Default snapshot": 1,
            "Polling": 15
        }
    },
    {
        "Camera information": {
            "Identifier": "cctv-corunya-276",
            "Creation date": "1970-01-01T00:00:00.000Z",
            "Server port": 0,
            "Server port external": 0,
            "Number": 276,
            "Group": "A CORUÑA",
            "Name": "CyD.- Calle Alfredo Vicenti 02",
            "Location": "",
            "Direction": "",
            "Municipality": "A CORUÑA",
            "Description": "Calle Alfredo Vicenti",
            "Kilometric point": "",
            "Latitude": 43.35790740543055,
            "Longitude": -8.399858499089948,
            "Latitude offset": 0.0,
            "Longitude offset": 0.0,
            "Owner": "",
            "Maintainer": "",
            "Symbol": "Dome camera",
            "Alarms": [],
            "Manufacturer": "HIKVISION",
            "Model": "DS-2DE7A232IW-AEB",
            "Protocol": "ONVIF",
            "North degrees": 0.0,
            "Connection": {
                "Address": "172.17.26.134",
                "Default multicast": true,
                "HTTP port": 80,
                "Network caching": 50,
                "ONVIF port": 80,
                "Password": "Administrador",
                "RTSP port": 554,
                "User": "admin"
            },
            "Snapshot": [],
            "Default snapshot": 1,
            "Polling": 15
        }
    },
    {
        "Camera information": {
            "Identifier": "cctv-corunya-277",
            "Creation date": "1970-01-01T00:00:00.000Z",
            "Server port": 0,
            "Server port external": 0,
            "Number": 277,
            "Group": "A CORUÑA",
            "Name": "CyD.- Mercado de Elviña 01",
            "Location": "",
            "Direction": "",
            "Municipality": "A CORUÑA",
            "Description": "Mercado de Elviña",
            "Kilometric point": "",
            "Latitude": 43.35790740543055,
            "Longitude": -8.399858499089948,
            "Latitude offset": 0.0,
            "Longitude offset": 0.0,
            "Owner": "",
            "Maintainer": "",
            "Symbol": "Dome camera",
            "Alarms": [],
            "Manufacturer": "HIKVISION",
            "Model": "DS-2DE7A232IW-AEB",
            "Protocol": "ONVIF",
            "North degrees": 0.0,
            "Connection": {
                "Address": "172.17.117.44",
                "Default multicast": true,
                "HTTP port": 80,
                "Network caching": 50,
                "ONVIF port": 80,
                "Password": "Administrador",
                "RTSP port": 554,
                "User": "admin"
            },
            "Snapshot": [],
            "Default snapshot": 1,
            "Polling": 15
        }
    },
    {
        "Camera information": {
            "Identifier": "cctv-corunya-278",
            "Creation date": "1970-01-01T00:00:00.000Z",
            "Server port": 0,
            "Server port external": 0,
            "Number": 278,
            "Group": "A CORUÑA",
            "Name": "CyD.- Mercado de Elviña 02",
            "Location": "",
            "Direction": "",
            "Municipality": "A CORUÑA",
            "Description": "Mercado de Elviña",
            "Kilometric point": "",
            "Latitude": 43.35790740543055,
            "Longitude": -8.399858499089948,
            "Latitude offset": 0.0,
            "Longitude offset": 0.0,
            "Owner": "",
            "Maintainer": "",
            "Symbol": "Dome camera",
            "Alarms": [],
            "Manufacturer": "HIKVISION",
            "Model": "DS-2DE7A232IW-AEB",
            "Protocol": "ONVIF",
            "North degrees": 0.0,
            "Connection": {
                "Address": "172.17.117.41",
                "Default multicast": true,
                "HTTP port": 80,
                "Network caching": 50,
                "ONVIF port": 80,
                "Password": "Administrador",
                "RTSP port": 554,
                "User": "admin"
            },
            "Snapshot": [],
            "Default snapshot": 1,
            "Polling": 15
        }
    },
    {
        "Camera information": {
            "Identifier": "cctv-corunya-279",
            "Creation date": "1970-01-01T00:00:00.000Z",
            "Server port": 0,
            "Server port external": 0,
            "Number": 279,
            "Group": "A CORUÑA",
            "Name": "CyD.- Mercado de Elviña 03",
            "Location": "",
            "Direction": "",
            "Municipality": "A CORUÑA",
            "Description": "Mercado de Elviña",
            "Kilometric point": "",
            "Latitude": 43.35790740543055,
            "Longitude": -8.399858499089948,
            "Latitude offset": 0.0,
            "Longitude offset": 0.0,
            "Owner": "",
            "Maintainer": "",
            "Symbol": "Dome camera",
            "Alarms": [],
            "Manufacturer": "HIKVISION",
            "Model": "DS-2DE7A232IW-AEB",
            "Protocol": "ONVIF",
            "North degrees": 0.0,
            "Connection": {
                "Address": "172.17.117.38",
                "Default multicast": true,
                "HTTP port": 80,
                "Network caching": 50,
                "ONVIF port": 80,
                "Password": "Administrador",
                "RTSP port": 554,
                "User": "admin"
            },
            "Snapshot": [],
            "Default snapshot": 1,
            "Polling": 15
        }
    },
    {
        "Camera information": {
            "Identifier": "cctv-corunya-280",
            "Creation date": "1970-01-01T00:00:00.000Z",
            "Server port": 0,
            "Server port external": 0,
            "Number": 280,
            "Group": "A CORUÑA",
            "Name": "CyD.- Plaza de Vigo-01",
            "Location": "",
            "Direction": "",
            "Municipality": "A CORUÑA",
            "Description": "Plaza de Vigo",
            "Kilometric point": "",
            "Latitude": 43.35790740543055,
            "Longitude": -8.399858499089948,
            "Latitude offset": 0.0,
            "Longitude offset": 0.0,
            "Owner": "",
            "Maintainer": "",
            "Symbol": "Fixed camera",
            "Alarms": [],
            "Manufacturer": "DAHUA",
            "Model": "DH-IPC-HFW5241EP-Z12E",
            "Protocol": "ONVIF",
            "North degrees": 0.0,
            "Connection": {
                "Address": "172.17.105.20",
                "Default multicast": true,
                "HTTP port": 80,
                "Network caching": 50,
                "ONVIF port": 80,
                "Password": "Administrador",
                "RTSP port": 554,
                "User": "admin"
            },
            "Snapshot": [],
            "Default snapshot": 1,
            "Polling": 15
        }
    },
    {
        "Camera information": {
            "Identifier": "cctv-corunya-281",
            "Creation date": "1970-01-01T00:00:00.000Z",
            "Server port": 0,
            "Server port external": 0,
            "Number": 281,
            "Group": "A CORUÑA",
            "Name": "CyD.- Alfredo Vicenti Fija 01",
            "Location": "",
            "Direction": "",
            "Municipality": "A CORUÑA",
            "Description": "Plaza de Vigo",
            "Kilometric point": "",
            "Latitude": 43.35790740543055,
            "Longitude": -8.399858499089948,
            "Latitude offset": 0.0,
            "Longitude offset": 0.0,
            "Owner": "",
            "Maintainer": "",
            "Symbol": "Fixed camera",
            "Alarms": [],
            "Manufacturer": "DAHUA",
            "Model": "DH-IPC-HFW5241EP-Z12E",
            "Protocol": "ONVIF",
            "North degrees": 0.0,
            "Connection": {
                "Address": "172.17.26.135",
                "Default multicast": true,
                "HTTP port": 80,
                "Network caching": 50,
                "ONVIF port": 80,
                "Password": "Administrador",
                "RTSP port": 554,
                "User": "admin"
            },
            "Snapshot": [],
            "Default snapshot": 1,
            "Polling": 15
        }
    },
    {
        "Camera information": {
            "Identifier": "cctv-corunya-282",
            "Creation date": "1970-01-01T00:00:00.000Z",
            "Server port": 0,
            "Server port external": 0,
            "Number": 282,
            "Group": "A CORUÑA",
            "Name": "CyD.- Alfredo Vicenti Fija 02",
            "Location": "",
            "Direction": "",
            "Municipality": "A CORUÑA",
            "Description": "Plaza de Vigo",
            "Kilometric point": "",
            "Latitude": 43.35790740543055,
            "Longitude": -8.399858499089948,
            "Latitude offset": 0.0,
            "Longitude offset": 0.0,
            "Owner": "",
            "Maintainer": "",
            "Symbol": "Fixed camera",
            "Alarms": [],
            "Manufacturer": "DAHUA",
            "Model": "DH-IPC-HFW5241EP-Z12E",
            "Protocol": "ONVIF",
            "North degrees": 0.0,
            "Connection": {
                "Address": "172.17.26.137",
                "Default multicast": true,
                "HTTP port": 80,
                "Network caching": 50,
                "ONVIF port": 80,
                "Password": "Administrador",
                "RTSP port": 554,
                "User": "admin"
            },
            "Snapshot": [],
            "Default snapshot": 1,
            "Polling": 15
        }
    },
    {
        "Camera information": {
            "Identifier": "cctv-corunya-283",
            "Creation date": "1970-01-01T00:00:00.000Z",
            "Server port": 0,
            "Server port external": 0,
            "Number": 283,
            "Group": "A CORUÑA",
            "Name": "CyD.- Mercado de Elviña Fija 01",
            "Location": "",
            "Direction": "",
            "Municipality": "A CORUÑA",
            "Description": "Mercado de Elviña",
            "Kilometric point": "",
            "Latitude": 43.35790740543055,
            "Longitude": -8.399858499089948,
            "Latitude offset": 0.0,
            "Longitude offset": 0.0,
            "Owner": "",
            "Maintainer": "",
            "Symbol": "Fixed camera",
            "Alarms": [],
            "Manufacturer": "DAHUA",
            "Model": "DH-IPC-HFW5241EP-Z12E",
            "Protocol": "ONVIF",
            "North degrees": 0.0,
            "Connection": {
                "Address": "172.17.117.43",
                "Default multicast": true,
                "HTTP port": 80,
                "Network caching": 50,
                "ONVIF port": 80,
                "Password": "Administrador",
                "RTSP port": 554,
                "User": "admin"
            },
            "Snapshot": [],
            "Default snapshot": 1,
            "Polling": 15
        }
    },
    {
        "Camera information": {
            "Identifier": "cctv-corunya-284",
            "Creation date": "1970-01-01T00:00:00.000Z",
            "Server port": 0,
            "Server port external": 0,
            "Number": 284,
            "Group": "A CORUÑA",
            "Name": "CyD.- Mercado de Elviña Fija 02",
            "Location": "",
            "Direction": "",
            "Municipality": "A CORUÑA",
            "Description": "Mercado de Elviña",
            "Kilometric point": "",
            "Latitude": 43.35790740543055,
            "Longitude": -8.399858499089948,
            "Latitude offset": 0.0,
            "Longitude offset": 0.0,
            "Owner": "",
            "Maintainer": "",
            "Symbol": "Fixed camera",
            "Alarms": [],
            "Manufacturer": "DAHUA",
            "Model": "DH-IPC-HFW5241EP-Z12E",
            "Protocol": "ONVIF",
            "North degrees": 0.0,
            "Connection": {
                "Address": "172.17.117.40",
                "Default multicast": true,
                "HTTP port": 80,
                "Network caching": 50,
                "ONVIF port": 80,
                "Password": "Administrador",
                "RTSP port": 554,
                "User": "admin"
            },
            "Snapshot": [],
            "Default snapshot": 1,
            "Polling": 15
        }
    },
    {
        "Camera information": {
            "Identifier": "cctv-corunya-285",
            "Creation date": "1970-01-01T00:00:00.000Z",
            "Server port": 0,
            "Server port external": 0,
            "Number": 285,
            "Group": "A CORUÑA",
            "Name": "CyD.- Mercado de Elviña Fija 03",
            "Location": "",
            "Direction": "",
            "Municipality": "A CORUÑA",
            "Description": "Mercado de Elviña",
            "Kilometric point": "",
            "Latitude": 43.35790740543055,
            "Longitude": -8.399858499089948,
            "Latitude offset": 0.0,
            "Longitude offset": 0.0,
            "Owner": "",
            "Maintainer": "",
            "Symbol": "Fixed camera",
            "Alarms": [],
            "Manufacturer": "DAHUA",
            "Model": "DH-IPC-HFW5241EP-Z12E",
            "Protocol": "ONVIF",
            "North degrees": 0.0,
            "Connection": {
                "Address": "172.17.117.37",
                "Default multicast": true,
                "HTTP port": 80,
                "Network caching": 50,
                "ONVIF port": 80,
                "Password": "Administrador",
                "RTSP port": 554,
                "User": "admin"
            },
            "Snapshot": [],
            "Default snapshot": 1,
            "Polling": 15
        }
    },
    {
        "Camera information": {
            "Identifier": "cctv-corunya-286",
            "Creation date": "1970-01-01T00:00:00.000Z",
            "Server port": 0,
            "Server port external": 0,
            "Number": 286,
            "Group": "A CORUÑA",
            "Name": "CyD.- Mercado de Elviña Fija 03",
            "Location": "",
            "Direction": "",
            "Municipality": "A CORUÑA",
            "Description": "Mercado de Elviña",
            "Kilometric point": "",
            "Latitude": 43.35790740543055,
            "Longitude": -8.399858499089948,
            "Latitude offset": 0.0,
            "Longitude offset": 0.0,
            "Owner": "",
            "Maintainer": "",
            "Symbol": "Fixed camera",
            "Alarms": [],
            "Manufacturer": "DAHUA",
            "Model": "DH-IPC-HFW5241EP-Z12E",
            "Protocol": "ONVIF",
            "North degrees": 0.0,
            "Connection": {
                "Address": "172.17.105.18",
                "Default multicast": true,
                "HTTP port": 80,
                "Network caching": 50,
                "ONVIF port": 80,
                "Password": "Administrador",
                "RTSP port": 554,
                "User": "admin"
            },
            "Snapshot": [],
            "Default snapshot": 1,
            "Polling": 15
        }
    }
]