From 0db7d940b51364234294abfba854b5e250d18af3 Mon Sep 17 00:00:00 2001 From: grzesiekb Date: Fri, 21 Jul 2017 12:49:30 +0200 Subject: [PATCH 01/54] #318 Correcting travis.yml (new version tomcat) --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index faa5c122dc..85339f190a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,14 +40,13 @@ jdk: services: - docker - mysql -# script: ant war && ant junit +#script: ant war && ant junit script: ant war branches: only: - "/^PROC-.*$/" - "/^develop-sdtabilit.*$/" - "/^#179*$/" - - "/^master-sdtabilit.*$/" notifications: email: false env: @@ -58,7 +57,7 @@ env: - secure: KNfVmgjr2ZNsnvIfuhSkZ/kPrSTjn6WSDxEJt/3ioTCgeEGGvPL7UGonHHozZu3WzpzBVyUr60hXjb1nmb9dk6A3Dg05UPZmuS7NiHEA4Ub2zQKgefSbK0AJEhXSDg+bT16Hqxf1aZDaAEpMXGWTGLdpbKkGAW56UZu6LpOlOvoX9pFoSWAyzh1jKiYQsaKJ3eCncHKug5WqTVidOL/ENR6CAYyVLkgZ0yffwsCyVAnh14vri2lswPhPsPvMzYxtLQGkKkUOYkuPOZvBD7l5mp5Y4QLv86iKTFlOteim7yD+RpZZDFpb+3+OhRuj6jlBYWina33RKqBqjhhsayyYN/tYnPUefZhT+ALs8JfUaDXqMdgd7NQj8i5ZvrB+YsCTUVGrnPVbmEq8A4l/An5ushQpK5CrASiAC0K4dOBVT+U89QHtYWuE3ZOmSb518dlbH084ljypAj3JTQpUgRAAxn21VUMKb6QyIPsSPVEQ+zPQnaxBLhYVqafO7iX1tyvdr0mGhLZjXaaGwQu8Y/RoHdmRYcQAGn6zVFNuxWxTlr2OQ0fJ5l6/qBVyqZvqNirYa5hX8KtDu3dVMo5VOirIsoJTw75qTpGxYjhCNCb/woxtRvfX9xoT7tINWOxi2ucFfObSCsTv+BPeZeJiq7UDuFQYsQtWjNRp/iQNJ+rclpQ= after_script: # get tomcat7 to ./docker/app -- wget http://www-us.apache.org/dist/tomcat/tomcat-7/v7.0.78/bin/apache-tomcat-7.0.78.tar.gz +- wget http://www-us.apache.org/dist/tomcat/tomcat-7/v7.0.79/bin/apache-tomcat-7.0.79.tar.gz - mkdir ./docker/app - mv apache-tomcat-7.0.78.tar.gz ./docker/app - ls -l ./docker/app/apache-tomcat-7.0.78.tar.gz From 0b5aca01318182b516eb3305e6a9908d3f36dd26 Mon Sep 17 00:00:00 2001 From: grzesiekb Date: Fri, 21 Jul 2017 13:03:44 +0200 Subject: [PATCH 02/54] #318 Correcting travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 85339f190a..785d028b5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,6 +47,7 @@ branches: - "/^PROC-.*$/" - "/^develop-sdtabilit.*$/" - "/^#179*$/" + - "/^master-sdtabilit.*$/" notifications: email: false env: From e88b6165a34f9ffcee9c9c3f3196fa4707febb6d Mon Sep 17 00:00:00 2001 From: grzesiekb Date: Fri, 21 Jul 2017 13:08:29 +0200 Subject: [PATCH 03/54] Next correcting travis --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 785d028b5e..299b1c5f87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,15 +60,15 @@ after_script: # get tomcat7 to ./docker/app - wget http://www-us.apache.org/dist/tomcat/tomcat-7/v7.0.79/bin/apache-tomcat-7.0.79.tar.gz - mkdir ./docker/app -- mv apache-tomcat-7.0.78.tar.gz ./docker/app -- ls -l ./docker/app/apache-tomcat-7.0.78.tar.gz +- mv apache-tomcat-7.0.79.tar.gz ./docker/app +- ls -l ./docker/app/apache-tomcat-7.0.79.tar.gz - cd ./docker/app - echo `pwd` - echo `ls -l` -- tar -zxvf apache-tomcat-7.0.78.tar.gz +- tar -zxvf apache-tomcat-7.0.79.tar.gz - ls -l -- mv ./apache-tomcat-7.0.78/* ./ -- rm -rf ./apache-tomcat-7.0.78 +- mv ./apache-tomcat-7.0.79/* ./ +- rm -rf ./apache-tomcat-7.0.79 - cp ../../ScadaBR.war ./webapps - cp ../../ScadaLTS-UI/war/ScadaLTS.war ./webapps - ls -l ./webapps/ScadaLTS.war From 6beed27a89d1a272f9b2617f1ac80d3ca88dd1f5 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Mon, 24 Jul 2017 13:42:58 +0200 Subject: [PATCH 04/54] #320 Running in safe mode --- WebContent/WEB-INF/classes/env.properties | 4 +++ .../serotonin/mango/MangoContextListener.java | 28 +++++++++++-------- .../mango/vo/dataSource/DataSourceVO.java | 11 ++++++++ 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/WebContent/WEB-INF/classes/env.properties b/WebContent/WEB-INF/classes/env.properties index e7d56d997c..d0b3ae8c74 100644 --- a/WebContent/WEB-INF/classes/env.properties +++ b/WebContent/WEB-INF/classes/env.properties @@ -55,6 +55,7 @@ api.password=admin abilit.api.replace.alert.onview=true abilit.cacheEnable=true +abilit.safeModeEnable=false abilit.START_UPDATE_UNSILENCED_ALARM_LEVEL=100000 abilit.START_UPDATE_EVENT_DETECTORS=100000 abilit.START_UPDATE_PENDING_EVENTS=100000 @@ -63,5 +64,8 @@ abilit.MILLIS_SECONDS_PERIOD_UPDATE_EVENT_DETECTORS=1000 abilit.MILLIS_SECONDS_PERIOD_UPDATE_PENDING_EVENTS=1000 abilit.CRONE_UPDATE_CACHE_POINT_HIERARCHY=0 0/10 * * * ? + + + #security.hashAlgorithm=NONE #grove.url=http://mango.serotoninsoftware.com/servlet diff --git a/src/com/serotonin/mango/MangoContextListener.java b/src/com/serotonin/mango/MangoContextListener.java index 5a156ef655..301678a480 100644 --- a/src/com/serotonin/mango/MangoContextListener.java +++ b/src/com/serotonin/mango/MangoContextListener.java @@ -449,19 +449,21 @@ private void eventManagerTerminate(ContextWrapper ctx) { em.joinTermination(); } } - - // - // - // Runtime manager - // + + /** + * RuntimeManagerInitialize + * Initialize the web-application. + * Allows to run the Scada-LTS in safe mode with disabled DataSources + * by changing the property in env.properites file + * @param ctx - servlet context + */ private void runtimeManagerInitialize(ServletContext ctx) { RuntimeManager rtm = new RuntimeManager(); ctx.setAttribute(Common.ContextKeys.RUNTIME_MANAGER, rtm); - // Check for safe mode. - File safeFile = new File(ctx.getRealPath("SAFE")); - boolean safe = false; - if (safeFile.exists() && safeFile.isFile()) { + // Check for safe mode enabled from env.properties file. + boolean safe = Boolean.parseBoolean(Common.getEnvironmentProfile().getString("abilit.safeModeEnable")); + if (safe) { // Indicate that we're in safe mode. StringBuilder sb = new StringBuilder(); sb.append("\r\n"); @@ -471,8 +473,8 @@ private void runtimeManagerInitialize(ServletContext ctx) { sb.append("* Mango M2M is starting in safe mode. All data sources, *\r\n"); sb.append("* point links, scheduled events, compound events, and *\r\n"); sb.append("* publishers will be disabled. To disable safe mode, *\r\n"); - sb.append("* remove the SAFE file from the Mango M2M application *\r\n"); - sb.append("* directory. *\r\n"); + sb.append("* change the property in env.properties safeModeEnable *\r\n"); + sb.append("* to \"false\". *\r\n"); sb.append("* *\r\n"); sb.append("* To find all objects that were automatically disabled, *\r\n"); sb.append("* search for Audit Events on the alarms page. *\r\n"); @@ -488,8 +490,10 @@ private void runtimeManagerInitialize(ServletContext ctx) { } catch (Exception e) { log.error("RuntimeManager initialization failure", e); } finally { - if (safe) + if (safe) { BackgroundContext.remove(); + } + } } diff --git a/src/com/serotonin/mango/vo/dataSource/DataSourceVO.java b/src/com/serotonin/mango/vo/dataSource/DataSourceVO.java index 4f177ef09d..a9dcaf201c 100644 --- a/src/com/serotonin/mango/vo/dataSource/DataSourceVO.java +++ b/src/com/serotonin/mango/vo/dataSource/DataSourceVO.java @@ -85,6 +85,17 @@ abstract public class DataSourceVO> implements Serializable, Cloneable, JsonSerializable, ChangeComparable { + /** + * DataSourceType enum + * Display and create a new DataSurce types + * + * NAME(DataSouceID, DataSourceKey, DataSource display) { + * @Overiride + * public DataSourceVO createDataSource() { + * return new NAMEDataSourceVO(); + * } + * } + */ public enum Type { EBI25(16, "dsEdit.ebi25", false) { @Override From 51413ec7250ae4e3fbbc794d7b721616cc9ddebd Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Mon, 24 Jul 2017 14:57:34 +0200 Subject: [PATCH 05/54] #320 Running in safe mode --- .../serotonin/mango/vo/dataSource/DataSourceVO.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/com/serotonin/mango/vo/dataSource/DataSourceVO.java b/src/com/serotonin/mango/vo/dataSource/DataSourceVO.java index a9dcaf201c..4f177ef09d 100644 --- a/src/com/serotonin/mango/vo/dataSource/DataSourceVO.java +++ b/src/com/serotonin/mango/vo/dataSource/DataSourceVO.java @@ -85,17 +85,6 @@ abstract public class DataSourceVO> implements Serializable, Cloneable, JsonSerializable, ChangeComparable { - /** - * DataSourceType enum - * Display and create a new DataSurce types - * - * NAME(DataSouceID, DataSourceKey, DataSource display) { - * @Overiride - * public DataSourceVO createDataSource() { - * return new NAMEDataSourceVO(); - * } - * } - */ public enum Type { EBI25(16, "dsEdit.ebi25", false) { @Override From c57bc19c43b053591434f18be838d350a50210c2 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Mon, 24 Jul 2017 15:09:04 +0200 Subject: [PATCH 06/54] #320 Running in safe mode --- WebContent/WEB-INF/classes/env.properties | 4 +++- src/com/serotonin/mango/MangoContextListener.java | 13 ++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/WebContent/WEB-INF/classes/env.properties b/WebContent/WEB-INF/classes/env.properties index d0b3ae8c74..37b7a818ea 100644 --- a/WebContent/WEB-INF/classes/env.properties +++ b/WebContent/WEB-INF/classes/env.properties @@ -52,10 +52,12 @@ api.authentication=disabled api.username=admin api.password=admin +abilit.disableDataSourcesOnServerStart=true + abilit.api.replace.alert.onview=true + abilit.cacheEnable=true -abilit.safeModeEnable=false abilit.START_UPDATE_UNSILENCED_ALARM_LEVEL=100000 abilit.START_UPDATE_EVENT_DETECTORS=100000 abilit.START_UPDATE_PENDING_EVENTS=100000 diff --git a/src/com/serotonin/mango/MangoContextListener.java b/src/com/serotonin/mango/MangoContextListener.java index 301678a480..25a851c9ab 100644 --- a/src/com/serotonin/mango/MangoContextListener.java +++ b/src/com/serotonin/mango/MangoContextListener.java @@ -452,17 +452,20 @@ private void eventManagerTerminate(ContextWrapper ctx) { /** * RuntimeManagerInitialize + * * Initialize the web-application. - * Allows to run the Scada-LTS in safe mode with disabled DataSources - * by changing the property in env.properites file + * Allows to run the Scada-LTS in safe mode with disabled DataSources + * by changing the "abilit.disableDataSourcesOnServerStart" property + * in WEB-INF/classes/env.properites file to "TRUE" or "FALSE" * @param ctx - servlet context */ + @SuppressWarnings("deprecation") private void runtimeManagerInitialize(ServletContext ctx) { RuntimeManager rtm = new RuntimeManager(); ctx.setAttribute(Common.ContextKeys.RUNTIME_MANAGER, rtm); // Check for safe mode enabled from env.properties file. - boolean safe = Boolean.parseBoolean(Common.getEnvironmentProfile().getString("abilit.safeModeEnable")); + boolean safe = Boolean.parseBoolean(Common.getEnvironmentProfile().getString("abilit.disableDataSourcesOnServerStart")); if (safe) { // Indicate that we're in safe mode. StringBuilder sb = new StringBuilder(); @@ -473,8 +476,8 @@ private void runtimeManagerInitialize(ServletContext ctx) { sb.append("* Mango M2M is starting in safe mode. All data sources, *\r\n"); sb.append("* point links, scheduled events, compound events, and *\r\n"); sb.append("* publishers will be disabled. To disable safe mode, *\r\n"); - sb.append("* change the property in env.properties safeModeEnable *\r\n"); - sb.append("* to \"false\". *\r\n"); + sb.append("* change the property in env.properties: *\r\n"); + sb.append("* abilit.disableDataSourcesOnServerStart to \"false\". *\r\n"); sb.append("* *\r\n"); sb.append("* To find all objects that were automatically disabled, *\r\n"); sb.append("* search for Audit Events on the alarms page. *\r\n"); From f9b99d8b0149ed0a18bbee94a7adeaaf73b3ef12 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Mon, 24 Jul 2017 16:03:47 +0200 Subject: [PATCH 07/54] #320 Running in safe mode -Fixing exceptions when property is commented --- WebContent/WEB-INF/classes/env.properties | 2 +- src/com/serotonin/mango/MangoContextListener.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WebContent/WEB-INF/classes/env.properties b/WebContent/WEB-INF/classes/env.properties index 37b7a818ea..844d1fbde9 100644 --- a/WebContent/WEB-INF/classes/env.properties +++ b/WebContent/WEB-INF/classes/env.properties @@ -52,7 +52,7 @@ api.authentication=disabled api.username=admin api.password=admin -abilit.disableDataSourcesOnServerStart=true +abilit.disableDataSourcesOnServerStart=false abilit.api.replace.alert.onview=true diff --git a/src/com/serotonin/mango/MangoContextListener.java b/src/com/serotonin/mango/MangoContextListener.java index 25a851c9ab..d0b5f58306 100644 --- a/src/com/serotonin/mango/MangoContextListener.java +++ b/src/com/serotonin/mango/MangoContextListener.java @@ -465,7 +465,7 @@ private void runtimeManagerInitialize(ServletContext ctx) { ctx.setAttribute(Common.ContextKeys.RUNTIME_MANAGER, rtm); // Check for safe mode enabled from env.properties file. - boolean safe = Boolean.parseBoolean(Common.getEnvironmentProfile().getString("abilit.disableDataSourcesOnServerStart")); + boolean safe = Common.getEnvironmentProfile().getBoolean("abilit.disableDataSourcesOnServerStart", false); if (safe) { // Indicate that we're in safe mode. StringBuilder sb = new StringBuilder(); From 99b409a236dcc48baaffb5ca1e3f7320f96dffef Mon Sep 17 00:00:00 2001 From: grzesiekb Date: Tue, 25 Jul 2017 19:48:24 +0200 Subject: [PATCH 08/54] #315 Creating REST to point value save. --- .../dao/model/point/PointValueTypeOfREST.java | 10 ++ .../dao/pointvalues/PointValueDAO.java | 11 ++ .../dao/pointvalues/PointValueDAO4REST.java | 103 ++++++++++++++++++ .../mango/service/DataPointService.java | 15 +++ .../scada_lts/web/mvc/api/PointValueAPI.java | 36 +++++- 5 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/org/scada_lts/dao/model/point/PointValueTypeOfREST.java create mode 100644 src/org/scada_lts/dao/pointvalues/PointValueDAO4REST.java diff --git a/src/org/scada_lts/dao/model/point/PointValueTypeOfREST.java b/src/org/scada_lts/dao/model/point/PointValueTypeOfREST.java new file mode 100644 index 0000000000..28fec1196f --- /dev/null +++ b/src/org/scada_lts/dao/model/point/PointValueTypeOfREST.java @@ -0,0 +1,10 @@ +package org.scada_lts.dao.model.point; + +public class PointValueTypeOfREST { + + public final static int TYPE_BINARY = 0; + public final static int TYPE_MULTISTATE = 1; + public final static int TYPE_DOUBLE = 2; + public final static int TYPE_STRING = 3; + +} diff --git a/src/org/scada_lts/dao/pointvalues/PointValueDAO.java b/src/org/scada_lts/dao/pointvalues/PointValueDAO.java index 4521c9139a..90237d3d9f 100644 --- a/src/org/scada_lts/dao/pointvalues/PointValueDAO.java +++ b/src/org/scada_lts/dao/pointvalues/PointValueDAO.java @@ -384,9 +384,18 @@ public PreparedStatement createPreparedStatement(Connection connection) throws S } + + @Transactional(readOnly = false,propagation= Propagation.REQUIRES_NEW,isolation= Isolation.READ_COMMITTED,rollbackFor=SQLException.class) public Object[] create(final int pointId,final int dataType,final double dvalue,final long time) { + return createNoTransaction(pointId, dataType, dvalue, time); + + } + + + public Object[] createNoTransaction(final int pointId,final int dataType,final double dvalue,final long time) { + if (LOG.isTraceEnabled()) { LOG.trace("pointId:"+pointId+" dataType:"+dataType+" dvalue:"+time); } @@ -411,6 +420,8 @@ public PreparedStatement createPreparedStatement(Connection connection) throws S } + + @Transactional(readOnly = false,propagation= Propagation.REQUIRES_NEW,isolation= Isolation.READ_COMMITTED,rollbackFor=SQLException.class) public void executeBatchUpdateInsert( List params) { diff --git a/src/org/scada_lts/dao/pointvalues/PointValueDAO4REST.java b/src/org/scada_lts/dao/pointvalues/PointValueDAO4REST.java new file mode 100644 index 0000000000..76c033dfa2 --- /dev/null +++ b/src/org/scada_lts/dao/pointvalues/PointValueDAO4REST.java @@ -0,0 +1,103 @@ +/* + * (c) 2017 Abil'I.T. http://abilit.eu/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package org.scada_lts.dao.pointvalues; + +import java.sql.SQLException; +import java.util.Date; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.scada_lts.dao.DAO; +import org.scada_lts.dao.model.point.PointValueAdnnotation; +import org.scada_lts.dao.model.point.PointValueTypeOfREST; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import com.serotonin.mango.DataTypes; +import com.serotonin.mango.rt.dataImage.PointValueTime; + +/** + * + * @author grzegorz bylica Abil'I.T. development team, sdt@abilit.eu + * + */ +@Repository +public class PointValueDAO4REST { + + private static final Log LOG = LogFactory.getLog(PointValueDAO4REST.class); + + @Transactional(readOnly = false,propagation= Propagation.REQUIRES_NEW,isolation= Isolation.READ_COMMITTED,rollbackFor=SQLException.class) + public PointValueTime save(String value, int typePointValueOfREST, int dpid) { + + if (LOG.isTraceEnabled()) { + LOG.trace("save data from REST for point:" + dpid); + } + + PointValueTime pvt = null; + + String interpretationBinaryValueFalseOfREST = "0"; + String interpretationBinaryValueTrueOfREST = "1"; + + if (typePointValueOfREST==PointValueTypeOfREST.TYPE_BINARY) { + if (value.equals(interpretationBinaryValueTrueOfREST)) { + pvt = new PointValueTime(true, new Date().getTime() ); + new PointValueDAO().createNoTransaction(dpid, DataTypes.BINARY, 1, new Date().getTime()); + } else if (value.equals(interpretationBinaryValueFalseOfREST)) { + pvt = new PointValueTime(false, new Date().getTime() ); + new PointValueDAO().createNoTransaction(dpid, DataTypes.BINARY, 0, new Date().getTime()); + } else { + new RuntimeException("Value not compatible with type (binary)"); + } + } else if (typePointValueOfREST==PointValueTypeOfREST.TYPE_MULTISTATE) { + try { + pvt = new PointValueTime(Integer.parseInt(value), new Date().getTime() ); + new PointValueDAO().createNoTransaction(dpid, DataTypes.MULTISTATE, Integer.parseInt(value), new Date().getTime()); + } catch (NumberFormatException e) { + new RuntimeException("Value not compatible with type (multistate)"); + } + } else if (typePointValueOfREST==PointValueTypeOfREST.TYPE_DOUBLE) { + try { + pvt = new PointValueTime(Double.parseDouble(value), new Date().getTime() ); + new PointValueDAO().createNoTransaction(dpid, DataTypes.NUMERIC, Double.parseDouble(value), new Date().getTime()); + } catch (NumberFormatException e) { + new RuntimeException("Value not compatible with type (double)"); + } + } else if (typePointValueOfREST==PointValueTypeOfREST.TYPE_STRING) { + pvt = new PointValueTime(value, new Date().getTime() ); + Object[] resultPointValue = new PointValueDAO().createNoTransaction(dpid, DataTypes.ALPHANUMERIC, 0, new Date().getTime()); + PointValueAdnnotation pva = new PointValueAdnnotation(); + Long pointValueId = (Long) resultPointValue[0]; + pva.setPointValueId(pointValueId); + pva.setSourceType(DataTypes.ALPHANUMERIC); + pva.setTextPointValueLong(value); + pva.setTextPointValueShort(value); + Object[] resultPointValueAdnnotation = new PointValueAdnnotationsDAO().create(pva); + if (LOG.isTraceEnabled()) { + LOG.trace("save data string:" + dpid); + } + + } else { + new RuntimeException("Unknown value type"); + } + + return pvt; + } + +} diff --git a/src/org/scada_lts/mango/service/DataPointService.java b/src/org/scada_lts/mango/service/DataPointService.java index 368d26bf7d..ce9320fc5c 100644 --- a/src/org/scada_lts/mango/service/DataPointService.java +++ b/src/org/scada_lts/mango/service/DataPointService.java @@ -36,6 +36,7 @@ import org.scada_lts.dao.PointLinkDAO; import org.scada_lts.dao.UserCommentDAO; import org.scada_lts.dao.pointvalues.PointValueDAO; +import org.scada_lts.dao.pointvalues.PointValueDAO4REST; import org.scada_lts.dao.watchlist.WatchListDAO; import org.scada_lts.mango.adapter.MangoDataPoint; import org.scada_lts.mango.adapter.MangoPointHierarchy; @@ -47,6 +48,8 @@ import com.serotonin.db.IntValuePair; import com.serotonin.mango.Common; import com.serotonin.mango.db.dao.PointValueDao; +import com.serotonin.mango.rt.dataImage.DataPointRT; +import com.serotonin.mango.rt.dataImage.PointValueTime; import com.serotonin.mango.vo.DataPointExtendedNameComparator; import com.serotonin.mango.vo.DataPointVO; import com.serotonin.mango.vo.User; @@ -138,6 +141,18 @@ public List getDataPoints(int dataSourceId, Comparator } return dpList; } + + public void save(String value, String xid, int typePointValueOfREST ) { + DataPointVO dpvo = dataPointDAO.getDataPoint(xid); + + PointValueTime pvt = new PointValueDAO4REST().save(value, typePointValueOfREST, dpvo.getId()); + + DataPointRT dpRT = Common.ctx.getRuntimeManager().getDataPoint( + dpvo.getId()); + + dpRT.updatePointValue(pvt); + + } private void setRelationalData(List dpList) { for (DataPointVO dp: dpList) { diff --git a/src/org/scada_lts/web/mvc/api/PointValueAPI.java b/src/org/scada_lts/web/mvc/api/PointValueAPI.java index cff128e192..f98e450768 100644 --- a/src/org/scada_lts/web/mvc/api/PointValueAPI.java +++ b/src/org/scada_lts/web/mvc/api/PointValueAPI.java @@ -323,9 +323,9 @@ public ResponseEntity getValue(@PathVariable("xid") String xid, HttpServ try { User user = Common.getUser(request); - DataPointVO dpvo = dataPointService.getDataPoint(xid); if (user != null) { + DataPointVO dpvo = dataPointService.getDataPoint(xid); PointValueTime pvt = pointValueService.getLatestPointValue(dpvo.getId()); String json = null; ObjectMapper mapper = new ObjectMapper(); @@ -346,6 +346,40 @@ public ResponseEntity getValue(@PathVariable("xid") String xid, HttpServ } } + + /** + * @param xid + * @param type (0 - binary, 1 - multistate, 2 - double, 3 - string) + * @param value (for binary [0,1] + * @param request + * @return + */ + @RequestMapping(value = "/api/point_value/setValue/{xid}/{type}/{value}", method = RequestMethod.POST) + public ResponseEntity setValue( + @PathVariable("xid") String xid, + @PathVariable("type") int type, + @PathVariable("value") String value, + HttpServletRequest request) { + + LOG.info("/api/point_value/setValue/{xid}/{type}/{value} xid:"+xid+" type:"+type+" value:"+value); + + try { + User user = Common.getUser(request); + if (user != null) { + + dataPointService.save(value, xid, type); + + return new ResponseEntity(value,HttpStatus.OK); + } + + return new ResponseEntity(HttpStatus.UNAUTHORIZED); + + } catch (Exception e) { + LOG.error(e); + return new ResponseEntity(HttpStatus.BAD_REQUEST); + } + } + /** From d904b849a5a0742ad20ac8ee180e4edc89219f5b Mon Sep 17 00:00:00 2001 From: Bartek Date: Wed, 26 Jul 2017 14:18:24 +0200 Subject: [PATCH 09/54] Added badge for Docker Image --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cbd047780b..0f01bb5fcb 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Build Status](https://img.shields.io/travis/grzesiekb/json.svg?style=flat-square)](https://travis-ci.org/sdtabilit/Scada-LTS) [![GPL-2.0](https://img.shields.io/npm/l/gb-json.svg?style=flat-square)](https://github.com/sdtabilit/Scada-LTS/blob/master-sdtabilit/LICENSE) +[![](https://images.microbadger.com/badges/version/dockergb/scadalts-dev.svg)](https://microbadger.com/images/dockergb/scadalts-dev "Get your own version badge on microbadger.com") Scada-LTS is an Open Source, web-based, multi-platform solution for building your own SCADA (Supervisory Control and Data Acquisiton) system. From 4d7fcae589a9c4c74b731fa505615a35eb6996eb Mon Sep 17 00:00:00 2001 From: Bartek Date: Wed, 26 Jul 2017 14:29:06 +0200 Subject: [PATCH 10/54] Added second badge for Docker Image --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0f01bb5fcb..df6c97e145 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Build Status](https://img.shields.io/travis/grzesiekb/json.svg?style=flat-square)](https://travis-ci.org/sdtabilit/Scada-LTS) [![GPL-2.0](https://img.shields.io/npm/l/gb-json.svg?style=flat-square)](https://github.com/sdtabilit/Scada-LTS/blob/master-sdtabilit/LICENSE) [![](https://images.microbadger.com/badges/version/dockergb/scadalts-dev.svg)](https://microbadger.com/images/dockergb/scadalts-dev "Get your own version badge on microbadger.com") +[![](https://images.microbadger.com/badges/image/dockergb/scadalts-dev.svg)](https://microbadger.com/images/dockergb/scadalts-dev "Get your own image badge on microbadger.com") Scada-LTS is an Open Source, web-based, multi-platform solution for building your own SCADA (Supervisory Control and Data Acquisiton) system. From 7bad5e4df27b8ed656b4708350b75c64df2994ca Mon Sep 17 00:00:00 2001 From: grzesiekb Date: Wed, 26 Jul 2017 16:56:23 +0200 Subject: [PATCH 11/54] #315 Correcting REST save point value. --- .../dao/pointvalues/PointValueDAO4REST.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/org/scada_lts/dao/pointvalues/PointValueDAO4REST.java b/src/org/scada_lts/dao/pointvalues/PointValueDAO4REST.java index 76c033dfa2..db7db5044b 100644 --- a/src/org/scada_lts/dao/pointvalues/PointValueDAO4REST.java +++ b/src/org/scada_lts/dao/pointvalues/PointValueDAO4REST.java @@ -58,37 +58,42 @@ public PointValueTime save(String value, int typePointValueOfREST, int dpid) { if (typePointValueOfREST==PointValueTypeOfREST.TYPE_BINARY) { if (value.equals(interpretationBinaryValueTrueOfREST)) { pvt = new PointValueTime(true, new Date().getTime() ); - new PointValueDAO().createNoTransaction(dpid, DataTypes.BINARY, 1, new Date().getTime()); + } else if (value.equals(interpretationBinaryValueFalseOfREST)) { pvt = new PointValueTime(false, new Date().getTime() ); - new PointValueDAO().createNoTransaction(dpid, DataTypes.BINARY, 0, new Date().getTime()); } else { new RuntimeException("Value not compatible with type (binary)"); } } else if (typePointValueOfREST==PointValueTypeOfREST.TYPE_MULTISTATE) { try { pvt = new PointValueTime(Integer.parseInt(value), new Date().getTime() ); - new PointValueDAO().createNoTransaction(dpid, DataTypes.MULTISTATE, Integer.parseInt(value), new Date().getTime()); } catch (NumberFormatException e) { new RuntimeException("Value not compatible with type (multistate)"); } } else if (typePointValueOfREST==PointValueTypeOfREST.TYPE_DOUBLE) { try { pvt = new PointValueTime(Double.parseDouble(value), new Date().getTime() ); - new PointValueDAO().createNoTransaction(dpid, DataTypes.NUMERIC, Double.parseDouble(value), new Date().getTime()); } catch (NumberFormatException e) { new RuntimeException("Value not compatible with type (double)"); } } else if (typePointValueOfREST==PointValueTypeOfREST.TYPE_STRING) { + pvt = new PointValueTime(value, new Date().getTime() ); Object[] resultPointValue = new PointValueDAO().createNoTransaction(dpid, DataTypes.ALPHANUMERIC, 0, new Date().getTime()); PointValueAdnnotation pva = new PointValueAdnnotation(); Long pointValueId = (Long) resultPointValue[0]; pva.setPointValueId(pointValueId); pva.setSourceType(DataTypes.ALPHANUMERIC); - pva.setTextPointValueLong(value); - pva.setTextPointValueShort(value); - Object[] resultPointValueAdnnotation = new PointValueAdnnotationsDAO().create(pva); + + int lengthShortValue = 128; + if (value.length()<=lengthShortValue) { + pva.setTextPointValueShort(value); + } else { + pva.setTextPointValueLong(value); + } + + new PointValueAdnnotationsDAO().create(pva); + if (LOG.isTraceEnabled()) { LOG.trace("save data string:" + dpid); } From 8087c992d9d09a61010cfbb780b1e1be21ab0e56 Mon Sep 17 00:00:00 2001 From: grzesiekb Date: Thu, 27 Jul 2017 17:22:24 +0200 Subject: [PATCH 12/54] #330 An initial version of the ScadaLTS simulation with REST API --- .../war/WebContent/META-INF/MANIFEST.MF | 3 + .../war/WebContent/WEB-INF/web.xml | 3 + ScadaLTS-Simulation/war/WebContent/index.html | 294 ++++++++++++++++++ 3 files changed, 300 insertions(+) create mode 100644 ScadaLTS-Simulation/war/WebContent/META-INF/MANIFEST.MF create mode 100644 ScadaLTS-Simulation/war/WebContent/WEB-INF/web.xml create mode 100644 ScadaLTS-Simulation/war/WebContent/index.html diff --git a/ScadaLTS-Simulation/war/WebContent/META-INF/MANIFEST.MF b/ScadaLTS-Simulation/war/WebContent/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..254272e1c0 --- /dev/null +++ b/ScadaLTS-Simulation/war/WebContent/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/ScadaLTS-Simulation/war/WebContent/WEB-INF/web.xml b/ScadaLTS-Simulation/war/WebContent/WEB-INF/web.xml new file mode 100644 index 0000000000..91687fac77 --- /dev/null +++ b/ScadaLTS-Simulation/war/WebContent/WEB-INF/web.xml @@ -0,0 +1,3 @@ + +index.html + \ No newline at end of file diff --git a/ScadaLTS-Simulation/war/WebContent/index.html b/ScadaLTS-Simulation/war/WebContent/index.html new file mode 100644 index 0000000000..bc4c21e0ea --- /dev/null +++ b/ScadaLTS-Simulation/war/WebContent/index.html @@ -0,0 +1,294 @@ + + + + + + + + + + + + + +
+
+
+ + Simulation + +
+
+
+ Simulation + +
+
+
+
+
+ +
+ +
+

Simulation monitoring of fuel consumption in the generator

+
+
+

+ +
+
+
+ + +
+
+
+
+
+ + \ No newline at end of file From 944017316e1bd204f2c32d20f0deacaabd184bb8 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Wed, 2 Aug 2017 10:17:33 +0200 Subject: [PATCH 13/54] #332_Simulation_1 Adding a new View based on the REST API. Getting current data from Scada and dispaly it on the page. --- ScadaLTS-Simulation1.7z | Bin 0 -> 9138 bytes .../war/WebContent/META-INF/MANIFEST.MF | 3 + .../war/WebContent/WEB-INF/web.xml | 3 + .../war/WebContent/index.html | 400 ++++++++++++++++++ ScadaLTS-Simulation1/war/WebContent/style.css | 60 +++ .../war/WebContent/styles.scss | 79 ++++ .../war/WebContent/text48.png | Bin 0 -> 2360 bytes ScadaLTS-Simulation1/war/build.xml | 21 + 8 files changed, 566 insertions(+) create mode 100644 ScadaLTS-Simulation1.7z create mode 100644 ScadaLTS-Simulation1/war/WebContent/META-INF/MANIFEST.MF create mode 100644 ScadaLTS-Simulation1/war/WebContent/WEB-INF/web.xml create mode 100644 ScadaLTS-Simulation1/war/WebContent/index.html create mode 100644 ScadaLTS-Simulation1/war/WebContent/style.css create mode 100644 ScadaLTS-Simulation1/war/WebContent/styles.scss create mode 100644 ScadaLTS-Simulation1/war/WebContent/text48.png create mode 100644 ScadaLTS-Simulation1/war/build.xml diff --git a/ScadaLTS-Simulation1.7z b/ScadaLTS-Simulation1.7z new file mode 100644 index 0000000000000000000000000000000000000000..52cd5558c0a6cc250cc7dec2ce455a6c20534c69 GIT binary patch literal 9138 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 +index.html + \ No newline at end of file diff --git a/ScadaLTS-Simulation1/war/WebContent/index.html b/ScadaLTS-Simulation1/war/WebContent/index.html new file mode 100644 index 0000000000..de6d2bd004 --- /dev/null +++ b/ScadaLTS-Simulation1/war/WebContent/index.html @@ -0,0 +1,400 @@ + + + + + Recy Kunden Zähel + + + + + + + + + + + + + +
+
+
+ + Recy Kunden Zähel + + +
+ +
+
+ RECY + +
+
+ +
+
+
+
+
+

Schließen

+
+ +
+
+
+
+ +
+ + +
+
+
+
+

Esch

+
+
+
+
+
+
+ Akt. St: +
+
+ 2 +
+
+ Verg. St: +
+
+ 2#/h +
+
+ Akt. Tg: +
+
+ 4 +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+

Mondercange

+
+
+
+
+
+
+ Akt. St: +
+
+ 2 +
+
+ Verg. St: +
+
+ 2#/h +
+
+ Akt. Tg: +
+
+ 4 +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+

Reckange

+
+
+
+
+
+
+ Akt. St: +
+
+ 2 +
+
+ Verg. St: +
+
+ 2#/h +
+
+ Akt. Tg: +
+
+ 4 +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+

Sanem

+
+
+
+
+
+
+ Akt. St: +
+
+ 2 +
+
+ Verg. St: +
+
+ 2#/h +
+
+ Akt. Tg: +
+
+ 4 +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+

Schifflange

+
+
+
+
+
+
+ Akt. St: +
+
+ 2 +
+
+ Verg. St: +
+
+ 2#/h +
+
+ Akt. Tg: +
+
+ 4 +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+

CIGL

+
+
+
+
+
+
+ Akt. St: +
+
+ 2 +
+
+ Verg. St: +
+
+ 2#/h +
+
+ Akt. Tg: +
+
+ 4 +
+
+ +
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+

Gesamt Tag: 32

+
+
+ +
+ +
+ +
+
+
+
+
+ Portal +
+
+
+
+
+
+
+ Portal +
+
+
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/ScadaLTS-Simulation1/war/WebContent/style.css b/ScadaLTS-Simulation1/war/WebContent/style.css new file mode 100644 index 0000000000..a2ed3804da --- /dev/null +++ b/ScadaLTS-Simulation1/war/WebContent/style.css @@ -0,0 +1,60 @@ +main-theme { + background-color: green; } + +.mdl-card { + width: 100%; + min-height: 20px; } + +.mdl-layout__header { + background-color: green; } + +.button-color { + color: white; + background-color: green; } + .button-color:hover { + background-color: #2CB32C; } + +.mdl-card__actions img { + display: block; + width: 100%; } + +.mdl-switch { + display: unset; } + +.mdl-switch.is-checked .mdl-switch__thumb { + background-color: green; } + +.mdl-switch.is-checked .mdl-switch__track { + background-color: rgba(0, 128, 0, 0.5); } + +.mdl-layout-title, #clock { + margin-top: 10px; + display: inline-block; + width: 100%; + color: white; + font-size: 25px; + font-weight: bold; + text-align: center; + background-color: green; } + +#clock { + margin-bottom: 15px; } + +.logo { + position: fixed; + margin: 10px; + right: 20px; + top: 0px; + display: inline; } + +.center-element { + width: 20%; + text-align: center; + margin: 0 auto; } + @media screen and (max-width: 840px) { + .center-element { + width: 100%; } } + .center-element h2 { + margin-right: 20px; } + +/*# sourceMappingURL=style.css.map */ diff --git a/ScadaLTS-Simulation1/war/WebContent/styles.scss b/ScadaLTS-Simulation1/war/WebContent/styles.scss new file mode 100644 index 0000000000..33fbfd9c07 --- /dev/null +++ b/ScadaLTS-Simulation1/war/WebContent/styles.scss @@ -0,0 +1,79 @@ +$theme_main_color: green; +$theme_main_color_light: #2CB32C; +$theme_main_color_dark: #004100; +$header_font_size: 25px; +$card_height: 60px; + +main-theme { + background-color: $theme_main_color; +} + +.mdl-card { + width: 100%; + min-height: 20px; +} + +.mdl-layout__header { + background-color: $theme_main_color; +} +.button-color { + color: white; + background-color: $theme_main_color; + &:hover { + background-color: $theme_main_color_light; + } + +} +.mdl-card__actions { + img { + display: block; + width: 100%; + + } +} +.mdl-switch { + display: unset; +} +.mdl-switch.is-checked .mdl-switch__thumb { + background-color: $theme_main_color; +} +.mdl-switch.is-checked .mdl-switch__track { + background-color: rgba(0, 128, 0, 0.5); +} +.mdl-layout-title , #clock{ + margin-top: 10px; + display: inline-block; + width: 100%; + color: white; + font-size: $header_font_size; + font-weight: bold; + text-align: center; + background-color: $theme_main_color; +} +#clock { + margin-bottom: 15px; +} +.logo { + position: fixed; + margin: 10px; + right: 20px; + top: 0px; + display: inline; + +} +.center-element { + width: 20%; + text-align: center; + margin: 0 auto; + + @media screen and (max-width: 840px) { + width: 100%; + + } + + h2 { + margin-right: 20px; + } + +} +//840px \ No newline at end of file diff --git a/ScadaLTS-Simulation1/war/WebContent/text48.png b/ScadaLTS-Simulation1/war/WebContent/text48.png new file mode 100644 index 0000000000000000000000000000000000000000..ea1edab3f993cda928b8a6c843a148d6a36cbaee GIT binary patch literal 2360 zcmV-83CH${P)K~!jg&6nvxn^M%gA zm}oE&7zZ5m%~FCUgSUWMblR`+in zuiKLv42`nLCzH6AnUk-UxC1nOFaZmoOVVRXaQE`rJ6p@?STgxVFHJtrq(^`mWz#DS zAA;S>xH0!MoVB^Pln#d^f8B;jm5FYbH25wM8#2X1V~ZzUyL|4>Er&8JN`B$`s_~Y# z-y5709k-J35oTX+sNM0qVn!}Zv3SjtFSxY5It;`CMj|~|-&nPzm{GxzzhV8f>P$Ml z5%}yULai+5#)i6`%L-`*kYBjIYP?I^MqtV(&Z{(}P0V|AZqu54MZdI3CULP|Tg9h` zI6z#+GuOW~`HT6Ae&qMgtiDyo#fOhq$vDcBR@T3EW+Eu;Bfs#EpPP=j^YHU38K=>f zx-}^1BkwZtdw|4%E}tgIZogq|)#r0f2e7cQ>U_{whmTdss7RaLk!v{r&ku%=PkAs{ zkQ;rscwO~Wu-f4!RR&_7*=+z$8M}hPPK}2Ng8A2Nm{jS^bir_w83aaEbh(S2VA60i z84Nt*atDkbZX$z$p>yNFQ4#rTH`s!)ACHfOIxx!!KIk7+y-xPwkfX_Z<3#s@vA?%F zahX+gB;u}OzWFsESP6Qq=Y_Z>Ix?P3iFq318DmW9H${AQcBb5%NA}&Nzvvtmi=~!??8Kll%v{ve+q1m$az0FqxrqFCmlyri&~-;0_2x2 z*wg8meGMpSOQpP6+MP+b$nxEccOh>s-`>9CUzoidRggZ&HG7!|%cP$+@tokMHB&}+ zo3|3_!l;4-!tH_RDh=4jBfsdy>S^81`#Z+v(FF*EGVL*o?&;c>^GnvBe2m5THE?od z&huksV$Fkmy1rqsVt~I~wOKZMTU$e2)0e!sjz?Mm_7pIv9qACLXGFSLP;T06=&A6& z{Ag{{w}3~2idZmh0G7|*+1fC7=d%rUJHBz?gQnv=&zp&n1ib=ehCse;#jIUjl>P=K zu=^M{wsys=UGHOP!mCX;%6PobK-rNmX@T{I7bcGN60sV|)q>`b{V<|bDz7!nZ92QY zvHAcorns@~HEB_y%`=46ud8|h+0BXg5#yH4-qtp#)#1hKs;4Sr7vrcwnnm^tj}Y!W z-DMq%M(D_5(~mB&`{NarKYMuAe~M01>eo(Q+)%fp0YgJx+D;~M&F4*;VV>21)d1%M zqXP7Qf@u|UZx-l&5O|yzOa0kxS%`dHzW%i{6YM*1E{+-#HJo~n zldn6^Z@=lc_xSA@c|P9t<u6?aU}uPZj$omY&nI69XOk@+T|nQbS!T8y*d5j> zjC`AazD80r@SvF$tIgZV=JpAajxn<~!bkp8Nmu9MnAx9!YQMeNY=}$llEzEQ1n&BS zl9mMY{i=;G+vLkGk`(hRg(vAVzP?bkdD++f$ZtPi4$p$s#>`rQ)dA5c;2}wKi}(sw zoM~h$#oK09%Huz`GgH=7q1a|xJ@DH=+bCW>gLz*p-%~)7f9&;Txd+>k#mMF(l)Ra} zZ)R5lGl9(kVqpl5d@=IBFtf@2G2fTvHk!-YH96!qrkTA;b}9gHOcB#9fPhng(|uVf zl?Gs!e?CJ}$(!0?PuNq`e_b(GeLBJ%`MJG|?7zOo7ne#tXLmH&_kkRbN=cz_ZDAun z71$){D}J@O-j}~uB8d@XCss`bY%Y}a{lIaQzsO5z89juER1K^$oCYG33&1l*B$)wy3~}(;UNlda)j>C z7kt8+*&0cglbs-)LAL(h<=?!Jy$7BJn)AAD^5p<8=IJ&EbU}3bF}ozy0Ly?mWJ~H@ eX0|?z{Qm*y + + + + + + + + + + + + + + + + + + \ No newline at end of file From 50351fc39791cb501aacdcbf067a6021bfd8d0e8 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Wed, 2 Aug 2017 10:24:11 +0200 Subject: [PATCH 14/54] #332 Simulation 1 - Adding data changes --- .../war/WebContent/index.html | 70 ++++++++++++------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/ScadaLTS-Simulation1/war/WebContent/index.html b/ScadaLTS-Simulation1/war/WebContent/index.html index de6d2bd004..a302c4ae97 100644 --- a/ScadaLTS-Simulation1/war/WebContent/index.html +++ b/ScadaLTS-Simulation1/war/WebContent/index.html @@ -1,4 +1,3 @@ - @@ -70,19 +69,19 @@

Esch

Akt. St:
- 2 + 2
Verg. St:
- 2#/h + 2#/h
Akt. Tg:
- 4 + 4
@@ -110,19 +109,19 @@

Mondercange

Akt. St:
- 2 + 2
Verg. St:
- 2#/h + 2#/h
Akt. Tg:
- 4 + 4
@@ -150,19 +149,19 @@

Reckange

Akt. St:
- 2 + 2
Verg. St:
- 2#/h + 2#/h
Akt. Tg:
- 4 + 4
@@ -190,19 +189,19 @@

Sanem

Akt. St:
- 2 + 2
Verg. St:
- 2#/h + 2#/h
Akt. Tg:
- 4 + 4
@@ -230,19 +229,19 @@

Schifflange

Akt. St:
- 2 + 2
Verg. St:
- 2#/h + 2#/h
Akt. Tg:
- 4 + 4
@@ -250,7 +249,7 @@

Schifflange

- +
@@ -270,19 +269,19 @@

CIGL

Akt. St:
- 2 + 2
Verg. St:
- 2#/h + 2#/h
Akt. Tg:
- 4 + 4
@@ -290,7 +289,7 @@

CIGL

- +
@@ -342,6 +341,9 @@

Gesamt Tag: 32

+ + + From b2ac8690bf62bb893d652946467e40b177fb7207 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Wed, 2 Aug 2017 13:04:39 +0200 Subject: [PATCH 15/54] #332 Simulation 1 --- .../war/WebContent/index.html | 111 +++++++++++++----- 1 file changed, 84 insertions(+), 27 deletions(-) diff --git a/ScadaLTS-Simulation1/war/WebContent/index.html b/ScadaLTS-Simulation1/war/WebContent/index.html index a302c4ae97..574a271a77 100644 --- a/ScadaLTS-Simulation1/war/WebContent/index.html +++ b/ScadaLTS-Simulation1/war/WebContent/index.html @@ -12,6 +12,7 @@ + @@ -89,7 +90,7 @@

Esch

- +
@@ -129,7 +130,7 @@

Mondercange

- +
@@ -169,7 +170,7 @@

Reckange

- +
@@ -209,7 +210,7 @@

Sanem

- +
@@ -249,7 +250,7 @@

Schifflange

- +
@@ -289,7 +290,7 @@

CIGL

- +
@@ -300,7 +301,7 @@

CIGL

-

Gesamt Tag: 32

+

Gesamt Tag: 32

@@ -345,6 +346,8 @@

Gesamt Tag: 32

From b2011fc2c1cbac3ac5661f2fa661380c2c80db7d Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Wed, 2 Aug 2017 13:08:46 +0200 Subject: [PATCH 16/54] #332 Simulation 1 - fix values --- .../war/WebContent/index.html | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/ScadaLTS-Simulation1/war/WebContent/index.html b/ScadaLTS-Simulation1/war/WebContent/index.html index 574a271a77..5b65e4a48c 100644 --- a/ScadaLTS-Simulation1/war/WebContent/index.html +++ b/ScadaLTS-Simulation1/war/WebContent/index.html @@ -21,10 +21,10 @@
- Recy Kunden Zähel + Simulation Model View
@@ -60,7 +60,7 @@

Schließen

-

Esch

+

Location 1

@@ -100,7 +100,7 @@

Esch

-

Mondercange

+

Location 2

@@ -140,7 +140,7 @@

Mondercange

-

Reckange

+

Location 3

@@ -180,7 +180,7 @@

Reckange

-

Sanem

+

Location 4

@@ -220,7 +220,7 @@

Sanem

-

Schifflange

+

Location 5

@@ -260,7 +260,7 @@

Schifflange

-

CIGL

+

Location 6

@@ -314,8 +314,7 @@

Gesamt Tag: 32
- Portal +

@@ -323,8 +322,7 @@

Gesamt Tag: 32
- Portal +

@@ -385,7 +383,7 @@

Gesamt Tag: 32 Date: Wed, 2 Aug 2017 14:47:43 +0200 Subject: [PATCH 17/54] #330 remove simulation, add REST set value (method get for send with command line curl value in scadaLTS) --- .../war/WebContent/META-INF/MANIFEST.MF | 3 - .../war/WebContent/WEB-INF/web.xml | 3 - ScadaLTS-Simulation/war/WebContent/index.html | 294 ------------------ .../scada_lts/web/mvc/api/PointValueAPI.java | 33 ++ 4 files changed, 33 insertions(+), 300 deletions(-) delete mode 100644 ScadaLTS-Simulation/war/WebContent/META-INF/MANIFEST.MF delete mode 100644 ScadaLTS-Simulation/war/WebContent/WEB-INF/web.xml delete mode 100644 ScadaLTS-Simulation/war/WebContent/index.html diff --git a/ScadaLTS-Simulation/war/WebContent/META-INF/MANIFEST.MF b/ScadaLTS-Simulation/war/WebContent/META-INF/MANIFEST.MF deleted file mode 100644 index 254272e1c0..0000000000 --- a/ScadaLTS-Simulation/war/WebContent/META-INF/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -Class-Path: - diff --git a/ScadaLTS-Simulation/war/WebContent/WEB-INF/web.xml b/ScadaLTS-Simulation/war/WebContent/WEB-INF/web.xml deleted file mode 100644 index 91687fac77..0000000000 --- a/ScadaLTS-Simulation/war/WebContent/WEB-INF/web.xml +++ /dev/null @@ -1,3 +0,0 @@ - -index.html - \ No newline at end of file diff --git a/ScadaLTS-Simulation/war/WebContent/index.html b/ScadaLTS-Simulation/war/WebContent/index.html deleted file mode 100644 index bc4c21e0ea..0000000000 --- a/ScadaLTS-Simulation/war/WebContent/index.html +++ /dev/null @@ -1,294 +0,0 @@ - - - - - - - - - - - - - -
-
-
- - Simulation - -
-
-
- Simulation - -
-
-
-
-
- -
- -
-

Simulation monitoring of fuel consumption in the generator

-
-
-

- -
-
-
- - -
-
-
-
-
- - \ No newline at end of file diff --git a/src/org/scada_lts/web/mvc/api/PointValueAPI.java b/src/org/scada_lts/web/mvc/api/PointValueAPI.java index f98e450768..5ff89efdc3 100644 --- a/src/org/scada_lts/web/mvc/api/PointValueAPI.java +++ b/src/org/scada_lts/web/mvc/api/PointValueAPI.java @@ -380,6 +380,39 @@ public ResponseEntity setValue( } } + /** + * @param xid + * @param type (0 - binary, 1 - multistate, 2 - double, 3 - string) + * @param value (for binary [0,1] + * @param request + * @return + */ + @RequestMapping(value = "/api/point_value/setValue/{xid}/{type}/{value}", method = RequestMethod.GET) + public ResponseEntity setValueGet( + @PathVariable("xid") String xid, + @PathVariable("type") int type, + @PathVariable("value") String value, + HttpServletRequest request) { + + LOG.info("/api/point_value/setValue/{xid}/{type}/{value} xid:"+xid+" type:"+type+" value:"+value); + + try { + User user = Common.getUser(request); + if (user != null) { + + dataPointService.save(value, xid, type); + + return new ResponseEntity(value,HttpStatus.OK); + } + + return new ResponseEntity(HttpStatus.UNAUTHORIZED); + + } catch (Exception e) { + LOG.error(e); + return new ResponseEntity(HttpStatus.BAD_REQUEST); + } + } + /** From 8500b006a9c65fe0e130f4f7e7b3c4a72fcad3d9 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Wed, 2 Aug 2017 15:14:37 +0200 Subject: [PATCH 18/54] #332 Simulation 1 - ready component --- .../styles.scssc | Bin 0 -> 20283 bytes .../war/WebContent/index.html | 134 +++++++++++------- .../war/WebContent/preloader.gif | Bin 0 -> 13999 bytes ScadaLTS-Simulation1/war/WebContent/style.css | 19 ++- .../war/WebContent/style.css.map | 7 + .../war/WebContent/styles.scss | 22 ++- .../war/WebContent/values.txt | 7 + 7 files changed, 131 insertions(+), 58 deletions(-) create mode 100644 ScadaLTS-Simulation1/war/WebContent/.sass-cache/75fa2e9602e01a1d5fd59f17f46e0c71338a5795/styles.scssc create mode 100644 ScadaLTS-Simulation1/war/WebContent/preloader.gif create mode 100644 ScadaLTS-Simulation1/war/WebContent/style.css.map create mode 100644 ScadaLTS-Simulation1/war/WebContent/values.txt diff --git a/ScadaLTS-Simulation1/war/WebContent/.sass-cache/75fa2e9602e01a1d5fd59f17f46e0c71338a5795/styles.scssc b/ScadaLTS-Simulation1/war/WebContent/.sass-cache/75fa2e9602e01a1d5fd59f17f46e0c71338a5795/styles.scssc new file mode 100644 index 0000000000000000000000000000000000000000..5353a13cd9a947e49b09b427b49aab579c630362 GIT binary patch literal 20283 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 aF#qDfQ(K0%9|5Bp7I*9lx|;LE!~X|sqz0M* literal 0 HcmV?d00001 diff --git a/ScadaLTS-Simulation1/war/WebContent/index.html b/ScadaLTS-Simulation1/war/WebContent/index.html index 5b65e4a48c..a598c40942 100644 --- a/ScadaLTS-Simulation1/war/WebContent/index.html +++ b/ScadaLTS-Simulation1/war/WebContent/index.html @@ -12,7 +12,6 @@ - @@ -21,16 +20,16 @@
- Simulation Model View +
- RECY + @@ -42,6 +41,7 @@
+

Gesamt Tag: 32

Schließen

-
@@ -60,7 +59,7 @@

Schließen

-

Location 1

+

@@ -70,19 +69,19 @@

Location 1

Akt. St:
- 2 + 0
Verg. St:
- 2#/h + 0
Akt. Tg:
- 4 + 0

@@ -100,7 +99,7 @@

Location 1

-

Location 2

+

@@ -110,19 +109,19 @@

Location 2

Akt. St:
- 2 + 0
Verg. St:
- 2#/h + 0
Akt. Tg:
- 4 + 0
@@ -140,7 +139,7 @@

Location 2

-

Location 3

+

@@ -150,19 +149,19 @@

Location 3

Akt. St:
- 2 + 0
Verg. St:
- 2#/h + 0
Akt. Tg:
- 4 + 0
@@ -180,7 +179,7 @@

Location 3

-

Location 4

+

@@ -190,19 +189,19 @@

Location 4

Akt. St:
- 2 + 0
Verg. St:
- 2#/h + 0
Akt. Tg:
- 4 + 0
@@ -220,7 +219,7 @@

Location 4

-

Location 5

+

@@ -230,19 +229,19 @@

Location 5

Akt. St:
- 2 + 0
Verg. St:
- 2#/h + 0
Akt. Tg:
- 4 + 0
@@ -260,7 +259,7 @@

Location 5

-

Location 6

+

@@ -270,19 +269,19 @@

Location 6

Akt. St:
- 2 + 0
Verg. St:
- 2#/h + 0
Akt. Tg:
- 4 + 0
@@ -296,25 +295,14 @@

Location 6

- -
-
-
-
-

Gesamt Tag: 32

-
-
- -
- -
- + Camera1
@@ -322,7 +310,8 @@

Gesamt Tag: 32
- + Camera2

@@ -344,8 +333,39 @@

Gesamt Tag: 32 diff --git a/ScadaLTS-Simulation1/war/WebContent/style.css b/ScadaLTS-Simulation1/war/WebContent/style.css index 535c2202f7..f0ed3a0324 100644 --- a/ScadaLTS-Simulation1/war/WebContent/style.css +++ b/ScadaLTS-Simulation1/war/WebContent/style.css @@ -1,6 +1,10 @@ +@import url(https://fonts.googleapis.com/css?family=Roboto+Condensed:300|Oswald); main-theme { background-color: green; } +.mdl-cell { + float: left; } + .mdl-card { width: 100%; min-height: 20px; } @@ -42,10 +46,16 @@ main-theme { .logo { position: fixed; - margin: 10px; - right: 20px; - top: 0px; - display: inline; } + max-height: 80px; + margin-left: 20px; + left: 35%; + top: 3px; } + @media screen and (max-width: 1366px) { + .logo { + left: 25%; } } + @media screen and (max-width: 840px) { + .logo { + left: 10%; } } .center-element { width: 60%; diff --git a/ScadaLTS-Simulation1/war/WebContent/styles.scss b/ScadaLTS-Simulation1/war/WebContent/styles.scss index 100cd76853..b04e46b943 100644 --- a/ScadaLTS-Simulation1/war/WebContent/styles.scss +++ b/ScadaLTS-Simulation1/war/WebContent/styles.scss @@ -4,9 +4,14 @@ $theme_main_color_dark: #004100; $header_font_size: 25px; $card_height: 60px; +@import url(https://fonts.googleapis.com/css?family=Roboto+Condensed:300|Oswald); + main-theme { background-color: $theme_main_color; } +.mdl-cell { + float: left; +} .mdl-card { width: 100%; @@ -53,13 +58,19 @@ main-theme { #clock { margin-bottom: 15px; } + .logo { position: fixed; - margin: 10px; - right: 20px; - top: 0px; - display: inline; - + max-height: 80px; + margin-left: 20px; + left: 35%; + top: 3px; + @media screen and (max-width: 1366px) { + left: 25%; + } + @media screen and (max-width: 840px) { + left: 10%; + } } .center-element { width: 60%; From b5c8dbbc66f5c70c4211f8b92ca28f98cdba5777 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Fri, 4 Aug 2017 10:14:15 +0200 Subject: [PATCH 24/54] #332 Simulation 1 - login and authorization service --- .../war/WebContent/index.html | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/ScadaLTS-Simulation1/war/WebContent/index.html b/ScadaLTS-Simulation1/war/WebContent/index.html index ae707ede74..c69768164b 100644 --- a/ScadaLTS-Simulation1/war/WebContent/index.html +++ b/ScadaLTS-Simulation1/war/WebContent/index.html @@ -15,7 +15,7 @@ - +
@@ -344,47 +344,50 @@

navTitle: "Navigation", cardDescription: ["All day: ", "Enable/Disable", "Current Hour", "Last Hour", "Current Day"], logoSrc: "logo.png", - enableButtonDSxid: "DP_712941" + enableButtonDSxid: "DP_363479" } var cardsData = { card: [ { title: "Location 1", - dataPointXID: "DP_643745" + dataPointXID: " DP_121807" }, { title: "Location 2", - dataPointXID: "DP_969596" + dataPointXID: "DP_331412" }, { title: "Location 3", - dataPointXID: "DP_842922" + dataPointXID: "DP_331412" }, { title: "Location 4", - dataPointXID: "DP_934891" + dataPointXID: "DP_331412" }, { title: "Location 5", - dataPointXID: "DP_249754" + dataPointXID: "DP_331412" }, { title: "Location 6", - dataPointXID: "DP_822413" + dataPointXID: "DP_331412" }, ] } var cameraSrc = ["cam.png", "cam.png"]; + + var username; + var password; /** * Init * Initialization of webContent - values and names loading; */ function init() { - + document.getElementById("mainTitle").innerHTML = viewConfiguration.mainTitle; document.getElementById("navTitle").innerHTML = viewConfiguration.navTitle; @@ -411,6 +414,13 @@

document.getElementById("cardTitle4").innerHTML = cardsData.card[3].title; document.getElementById("cardTitle5").innerHTML = cardsData.card[4].title; document.getElementById("cardTitle6").innerHTML = cardsData.card[5].title; + + var url_string = window.location; + var url = new URL(url_string); + username = url.searchParams.get("username"); + password = url.searchParams.get("pass"); + + login(username, password); } @@ -451,12 +461,10 @@

var allEntires = []; function login(username, password) { - $.get("../ScadaBR/api/auth/" + "admin" + "/" + "admin", function (data) { + $.get("../ScadaBR/api/auth/" + username + "/" + password, function (data) { console.log(data); }); - init(); - startTime(); updateView(); checkCheckBox(); @@ -477,9 +485,9 @@

contentType: "application/text;charset=utf-8", dataType: "json", success: function (data) { - console.log("succsess!" + xid) + //console.log("succsess!" + xid) }, - error: function (ts) { alert(ts.responseText) } + error: function (ts) { alert("DataPoint not found!\n - Error during establishing connection") } }); } @@ -535,7 +543,7 @@

*/ function updateView() { - console.log(date); + //console.log(date); updateCardData('6'); updateCardData('5'); updateCardData('4'); From 97683311338df691e3248ca2462edb184dc31611 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Sat, 12 Aug 2017 12:16:05 +0200 Subject: [PATCH 25/54] #332 Simulation, button fix and added scheduler --- ScadaLTS-Simulation1/war/WebContent/index.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ScadaLTS-Simulation1/war/WebContent/index.html b/ScadaLTS-Simulation1/war/WebContent/index.html index c69768164b..18d2208db5 100644 --- a/ScadaLTS-Simulation1/war/WebContent/index.html +++ b/ScadaLTS-Simulation1/war/WebContent/index.html @@ -344,7 +344,11 @@

navTitle: "Navigation", cardDescription: ["All day: ", "Enable/Disable", "Current Hour", "Last Hour", "Current Day"], logoSrc: "logo.png", - enableButtonDSxid: "DP_363479" + enableButtonDSxid: "DP_558690", + /* weekEnableShedule [mon, tue, wed, th, fri, sat, sun] :: 0 is disable 1 is enable */ + weekEnableShedule: [0, 1, 1, 1, 1, 0, 0], + /* weekEnableHours [minHour, maxHour] :: when time is beatween this values DS is enabled */ + weekEnableHours: [9, 17] } var cardsData = { From 9e027bcb8fd62075340e30b48642ab913fe2f409 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Sat, 12 Aug 2017 13:30:24 +0200 Subject: [PATCH 26/54] #332 Simulation - Added flexible page generating --- .../war/WebContent/index.html | 436 ++++++------------ 1 file changed, 131 insertions(+), 305 deletions(-) diff --git a/ScadaLTS-Simulation1/war/WebContent/index.html b/ScadaLTS-Simulation1/war/WebContent/index.html index 18d2208db5..8b12637417 100644 --- a/ScadaLTS-Simulation1/war/WebContent/index.html +++ b/ScadaLTS-Simulation1/war/WebContent/index.html @@ -36,7 +36,7 @@
-
+
@@ -57,276 +57,38 @@

- - -
-
-
-
-

-
-
-
-
-
-
- -
-
- 0 -
-
- -
-
- 0 -
-
- -
-
- 0 -
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
-

-
-
-
-
-
-
- -
-
- 0 -
-
- -
-
- 0 -
-
- -
-
- 0 -
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
-

-
-
-
-
-
-
- -
-
- 0 -
-
- -
-
- 0 -
-
- -
-
- 0 -
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
-

-
-
-
-
-
-
- -
-
- 0 -
-
- -
-
- 0 -
-
- -
-
- 0 -
-
- -
-
-
-
- +
+
+ +
+
+
+
+
+ Camera1
-
+
-
- -
-
-
-
-

+
+
+
+
+ Camera2
-
-
-
-
-
- -
-
- 0 -
-
- -
-
- 0 -
-
- -
-
- 0 -
-
- -
-
-
-
- -
-
+
-
- -
-
-
-
-

-
-
-
-
-
-
- -
-
- 0 -
-
- -
-
- 0 -
-
- -
-
- 0 -
-
-
-
-
-
- -
-
-
- -
-
-
-
-
- Camera1 +
+
+ -
-
-
-
-
- Camera2 -
-
-
- +
-
- -
-
@@ -355,49 +117,57 @@

card: [ { title: "Location 1", - dataPointXID: " DP_121807" + dataPointXID: "DP_260255" }, { title: "Location 2", - dataPointXID: "DP_331412" + dataPointXID: "DP_260255" }, { title: "Location 3", - dataPointXID: "DP_331412" + dataPointXID: "DP_260255" }, { title: "Location 4", - dataPointXID: "DP_331412" + dataPointXID: "DP_843430" }, { title: "Location 5", - dataPointXID: "DP_331412" + dataPointXID: "DP_843430" }, { title: "Location 6", - dataPointXID: "DP_331412" + dataPointXID: "DP_843430" }, ] } var cameraSrc = ["cam.png", "cam.png"]; - + var username; var password; + for (var i = 1; i <= cardsData.card.length; i++) { + $('

0
0
0
').appendTo('#locationsection'); + } + /** * Init * Initialization of webContent - values and names loading; */ function init() { - + document.getElementById("mainTitle").innerHTML = viewConfiguration.mainTitle; document.getElementById("navTitle").innerHTML = viewConfiguration.navTitle; document.getElementById("current-day-all-label").innerHTML = viewConfiguration.cardDescription[0]; document.getElementById("enable-switch-label").innerHTML = viewConfiguration.cardDescription[1]; + for (var i = 1; i <= cardsData.card.length; i++) { + document.getElementById("cardTitle" + i).innerHTML = cardsData.card[i - 1].title; + } + var currHourList = document.getElementsByClassName("current-hour-label"); var prevHourList = document.getElementsByClassName("previous-hour-label"); var currDayList = document.getElementsByClassName("current-day-label"); @@ -412,18 +182,11 @@

document.getElementById("liveStream1").setAttribute('src', cameraSrc[0]); document.getElementById("liveStream2").setAttribute('src', cameraSrc[1]); - document.getElementById("cardTitle1").innerHTML = cardsData.card[0].title; - document.getElementById("cardTitle2").innerHTML = cardsData.card[1].title; - document.getElementById("cardTitle3").innerHTML = cardsData.card[2].title; - document.getElementById("cardTitle4").innerHTML = cardsData.card[3].title; - document.getElementById("cardTitle5").innerHTML = cardsData.card[4].title; - document.getElementById("cardTitle6").innerHTML = cardsData.card[5].title; - var url_string = window.location; var url = new URL(url_string); username = url.searchParams.get("username"); password = url.searchParams.get("pass"); - + login(username, password); } @@ -434,7 +197,7 @@

function startTime() { var today = new Date(); var d = today.getDate(); - var mo = today.getMonth(); + var mo = today.getMonth() + 1; var y = today.getFullYear(); var h = today.getHours(); var m = today.getMinutes(); @@ -459,6 +222,14 @@

return i; } + function sum(points) { + return points.reduce( + function (sum, current) { + return parseInt(sum) + parseInt(current); + }, 0 + ); + } + /* * SCADA Functions */ @@ -471,6 +242,7 @@

startTime(); updateView(); + openingShedule(); checkCheckBox(); } @@ -533,13 +305,15 @@

} allEntires[htmlid] = day_points.length; - document.getElementById("current-hour-data-" + htmlid).innerHTML = hour_points.length; - document.getElementById("previous-hour-data-" + htmlid).innerHTML = last_hour_points.length; - document.getElementById("current-day-data-" + htmlid).innerHTML = day_points.length; + document.getElementById("current-hour-data-" + htmlid).innerHTML = sum(hour_points); + document.getElementById("previous-hour-data-" + htmlid).innerHTML = sum(last_hour_points); + document.getElementById("current-day-data-" + htmlid).innerHTML = sum(day_points); }); } + + /** * Update HTML View * Refresh data in every card by running updateCardData() @@ -574,45 +348,97 @@

// console.log(JSON.parse(data).value == 'true'); var x = (JSON.parse(data).value == 'true'); - var buttonsList = document.getElementsByClassName("mdl-button"); - var sw = document.getElementsByClassName("switch-1"); + changeSwitch(x); - sw.checked = x; - for (var i = 0; i < buttonsList.length; i++) { - buttonsList[i].disabled = !x; - } - if (x == false) { - $("#labelCheckbox").removeClass("is-checked"); - } else { - $("#labelCheckbox").addClass("is-checked"); - } }); } + /** + * ChangeSwitch + * @param x - enable/disable button + */ + function changeSwitch(x) { + + var buttonsList = document.getElementsByClassName("mdl-button"); + var sw = document.getElementsByClassName("switch-1"); + + sw.checked = x; + for (var i = 0; i < buttonsList.length; i++) { + buttonsList[i].disabled = !x; + } + if (x == false) { + $("#labelCheckbox").removeClass("is-checked"); + } else { + $("#labelCheckbox").addClass("is-checked"); + } + + } + /** * postCheckBox * Send a POST with actual state of selected checkbox * @callback - invoking checkbox - onClick method */ + var globalType; function postCheckBox(callback) { var xid = viewConfiguration.enableButtonDSxid; - var type = 0; - if (callback.checked) { - type = 1; + try { + globalType = callback.checked; + console.log(globalType); + } catch (err) { + console.log(err); + } + var number = 0; + changeSwitch(globalType); + if (globalType) { + number = 1; } - $.ajax({ - type: "POST", - url: "../ScadaBR/api/point_value/setValue/" + xid + "/0/" + type, - contentType: "application/text;charset=utf-8", - dataType: "json", - success: function (data) { - console.log("succsess Change!" + xid) - }, - error: function (ts) { alert(ts.responseText) } - }); + $.post( + "../ScadaBR/api/point_value/setValue/" + xid + "/0/" + number, function (data) { + console.log(data); + } + ); + // $.ajax({ + // type: "POST", + // url: "../ScadaBR/api/point_value/setValue/" + xid + "/0/" + globalType, + // contentType: "application/text;charset=utf-8", + // dataType: "json", + // success: function (data) { + // console.log(data); + // }, + // error: function (ts) { alert("DataPoint not found!\n - Error during establishing connection") } + // }); + + } + + /** + * openingShedule + * When this counter should be active. Disable buttons and data source + * if this side is opened on the wrong day or wrong time + */ + function openingShedule() { + var today = new Date(); + var d = today.getDay() - 1; + var h = today.getHours(); + var request = { checked: true }; + request.checked = Boolean('true'); + + var x = viewConfiguration; + var t = setTimeout(openingShedule, 12000000); + + if (viewConfiguration.weekEnableShedule[d] == 1) { + if (viewConfiguration.weekEnableHours[0] < h && h < viewConfiguration.weekEnableHours[1]) { + postCheckBox(request); + checkCheckBox(); + return; + } + } + + request.checked = false; + postCheckBox(request); } From 0babaedf8aac70f2cb634cd9cbd109a7d2e675ca Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Mon, 7 Aug 2017 15:41:08 +0200 Subject: [PATCH 27/54] #332 Simulation: Added - edit dialog to change parameters --- .../war/WebContent/index.html | 82 ++++++++++++++++++- ScadaLTS-Simulation1/war/WebContent/style.css | 45 ++++++++++ .../war/WebContent/styles.scss | 40 +++++++++ 3 files changed, 166 insertions(+), 1 deletion(-) diff --git a/ScadaLTS-Simulation1/war/WebContent/index.html b/ScadaLTS-Simulation1/war/WebContent/index.html index 8b12637417..fc813cbc59 100644 --- a/ScadaLTS-Simulation1/war/WebContent/index.html +++ b/ScadaLTS-Simulation1/war/WebContent/index.html @@ -90,6 +90,26 @@

+ + +

Edit element

+
+
+ + +
+
+ + +
+
+
+ + + +
+
+
@@ -139,6 +159,30 @@

title: "Location 6", dataPointXID: "DP_843430" }, + { + title: "Location 7", + dataPointXID: "DP_260255" + }, + { + title: "Location 8", + dataPointXID: "DP_260255" + }, + { + title: "Location 9", + dataPointXID: "DP_260255" + }, + { + title: "Location 10", + dataPointXID: "DP_843430" + }, + { + title: "Location 11", + dataPointXID: "DP_843430" + }, + { + title: "Location 12", + dataPointXID: "DP_843430" + } ] } @@ -147,9 +191,11 @@

var username; var password; + + var currentLocation = 0; for (var i = 1; i <= cardsData.card.length; i++) { - $('

0
0
0
').appendTo('#locationsection'); + $('

0
0
0
').appendTo('#locationsection'); } /** @@ -229,6 +275,16 @@

}, 0 ); } + + (function () { + 'use strict'; + var dialogButton = document.querySelector('.dialog-button'); + + dialog.querySelector('button:not([disabled])') + .addEventListener('click', function () { + dialog.close(); + }); + }()); /* * SCADA Functions @@ -441,6 +497,30 @@

postCheckBox(request); } + + function editLocation(x) { + currentLocation = x; + var dialog = document.querySelector('#dialog'); + if (!dialog.showModal) { + dialogPolyfill.registerDialog(dialog); + } + dialog.showModal(); + + document.getElementById('nameField').value = cardsData.card[currentLocation - 1].title; + document.getElementById('xidField').value = cardsData.card[currentLocation - 1].dataPointXID; + + } + + function saveData() { + var nameField = document.getElementById('nameField').value; + var xidField = document.getElementById('xidField').value; + + cardsData.card[currentLocation - 1].title = nameField; + cardsData.card[currentLocation - 1].dataPointXID = xidField; + + document.getElementById("cardTitle" + currentLocation).innerHTML = cardsData.card[currentLocation - 1].title; + + } diff --git a/ScadaLTS-Simulation1/war/WebContent/style.css b/ScadaLTS-Simulation1/war/WebContent/style.css index f0ed3a0324..23d12b0596 100644 --- a/ScadaLTS-Simulation1/war/WebContent/style.css +++ b/ScadaLTS-Simulation1/war/WebContent/style.css @@ -31,6 +31,51 @@ main-theme { .mdl-switch.is-checked .mdl-switch__track { background-color: rgba(0, 128, 0, 0.5); } +.mdl-dialog { + border: none; + box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2); + width: 280px; } + +.mdl-dialog__title { + padding: 24px 24px 0; + margin: 0; + font-size: 2.5rem; } + +.mdl-dialog__actions { + padding: 8px 8px 8px 24px; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row-reverse; + -ms-flex-direction: row-reverse; + flex-direction: row-reverse; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; } + +.mdl-dialog__actions > * { + margin-right: 8px; + height: 36px; } + +.mdl-dialog__actions > *:first-child { + margin-right: 0; } + +.mdl-dialog__actions--full-width { + padding: 0 0 8px 0; } + +.mdl-dialog__actions--full-width > * { + height: 48px; + -webkit-flex: 0 0 100%; + -ms-flex: 0 0 100%; + flex: 0 0 100%; + padding-right: 16px; + margin-right: 0; + text-align: right; } + +.mdl-dialog__content { + padding: 20px 24px 24px 24px; + color: rgba(0, 0, 0, 0.54); } + .mdl-layout-title, #clock { margin-top: 10px; display: inline-block; diff --git a/ScadaLTS-Simulation1/war/WebContent/styles.scss b/ScadaLTS-Simulation1/war/WebContent/styles.scss index b04e46b943..9d773aad5f 100644 --- a/ScadaLTS-Simulation1/war/WebContent/styles.scss +++ b/ScadaLTS-Simulation1/war/WebContent/styles.scss @@ -45,6 +45,46 @@ main-theme { .mdl-switch.is-checked .mdl-switch__track { background-color: rgba(0, 128, 0, 0.5); } + +.mdl-dialog { + border: none; + box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2); + width: 280px; } + .mdl-dialog__title { + padding: 24px 24px 0; + margin: 0; + font-size: 2.5rem; } + .mdl-dialog__actions { + padding: 8px 8px 8px 24px; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row-reverse; + -ms-flex-direction: row-reverse; + flex-direction: row-reverse; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; } + .mdl-dialog__actions > * { + margin-right: 8px; + height: 36px; } + .mdl-dialog__actions > *:first-child { + margin-right: 0; } + .mdl-dialog__actions--full-width { + padding: 0 0 8px 0; } + .mdl-dialog__actions--full-width > * { + height: 48px; + -webkit-flex: 0 0 100%; + -ms-flex: 0 0 100%; + flex: 0 0 100%; + padding-right: 16px; + margin-right: 0; + text-align: right; } + .mdl-dialog__content { + padding: 20px 24px 24px 24px; + color: rgba(0,0,0, 0.54); } + + .mdl-layout-title , #clock{ margin-top: 10px; display: inline-block; From d138ea85a6c3f1d8afa96f9becb068ac7dd13429 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Mon, 7 Aug 2017 15:56:52 +0200 Subject: [PATCH 28/54] #332 - Simulation: added icons --- .../war/WebContent/index.html | 56 +++---------------- 1 file changed, 7 insertions(+), 49 deletions(-) diff --git a/ScadaLTS-Simulation1/war/WebContent/index.html b/ScadaLTS-Simulation1/war/WebContent/index.html index fc813cbc59..62be0c7b66 100644 --- a/ScadaLTS-Simulation1/war/WebContent/index.html +++ b/ScadaLTS-Simulation1/war/WebContent/index.html @@ -42,7 +42,7 @@
-

0

+

people 0

@@ -94,11 +94,11 @@

Edit element

-
+
-
+
@@ -146,42 +146,6 @@

Edit element

{ title: "Location 3", dataPointXID: "DP_260255" - }, - { - title: "Location 4", - dataPointXID: "DP_843430" - }, - { - title: "Location 5", - dataPointXID: "DP_843430" - }, - { - title: "Location 6", - dataPointXID: "DP_843430" - }, - { - title: "Location 7", - dataPointXID: "DP_260255" - }, - { - title: "Location 8", - dataPointXID: "DP_260255" - }, - { - title: "Location 9", - dataPointXID: "DP_260255" - }, - { - title: "Location 10", - dataPointXID: "DP_843430" - }, - { - title: "Location 11", - dataPointXID: "DP_843430" - }, - { - title: "Location 12", - dataPointXID: "DP_843430" } ] @@ -195,7 +159,7 @@

Edit element

var currentLocation = 0; for (var i = 1; i <= cardsData.card.length; i++) { - $('

0
0
0
').appendTo('#locationsection'); + $('

schedule
0
restore
0
today
0
').appendTo('#locationsection'); } /** @@ -368,8 +332,6 @@

Edit element

}); } - - /** * Update HTML View * Refresh data in every card by running updateCardData() @@ -378,15 +340,11 @@

Edit element

function updateView() { //console.log(date); - updateCardData('6'); - updateCardData('5'); - updateCardData('4'); - updateCardData('3'); - updateCardData('2'); - updateCardData('1'); + for (var i = 1; i <= cardsData.card.length; i++) { + updateCardData(i); + } checkCheckBox(); - allEntires2 = allEntires.reduce((pv, cv) => pv + cv, 0); document.getElementById("allEntires").innerHTML = allEntires2; From 6a6809ed1541b0702fe80510423e191583976112 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Tue, 8 Aug 2017 10:05:08 +0200 Subject: [PATCH 29/54] #332 Simulation: Added modification menu. --- ScadaLTS-Simulation1/war/WebContent/config.js | 11 ++ ScadaLTS-Simulation1/war/WebContent/data.js | 16 +++ .../war/WebContent/index.html | 127 ++++++++++++------ .../war/WebContent/{ => resources}/style.css | 3 + .../WebContent/{ => resources}/styles.scss | 3 + 5 files changed, 117 insertions(+), 43 deletions(-) create mode 100644 ScadaLTS-Simulation1/war/WebContent/config.js create mode 100644 ScadaLTS-Simulation1/war/WebContent/data.js rename ScadaLTS-Simulation1/war/WebContent/{ => resources}/style.css (98%) rename ScadaLTS-Simulation1/war/WebContent/{ => resources}/styles.scss (99%) diff --git a/ScadaLTS-Simulation1/war/WebContent/config.js b/ScadaLTS-Simulation1/war/WebContent/config.js new file mode 100644 index 0000000000..262d3d4fba --- /dev/null +++ b/ScadaLTS-Simulation1/war/WebContent/config.js @@ -0,0 +1,11 @@ +var viewConfiguration = { + mainTitle: "ScadaLTS View", + navTitle: "Navigation", + cardDescription: ["All day: ", "Enable/Disable", "Current Hour", "Last Hour", "Current Day"], + logoSrc: "resources/logo.png", + enableButtonDSxid: "DP_558690", + /* weekEnableShedule [mon, tue, wed, th, fri, sat, sun] :: 0 is disable 1 is enable */ + weekEnableShedule: [0, 1, 1, 1, 1, 0, 0], + /* weekEnableHours [minHour, maxHour] :: when time is beatween this values DS is enabled */ + weekEnableHours: [9, 17] +} \ No newline at end of file diff --git a/ScadaLTS-Simulation1/war/WebContent/data.js b/ScadaLTS-Simulation1/war/WebContent/data.js new file mode 100644 index 0000000000..c4eca485d9 --- /dev/null +++ b/ScadaLTS-Simulation1/war/WebContent/data.js @@ -0,0 +1,16 @@ +var cardsData = { + card: [ + { + title: "Location 1", + dataPointXID: "DP_260255" + }, + { + title: "Location 2", + dataPointXID: "DP_260255" + }, + { + title: "Location 3", + dataPointXID: "DP_260255" + } + ] +} \ No newline at end of file diff --git a/ScadaLTS-Simulation1/war/WebContent/index.html b/ScadaLTS-Simulation1/war/WebContent/index.html index 62be0c7b66..f747fa81d7 100644 --- a/ScadaLTS-Simulation1/war/WebContent/index.html +++ b/ScadaLTS-Simulation1/war/WebContent/index.html @@ -12,7 +12,7 @@ - + @@ -29,14 +29,17 @@
- +
+ +
-
+
@@ -57,6 +60,25 @@

+
+
+
+
+

Add a new location

+ +
+
+
+
+
+ +
+
+
+
+ +
@@ -90,8 +112,8 @@

- - + +

Edit element

@@ -109,10 +131,13 @@

Edit element

- +
+ + + \ No newline at end of file From 07e5758e0df227170d4f6bb5c44d9a1c1082dc80 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Tue, 8 Aug 2017 13:02:31 +0200 Subject: [PATCH 31/54] #332 Simulation: Added - saving values to ScadaDataPoint --- ScadaLTS-Simulation1/war/WebContent/config.js | 1 + .../war/WebContent/index.html | 90 ++++++++++++++++--- ScadaLTS-Simulation1/war/build.xml | 1 + 3 files changed, 78 insertions(+), 14 deletions(-) diff --git a/ScadaLTS-Simulation1/war/WebContent/config.js b/ScadaLTS-Simulation1/war/WebContent/config.js index 262d3d4fba..7566328433 100644 --- a/ScadaLTS-Simulation1/war/WebContent/config.js +++ b/ScadaLTS-Simulation1/war/WebContent/config.js @@ -4,6 +4,7 @@ var viewConfiguration = { cardDescription: ["All day: ", "Enable/Disable", "Current Hour", "Last Hour", "Current Day"], logoSrc: "resources/logo.png", enableButtonDSxid: "DP_558690", + configLocationDSxid: "DP_558691", /* weekEnableShedule [mon, tue, wed, th, fri, sat, sun] :: 0 is disable 1 is enable */ weekEnableShedule: [0, 1, 1, 1, 1, 0, 0], /* weekEnableHours [minHour, maxHour] :: when time is beatween this values DS is enabled */ diff --git a/ScadaLTS-Simulation1/war/WebContent/index.html b/ScadaLTS-Simulation1/war/WebContent/index.html index 3e0e5d5663..05c26cef6c 100644 --- a/ScadaLTS-Simulation1/war/WebContent/index.html +++ b/ScadaLTS-Simulation1/war/WebContent/index.html @@ -65,14 +65,13 @@

Add a new location

- +
-
+
- +
@@ -161,6 +160,7 @@

Edit element

* Init * Initialization of webContent - values and names loading; */ + var firstRun = true; function init() { document.getElementById("mainTitle").innerHTML = viewConfiguration.mainTitle; @@ -193,6 +193,11 @@

Edit element

password = url.searchParams.get("pass"); login(username, password); + if (firstRun) { + loadConfigFromServer(); + firstRun = false; + } + } @@ -369,19 +374,27 @@

Edit element

*/ function addCard() { - + if (cardsData === null) { + var newCardsData = { + card: [{ + title: "Location 1", + dataPointXID: "DP_260255" + }] + }; + cardsData = newCardsData; + } cardsData.card.push({ - title:"Name...", + title: "Name...", dataPointXID: "DP_260255" }); var i = cardsData.card.length; $('

schedule
0
restore
0
today
0
').appendTo('#locationsection'); editLocation(i); init(); - - + + } - + /** * Edit Location * Edit location data - name and datasource xid @@ -412,6 +425,7 @@

Edit element

document.getElementById("cardTitle" + currentLocation).innerHTML = cardsData.card[currentLocation - 1].title; + saveConfigToServer(); } /** @@ -421,16 +435,16 @@

Edit element

*/ function deleteLocation(x) { - cardsData.card.splice(x-1,1); + cardsData.card.splice(x - 1, 1); $('#locationsection').empty(); for (var i = 1; i <= cardsData.card.length; i++) { - $('

schedule
0
restore
0
today
0
').appendTo('#locationsection'); + $('

schedule
0
restore
0
today
0
').appendTo('#locationsection'); } - init(); - + saveConfigToServer(); + init(); } /** @@ -446,7 +460,6 @@

Edit element

var x = (JSON.parse(data).value == 'true'); changeSwitch(x); - }); } @@ -533,6 +546,55 @@

Edit element

} + /** + * save Configuration to Server + * Send a POST to special alphanumeric DataPoint in ScadaLts + * with configured JSON string. + */ + function saveConfigToServer() { + + var xid = viewConfiguration.configLocationDSxid; + + var savedData = JSON.stringify(cardsData); + savedData = encodeURI(savedData); + + $.ajax({ + type: "POST", + url: "../ScadaBR/api/point_value/setValue/" + xid + "/3/" + savedData, + contentType: "application/text;charset=utf-8", + dataType: "json", + success: function (data) { + console.log(data); + }, + error: function (ts) { alert("DataPoint not found!\n - Error during establishing connection") } + }); + + } + + /** + * Load Configuration from Server + * Get a data from server DataSource with JSON configuration data + * Parse this data and save as local variable + */ + function loadConfigFromServer() { + + var xid = viewConfiguration.configLocationDSxid; + + $.get("../ScadaBR/api/point_value/getValue/" + xid, function (data) { + + console.log(data); + + var recivedValue = JSON.parse(decodeURI(data)).value; + cardsData = JSON.parse(recivedValue); + + $('#locationsection').empty(); + for (var i = 1; i <= cardsData.card.length; i++) { + $('

schedule
0
restore
0
today
0
').appendTo('#locationsection'); + } + init(); + }); + } + \ No newline at end of file diff --git a/ScadaLTS-Simulation1/war/build.xml b/ScadaLTS-Simulation1/war/build.xml index 2c7d41e3f9..ddb5455e54 100644 --- a/ScadaLTS-Simulation1/war/build.xml +++ b/ScadaLTS-Simulation1/war/build.xml @@ -9,6 +9,7 @@ + From 7b015f89b87cc49239e0e8463e64392da0806ae7 Mon Sep 17 00:00:00 2001 From: grzesiekb Date: Fri, 18 Aug 2017 13:27:32 +0200 Subject: [PATCH 32/54] #337 correcting getUserAccess --- src/com/serotonin/mango/view/View.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/com/serotonin/mango/view/View.java b/src/com/serotonin/mango/view/View.java index a631c36bdf..90bd4453f0 100644 --- a/src/com/serotonin/mango/view/View.java +++ b/src/com/serotonin/mango/view/View.java @@ -26,6 +26,8 @@ import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; +import org.scada_lts.dao.ViewDAO; + import com.serotonin.json.JsonArray; import com.serotonin.json.JsonException; import com.serotonin.json.JsonObject; @@ -129,6 +131,10 @@ public int getUserAccess(User user) { if (userId == user.getId() || user.isAdmin()) return ShareUser.ACCESS_OWNER; + if (viewUsers == null) { + viewUsers = new ViewDAO().getShareUsers(getId()); + } + for (ShareUser vu : viewUsers) { if (vu.getUserId() == user.getId()) return vu.getAccessType(); From 24928480b25966bdaaea8bc90efa2ccaf6b6ed53 Mon Sep 17 00:00:00 2001 From: grzesiekb Date: Fri, 18 Aug 2017 13:31:16 +0200 Subject: [PATCH 33/54] #337 correcting travis for build brunch with v* --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index faa5c122dc..21efba9ee4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,6 +48,7 @@ branches: - "/^develop-sdtabilit.*$/" - "/^#179*$/" - "/^master-sdtabilit.*$/" + - "/^v*$/" notifications: email: false env: From 3a2b35b5c59eb770e27f60f59daf6ee22cb43732 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Fri, 1 Sep 2017 10:29:17 +0200 Subject: [PATCH 34/54] #332_ScadaLTS-UI_to_angualr4 --- .classpath | 236 +++++++++--------- ScadaLTS-UI/angular-cli.json | 3 +- ScadaLTS-UI/package.json | 61 +++-- ScadaLTS-UI/src/app/app.module.ts | 1 - ScadaLTS-UI/src/app/app.routing.ts | 3 +- ScadaLTS-UI/src/app/appBody/appBody.module.ts | 6 +- .../app/appBody/dashboard/dashboard.module.ts | 2 +- .../src/app/appBody/views/views.component.ts | 6 +- .../appBody/watchlist/watchlist.component.ts | 2 +- .../app/appBody/watchlist/watchlist.module.ts | 2 +- .../app/registration/registration.module.ts | 2 +- ScadaLTS-UI/src/styles.css | 2 +- 12 files changed, 167 insertions(+), 159 deletions(-) diff --git a/.classpath b/.classpath index 72c44f30fb..912c741641 100644 --- a/.classpath +++ b/.classpath @@ -2,131 +2,131 @@ - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + diff --git a/ScadaLTS-UI/angular-cli.json b/ScadaLTS-UI/angular-cli.json index 9a951513d6..13fa27e2aa 100644 --- a/ScadaLTS-UI/angular-cli.json +++ b/ScadaLTS-UI/angular-cli.json @@ -26,7 +26,8 @@ "styles.css" ], "scripts": [ - "../node_modules/hammerjs/hammer.min.js" + "../node_modules/hammerjs/hammer.min.js", + "../node_modules/jquery/dist/jquery.min.js" ], "environmentSource": "environments/environment.ts", "environments": { diff --git a/ScadaLTS-UI/package.json b/ScadaLTS-UI/package.json index 00aff4472f..9cc73ddc11 100644 --- a/ScadaLTS-UI/package.json +++ b/ScadaLTS-UI/package.json @@ -12,47 +12,54 @@ }, "private": true, "dependencies": { - "@angular/common": "^2.4.10", - "@angular/compiler": "^2.4.10", - "@angular/core": "^2.4.10", - "@angular/forms": "^2.4.10", - "@angular/http": "^2.4.10", - "@angular/material": "2.0.0-beta.2", - "@angular/platform-browser": "^2.4.10", - "@angular/platform-browser-dynamic": "^2.4.10", - "@angular/router": "^3.4.10", + "@angular/animations": "^4.3.4", + "@angular/cdk": "^2.0.0-beta.8", + "@angular/common": "^4.3.4", + "@angular/compiler": "^4.3.4", + "@angular/core": "^4.3.4", + "@angular/forms": "^4.3.4", + "@angular/http": "^4.3.4", + "@angular/material": "^2.0.0-beta.8", + "@angular/platform-browser": "^4.3.4", + "@angular/platform-browser-dynamic": "^4.3.4", + "@angular/router": "^4.3.4", "@angular2-material/core": "2.0.0-alpha.8-3", "@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.22", "@types/d3-selection": "^1.0.14", "angular2-highcharts": "^0.4.3", "c3": "^0.4.11", - "core-js": "^2.4.1", + "core-js": "^2.5.0", "d3": "^4.7.4", "hammerjs": "^2.0.8", "ng2-bs3-modal": "^0.10.4", "ng2-material": "^0.8.1", "ngx-clipboard": "^3.0.7", - "rxjs": "^5.0.0-beta.12", + "rxjs": "^5.4.2", "ts-helpers": "^1.1.2", - "zone.js": "^0.6.26" + "zone.js": "^0.8.16", + "@scadalts/scadalts-dashbord-components": "0.0.7" }, "devDependencies": { - "@angular/cli": "1.0.0", - "@angular/compiler-cli": "^2.1.0", - "@types/jasmine": "2.2.30", - "@types/node": "^6.0.42", - "codelyzer": "~1.0.0-beta.3", - "jasmine-core": "2.4.1", - "jasmine-spec-reporter": "2.5.0", - "karma": "1.2.0", - "karma-chrome-launcher": "^2.0.0", - "karma-cli": "^1.0.1", - "karma-jasmine": "^1.0.2", + "@angular/cli": "1.3.0", + "@angular/compiler-cli": "^4.3.4", + "@angular/language-service": "^4.3.4", + "@types/jasmine": "~2.5.53", + "@types/jasminewd2": "~2.0.2", + "@types/jquery": "^3.2.12", + "@types/node": "~8.0.20", + "codelyzer": "~3.1.1", + "jasmine-core": "~2.7.0", + "jasmine-spec-reporter": "~4.2.1", + "karma": "^1.7.0", + "karma-chrome-launcher": "~2.2.0", + "karma-cli": "~1.0.1", + "karma-jasmine": "~1.1.0", + "karma-jasmine-html-reporter": "^0.2.2", "karma-remap-istanbul": "^0.2.1", - "protractor": "4.0.9", - "ts-node": "1.2.1", - "tslint": "3.13.0", - "typescript": "~2.0.3", + "protractor": "~5.1.2", + "ts-node": "~3.3.0", + "tslint": "~5.6.0", + "typescript": "~2.4.2", "webdriver-manager": "10.2.5" } } diff --git a/ScadaLTS-UI/src/app/app.module.ts b/ScadaLTS-UI/src/app/app.module.ts index d7a09c5a57..69ea482d2b 100644 --- a/ScadaLTS-UI/src/app/app.module.ts +++ b/ScadaLTS-UI/src/app/app.module.ts @@ -88,7 +88,6 @@ import { UserAuthenticationService } from './UserAuthenticationService'; FormsModule, ReactiveFormsModule, HttpModule, - MaterialModule.forRoot(), MaterialModule, routing, NgbModule.forRoot(), diff --git a/ScadaLTS-UI/src/app/app.routing.ts b/ScadaLTS-UI/src/app/app.routing.ts index 2d9e490c78..9080b206c1 100644 --- a/ScadaLTS-UI/src/app/app.routing.ts +++ b/ScadaLTS-UI/src/app/app.routing.ts @@ -30,7 +30,8 @@ import { WleditComponent } from './appBody/wledit/wledit.component'; import { WorksheetAccessGuard } from './ActivationGuard'; const appRoutes: Routes = [ - { path: '', component: LoginComponent }, + // { path: '', component: LoginComponent }, + { path: '', redirectTo: 'appBody', pathMatch: 'full' }, { path: 'registration', component: RegistrationComponent }, { path: 'appBody', component: AppBodyComponent, children: [ diff --git a/ScadaLTS-UI/src/app/appBody/appBody.module.ts b/ScadaLTS-UI/src/app/appBody/appBody.module.ts index 7450126f91..ce44e91442 100644 --- a/ScadaLTS-UI/src/app/appBody/appBody.module.ts +++ b/ScadaLTS-UI/src/app/appBody/appBody.module.ts @@ -2,7 +2,8 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpModule } from '@angular/http'; -import { MaterialModule } from '@angular/material'; +import { MdIconModule } from '@angular/material'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { AppBodyComponent } from './appBody.component'; import { ScriptingComponent } from './scripting/scripting.component'; @@ -15,9 +16,8 @@ import { ScriptingComponent } from './scripting/scripting.component'; BrowserModule, FormsModule, HttpModule, - MaterialModule.forRoot() + MdIconModule ], - providers: [], bootstrap: [AppBodyComponent] }) export class AppModule { } diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard.module.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard.module.ts index 4e10caf866..c6692b220c 100644 --- a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard.module.ts +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard.module.ts @@ -13,7 +13,7 @@ import { DashboardComponent } from './dashboard.component'; BrowserModule, FormsModule, HttpModule, - MaterialModule.forRoot() + MaterialModule ], providers: [], bootstrap: [DashboardComponent] diff --git a/ScadaLTS-UI/src/app/appBody/views/views.component.ts b/ScadaLTS-UI/src/app/appBody/views/views.component.ts index b02f75d1fe..989531e3de 100644 --- a/ScadaLTS-UI/src/app/appBody/views/views.component.ts +++ b/ScadaLTS-UI/src/app/appBody/views/views.component.ts @@ -20,7 +20,7 @@ export class ViewsComponent implements OnInit { openDlgSelectViewWithEdtHierarchyView(){ - let dialogRef = this.dialogSelectViewWithEdtHierarchyView.open(DlgSelectViewWithEdtHierarchyView, this.dialogSelectViewWithEdtHierarchyView); + let dialogRef = this.dialogSelectViewWithEdtHierarchyView.open(DlgSelectViewWithEdtHierarchyView); dialogRef.afterClosed().subscribe(result => { this.viewKey = result; console.log(this.viewKey); @@ -251,7 +251,7 @@ export class DlgSelectViewWithEdtHierarchyView { } openDlgAddFolderHierarchyView(){ - let dialogRef = this.dialogAddFolderHierarchyView.open(DlgAddFolderHierarchyView, this.dialogAddFolderHierarchyView); + let dialogRef = this.dialogAddFolderHierarchyView.open(DlgAddFolderHierarchyView); dialogRef.afterClosed().subscribe(result => { this.rerfreshTree() }); @@ -259,7 +259,7 @@ export class DlgSelectViewWithEdtHierarchyView { deleteFolderHierarchyView(){ if ($("#tree").fancytree("getTree").getActiveNode().folder) { - let dialogRef = this.dialogConfirmDeleteFolderHierarchyView.open(DlgConfirmDeleteFolderHierarchyView, this.dialogConfirmDeleteFolderHierarchyView); + let dialogRef = this.dialogConfirmDeleteFolderHierarchyView.open(DlgConfirmDeleteFolderHierarchyView); //TODO catch error dialogRef.afterClosed().subscribe(result => { if (result) { diff --git a/ScadaLTS-UI/src/app/appBody/watchlist/watchlist.component.ts b/ScadaLTS-UI/src/app/appBody/watchlist/watchlist.component.ts index 57e9b2970e..ba506bba98 100644 --- a/ScadaLTS-UI/src/app/appBody/watchlist/watchlist.component.ts +++ b/ScadaLTS-UI/src/app/appBody/watchlist/watchlist.component.ts @@ -1,6 +1,6 @@ import {Component, Inject, OnInit, OnDestroy, NgZone} from '@angular/core'; import {Http} from '@angular/http'; -import {Observable} from 'rxjs/Observable'; +import { Observable } from 'rxjs/Rx'; import 'rxjs/add/operator/catch'; import {Subject} from 'rxjs/Subject'; declare let Plotly: any; diff --git a/ScadaLTS-UI/src/app/appBody/watchlist/watchlist.module.ts b/ScadaLTS-UI/src/app/appBody/watchlist/watchlist.module.ts index f83c5cc1fb..8b1091f342 100644 --- a/ScadaLTS-UI/src/app/appBody/watchlist/watchlist.module.ts +++ b/ScadaLTS-UI/src/app/appBody/watchlist/watchlist.module.ts @@ -13,7 +13,7 @@ import { WatchlistComponent } from './watchlist.component'; BrowserModule, FormsModule, HttpModule, - MaterialModule.forRoot() + MaterialModule ], providers: [], bootstrap: [WatchlistComponent] diff --git a/ScadaLTS-UI/src/app/registration/registration.module.ts b/ScadaLTS-UI/src/app/registration/registration.module.ts index 520644cb88..089a2b5312 100644 --- a/ScadaLTS-UI/src/app/registration/registration.module.ts +++ b/ScadaLTS-UI/src/app/registration/registration.module.ts @@ -13,7 +13,7 @@ import { RegistrationComponent } from './registration.component'; BrowserModule, FormsModule, HttpModule, - MaterialModule.forRoot() + MaterialModule ], providers: [], bootstrap: [RegistrationComponent] diff --git a/ScadaLTS-UI/src/styles.css b/ScadaLTS-UI/src/styles.css index 28985cc2a5..173c9ff292 100644 --- a/ScadaLTS-UI/src/styles.css +++ b/ScadaLTS-UI/src/styles.css @@ -1,6 +1,6 @@ @import '~https://fonts.googleapis.com/icon?family=Material+Icons'; -@import '~@angular/material/core/theming/prebuilt/deeppurple-amber.css'; @import url('https://fonts.googleapis.com/css?family=Raleway'); +@import "~@angular/material/prebuilt-themes/deeppurple-amber.css"; /* global settings From fb1a83d324020744084466d51a84d952be413b39 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Fri, 1 Sep 2017 11:36:28 +0200 Subject: [PATCH 35/54] #343 DashboardGridModuleImport --- ScadaLTS-UI/src/app/app.module.ts | 4 +- ScadaLTS-UI/src/app/app.routing.ts | 3 +- ScadaLTS-UI/src/app/appBody/appBody.module.ts | 2 + .../dashboard/dashboard-grid/README.md | 51 +++++++++++ .../dashboard-grid/classes/dialog-item.ts | 11 +++ .../dashboard-grid/classes/view-page.ts | 11 +++ .../dashboard-grid.component.html | 28 +++++++ .../dashboard-grid.component.ts | 64 ++++++++++++++ .../dashboard-grid/dashboard-grid.module.ts | 29 +++++++ .../dashboard-grid/dashboard-grid.service.ts | 44 ++++++++++ .../dashboard-grid/dashboard.mock.ts | 46 ++++++++++ .../dialogs/item-editor-dialog.component.html | 8 ++ .../dialogs/item-editor-dialog.component.ts | 27 ++++++ .../view-navigator-dialog.component.html | 14 ++++ .../view-navigator-dialog.component.ts | 11 +++ .../view-navigator-dialogs.component.scss | 5 ++ ...iew-navigator-settings-dialog.component.ts | 21 +++++ .../dashboard-grid/item/dashboard-item.ts | 10 +++ .../dashboard-grid/item/frame.component.html | 24 ++++++ .../dashboard-grid/item/frame.component.ts | 84 +++++++++++++++++++ .../dashboard-grid/item/item.directive.ts | 10 +++ .../dashboard-grid/item/item.module.ts | 24 ++++++ .../dashboard-grid/item/item.service.ts | 78 +++++++++++++++++ .../navigator/navigator.component.html | 13 +++ .../navigator/navigator.component.spec.ts | 41 +++++++++ .../navigator/navigator.component.ts | 70 ++++++++++++++++ .../dashboard-grid/page/page.component.html | 13 +++ .../dashboard-grid/page/page.component.ts | 68 +++++++++++++++ .../dashboard/utils/connection.service.ts | 58 +++++++++++++ .../dashboard/utils/storage.service.ts | 23 +++++ ScadaLTS-UI/src/tsconfig.json | 2 +- 31 files changed, 894 insertions(+), 3 deletions(-) create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/README.md create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/classes/dialog-item.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/classes/view-page.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.html create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.module.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.service.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard.mock.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/item-editor-dialog.component.html create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/item-editor-dialog.component.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-dialog.component.html create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-dialog.component.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-dialogs.component.scss create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-settings-dialog.component.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/dashboard-item.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/frame.component.html create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/frame.component.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.directive.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.module.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.service.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/navigator/navigator.component.html create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/navigator/navigator.component.spec.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/navigator/navigator.component.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/page/page.component.html create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/page/page.component.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/utils/connection.service.ts create mode 100644 ScadaLTS-UI/src/app/appBody/dashboard/utils/storage.service.ts diff --git a/ScadaLTS-UI/src/app/app.module.ts b/ScadaLTS-UI/src/app/app.module.ts index 69ea482d2b..acb5fd6103 100644 --- a/ScadaLTS-UI/src/app/app.module.ts +++ b/ScadaLTS-UI/src/app/app.module.ts @@ -40,6 +40,7 @@ import { DlgAddFolderHierarchyView } from './appBody/views/views.component'; import { DlgConfirmDeleteFolderHierarchyView } from './appBody/views/views.component'; import { ClipboardModule } from 'ngx-clipboard'; +import { DashboardGridModule } from 'app/appBody/dashboard/dashboard-grid/dashboard-grid.module'; import { WorksheetAccessGuard } from './ActivationGuard'; import { UserAuthenticationService } from './UserAuthenticationService'; @@ -91,7 +92,8 @@ import { UserAuthenticationService } from './UserAuthenticationService'; MaterialModule, routing, NgbModule.forRoot(), - ClipboardModule + ClipboardModule, + DashboardGridModule ], providers: [WorksheetAccessGuard, UserAuthenticationService], bootstrap: [AppComponent] diff --git a/ScadaLTS-UI/src/app/app.routing.ts b/ScadaLTS-UI/src/app/app.routing.ts index 9080b206c1..71798b53fa 100644 --- a/ScadaLTS-UI/src/app/app.routing.ts +++ b/ScadaLTS-UI/src/app/app.routing.ts @@ -28,6 +28,7 @@ import { OldWatchlistComponent } from './appBody/old-watchlist/old-watchlist.com import { WleditComponent } from './appBody/wledit/wledit.component'; import { WorksheetAccessGuard } from './ActivationGuard'; +import { DashboardGridComponent } from 'app/appBody/dashboard/dashboard-grid/dashboard-grid.component'; const appRoutes: Routes = [ // { path: '', component: LoginComponent }, @@ -37,7 +38,7 @@ const appRoutes: Routes = [ children: [ { path: 'watchlist', component: WatchlistComponent/*, canActivate: [WorksheetAccessGuard]*/ }, { path: 'dashboard', component: DashboardComponent }, - { path: 'views', component: ViewsComponent }, + { path: 'views', component: DashboardGridComponent }, { path: 'system', component: SystemComponent }, { path: 'users', component: UsersComponent }, { path: 'about', component: AboutComponent }, diff --git a/ScadaLTS-UI/src/app/appBody/appBody.module.ts b/ScadaLTS-UI/src/app/appBody/appBody.module.ts index ce44e91442..ce46e87f2c 100644 --- a/ScadaLTS-UI/src/app/appBody/appBody.module.ts +++ b/ScadaLTS-UI/src/app/appBody/appBody.module.ts @@ -6,6 +6,7 @@ import { MdIconModule } from '@angular/material'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { AppBodyComponent } from './appBody.component'; import { ScriptingComponent } from './scripting/scripting.component'; +import { DashboardGridModule } from 'app/appBody/dashboard/dashboard-grid/dashboard-grid.module'; @NgModule({ declarations: [ @@ -13,6 +14,7 @@ import { ScriptingComponent } from './scripting/scripting.component'; ScriptingComponent ], imports: [ + DashboardGridModule, BrowserModule, FormsModule, HttpModule, diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/README.md b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/README.md new file mode 100644 index 0000000000..66a727fd3b --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/README.md @@ -0,0 +1,51 @@ +# ScadaLTS - Dashboard Grid Update +This is module imported from [ScdadaLTS-Dashboard project](https://github.com/SCADA-LTS/ScadaLTS-Dashbord) +This is independent module which allows user to manage Scada Components in GridView Mode. This module displays Dashboard-Grid-Component +which contain Navigator-Component and Page-Component. + +## Navigator-Component +This is a component which displays created dashboard views. +Functionality: +- Open a selected view Page. +- Delete view page when user is edit mode +- Create a new view page. (Also with JSON import option) + +## Page-Component +Displays a single View Page Instance which contain a varoius components. +This component uses a Frame-Component to display a single ScadaLTSItemComponent. +It is binded with Dashboard-Grid-Component (parent) and with Frame-Component (Child) +by an @Input and @Output decorators. This component recive a single active ViewPage data. +And returns every change of this page to his parent. +Functionality: +- Update a View Page +- Add a new ItemComponent +- Remove an exisiting ItemComponent (when recived event from FrameComponent) + +## Frame-Component +Inside item directory. This is an component which handle the custom user-created components +It has a directive which allows to pin a custom ItemComponent. ItemComponent is the generic +component which is created. It has two variables. 'Component' and 'Data'. 'Component' is +a Component class, 'Data' is an Object with this component data variables. This object do +do not have any limitations. +Functionality: +- Display a custom user-created components. +- Edit selected ItemComponent +- Delete this Component (init event) + +## Dialogs +Dialogs directory contains custom dialogs which are used in this module + +## Classes +Classes directory contains a classes which are used in this module + +## Utils +Some services required to work DashboardGridModule + +# ScadaLTS - Dashboard (Adding a new custom user-creted component) +To expand the library of custom compoents import them to the node_modules by your `package.json` file. +Later find `item.service.ts` file inside /dashboard-grid/item/ directory. +Inside this file import a custom component and include this inside ItemServie class. +- Add a new retrun condition to getDashboardItem() method. +- Add a new return statemanet inside getComponentType() method to return a your component code +- Add a new return array object instance inside getDashboardComponentList() method to return all necessary data. Like on the example in this file. +(Remember! to add data object template in this getDashboardComponentList() method ) \ No newline at end of file diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/classes/dialog-item.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/classes/dialog-item.ts new file mode 100644 index 0000000000..c56e6c3076 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/classes/dialog-item.ts @@ -0,0 +1,11 @@ +export class DialogEditItem { + + label: string; + value: any; + + constructor(label: string, value: any) { + this.label = label; + this.value = value; + } + +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/classes/view-page.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/classes/view-page.ts new file mode 100644 index 0000000000..cfec6d98c7 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/classes/view-page.ts @@ -0,0 +1,11 @@ +export class ViewPage { + id: number; + name: string; + data: any; + + constructor(id: number, name: string, data: any) { + this.id = id; + this.name = name; + this.data = data; + } +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.html b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.html new file mode 100644 index 0000000000..763b7bb2f6 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.html @@ -0,0 +1,28 @@ + + + + + + + + + + + {{viewPage.name}} + + + + + + + + + + + + +
+ +
+ +
\ No newline at end of file diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.ts new file mode 100644 index 0000000000..6038236424 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.ts @@ -0,0 +1,64 @@ +import { Component, ViewChild, OnInit } from '@angular/core'; +import { DashboardGridPageComponent } from './page/page.component'; +import { DashboardGridService } from './dashboard-grid.service'; +import { StorageService } from '../utils/storage.service'; +import { ViewPage } from './classes/view-page'; +import { MOCKPAGES } from './dashboard.mock'; + +@Component({ + selector: 'app-dashboard-grid', + templateUrl: 'dashboard-grid.component.html', + styles: [`md-sidenav-container { height:calc(100vh - 64px); display: block} #viewPage-name { text-align: center;}`] +}) +export class DashboardGridComponent implements OnInit { + + + + /* viewPage = Current Displayed page */ + viewPage: ViewPage; + viewPages = MOCKPAGES; // Mocked data form file // + // viewPages: ViewPage[]; // Standard variable to handle data from Scada // + editMode: boolean; + dataPointExportID: string; + + @ViewChild(DashboardGridPageComponent) dashboardGridPageComponent: DashboardGridPageComponent; + + constructor(private dashboardGridService: DashboardGridService, private storageService: StorageService) { } + + ngOnInit(): void { + this.dataPointExportID = this.storageService.read('config'); + /* Comment or uncomment this section to test data with or without Scada */ + // this.viewPages = []; + // this.dashboardGridService.authenticate(); + // this.dashboardGridService.getViewPages(this.dataPointExportID).then(response => this.viewPages = response); + /* --- End section --- */ + } + + updateViewPage(viewPages: ViewPage[]) { + this.viewPages = viewPages; + + } + + openViewPage(viewPage: ViewPage) { + this.viewPage = viewPage; + if (this.dashboardGridPageComponent !== undefined) { + this.dashboardGridPageComponent.viewPage = this.viewPage; + this.dashboardGridPageComponent.ngOnInit(); + } + + } + + saveConfiguration() { + this.storageService.write('config', this.dataPointExportID); + this.dashboardGridService.setViewPages(this.dataPointExportID, JSON.stringify(this.viewPages)); + console.debug(JSON.stringify(this.viewPages)); + } + + saveViewPage(viewPage: ViewPage) { + this.viewPage = viewPage; + const id = this.viewPage.id - 1; + this.viewPages[id] = viewPage; + + } + +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.module.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.module.ts new file mode 100644 index 0000000000..c34629eb4d --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.module.ts @@ -0,0 +1,29 @@ +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MdIconModule, MdToolbarModule, MdButtonModule } from '@angular/material'; +import { MdSidenavModule, MdInputModule, MdSelectModule } from '@angular/material'; +import { MdDialogModule, MdDialog } from '@angular/material'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { DashboardGridComponent } from './dashboard-grid.component'; +import { DashboardGridNavigatorComponent } from './navigator/navigator.component'; +import { DashboardGridPageComponent } from './page/page.component'; +import { ItemModule } from './item/item.module'; +import { DashboardGridService } from './dashboard-grid.service'; +import { ConnectionService } from '../utils/connection.service'; +import { ViewNavigatorSettingsDialogComponent } from './dialogs/view-navigator-settings-dialog.component'; +import { ViewNavigatorDialogComponent } from './dialogs/view-navigator-dialog.component'; +import { ItemEditorDialogComponent } from './dialogs/item-editor-dialog.component'; +import { StorageService } from '../utils/storage.service'; + + +@NgModule({ + declarations: [DashboardGridComponent, DashboardGridNavigatorComponent, DashboardGridPageComponent, + ItemEditorDialogComponent, ViewNavigatorDialogComponent, ViewNavigatorSettingsDialogComponent], + entryComponents: [ViewNavigatorDialogComponent, ViewNavigatorSettingsDialogComponent, ItemEditorDialogComponent], + imports: [MdToolbarModule, MdIconModule, MdButtonModule, MdSidenavModule, MdDialogModule, MdSelectModule, + MdInputModule, BrowserModule, BrowserAnimationsModule, FormsModule, ItemModule], + providers: [DashboardGridService, ConnectionService, StorageService], + exports: [DashboardGridComponent] +}) +export class DashboardGridModule { } diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.service.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.service.ts new file mode 100644 index 0000000000..4c47d18b35 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.service.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@angular/core'; +import { ViewPage } from './classes/view-page'; +import { ConnectionService } from '../utils/connection.service'; + +@Injectable() +export class DashboardGridService { + + constructor(private connectionService: ConnectionService) { } + + authenticate(): void { + + this.connectionService.authenticate('admin', 'admin'); + } + + /** + * Promise: get View Pages Array + * Connect to remote server and load data from alphanumeric datapoint. + * Parse the response and retrun the viewPageArray promise data. + * @param datapointExportID - Data Point Export ID with saved configuration. + */ + getViewPages(datapointExportID: string): Promise { + + return this.connectionService.getDataFromRemote('point_value/getValue/', datapointExportID).then( + response => { + let temp = response.json().value; + temp = JSON.parse(temp); + return temp.viewPage; + } + ); + } + + /** + * Set View Pages and save them into remote data point + * Connect to remote data point and save data to remote server. + * @param datapointExportID - Data Point Export ID to save configuration. + * @param viewPageData - configuration data. + */ + setViewPages(datapointExportID: string, viewPageData: string) { + + this.connectionService.postDataToRemote('point_value/setValue/', datapointExportID + '/3/{"viewPage":' + viewPageData + '}'); + + } + +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard.mock.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard.mock.ts new file mode 100644 index 0000000000..6459a9847a --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard.mock.ts @@ -0,0 +1,46 @@ + +import { ViewPage } from './classes/view-page'; + +export const MOCKPAGES: ViewPage[] = [ + { + id: 1, name: 'Test 1', data: [ + { + type: 'incrementator', + data: { + number: 1, + name: 'Example Incrementator 1', + datapointXid: 'DP_EX_010203' + } + }, + { + type: 'incrementator', + data: { + number: 2, + name: 'Example Incrementator 2', + datapointXid: 'DP_EX_010203' + } + } + ] + }, + { + id: 2, name: 'Test 2', data: [ + { + type: 'incrementator', + data: { + number: 2, + name: 'Example Incrementator 2', + datapointXid: 'DP_EX_010203' + } + }, + { + type: 'camera', + data: { + number: 1, + label: 'Camera 1', + cameraPath: 'https://kamilmysliwiec.com/wp-content/themes/src/img/background-0@2x.png' + } + } + ] + }, + { id: 3, name: 'Test 3', data: [] }, +]; diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/item-editor-dialog.component.html b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/item-editor-dialog.component.html new file mode 100644 index 0000000000..869a10f000 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/item-editor-dialog.component.html @@ -0,0 +1,8 @@ +

Edit Component

+
+ + + +
+ + diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/item-editor-dialog.component.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/item-editor-dialog.component.ts new file mode 100644 index 0000000000..51000ae268 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/item-editor-dialog.component.ts @@ -0,0 +1,27 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { MdDialogRef, MD_DIALOG_DATA } from '@angular/material'; +import { DialogEditItem } from '../classes/dialog-item'; + +@Component({ + selector: 'app-item-editor-dialog', + templateUrl: 'item-editor-dialog.component.html', + styleUrls: ['view-navigator-dialogs.component.scss'], +}) +export class ItemEditorDialogComponent { + + labels: string[]; + values: any[]; + + items: DialogEditItem[]; + + constructor( @Inject(MD_DIALOG_DATA) public data: any) { + const labels = Object.keys(this.data); + const values = Object.values(this.data); + this.items = []; + for (let x = 0; x < labels.length; x++) { + this.items.push(new DialogEditItem(labels[x], values[x])); + } + + console.debug(this.items); + } +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-dialog.component.html b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-dialog.component.html new file mode 100644 index 0000000000..84c77bab65 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-dialog.component.html @@ -0,0 +1,14 @@ +

Create a dashboard view

+
+ + +
+
+ + + +
+
+ + +
\ No newline at end of file diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-dialog.component.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-dialog.component.ts new file mode 100644 index 0000000000..c15f17247f --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-dialog.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { MdDialogRef } from '@angular/material'; + +@Component({ + selector: 'app-dashboard-navigator-dialog', + templateUrl: 'view-navigator-dialog.component.html', + styleUrls: ['view-navigator-dialogs.component.scss'], +}) +export class ViewNavigatorDialogComponent { + constructor(public dialogRef: MdDialogRef) { } +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-dialogs.component.scss b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-dialogs.component.scss new file mode 100644 index 0000000000..a7746a04c5 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-dialogs.component.scss @@ -0,0 +1,5 @@ +.mat-input-container { + width: 100%; + padding-left: 8px; + padding-right: 8px; +} \ No newline at end of file diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-settings-dialog.component.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-settings-dialog.component.ts new file mode 100644 index 0000000000..bb3a9eff7a --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dialogs/view-navigator-settings-dialog.component.ts @@ -0,0 +1,21 @@ +import { Component, Inject } from '@angular/core'; +import { MdDialogRef, MD_DIALOG_DATA } from '@angular/material'; + +@Component({ + selector: 'app-dashboard-navigator-settings-dialog', + template: `
+

Configuration

+
+ + +
+
+ + +
+ `, + styleUrls: ['view-navigator-dialogs.component.scss'], +}) +export class ViewNavigatorSettingsDialogComponent { + constructor( @Inject(MD_DIALOG_DATA) public data: any) { } +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/dashboard-item.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/dashboard-item.ts new file mode 100644 index 0000000000..5de48b8abc --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/dashboard-item.ts @@ -0,0 +1,10 @@ +import { Type } from '@angular/core'; + +/** + * Dashboard Item + * Item class for every component used inside ScadaLTS-Dashboard + * Most general object of every Dashboard single Item. + */ +export class DashboardItem { + constructor(public component: Type, public data: any) { } +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/frame.component.html b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/frame.component.html new file mode 100644 index 0000000000..53818c91e6 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/frame.component.html @@ -0,0 +1,24 @@ + + +

{{title}}

+ + + + + + + + +
+ + + +
\ No newline at end of file diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/frame.component.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/frame.component.ts new file mode 100644 index 0000000000..794cbe94fb --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/frame.component.ts @@ -0,0 +1,84 @@ +import { Component, Input, OnInit, ViewChild, ComponentFactoryResolver, EventEmitter, Output } from '@angular/core'; +import { DashboardItem } from './dashboard-item'; +import { ItemDirective } from './item.directive'; +import { MdDialog } from '@angular/material'; +import { ItemEditorDialogComponent } from '../dialogs/item-editor-dialog.component'; + +@Component({ + selector: 'app-item-frame', + templateUrl: 'frame.component.html', + styles: [`md-card { width:96%;}`], +}) +/** + * Frame Component + * This is a handler for custom ItemComponents. + * It loads a data and generate a special componet based on the recived data + */ +export class FrameComponent implements OnInit { + + title: string; + @Input() item: DashboardItem; + @Input() editMode: boolean; + @Output() savedItem = new EventEmitter(); + @Output() removedItem = new EventEmitter(); + @ViewChild(ItemDirective) itemHost: ItemDirective; + + constructor( + private componentFactoryResolver: ComponentFactoryResolver, + private dialog: MdDialog + ) { } + + ngOnInit() { + this.loadComponent(); + } + + loadComponent() { + + const viewContainerRef = this.itemHost.viewContainerRef; + viewContainerRef.clear(); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.item.component); + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = this.item.data; + + // TODO: Make this card title unique for all components for example: ... data: {label:'title', ...} + // This is a section to display a card title based on the data variable // + if (this.item.data.label !== undefined) { + this.title = this.item.data.label; + } + if (this.item.data.name !== undefined) { + this.title = this.item.data.name; + } + + } + + clearView() { + this.itemHost.viewContainerRef.clear(); + } + + editDialog() { + console.debug(this.item.data); + const dialogReference = this.dialog.open(ItemEditorDialogComponent, { data: this.item.data }); + dialogReference.afterClosed().subscribe(result => { + if (result !== undefined) { + // Create a two arrays to handle Object Keys and Values // + const labels: string[] = []; + const values: any[] = []; + result.forEach(element => { + labels.push(element.label); + values.push(element.value); + }); + + // Update this keys in orginal item.data variable // + for (let x = 0; x < labels.length; x++) { + this.item.data[labels[x]] = values[x]; + } + this.savedItem.emit(this.item); + } + }); + + } + + delete() { + this.removedItem.emit(this.item); + } +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.directive.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.directive.ts new file mode 100644 index 0000000000..0bbda22a6f --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.directive.ts @@ -0,0 +1,10 @@ +import { Directive, ViewContainerRef } from '@angular/core'; + +@Directive({ + selector: '[appItemHost]', +}) +export class ItemDirective { + constructor(public viewContainerRef: ViewContainerRef) { } +} + + diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.module.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.module.ts new file mode 100644 index 0000000000..22572f5e7a --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.module.ts @@ -0,0 +1,24 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { MdCardModule, MdButtonModule, MdIconModule, MdDialogModule} from '@angular/material'; +import { MdMenuModule } from '@angular/material'; + +import { LibexModule } from '@scadalts/scadalts-dashbord-components'; + +import { BrowserModule } from '@angular/platform-browser'; +import { IncrementatorComponent } from '@scadalts/scadalts-dashbord-components/incrementator/incrementator.component'; +import { CameraComponent } from '@scadalts/scadalts-dashbord-components/camera/camera.component'; +import { ItemDirective } from './item.directive'; +import { ItemService } from './item.service'; +import { FrameComponent } from './frame.component'; + + +@NgModule({ + imports: [CommonModule, LibexModule, BrowserModule, MdCardModule, MdButtonModule, MdIconModule, MdDialogModule, MdMenuModule], + /* Entry Components - custom components declaration */ + entryComponents: [CameraComponent, IncrementatorComponent], + exports: [ItemDirective, FrameComponent], + declarations: [ItemDirective, FrameComponent], + providers: [ItemService] +}) +export class ItemModule { } diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.service.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.service.ts new file mode 100644 index 0000000000..5e55b5673e --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.service.ts @@ -0,0 +1,78 @@ +import { Injectable, Type } from '@angular/core'; +import { DashboardItem } from './dashboard-item'; +import { CameraComponent } from '@scadalts/scadalts-dashbord-components/camera/camera.component'; +import { IncrementatorComponent } from '@scadalts/scadalts-dashbord-components/incrementator/incrementator.component'; + +/** + * This is the major class to be changed when user created a new component + * Add necessary data to all methods included inside this class. + */ +@Injectable() +export class ItemService { + + /** + * get Dashboard Item Factory + * Factory pattern to create custom components based on the type + * defined in recived data. + * + * @Important - When a new Custom Component has been created + * add a new checking condition to this method to create this custom + * component. In sinilar way as it is presented below. + * + * Remember to add this components to EntryComponents array in + * item.module.ts file inside this directory. + * + * @param componentType - Component type which has to be created + * @param componentData - Component data. + */ + static getDashboardItem(componentType: string, componentData: any): DashboardItem { + if (componentType === 'incrementator') { + return new DashboardItem(IncrementatorComponent, componentData); + } + if (componentType === 'camera') { + return new DashboardItem(CameraComponent, componentData); + } + + /* Place for another component */ + // if (componentType == ''){ + // return new DashboadItem(, componentData); + // } + + } + + /** + * Get Component Type Code + * + * When saving to JSON object the type of the component must be specified + * so this method returns the component 'type' which has to be saved. + * @param component - Component varialbe + */ + static getComponentType(component: Type) { + if (component.name === 'IncrementatorComponent') { + return 'incrementator'; + } + if (component.name === 'CameraComponent') { + return 'camera'; + } + + } + + /** + * get Dashboard Components List + * + * Static method which returns list of all the exisitng components + * If user has created a new component it should be implemented here. + * Returns an array of objects which contains the type-code, + * human readable label of this component and data Object template. + * + * Remember to set up a template for 'data' variable. If it won't be set + * User won't be able to edit this component in Edit Dialog! + */ + static getDashboardComponentsList() { + return [ + { id: 0, type: 'incrementator', label: 'SLTS Visit Counter', data: { number: 0, name: '', datapointXid: '' } }, + { id: 1, type: 'camera', label: 'SLTS Image Component', data: { number: 0, label: '', cameraPath: '' } } + ]; + } + +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/navigator/navigator.component.html b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/navigator/navigator.component.html new file mode 100644 index 0000000000..044fcfb0a6 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/navigator/navigator.component.html @@ -0,0 +1,13 @@ + + View List + + + + +
+ + +
+
+ +
\ No newline at end of file diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/navigator/navigator.component.spec.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/navigator/navigator.component.spec.ts new file mode 100644 index 0000000000..a3aff72788 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/navigator/navigator.component.spec.ts @@ -0,0 +1,41 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { MdToolbarModule, MdIconModule, MdDialogModule } from '@angular/material'; +import { StorageService } from '../../utils/storage.service'; +import { DashboardGridNavigatorComponent } from './navigator.component'; + +describe('DashboardGridNavigatorComponent', () => { + + let component: DashboardGridNavigatorComponent; + let fixture: ComponentFixture; + let debugEl: DebugElement; + + beforeEach(async(() => { + + TestBed.configureTestingModule({ + imports: [MdToolbarModule, MdIconModule, MdDialogModule], + declarations: [DashboardGridNavigatorComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(DashboardGridNavigatorComponent); + component = fixture.componentInstance; + debugEl = fixture.debugElement; + + + })); + + it('Initialization test', () => { + expect(undefined).toEqual(component.editEnabled); + expect(undefined).toEqual(component.viewPagesArray); + }); + + it('Toggle Edit test', () => { + component.editEnabled = 'none'; + component.toggleEditMode(); + expect('block').toEqual(component.editEnabled); + + }); + +}); diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/navigator/navigator.component.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/navigator/navigator.component.ts new file mode 100644 index 0000000000..f9087e5044 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/navigator/navigator.component.ts @@ -0,0 +1,70 @@ + +import { Component, Input, Output, EventEmitter } from '@angular/core'; +import { ViewPage } from '../classes/view-page'; +import { ViewNavigatorDialogComponent } from '../dialogs/view-navigator-dialog.component'; +import { MdDialog } from '@angular/material'; + + +@Component({ + selector: 'app-dashboard-grid-navigator', + templateUrl: 'navigator.component.html', + styles: [` + .open-btn { float: left; width: 80%; text-align: left} + .open-btn--edit { width: 100% } + .remove-btn { float: left; width:20%; height:34px } + .mat-btn { width: 100%} + .edit { display:block } + `] +}) +export class DashboardGridNavigatorComponent { + + @Input() viewPagesArray: ViewPage[]; + @Output() updateViewPages = new EventEmitter(); + @Output() openViewPage = new EventEmitter(); + editEnabled: string; + + constructor(private dialog: MdDialog) { } + + open(view) { + console.debug(view); + this.openViewPage.emit(view); + } + + remove(view) { + this.viewPagesArray = this.viewPagesArray.filter(page => page !== view); + console.debug(this.viewPagesArray); + this.updateViewPages.emit(this.viewPagesArray); + } + + toggleEditMode() { + const viewListButtons: any = document.querySelectorAll('.open-btn'); + if (this.editEnabled === 'none') { + this.editEnabled = 'block'; + viewListButtons.forEach(function (button) { + button.classList.remove('open-btn--edit'); + }); + } else { + this.editEnabled = 'none'; + viewListButtons.forEach(function (button) { + button.classList.add('open-btn--edit'); + }); + } + + } + + openNewPageDialog() { + const dialogReference = this.dialog.open(ViewNavigatorDialogComponent); + dialogReference.afterClosed().subscribe(result => { + if (result !== undefined) { + let data; + if (result.name !== '') { const name = result.name; } else { alert('Enter View Name'); return false; } + if (result.data !== '') { data = result.data; } else { data = '[]'; } + + this.viewPagesArray.push(new ViewPage(this.viewPagesArray.length + 1, name, JSON.parse(data))); + this.updateViewPages.emit(this.viewPagesArray); + console.debug(this.viewPagesArray); + + } + }); + } +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/page/page.component.html b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/page/page.component.html new file mode 100644 index 0000000000..7c8a177649 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/page/page.component.html @@ -0,0 +1,13 @@ + + + + {{componentType.label}} + + + + +
+
+ +
+
\ No newline at end of file diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/page/page.component.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/page/page.component.ts new file mode 100644 index 0000000000..263dd6dc7a --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/page/page.component.ts @@ -0,0 +1,68 @@ + +import { Component, Input, Output, ViewChild, OnInit, EventEmitter } from '@angular/core'; +import { DashboardItem } from '../item/dashboard-item'; +import { ItemService } from '../item/item.service'; +import { ViewPage } from '../classes/view-page'; +import { FrameComponent } from '../item/frame.component'; + +@Component({ + selector: 'app-dashboard-grid-page', + templateUrl: 'page.component.html', + styles: ['md-select { width:33%;}'] +}) +export class DashboardGridPageComponent implements OnInit { + + @Input() viewPage: ViewPage; + @Input() editMode: boolean; + @Output() saveViewPage = new EventEmitter(); + @ViewChild(FrameComponent) frameComponent: FrameComponent; + items: DashboardItem[]; + selectedId: number; + componentTypes; + + ngOnInit() { + + this.items = []; + this.loadComponents(); + this.componentTypes = ItemService.getDashboardComponentsList(); + + } + + loadComponents() { + + for (let x = 0; x < this.viewPage.data.length; x++) { + const item = this.viewPage.data[x]; + this.items.push(ItemService.getDashboardItem(item.type, item.data)); + } + + } + + addComponent() { + if (this.selectedId !== undefined) { + const selectedComponent = this.componentTypes[this.selectedId]; + selectedComponent.data.number = this.items.length + 1; + this.items.push(ItemService.getDashboardItem(selectedComponent.type, selectedComponent.data)); + this.viewPage.data.push({ type: selectedComponent.type, data: selectedComponent.data }); + console.debug(this.viewPage); + } + + + } + + savedItem(item: DashboardItem) { + + this.saveViewPage.emit(this.viewPage); + + } + + removedItem(item: DashboardItem) { + + this.viewPage.data = this.viewPage.data.filter(page => page.data.number !== item.data.number); + + this.frameComponent.clearView(); + this.ngOnInit(); + + this.saveViewPage.emit(this.viewPage); + } + +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/utils/connection.service.ts b/ScadaLTS-UI/src/app/appBody/dashboard/utils/connection.service.ts new file mode 100644 index 0000000000..1d5cb16675 --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/utils/connection.service.ts @@ -0,0 +1,58 @@ +import { Injectable } from '@angular/core'; +import { Http, Headers } from '@angular/http'; +import 'rxjs/add/operator/toPromise'; + +@Injectable() +export class ConnectionService { + + apiURL = '/ScadaBR/api/'; + + constructor(private http: Http) { } + + /** + * Authenticate session + * Establish connection with a remote server + * @param username - API username + * @param password - API user password + */ + authenticate(username: string, password: string): void { + + this.http.get(this.apiURL + 'auth/' + username + '/' + password).subscribe( + response => { + console.debug(response); + }, err => { + console.error('Error during the authentication! ' + err); + } + ); + + } + + /** + * Get Data From Remote Server + * Use HTTP GET method to recive any data from server. + * @param request - API URL method to invoke + * @param parameters - request parameters (ex. DataPointXid) + */ + getDataFromRemote(request: string, parameters: string): Promise { + + return this.http.get(this.apiURL + request + parameters).toPromise() + .then(response => { + console.debug(response); + return response; + }); + } + + /** + * Post Data To Remote Server + * Use HTTP POST method to send data to server. + * @param request - API URL method to invoke + * @param parameters - request parameters (ex. DataPointXid value) + */ + postDataToRemote(request: string, parameters: string): void { + + const headers = new Headers({ 'Content-Type': 'application/text;charset=utf-8' }); + this.http.post(this.apiURL + request + parameters, '', { headers: headers }) + .subscribe((data) => console.info('POST Done!')); + + } +} diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/utils/storage.service.ts b/ScadaLTS-UI/src/app/appBody/dashboard/utils/storage.service.ts new file mode 100644 index 0000000000..321d39075e --- /dev/null +++ b/ScadaLTS-UI/src/app/appBody/dashboard/utils/storage.service.ts @@ -0,0 +1,23 @@ +/** + * Storage Service class + * This Class respond for memory of an aplication + * Save and Read data from Storage Memory of an web browser + */ +export class StorageService { + write(key: string, value: any) { + if (value) { + value = JSON.stringify(value); + } + localStorage.setItem(key, value); + } + + read(key: string): T { + let value: string = localStorage.getItem(key); + + if (value && value != "undefined" && value != "null") { + return JSON.parse(value); + } + + return null; + } +} \ No newline at end of file diff --git a/ScadaLTS-UI/src/tsconfig.json b/ScadaLTS-UI/src/tsconfig.json index e2802124fd..6079ec8ad6 100644 --- a/ScadaLTS-UI/src/tsconfig.json +++ b/ScadaLTS-UI/src/tsconfig.json @@ -4,7 +4,7 @@ "declaration": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "lib": ["es6", "dom"], + "lib": ["es2015","es2017", "dom"], "mapRoot": "./", "module": "es6", "moduleResolution": "node", From 676b6240dc9e4b54fe87a8d53fcee944c64f859d Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Fri, 1 Sep 2017 11:54:05 +0200 Subject: [PATCH 36/54] #343 Refresh button added - styles fix --- ScadaLTS-UI/src/app/appBody/appBody.component.css | 2 +- .../dashboard-grid/dashboard-grid.component.html | 3 ++- .../dashboard-grid/dashboard-grid.component.ts | 14 +++++++++----- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/ScadaLTS-UI/src/app/appBody/appBody.component.css b/ScadaLTS-UI/src/app/appBody/appBody.component.css index 2b33b47299..24d9ea4674 100644 --- a/ScadaLTS-UI/src/app/appBody/appBody.component.css +++ b/ScadaLTS-UI/src/app/appBody/appBody.component.css @@ -345,7 +345,7 @@ a { transition: margin 0.3s cubic-bezier(0.82, 0, 0.11, 1); } .contentInside { - padding: 40px; + /* padding: 40px; */ z-index: -99999999; } /* MEDIA QUERIES */ diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.html b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.html index 763b7bb2f6..b3cb4b857e 100644 --- a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.html +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.html @@ -17,7 +17,8 @@ - + + diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.ts index 6038236424..1275162e13 100644 --- a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.ts +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.ts @@ -16,8 +16,8 @@ export class DashboardGridComponent implements OnInit { /* viewPage = Current Displayed page */ viewPage: ViewPage; - viewPages = MOCKPAGES; // Mocked data form file // - // viewPages: ViewPage[]; // Standard variable to handle data from Scada // + // viewPages = MOCKPAGES; // Mocked data form file // + viewPages: ViewPage[]; // Standard variable to handle data from Scada // editMode: boolean; dataPointExportID: string; @@ -28,9 +28,9 @@ export class DashboardGridComponent implements OnInit { ngOnInit(): void { this.dataPointExportID = this.storageService.read('config'); /* Comment or uncomment this section to test data with or without Scada */ - // this.viewPages = []; - // this.dashboardGridService.authenticate(); - // this.dashboardGridService.getViewPages(this.dataPointExportID).then(response => this.viewPages = response); + this.viewPages = []; + this.dashboardGridService.authenticate(); + this.dashboardGridService.getViewPages(this.dataPointExportID).then(response => this.viewPages = response); /* --- End section --- */ } @@ -61,4 +61,8 @@ export class DashboardGridComponent implements OnInit { } + reloadConfiguration() { + this.dashboardGridService.getViewPages(this.dataPointExportID).then(response => this.viewPages = response); + } + } From 472fec031626b8f05f6e989f28f3208b2ea77322 Mon Sep 17 00:00:00 2001 From: Radek Jajko Date: Fri, 1 Sep 2017 16:22:55 +0200 Subject: [PATCH 37/54] #343 Bugs, iframe and custom components --- ScadaLTS-UI/package.json | 2 +- .../dashboard-grid.component.html | 6 +-- .../dashboard-grid.component.ts | 2 - .../dashboard-grid/dashboard-grid.module.ts | 42 +++++++++++++++---- .../dashboard-grid/dashboard.mock.ts | 8 ++-- .../dashboard-grid/item/frame.component.ts | 14 +++++-- .../dashboard-grid/item/item.module.ts | 3 +- .../dashboard-grid/item/item.service.ts | 14 ++++++- 8 files changed, 66 insertions(+), 25 deletions(-) diff --git a/ScadaLTS-UI/package.json b/ScadaLTS-UI/package.json index 9cc73ddc11..dc4ce16eb4 100644 --- a/ScadaLTS-UI/package.json +++ b/ScadaLTS-UI/package.json @@ -37,7 +37,7 @@ "rxjs": "^5.4.2", "ts-helpers": "^1.1.2", "zone.js": "^0.8.16", - "@scadalts/scadalts-dashbord-components": "0.0.7" + "@scadalts/scadalts-dashbord-components": "0.0.13" }, "devDependencies": { "@angular/cli": "1.3.0", diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.html b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.html index b3cb4b857e..9f79576758 100644 --- a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.html +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.html @@ -7,18 +7,18 @@ - + {{viewPage.name}} - + - + diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.ts index 1275162e13..809e7113a3 100644 --- a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.ts +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.component.ts @@ -12,8 +12,6 @@ import { MOCKPAGES } from './dashboard.mock'; }) export class DashboardGridComponent implements OnInit { - - /* viewPage = Current Displayed page */ viewPage: ViewPage; // viewPages = MOCKPAGES; // Mocked data form file // diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.module.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.module.ts index c34629eb4d..f44cbc4229 100644 --- a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.module.ts +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard-grid.module.ts @@ -16,14 +16,40 @@ import { ViewNavigatorDialogComponent } from './dialogs/view-navigator-dialog.co import { ItemEditorDialogComponent } from './dialogs/item-editor-dialog.component'; import { StorageService } from '../utils/storage.service'; - @NgModule({ - declarations: [DashboardGridComponent, DashboardGridNavigatorComponent, DashboardGridPageComponent, - ItemEditorDialogComponent, ViewNavigatorDialogComponent, ViewNavigatorSettingsDialogComponent], - entryComponents: [ViewNavigatorDialogComponent, ViewNavigatorSettingsDialogComponent, ItemEditorDialogComponent], - imports: [MdToolbarModule, MdIconModule, MdButtonModule, MdSidenavModule, MdDialogModule, MdSelectModule, - MdInputModule, BrowserModule, BrowserAnimationsModule, FormsModule, ItemModule], - providers: [DashboardGridService, ConnectionService, StorageService], - exports: [DashboardGridComponent] + declarations: [ + DashboardGridComponent, + DashboardGridNavigatorComponent, + DashboardGridPageComponent, + ItemEditorDialogComponent, + ViewNavigatorDialogComponent, + ViewNavigatorSettingsDialogComponent, + ], + entryComponents: [ + ViewNavigatorDialogComponent, + ViewNavigatorSettingsDialogComponent, + ItemEditorDialogComponent + ], + imports: [ + MdToolbarModule, + MdIconModule, + MdButtonModule, + MdSidenavModule, + MdDialogModule, + MdSelectModule, + MdInputModule, + BrowserModule, + BrowserAnimationsModule, + FormsModule, + ItemModule + ], + providers: [ + DashboardGridService, + StorageService, + ConnectionService + ], + exports: [ + DashboardGridComponent + ] }) export class DashboardGridModule { } diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard.mock.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard.mock.ts index 6459a9847a..12da3c04b5 100644 --- a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard.mock.ts +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/dashboard.mock.ts @@ -8,7 +8,7 @@ export const MOCKPAGES: ViewPage[] = [ type: 'incrementator', data: { number: 1, - name: 'Example Incrementator 1', + label: 'Example Incrementator 1', datapointXid: 'DP_EX_010203' } }, @@ -16,7 +16,7 @@ export const MOCKPAGES: ViewPage[] = [ type: 'incrementator', data: { number: 2, - name: 'Example Incrementator 2', + label: 'Example Incrementator 2', datapointXid: 'DP_EX_010203' } } @@ -28,7 +28,7 @@ export const MOCKPAGES: ViewPage[] = [ type: 'incrementator', data: { number: 2, - name: 'Example Incrementator 2', + label: 'Example Incrementator 2', datapointXid: 'DP_EX_010203' } }, @@ -37,7 +37,7 @@ export const MOCKPAGES: ViewPage[] = [ data: { number: 1, label: 'Camera 1', - cameraPath: 'https://kamilmysliwiec.com/wp-content/themes/src/img/background-0@2x.png' + imageLocation: 'https://kamilmysliwiec.com/wp-content/themes/src/img/background-0@2x.png' } } ] diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/frame.component.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/frame.component.ts index 794cbe94fb..973ec4cb80 100644 --- a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/frame.component.ts +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/frame.component.ts @@ -45,9 +45,7 @@ export class FrameComponent implements OnInit { if (this.item.data.label !== undefined) { this.title = this.item.data.label; } - if (this.item.data.name !== undefined) { - this.title = this.item.data.name; - } + } @@ -70,8 +68,16 @@ export class FrameComponent implements OnInit { // Update this keys in orginal item.data variable // for (let x = 0; x < labels.length; x++) { - this.item.data[labels[x]] = values[x]; + + // Prevention before crash when there is a '/' character // + let valueString = values[x]; + if (typeof valueString === 'string') { + // Replace '/' by the '1SLASH212SLASH1' pattern + valueString = valueString.replace(/\//gi, '1SLASH212SLASH1'); + } + this.item.data[labels[x]] = valueString; } + this.title = this.item.data.label; this.savedItem.emit(this.item); } }); diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.module.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.module.ts index 22572f5e7a..a5ea09e611 100644 --- a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.module.ts +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.module.ts @@ -11,12 +11,13 @@ import { CameraComponent } from '@scadalts/scadalts-dashbord-components/camera/c import { ItemDirective } from './item.directive'; import { ItemService } from './item.service'; import { FrameComponent } from './frame.component'; +import { IframeComponent } from '@scadalts/scadalts-dashbord-components/iframe/iframe.component'; @NgModule({ imports: [CommonModule, LibexModule, BrowserModule, MdCardModule, MdButtonModule, MdIconModule, MdDialogModule, MdMenuModule], /* Entry Components - custom components declaration */ - entryComponents: [CameraComponent, IncrementatorComponent], + entryComponents: [CameraComponent, IncrementatorComponent, IframeComponent], exports: [ItemDirective, FrameComponent], declarations: [ItemDirective, FrameComponent], providers: [ItemService] diff --git a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.service.ts b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.service.ts index 5e55b5673e..520418d640 100644 --- a/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.service.ts +++ b/ScadaLTS-UI/src/app/appBody/dashboard/dashboard-grid/item/item.service.ts @@ -2,6 +2,7 @@ import { Injectable, Type } from '@angular/core'; import { DashboardItem } from './dashboard-item'; import { CameraComponent } from '@scadalts/scadalts-dashbord-components/camera/camera.component'; import { IncrementatorComponent } from '@scadalts/scadalts-dashbord-components/incrementator/incrementator.component'; +import { IframeComponent } from '@scadalts/scadalts-dashbord-components/iframe/iframe.component'; /** * This is the major class to be changed when user created a new component @@ -22,6 +23,8 @@ export class ItemService { * Remember to add this components to EntryComponents array in * item.module.ts file inside this directory. * + * !!! Also add this component to item.module.file as entryComponent !!! + * * @param componentType - Component type which has to be created * @param componentData - Component data. */ @@ -32,6 +35,9 @@ export class ItemService { if (componentType === 'camera') { return new DashboardItem(CameraComponent, componentData); } + if (componentType === 'iframe') { + return new DashboardItem(IframeComponent, componentData); + } /* Place for another component */ // if (componentType == ''){ @@ -54,6 +60,9 @@ export class ItemService { if (component.name === 'CameraComponent') { return 'camera'; } + if (component.name === 'IframeComponent') { + return 'iframe'; + } } @@ -70,8 +79,9 @@ export class ItemService { */ static getDashboardComponentsList() { return [ - { id: 0, type: 'incrementator', label: 'SLTS Visit Counter', data: { number: 0, name: '', datapointXid: '' } }, - { id: 1, type: 'camera', label: 'SLTS Image Component', data: { number: 0, label: '', cameraPath: '' } } + { id: 0, type: 'incrementator', label: 'SLTS Visit Counter', data: { number: 0, label: '', datapointXid: '' } }, + { id: 1, type: 'camera', label: 'SLTS Image Component', data: { number: 0, label: '', imageLocation: '' } }, + // { id: 2, type: 'iframe', label: 'SLTS Inlie Frame', data: { number: 0, label: '', frameLocation: '' } } ]; } From cc1dc0a985aed034db41ca62c448b72da8ba48f2 Mon Sep 17 00:00:00 2001 From: grzesiekb Date: Wed, 6 Sep 2017 13:09:02 +0200 Subject: [PATCH 38/54] feat: #344 Add proxy config to ScadaLTS UI --- ScadaLTS-UI/package.json | 5 +++-- ScadaLTS-UI/proxy.config.json | 17 +++++++++++++++++ ScadaLTS-UI/src/app/app.routing.ts | 2 +- .../assets/ScadaLTS/app/media/ScadaLogo.png | Bin 0 -> 28732 bytes .../src/assets/ScadaLTS/app/media/blur-bg.jpg | Bin 0 -> 473263 bytes .../assets/ScadaLTS/app/media/defaultUser.png | Bin 0 -> 1512 bytes ScadaLTS-UI/start.bat | 1 + ScadaLTS-UI/start.sh | 1 + 8 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 ScadaLTS-UI/proxy.config.json create mode 100644 ScadaLTS-UI/src/assets/ScadaLTS/app/media/ScadaLogo.png create mode 100644 ScadaLTS-UI/src/assets/ScadaLTS/app/media/blur-bg.jpg create mode 100644 ScadaLTS-UI/src/assets/ScadaLTS/app/media/defaultUser.png create mode 100644 ScadaLTS-UI/start.bat create mode 100644 ScadaLTS-UI/start.sh diff --git a/ScadaLTS-UI/package.json b/ScadaLTS-UI/package.json index dc4ce16eb4..b604795c88 100644 --- a/ScadaLTS-UI/package.json +++ b/ScadaLTS-UI/package.json @@ -25,19 +25,20 @@ "@angular/router": "^4.3.4", "@angular2-material/core": "2.0.0-alpha.8-3", "@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.22", + "@scadalts/scadalts-dashbord-components": "0.0.13", "@types/d3-selection": "^1.0.14", "angular2-highcharts": "^0.4.3", "c3": "^0.4.11", "core-js": "^2.5.0", "d3": "^4.7.4", "hammerjs": "^2.0.8", + "jquery": "^3.2.1", "ng2-bs3-modal": "^0.10.4", "ng2-material": "^0.8.1", "ngx-clipboard": "^3.0.7", "rxjs": "^5.4.2", "ts-helpers": "^1.1.2", - "zone.js": "^0.8.16", - "@scadalts/scadalts-dashbord-components": "0.0.13" + "zone.js": "^0.8.16" }, "devDependencies": { "@angular/cli": "1.3.0", diff --git a/ScadaLTS-UI/proxy.config.json b/ScadaLTS-UI/proxy.config.json new file mode 100644 index 0000000000..fafbb19332 --- /dev/null +++ b/ScadaLTS-UI/proxy.config.json @@ -0,0 +1,17 @@ +{ + "/api/*": { + "target": "http://localhost:8080/ScadaBR", + "secure": false, + "logLevel":"debug" + }, + "/ScadaLTS/app/media/*":{ + "target": "http://localhost:4200/assets/", + "secure": false, + "logLevel":"debug" + }, + "/ScadaBR/*": { + "target": "http://localhost:8080/", + "secure": false, + "logLevel":"debug" + } + } \ No newline at end of file diff --git a/ScadaLTS-UI/src/app/app.routing.ts b/ScadaLTS-UI/src/app/app.routing.ts index 71798b53fa..6f6b11e855 100644 --- a/ScadaLTS-UI/src/app/app.routing.ts +++ b/ScadaLTS-UI/src/app/app.routing.ts @@ -31,7 +31,7 @@ import { WorksheetAccessGuard } from './ActivationGuard'; import { DashboardGridComponent } from 'app/appBody/dashboard/dashboard-grid/dashboard-grid.component'; const appRoutes: Routes = [ - // { path: '', component: LoginComponent }, + { path: '', component: LoginComponent }, { path: '', redirectTo: 'appBody', pathMatch: 'full' }, { path: 'registration', component: RegistrationComponent }, { path: 'appBody', component: AppBodyComponent, diff --git a/ScadaLTS-UI/src/assets/ScadaLTS/app/media/ScadaLogo.png b/ScadaLTS-UI/src/assets/ScadaLTS/app/media/ScadaLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..be4b19360330b1767b684a313c20ac55ba294dfa GIT binary patch literal 28732 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 literal 0 HcmV?d00001 diff --git a/ScadaLTS-UI/src/assets/ScadaLTS/app/media/blur-bg.jpg b/ScadaLTS-UI/src/assets/ScadaLTS/app/media/blur-bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3f557e85b6aeee0f67ca0c5f1444b31d61f22345 GIT binary patch literal 473263 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%0D_XmTW?=F8q0A}BH>DR83CM4s%RIQ{(d>+VWp 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%0A< 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 {2uxx+tTd9?*}?`a9wW7mDi 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 literal 0 HcmV?d00001 diff --git a/ScadaLTS-UI/src/assets/ScadaLTS/app/media/defaultUser.png b/ScadaLTS-UI/src/assets/ScadaLTS/app/media/defaultUser.png new file mode 100644 index 0000000000000000000000000000000000000000..6c2134596a2ba0ec7ff08c2ffe8b49a0f9608740 GIT binary patch literal 1512 zcmVP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1${|GK~#8N?VM*% z+&~mX_y2!p>Am;fd#|E*kmybHCOS-Xtnr3`11#$|vn0OKRUl$L{IRP_whMYJPrRZEbC-hldCKSMi~^0r>Lr zqIPz6R8LQjDlRToX=!OHF)>kv!{Lbey`-c>?eFjFPuW*o09;#JQ&m+}DmgjX0hN@L z z#A)`XWep(tjhhFA7o@Kmh;CCSGW+}c)!p5lE=68e04^>rIyX<`y#*4Bftiqypvue3 z)y2hyE=^X(0j{pDIyZ{FAoyXTv8=32-QM2nQsrb6;L*{M%E-v@J@ULvB=+|9>XPMT z4B*q#ld7(+jydOj)kHWs@$BqO*FZ+b04^;p8H4AV^5*8|bPZ%=1R&8zVvlC1;)em) z*Vm_OAtNII4-O7QJB`1Y2iDTkqH7@|BLK(8$Bj2%48Vql23-po83EYb+-$u0V#=(m ztJAfRkvPET=Vw(~T54qI^40*Xt*zBHk&!q+2D7=jxz=)EO-+riiHyVnGNoehYzrU@ z4U!TE$O=hnYN{20qz$HYtTjqW9N^*Mq36w+FaQe+3!N2iDTxDQ4Cr-pCQQ_4W@f6( z%S&Aw|0NEP<#!v+*EM-?XlO{+#(x7`7;F%*^Q8_%CsQS65dmD=W(iK*}WgkB^UaZTy!w zK-L0n&V|W;KYAdICMPGYEN4;X^768-g^Y{f607>+I zZg=u9r1yZmWDOt#T?V{meSL*^`Du`(<%b^FYeDgC~P7(kA-4G#}HlY7a0_nCo6^h-hX6(CDh8yg#{ zqoc#w%B1ps_q5+J^9vgOKax8K!=0I#pF)#m1=8XFsP z7C{-mvC~flTww7QY0=ny@Z@RUC*c*`Xq)&ufTyRYYGPu-Io(bkbDtQ6{d8b|Gxy{M z1WlaI@2gv)e*h#e&?H@8|01l<>;?=ijbkCx)6*Z$YW@J&+S=-T*z3aon+YDbiIck6 zP4rsni2$^DiYngiMrB)Dn=`9=tq4F4;RMn5v6+gp=luG-O$4Aj(f9gb;NJ!!UjpRH z0Z7-)>II?d^`XGOO6smX^e{p5{h9&DP|uycH~@Jq zJ^=W2(~RAduMR-A1Nl#{KMwrfu;N8-#)To9@ALj-!)tGEPlZ?`3*bd>QXXH`7vjsh zg8Ub~8S?R6h9M651o Date: Thu, 7 Sep 2017 17:02:15 +0200 Subject: [PATCH 39/54] #347 Correcting save datapoint and render getHistoryTableData --- .../mango/web/dwr/DataPointDetailsDwr.java | 73 +++++++++---------- .../dao/pointvalues/PointValueDAO.java | 14 ++-- .../mango/service/PointValueService.java | 2 +- 3 files changed, 40 insertions(+), 49 deletions(-) diff --git a/src/com/serotonin/mango/web/dwr/DataPointDetailsDwr.java b/src/com/serotonin/mango/web/dwr/DataPointDetailsDwr.java index 37620e0f96..9328da3cb7 100644 --- a/src/com/serotonin/mango/web/dwr/DataPointDetailsDwr.java +++ b/src/com/serotonin/mango/web/dwr/DataPointDetailsDwr.java @@ -28,6 +28,9 @@ import org.directwebremoting.WebContextFactory; import org.joda.time.DateTime; +import org.scada_lts.dao.UserDAO; +import org.scada_lts.dao.model.point.PointValueAdnnotation; +import org.scada_lts.dao.pointvalues.PointValueAdnnotationsDAO; import com.serotonin.mango.Common; import com.serotonin.mango.rt.RuntimeManager; @@ -35,6 +38,7 @@ import com.serotonin.mango.rt.dataImage.DataPointRT; import com.serotonin.mango.rt.dataImage.PointValueFacade; import com.serotonin.mango.rt.dataImage.PointValueTime; +import com.serotonin.mango.rt.dataImage.SetPointSource; import com.serotonin.mango.rt.dataImage.types.ImageValue; import com.serotonin.mango.view.chart.StatisticsChartRenderer; import com.serotonin.mango.vo.DataPointVO; @@ -55,8 +59,7 @@ public class DataPointDetailsDwr extends BaseDwr { public WatchListState getPointData() { // Get the point from the user's session. It should have been set by the // controller. - HttpServletRequest request = WebContextFactory.get() - .getHttpServletRequest(); + HttpServletRequest request = WebContextFactory.get().getHttpServletRequest(); User user = Common.getUser(request); DataPointVO pointVO = user.getEditPoint(); @@ -70,8 +73,7 @@ public WatchListState getPointData() { WatchListState state = new WatchListState(); state.setId(Integer.toString(pointVO.getId())); - PointValueTime pointValue = prepareBasePointState( - Integer.toString(pointVO.getId()), state, pointVO, pointRT, + PointValueTime pointValue = prepareBasePointState(Integer.toString(pointVO.getId()), state, pointVO, pointRT, model); setPrettyText(state, pointVO, model, pointValue); if (state.getValue() != null) @@ -89,16 +91,21 @@ public DwrResponseI18n getHistoryTableData(int limit) { PointValueFacade facade = new PointValueFacade(pointVO.getId()); List rawData = facade.getLatestPointValues(limit); - List renderedData = new ArrayList( - rawData.size()); + List renderedData = new ArrayList(rawData.size()); for (PointValueTime pvt : rawData) { RenderedPointValueTime rpvt = new RenderedPointValueTime(); rpvt.setValue(Functions.getHtmlText(pointVO, pvt)); rpvt.setTime(Functions.getTime(pvt)); + if (pvt.isAnnotated()) { + AnnotatedPointValueTime apvt = (AnnotatedPointValueTime) pvt; - rpvt.setAnnotation(apvt.getAnnotation(getResourceBundle())); + if (apvt.getSourceDescriptionArgument() == null) { + apvt.setSourceDescriptionArgument(""); + } else { + rpvt.setAnnotation(apvt.getAnnotation(getResourceBundle())); + } } renderedData.add(rpvt); } @@ -110,14 +117,11 @@ public DwrResponseI18n getHistoryTableData(int limit) { } @MethodFilter - public DwrResponseI18n getImageChartData(int fromYear, int fromMonth, - int fromDay, int fromHour, int fromMinute, int fromSecond, - boolean fromNone, int toYear, int toMonth, int toDay, int toHour, - int toMinute, int toSecond, boolean toNone, int width, int height) { - DateTime from = createDateTime(fromYear, fromMonth, fromDay, fromHour, - fromMinute, fromSecond, fromNone); - DateTime to = createDateTime(toYear, toMonth, toDay, toHour, toMinute, - toSecond, toNone); + public DwrResponseI18n getImageChartData(int fromYear, int fromMonth, int fromDay, int fromHour, int fromMinute, + int fromSecond, boolean fromNone, int toYear, int toMonth, int toDay, int toHour, int toMinute, + int toSecond, boolean toNone, int width, int height) { + DateTime from = createDateTime(fromYear, fromMonth, fromDay, fromHour, fromMinute, fromSecond, fromNone); + DateTime to = createDateTime(toYear, toMonth, toDay, toHour, toMinute, toSecond, toNone); StringBuilder htmlData = new StringBuilder(); htmlData.append(" model = new HashMap(); model.put("point", pointVO); - StatisticsChartRenderer r = new StatisticsChartRenderer(periodType, - period, includeSum); + StatisticsChartRenderer r = new StatisticsChartRenderer(periodType, period, includeSum); r.addDataToModel(model, pointVO); DwrResponseI18n response = new DwrResponseI18n(); - response.addData("stats", - generateContent(request, "statsChart.jsp", model)); + response.addData("stats", generateContent(request, "statsChart.jsp", model)); addAsof(response); return response; } @@ -181,8 +177,7 @@ private DataPointVO getDataPointVO() { @MethodFilter public DwrResponseI18n getFlipbookData(int limit) { - HttpServletRequest request = WebContextFactory.get() - .getHttpServletRequest(); + HttpServletRequest request = WebContextFactory.get().getHttpServletRequest(); DataPointVO vo = Common.getUser(request).getEditPoint(); PointValueFacade facade = new PointValueFacade(vo.getId()); @@ -191,20 +186,20 @@ public DwrResponseI18n getFlipbookData(int limit) { List result = new ArrayList(); for (PointValueTime pvt : values) { ImageValue imageValue = (ImageValue) pvt.getValue(); - String uri = ImageValueServlet.servletPath - + ImageValueServlet.historyPrefix + pvt.getTime() + "_" + String uri = ImageValueServlet.servletPath + ImageValueServlet.historyPrefix + pvt.getTime() + "_" + vo.getId() + "." + imageValue.getTypeExtension(); result.add(new ImageValueBean(Functions.getTime(pvt), uri)); } DwrResponseI18n response = new DwrResponseI18n(); + System.out.println(result); response.addData("images", result); addAsof(response); return response; } private void addAsof(DwrResponseI18n response) { - response.addData("asof", new LocalizableMessage("dsDetils.asof", - DateFunctions.getFullSecondTime(System.currentTimeMillis()))); + response.addData("asof", + new LocalizableMessage("dsDetils.asof", DateFunctions.getFullSecondTime(System.currentTimeMillis()))); } } diff --git a/src/org/scada_lts/dao/pointvalues/PointValueDAO.java b/src/org/scada_lts/dao/pointvalues/PointValueDAO.java index 90237d3d9f..a20914b03c 100644 --- a/src/org/scada_lts/dao/pointvalues/PointValueDAO.java +++ b/src/org/scada_lts/dao/pointvalues/PointValueDAO.java @@ -251,22 +251,18 @@ public PointValue mapRow(ResultSet rs, int rowNum) throws SQLException { //TODO rewrite MangoValue MangoValue value = createMangoValue(rs); long time = rs.getLong(COLUMN_NAME_TIME_STAMP); - int sourceType = rs.getInt(COLUMN_NAME_SOURCE_TYPE); + PointValue pv = new PointValue(); pv.setId(rs.getLong(COLUMN_NAME_ID)); pv.setDataPointId(rs.getInt(COLUMN_NAME_DATA_POINT_ID)); + int sourceId = rs.getInt(COLUMN_NAME_SOURCE_ID); + int sourceType = rs.getInt(COLUMN_NAME_SOURCE_TYPE); - //TODO rewrite wasNull ? - //if (rs.wasNull()) { - if (rs.getLong(COLUMN_NAME_SOURCE_ID)==0){ - // No annotations, just return a point value. + if (rs.wasNull()) { pv.setPointValue(new PointValueTime(value, time)); } else { - // There was a source for the point value, so return an annotated - // version. - pv.setPointValue(new AnnotatedPointValueTime(value, time, sourceType, - rs.getInt(COLUMN_NAME_SOURCE_ID))); + pv.setPointValue(new AnnotatedPointValueTime(value, time, sourceType, sourceId)); } return pv; } diff --git a/src/org/scada_lts/mango/service/PointValueService.java b/src/org/scada_lts/mango/service/PointValueService.java index f5f6d6e837..66f1312fde 100644 --- a/src/org/scada_lts/mango/service/PointValueService.java +++ b/src/org/scada_lts/mango/service/PointValueService.java @@ -133,7 +133,7 @@ public long savePointValueImpl(final int pointId, final PointValueTime pointValu // Create a transaction within which to do the insert. - id = savePointValueInTrasaction(pointId, dataType, dvalueFinal, pointValue.getTime(), svalueFinal, source, async); + id = savePointValueInTrasaction(pointId, dataType, dvalueFinal, pointValue.getTime(), svalueFinal, source, false); } else // Single sql call, so no transaction required. From ebaad91f86d8799a0de12da5e079dc9b1c80996f Mon Sep 17 00:00:00 2001 From: Arkadiusz Parafiniuk Date: Mon, 11 Sep 2017 10:34:55 +0200 Subject: [PATCH 40/54] Project migration to Java 1.8 --- .classpath | 10 ++++---- .settings/org.eclipse.jdt.core.prefs | 24 +++++++++---------- ....eclipse.wst.common.project.facet.core.xml | 14 +++++------ .travis.yml | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.classpath b/.classpath index 912c741641..81a49932ca 100644 --- a/.classpath +++ b/.classpath @@ -112,11 +112,6 @@ - - - - - @@ -128,5 +123,10 @@ + + + + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index d17b6724d1..ace45ceefb 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,12 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.7 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml index 4c2c1a85b1..7314a2777d 100644 --- a/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,7 +1,7 @@ - - - - - - - + + + + + + + diff --git a/.travis.yml b/.travis.yml index b67e874791..f4a59e7588 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,7 +36,7 @@ before_script: - cd ../.. language: java jdk: -- openjdk7 +- openjdk8 services: - docker - mysql From a2f880971db50918305d40deee4c5f4e1053138a Mon Sep 17 00:00:00 2001 From: Arkadiusz Parafiniuk Date: Mon, 11 Sep 2017 11:52:39 +0200 Subject: [PATCH 41/54] Travis file corrected(Tomcat version) --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index f4a59e7588..70d861fe64 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,17 +59,17 @@ env: - secure: KNfVmgjr2ZNsnvIfuhSkZ/kPrSTjn6WSDxEJt/3ioTCgeEGGvPL7UGonHHozZu3WzpzBVyUr60hXjb1nmb9dk6A3Dg05UPZmuS7NiHEA4Ub2zQKgefSbK0AJEhXSDg+bT16Hqxf1aZDaAEpMXGWTGLdpbKkGAW56UZu6LpOlOvoX9pFoSWAyzh1jKiYQsaKJ3eCncHKug5WqTVidOL/ENR6CAYyVLkgZ0yffwsCyVAnh14vri2lswPhPsPvMzYxtLQGkKkUOYkuPOZvBD7l5mp5Y4QLv86iKTFlOteim7yD+RpZZDFpb+3+OhRuj6jlBYWina33RKqBqjhhsayyYN/tYnPUefZhT+ALs8JfUaDXqMdgd7NQj8i5ZvrB+YsCTUVGrnPVbmEq8A4l/An5ushQpK5CrASiAC0K4dOBVT+U89QHtYWuE3ZOmSb518dlbH084ljypAj3JTQpUgRAAxn21VUMKb6QyIPsSPVEQ+zPQnaxBLhYVqafO7iX1tyvdr0mGhLZjXaaGwQu8Y/RoHdmRYcQAGn6zVFNuxWxTlr2OQ0fJ5l6/qBVyqZvqNirYa5hX8KtDu3dVMo5VOirIsoJTw75qTpGxYjhCNCb/woxtRvfX9xoT7tINWOxi2ucFfObSCsTv+BPeZeJiq7UDuFQYsQtWjNRp/iQNJ+rclpQ= after_script: # get tomcat7 to ./docker/app -- wget http://www-us.apache.org/dist/tomcat/tomcat-7/v7.0.79/bin/apache-tomcat-7.0.79.tar.gz +- wget http://www-us.apache.org/dist/tomcat/tomcat-7/v7.0.81/bin/apache-tomcat-7.0.81.tar.gz - mkdir ./docker/app -- mv apache-tomcat-7.0.79.tar.gz ./docker/app -- ls -l ./docker/app/apache-tomcat-7.0.79.tar.gz +- mv apache-tomcat-7.0.81.tar.gz ./docker/app +- ls -l ./docker/app/apache-tomcat-7.0.81.tar.gz - cd ./docker/app - echo `pwd` - echo `ls -l` -- tar -zxvf apache-tomcat-7.0.79.tar.gz +- tar -zxvf apache-tomcat-7.0.81.tar.gz - ls -l -- mv ./apache-tomcat-7.0.79/* ./ -- rm -rf ./apache-tomcat-7.0.79 +- mv ./apache-tomcat-7.0.81/* ./ +- rm -rf ./apache-tomcat-7.0.81 - cp ../../ScadaBR.war ./webapps - cp ../../ScadaLTS-UI/war/ScadaLTS.war ./webapps - ls -l ./webapps/ScadaLTS.war From ed344c13620ffc2edb3cede541fadab6e86e8aae Mon Sep 17 00:00:00 2001 From: Arkadiusz Parafiniuk Date: Tue, 12 Sep 2017 12:11:39 +0200 Subject: [PATCH 42/54] List of views sorting by name fixed --- .../web/mvc/controller/ViewsController.java | 196 +++++++++--------- 1 file changed, 103 insertions(+), 93 deletions(-) diff --git a/src/com/serotonin/mango/web/mvc/controller/ViewsController.java b/src/com/serotonin/mango/web/mvc/controller/ViewsController.java index 7d0a9ffa11..76a41828b0 100644 --- a/src/com/serotonin/mango/web/mvc/controller/ViewsController.java +++ b/src/com/serotonin/mango/web/mvc/controller/ViewsController.java @@ -1,93 +1,103 @@ -/* - Mango - Open Source M2M - http://mango.serotoninsoftware.com - Copyright (C) 2006-2011 Serotonin Software Technologies Inc. - @author Matthew Lohbihler - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -package com.serotonin.mango.web.mvc.controller; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.servlet.mvc.ParameterizableViewController; - -import com.serotonin.db.IntValuePair; -import com.serotonin.mango.Common; -import com.serotonin.mango.db.dao.ViewDao; -import com.serotonin.mango.view.ShareUser; -import com.serotonin.mango.view.View; -import com.serotonin.mango.vo.User; -import com.serotonin.mango.vo.permission.Permissions; - -public class ViewsController extends ParameterizableViewController { - private Log LOG = LogFactory.getLog(ViewsController.class); - - @Override - protected ModelAndView handleRequestInternal(HttpServletRequest request, - HttpServletResponse response) throws Exception { - Map model = new HashMap(); - ViewDao viewDao = new ViewDao(); - User user = Common.getUser(request); - List views; - - if (user.isAdmin()) { // Admin user has access to all views - views = viewDao.getAllViewNames(); - LOG.debug("Views: " + views.size()); - model.put("views", views); - - } else { - views = viewDao.getViewNamesWithReadOrWritePermissions( - user.getId(), user.getUserProfile()); - model.put("views", views); - } - - // Set the current view. - View currentView = null; - String vid = request.getParameter("viewId"); - try { - currentView = viewDao.getView(Integer.parseInt(vid)); - } catch (NumberFormatException e) { - // no op - } - - if (currentView == null && views.size() > 0) - currentView = viewDao.getView(views.get(0).getKey()); - - if (currentView != null) { - if (!user.isAdmin()) - Permissions.ensureViewPermission(user, currentView); - - // Make sure the owner still has permission to all of the points in - // the view, and that components are - // otherwise valid. - currentView.validateViewComponents(false); - - // Add the view to the session for the dwr access stuff. - model.put("currentView", currentView); - model.put("owner", - currentView.getUserAccess(user) == ShareUser.ACCESS_OWNER); - user.setView(currentView); - } - - return new ModelAndView(getViewName(), model); - } -} +/* + Mango - Open Source M2M - http://mango.serotoninsoftware.com + Copyright (C) 2006-2011 Serotonin Software Technologies Inc. + @author Matthew Lohbihler + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +package com.serotonin.mango.web.mvc.controller; + +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.ParameterizableViewController; + +import com.serotonin.db.IntValuePair; +import com.serotonin.mango.Common; +import com.serotonin.mango.db.dao.ViewDao; +import com.serotonin.mango.view.ShareUser; +import com.serotonin.mango.view.View; +import com.serotonin.mango.vo.User; +import com.serotonin.mango.vo.permission.Permissions; + +public class ViewsController extends ParameterizableViewController { + private Log LOG = LogFactory.getLog(ViewsController.class); + + @Override + protected ModelAndView handleRequestInternal(HttpServletRequest request, + HttpServletResponse response) throws Exception { + Map model = new HashMap(); + ViewDao viewDao = new ViewDao(); + User user = Common.getUser(request); + List views; + + if (user.isAdmin()) { // Admin user has access to all views + views = viewDao.getAllViewNames(); + Comparator comp = (IntValuePair prev, IntValuePair next) -> { + return prev.getValue().compareTo(next.getValue()); + }; + Collections.sort(views, comp); + if(LOG.isDebugEnabled()) LOG.debug("Views: " + views.size()); + model.put("views", views); + } else { + views = viewDao.getViewNamesWithReadOrWritePermissions( + user.getId(), user.getUserProfile()); + Comparator comp = (IntValuePair prev, IntValuePair next) -> { + return prev.getValue().compareTo(next.getValue()); + }; + Collections.sort(views, comp); + if(LOG.isDebugEnabled()) LOG.debug("Views: " + views.size()); + model.put("views", views); + } + + // Set the current view. + View currentView = null; + String vid = request.getParameter("viewId"); + try { + currentView = viewDao.getView(Integer.parseInt(vid)); + } catch (NumberFormatException e) { + // no op + } + + if (currentView == null && views.size() > 0) + currentView = viewDao.getView(views.get(0).getKey()); + + if (currentView != null) { + if (!user.isAdmin()) + Permissions.ensureViewPermission(user, currentView); + + // Make sure the owner still has permission to all of the points in + // the view, and that components are + // otherwise valid. + currentView.validateViewComponents(false); + + // Add the view to the session for the dwr access stuff. + model.put("currentView", currentView); + model.put("owner", + currentView.getUserAccess(user) == ShareUser.ACCESS_OWNER); + user.setView(currentView); + } + + return new ModelAndView(getViewName(), model); + } +} From fdffebf3e460a066e2dd33dc8681316a6c3f41cf Mon Sep 17 00:00:00 2001 From: Arkadiusz Parafiniuk Date: Tue, 12 Sep 2017 13:10:44 +0200 Subject: [PATCH 43/54] Java version fix in build.xml --- build.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.xml b/build.xml index c87f1b49d6..99b5492df3 100644 --- a/build.xml +++ b/build.xml @@ -7,8 +7,8 @@ - - + + From cf451a414a0211dce1bdb169e1f21a7f58ded86b Mon Sep 17 00:00:00 2001 From: sdtabilit Date: Wed, 13 Sep 2017 10:46:38 +0200 Subject: [PATCH 44/54] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index df6c97e145..0eee5fc867 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![GPL-2.0](https://img.shields.io/npm/l/gb-json.svg?style=flat-square)](https://github.com/sdtabilit/Scada-LTS/blob/master-sdtabilit/LICENSE) [![](https://images.microbadger.com/badges/version/dockergb/scadalts-dev.svg)](https://microbadger.com/images/dockergb/scadalts-dev "Get your own version badge on microbadger.com") [![](https://images.microbadger.com/badges/image/dockergb/scadalts-dev.svg)](https://microbadger.com/images/dockergb/scadalts-dev "Get your own image badge on microbadger.com") +[![Stories in Ready](https://badge.waffle.io/SCADA-LTS/Scada-LTS.svg?label=ready&title=Ready)](http://waffle.io/SCADA-LTS/Scada-LTS) Scada-LTS is an Open Source, web-based, multi-platform solution for building your own SCADA (Supervisory Control and Data Acquisiton) system. From 6be4b329e10ced1f84f485509b4e9564a809fce6 Mon Sep 17 00:00:00 2001 From: grzesiekb Date: Wed, 13 Sep 2017 15:26:55 +0200 Subject: [PATCH 45/54] #368 enable/disable/reset data pointthat have an EventDetector in cont --- src/org/scada_lts/mango/service/DataPointService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/org/scada_lts/mango/service/DataPointService.java b/src/org/scada_lts/mango/service/DataPointService.java index ce9320fc5c..b1acb67d8a 100644 --- a/src/org/scada_lts/mango/service/DataPointService.java +++ b/src/org/scada_lts/mango/service/DataPointService.java @@ -44,7 +44,7 @@ import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.UncategorizedSQLException; import org.springframework.stereotype.Service; - +import org.springframework.dao.DuplicateKeyException; import com.serotonin.db.IntValuePair; import com.serotonin.mango.Common; import com.serotonin.mango.db.dao.PointValueDao; @@ -358,7 +358,11 @@ private void saveEventDetectors(DataPointVO dataPoint) { for (PointEventDetectorVO pointEventDetector: dataPoint.getEventDetectors()) { if (pointEventDetector.getId() < 0) { - pointEventDetectorDAO.insert(pointEventDetector); + try { + pointEventDetectorDAO.insert(pointEventDetector); + } catch (DuplicateKeyException e) { + pointEventDetectorDAO.update(pointEventDetector); + } } else { pointEventDetectorDAO.update(pointEventDetector); } From 510e5bf550cf57e8ec57ba23635752fdd438f910 Mon Sep 17 00:00:00 2001 From: Arkadiusz Parafiniuk Date: Fri, 22 Sep 2017 10:45:33 +0200 Subject: [PATCH 46/54] Removed warning for "None-level alarms" --- WebContent/WEB-INF/snippet/warningContent.jsp | 122 ++++++++++-------- 1 file changed, 68 insertions(+), 54 deletions(-) diff --git a/WebContent/WEB-INF/snippet/warningContent.jsp b/WebContent/WEB-INF/snippet/warningContent.jsp index 20ca7245ab..d4608e2fa2 100644 --- a/WebContent/WEB-INF/snippet/warningContent.jsp +++ b/WebContent/WEB-INF/snippet/warningContent.jsp @@ -1,55 +1,69 @@ -<%-- - Mango - Open Source M2M - http://mango.serotoninsoftware.com - Copyright (C) 2006-2011 Serotonin Software Technologies Inc. - @author Matthew Lohbihler - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. ---%><%@ include file="/WEB-INF/jsp/include/tech.jsp" %> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
 ${sst:time(event.activeTimestamp)} 
+<%-- + Mango - Open Source M2M - http://mango.serotoninsoftware.com + Copyright (C) 2006-2011 Serotonin Software Technologies Inc. + @author Matthew Lohbihler + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +--%><%@ include file="/WEB-INF/jsp/include/tech.jsp" %> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
 ${sst:time(event.activeTimestamp)} 
+ +
\ No newline at end of file From f91c60872accce976e686833162c581aee096772 Mon Sep 17 00:00:00 2001 From: Arkadiusz Parafiniuk Date: Fri, 22 Sep 2017 11:46:38 +0200 Subject: [PATCH 47/54] Code clean --- WebContent/WEB-INF/snippet/warningContent.jsp | 88 +++++++++---------- 1 file changed, 42 insertions(+), 46 deletions(-) diff --git a/WebContent/WEB-INF/snippet/warningContent.jsp b/WebContent/WEB-INF/snippet/warningContent.jsp index d4608e2fa2..63c5aa0084 100644 --- a/WebContent/WEB-INF/snippet/warningContent.jsp +++ b/WebContent/WEB-INF/snippet/warningContent.jsp @@ -17,53 +17,49 @@ along with this program. If not, see http://www.gnu.org/licenses/. --%><%@ include file="/WEB-INF/jsp/include/tech.jsp" %> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + +
- - -
+ + + + + + + + - - - - + + - - - -
 ${sst:time(event.activeTimestamp)} 
- + + + + + + + + + + + + + + + + +   + ${sst:time(event.activeTimestamp)} +   + + + + +
\ No newline at end of file From 18f30916dd11648d8c10e405b25389046a85c087 Mon Sep 17 00:00:00 2001 From: grzesiekb Date: Fri, 22 Sep 2017 12:49:12 +0200 Subject: [PATCH 48/54] fix: #379 angular library fix --- ScadaLTS-UI/package.json | 86 ++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/ScadaLTS-UI/package.json b/ScadaLTS-UI/package.json index b604795c88..1090e38ba6 100644 --- a/ScadaLTS-UI/package.json +++ b/ScadaLTS-UI/package.json @@ -12,55 +12,55 @@ }, "private": true, "dependencies": { - "@angular/animations": "^4.3.4", - "@angular/cdk": "^2.0.0-beta.8", - "@angular/common": "^4.3.4", - "@angular/compiler": "^4.3.4", - "@angular/core": "^4.3.4", - "@angular/forms": "^4.3.4", - "@angular/http": "^4.3.4", - "@angular/material": "^2.0.0-beta.8", - "@angular/platform-browser": "^4.3.4", - "@angular/platform-browser-dynamic": "^4.3.4", - "@angular/router": "^4.3.4", + "@angular/animations": "4.3.4", + "@angular/cdk": "2.0.0-beta.8", + "@angular/common": "4.3.4", + "@angular/compiler": "4.3.4", + "@angular/core": "4.3.4", + "@angular/forms": "4.3.4", + "@angular/http": "4.3.4", + "@angular/material": "2.0.0-beta.8", + "@angular/platform-browser": "4.3.4", + "@angular/platform-browser-dynamic": "4.3.4", + "@angular/router": "4.3.4", "@angular2-material/core": "2.0.0-alpha.8-3", "@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.22", "@scadalts/scadalts-dashbord-components": "0.0.13", - "@types/d3-selection": "^1.0.14", - "angular2-highcharts": "^0.4.3", - "c3": "^0.4.11", - "core-js": "^2.5.0", - "d3": "^4.7.4", - "hammerjs": "^2.0.8", - "jquery": "^3.2.1", - "ng2-bs3-modal": "^0.10.4", - "ng2-material": "^0.8.1", - "ngx-clipboard": "^3.0.7", - "rxjs": "^5.4.2", - "ts-helpers": "^1.1.2", - "zone.js": "^0.8.16" + "@types/d3-selection": "1.0.14", + "angular2-highcharts": "0.4.3", + "c3": "0.4.11", + "core-js": "2.5.0", + "d3": "4.7.4", + "hammerjs": "2.0.8", + "jquery": "3.2.1", + "ng2-bs3-modal": "0.10.4", + "ng2-material": "0.8.1", + "ngx-clipboard": "3.0.7", + "rxjs": "5.4.2", + "ts-helpers": "1.1.2", + "zone.js": "0.8.16" }, "devDependencies": { "@angular/cli": "1.3.0", - "@angular/compiler-cli": "^4.3.4", - "@angular/language-service": "^4.3.4", - "@types/jasmine": "~2.5.53", - "@types/jasminewd2": "~2.0.2", - "@types/jquery": "^3.2.12", - "@types/node": "~8.0.20", - "codelyzer": "~3.1.1", - "jasmine-core": "~2.7.0", - "jasmine-spec-reporter": "~4.2.1", - "karma": "^1.7.0", - "karma-chrome-launcher": "~2.2.0", - "karma-cli": "~1.0.1", - "karma-jasmine": "~1.1.0", - "karma-jasmine-html-reporter": "^0.2.2", - "karma-remap-istanbul": "^0.2.1", - "protractor": "~5.1.2", - "ts-node": "~3.3.0", - "tslint": "~5.6.0", - "typescript": "~2.4.2", + "@angular/compiler-cli": "4.3.4", + "@angular/language-service": "4.3.4", + "@types/jasmine": "2.5.53", + "@types/jasminewd2": "2.0.2", + "@types/jquery": "3.2.12", + "@types/node": "8.0.20", + "codelyzer": "3.1.1", + "jasmine-core": "2.7.0", + "jasmine-spec-reporter": "4.2.1", + "karma": "1.7.0", + "karma-chrome-launcher": "2.2.0", + "karma-cli": "1.0.1", + "karma-jasmine": "1.1.0", + "karma-jasmine-html-reporter": "0.2.2", + "karma-remap-istanbul": "0.2.1", + "protractor": "5.1.2", + "ts-node": "3.3.0", + "tslint": "5.6.0", + "typescript": "2.4.2", "webdriver-manager": "10.2.5" } } From 14ecae1a8afb517eb6151a430b5e7459deee29d9 Mon Sep 17 00:00:00 2001 From: Arkadiusz Parafiniuk Date: Fri, 22 Sep 2017 15:48:28 +0200 Subject: [PATCH 49/54] #382 No more display of none-level alarm warnings on watchlist --- .../WEB-INF/snippet/watchListMessages.jsp | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/WebContent/WEB-INF/snippet/watchListMessages.jsp b/WebContent/WEB-INF/snippet/watchListMessages.jsp index cd29a7a65a..2b3bd79f7c 100644 --- a/WebContent/WEB-INF/snippet/watchListMessages.jsp +++ b/WebContent/WEB-INF/snippet/watchListMessages.jsp @@ -1,34 +1,36 @@ -<%-- - Mango - Open Source M2M - http://mango.serotoninsoftware.com - Copyright (C) 2006-2011 Serotonin Software Technologies Inc. - @author Matthew Lohbihler - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. ---%> -<%-- - This snippet supports all data types. ---%> -<%@ include file="/WEB-INF/snippet/common.jsp" %> - -
-
- - -
-
- - - ${sst:time(event.activeTimestamp)} - -
+<%-- + Mango - Open Source M2M - http://mango.serotoninsoftware.com + Copyright (C) 2006-2011 Serotonin Software Technologies Inc. + @author Matthew Lohbihler + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +--%> +<%-- + This snippet supports all data types. +--%> +<%@ include file="/WEB-INF/snippet/common.jsp" %> + +
+
+ + +
+
+ + + + ${sst:time(event.activeTimestamp)} - +
+
\ No newline at end of file From c36c060246ecd635ca238d60b6e3a181c31427bb Mon Sep 17 00:00:00 2001 From: Arkadiusz Parafiniuk Date: Mon, 25 Sep 2017 11:52:04 +0200 Subject: [PATCH 50/54] #384 Event detectors are not deleted while saving a data point. --- .../serotonin/mango/rt/RuntimeManager.java | 1748 ++++++++--------- 1 file changed, 874 insertions(+), 874 deletions(-) diff --git a/src/com/serotonin/mango/rt/RuntimeManager.java b/src/com/serotonin/mango/rt/RuntimeManager.java index 91f7d4f979..27792e828e 100644 --- a/src/com/serotonin/mango/rt/RuntimeManager.java +++ b/src/com/serotonin/mango/rt/RuntimeManager.java @@ -1,874 +1,874 @@ -/* - Mango - Open Source M2M - http://mango.serotoninsoftware.com - Copyright (C) 2006-2011 Serotonin Software Technologies Inc. - @author Matthew Lohbihler - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -package com.serotonin.mango.rt; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.util.Assert; - -import com.serotonin.ShouldNeverHappenException; -import com.serotonin.mango.Common; -import com.serotonin.mango.db.dao.CompoundEventDetectorDao; -import com.serotonin.mango.db.dao.DataPointDao; -import com.serotonin.mango.db.dao.DataSourceDao; -import com.serotonin.mango.db.dao.MaintenanceEventDao; -import com.serotonin.mango.db.dao.PointLinkDao; -import com.serotonin.mango.db.dao.PointValueDao; -import com.serotonin.mango.db.dao.PublisherDao; -import com.serotonin.mango.db.dao.ScheduledEventDao; -import com.serotonin.mango.rt.dataImage.DataPointEventMulticaster; -import com.serotonin.mango.rt.dataImage.DataPointListener; -import com.serotonin.mango.rt.dataImage.DataPointRT; -import com.serotonin.mango.rt.dataImage.PointValueTime; -import com.serotonin.mango.rt.dataImage.SetPointSource; -import com.serotonin.mango.rt.dataImage.types.MangoValue; -import com.serotonin.mango.rt.dataSource.DataSourceRT; -import com.serotonin.mango.rt.dataSource.meta.MetaDataSourceRT; -import com.serotonin.mango.rt.event.SimpleEventDetector; -import com.serotonin.mango.rt.event.compound.CompoundEventDetectorRT; -import com.serotonin.mango.rt.event.detectors.PointEventDetectorRT; -import com.serotonin.mango.rt.event.maintenance.MaintenanceEventRT; -import com.serotonin.mango.rt.event.schedule.ScheduledEventRT; -import com.serotonin.mango.rt.link.PointLinkRT; -import com.serotonin.mango.rt.publish.PublisherRT; -import com.serotonin.mango.util.DateUtils; -import com.serotonin.mango.vo.DataPointVO; -import com.serotonin.mango.vo.dataSource.DataSourceVO; -import com.serotonin.mango.vo.event.CompoundEventDetectorVO; -import com.serotonin.mango.vo.event.MaintenanceEventVO; -import com.serotonin.mango.vo.event.PointEventDetectorVO; -import com.serotonin.mango.vo.event.ScheduledEventVO; -import com.serotonin.mango.vo.link.PointLinkVO; -import com.serotonin.mango.vo.publish.PublishedPointVO; -import com.serotonin.mango.vo.publish.PublisherVO; -import com.serotonin.util.LifecycleException; -import com.serotonin.web.i18n.LocalizableException; -import com.serotonin.web.i18n.LocalizableMessage; - -public class RuntimeManager { - private static final Log LOG = LogFactory.getLog(RuntimeManager.class); - - private final List runningDataSources = new CopyOnWriteArrayList(); - - /** - * Provides a quick lookup map of the running data points. - */ - private final Map dataPoints = new ConcurrentHashMap(); - - /** - * The list of point listeners, kept here such that listeners can be - * notified of point initializations (i.e. a listener can register itself - * before the point is enabled). - */ - private final Map dataPointListeners = new ConcurrentHashMap(); - - /** - * Store of enabled event detectors. - */ - private final Map simpleEventDetectors = new ConcurrentHashMap(); - - /** - * Store of enabled compound event detectors. - */ - private final Map compoundEventDetectors = new ConcurrentHashMap(); - - /** - * Store of enabled publishers - */ - private final List> runningPublishers = new CopyOnWriteArrayList>(); - - /** - * Store of enabled point links - */ - private final List pointLinks = new CopyOnWriteArrayList(); - - /** - * Store of maintenance events - */ - private final List maintenanceEvents = new CopyOnWriteArrayList(); - - private boolean started = false; - - // - // Lifecycle - synchronized public void initialize(boolean safe) { - if (started) - throw new ShouldNeverHappenException( - "RuntimeManager already started"); - - // Set the started indicator to true. - started = true; - - // Initialize data sources that are enabled. - DataSourceDao dataSourceDao = new DataSourceDao(); - List> configs = dataSourceDao.getDataSources(); - List> pollingRound = new ArrayList>(); - for (DataSourceVO config : configs) { - if (config.isEnabled()) { - if (safe) { - config.setEnabled(false); - dataSourceDao.saveDataSource(config); - } else if (initializeDataSource(config)) - pollingRound.add(config); - } - } - - // Set up point links. - PointLinkDao pointLinkDao = new PointLinkDao(); - for (PointLinkVO vo : pointLinkDao.getPointLinks()) { - if (!vo.isDisabled()) { - if (safe) { - vo.setDisabled(true); - pointLinkDao.savePointLink(vo); - } else - startPointLink(vo); - } - } - - // Tell the data sources to start polling. Delaying the polling start - // gives the data points a chance to - // initialize such that point listeners in meta points and set point - // handlers can run properly. - for (DataSourceVO config : pollingRound) - startDataSourcePolling(config); - - // Initialize the scheduled events. - ScheduledEventDao scheduledEventDao = new ScheduledEventDao(); - List scheduledEvents = scheduledEventDao - .getScheduledEvents(); - for (ScheduledEventVO se : scheduledEvents) { - if (!se.isDisabled()) { - if (safe) { - se.setDisabled(true); - scheduledEventDao.saveScheduledEvent(se); - } else - startScheduledEvent(se); - } - } - - // Initialize the compound events. - CompoundEventDetectorDao compoundEventDetectorDao = new CompoundEventDetectorDao(); - List compoundDetectors = compoundEventDetectorDao - .getCompoundEventDetectors(); - for (CompoundEventDetectorVO ced : compoundDetectors) { - if (!ced.isDisabled()) { - if (safe) { - ced.setDisabled(true); - compoundEventDetectorDao.saveCompoundEventDetector(ced); - } else - startCompoundEventDetector(ced); - } - } - - // Start the publishers that are enabled - PublisherDao publisherDao = new PublisherDao(); - List> publishers = publisherDao - .getPublishers(); - for (PublisherVO vo : publishers) { - if (vo.isEnabled()) { - if (safe) { - vo.setEnabled(false); - publisherDao.savePublisher(vo); - } else - startPublisher(vo); - } - } - - // Start the maintenance events that are enabled - MaintenanceEventDao maintenanceEventDao = new MaintenanceEventDao(); - for (MaintenanceEventVO vo : maintenanceEventDao.getMaintenanceEvents()) { - if (!vo.isDisabled()) { - if (safe) { - vo.setDisabled(true); - maintenanceEventDao.saveMaintenanceEvent(vo); - } else - startMaintenanceEvent(vo); - } - } - } - - synchronized public void terminate() { - if (!started) - throw new ShouldNeverHappenException( - "RuntimeManager not yet started"); - - started = false; - for (MaintenanceEventRT me : maintenanceEvents) - stopMaintenanceEvent(me.getVo().getId()); - - for (PublisherRT publisher : runningPublishers) - stopPublisher(publisher.getId()); - - for (Integer id : compoundEventDetectors.keySet()) - stopCompoundEventDetector(id); - - for (PointLinkRT pointLink : pointLinks) - stopPointLink(pointLink.getId()); - - // First stop meta data sources. - for (DataSourceRT dataSource : runningDataSources) { - if (dataSource instanceof MetaDataSourceRT) - stopDataSource(dataSource.getId()); - } - // Then stop everything else. - for (DataSourceRT dataSource : runningDataSources) - stopDataSource(dataSource.getId()); - - for (String key : simpleEventDetectors.keySet()) - stopSimpleEventDetector(key); - } - - public void joinTermination() { - for (DataSourceRT dataSource : runningDataSources) { - try { - dataSource.joinTermination(); - } catch (ShouldNeverHappenException e) { - LOG.error("Error stopping data source " + dataSource.getId(), e); - } - } - } - - // - // - // Data sources - // - public DataSourceRT getRunningDataSource(int dataSourceId) { - for (DataSourceRT dataSource : runningDataSources) { - if (dataSource.getId() == dataSourceId) - return dataSource; - } - return null; - } - - public boolean isDataSourceRunning(int dataSourceId) { - return getRunningDataSource(dataSourceId) != null; - } - - public List> getDataSources() { - return new DataSourceDao().getDataSources(); - } - - public DataSourceVO getDataSource(int dataSourceId) { - return new DataSourceDao().getDataSource(dataSourceId); - } - - public void deleteDataSource(int dataSourceId) { - stopDataSource(dataSourceId); - new DataSourceDao().deleteDataSource(dataSourceId); - Common.ctx.getEventManager().cancelEventsForDataSource(dataSourceId); - } - - public void saveDataSource(DataSourceVO vo) { - LOG.debug("Stoping DS: " + vo.getName()); - // If the data source is running, stop it. - stopDataSource(vo.getId()); - LOG.debug("DS Stoped!"); - - // In case this is a new data source, we need to save to the database - // first so that it has a proper id. - LOG.debug("Saving DS: " + vo.getName()); - new DataSourceDao().saveDataSource(vo); - LOG.debug("DS saved!"); - // If the data source is enabled, start it. - if (vo.isEnabled()) { - LOG.debug("Starting DS: " + vo.getName()); - if (initializeDataSource(vo)) { - LOG.debug("DS Started!"); - startDataSourcePolling(vo); - LOG.debug("DS polling Started!"); - } - } - } - - private boolean initializeDataSource(DataSourceVO vo) { - synchronized (runningDataSources) { - // If the data source is already running, just quit. - if (isDataSourceRunning(vo.getId())) - return false; - - // Ensure that the data source is enabled. - Assert.isTrue(vo.isEnabled()); - - // Create and initialize the runtime version of the data source. - DataSourceRT dataSource = vo.createDataSourceRT(); - dataSource.initialize(); - - // Add it to the list of running data sources. - runningDataSources.add(dataSource); - - // Add the enabled points to the data source. - List dataSourcePoints = new DataPointDao() - .getDataPoints(vo.getId(), null); - for (DataPointVO dataPoint : dataSourcePoints) { - if (dataPoint.isEnabled()) - startDataPoint(dataPoint); - } - - LOG.info("Data source '" + vo.getName() + "' initialized"); - - return true; - } - } - - private void startDataSourcePolling(DataSourceVO vo) { - DataSourceRT dataSource = getRunningDataSource(vo.getId()); - if (dataSource != null) - dataSource.beginPolling(); - } - - public void stopDataSource(int id) { - synchronized (runningDataSources) { - DataSourceRT dataSource = getRunningDataSource(id); - if (dataSource == null) - return; - - // Stop the data points. - for (DataPointRT p : dataPoints.values()) { - if (p.getDataSourceId() == id) - stopDataPoint(p.getId()); - } - - runningDataSources.remove(dataSource); - dataSource.terminate(); - - dataSource.joinTermination(); - LOG.info("Data source '" + dataSource.getName() + "' stopped"); - } - } - - // - // - // Data points - // - public void saveDataPoint(DataPointVO point) { - stopDataPoint(point.getId()); - - // Since the point's data type may have changed, we must ensure that the - // other attrtibutes are still ok with - // it. - int dataType = point.getPointLocator().getDataTypeId(); - - // Chart renderer - if (point.getChartRenderer() != null - && !point.getChartRenderer().getDef().supports(dataType)) - // Return to a default renderer - point.setChartRenderer(null); - - // Text renderer - if (point.getTextRenderer() != null - && !point.getTextRenderer().getDef().supports(dataType)) - // Return to a default renderer - point.defaultTextRenderer(); - - // Event detectors - Iterator peds = point.getEventDetectors() - .iterator(); - while (peds.hasNext()) { - PointEventDetectorVO ped = peds.next(); - if (!ped.getDef().supports(dataType)) - // Remove the detector. - peds.remove(); - } - - new DataPointDao().saveDataPoint(point); - - if (point.isEnabled()) - startDataPoint(point); - } - - public void deleteDataPoint(DataPointVO point) { - if (point.isEnabled()) - stopDataPoint(point.getId()); - new DataPointDao().deleteDataPoint(point.getId()); - Common.ctx.getEventManager().cancelEventsForDataPoint(point.getId()); - } - - private void startDataPoint(DataPointVO vo) { - synchronized (dataPoints) { - Assert.isTrue(vo.isEnabled()); - - // Only add the data point if its data source is enabled. - DataSourceRT ds = getRunningDataSource(vo.getDataSourceId()); - if (ds != null) { - // Change the VO into a data point implementation. - DataPointRT dataPoint = new DataPointRT(vo, vo - .getPointLocator().createRuntime()); - - // Add/update it in the data image. - dataPoints.put(dataPoint.getId(), dataPoint); - - // Initialize it. - dataPoint.initialize(); - DataPointListener l = getDataPointListeners(vo.getId()); - if (l != null) - l.pointInitialized(); - - // Add/update it in the data source. - ds.addDataPoint(dataPoint); - } - } - } - - private void stopDataPoint(int dataPointId) { - synchronized (dataPoints) { - // Remove this point from the data image if it is there. If not, - // just quit. - DataPointRT p = dataPoints.remove(dataPointId); - - // Remove it from the data source, and terminate it. - if (p != null) { - getRunningDataSource(p.getDataSourceId()).removeDataPoint(p); - DataPointListener l = getDataPointListeners(dataPointId); - if (l != null) - l.pointTerminated(); - p.terminate(); - } - } - } - - public boolean isDataPointRunning(int dataPointId) { - return dataPoints.get(dataPointId) != null; - } - - public DataPointRT getDataPoint(int dataPointId) { - return dataPoints.get(dataPointId); - } - - public void addDataPointListener(int dataPointId, DataPointListener l) { - DataPointListener listeners = dataPointListeners.get(dataPointId); - dataPointListeners.put(dataPointId, - DataPointEventMulticaster.add(listeners, l)); - } - - public void removeDataPointListener(int dataPointId, DataPointListener l) { - DataPointListener listeners = DataPointEventMulticaster.remove( - dataPointListeners.get(dataPointId), l); - if (listeners == null) - dataPointListeners.remove(dataPointId); - else - dataPointListeners.put(dataPointId, listeners); - } - - public DataPointListener getDataPointListeners(int dataPointId) { - return dataPointListeners.get(dataPointId); - } - - // - // Point values - public void setDataPointValue(int dataPointId, MangoValue value, - SetPointSource source) { - setDataPointValue(dataPointId, - new PointValueTime(value, System.currentTimeMillis()), source); - } - - public void setDataPointValue(int dataPointId, PointValueTime valueTime, - SetPointSource source) { - DataPointRT dataPoint = dataPoints.get(dataPointId); - if (dataPoint == null) - throw new RTException("Point is not enabled"); - - if (!dataPoint.getPointLocator().isSettable()) - throw new RTException("Point is not settable"); - - // Tell the data source to set the value of the point. - DataSourceRT ds = getRunningDataSource(dataPoint.getDataSourceId()); - // The data source may have been disabled. Just make sure. - if (ds != null) - ds.setPointValue(dataPoint, valueTime, source); - } - - public void relinquish(int dataPointId) { - DataPointRT dataPoint = dataPoints.get(dataPointId); - if (dataPoint == null) - throw new RTException("Point is not enabled"); - - if (!dataPoint.getPointLocator().isSettable()) - throw new RTException("Point is not settable"); - if (!dataPoint.getPointLocator().isRelinquishable()) - throw new RTException("Point is not relinquishable"); - - // Tell the data source to relinquish value of the point. - DataSourceRT ds = getRunningDataSource(dataPoint.getDataSourceId()); - // The data source may have been disabled. Just make sure. - if (ds != null) - ds.relinquish(dataPoint); - } - - public void forcePointRead(int dataPointId) { - DataPointRT dataPoint = dataPoints.get(dataPointId); - if (dataPoint == null) - throw new RTException("Point is not enabled"); - - // Tell the data source to read the point value; - DataSourceRT ds = getRunningDataSource(dataPoint.getDataSourceId()); - if (ds != null) - // The data source may have been disabled. Just make sure. - ds.forcePointRead(dataPoint); - } - - public long purgeDataPointValues() { - /* - PointValueDao pointValueDao = new PointValueDao(); - long count = pointValueDao.deleteAllPointData(); - pointValueDao.compressTables(); - for (Integer id : dataPoints.keySet()) - updateDataPointValuesRT(id); - return count;*/ - //TODO not allow the deletion of data should be switched to a new database - return 0; - } - - public long purgeDataPointValues(int dataPointId, int periodType, - int periodCount) { - long before = DateUtils.minus(System.currentTimeMillis(), periodType, - periodCount); - return purgeDataPointValues(dataPointId, before); - } - - public long purgeDataPointValues(int dataPointId) { - /*long count = new PointValueDao().deletePointValues(dataPointId); - updateDataPointValuesRT(dataPointId); - return count;*/ - //TODO not allow the deletion of data should be switched to a new database - return 0; - } - - public long purgeDataPointValues(int dataPointId, long before) { - /*long count = new PointValueDao().deletePointValuesBefore(dataPointId, - before); - if (count > 0) - updateDataPointValuesRT(dataPointId); - return count;*/ - return 0; - } - - private void updateDataPointValuesRT(int dataPointId) { - DataPointRT dataPoint = dataPoints.get(dataPointId); - if (dataPoint != null) - // Enabled. Reset the point's cache. - dataPoint.resetValues(); - } - - // - // - // Scheduled events - // - public void saveScheduledEvent(ScheduledEventVO vo) { - // If the scheduled event is running, stop it. - stopSimpleEventDetector(vo.getEventDetectorKey()); - - new ScheduledEventDao().saveScheduledEvent(vo); - - // If the scheduled event is enabled, start it. - if (!vo.isDisabled()) - startScheduledEvent(vo); - } - - private void startScheduledEvent(ScheduledEventVO vo) { - synchronized (simpleEventDetectors) { - stopSimpleEventDetector(vo.getEventDetectorKey()); - ScheduledEventRT rt = vo.createRuntime(); - simpleEventDetectors.put(vo.getEventDetectorKey(), rt); - rt.initialize(); - } - } - - public void stopSimpleEventDetector(String key) { - synchronized (simpleEventDetectors) { - SimpleEventDetector rt = simpleEventDetectors.remove(key); - if (rt != null) - rt.terminate(); - } - } - - // - // - // Point event detectors - // - public void addPointEventDetector(PointEventDetectorRT ped) { - synchronized (simpleEventDetectors) { - ped.initialize(); - simpleEventDetectors.put(ped.getEventDetectorKey(), ped); - } - } - - public void removePointEventDetector(String pointEventDetectorKey) { - synchronized (simpleEventDetectors) { - SimpleEventDetector sed = simpleEventDetectors - .remove(pointEventDetectorKey); - if (sed != null) - sed.terminate(); - } - } - - public SimpleEventDetector getSimpleEventDetector(String key) { - return simpleEventDetectors.get(key); - } - - // - // - // Compound event detectors - // - public boolean saveCompoundEventDetector(CompoundEventDetectorVO vo) { - // If the CED is running, stop it. - stopCompoundEventDetector(vo.getId()); - - new CompoundEventDetectorDao().saveCompoundEventDetector(vo); - - // If the scheduled event is enabled, start it. - if (!vo.isDisabled()) - return startCompoundEventDetector(vo); - - return true; - } - - public boolean startCompoundEventDetector(CompoundEventDetectorVO ced) { - stopCompoundEventDetector(ced.getId()); - CompoundEventDetectorRT rt = ced.createRuntime(); - try { - rt.initialize(); - compoundEventDetectors.put(ced.getId(), rt); - return true; - } catch (LifecycleException e) { - rt.raiseFailureEvent(new LocalizableMessage( - "event.compound.exceptionFailure", ced.getName(), - ((LocalizableException) e.getCause()) - .getLocalizableMessage())); - } catch (Exception e) { - rt.raiseFailureEvent(new LocalizableMessage( - "event.compound.exceptionFailure", ced.getName(), e - .getMessage())); - } - return false; - } - - public void stopCompoundEventDetector(int compoundEventDetectorId) { - CompoundEventDetectorRT rt = compoundEventDetectors - .remove(compoundEventDetectorId); - if (rt != null) - rt.terminate(); - } - - // - // - // Publishers - // - public PublisherRT getRunningPublisher(int publisherId) { - for (PublisherRT publisher : runningPublishers) { - if (publisher.getId() == publisherId) - return publisher; - } - return null; - } - - public boolean isPublisherRunning(int publisherId) { - return getRunningPublisher(publisherId) != null; - } - - public PublisherVO getPublisher(int publisherId) { - return new PublisherDao().getPublisher(publisherId); - } - - public void deletePublisher(int publisherId) { - stopPublisher(publisherId); - new PublisherDao().deletePublisher(publisherId); - Common.ctx.getEventManager().cancelEventsForPublisher(publisherId); - } - - public void savePublisher(PublisherVO vo) { - // If the data source is running, stop it. - stopPublisher(vo.getId()); - - // In case this is a new publisher, we need to save to the database - // first so that it has a proper id. - new PublisherDao().savePublisher(vo); - - // If the publisher is enabled, start it. - if (vo.isEnabled()) - startPublisher(vo); - } - - private void startPublisher(PublisherVO vo) { - synchronized (runningPublishers) { - // If the publisher is already running, just quit. - if (isPublisherRunning(vo.getId())) - return; - - // Ensure that the data source is enabled. - Assert.isTrue(vo.isEnabled()); - - // Create and start the runtime version of the publisher. - PublisherRT publisher = vo.createPublisherRT(); - publisher.initialize(); - - // Add it to the list of running publishers. - runningPublishers.add(publisher); - } - } - - private void stopPublisher(int id) { - synchronized (runningPublishers) { - PublisherRT publisher = getRunningPublisher(id); - if (publisher == null) - return; - - runningPublishers.remove(publisher); - publisher.terminate(); - publisher.joinTermination(); - } - } - - // - // - // Point links - // - private PointLinkRT getRunningPointLink(int pointLinkId) { - for (PointLinkRT pointLink : pointLinks) { - if (pointLink.getId() == pointLinkId) - return pointLink; - } - return null; - } - - public boolean isPointLinkRunning(int pointLinkId) { - return getRunningPointLink(pointLinkId) != null; - } - - public void deletePointLink(int pointLinkId) { - stopPointLink(pointLinkId); - new PointLinkDao().deletePointLink(pointLinkId); - } - - public void savePointLink(PointLinkVO vo) { - // If the point link is running, stop it. - stopPointLink(vo.getId()); - - new PointLinkDao().savePointLink(vo); - - // If the point link is enabled, start it. - if (!vo.isDisabled()) - startPointLink(vo); - } - - private void startPointLink(PointLinkVO vo) { - synchronized (pointLinks) { - // If the point link is already running, just quit. - if (isPointLinkRunning(vo.getId())) - return; - - // Ensure that the point link is enabled. - Assert.isTrue(!vo.isDisabled()); - - // Create and start the runtime version of the point link. - PointLinkRT pointLink = new PointLinkRT(vo); - pointLink.initialize(); - - // Add it to the list of running point links. - pointLinks.add(pointLink); - } - } - - private void stopPointLink(int id) { - synchronized (pointLinks) { - PointLinkRT pointLink = getRunningPointLink(id); - if (pointLink == null) - return; - - pointLinks.remove(pointLink); - pointLink.terminate(); - } - } - - // - // - // Maintenance events - // - public MaintenanceEventRT getRunningMaintenanceEvent(int id) { - for (MaintenanceEventRT rt : maintenanceEvents) { - if (rt.getVo().getId() == id) - return rt; - } - return null; - } - - public boolean isActiveMaintenanceEvent(int dataSourceId) { - for (MaintenanceEventRT rt : maintenanceEvents) { - if (rt.getVo().getDataSourceId() == dataSourceId - && rt.isEventActive()) - return true; - } - return false; - } - - public boolean isMaintenanceEventRunning(int id) { - return getRunningMaintenanceEvent(id) != null; - } - - public void deleteMaintenanceEvent(int id) { - stopMaintenanceEvent(id); - new MaintenanceEventDao().deleteMaintenanceEvent(id); - } - - public void saveMaintenanceEvent(MaintenanceEventVO vo) { - // If the maintenance event is running, stop it. - stopMaintenanceEvent(vo.getId()); - - new MaintenanceEventDao().saveMaintenanceEvent(vo); - - // If the maintenance event is enabled, start it. - if (!vo.isDisabled()) - startMaintenanceEvent(vo); - } - - private void startMaintenanceEvent(MaintenanceEventVO vo) { - synchronized (maintenanceEvents) { - // If the maintenance event is already running, just quit. - if (isMaintenanceEventRunning(vo.getId())) - return; - - // Ensure that the maintenance event is enabled. - Assert.isTrue(!vo.isDisabled()); - - // Create and start the runtime version of the maintenance event. - MaintenanceEventRT rt = new MaintenanceEventRT(vo); - rt.initialize(); - - // Add it to the list of running maintenance events. - maintenanceEvents.add(rt); - } - } - - private void stopMaintenanceEvent(int id) { - synchronized (maintenanceEvents) { - MaintenanceEventRT rt = getRunningMaintenanceEvent(id); - if (rt == null) - return; - - maintenanceEvents.remove(rt); - rt.terminate(); - } - } -} +/* + Mango - Open Source M2M - http://mango.serotoninsoftware.com + Copyright (C) 2006-2011 Serotonin Software Technologies Inc. + @author Matthew Lohbihler + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +package com.serotonin.mango.rt; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.util.Assert; + +import com.serotonin.ShouldNeverHappenException; +import com.serotonin.mango.Common; +import com.serotonin.mango.db.dao.CompoundEventDetectorDao; +import com.serotonin.mango.db.dao.DataPointDao; +import com.serotonin.mango.db.dao.DataSourceDao; +import com.serotonin.mango.db.dao.MaintenanceEventDao; +import com.serotonin.mango.db.dao.PointLinkDao; +import com.serotonin.mango.db.dao.PointValueDao; +import com.serotonin.mango.db.dao.PublisherDao; +import com.serotonin.mango.db.dao.ScheduledEventDao; +import com.serotonin.mango.rt.dataImage.DataPointEventMulticaster; +import com.serotonin.mango.rt.dataImage.DataPointListener; +import com.serotonin.mango.rt.dataImage.DataPointRT; +import com.serotonin.mango.rt.dataImage.PointValueTime; +import com.serotonin.mango.rt.dataImage.SetPointSource; +import com.serotonin.mango.rt.dataImage.types.MangoValue; +import com.serotonin.mango.rt.dataSource.DataSourceRT; +import com.serotonin.mango.rt.dataSource.meta.MetaDataSourceRT; +import com.serotonin.mango.rt.event.SimpleEventDetector; +import com.serotonin.mango.rt.event.compound.CompoundEventDetectorRT; +import com.serotonin.mango.rt.event.detectors.PointEventDetectorRT; +import com.serotonin.mango.rt.event.maintenance.MaintenanceEventRT; +import com.serotonin.mango.rt.event.schedule.ScheduledEventRT; +import com.serotonin.mango.rt.link.PointLinkRT; +import com.serotonin.mango.rt.publish.PublisherRT; +import com.serotonin.mango.util.DateUtils; +import com.serotonin.mango.vo.DataPointVO; +import com.serotonin.mango.vo.dataSource.DataSourceVO; +import com.serotonin.mango.vo.event.CompoundEventDetectorVO; +import com.serotonin.mango.vo.event.MaintenanceEventVO; +import com.serotonin.mango.vo.event.PointEventDetectorVO; +import com.serotonin.mango.vo.event.ScheduledEventVO; +import com.serotonin.mango.vo.link.PointLinkVO; +import com.serotonin.mango.vo.publish.PublishedPointVO; +import com.serotonin.mango.vo.publish.PublisherVO; +import com.serotonin.util.LifecycleException; +import com.serotonin.web.i18n.LocalizableException; +import com.serotonin.web.i18n.LocalizableMessage; + +public class RuntimeManager { + private static final Log LOG = LogFactory.getLog(RuntimeManager.class); + + private final List runningDataSources = new CopyOnWriteArrayList(); + + /** + * Provides a quick lookup map of the running data points. + */ + private final Map dataPoints = new ConcurrentHashMap(); + + /** + * The list of point listeners, kept here such that listeners can be + * notified of point initializations (i.e. a listener can register itself + * before the point is enabled). + */ + private final Map dataPointListeners = new ConcurrentHashMap(); + + /** + * Store of enabled event detectors. + */ + private final Map simpleEventDetectors = new ConcurrentHashMap(); + + /** + * Store of enabled compound event detectors. + */ + private final Map compoundEventDetectors = new ConcurrentHashMap(); + + /** + * Store of enabled publishers + */ + private final List> runningPublishers = new CopyOnWriteArrayList>(); + + /** + * Store of enabled point links + */ + private final List pointLinks = new CopyOnWriteArrayList(); + + /** + * Store of maintenance events + */ + private final List maintenanceEvents = new CopyOnWriteArrayList(); + + private boolean started = false; + + // + // Lifecycle + synchronized public void initialize(boolean safe) { + if (started) + throw new ShouldNeverHappenException( + "RuntimeManager already started"); + + // Set the started indicator to true. + started = true; + + // Initialize data sources that are enabled. + DataSourceDao dataSourceDao = new DataSourceDao(); + List> configs = dataSourceDao.getDataSources(); + List> pollingRound = new ArrayList>(); + for (DataSourceVO config : configs) { + if (config.isEnabled()) { + if (safe) { + config.setEnabled(false); + dataSourceDao.saveDataSource(config); + } else if (initializeDataSource(config)) + pollingRound.add(config); + } + } + + // Set up point links. + PointLinkDao pointLinkDao = new PointLinkDao(); + for (PointLinkVO vo : pointLinkDao.getPointLinks()) { + if (!vo.isDisabled()) { + if (safe) { + vo.setDisabled(true); + pointLinkDao.savePointLink(vo); + } else + startPointLink(vo); + } + } + + // Tell the data sources to start polling. Delaying the polling start + // gives the data points a chance to + // initialize such that point listeners in meta points and set point + // handlers can run properly. + for (DataSourceVO config : pollingRound) + startDataSourcePolling(config); + + // Initialize the scheduled events. + ScheduledEventDao scheduledEventDao = new ScheduledEventDao(); + List scheduledEvents = scheduledEventDao + .getScheduledEvents(); + for (ScheduledEventVO se : scheduledEvents) { + if (!se.isDisabled()) { + if (safe) { + se.setDisabled(true); + scheduledEventDao.saveScheduledEvent(se); + } else + startScheduledEvent(se); + } + } + + // Initialize the compound events. + CompoundEventDetectorDao compoundEventDetectorDao = new CompoundEventDetectorDao(); + List compoundDetectors = compoundEventDetectorDao + .getCompoundEventDetectors(); + for (CompoundEventDetectorVO ced : compoundDetectors) { + if (!ced.isDisabled()) { + if (safe) { + ced.setDisabled(true); + compoundEventDetectorDao.saveCompoundEventDetector(ced); + } else + startCompoundEventDetector(ced); + } + } + + // Start the publishers that are enabled + PublisherDao publisherDao = new PublisherDao(); + List> publishers = publisherDao + .getPublishers(); + for (PublisherVO vo : publishers) { + if (vo.isEnabled()) { + if (safe) { + vo.setEnabled(false); + publisherDao.savePublisher(vo); + } else + startPublisher(vo); + } + } + + // Start the maintenance events that are enabled + MaintenanceEventDao maintenanceEventDao = new MaintenanceEventDao(); + for (MaintenanceEventVO vo : maintenanceEventDao.getMaintenanceEvents()) { + if (!vo.isDisabled()) { + if (safe) { + vo.setDisabled(true); + maintenanceEventDao.saveMaintenanceEvent(vo); + } else + startMaintenanceEvent(vo); + } + } + } + + synchronized public void terminate() { + if (!started) + throw new ShouldNeverHappenException( + "RuntimeManager not yet started"); + + started = false; + for (MaintenanceEventRT me : maintenanceEvents) + stopMaintenanceEvent(me.getVo().getId()); + + for (PublisherRT publisher : runningPublishers) + stopPublisher(publisher.getId()); + + for (Integer id : compoundEventDetectors.keySet()) + stopCompoundEventDetector(id); + + for (PointLinkRT pointLink : pointLinks) + stopPointLink(pointLink.getId()); + + // First stop meta data sources. + for (DataSourceRT dataSource : runningDataSources) { + if (dataSource instanceof MetaDataSourceRT) + stopDataSource(dataSource.getId()); + } + // Then stop everything else. + for (DataSourceRT dataSource : runningDataSources) + stopDataSource(dataSource.getId()); + + for (String key : simpleEventDetectors.keySet()) + stopSimpleEventDetector(key); + } + + public void joinTermination() { + for (DataSourceRT dataSource : runningDataSources) { + try { + dataSource.joinTermination(); + } catch (ShouldNeverHappenException e) { + LOG.error("Error stopping data source " + dataSource.getId(), e); + } + } + } + + // + // + // Data sources + // + public DataSourceRT getRunningDataSource(int dataSourceId) { + for (DataSourceRT dataSource : runningDataSources) { + if (dataSource.getId() == dataSourceId) + return dataSource; + } + return null; + } + + public boolean isDataSourceRunning(int dataSourceId) { + return getRunningDataSource(dataSourceId) != null; + } + + public List> getDataSources() { + return new DataSourceDao().getDataSources(); + } + + public DataSourceVO getDataSource(int dataSourceId) { + return new DataSourceDao().getDataSource(dataSourceId); + } + + public void deleteDataSource(int dataSourceId) { + stopDataSource(dataSourceId); + new DataSourceDao().deleteDataSource(dataSourceId); + Common.ctx.getEventManager().cancelEventsForDataSource(dataSourceId); + } + + public void saveDataSource(DataSourceVO vo) { + LOG.debug("Stoping DS: " + vo.getName()); + // If the data source is running, stop it. + stopDataSource(vo.getId()); + LOG.debug("DS Stoped!"); + + // In case this is a new data source, we need to save to the database + // first so that it has a proper id. + LOG.debug("Saving DS: " + vo.getName()); + new DataSourceDao().saveDataSource(vo); + LOG.debug("DS saved!"); + // If the data source is enabled, start it. + if (vo.isEnabled()) { + LOG.debug("Starting DS: " + vo.getName()); + if (initializeDataSource(vo)) { + LOG.debug("DS Started!"); + startDataSourcePolling(vo); + LOG.debug("DS polling Started!"); + } + } + } + + private boolean initializeDataSource(DataSourceVO vo) { + synchronized (runningDataSources) { + // If the data source is already running, just quit. + if (isDataSourceRunning(vo.getId())) + return false; + + // Ensure that the data source is enabled. + Assert.isTrue(vo.isEnabled()); + + // Create and initialize the runtime version of the data source. + DataSourceRT dataSource = vo.createDataSourceRT(); + dataSource.initialize(); + + // Add it to the list of running data sources. + runningDataSources.add(dataSource); + + // Add the enabled points to the data source. + List dataSourcePoints = new DataPointDao() + .getDataPoints(vo.getId(), null); + for (DataPointVO dataPoint : dataSourcePoints) { + if (dataPoint.isEnabled()) + startDataPoint(dataPoint); + } + + LOG.info("Data source '" + vo.getName() + "' initialized"); + + return true; + } + } + + private void startDataSourcePolling(DataSourceVO vo) { + DataSourceRT dataSource = getRunningDataSource(vo.getId()); + if (dataSource != null) + dataSource.beginPolling(); + } + + public void stopDataSource(int id) { + synchronized (runningDataSources) { + DataSourceRT dataSource = getRunningDataSource(id); + if (dataSource == null) + return; + + // Stop the data points. + for (DataPointRT p : dataPoints.values()) { + if (p.getDataSourceId() == id) + stopDataPoint(p.getId()); + } + + runningDataSources.remove(dataSource); + dataSource.terminate(); + + dataSource.joinTermination(); + LOG.info("Data source '" + dataSource.getName() + "' stopped"); + } + } + + // + // + // Data points + // + public void saveDataPoint(DataPointVO point) { + stopDataPoint(point.getId()); + + // Since the point's data type may have changed, we must ensure that the + // other attrtibutes are still ok with + // it. + int dataType = point.getPointLocator().getDataTypeId(); + + // Chart renderer + if (point.getChartRenderer() != null + && !point.getChartRenderer().getDef().supports(dataType)) + // Return to a default renderer + point.setChartRenderer(null); + + // Text renderer + if (point.getTextRenderer() != null + && !point.getTextRenderer().getDef().supports(dataType)) + // Return to a default renderer + point.defaultTextRenderer(); + + // Event detectors + /*Iterator peds = point.getEventDetectors() + .iterator(); + while (peds.hasNext()) { + PointEventDetectorVO ped = peds.next(); + if (!ped.getDef().supports(dataType)) + // Remove the detector. + peds.remove(); + }*/ + + new DataPointDao().saveDataPoint(point); + + if (point.isEnabled()) + startDataPoint(point); + } + + public void deleteDataPoint(DataPointVO point) { + if (point.isEnabled()) + stopDataPoint(point.getId()); + new DataPointDao().deleteDataPoint(point.getId()); + Common.ctx.getEventManager().cancelEventsForDataPoint(point.getId()); + } + + private void startDataPoint(DataPointVO vo) { + synchronized (dataPoints) { + Assert.isTrue(vo.isEnabled()); + + // Only add the data point if its data source is enabled. + DataSourceRT ds = getRunningDataSource(vo.getDataSourceId()); + if (ds != null) { + // Change the VO into a data point implementation. + DataPointRT dataPoint = new DataPointRT(vo, vo + .getPointLocator().createRuntime()); + + // Add/update it in the data image. + dataPoints.put(dataPoint.getId(), dataPoint); + + // Initialize it. + dataPoint.initialize(); + DataPointListener l = getDataPointListeners(vo.getId()); + if (l != null) + l.pointInitialized(); + + // Add/update it in the data source. + ds.addDataPoint(dataPoint); + } + } + } + + private void stopDataPoint(int dataPointId) { + synchronized (dataPoints) { + // Remove this point from the data image if it is there. If not, + // just quit. + DataPointRT p = dataPoints.remove(dataPointId); + + // Remove it from the data source, and terminate it. + if (p != null) { + getRunningDataSource(p.getDataSourceId()).removeDataPoint(p); + DataPointListener l = getDataPointListeners(dataPointId); + if (l != null) + l.pointTerminated(); + p.terminate(); + } + } + } + + public boolean isDataPointRunning(int dataPointId) { + return dataPoints.get(dataPointId) != null; + } + + public DataPointRT getDataPoint(int dataPointId) { + return dataPoints.get(dataPointId); + } + + public void addDataPointListener(int dataPointId, DataPointListener l) { + DataPointListener listeners = dataPointListeners.get(dataPointId); + dataPointListeners.put(dataPointId, + DataPointEventMulticaster.add(listeners, l)); + } + + public void removeDataPointListener(int dataPointId, DataPointListener l) { + DataPointListener listeners = DataPointEventMulticaster.remove( + dataPointListeners.get(dataPointId), l); + if (listeners == null) + dataPointListeners.remove(dataPointId); + else + dataPointListeners.put(dataPointId, listeners); + } + + public DataPointListener getDataPointListeners(int dataPointId) { + return dataPointListeners.get(dataPointId); + } + + // + // Point values + public void setDataPointValue(int dataPointId, MangoValue value, + SetPointSource source) { + setDataPointValue(dataPointId, + new PointValueTime(value, System.currentTimeMillis()), source); + } + + public void setDataPointValue(int dataPointId, PointValueTime valueTime, + SetPointSource source) { + DataPointRT dataPoint = dataPoints.get(dataPointId); + if (dataPoint == null) + throw new RTException("Point is not enabled"); + + if (!dataPoint.getPointLocator().isSettable()) + throw new RTException("Point is not settable"); + + // Tell the data source to set the value of the point. + DataSourceRT ds = getRunningDataSource(dataPoint.getDataSourceId()); + // The data source may have been disabled. Just make sure. + if (ds != null) + ds.setPointValue(dataPoint, valueTime, source); + } + + public void relinquish(int dataPointId) { + DataPointRT dataPoint = dataPoints.get(dataPointId); + if (dataPoint == null) + throw new RTException("Point is not enabled"); + + if (!dataPoint.getPointLocator().isSettable()) + throw new RTException("Point is not settable"); + if (!dataPoint.getPointLocator().isRelinquishable()) + throw new RTException("Point is not relinquishable"); + + // Tell the data source to relinquish value of the point. + DataSourceRT ds = getRunningDataSource(dataPoint.getDataSourceId()); + // The data source may have been disabled. Just make sure. + if (ds != null) + ds.relinquish(dataPoint); + } + + public void forcePointRead(int dataPointId) { + DataPointRT dataPoint = dataPoints.get(dataPointId); + if (dataPoint == null) + throw new RTException("Point is not enabled"); + + // Tell the data source to read the point value; + DataSourceRT ds = getRunningDataSource(dataPoint.getDataSourceId()); + if (ds != null) + // The data source may have been disabled. Just make sure. + ds.forcePointRead(dataPoint); + } + + public long purgeDataPointValues() { + /* + PointValueDao pointValueDao = new PointValueDao(); + long count = pointValueDao.deleteAllPointData(); + pointValueDao.compressTables(); + for (Integer id : dataPoints.keySet()) + updateDataPointValuesRT(id); + return count;*/ + //TODO not allow the deletion of data should be switched to a new database + return 0; + } + + public long purgeDataPointValues(int dataPointId, int periodType, + int periodCount) { + long before = DateUtils.minus(System.currentTimeMillis(), periodType, + periodCount); + return purgeDataPointValues(dataPointId, before); + } + + public long purgeDataPointValues(int dataPointId) { + /*long count = new PointValueDao().deletePointValues(dataPointId); + updateDataPointValuesRT(dataPointId); + return count;*/ + //TODO not allow the deletion of data should be switched to a new database + return 0; + } + + public long purgeDataPointValues(int dataPointId, long before) { + /*long count = new PointValueDao().deletePointValuesBefore(dataPointId, + before); + if (count > 0) + updateDataPointValuesRT(dataPointId); + return count;*/ + return 0; + } + + private void updateDataPointValuesRT(int dataPointId) { + DataPointRT dataPoint = dataPoints.get(dataPointId); + if (dataPoint != null) + // Enabled. Reset the point's cache. + dataPoint.resetValues(); + } + + // + // + // Scheduled events + // + public void saveScheduledEvent(ScheduledEventVO vo) { + // If the scheduled event is running, stop it. + stopSimpleEventDetector(vo.getEventDetectorKey()); + + new ScheduledEventDao().saveScheduledEvent(vo); + + // If the scheduled event is enabled, start it. + if (!vo.isDisabled()) + startScheduledEvent(vo); + } + + private void startScheduledEvent(ScheduledEventVO vo) { + synchronized (simpleEventDetectors) { + stopSimpleEventDetector(vo.getEventDetectorKey()); + ScheduledEventRT rt = vo.createRuntime(); + simpleEventDetectors.put(vo.getEventDetectorKey(), rt); + rt.initialize(); + } + } + + public void stopSimpleEventDetector(String key) { + synchronized (simpleEventDetectors) { + SimpleEventDetector rt = simpleEventDetectors.remove(key); + if (rt != null) + rt.terminate(); + } + } + + // + // + // Point event detectors + // + public void addPointEventDetector(PointEventDetectorRT ped) { + synchronized (simpleEventDetectors) { + ped.initialize(); + simpleEventDetectors.put(ped.getEventDetectorKey(), ped); + } + } + + public void removePointEventDetector(String pointEventDetectorKey) { + synchronized (simpleEventDetectors) { + SimpleEventDetector sed = simpleEventDetectors + .remove(pointEventDetectorKey); + if (sed != null) + sed.terminate(); + } + } + + public SimpleEventDetector getSimpleEventDetector(String key) { + return simpleEventDetectors.get(key); + } + + // + // + // Compound event detectors + // + public boolean saveCompoundEventDetector(CompoundEventDetectorVO vo) { + // If the CED is running, stop it. + stopCompoundEventDetector(vo.getId()); + + new CompoundEventDetectorDao().saveCompoundEventDetector(vo); + + // If the scheduled event is enabled, start it. + if (!vo.isDisabled()) + return startCompoundEventDetector(vo); + + return true; + } + + public boolean startCompoundEventDetector(CompoundEventDetectorVO ced) { + stopCompoundEventDetector(ced.getId()); + CompoundEventDetectorRT rt = ced.createRuntime(); + try { + rt.initialize(); + compoundEventDetectors.put(ced.getId(), rt); + return true; + } catch (LifecycleException e) { + rt.raiseFailureEvent(new LocalizableMessage( + "event.compound.exceptionFailure", ced.getName(), + ((LocalizableException) e.getCause()) + .getLocalizableMessage())); + } catch (Exception e) { + rt.raiseFailureEvent(new LocalizableMessage( + "event.compound.exceptionFailure", ced.getName(), e + .getMessage())); + } + return false; + } + + public void stopCompoundEventDetector(int compoundEventDetectorId) { + CompoundEventDetectorRT rt = compoundEventDetectors + .remove(compoundEventDetectorId); + if (rt != null) + rt.terminate(); + } + + // + // + // Publishers + // + public PublisherRT getRunningPublisher(int publisherId) { + for (PublisherRT publisher : runningPublishers) { + if (publisher.getId() == publisherId) + return publisher; + } + return null; + } + + public boolean isPublisherRunning(int publisherId) { + return getRunningPublisher(publisherId) != null; + } + + public PublisherVO getPublisher(int publisherId) { + return new PublisherDao().getPublisher(publisherId); + } + + public void deletePublisher(int publisherId) { + stopPublisher(publisherId); + new PublisherDao().deletePublisher(publisherId); + Common.ctx.getEventManager().cancelEventsForPublisher(publisherId); + } + + public void savePublisher(PublisherVO vo) { + // If the data source is running, stop it. + stopPublisher(vo.getId()); + + // In case this is a new publisher, we need to save to the database + // first so that it has a proper id. + new PublisherDao().savePublisher(vo); + + // If the publisher is enabled, start it. + if (vo.isEnabled()) + startPublisher(vo); + } + + private void startPublisher(PublisherVO vo) { + synchronized (runningPublishers) { + // If the publisher is already running, just quit. + if (isPublisherRunning(vo.getId())) + return; + + // Ensure that the data source is enabled. + Assert.isTrue(vo.isEnabled()); + + // Create and start the runtime version of the publisher. + PublisherRT publisher = vo.createPublisherRT(); + publisher.initialize(); + + // Add it to the list of running publishers. + runningPublishers.add(publisher); + } + } + + private void stopPublisher(int id) { + synchronized (runningPublishers) { + PublisherRT publisher = getRunningPublisher(id); + if (publisher == null) + return; + + runningPublishers.remove(publisher); + publisher.terminate(); + publisher.joinTermination(); + } + } + + // + // + // Point links + // + private PointLinkRT getRunningPointLink(int pointLinkId) { + for (PointLinkRT pointLink : pointLinks) { + if (pointLink.getId() == pointLinkId) + return pointLink; + } + return null; + } + + public boolean isPointLinkRunning(int pointLinkId) { + return getRunningPointLink(pointLinkId) != null; + } + + public void deletePointLink(int pointLinkId) { + stopPointLink(pointLinkId); + new PointLinkDao().deletePointLink(pointLinkId); + } + + public void savePointLink(PointLinkVO vo) { + // If the point link is running, stop it. + stopPointLink(vo.getId()); + + new PointLinkDao().savePointLink(vo); + + // If the point link is enabled, start it. + if (!vo.isDisabled()) + startPointLink(vo); + } + + private void startPointLink(PointLinkVO vo) { + synchronized (pointLinks) { + // If the point link is already running, just quit. + if (isPointLinkRunning(vo.getId())) + return; + + // Ensure that the point link is enabled. + Assert.isTrue(!vo.isDisabled()); + + // Create and start the runtime version of the point link. + PointLinkRT pointLink = new PointLinkRT(vo); + pointLink.initialize(); + + // Add it to the list of running point links. + pointLinks.add(pointLink); + } + } + + private void stopPointLink(int id) { + synchronized (pointLinks) { + PointLinkRT pointLink = getRunningPointLink(id); + if (pointLink == null) + return; + + pointLinks.remove(pointLink); + pointLink.terminate(); + } + } + + // + // + // Maintenance events + // + public MaintenanceEventRT getRunningMaintenanceEvent(int id) { + for (MaintenanceEventRT rt : maintenanceEvents) { + if (rt.getVo().getId() == id) + return rt; + } + return null; + } + + public boolean isActiveMaintenanceEvent(int dataSourceId) { + for (MaintenanceEventRT rt : maintenanceEvents) { + if (rt.getVo().getDataSourceId() == dataSourceId + && rt.isEventActive()) + return true; + } + return false; + } + + public boolean isMaintenanceEventRunning(int id) { + return getRunningMaintenanceEvent(id) != null; + } + + public void deleteMaintenanceEvent(int id) { + stopMaintenanceEvent(id); + new MaintenanceEventDao().deleteMaintenanceEvent(id); + } + + public void saveMaintenanceEvent(MaintenanceEventVO vo) { + // If the maintenance event is running, stop it. + stopMaintenanceEvent(vo.getId()); + + new MaintenanceEventDao().saveMaintenanceEvent(vo); + + // If the maintenance event is enabled, start it. + if (!vo.isDisabled()) + startMaintenanceEvent(vo); + } + + private void startMaintenanceEvent(MaintenanceEventVO vo) { + synchronized (maintenanceEvents) { + // If the maintenance event is already running, just quit. + if (isMaintenanceEventRunning(vo.getId())) + return; + + // Ensure that the maintenance event is enabled. + Assert.isTrue(!vo.isDisabled()); + + // Create and start the runtime version of the maintenance event. + MaintenanceEventRT rt = new MaintenanceEventRT(vo); + rt.initialize(); + + // Add it to the list of running maintenance events. + maintenanceEvents.add(rt); + } + } + + private void stopMaintenanceEvent(int id) { + synchronized (maintenanceEvents) { + MaintenanceEventRT rt = getRunningMaintenanceEvent(id); + if (rt == null) + return; + + maintenanceEvents.remove(rt); + rt.terminate(); + } + } +} From f76be91387ce496ff460aa76581fec290bfddce5 Mon Sep 17 00:00:00 2001 From: Arkadiusz Parafiniuk Date: Tue, 26 Sep 2017 14:14:59 +0200 Subject: [PATCH 51/54] #384 Better way to solve vanishing event detectors issue --- src/com/serotonin/mango/rt/RuntimeManager.java | 6 +++--- .../mango/service/DataPointService.java | 18 +++++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/com/serotonin/mango/rt/RuntimeManager.java b/src/com/serotonin/mango/rt/RuntimeManager.java index 27792e828e..90045c900b 100644 --- a/src/com/serotonin/mango/rt/RuntimeManager.java +++ b/src/com/serotonin/mango/rt/RuntimeManager.java @@ -384,14 +384,14 @@ public void saveDataPoint(DataPointVO point) { point.defaultTextRenderer(); // Event detectors - /*Iterator peds = point.getEventDetectors() + Iterator peds = point.getEventDetectors() .iterator(); - while (peds.hasNext()) { + while (peds.hasNext()) { PointEventDetectorVO ped = peds.next(); if (!ped.getDef().supports(dataType)) // Remove the detector. peds.remove(); - }*/ + } new DataPointDao().saveDataPoint(point); diff --git a/src/org/scada_lts/mango/service/DataPointService.java b/src/org/scada_lts/mango/service/DataPointService.java index b1acb67d8a..b2d27eea05 100644 --- a/src/org/scada_lts/mango/service/DataPointService.java +++ b/src/org/scada_lts/mango/service/DataPointService.java @@ -356,21 +356,17 @@ private List getEventDetectors(DataPointVO dataPoint) { private void saveEventDetectors(DataPointVO dataPoint) { List detectors = getEventDetectors(dataPoint); + for (PointEventDetectorVO pointEventDetector: detectors) { + pointEventDetectorDAO.delete(dataPoint.getId(), pointEventDetector.getId()); + } + for (PointEventDetectorVO pointEventDetector: dataPoint.getEventDetectors()) { - if (pointEventDetector.getId() < 0) { - try { - pointEventDetectorDAO.insert(pointEventDetector); - } catch (DuplicateKeyException e) { - pointEventDetectorDAO.update(pointEventDetector); - } - } else { + try { + pointEventDetectorDAO.insert(pointEventDetector); + } catch (DuplicateKeyException e) { pointEventDetectorDAO.update(pointEventDetector); } } - - for (PointEventDetectorVO pointEventDetector: detectors) { - pointEventDetectorDAO.delete(dataPoint.getId(), pointEventDetector.getId()); - } } private PointEventDetectorVO removeFromList(List list, int id) { From 67b6b36496324371c45167bafbcde9455ccc45f6 Mon Sep 17 00:00:00 2001 From: Arkadiusz Parafiniuk Date: Wed, 27 Sep 2017 11:05:47 +0200 Subject: [PATCH 52/54] #384 Added way to avoid vanishing events from event handlers list --- src/org/scada_lts/mango/service/DataPointService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/org/scada_lts/mango/service/DataPointService.java b/src/org/scada_lts/mango/service/DataPointService.java index b2d27eea05..2d2d2b3113 100644 --- a/src/org/scada_lts/mango/service/DataPointService.java +++ b/src/org/scada_lts/mango/service/DataPointService.java @@ -357,7 +357,9 @@ private void saveEventDetectors(DataPointVO dataPoint) { List detectors = getEventDetectors(dataPoint); for (PointEventDetectorVO pointEventDetector: detectors) { - pointEventDetectorDAO.delete(dataPoint.getId(), pointEventDetector.getId()); + if(!dataPoint.getEventDetectors().contains(pointEventDetector)) { + pointEventDetectorDAO.delete(dataPoint.getId(), pointEventDetector.getId()); + } } for (PointEventDetectorVO pointEventDetector: dataPoint.getEventDetectors()) { From 03815319eaa455434d2c1ff3aa0c3fd3b865f10c Mon Sep 17 00:00:00 2001 From: Arkadiusz Parafiniuk Date: Tue, 10 Oct 2017 11:52:16 +0200 Subject: [PATCH 53/54] #391 temporary fix for non-admin users access to data points details --- .../DataPointDetailsController.java | 338 +++++++++--------- 1 file changed, 169 insertions(+), 169 deletions(-) diff --git a/src/com/serotonin/mango/web/mvc/controller/DataPointDetailsController.java b/src/com/serotonin/mango/web/mvc/controller/DataPointDetailsController.java index 0ded513e22..9005b48c46 100644 --- a/src/com/serotonin/mango/web/mvc/controller/DataPointDetailsController.java +++ b/src/com/serotonin/mango/web/mvc/controller/DataPointDetailsController.java @@ -1,169 +1,169 @@ -/* - Mango - Open Source M2M - http://mango.serotoninsoftware.com - Copyright (C) 2006-2011 Serotonin Software Technologies Inc. - @author Matthew Lohbihler - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -package com.serotonin.mango.web.mvc.controller; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.servlet.mvc.ParameterizableViewController; - -import com.serotonin.ShouldNeverHappenException; -import com.serotonin.mango.Common; -import com.serotonin.mango.db.dao.DataPointDao; -import com.serotonin.mango.db.dao.EventDao; -import com.serotonin.mango.db.dao.UserDao; -import com.serotonin.mango.db.dao.ViewDao; -import com.serotonin.mango.view.View; -import com.serotonin.mango.view.chart.ImageChartRenderer; -import com.serotonin.mango.view.chart.ImageFlipbookRenderer; -import com.serotonin.mango.view.chart.TableChartRenderer; -import com.serotonin.mango.vo.DataPointVO; -import com.serotonin.mango.vo.User; -import com.serotonin.mango.vo.permission.Permissions; -import com.serotonin.util.StringUtils; - -public class DataPointDetailsController extends ParameterizableViewController { - @Override - protected ModelAndView handleRequestInternal(HttpServletRequest request, - HttpServletResponse response) throws Exception { - Map model = new HashMap(); - User user = Common.getUser(request); - - int id; - DataPointDao dataPointDao = new DataPointDao(); - String idStr = request.getParameter("dpid"); - DataPointVO point = null; - - if (StringUtils.isEmpty(idStr)) { - // Check for pedid (point event detector id) - String pedStr = request.getParameter("pedid"); - if (pedStr == null) { - // Check if an XID was provided. - String xid = request.getParameter("dpxid"); - if (xid == null) - throw new ShouldNeverHappenException( - "One of dpid, dpxid, or pedid must be provided for this view"); - - model.put("currentXid", xid); - point = dataPointDao.getDataPoint(xid); - id = point == null ? -1 : point.getId(); - } else { - int pedid = Integer.parseInt(pedStr); - id = dataPointDao.getDataPointIdFromDetectorId(pedid); - } - } else - id = Integer.parseInt(idStr); - - // Put the point in the model. - if (point == null) - point = dataPointDao.getDataPoint(id); - - if (point != null) { - Permissions.ensureDataPointReadPermission(user, point); - - model.put("point", point); - - // Get the views for this user that contain this point. - List userViews = new ViewDao().getViews(user.getId(), - user.getUserProfile()); - List views = new LinkedList(); - for (View view : userViews) { - view.validateViewComponents(false); - if (view.containsValidVisibleDataPoint(id)) - views.add(view); - } - model.put("views", views); - - // Get the users that have access to this point. - List allUsers = new UserDao().getUsers(); - List> users = new LinkedList>(); - Map userData; - int accessType; - for (User mangoUser : allUsers) { - accessType = Permissions.getDataPointAccessType(mangoUser, - point); - if (accessType != Permissions.DataPointAccessTypes.NONE) { - userData = new HashMap(); - userData.put("user", mangoUser); - userData.put("accessType", accessType); - users.add(userData); - } - } - model.put("users", users); - - // Determine whether the link to edit the point should be displayed - model.put( - "pointEditor", - Permissions.hasDataSourcePermission(user, - point.getDataSourceId())); - - // Put the events in the model. - model.put("events", - new EventDao().getEventsForDataPoint(id, user.getId())); - - // Put the default history table count into the model. Default to - // 10. - int historyLimit = 10; - if (point.getChartRenderer() instanceof TableChartRenderer) - historyLimit = ((TableChartRenderer) point.getChartRenderer()) - .getLimit(); - else if (point.getChartRenderer() instanceof ImageFlipbookRenderer) - historyLimit = ((ImageFlipbookRenderer) point - .getChartRenderer()).getLimit(); - model.put("historyLimit", historyLimit); - - // Determine our image chart rendering capabilities. - if (ImageChartRenderer.getDefinition().supports( - point.getPointLocator().getDataTypeId())) { - // This point can render an image chart. Carry on... - int periodType = Common.TimePeriods.DAYS; - int periodCount = 1; - if (point.getChartRenderer() instanceof ImageChartRenderer) { - ImageChartRenderer r = (ImageChartRenderer) point - .getChartRenderer(); - periodType = r.getTimePeriod(); - periodCount = r.getNumberOfPeriods(); - } - model.put("periodType", periodType); - model.put("periodCount", periodCount); - } - - // Determine out flipbook rendering capabilities - if (ImageFlipbookRenderer.getDefinition().supports( - point.getPointLocator().getDataTypeId())) - model.put("flipbookLimit", 10); - - model.put("currentXid", point.getXid()); - } - - // Set the point in the session for the dwr. - user.setEditPoint(point); - - // Find accessible points for the goto list - ControllerUtils.addPointListDataToModel(user, id, model); - - return new ModelAndView(getViewName(), model); - } -} +/* + Mango - Open Source M2M - http://mango.serotoninsoftware.com + Copyright (C) 2006-2011 Serotonin Software Technologies Inc. + @author Matthew Lohbihler + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +package com.serotonin.mango.web.mvc.controller; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.ParameterizableViewController; + +import com.serotonin.ShouldNeverHappenException; +import com.serotonin.mango.Common; +import com.serotonin.mango.db.dao.DataPointDao; +import com.serotonin.mango.db.dao.EventDao; +import com.serotonin.mango.db.dao.UserDao; +import com.serotonin.mango.db.dao.ViewDao; +import com.serotonin.mango.view.View; +import com.serotonin.mango.view.chart.ImageChartRenderer; +import com.serotonin.mango.view.chart.ImageFlipbookRenderer; +import com.serotonin.mango.view.chart.TableChartRenderer; +import com.serotonin.mango.vo.DataPointVO; +import com.serotonin.mango.vo.User; +import com.serotonin.mango.vo.permission.Permissions; +import com.serotonin.util.StringUtils; + +public class DataPointDetailsController extends ParameterizableViewController { + @Override + protected ModelAndView handleRequestInternal(HttpServletRequest request, + HttpServletResponse response) throws Exception { + Map model = new HashMap(); + User user = Common.getUser(request); + + int id; + DataPointDao dataPointDao = new DataPointDao(); + String idStr = request.getParameter("dpid"); + DataPointVO point = null; + + if (StringUtils.isEmpty(idStr)) { + // Check for pedid (point event detector id) + String pedStr = request.getParameter("pedid"); + if (pedStr == null) { + // Check if an XID was provided. + String xid = request.getParameter("dpxid"); + if (xid == null) + throw new ShouldNeverHappenException( + "One of dpid, dpxid, or pedid must be provided for this view"); + + model.put("currentXid", xid); + point = dataPointDao.getDataPoint(xid); + id = point == null ? -1 : point.getId(); + } else { + int pedid = Integer.parseInt(pedStr); + id = dataPointDao.getDataPointIdFromDetectorId(pedid); + } + } else + id = Integer.parseInt(idStr); + + // Put the point in the model. + if (point == null) + point = dataPointDao.getDataPoint(id); + + if (point != null) { + //Permissions.ensureDataPointReadPermission(user, point); + + model.put("point", point); + + // Get the views for this user that contain this point. + List userViews = new ViewDao().getViews(user.getId(), + user.getUserProfile()); + List views = new LinkedList(); + for (View view : userViews) { + view.validateViewComponents(false); + if (view.containsValidVisibleDataPoint(id)) + views.add(view); + } + model.put("views", views); + + // Get the users that have access to this point. + List allUsers = new UserDao().getUsers(); + List> users = new LinkedList>(); + Map userData; + int accessType; + for (User mangoUser : allUsers) { + accessType = Permissions.getDataPointAccessType(mangoUser, + point); + if (accessType != Permissions.DataPointAccessTypes.NONE) { + userData = new HashMap(); + userData.put("user", mangoUser); + userData.put("accessType", accessType); + users.add(userData); + } + } + model.put("users", users); + + // Determine whether the link to edit the point should be displayed + model.put( + "pointEditor", + Permissions.hasDataSourcePermission(user, + point.getDataSourceId())); + + // Put the events in the model. + model.put("events", + new EventDao().getEventsForDataPoint(id, user.getId())); + + // Put the default history table count into the model. Default to + // 10. + int historyLimit = 10; + if (point.getChartRenderer() instanceof TableChartRenderer) + historyLimit = ((TableChartRenderer) point.getChartRenderer()) + .getLimit(); + else if (point.getChartRenderer() instanceof ImageFlipbookRenderer) + historyLimit = ((ImageFlipbookRenderer) point + .getChartRenderer()).getLimit(); + model.put("historyLimit", historyLimit); + + // Determine our image chart rendering capabilities. + if (ImageChartRenderer.getDefinition().supports( + point.getPointLocator().getDataTypeId())) { + // This point can render an image chart. Carry on... + int periodType = Common.TimePeriods.DAYS; + int periodCount = 1; + if (point.getChartRenderer() instanceof ImageChartRenderer) { + ImageChartRenderer r = (ImageChartRenderer) point + .getChartRenderer(); + periodType = r.getTimePeriod(); + periodCount = r.getNumberOfPeriods(); + } + model.put("periodType", periodType); + model.put("periodCount", periodCount); + } + + // Determine out flipbook rendering capabilities + if (ImageFlipbookRenderer.getDefinition().supports( + point.getPointLocator().getDataTypeId())) + model.put("flipbookLimit", 10); + + model.put("currentXid", point.getXid()); + } + + // Set the point in the session for the dwr. + user.setEditPoint(point); + + // Find accessible points for the goto list + ControllerUtils.addPointListDataToModel(user, id, model); + + return new ModelAndView(getViewName(), model); + } +} From 84f33663c7dc006d482b2d00fb00e6ca957c2971 Mon Sep 17 00:00:00 2001 From: Arkadiusz Parafiniuk Date: Wed, 11 Oct 2017 12:42:28 +0200 Subject: [PATCH 54/54] #391 travis config fix --- .travis.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 70d861fe64..b0a6fa3358 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,17 +59,17 @@ env: - secure: KNfVmgjr2ZNsnvIfuhSkZ/kPrSTjn6WSDxEJt/3ioTCgeEGGvPL7UGonHHozZu3WzpzBVyUr60hXjb1nmb9dk6A3Dg05UPZmuS7NiHEA4Ub2zQKgefSbK0AJEhXSDg+bT16Hqxf1aZDaAEpMXGWTGLdpbKkGAW56UZu6LpOlOvoX9pFoSWAyzh1jKiYQsaKJ3eCncHKug5WqTVidOL/ENR6CAYyVLkgZ0yffwsCyVAnh14vri2lswPhPsPvMzYxtLQGkKkUOYkuPOZvBD7l5mp5Y4QLv86iKTFlOteim7yD+RpZZDFpb+3+OhRuj6jlBYWina33RKqBqjhhsayyYN/tYnPUefZhT+ALs8JfUaDXqMdgd7NQj8i5ZvrB+YsCTUVGrnPVbmEq8A4l/An5ushQpK5CrASiAC0K4dOBVT+U89QHtYWuE3ZOmSb518dlbH084ljypAj3JTQpUgRAAxn21VUMKb6QyIPsSPVEQ+zPQnaxBLhYVqafO7iX1tyvdr0mGhLZjXaaGwQu8Y/RoHdmRYcQAGn6zVFNuxWxTlr2OQ0fJ5l6/qBVyqZvqNirYa5hX8KtDu3dVMo5VOirIsoJTw75qTpGxYjhCNCb/woxtRvfX9xoT7tINWOxi2ucFfObSCsTv+BPeZeJiq7UDuFQYsQtWjNRp/iQNJ+rclpQ= after_script: # get tomcat7 to ./docker/app -- wget http://www-us.apache.org/dist/tomcat/tomcat-7/v7.0.81/bin/apache-tomcat-7.0.81.tar.gz +- wget http://www-us.apache.org/dist/tomcat/tomcat-7/v7.0.82/bin/apache-tomcat-7.0.82.tar.gz - mkdir ./docker/app -- mv apache-tomcat-7.0.81.tar.gz ./docker/app -- ls -l ./docker/app/apache-tomcat-7.0.81.tar.gz +- mv apache-tomcat-7.0.82.tar.gz ./docker/app +- ls -l ./docker/app/apache-tomcat-7.0.82.tar.gz - cd ./docker/app -- echo `pwd` +- echo `pwd` - echo `ls -l` -- tar -zxvf apache-tomcat-7.0.81.tar.gz +- tar -zxvf apache-tomcat-7.0.82.tar.gz - ls -l -- mv ./apache-tomcat-7.0.81/* ./ -- rm -rf ./apache-tomcat-7.0.81 +- mv ./apache-tomcat-7.0.82/* ./ +- rm -rf ./apache-tomcat-7.0.82 - cp ../../ScadaBR.war ./webapps - cp ../../ScadaLTS-UI/war/ScadaLTS.war ./webapps - ls -l ./webapps/ScadaLTS.war @@ -94,5 +94,4 @@ after_script: #- echo $TRAVIS_BUILD_DIR -#- sshpass -e scp ./ScadaBR.war test@149.56.44.225:/home/test/ScadaBR.war -#- sshpass -e scp ./ScadaLTS-UI/war/ScadaLTS.war test@149.56.44.225:/home/test/ScadaLTS.war +#- sshpa \ No newline at end of file